json_schemer 1.0.1 → 1.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 460e70448c0b37c65fd4e51f046036336b17121cc716c197fe80f2e2517f45e7
4
- data.tar.gz: f06d11eab9bb88c45a018c8913d6a5d2e33162064c9f995e5772beb811e68ed6
3
+ metadata.gz: '03538ce8b7525466940396aecbfffeac23f2f942af4e11023ea370d73045ec8b'
4
+ data.tar.gz: a06e7a91e8c851dffac5b9ecab91e47b6e89d46173abc8f95619dc4eca7f938d
5
5
  SHA512:
6
- metadata.gz: 83549b328ba3067ed206a8bdea448e34ba274c7c5a7857d38793d74f0691339f845b0e39fdbb0ff8c3869dfbaf0dcd13380c458c80397b100a848f96443bf691
7
- data.tar.gz: 106314824f1805e7d2306c10c696d4503b54b4d9203321e37816242c30598c3870ec40ade53dc08692ec3b2a35f18360c96211f0b8af44fd4414931da4e5b1e5
6
+ metadata.gz: 87f3d572f430bc5b64f25ffc96bf5fcf979fa53eea9e0d325e6d0b853b4f653d2264e151ab312da4e472a02342eb162e9ffdfa3b06c3ec29fa09e39123412f3a
7
+ data.tar.gz: fbbed8f04fea519b2264075051e64a7f6af2ade9b92600a490a2291065ed9a13eb15fb73cf356a0caff5ea3f63065d4c7a50ff93b293441273ed98708429cfe8
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json_schemer (1.0.1)
4
+ json_schemer (1.0.3)
5
5
  hana (~> 1.3)
6
6
  regexp_parser (~> 2.0)
7
7
  simpleidn (~> 0.2)
@@ -13,7 +13,7 @@ GEM
13
13
  hana (1.3.7)
14
14
  minitest (5.15.0)
15
15
  rake (13.0.6)
16
- regexp_parser (2.6.1)
16
+ regexp_parser (2.8.1)
17
17
  simplecov (0.22.0)
18
18
  docile (~> 1.1)
