json_schemer 0.2.20 → 0.2.22

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79ed6f849e3328efd2414b4015f6e1d2d4d897d5aa97400fabf99f0dd5c2dbc5
4
- data.tar.gz: e33eb4f20852cf54fd14d591d2a2cee7892ada8516477e78f605107eebc7a6c8
3
+ metadata.gz: bc9ff5876e71054ee601dc4464c99560e86557796ef792e36512e1f08725a065
4
+ data.tar.gz: 5ee26787348f3aecb1a591c38c7bccc7aaf4166fd14d1299999d426ecaa15893
5
5
  SHA512:
6
- metadata.gz: 611e3e327169b79b74adb979b00fd0e8124ac224c3971bb7f02dfc8040c17024720f4bd0308428eaa79c138c5ab461cb06ae9ea12b122ca4ed75ad0e396804bd
7
- data.tar.gz: ee237ca11f77f20aa4d1dd7a1c192744019abfddcaeebaf5e1c0e63ebdf53eb15fc1a3c52a3f34af9bee41f868b28f0f2ae1e131476880d46177ad10be5c4ea8
6
+ metadata.gz: 9b5dc77e4a136d9dd7ab774e530880188c3125647535707d67b9b09e615e538bfe826249fd53644d3dc452e8387667bc74a3e24ec21f847145bc4b92de15371d
7
+ data.tar.gz: 160ead197e1f0a61090e936a526e4753156b185e4049db6d5ca7efb9c8bbf4430ebd9a0eff952299fc5bdb0b93a063745d9be3e919bee80ce93c05864a9655b7
@@ -23,4 +23,9 @@ jobs:
23
23
  with:
24
24
  ruby-version: ${{ matrix.ruby }}
25
25
  bundler-cache: true
26
- - run: bundle exec rake test
26
+ - run: |
27
+ mkdir -p tmp/gems
28
+ gem build json_schemer.gemspec
29
+ gem install --local --ignore-dependencies --no-document --install-dir tmp/gems json_schemer-*.gem
30
+ rm json_schemer-*.gem
31
+ bin/rake test
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json_schemer (0.2.20)
4
+ json_schemer (0.2.22)
5
5
  ecma-re-validator (~> 0.3)
6
6
  hana (~> 1.3)
7
7
  regexp_parser (~> 2.0)
@@ -13,9 +13,9 @@ GEM
13
13
  ecma-re-validator (0.3.0)
14
14
  regexp_parser (~> 2.0)
15
15
  hana (1.3.7)
