cocina-models 0.81.0 → 0.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +6 -5
- data/cocina-models.gemspec +3 -0
- data/lib/cocina/models/mapping/escape_html.rb +23 -0
- data/lib/cocina/models/mapping/to_mods/note.rb +3 -1
- data/lib/cocina/models/validators/date_time_validator.rb +102 -0
- data/lib/cocina/models/version.rb +1 -1
- metadata +47 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ebc24ff8dbe8eb1fe740eb977abb73abc504409aa510905395e6660adcd05b3b
|
|
4
|
+
data.tar.gz: 62ad4e7cafce859250323e92cc2173257957b16775e767224a4de2e9fd639bae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a3b0ed8ab383f945450d42343dbaed6e709854ff0f3deca1f62b93c79883d3157b42f14cdaafd9392ef858620a0c58ae6867c16037c627499efddf3cb33880b
|
|
7
|
+
data.tar.gz: 9e1084ea73c6f547eab7b8a076d9e2a61a46361c9da1541effca8529d48d032621b6cd5868bd2886308aea1f834b4c586ae1058ca6f67f0315393e4eb632bbb9
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config --auto-gen-only-exclude`
|
|
3
|
-
# on 2022-
|
|
3
|
+
# on 2022-06-08 23:20:02 UTC using RuboCop version 1.28.2.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -35,7 +35,7 @@ Lint/UnusedMethodArgument:
|
|
|
35
35
|
- 'lib/cocina/models/mapping/from_mods/subject.rb'
|
|
36
36
|
- 'lib/cocina/models/mapping/to_mods/event.rb'
|
|
37
37
|
|
|
38
|
-
# Offense count:
|
|
38
|
+
# Offense count: 96
|
|
39
39
|
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
|
|
40
40
|
Metrics/AbcSize:
|
|
41
41
|
Max: 40
|
|
@@ -56,16 +56,17 @@ Metrics/ParameterLists:
|
|
|
56
56
|
RSpec/DescribeClass:
|
|
57
57
|
Enabled: false
|
|
58
58
|
|
|
59
|
-
# Offense count:
|
|
59
|
+
# Offense count: 87
|
|
60
60
|
# Configuration parameters: CountAsOne.
|
|
61
61
|
RSpec/ExampleLength:
|
|
62
62
|
Max: 128
|
|
63
63
|
|
|
64
|
-
# Offense count:
|
|
64
|
+
# Offense count: 10
|
|
65
65
|
# Configuration parameters: Max.
|
|
66
66
|
RSpec/NestedGroups:
|
|
67
67
|
Exclude:
|
|
68
68
|
- 'spec/cocina/models/mapping/normalizers/mods/origin_info_normalizer_spec.rb'
|
|
69
|
+
- 'spec/cocina/models/validators/date_time_validator_spec.rb'
|
|
69
70
|
|
|
70
71
|
# Offense count: 1
|
|
71
72
|
# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals.
|
|
@@ -87,7 +88,7 @@ Style/MultilineBlockChain:
|
|
|
87
88
|
- 'lib/cocina/models/mapping/to_mods/form.rb'
|
|
88
89
|
- 'lib/cocina/models/mapping/to_mods/subject.rb'
|
|
89
90
|
|
|
90
|
-
# Offense count:
|
|
91
|
+
# Offense count: 223
|
|
91
92
|
# This cop supports safe auto-correction (--auto-correct).
|
|
92
93
|
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, IgnoredPatterns.
|
|
93
94
|
# URISchemes: http, https
|
data/cocina-models.gemspec
CHANGED
|
@@ -28,12 +28,15 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
spec.add_dependency 'deprecation'
|
|
29
29
|
spec.add_dependency 'dry-struct', '~> 1.0'
|
|
30
30
|
spec.add_dependency 'dry-types', '~> 1.1'
|
|
31
|
+
spec.add_dependency 'edtf' # used for date/time validation
|
|
31
32
|
spec.add_dependency 'equivalent-xml' # for diffing MODS
|
|
33
|
+
spec.add_dependency 'jsonpath' # used for date/time validation
|
|
32
34
|
spec.add_dependency 'nokogiri'
|
|
33
35
|
spec.add_dependency 'openapi3_parser' # Parsing openapi doc
|
|
34
36
|
# Match these version requirements to what committee wants,
|
|
35
37
|
# so that our client (non-committee) users have the same dependencies.
|
|
36
38
|
spec.add_dependency 'openapi_parser', '>= 0.11.1', '< 1.0'
|
|
39
|
+
spec.add_dependency 'rss' # used for date/time validation
|
|
37
40
|
spec.add_dependency 'super_diff'
|
|
38
41
|
spec.add_dependency 'thor'
|
|
39
42
|
spec.add_dependency 'zeitwerk', '~> 2.1'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cocina
|
|
4
|
+
module Models
|
|
5
|
+
module Mapping
|
|
6
|
+
# Escaps HTML entities as CDATA for MODS since HTML is not permitted in MODS
|
|
7
|
+
class EscapeHtml
|
|
8
|
+
# @param [String] data
|
|
9
|
+
# @param [Nokogiri::XML::Builder]
|
|
10
|
+
def self.with_cdata(data, builder)
|
|
11
|
+
tokens = data.split(%r{(</?(?:i|cite)>)})
|
|
12
|
+
tokens.map do |token|
|
|
13
|
+
if /\A<.+>\z/.match? token
|
|
14
|
+
builder.cdata(token)
|
|
15
|
+
else
|
|
16
|
+
builder.text(token)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'edtf'
|
|
4
|
+
require 'jsonpath'
|
|
5
|
+
require 'rss'
|
|
6
|
+
|
|
7
|
+
module Cocina
|
|
8
|
+
module Models
|
|
9
|
+
module Validators
|
|
10
|
+
# Validates that dates of known types are type-valid
|
|
11
|
+
class DateTimeValidator
|
|
12
|
+
VALIDATABLE_TYPES = %w[edtf iso8601 w3cdtf].freeze
|
|
13
|
+
|
|
14
|
+
def self.validate(_clazz, attributes)
|
|
15
|
+
new(attributes).validate
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize(attributes)
|
|
19
|
+
@attributes = attributes
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def validate
|
|
23
|
+
return unless meets_preconditions?
|
|
24
|
+
|
|
25
|
+
return if invalid_dates.empty?
|
|
26
|
+
|
|
27
|
+
raise ValidationError, "Invalid date(s) for #{druid}: #{invalid_dates}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
attr_reader :attributes
|
|
33
|
+
|
|
34
|
+
def meets_preconditions?
|
|
35
|
+
attributes.key?(:description)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def invalid_dates
|
|
39
|
+
@invalid_dates ||= validatable_dates.filter_map do |date_hash|
|
|
40
|
+
code = date_hash.dig('encoding', 'code')
|
|
41
|
+
bad_values = JsonPath.new('$..value').on(date_hash.to_json).reject do |value|
|
|
42
|
+
send("valid_#{code}?", value)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
next if bad_values.empty?
|
|
46
|
+
|
|
47
|
+
[*bad_values, code]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def validatable_dates
|
|
52
|
+
# Why is the `uniq` needed below? Odd behavior when handling highly nested use cases:
|
|
53
|
+
#
|
|
54
|
+
# > JsonPath.new("$..date..[?(@.encoding.code =~ /#{VALIDATABLE_TYPES.join('|')}/)]").on(attributes[:description].to_json)
|
|
55
|
+
# > [
|
|
56
|
+
# {"structuredValue"=>[{"value"=>"1996", "type"=>"start"}, {"value"=>"1998", "type"=>"end"}], "encoding"=>{"code"=>"iso8601"}},
|
|
57
|
+
# {"structuredValue"=>[{"value"=>"1996", "type"=>"start"}, {"value"=>"1998", "type"=>"end"}], "encoding"=>{"code"=>"iso8601"}}
|
|
58
|
+
# ]
|
|
59
|
+
#
|
|
60
|
+
# Notice how the JSONPath expression returns the *same exact* structure twice despite only being present once in the data.
|
|
61
|
+
JsonPath
|
|
62
|
+
.new("$..date..[?(@.encoding.code =~ /#{VALIDATABLE_TYPES.join('|')}/)]")
|
|
63
|
+
.on(attributes[:description].to_json)
|
|
64
|
+
.uniq
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def valid_edtf?(value)
|
|
68
|
+
Date.edtf!(value)
|
|
69
|
+
true
|
|
70
|
+
rescue StandardError
|
|
71
|
+
false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def valid_iso8601?(value)
|
|
75
|
+
DateTime.iso8601(value)
|
|
76
|
+
true
|
|
77
|
+
rescue StandardError
|
|
78
|
+
false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def valid_w3cdtf?(value)
|
|
82
|
+
Time.w3cdtf(value)
|
|
83
|
+
true
|
|
84
|
+
rescue StandardError
|
|
85
|
+
# NOTE: the upstream W3CDTF implementation in the `rss` gem does not
|
|
86
|
+
# allow two patterns that should be valid per the specification:
|
|
87
|
+
#
|
|
88
|
+
# * YYYY
|
|
89
|
+
# * YYYY-MM
|
|
90
|
+
#
|
|
91
|
+
# So we catch the false positives from the upstream gem and allow
|
|
92
|
+
# these two patterns to validate
|
|
93
|
+
/\A\d{4}(-0[1-9]|1[0-2])?\Z/.match?(value)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def druid
|
|
97
|
+
@druid ||= attributes[:externalIdentifier]
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cocina-models
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.82.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Coyne
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-06-
|
|
11
|
+
date: 2022-06-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -66,6 +66,20 @@ dependencies:
|
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '1.1'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: edtf
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
69
83
|
- !ruby/object:Gem::Dependency
|
|
70
84
|
name: equivalent-xml
|
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -80,6 +94,20 @@ dependencies:
|
|
|
80
94
|
- - ">="
|
|
81
95
|
- !ruby/object:Gem::Version
|
|
82
96
|
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: jsonpath
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :runtime
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
83
111
|
- !ruby/object:Gem::Dependency
|
|
84
112
|
name: nokogiri
|
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -128,6 +156,20 @@ dependencies:
|
|
|
128
156
|
- - "<"
|
|
129
157
|
- !ruby/object:Gem::Version
|
|
130
158
|
version: '1.0'
|
|
159
|
+
- !ruby/object:Gem::Dependency
|
|
160
|
+
name: rss
|
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
|
162
|
+
requirements:
|
|
163
|
+
- - ">="
|
|
164
|
+
- !ruby/object:Gem::Version
|
|
165
|
+
version: '0'
|
|
166
|
+
type: :runtime
|
|
167
|
+
prerelease: false
|
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
169
|
+
requirements:
|
|
170
|
+
- - ">="
|
|
171
|
+
- !ruby/object:Gem::Version
|
|
172
|
+
version: '0'
|
|
131
173
|
- !ruby/object:Gem::Dependency
|
|
132
174
|
name: super_diff
|
|
133
175
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -377,6 +419,7 @@ files:
|
|
|
377
419
|
- lib/cocina/models/location_based_access.rb
|
|
378
420
|
- lib/cocina/models/location_based_download_access.rb
|
|
379
421
|
- lib/cocina/models/mapping/error_notifier.rb
|
|
422
|
+
- lib/cocina/models/mapping/escape_html.rb
|
|
380
423
|
- lib/cocina/models/mapping/from_mods/access.rb
|
|
381
424
|
- lib/cocina/models/mapping/from_mods/admin_metadata.rb
|
|
382
425
|
- lib/cocina/models/mapping/from_mods/alt_rep_group.rb
|
|
@@ -461,6 +504,7 @@ files:
|
|
|
461
504
|
- lib/cocina/models/validators/associated_name_validator.rb
|
|
462
505
|
- lib/cocina/models/validators/catalog_links_validator.rb
|
|
463
506
|
- lib/cocina/models/validators/dark_validator.rb
|
|
507
|
+
- lib/cocina/models/validators/date_time_validator.rb
|
|
464
508
|
- lib/cocina/models/validators/description_types_validator.rb
|
|
465
509
|
- lib/cocina/models/validators/description_values_validator.rb
|
|
466
510
|
- lib/cocina/models/validators/open_api_validator.rb
|
|
@@ -492,7 +536,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
492
536
|
- !ruby/object:Gem::Version
|
|
493
537
|
version: '0'
|
|
494
538
|
requirements: []
|
|
495
|
-
rubygems_version: 3.3.
|
|
539
|
+
rubygems_version: 3.3.7
|
|
496
540
|
signing_key:
|
|
497
541
|
specification_version: 4
|
|
498
542
|
summary: Data models for the SDR
|