19
19
  simplecov-html (~> 0.11)
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ module JSONSchemer
3
+ module Format
4
+ module Email
5
+ # https://datatracker.ietf.org/doc/html/rfc6531#section-3.3
6
+ # I think this is the same as "UTF8-non-ascii"? (https://datatracker.ietf.org/doc/html/rfc6532#section-3.1)
7
+ UTF8_NON_ASCII = '[^[:ascii:]]'
8
+ # https://datatracker.ietf.org/doc/html/rfc5321#section-4.1.2
9
+ A_TEXT = "([\\w!#$%&'*+\\-/=?\\^`{|}~]|#{UTF8_NON_ASCII})" # atext = ALPHA / DIGIT / ; Printable US-ASCII
10
+ # "!" / "#" / ; characters not including
11
+ # "$" / "%" / ; specials. Used for atoms.
12
+ # "&" / "'" /
13
+ # "*" / "+" /
14
+ # "-" / "/" /
15
+ # "=" / "?" /
16
+ # "^" / "_" /
17
+ # "`" / "{" /
18
+ # "|" / "}" /
19
+ # "~"
20
+ Q_TEXT_SMTP = "([\\x20-\\x21\\x23-\\x5B\\x5D-\\x7E]|#{UTF8_NON_ASCII})" # qtextSMTP = %d32-33 / %d35-91 / %d93-126
21
+ # ; i.e., within a quoted string, any
22
+ # ; ASCII graphic or space is permitted
23
+ # ; without blackslash-quoting except
24
+ # ; double-quote and the backslash itself.
25
+ QUOTED_PAIR_SMTP = '\x5C[\x20-\x7E]' # quoted-pairSMTP = %d92 %d32-126
26
+ # ; i.e., backslash followed by any ASCII
27
+ # ; graphic (including itself) or SPace
28
+ Q_CONTENT_SMTP = "#{Q_TEXT_SMTP}|#{QUOTED_PAIR_SMTP}" # QcontentSMTP = qtextSMTP / quoted-pairSMTP
29
+ QUOTED_STRING = "\"(#{Q_CONTENT_SMTP})*\"" # Quoted-string = DQUOTE *QcontentSMTP DQUOTE
30
+ ATOM = "#{A_TEXT}+" # Atom = 1*atext
31
+ DOT_STRING = "#{ATOM}(\\.#{ATOM})*" # Dot-string = Atom *("." Atom)
32
+ LOCAL_PART = "#{DOT_STRING}|#{QUOTED_STRING}" # Local-part = Dot-string / Quoted-string
33
+ # ; MAY be case-sensitive
34
+ # IPv4-address-literal = Snum 3("." Snum)
35
+ # using `valid_id?` to check ip addresses because it's complicated. # IPv6-address-literal = "IPv6:" IPv6-addr
36
+ ADDRESS_LITERAL = '\[(IPv6:(?<ipv6>[\h:]+)|(?<ipv4>[\d.]+))\]' # address-literal = "[" ( IPv4-address-literal /
37
+ # IPv6-address-literal /
38
+ # General-address-literal ) "]"
39
+ # ; See Section 4.1.3
40
+ # using `valid_hostname?` to check domain because it's complicated
41
+ MAILBOX = "(#{LOCAL_PART})@(#{ADDRESS_LITERAL}|(?<domain>.+))" # Mailbox = Local-part "@" ( Domain / address-literal )
42
+ EMAIL_REGEX = /\A#{MAILBOX}\z/
43
+
44
+ def valid_email?(data)
45
+ return false unless match = EMAIL_REGEX.match(data)
46
+ if ipv4 = match.named_captures.fetch('ipv4')
47
+ valid_ip?(ipv4, Socket::AF_INET)
48
+ elsif ipv6 = match.named_captures.fetch('ipv6')
49
+ valid_ip?(ipv6, Socket::AF_INET6)
50
+ else
51
+ valid_hostname?(match.named_captures.fetch('domain'))
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
  module JSONSchemer
3
3
  module Format
4
+ include Email
4
5
  include Hostname
5
6
  include URITemplate
6
7
 
7
- # this is no good
8
- EMAIL_REGEX = /\A[^@\s]+@([\p{L}\d-]+\.)+[\p{L}\d\-]{2,}\z/i.freeze
9
8
  JSON_POINTER_REGEX_STRING = '(\/([^~\/]|~[01])*)*'
10
9
  JSON_POINTER_REGEX = /\A#{JSON_POINTER_REGEX_STRING}\z/.freeze
