schemurai 3.1.0-aarch64-linux-gnu

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +395 -0
  4. data/lib/schemurai/backend.rb +34 -0
  5. data/lib/schemurai/container_checks/array_diagnostics.rb +119 -0
  6. data/lib/schemurai/container_checks/object_diagnostics.rb +152 -0
  7. data/lib/schemurai/container_checks.rb +534 -0
  8. data/lib/schemurai/decimal.rb +11 -0
  9. data/lib/schemurai/dialect.rb +106 -0
  10. data/lib/schemurai/dialect_keywords.rb +91 -0
  11. data/lib/schemurai/dialects/draft2019_09.rb +27 -0
  12. data/lib/schemurai/dialects/draft2020_12.rb +27 -0
  13. data/lib/schemurai/dialects/draft7.rb +27 -0
  14. data/lib/schemurai/ecma_regexp.rb +46 -0
  15. data/lib/schemurai/error_message.rb +102 -0
  16. data/lib/schemurai/evaluation.rb +63 -0
  17. data/lib/schemurai/evaluation_limits.rb +65 -0
  18. data/lib/schemurai/evaluation_pool.rb +66 -0
  19. data/lib/schemurai/evaluator.rb +861 -0
  20. data/lib/schemurai/formats.rb +403 -0
  21. data/lib/schemurai/json_pointer.rb +11 -0
  22. data/lib/schemurai/limit_budget.rb +78 -0
  23. data/lib/schemurai/limit_exceeded.rb +18 -0
  24. data/lib/schemurai/limited_evaluator.rb +43 -0
  25. data/lib/schemurai/meta_schemas/draft2019_09.rb +149 -0
  26. data/lib/schemurai/meta_schemas/draft2020_12.rb +149 -0
  27. data/lib/schemurai/meta_schemas/draft7.rb +121 -0
  28. data/lib/schemurai/meta_schemas.rb +28 -0
  29. data/lib/schemurai/native/4.0/schemurai_native.so +0 -0
  30. data/lib/schemurai/native/diagnostics.rb +53 -0
  31. data/lib/schemurai/native/evaluator.rb +87 -0
  32. data/lib/schemurai/native/null_numeric.rb +23 -0
  33. data/lib/schemurai/number_checks.rb +128 -0
  34. data/lib/schemurai/schema_domain.rb +95 -0
  35. data/lib/schemurai/schema_graph.rb +538 -0
  36. data/lib/schemurai/schema_node.rb +55 -0
  37. data/lib/schemurai/string_checks.rb +166 -0
  38. data/lib/schemurai/type_checks.rb +59 -0
  39. data/lib/schemurai/unique_items.rb +68 -0
  40. data/lib/schemurai/value_equality.rb +72 -0
  41. data/lib/schemurai/version.rb +6 -0
  42. data/lib/schemurai/vm/compiler.rb +410 -0
  43. data/lib/schemurai/vm/evaluator.rb +663 -0
  44. data/lib/schemurai/vm/limited_evaluator.rb +27 -0
  45. data/lib/schemurai.rb +307 -0
  46. data/lib/schemurai_native.rb +4 -0
  47. data/sig/schemurai.rbs +108 -0
  48. metadata +121 -0
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../meta_schemas"
4
+
5
+ module Schemurai
6
+ module Internal
7
+ module MetaSchemas
8
+ module Draft201909
9
+ META_SCHEMA_URI = "https://json-schema.org/draft/2019-09/schema"
10
+ SCHEMA = {
11
+ "$schema" => META_SCHEMA_URI,
12
+ "$id" => META_SCHEMA_URI,
13
+ "$recursiveAnchor" => true,
14
+ "type" => ["object", "boolean"],
15
+ "properties" => {
16
+ "$id" => {"type" => "string"},
17
+ "$schema" => {"type" => "string"},
18
+ "$ref" => {"type" => "string"},
19
+ "$anchor" => {"type" => "string", "pattern" => "^[A-Za-z][-A-Za-z0-9.:_]*$"},
20
+ "$recursiveRef" => {"type" => "string"},
21
+ "$recursiveAnchor" => {"type" => "boolean"},
22
+ "$vocabulary" => {"type" => "object", "additionalProperties" => {"type" => "boolean"}},
23
+ "$comment" => {"type" => "string"},
24
+ "$defs" => {"type" => "object", "additionalProperties" => {"$recursiveRef" => "#"}},
25
+ "definitions" => {"type" => "object", "additionalProperties" => {"$recursiveRef" => "#"}},
26
+ "items" => {
27
+ "anyOf" => [
28
+ {"$recursiveRef" => "#"},
29
+ {"type" => "array", "minItems" => 1, "items" => {"$recursiveRef" => "#"}}
30
+ ]
31
+ },
32
+ "additionalItems" => {"$recursiveRef" => "#"},
33
+ "contains" => {"$recursiveRef" => "#"},
34
+ "additionalProperties" => {"$recursiveRef" => "#"},
35
+ "unevaluatedItems" => {"$recursiveRef" => "#"},
36
+ "unevaluatedProperties" => {"$recursiveRef" => "#"},
37
+ "properties" => {"type" => "object", "additionalProperties" => {"$recursiveRef" => "#"}},
38
+ "patternProperties" => {"type" => "object", "additionalProperties" => {"$recursiveRef" => "#"}},
39
+ "dependentSchemas" => {"type" => "object", "additionalProperties" => {"$recursiveRef" => "#"}},
40
+ "dependencies" => {
41
+ "type" => "object",
42
+ "additionalProperties" => {
43
+ "anyOf" => [
44
+ {"$recursiveRef" => "#"},
45
+ {"type" => "array", "items" => {"type" => "string"}, "uniqueItems" => true}
46
+ ]
47
+ }
48
+ },
49
+ "propertyNames" => {"$recursiveRef" => "#"},
50
+ "if" => {"$recursiveRef" => "#"},
51
+ "then" => {"$recursiveRef" => "#"},
52
+ "else" => {"$recursiveRef" => "#"},
53
+ "allOf" => {"type" => "array", "minItems" => 1, "items" => {"$recursiveRef" => "#"}},
54
+ "anyOf" => {"type" => "array", "minItems" => 1, "items" => {"$recursiveRef" => "#"}},
55
+ "oneOf" => {"type" => "array", "minItems" => 1, "items" => {"$recursiveRef" => "#"}},
56
+ "not" => {"$recursiveRef" => "#"},
57
+ "type" => {
58
+ "anyOf" => [
59
+ {"enum" => ["null", "boolean", "object", "array", "number", "integer", "string"]},
60
+ {
61
+ "type" => "array",
62
+ "items" => {"enum" => ["null", "boolean", "object", "array", "number", "integer", "string"]},
63
+ "minItems" => 1,
64
+ "uniqueItems" => true
65
+ }
66
+ ]
67
+ },
68
+ "enum" => {"type" => "array"},
69
+ "multipleOf" => {"type" => "number", "exclusiveMinimum" => 0},
70
+ "maximum" => {"type" => "number"},
71
+ "exclusiveMaximum" => {"type" => "number"},
72
+ "minimum" => {"type" => "number"},
73
+ "exclusiveMinimum" => {"type" => "number"},
74
+ "minLength" => {"type" => "integer", "minimum" => 0},
75
+ "maxLength" => {"type" => "integer", "minimum" => 0},
76
+ "pattern" => {"type" => "string"},
77
+ "minItems" => {"type" => "integer", "minimum" => 0},
78
+ "maxItems" => {"type" => "integer", "minimum" => 0},
79
+ "uniqueItems" => {"type" => "boolean"},
80
+ "minContains" => {"type" => "integer", "minimum" => 0},
81
+ "maxContains" => {"type" => "integer", "minimum" => 0},
82
+ "minProperties" => {"type" => "integer", "minimum" => 0},
83
+ "maxProperties" => {"type" => "integer", "minimum" => 0},
84
+ "required" => {
85
+ "type" => "array",
86
+ "items" => {"type" => "string"},
87
+ "uniqueItems" => true
88
+ },
89
+ "dependentRequired" => {
90
+ "type" => "object",
91
+ "additionalProperties" => {
92
+ "type" => "array",
93
+ "items" => {"type" => "string"},
94
+ "uniqueItems" => true
95
+ }
96
+ },
97
+ "title" => {"type" => "string"},
98
+ "description" => {"type" => "string"},
99
+ "deprecated" => {"type" => "boolean"},
100
+ "readOnly" => {"type" => "boolean"},
101
+ "writeOnly" => {"type" => "boolean"},
102
+ "examples" => {"type" => "array"},
103
+ "format" => {"type" => "string"},
104
+ "contentEncoding" => {"type" => "string"},
105
+ "contentMediaType" => {"type" => "string"},
106
+ "contentSchema" => {"$recursiveRef" => "#"}
107
+ }
108
+ }.freeze
109
+
110
+ MetaSchemas.register(META_SCHEMA_URI, SCHEMA)
111
+
112
+ COMPONENT_KEYWORDS = {
113
+ "core" => %w[
114
+ $id $schema $ref $anchor $recursiveRef $recursiveAnchor $vocabulary $comment $defs
115
+ ],
116
+ "applicator" => %w[
117
+ additionalItems unevaluatedItems items contains additionalProperties
118
+ unevaluatedProperties properties patternProperties dependentSchemas propertyNames
119
+ if then else allOf anyOf oneOf not
120
+ ],
121
+ "validation" => %w[
122
+ type const enum multipleOf maximum exclusiveMaximum minimum exclusiveMinimum
123
+ maxLength minLength pattern maxItems minItems uniqueItems maxContains minContains
124
+ maxProperties minProperties required dependentRequired
125
+ ],
126
+ "meta-data" => %w[title description default deprecated readOnly writeOnly examples],
127
+ "format" => %w[format],
128
+ "content" => %w[contentEncoding contentMediaType contentSchema]
129
+ }.freeze
130
+
131
+ COMPONENT_KEYWORDS.each do |name, keywords|
132
+ uri = "https://json-schema.org/draft/2019-09/meta/#{name}"
133
+ component = {
134
+ "$schema" => META_SCHEMA_URI,
135
+ "$id" => uri,
136
+ "$recursiveAnchor" => true,
137
+ "type" => ["object", "boolean"],
138
+ "properties" => SCHEMA.fetch("properties").slice(*keywords)
139
+ }.freeze
140
+ MetaSchemas.register(uri, component)
141
+ end
142
+
143
+ private_constant :META_SCHEMA_URI, :SCHEMA, :COMPONENT_KEYWORDS
144
+ end
145
+ end
146
+ end
147
+
148
+ private_constant :Internal
149
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../meta_schemas"
4
+
5
+ module Schemurai
6
+ module Internal
7
+ module MetaSchemas
8
+ module Draft202012
9
+ META_SCHEMA_URI = "https://json-schema.org/draft/2020-12/schema"
10
+ SCHEMA = {
11
+ "$schema" => META_SCHEMA_URI,
12
+ "$id" => META_SCHEMA_URI,
13
+ "$dynamicAnchor" => "meta",
14
+ "type" => ["object", "boolean"],
15
+ "properties" => {
16
+ "$id" => {"type" => "string"},
17
+ "$schema" => {"type" => "string"},
18
+ "$ref" => {"type" => "string"},
19
+ "$anchor" => {"type" => "string", "pattern" => "^[A-Za-z_][-A-Za-z0-9._]*$"},
20
+ "$dynamicRef" => {"type" => "string"},
21
+ "$dynamicAnchor" => {"type" => "string", "pattern" => "^[A-Za-z_][-A-Za-z0-9._]*$"},
22
+ "$recursiveRef" => {"type" => "string"},
23
+ "$recursiveAnchor" => {"type" => "string", "pattern" => "^[A-Za-z_][-A-Za-z0-9._]*$"},
24
+ "$vocabulary" => {"type" => "object", "additionalProperties" => {"type" => "boolean"}},
25
+ "$comment" => {"type" => "string"},
26
+ "$defs" => {"type" => "object", "additionalProperties" => {"$dynamicRef" => "#meta"}},
27
+ "definitions" => {"type" => "object", "additionalProperties" => {"$dynamicRef" => "#meta"}},
28
+ "prefixItems" => {
29
+ "type" => "array",
30
+ "minItems" => 1,
31
+ "items" => {"$dynamicRef" => "#meta"}
32
+ },
33
+ "items" => {"$dynamicRef" => "#meta"},
34
+ "contains" => {"$dynamicRef" => "#meta"},
35
+ "additionalProperties" => {"$dynamicRef" => "#meta"},
36
+ "properties" => {"type" => "object", "additionalProperties" => {"$dynamicRef" => "#meta"}},
37
+ "patternProperties" => {"type" => "object", "additionalProperties" => {"$dynamicRef" => "#meta"}},
38
+ "dependentSchemas" => {"type" => "object", "additionalProperties" => {"$dynamicRef" => "#meta"}},
39
+ "dependencies" => {
40
+ "type" => "object",
41
+ "additionalProperties" => {
42
+ "anyOf" => [
43
+ {"$dynamicRef" => "#meta"},
44
+ {"type" => "array", "items" => {"type" => "string"}, "uniqueItems" => true}
45
+ ]
46
+ }
47
+ },
48
+ "propertyNames" => {"$dynamicRef" => "#meta"},
49
+ "if" => {"$dynamicRef" => "#meta"},
50
+ "then" => {"$dynamicRef" => "#meta"},
51
+ "else" => {"$dynamicRef" => "#meta"},
52
+ "allOf" => {"type" => "array", "minItems" => 1, "items" => {"$dynamicRef" => "#meta"}},
53
+ "anyOf" => {"type" => "array", "minItems" => 1, "items" => {"$dynamicRef" => "#meta"}},
54
+ "oneOf" => {"type" => "array", "minItems" => 1, "items" => {"$dynamicRef" => "#meta"}},
55
+ "not" => {"$dynamicRef" => "#meta"},
56
+ "type" => {
57
+ "anyOf" => [
58
+ {"enum" => ["null", "boolean", "object", "array", "number", "integer", "string"]},
59
+ {
60
+ "type" => "array",
61
+ "items" => {"enum" => ["null", "boolean", "object", "array", "number", "integer", "string"]},
62
+ "minItems" => 1,
63
+ "uniqueItems" => true
64
+ }
65
+ ]
66
+ },
67
+ "enum" => {"type" => "array"},
68
+ "multipleOf" => {"type" => "number", "exclusiveMinimum" => 0},
69
+ "maximum" => {"type" => "number"},
70
+ "exclusiveMaximum" => {"type" => "number"},
71
+ "minimum" => {"type" => "number"},
72
+ "exclusiveMinimum" => {"type" => "number"},
73
+ "minLength" => {"type" => "integer", "minimum" => 0},
74
+ "maxLength" => {"type" => "integer", "minimum" => 0},
75
+ "pattern" => {"type" => "string"},
76
+ "minItems" => {"type" => "integer", "minimum" => 0},
77
+ "maxItems" => {"type" => "integer", "minimum" => 0},
78
+ "uniqueItems" => {"type" => "boolean"},
79
+ "minContains" => {"type" => "integer", "minimum" => 0},
80
+ "maxContains" => {"type" => "integer", "minimum" => 0},
81
+ "minProperties" => {"type" => "integer", "minimum" => 0},
82
+ "maxProperties" => {"type" => "integer", "minimum" => 0},
83
+ "required" => {
84
+ "type" => "array",
85
+ "items" => {"type" => "string"},
86
+ "uniqueItems" => true
87
+ },
88
+ "dependentRequired" => {
89
+ "type" => "object",
90
+ "additionalProperties" => {
91
+ "type" => "array",
92
+ "items" => {"type" => "string"},
93
+ "uniqueItems" => true
94
+ }
95
+ },
96
+ "title" => {"type" => "string"},
97
+ "description" => {"type" => "string"},
98
+ "deprecated" => {"type" => "boolean"},
99
+ "readOnly" => {"type" => "boolean"},
100
+ "writeOnly" => {"type" => "boolean"},
101
+ "examples" => {"type" => "array"},
102
+ "format" => {"type" => "string"},
103
+ "contentEncoding" => {"type" => "string"},
104
+ "contentMediaType" => {"type" => "string"},
105
+ "contentSchema" => {"$dynamicRef" => "#meta"}
106
+ }
107
+ }.freeze
108
+
109
+ MetaSchemas.register(META_SCHEMA_URI, SCHEMA)
110
+
111
+ COMPONENT_KEYWORDS = {
112
+ "core" => %w[
113
+ $id $schema $ref $anchor $dynamicRef $dynamicAnchor $vocabulary $comment $defs
114
+ ],
115
+ "applicator" => %w[
116
+ prefixItems items contains additionalProperties properties patternProperties
117
+ dependentSchemas propertyNames if then else allOf anyOf oneOf not
118
+ ],
119
+ "unevaluated" => %w[unevaluatedItems unevaluatedProperties],
120
+ "validation" => %w[
121
+ type const enum multipleOf maximum exclusiveMaximum minimum exclusiveMinimum
122
+ maxLength minLength pattern maxItems minItems uniqueItems maxContains minContains
123
+ maxProperties minProperties required dependentRequired
124
+ ],
125
+ "meta-data" => %w[title description default deprecated readOnly writeOnly examples],
126
+ "format-annotation" => %w[format],
127
+ "format-assertion" => %w[format],
128
+ "content" => %w[contentEncoding contentMediaType contentSchema]
129
+ }.freeze
130
+
131
+ COMPONENT_KEYWORDS.each do |name, keywords|
132
+ uri = "https://json-schema.org/draft/2020-12/meta/#{name}"
133
+ component = {
134
+ "$schema" => META_SCHEMA_URI,
135
+ "$id" => uri,
136
+ "$dynamicAnchor" => "meta",
137
+ "type" => ["object", "boolean"],
138
+ "properties" => SCHEMA.fetch("properties").slice(*keywords)
139
+ }.freeze
140
+ MetaSchemas.register(uri, component)
141
+ end
142
+
143
+ private_constant :META_SCHEMA_URI, :SCHEMA, :COMPONENT_KEYWORDS
144
+ end
145
+ end
146
+ end
147
+
148
+ private_constant :Internal
149
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../meta_schemas"
4
+
5
+ module Schemurai
6
+ module Internal
7
+ module MetaSchemas
8
+ module Draft7
9
+ META_SCHEMA_URI = "http://json-schema.org/draft-07/schema"
10
+ SCHEMA = {
11
+ "$schema" => "#{META_SCHEMA_URI}#",
12
+ "$id" => "#{META_SCHEMA_URI}#",
13
+ "definitions" => {
14
+ "schemaArray" => {"type" => "array", "minItems" => 1, "items" => {"$ref" => "#"}},
15
+ "nonNegativeInteger" => {"type" => "integer", "minimum" => 0},
16
+ "nonNegativeIntegerDefault0" => {
17
+ "allOf" => [
18
+ {"$ref" => "#/definitions/nonNegativeInteger"},
19
+ {"default" => 0}
20
+ ]
21
+ },
22
+ "simpleTypes" => {"enum" => %w[array boolean integer null number object string]},
23
+ "stringArray" => {
24
+ "type" => "array",
25
+ "items" => {"type" => "string"},
26
+ "uniqueItems" => true,
27
+ "default" => []
28
+ }
29
+ },
30
+ "type" => ["object", "boolean"],
31
+ "properties" => {
32
+ "$id" => {"type" => "string", "format" => "uri-reference"},
33
+ "$schema" => {"type" => "string", "format" => "uri"},
34
+ "$ref" => {"type" => "string", "format" => "uri-reference"},
35
+ "$comment" => {"type" => "string"},
36
+ "title" => {"type" => "string"},
37
+ "description" => {"type" => "string"},
38
+ "default" => true,
39
+ "readOnly" => {"type" => "boolean", "default" => false},
40
+ "writeOnly" => {"type" => "boolean", "default" => false},
41
+ "examples" => {"type" => "array", "items" => true},
42
+ "multipleOf" => {"type" => "number", "exclusiveMinimum" => 0},
43
+ "maximum" => {"type" => "number"},
44
+ "exclusiveMaximum" => {"type" => "number"},
45
+ "minimum" => {"type" => "number"},
46
+ "exclusiveMinimum" => {"type" => "number"},
47
+ "maxLength" => {"$ref" => "#/definitions/nonNegativeInteger"},
48
+ "minLength" => {"$ref" => "#/definitions/nonNegativeIntegerDefault0"},
49
+ "pattern" => {"type" => "string", "format" => "regex"},
50
+ "additionalItems" => {"$ref" => "#"},
51
+ "items" => {
52
+ "anyOf" => [{"$ref" => "#"}, {"$ref" => "#/definitions/schemaArray"}],
53
+ "default" => true
54
+ },
55
+ "maxItems" => {"$ref" => "#/definitions/nonNegativeInteger"},
56
+ "minItems" => {"$ref" => "#/definitions/nonNegativeIntegerDefault0"},
57
+ "uniqueItems" => {"type" => "boolean", "default" => false},
58
+ "contains" => {"$ref" => "#"},
59
+ "maxProperties" => {"$ref" => "#/definitions/nonNegativeInteger"},
60
+ "minProperties" => {"$ref" => "#/definitions/nonNegativeIntegerDefault0"},
61
+ "required" => {"$ref" => "#/definitions/stringArray"},
62
+ "additionalProperties" => {"$ref" => "#"},
63
+ "definitions" => {
64
+ "type" => "object",
65
+ "additionalProperties" => {"$ref" => "#"},
66
+ "default" => {}
67
+ },
68
+ "properties" => {
69
+ "type" => "object",
70
+ "additionalProperties" => {"$ref" => "#"},
71
+ "default" => {}
72
+ },
73
+ "patternProperties" => {
74
+ "type" => "object",
75
+ "additionalProperties" => {"$ref" => "#"},
76
+ "propertyNames" => {"format" => "regex"},
77
+ "default" => {}
78
+ },
79
+ "dependencies" => {
80
+ "type" => "object",
81
+ "additionalProperties" => {
82
+ "anyOf" => [{"$ref" => "#"}, {"$ref" => "#/definitions/stringArray"}]
83
+ }
84
+ },
85
+ "propertyNames" => {"$ref" => "#"},
86
+ "const" => true,
87
+ "enum" => {"type" => "array", "items" => true, "minItems" => 1, "uniqueItems" => true},
88
+ "type" => {
89
+ "anyOf" => [
90
+ {"$ref" => "#/definitions/simpleTypes"},
91
+ {
92
+ "type" => "array",
93
+ "items" => {"$ref" => "#/definitions/simpleTypes"},
94
+ "minItems" => 1,
95
+ "uniqueItems" => true
96
+ }
97
+ ]
98
+ },
99
+ "format" => {"type" => "string"},
100
+ "contentMediaType" => {"type" => "string"},
101
+ "contentEncoding" => {"type" => "string"},
102
+ "if" => {"$ref" => "#"},
103
+ "then" => {"$ref" => "#"},
104
+ "else" => {"$ref" => "#"},
105
+ "allOf" => {"$ref" => "#/definitions/schemaArray"},
106
+ "anyOf" => {"$ref" => "#/definitions/schemaArray"},
107
+ "oneOf" => {"$ref" => "#/definitions/schemaArray"},
108
+ "not" => {"$ref" => "#"}
109
+ },
110
+ "default" => true
111
+ }.freeze
112
+
113
+ MetaSchemas.register(META_SCHEMA_URI, SCHEMA)
114
+
115
+ private_constant :META_SCHEMA_URI, :SCHEMA
116
+ end
117
+ end
118
+ end
119
+
120
+ private_constant :Internal
121
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schemurai
4
+ module Internal
5
+ module MetaSchemas
6
+ class << self
7
+ def register(uri, schema)
8
+ registry[normalize_uri(uri)] = schema
9
+ schema
10
+ end
11
+
12
+ def resolve(uri)
13
+ registry[normalize_uri(uri)]
14
+ end
15
+
16
+ private def registry
17
+ @registry ||= {}
18
+ end
19
+
20
+ private def normalize_uri(uri)
21
+ uri.to_s.delete_suffix("#")
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ private_constant :Internal
28
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schemurai
4
+ module Native
5
+ # Render native diagnostic output using the messages shared by every backend.
6
+ # The instance remains an original Ruby object; this layer never traverses it.
7
+ module Diagnostics
8
+ TYPE_NAMES = {Protocol::OP_TYPE_NULL => "null", Protocol::OP_TYPE_BOOLEAN => "boolean", Protocol::OP_TYPE_OBJECT => "object",
9
+ Protocol::OP_TYPE_ARRAY => "array", Protocol::OP_TYPE_NUMBER => "number", Protocol::OP_TYPE_INTEGER => "integer",
10
+ Protocol::OP_TYPE_STRING => "string", Protocol::OP_TYPED_NUMBER => "number", Protocol::OP_TYPED_INTEGER => "integer",
11
+ Protocol::OP_TYPED_STRING => "string", Protocol::OP_TYPED_ARRAY => "array", Protocol::OP_TYPED_OBJECT => "object"}.freeze
12
+ ATTRIBUTES = {"maximum" => :maximum, "minimum" => :minimum, "exclusiveMaximum" => :exclusive_maximum, "exclusiveMinimum" => :exclusive_minimum,
13
+ "maxLength" => :max_length, "minLength" => :min_length, "maxItems" => :max_items, "minItems" => :min_items,
14
+ "maxProperties" => :max_properties, "minProperties" => :min_properties}.freeze
15
+ private_constant :TYPE_NAMES, :ATTRIBUTES
16
+
17
+ module_function def error(row)
18
+ keyword, instance_path, schema_path, opcode, operand, instance, detail, rendered_message = row
19
+ ValidationError.new(keyword: keyword, instance_path: instance_path, schema_path: schema_path,
20
+ message: rendered_message || message(keyword, opcode, operand, instance, detail))
21
+ end
22
+
23
+ module_function def message(keyword, opcode, operand, instance, detail) # rubocop:disable Metrics/MethodLength
24
+ messages = Internal::ErrorMessage
25
+ case keyword
26
+ when "falseSchema" then messages.false_schema
27
+ when "type" then messages.type((opcode == Protocol::OP_TYPES) ? operand.names : TYPE_NAMES.fetch(opcode), instance)
28
+ when "const" then messages.const
29
+ when "enum" then messages.enum
30
+ when "maximum", "minimum", "exclusiveMaximum", "exclusiveMinimum"
31
+ messages.numeric_limit(keyword, operand.public_send(ATTRIBUTES.fetch(keyword)))
32
+ when "multipleOf" then messages.multiple_of(operand.multiple_of)
33
+ when "maxLength", "minLength", "maxItems", "minItems", "maxProperties", "minProperties"
34
+ messages.size(keyword, operand.public_send(ATTRIBUTES.fetch(keyword)), detail)
35
+ when "pattern" then (detail == 1) ? messages.invalid_pattern(operand.pattern) : messages.pattern(operand.pattern)
36
+ when "format" then messages.format(operand.format.name)
37
+ when "contentEncoding" then messages.content_encoding
38
+ when "contentMediaType" then messages.content_media_type
39
+ when "uniqueItems" then messages.unique_items
40
+ when "required" then messages.required(instance)
41
+ when "dependencies", "dependentRequired" then messages.dependent_required(operand, instance)
42
+ when "contains" then messages.contains(detail, operand.min_contains, operand.max_contains)
43
+ when "anyOf" then messages.any_of
44
+ when "oneOf" then messages.one_of(detail)
45
+ when "not" then messages.not
46
+ when "$ref", "$recursiveRef", "$dynamicRef" then operand
47
+ else raise "unknown native diagnostic #{keyword.inspect}"
48
+ end
49
+ end
50
+ private_class_method :message
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../decimal"
4
+ require_relative "../number_checks"
5
+ require_relative "../string_checks"
6
+ require_relative "../value_equality"
7
+ require_relative "../container_checks"
8
+ require_relative "../type_checks"
9
+ require_relative "../vm/compiler"
10
+ require_relative "../evaluation_pool"
11
+ require_relative "../limit_budget"
12
+ require_relative "../ecma_regexp"
13
+ require_relative "../json_pointer"
14
+ require "schemurai_native"
15
+ require_relative "diagnostics"
16
+ require_relative "null_numeric"
17
+
18
+ module Schemurai
19
+ module Native
20
+ class Evaluator
21
+ def backend = :native
22
+
23
+ def initialize(graph, compiler, root, content: false, format: false, compiled: nil)
24
+ @graph = graph
25
+ @compiler = compiler
26
+ @root = root
27
+ @content = content
28
+ @format = format
29
+ @graph_size = @graph.nodes.length
30
+ @compiled = compiled || Program.new(root, compiler, format, content)
31
+ @number_state = Internal::NumberChecks::State.new
32
+ @regexps = {}
33
+ @scope_state = []
34
+ @report_state = [nil, Internal::EvaluationPool.new]
35
+ @reference_state = []
36
+ @active_state = {}.compare_by_identity
37
+ @program = @compiled.runner(root)
38
+ @program.share_scalar_state(@number_state, @regexps, @scope_state, @reference_state, @active_state, @report_state)
39
+ @unresolved = @compiled.unresolved_references?
40
+ end
41
+
42
+ def valid?(instance, max_errors: nil, timeout: nil)
43
+ refresh_unresolved
44
+ if !max_errors.nil? || !timeout.nil?
45
+ budget = Internal::LimitBudget.new(max_errors: max_errors, timeout: timeout)
46
+ result = @program.valid_with_budget(instance, budget)
47
+ budget.check_deadline!
48
+ return result
49
+ end
50
+ @program.valid?(instance)
51
+ end
52
+
53
+ def validate(instance, max_errors: nil, timeout: nil)
54
+ refresh_unresolved
55
+ if !max_errors.nil? || !timeout.nil?
56
+ budget = Internal::LimitBudget.new(max_errors: max_errors, timeout: timeout)
57
+ rows = @program.diagnostics_with_budget(instance, budget)
58
+
59
+ errors = (rows == false) ? nil : rows.map do |row|
60
+ budget.reserve_error
61
+ Diagnostics.error(row)
62
+ end
63
+ budget.check_deadline!
64
+ return Result.new(errors)
65
+ end
66
+ rows = @program.diagnostics(instance)
67
+
68
+ return Result.new(nil) if rows == false
69
+
70
+ Result.new(rows.empty? ? rows : rows.map { |row| Diagnostics.error(row) })
71
+ end
72
+ private def refresh_unresolved
73
+ while @unresolved && @graph_size != @graph.nodes.length
74
+ graph_size = @graph.nodes.length
75
+ compiled = Program.new(@root, @compiler, @format, @content)
76
+ @program = compiled.runner(@root)
77
+ @program.share_scalar_state(@number_state, @regexps, @scope_state, @reference_state, @active_state, @report_state)
78
+ @compiled = compiled
79
+ @unresolved = @compiled.unresolved_references?
80
+ @graph_size = graph_size
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ private_constant :Native
87
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schemurai
4
+ module Native
5
+ # Native traversal selects one reached assertion and its comparison mode.
6
+ # Ruby dispatch preserves the exception and method visibility for nil.
7
+ module NullNumeric
8
+ module_function def valid?(value, bit, decimal)
9
+ actual = if decimal && !value.is_a?(Integer) && !value.is_a?(Rational)
10
+ Internal::Decimal.parse(value)
11
+ else
12
+ value
13
+ end
14
+ case bit
15
+ when Protocol::MAXIMUM, Protocol::MINIMUM, Protocol::EXCLUSIVE_MAXIMUM, Protocol::EXCLUSIVE_MINIMUM
16
+ Internal::NumberChecks.bound?(actual, bit, nil)
17
+ when Protocol::MULTIPLE_OF then nil.positive? && actual.remainder(nil).zero?
18
+ else raise "unknown null numeric assertion"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end