json_schemer 0.2.13 → 0.2.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +18 -9
- data/Gemfile.lock +9 -9
- data/README.md +14 -0
- data/json_schemer.gemspec +3 -3
- data/lib/json_schemer.rb +6 -2
- data/lib/json_schemer/format.rb +9 -3
- data/lib/json_schemer/schema/base.rb +42 -21
- data/lib/json_schemer/version.rb +1 -1
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 426a95173deee91594b5ad1df05dac15ea3c90bac6e17b3136a7170744555c50
|
4
|
+
data.tar.gz: 25268e7f5cb108245aad3d112624eee96774fe8820eda5e24a4f91d97d91e676
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5534a623dfece170bd27bbb2cbc34978e9e81c075ddad60213d8ce4538d50a6ee119b7efcb2b750068cee0cf565ee582a35eac990c14c2ca647d9d8cc314d4f5
|
7
|
+
data.tar.gz: b813c1b1acd0b1cf0680bf0ecae7eef33b6eb576ff5735d76f072e82fc5cfb36e80ec5b0a3fde6829ec3de856e903b42164a917b833019c33a11d79d6db6080b
|
data/.github/workflows/ci.yml
CHANGED
@@ -1,17 +1,26 @@
|
|
1
1
|
name: ci
|
2
2
|
on: [push, pull_request]
|
3
3
|
jobs:
|
4
|
-
|
4
|
+
test:
|
5
5
|
strategy:
|
6
|
+
fail-fast: false
|
6
7
|
matrix:
|
7
|
-
|
8
|
-
|
8
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
9
|
+
ruby: [2.4, 2.5, 2.6, 2.7, 3.0, head, jruby, jruby-head, truffleruby, truffleruby-head]
|
10
|
+
exclude:
|
11
|
+
- os: windows-latest
|
12
|
+
ruby: jruby
|
13
|
+
- os: windows-latest
|
14
|
+
ruby: jruby-head
|
15
|
+
- os: windows-latest
|
16
|
+
ruby: truffleruby
|
17
|
+
- os: windows-latest
|
18
|
+
ruby: truffleruby-head
|
19
|
+
runs-on: ${{ matrix.os }}
|
9
20
|
steps:
|
10
|
-
- uses: actions/checkout@
|
11
|
-
- uses:
|
21
|
+
- uses: actions/checkout@v2
|
22
|
+
- uses: ruby/setup-ruby@v1
|
12
23
|
with:
|
13
24
|
ruby-version: ${{ matrix.ruby }}
|
14
|
-
|
15
|
-
|
16
|
-
bundle install
|
17
|
-
bundle exec rake test
|
25
|
+
bundler-cache: true
|
26
|
+
- run: bundle exec rake test
|
data/Gemfile.lock
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
json_schemer (0.2.
|
5
|
-
ecma-re-validator (~> 0.
|
4
|
+
json_schemer (0.2.18)
|
5
|
+
ecma-re-validator (~> 0.3)
|
6
6
|
hana (~> 1.3)
|
7
|
-
regexp_parser (~>
|
7
|
+
regexp_parser (~> 2.0)
|
8
8
|
uri_template (~> 0.7)
|
9
9
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
ecma-re-validator (0.
|
14
|
-
regexp_parser (~>
|
15
|
-
hana (1.3.
|
16
|
-
minitest (5.
|
13
|
+
ecma-re-validator (0.3.0)
|
14
|
+
regexp_parser (~> 2.0)
|
15
|
+
hana (1.3.7)
|
16
|
+
minitest (5.14.3)
|
17
17
|
rake (13.0.1)
|
18
|
-
regexp_parser (1.
|
18
|
+
regexp_parser (2.1.1)
|
19
19
|
uri_template (0.7.0)
|
20
20
|
|
21
21
|
PLATFORMS
|
@@ -28,4 +28,4 @@ DEPENDENCIES
|
|
28
28
|
rake (~> 13.0)
|
29
29
|
|
30
30
|
BUNDLED WITH
|
31
|
-
2.
|
31
|
+
2.2.11
|
data/README.md
CHANGED
@@ -92,6 +92,20 @@ JSONSchemer.schema(
|
|
92
92
|
# default: false
|
93
93
|
insert_property_defaults: true,
|
94
94
|
|
95
|
+
# modify properties during validation. You can pass one Proc or a list of Procs to modify data.
|
96
|
+
# Proc/[Proc]
|
97
|
+
# default: nil
|
98
|
+
before_property_validation: proc do |data, property, property_schema, _parent|
|
99
|
+
data[property] ||= 42
|
100
|
+
end,
|
101
|
+
|
102
|
+
# modify properties after validation. You can pass one Proc or a list of Procs to modify data.
|
103
|
+
# Proc/[Proc]
|
104
|
+
# default: nil
|
105
|
+
after_property_validation: proc do |data, property, property_schema, _parent|
|
106
|
+
data[property] = Date.iso8601(data[property]) if property_schema.is_a?(Hash) && property_schema['format'] == 'date'
|
107
|
+
end,
|
108
|
+
|
95
109
|
# resolve external references
|
96
110
|
# 'net/http'/proc/lambda/respond_to?(:call)
|
97
111
|
# 'net/http': proc { |uri| JSON.parse(Net::HTTP.get(uri)) }
|
data/json_schemer.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.required_ruby_version = '
|
23
|
+
spec.required_ruby_version = '>= 2.4'
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 2.0"
|
26
26
|
spec.add_development_dependency "rake", "~> 13.0"
|
@@ -34,8 +34,8 @@ Gem::Specification.new do |spec|
|
|
34
34
|
# spec.add_development_dependency "jsonschema", "~> 2.0.2"
|
35
35
|
# spec.add_development_dependency "rj_schema", "~> 0.2.0"
|
36
36
|
|
37
|
-
spec.add_runtime_dependency "ecma-re-validator", "~> 0.
|
37
|
+
spec.add_runtime_dependency "ecma-re-validator", "~> 0.3"
|
38
38
|
spec.add_runtime_dependency "hana", "~> 1.3"
|
39
39
|
spec.add_runtime_dependency "uri_template", "~> 0.7"
|
40
|
-
spec.add_runtime_dependency "regexp_parser", "~>
|
40
|
+
spec.add_runtime_dependency "regexp_parser", "~> 2.0"
|
41
41
|
end
|
data/lib/json_schemer.rb
CHANGED
@@ -37,10 +37,14 @@ module JSONSchemer
|
|
37
37
|
|
38
38
|
DEFAULT_META_SCHEMA = 'http://json-schema.org/draft-07/schema#'
|
39
39
|
|
40
|
+
WINDOWS_URI_PATH_REGEX = /\A\/[a-z]:/i
|
41
|
+
|
40
42
|
FILE_URI_REF_RESOLVER = proc do |uri|
|
41
43
|
raise InvalidFileURI, 'must use `file` scheme' unless uri.scheme == 'file'
|
42
44
|
raise InvalidFileURI, 'cannot have a host (use `file:///`)' if uri.host && !uri.host.empty?
|
43
|
-
|
45
|
+
path = uri.path
|
46
|
+
path = path[1..-1] if path.match?(WINDOWS_URI_PATH_REGEX)
|
47
|
+
JSON.parse(File.read(path))
|
44
48
|
end
|
45
49
|
|
46
50
|
class << self
|
@@ -49,7 +53,7 @@ module JSONSchemer
|
|
49
53
|
when String
|
50
54
|
schema = JSON.parse(schema)
|
51
55
|
when Pathname
|
52
|
-
uri = URI.parse(
|
56
|
+
uri = URI.parse(File.join('file:', schema.realpath))
|
53
57
|
if options.key?(:ref_resolver)
|
54
58
|
schema = FILE_URI_REF_RESOLVER.call(uri)
|
55
59
|
else
|
data/lib/json_schemer/format.rb
CHANGED
@@ -3,7 +3,7 @@ module JSONSchemer
|
|
3
3
|
module Format
|
4
4
|
# this is no good
|
5
5
|
EMAIL_REGEX = /\A[^@\s]+@([\p{L}\d-]+\.)+[\p{L}\d\-]{2,}\z/i.freeze
|
6
|
-
LABEL_REGEX_STRING = '\p{L}([\p{L}\p{N}\-]*[\p{L}\p{N}])?'
|
6
|
+
LABEL_REGEX_STRING = '[\p{L}\p{N}]([\p{L}\p{N}\-]*[\p{L}\p{N}])?'
|
7
7
|
HOSTNAME_REGEX = /\A(#{LABEL_REGEX_STRING}\.)*#{LABEL_REGEX_STRING}\z/i.freeze
|
8
8
|
JSON_POINTER_REGEX_STRING = '(\/([^~\/]|~[01])*)*'
|
9
9
|
JSON_POINTER_REGEX = /\A#{JSON_POINTER_REGEX_STRING}\z/.freeze
|
@@ -61,7 +61,6 @@ module JSONSchemer
|
|
61
61
|
DateTime.rfc3339(data)
|
62
62
|
DATE_TIME_OFFSET_REGEX.match?(data)
|
63
63
|
rescue ArgumentError => e
|
64
|
-
raise e unless e.message == 'invalid date'
|
65
64
|
false
|
66
65
|
end
|
67
66
|
|
@@ -101,7 +100,14 @@ module JSONSchemer
|
|
101
100
|
end
|
102
101
|
|
103
102
|
def iri_escape(data)
|
104
|
-
|
103
|
+
data.gsub(/[^[:ascii:]]/) do |match|
|
104
|
+
us = match
|
105
|
+
tmp = +''
|
106
|
+
us.each_byte do |uc|
|
107
|
+
tmp << sprintf('%%%02X', uc)
|
108
|
+
end
|
109
|
+
tmp
|
110
|
+
end.force_encoding(Encoding::US_ASCII)
|
105
111
|
end
|
106
112
|
|
107
113
|
def valid_uri_template?(data)
|
@@ -4,16 +4,17 @@ module JSONSchemer
|
|
4
4
|
class Base
|
5
5
|
include Format
|
6
6
|
|
7
|
-
Instance = Struct.new(:data, :data_pointer, :schema, :schema_pointer, :parent_uri, :
|
7
|
+
Instance = Struct.new(:data, :data_pointer, :schema, :schema_pointer, :parent_uri, :before_property_validation, :after_property_validation) do
|
8
8
|
def merge(
|
9
9
|
data: self.data,
|
10
10
|
data_pointer: self.data_pointer,
|
11
11
|
schema: self.schema,
|
12
12
|
schema_pointer: self.schema_pointer,
|
13
13
|
parent_uri: self.parent_uri,
|
14
|
-
|
14
|
+
before_property_validation: self.before_property_validation,
|
15
|
+
after_property_validation: self.after_property_validation
|
15
16
|
)
|
16
|
-
self.class.new(data, data_pointer, schema, schema_pointer, parent_uri,
|
17
|
+
self.class.new(data, data_pointer, schema, schema_pointer, parent_uri, before_property_validation, after_property_validation)
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -29,10 +30,18 @@ module JSONSchemer
|
|
29
30
|
:eol => '\z'
|
30
31
|
}.freeze
|
31
32
|
|
33
|
+
INSERT_DEFAULT_PROPERTY = proc do |data, property, property_schema, _parent|
|
34
|
+
if !data.key?(property) && property_schema.is_a?(Hash) && property_schema.key?('default')
|
35
|
+
data[property] = property_schema.fetch('default').clone
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
32
39
|
def initialize(
|
33
40
|
schema,
|
34
41
|
format: true,
|
35
42
|
insert_property_defaults: false,
|
43
|
+
before_property_validation: nil,
|
44
|
+
after_property_validation: nil,
|
36
45
|
formats: nil,
|
37
46
|
keywords: nil,
|
38
47
|
ref_resolver: DEFAULT_REF_RESOLVER
|
@@ -40,18 +49,20 @@ module JSONSchemer
|
|
40
49
|
raise InvalidSymbolKey, 'schemas must use string keys' if schema.is_a?(Hash) && !schema.empty? && !schema.first.first.is_a?(String)
|
41
50
|
@root = schema
|
42
51
|
@format = format
|
43
|
-
@
|
52
|
+
@before_property_validation = [*before_property_validation]
|
53
|
+
@before_property_validation.unshift(INSERT_DEFAULT_PROPERTY) if insert_property_defaults
|
54
|
+
@after_property_validation = [*after_property_validation]
|
44
55
|
@formats = formats
|
45
56
|
@keywords = keywords
|
46
57
|
@ref_resolver = ref_resolver == 'net/http' ? CachedRefResolver.new(&NET_HTTP_REF_RESOLVER) : ref_resolver
|
47
58
|
end
|
48
59
|
|
49
60
|
def valid?(data)
|
50
|
-
valid_instance?(Instance.new(data, '', root, '', nil,
|
61
|
+
valid_instance?(Instance.new(data, '', root, '', nil, @before_property_validation, @after_property_validation))
|
51
62
|
end
|
52
63
|
|
53
64
|
def validate(data)
|
54
|
-
validate_instance(Instance.new(data, '', root, '', nil,
|
65
|
+
validate_instance(Instance.new(data, '', root, '', nil, @before_property_validation, @after_property_validation))
|
55
66
|
end
|
56
67
|
|
57
68
|
protected
|
@@ -101,7 +112,7 @@ module JSONSchemer
|
|
101
112
|
if keywords
|
102
113
|
keywords.each do |keyword, callable|
|
103
114
|
if schema.key?(keyword)
|
104
|
-
result = callable.call(data, schema, instance.
|
115
|
+
result = callable.call(data, schema, instance.data_pointer)
|
105
116
|
if result.is_a?(Array)
|
106
117
|
result.each(&block)
|
107
118
|
elsif !result
|
@@ -119,7 +130,8 @@ module JSONSchemer
|
|
119
130
|
subinstance = instance.merge(
|
120
131
|
schema: subschema,
|
121
132
|
schema_pointer: "#{instance.schema_pointer}/allOf/#{index}",
|
122
|
-
|
133
|
+
before_property_validation: false,
|
134
|
+
after_property_validation: false
|
123
135
|
)
|
124
136
|
validate_instance(subinstance, &block)
|
125
137
|
end
|
@@ -130,7 +142,8 @@ module JSONSchemer
|
|
130
142
|
subinstance = instance.merge(
|
131
143
|
schema: subschema,
|
132
144
|
schema_pointer: "#{instance.schema_pointer}/anyOf/#{index}",
|
133
|
-
|
145
|
+
before_property_validation: false,
|
146
|
+
after_property_validation: false
|
134
147
|
)
|
135
148
|
validate_instance(subinstance)
|
136
149
|
end
|
@@ -142,7 +155,8 @@ module JSONSchemer
|
|
142
155
|
subinstance = instance.merge(
|
143
156
|
schema: subschema,
|
144
157
|
schema_pointer: "#{instance.schema_pointer}/oneOf/#{index}",
|
145
|
-
|
158
|
+
before_property_validation: false,
|
159
|
+
after_property_validation: false
|
146
160
|
)
|
147
161
|
validate_instance(subinstance)
|
148
162
|
end
|
@@ -158,12 +172,13 @@ module JSONSchemer
|
|
158
172
|
subinstance = instance.merge(
|
159
173
|
schema: not_schema,
|
160
174
|
schema_pointer: "#{instance.schema_pointer}/not",
|
161
|
-
|
175
|
+
before_property_validation: false,
|
176
|
+
after_property_validation: false
|
162
177
|
)
|
163
178
|
yield error(subinstance, 'not') if valid_instance?(subinstance)
|
164
179
|
end
|
165
180
|
|
166
|
-
if if_schema && valid_instance?(instance.merge(schema: if_schema,
|
181
|
+
if if_schema && valid_instance?(instance.merge(schema: if_schema, before_property_validation: false, after_property_validation: false))
|
167
182
|
validate_instance(instance.merge(schema: then_schema, schema_pointer: "#{instance.schema_pointer}/then"), &block) unless then_schema.nil?
|
168
183
|
elsif if_schema
|
169
184
|
validate_instance(instance.merge(schema: else_schema, schema_pointer: "#{instance.schema_pointer}/else"), &block) unless else_schema.nil?
|
@@ -487,10 +502,10 @@ module JSONSchemer
|
|
487
502
|
dependencies = schema['dependencies']
|
488
503
|
property_names = schema['propertyNames']
|
489
504
|
|
490
|
-
if instance.
|
505
|
+
if instance.before_property_validation && properties
|
491
506
|
properties.each do |property, property_schema|
|
492
|
-
|
493
|
-
data
|
507
|
+
instance.before_property_validation.each do |hook|
|
508
|
+
hook.call(data, property, property_schema, schema)
|
494
509
|
end
|
495
510
|
end
|
496
511
|
end
|
@@ -565,15 +580,21 @@ module JSONSchemer
|
|
565
580
|
validate_instance(subinstance, &block)
|
566
581
|
end
|
567
582
|
end
|
583
|
+
|
584
|
+
if instance.after_property_validation && properties
|
585
|
+
properties.each do |property, property_schema|
|
586
|
+
instance.after_property_validation.each do |hook|
|
587
|
+
hook.call(data, property, property_schema, schema)
|
588
|
+
end
|
589
|
+
end
|
590
|
+
end
|
568
591
|
end
|
569
592
|
|
570
593
|
def safe_strict_decode64(data)
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
nil
|
576
|
-
end
|
594
|
+
Base64.strict_decode64(data)
|
595
|
+
rescue ArgumentError => e
|
596
|
+
raise e unless e.message == 'invalid base64'
|
597
|
+
nil
|
577
598
|
end
|
578
599
|
|
579
600
|
def ecma_262_regex(pattern)
|
data/lib/json_schemer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_schemer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Harsha
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0.
|
61
|
+
version: '0.3'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0.
|
68
|
+
version: '0.3'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: hana
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '2.0'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
110
|
+
version: '2.0'
|
111
111
|
description:
|
112
112
|
email:
|
113
113
|
- davishmcclurg@gmail.com
|
@@ -144,17 +144,16 @@ require_paths:
|
|
144
144
|
- lib
|
145
145
|
required_ruby_version: !ruby/object:Gem::Requirement
|
146
146
|
requirements:
|
147
|
-
- - "
|
147
|
+
- - ">="
|
148
148
|
- !ruby/object:Gem::Version
|
149
|
-
version: '2.
|
149
|
+
version: '2.4'
|
150
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
151
|
requirements:
|
152
152
|
- - ">="
|
153
153
|
- !ruby/object:Gem::Version
|
154
154
|
version: '0'
|
155
155
|
requirements: []
|
156
|
-
|
157
|
-
rubygems_version: 2.7.6
|
156
|
+
rubygems_version: 3.1.4
|
158
157
|
signing_key:
|
159
158
|
specification_version: 4
|
160
159
|
summary: JSON Schema validator. Supports drafts 4, 6, and 7.
|