11
10
  RELATIVE_JSON_POINTER_REGEX = /\A(0|[1-9]\d*)(#|#{JSON_POINTER_REGEX_STRING})?\z/.freeze
@@ -66,18 +65,12 @@ module JSONSchemer
66
65
  def valid_date_time?(data)
67
66
  return false if HOUR_24_REGEX.match?(data)
68
67
  datetime = DateTime.rfc3339(data)
69
- return false if LEAP_SECOND_REGEX.match?(data) && datetime.to_time.utc.strftime('%H:%M') != '23:59'
68
+ return false if LEAP_SECOND_REGEX.match?(data) && datetime.new_offset.strftime('%H:%M') != '23:59'
70
69
  DATE_TIME_OFFSET_REGEX.match?(data)
71
70
  rescue ArgumentError
72
71
  false
73
72
  end
74
73
 
75
- def valid_email?(data)
76
- return false unless EMAIL_REGEX.match?(data)
77
- local, _domain = data.partition('@')
78
- !local.start_with?('.') && !local.end_with?('.') && !local.include?('..')
79
- end
80
-
81
74
  def valid_ip?(data, family)
82
75
  IPAddr.new(data, family)
83
76
  IP_REGEX.match?(data)
@@ -324,16 +324,16 @@ module JSONSchemer
324
324
  ref_uri.fragment = nil
325
325
  end
326
326
 
327
- ref_object = if ids.key?(ref_uri) || ref_uri.to_s == @base_uri.to_s
327
+ ref_object = if ids.key?(ref_uri) || ref_uri.to_s.empty? || ref_uri.to_s == @base_uri.to_s
328
328
  self
329
329
  else
330
330
  child(resolve_ref(ref_uri), base_uri: ref_uri)
331
331
  end
332
332
 
333
- ref_schema, ref_schema_pointer = ref_object.ids[ref_uri] || [ref_object.root, '']
333
+ ref_schema, ref_schema_pointer, ref_parent_base_uri = ref_object.ids[ref_uri] || [ref_object.root, '', ref_uri]
334
334
 
335
335
  ref_uri_pointer_parts = Hana::Pointer.parse(URI.decode_www_form_component(ref_uri_pointer))
336
- schema, base_uri = ref_uri_pointer_parts.reduce([ref_schema, ref_uri]) do |(obj, uri), token|
336
+ schema, base_uri = ref_uri_pointer_parts.reduce([ref_schema, ref_parent_base_uri]) do |(obj, uri), token|
337
337
  if obj.is_a?(Array)
338
338
  [obj.fetch(token.to_i), uri]
339
339
  else
@@ -646,16 +646,18 @@ module JSONSchemer
646
646
  if schema.is_a?(Array)
647
647
  schema.each_with_index { |subschema, index| resolve_ids(subschema, ids, base_uri, "#{pointer}/#{index}") }
648
648
  elsif schema.is_a?(Hash)
649
- uri = join_uri(base_uri, schema[id_keyword])
649
+ if schema.key?(id_keyword)
650
+ parent_base_uri = base_uri
651
+ base_uri = join_uri(base_uri, schema[id_keyword])
652
+ ids[base_uri] ||= [schema, pointer, parent_base_uri]
653
+ end
650
654
  schema.each do |key, value|
651
655
  case key
652
- when id_keyword
653
- ids[uri] ||= [schema, pointer]
654
656
  when 'items', 'allOf', 'anyOf', 'oneOf', 'additionalItems', 'contains', 'additionalProperties', 'propertyNames', 'if', 'then', 'else', 'not'
655
- resolve_ids(value, ids, uri, "#{pointer}/#{key}")
657
+ resolve_ids(value, ids, base_uri, "#{pointer}/#{key}")
656
658
  when 'properties', 'patternProperties', 'definitions', 'dependencies'
657
659
  value.each do |subkey, subvalue|
658
- resolve_ids(subvalue, ids, uri, "#{pointer}/#{key}/#{subkey}")
660
+ resolve_ids(subvalue, ids, base_uri, "#{pointer}/#{key}/#{subkey}")
659
661
  end
660
662
  end
661
663
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module JSONSchemer
3
- VERSION = '1.0.1'
3
+ VERSION = '1.0.3'
4
4
  end
data/lib/json_schemer.rb CHANGED
@@ -16,6 +16,7 @@ require 'simpleidn'
16
16
  require 'json_schemer/version'
17
17
  require 'json_schemer/format/hostname'
18
18
  require 'json_schemer/format/uri_template'
19
+ require 'json_schemer/format/email'
19
20
  require 'json_schemer/format'
20
21
  require 'json_schemer/errors'
21
22
  require 'json_schemer/cached_resolver'
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: 1.0.1
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Harsha
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-27 00:00:00.000000000 Z
11
+ date: 2023-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -135,6 +135,7 @@ files:
135
135
  - lib/json_schemer/ecma_regexp.rb
136
136
  - lib/json_schemer/errors.rb
137
137
  - lib/json_schemer/format.rb
138
+ - lib/json_schemer/format/email.rb
138
139
  - lib/json_schemer/format/hostname.rb
139
140
  - lib/json_schemer/format/uri_template.rb
140
141
  - lib/json_schemer/schema/base.rb