16
- minitest (5.14.3)
17
- rake (13.0.1)
18
- regexp_parser (2.1.1)
16
+ minitest (5.15.0)
17
+ rake (13.0.6)
18
+ regexp_parser (2.3.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.2.11
31
+ 2.3.11
data/README.md CHANGED
@@ -110,10 +110,41 @@ JSONSchemer.schema(
110
110
  # 'net/http'/proc/lambda/respond_to?(:call)
111
111
  # 'net/http': proc { |uri| JSON.parse(Net::HTTP.get(uri)) }
112
112
  # default: proc { |uri| raise UnknownRef, uri.to_s }
113
- ref_resolver: 'net/http'
113
+ ref_resolver: 'net/http',
114
+
115
+ # use different method to match regexes
116
+ # 'ecma'/'ruby'/proc/lambda/respond_to?(:call)
117
+ # default: 'ecma'
118
+ regexp_resolver: proc do |pattern|
119
+ RE2::Regexp.new(pattern)
120
+ end
114
121
  )
115
122
  ```
116
123
 
124
+ ## CLI
125
+
126
+ The `json_schemer` executable takes a JSON schema file as the first argument followed by one or more JSON data files to validate. If there are any validation errors, it outputs them and returns an error code.
127
+
128
+ Validation errors are output as single-line JSON objects. The `--errors` option can be used to limit the number of errors returned or prevent output entirely (and fail fast).
129
+
130
+ The schema or data can also be read from stdin using `-`.
131
+
132
+ ```
133
+ % json_schemer --help
134
+ Usage:
135
+ json_schemer [options] <schema> <data>...
136
+ json_schemer [options] <schema> -
137
+ json_schemer [options] - <data>...
138
+ json_schemer -h | --help
139
+ json_schemer --version
140
+
141
+ Options:
142
+ -e, --errors MAX Maximum number of errors to output
143
+ Use "0" to validate with no output
144
+ -h, --help Show help
145
+ -v, --version Show version
146
+ ```
147
+
117
148
  ## Development
118
149
 
119
150
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/bin/rake ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rake", "rake")
data/exe/json_schemer ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'json'
4
+ require 'optparse'
5
+ require 'pathname'
6
+ require 'json_schemer'
7
+
8
+ parser = OptionParser.new('Usage:', 32, ' ')
9
+ parser.separator(" #{parser.program_name} [options] <schema> <data>...")
10
+ parser.separator(" #{parser.program_name} [options] <schema> -")
11
+ parser.separator(" #{parser.program_name} [options] - <data>...")
12
+ parser.separator(" #{parser.program_name} -h | --help")
13
+ parser.separator(" #{parser.program_name} --version")
14
+ parser.separator('')
15
+ parser.separator('Options:')
16
+ parser.on('-e', '--errors MAX', Integer, 'Maximum number of errors to output', 'Use "0" to validate with no output')
17
+ parser.on_tail('-h', '--help', 'Show help')
18
+ parser.on_tail('-v', '--version', 'Show version')
19
+
20
+ options = {}
21
+ parser.parse!(:into => options)
22
+
23
+ if options[:help]
24
+ $stdout.puts(parser)
25
+ exit
26
+ end
27
+
28
+ if options[:version]
29
+ $stdout.puts("#{parser.program_name} #{JSONSchemer::VERSION}")
30
+ exit
31
+ end
32
+
33
+ if ARGV.size == 0
34
+ $stderr.puts("#{parser.program_name}: no schema or data")
35
+ exit(false)
36
+ end
37
+
38
+ if ARGV.size == 1
39
+ $stderr.puts("#{parser.program_name}: no data")
40
+ exit(false)
41
+ end
42
+
43
+ if ARGV.count('-') > 1
44
+ $stderr.puts("#{parser.program_name}: multiple stdin")
45
+ exit(false)
46
+ end
47
+
48
+ errors = 0
49
+ schema = ARGF.file.is_a?(File) ? Pathname.new(ARGF.file.path) : ARGF.file.read
50
+ schemer = JSONSchemer.schema(schema)
51
+
52
+ while ARGV.any?
53
+ data = JSON.parse(ARGF.skip.file.read)
54
+ schemer.validate(data).each do |error|
55
+ exit(false) if options[:errors] == 0
56
+ errors += 1
57
+ $stdout.puts(JSON.generate(error))
58
+ exit(false) if options[:errors] == errors
59
+ end
60
+ end
61
+
62
+ exit(errors.zero?)
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ module JSONSchemer
3
+ class CachedResolver
4
+ def initialize(&resolver)
5
+ @resolver = resolver
6
+ @cache = {}
7
+ end
8
+
9
+ def call(*args)
10
+ @cache[args] = @resolver.call(*args) unless @cache.key?(args)
11
+ @cache[args]
12
+ end
13
+ end
14
+
15
+ class CachedRefResolver < CachedResolver; end
16
+ end
@@ -60,7 +60,7 @@ module JSONSchemer
60
60
  def valid_date_time?(data)
61
61
  DateTime.rfc3339(data)
62
62
  DATE_TIME_OFFSET_REGEX.match?(data)
63
- rescue ArgumentError => e
63
+ rescue ArgumentError
64
64
  false
65
65
  end
66
66
 
@@ -30,6 +30,14 @@ module JSONSchemer
30
30
  :eol => '\z'
31
31
  }.freeze
32
32
 
33
+ ECMA_262_REGEXP_RESOLVER = proc do |pattern|
34
+ Regexp.new(
35
+ Regexp::Scanner.scan(pattern).map do |type, token, text|
36
+ type == :anchor ? RUBY_REGEX_ANCHORS_TO_ECMA_262.fetch(token, text) : text
37
+ end.join
38
+ )
39
+ end
40
+
33
41
  INSERT_DEFAULT_PROPERTY = proc do |data, property, property_schema, _parent|
34
42
  if !data.key?(property) && property_schema.is_a?(Hash) && property_schema.key?('default')
35
43
  data[property] = property_schema.fetch('default').clone
@@ -44,7 +52,8 @@ module JSONSchemer
44
52
  after_property_validation: nil,
45
53
  formats: nil,
46
54
  keywords: nil,
47
- ref_resolver: DEFAULT_REF_RESOLVER
55
+ ref_resolver: DEFAULT_REF_RESOLVER,
56
+ regexp_resolver: 'ecma'
48
57
  )
49
58
  raise InvalidSymbolKey, 'schemas must use string keys' if schema.is_a?(Hash) && !schema.empty? && !schema.first.first.is_a?(String)
50
59
  @root = schema
@@ -54,7 +63,15 @@ module JSONSchemer
54
63
  @after_property_validation = [*after_property_validation]
55
64
  @formats = formats
56
65
  @keywords = keywords
57
- @ref_resolver = ref_resolver == 'net/http' ? CachedRefResolver.new(&NET_HTTP_REF_RESOLVER) : ref_resolver
66
+ @ref_resolver = ref_resolver == 'net/http' ? CachedResolver.new(&NET_HTTP_REF_RESOLVER) : ref_resolver
67
+ @regexp_resolver = case regexp_resolver
68
+ when 'ecma'
69
+ CachedResolver.new(&ECMA_262_REGEXP_RESOLVER)
70
+ when 'ruby'
71
+ CachedResolver.new(&Regexp.method(:new))
72
+ else
73
+ regexp_resolver
74
+ end
58
75
  end
59
76
 
60
77
  def valid?(data)
@@ -204,7 +221,7 @@ module JSONSchemer
204
221
 
205
222
  private
206
223
 
207
- attr_reader :root, :formats, :keywords, :ref_resolver
224
+ attr_reader :root, :formats, :keywords, :ref_resolver, :regexp_resolver
208
225
 
209
226
  def id_keyword
210
227
  ID_KEYWORD
@@ -228,7 +245,8 @@ module JSONSchemer
228
245
  format: format?,
229
246
  formats: formats,
230
247
  keywords: keywords,
231
- ref_resolver: ref_resolver
248
+ ref_resolver: ref_resolver,
249
+ regexp_resolver: regexp_resolver
232
250
  )
233
251
  end
234
252
 
@@ -398,7 +416,7 @@ module JSONSchemer
398
416
 
399
417
  yield error(instance, 'maxLength') if max_length && data.size > max_length
400
418
  yield error(instance, 'minLength') if min_length && data.size < min_length
401
- yield error(instance, 'pattern') if pattern && ecma_262_regex(pattern) !~ data
419
+ yield error(instance, 'pattern') if pattern && resolve_regexp(pattern) !~ data
402
420
  yield error(instance, 'format') if format? && spec_format?(format) && !valid_spec_format?(data, format)
403
421
 
404
422
  if content_encoding || content_media_type
@@ -551,7 +569,7 @@ module JSONSchemer
551
569
 
552
570
  if pattern_properties
553
571
  regex_pattern_properties ||= pattern_properties.map do |pattern, property_schema|
554
- [pattern, ecma_262_regex(pattern), property_schema]
572
+ [pattern, resolve_regexp(pattern), property_schema]
555
573
  end
556
574
  regex_pattern_properties.each do |pattern, regex, property_schema|
557
575
  if regex.match?(key)
@@ -596,15 +614,6 @@ module JSONSchemer
596
614
  nil
597
615
  end
598
616
 
599
- def ecma_262_regex(pattern)
600
- @ecma_262_regex ||= {}
601
- @ecma_262_regex[pattern] ||= Regexp.new(
602
- Regexp::Scanner.scan(pattern).map do |type, token, text|
603
- type == :anchor ? RUBY_REGEX_ANCHORS_TO_ECMA_262.fetch(token, text) : text
604
- end.join
605
- )
606
- end
607
-
608
617
  def join_uri(a, b)
609
618
  b = URI.parse(b) if b
610
619
  if a && b && a.relative? && b.relative?
@@ -652,6 +661,10 @@ module JSONSchemer
652
661
  def resolve_ref(uri)
653
662
  ref_resolver.call(uri) || raise(InvalidRefResolution, uri.to_s)
654
663
  end
664
+
665
+ def resolve_regexp(pattern)
666
+ regexp_resolver.call(pattern) || raise(InvalidRegexpResolution, pattern)
667
+ end
655
668
  end
656
669
  end
657
670
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module JSONSchemer
3
- VERSION = '0.2.20'
3
+ VERSION = '0.2.22'
4
4
  end
data/lib/json_schemer.rb CHANGED
@@ -17,7 +17,7 @@ require 'uri_template'
17
17
  require 'json_schemer/version'
18
18
  require 'json_schemer/format'
19
19
  require 'json_schemer/errors'
20
- require 'json_schemer/cached_ref_resolver'
20
+ require 'json_schemer/cached_resolver'
21
21
  require 'json_schemer/schema/base'
22
22
  require 'json_schemer/schema/draft4'
23
23
  require 'json_schemer/schema/draft6'
@@ -27,6 +27,7 @@ module JSONSchemer
27
27
  class UnsupportedMetaSchema < StandardError; end
28
28
  class UnknownRef < StandardError; end
29
29
  class InvalidRefResolution < StandardError; end
30
+ class InvalidRegexpResolution < StandardError; end
30
31
  class InvalidFileURI < StandardError; end
31
32
  class InvalidSymbolKey < StandardError; end
32
33
 
@@ -46,7 +47,7 @@ module JSONSchemer
46
47
  raise InvalidFileURI, 'cannot have a host (use `file:///`)' if uri.host && !uri.host.empty?
47
48
  path = uri.path
48
49
  path = path[1..-1] if path.match?(WINDOWS_URI_PATH_REGEX)
49
- JSON.parse(File.read(path))
50
+ JSON.parse(File.read(URI::DEFAULT_PARSER.unescape(path)))
50
51
  end
51
52
 
52
53
  class << self
@@ -55,11 +56,11 @@ module JSONSchemer
55
56
  when String
56
57
  schema = JSON.parse(schema)
57
58
  when Pathname
58
- uri = URI.parse(File.join('file:', schema.realpath))
59
+ uri = URI.parse(File.join('file:', URI::DEFAULT_PARSER.escape(schema.realpath.to_s)))
59
60
  if options.key?(:ref_resolver)
60
61
  schema = FILE_URI_REF_RESOLVER.call(uri)
61
62
  else
62
- ref_resolver = CachedRefResolver.new(&FILE_URI_REF_RESOLVER)
63
+ ref_resolver = CachedResolver.new(&FILE_URI_REF_RESOLVER)
63
64
  schema = ref_resolver.call(uri)
64
65
  options[:ref_resolver] = ref_resolver
65
66
  end
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.20
4
+ version: 0.2.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Harsha
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-01 00:00:00.000000000 Z
11
+ date: 2022-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,10 +108,11 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '2.0'
111
- description:
111
+ description:
112
112
  email:
113
113
  - davishmcclurg@gmail.com
114
- executables: []
114
+ executables:
115
+ - json_schemer
115
116
  extensions: []
116
117
  extra_rdoc_files: []
117
118
  files:
@@ -123,10 +124,12 @@ files:
123
124
  - README.md
124
125
  - Rakefile
125
126
  - bin/console
127
+ - bin/rake
126
128
  - bin/setup
129
+ - exe/json_schemer
127
130
  - json_schemer.gemspec
128
131
  - lib/json_schemer.rb
129
- - lib/json_schemer/cached_ref_resolver.rb
132
+ - lib/json_schemer/cached_resolver.rb
130
133
  - lib/json_schemer/errors.rb
131
134
  - lib/json_schemer/format.rb
132
135
  - lib/json_schemer/schema/base.rb
@@ -138,7 +141,7 @@ homepage: https://github.com/davishmcclurg/json_schemer
138
141
  licenses:
139
142
  - MIT
140
143
  metadata: {}
141
- post_install_message:
144
+ post_install_message:
142
145
  rdoc_options: []
143
146
  require_paths:
144
147
  - lib
@@ -153,8 +156,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
156
  - !ruby/object:Gem::Version
154
157
  version: '0'
155
158
  requirements: []
156
- rubygems_version: 3.1.4
157
- signing_key:
159
+ rubygems_version: 3.3.7
160
+ signing_key:
158
161
  specification_version: 4
159
162
  summary: JSON Schema validator. Supports drafts 4, 6, and 7.
160
163
  test_files: []
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
- module JSONSchemer
3
- class CachedRefResolver
4
- def initialize(&ref_resolver)
5
- @ref_resolver = ref_resolver
6
- @cache = {}
7
- end
8
-
9
- def call(uri)
10
- @cache[uri] = @ref_resolver.call(uri) unless @cache.key?(uri)
11
- @cache[uri]
12
- end
13
- end
14
- end