schemurai 3.0.1 → 3.0.2
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/README.md +6 -4
- data/ext/schemurai_native/Cargo.lock +48 -1
- data/ext/schemurai_native/Cargo.toml +3 -1
- data/ext/schemurai_native/extconf.rb +1 -1
- data/ext/schemurai_native/glue.c +1679 -62
- data/ext/schemurai_native/protocol.def +45 -0
- data/ext/schemurai_native/src/budget.rs +49 -0
- data/ext/schemurai_native/src/container.rs +460 -0
- data/ext/schemurai_native/src/content.rs +56 -27
- data/ext/schemurai_native/src/diagnostics/array.rs +392 -0
- data/ext/schemurai_native/src/diagnostics/object.rs +218 -0
- data/ext/schemurai_native/src/diagnostics.rs +1087 -307
- data/ext/schemurai_native/src/enumeration.rs +6 -1
- data/ext/schemurai_native/src/evaluation.rs +49 -20
- data/ext/schemurai_native/src/format.rs +8 -6
- data/ext/schemurai_native/src/graph.rs +37 -0
- data/ext/schemurai_native/src/instance_graph.rs +90 -0
- data/ext/schemurai_native/src/lib.rs +910 -237
- data/ext/schemurai_native/src/memo.rs +11 -38
- data/ext/schemurai_native/src/number/arbitrary.rs +154 -0
- data/ext/schemurai_native/src/number.rs +250 -59
- data/ext/schemurai_native/src/pattern.rs +113 -101
- data/ext/schemurai_native/src/pointer.rs +97 -0
- data/ext/schemurai_native/src/runtime/properties.rs +162 -0
- data/ext/schemurai_native/src/runtime/reports.rs +266 -0
- data/ext/schemurai_native/src/runtime/scopes.rs +430 -0
- data/ext/schemurai_native/src/runtime.rs +1020 -0
- data/ext/schemurai_native/src/scope.rs +60 -16
- data/ext/schemurai_native/src/string.rs +68 -0
- data/ext/schemurai_native/src/tracking.rs +244 -174
- data/lib/schemurai/container_checks/array_diagnostics.rb +119 -0
- data/lib/schemurai/container_checks/object_diagnostics.rb +152 -0
- data/lib/schemurai/container_checks.rb +534 -0
- data/lib/schemurai/decimal.rb +11 -0
- data/lib/schemurai/dialect.rb +0 -12
- data/lib/schemurai/ecma_regexp.rb +46 -0
- data/lib/schemurai/evaluation_pool.rb +66 -0
- data/lib/schemurai/evaluator.rb +9 -48
- data/lib/schemurai/json_pointer.rb +11 -0
- data/lib/schemurai/native/diagnostics.rb +4 -3
- data/lib/schemurai/native/evaluator.rb +38 -10
- data/lib/schemurai/native/null_numeric.rb +23 -0
- data/lib/schemurai/number_checks.rb +128 -0
- data/lib/schemurai/string_checks.rb +166 -0
- data/lib/schemurai/type_checks.rb +59 -0
- data/lib/schemurai/value_equality.rb +72 -0
- data/lib/schemurai/version.rb +1 -1
- data/lib/schemurai/vm/compiler.rb +18 -26
- data/lib/schemurai/vm/evaluator.rb +87 -545
- data/lib/schemurai/vm/limited_evaluator.rb +7 -22
- metadata +24 -2
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../evaluation"
|
|
4
|
+
require_relative "../error_message"
|
|
5
|
+
|
|
6
|
+
module Schemurai
|
|
7
|
+
module Internal
|
|
8
|
+
module ContainerChecks
|
|
9
|
+
module ArrayDiagnostics
|
|
10
|
+
private def check_array(rules, value, prior_evaluation)
|
|
11
|
+
evaluation = nil
|
|
12
|
+
if rules.max_items && value.length > rules.max_items
|
|
13
|
+
return Evaluation.invalid unless collecting_array_errors?
|
|
14
|
+
|
|
15
|
+
array_error("maxItems", rules, value)
|
|
16
|
+
end
|
|
17
|
+
if rules.min_items && value.length < rules.min_items
|
|
18
|
+
return Evaluation.invalid unless collecting_array_errors?
|
|
19
|
+
|
|
20
|
+
array_error("minItems", rules, value)
|
|
21
|
+
end
|
|
22
|
+
if rules.unique && !unique_items?(value)
|
|
23
|
+
return Evaluation.invalid unless collecting_array_errors?
|
|
24
|
+
|
|
25
|
+
array_error("uniqueItems", rules, value)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if (prefix_items = rules.prefix_items)
|
|
29
|
+
prefix_items.each_with_index do |child, index|
|
|
30
|
+
@budget&.checkpoint
|
|
31
|
+
break if index >= value.length
|
|
32
|
+
valid = evaluate_child_at(child, value[index], index, "prefixItems", index)
|
|
33
|
+
return Evaluation.invalid if !valid && !collecting_array_errors?
|
|
34
|
+
(evaluation ||= tracked_evaluation).record_item(index)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
items = rules.items
|
|
39
|
+
if rules.items_list
|
|
40
|
+
items.each_with_index do |child, index|
|
|
41
|
+
@budget&.checkpoint
|
|
42
|
+
break if index >= value.length
|
|
43
|
+
valid = evaluate_child_at(child, value[index], index, "items", index)
|
|
44
|
+
return Evaluation.invalid if !valid && !collecting_array_errors?
|
|
45
|
+
(evaluation ||= tracked_evaluation).record_item(index)
|
|
46
|
+
end
|
|
47
|
+
if value.length > items.length && (additional = rules.additional)
|
|
48
|
+
(items.length...value.length).each do |index|
|
|
49
|
+
@budget&.checkpoint
|
|
50
|
+
valid = evaluate_child_at(additional, value[index], index, "additionalItems")
|
|
51
|
+
return Evaluation.invalid if !valid && !collecting_array_errors?
|
|
52
|
+
(evaluation ||= tracked_evaluation).record_item(index)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
elsif items
|
|
56
|
+
start = rules.prefix_items&.length || 0
|
|
57
|
+
(start...value.length).each do |index|
|
|
58
|
+
@budget&.checkpoint
|
|
59
|
+
valid = evaluate_child_at(items, value[index], index, "items")
|
|
60
|
+
return Evaluation.invalid if !valid && !collecting_array_errors?
|
|
61
|
+
(evaluation ||= tracked_evaluation).record_item(index)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if (contains = rules.contains)
|
|
66
|
+
matched = nil
|
|
67
|
+
index = 0
|
|
68
|
+
while index < value.length
|
|
69
|
+
@budget&.checkpoint
|
|
70
|
+
(matched ||= []) << index if trial(contains, value[index]).valid?
|
|
71
|
+
index += 1
|
|
72
|
+
end
|
|
73
|
+
matched_count = matched ? matched.length : 0
|
|
74
|
+
unless matched_count.between?(rules.min_contains, rules.max_contains)
|
|
75
|
+
return Evaluation.invalid unless collecting_array_errors?
|
|
76
|
+
|
|
77
|
+
array_error("contains", rules, value, matched_count)
|
|
78
|
+
end
|
|
79
|
+
if matched
|
|
80
|
+
matched.each { |index| (evaluation ||= tracked_evaluation).record_item(index) }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if (unevaluated = rules.unevaluated)
|
|
85
|
+
prior_items = prior_evaluation.evaluated_items
|
|
86
|
+
index = 0
|
|
87
|
+
while index < value.length
|
|
88
|
+
@budget&.checkpoint
|
|
89
|
+
if prior_items.include?(index) || evaluation&.evaluated_items&.include?(index)
|
|
90
|
+
index += 1
|
|
91
|
+
next
|
|
92
|
+
end
|
|
93
|
+
valid = evaluate_child_at(unevaluated, value[index], index, "unevaluatedItems")
|
|
94
|
+
return Evaluation.invalid if !valid && !collecting_array_errors?
|
|
95
|
+
(evaluation ||= tracked_evaluation).record_item(index)
|
|
96
|
+
index += 1
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
return Evaluation.valid unless evaluation
|
|
100
|
+
|
|
101
|
+
evaluation
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private def collecting_array_errors? = @errors
|
|
105
|
+
|
|
106
|
+
private def array_error(keyword, rules, value, actual = nil)
|
|
107
|
+
add_error(keyword) do
|
|
108
|
+
case keyword
|
|
109
|
+
when "maxItems" then ErrorMessage.size(keyword, rules.max_items, value.length)
|
|
110
|
+
when "minItems" then ErrorMessage.size(keyword, rules.min_items, value.length)
|
|
111
|
+
when "uniqueItems" then ErrorMessage.unique_items
|
|
112
|
+
when "contains" then ErrorMessage.contains(actual, rules.min_contains, rules.max_contains)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../evaluation"
|
|
4
|
+
require_relative "../error_message"
|
|
5
|
+
|
|
6
|
+
module Schemurai
|
|
7
|
+
module Internal
|
|
8
|
+
module ContainerChecks
|
|
9
|
+
module ObjectDiagnostics
|
|
10
|
+
MISSING_SEGMENT = Object.new.freeze
|
|
11
|
+
|
|
12
|
+
private def check_object(rules, value, prior_evaluation)
|
|
13
|
+
evaluation = nil
|
|
14
|
+
if rules.max_properties && value.length > rules.max_properties
|
|
15
|
+
return Evaluation.invalid unless collecting_object_errors?
|
|
16
|
+
|
|
17
|
+
object_error("maxProperties", rules, value)
|
|
18
|
+
end
|
|
19
|
+
if rules.min_properties && value.length < rules.min_properties
|
|
20
|
+
return Evaluation.invalid unless collecting_object_errors?
|
|
21
|
+
|
|
22
|
+
object_error("minProperties", rules, value)
|
|
23
|
+
end
|
|
24
|
+
if (required = rules.required)
|
|
25
|
+
required.each do |name|
|
|
26
|
+
object_budget&.checkpoint
|
|
27
|
+
next if value.key?(name)
|
|
28
|
+
return Evaluation.invalid unless collecting_object_errors?
|
|
29
|
+
|
|
30
|
+
object_error("required", rules, value, name)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
properties = rules.properties
|
|
35
|
+
patterns = rules.patterns
|
|
36
|
+
value.each do |name, property_value|
|
|
37
|
+
object_budget&.checkpoint
|
|
38
|
+
matched = false
|
|
39
|
+
if (child = properties[name])
|
|
40
|
+
matched = true
|
|
41
|
+
valid = evaluate_child_at(child, property_value, name, "properties", name)
|
|
42
|
+
return Evaluation.invalid if !valid && !collecting_object_errors?
|
|
43
|
+
(evaluation ||= tracked_evaluation).record_property(name)
|
|
44
|
+
end
|
|
45
|
+
if patterns
|
|
46
|
+
patterns.each do |pattern, child|
|
|
47
|
+
object_budget&.checkpoint
|
|
48
|
+
next unless ecma_regexp(pattern).match?(name)
|
|
49
|
+
matched = true
|
|
50
|
+
valid = evaluate_child_at(child, property_value, name, "patternProperties", pattern)
|
|
51
|
+
return Evaluation.invalid if !valid && !collecting_object_errors?
|
|
52
|
+
(evaluation ||= tracked_evaluation).record_property(name)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
if !matched && (additional = rules.additional)
|
|
56
|
+
valid = evaluate_child_at(additional, property_value, name, "additionalProperties")
|
|
57
|
+
return Evaluation.invalid if !valid && !collecting_object_errors?
|
|
58
|
+
(evaluation ||= tracked_evaluation).record_property(name)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if (property_names = rules.property_names)
|
|
63
|
+
value.each_key do |name|
|
|
64
|
+
object_budget&.checkpoint
|
|
65
|
+
valid = evaluate_child_at(property_names, name, name, "propertyNames")
|
|
66
|
+
return Evaluation.invalid if !valid && !collecting_object_errors?
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
if (dependencies = rules.dependencies)
|
|
70
|
+
dependencies.each do |name, dependency|
|
|
71
|
+
object_budget&.checkpoint
|
|
72
|
+
next unless value.key?(name)
|
|
73
|
+
if dependency.is_a?(Array)
|
|
74
|
+
dependency.each do |required_name|
|
|
75
|
+
object_budget&.checkpoint
|
|
76
|
+
unless value.key?(required_name)
|
|
77
|
+
return Evaluation.invalid unless collecting_object_errors?
|
|
78
|
+
|
|
79
|
+
object_error("dependencies", rules, value, name, required_name)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
else
|
|
83
|
+
result = evaluate_at(dependency, value, MISSING_SEGMENT, "dependencies", name)
|
|
84
|
+
if result.valid? && !result.evaluated_properties.empty?
|
|
85
|
+
result.evaluated_properties.each do |property|
|
|
86
|
+
object_budget&.checkpoint
|
|
87
|
+
(evaluation ||= tracked_evaluation).record_property(property)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
if (dependent_required = rules.dependent_required)
|
|
94
|
+
dependent_required.each do |name, required_names|
|
|
95
|
+
object_budget&.checkpoint
|
|
96
|
+
next unless value.key?(name)
|
|
97
|
+
required_names.each do |required_name|
|
|
98
|
+
object_budget&.checkpoint
|
|
99
|
+
unless value.key?(required_name)
|
|
100
|
+
return Evaluation.invalid unless collecting_object_errors?
|
|
101
|
+
|
|
102
|
+
object_error("dependentRequired", rules, value, name, required_name)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
if (dependent_schemas = rules.dependent_schemas)
|
|
108
|
+
dependent_schemas.each do |name, child|
|
|
109
|
+
object_budget&.checkpoint
|
|
110
|
+
next unless value.key?(name)
|
|
111
|
+
result = evaluate_at(child, value, MISSING_SEGMENT, "dependentSchemas", name)
|
|
112
|
+
if result.valid? && !result.evaluated_properties.empty?
|
|
113
|
+
result.evaluated_properties.each do |property|
|
|
114
|
+
object_budget&.checkpoint
|
|
115
|
+
(evaluation ||= tracked_evaluation).record_property(property)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
if (unevaluated = rules.unevaluated)
|
|
121
|
+
prior_properties = prior_evaluation.evaluated_properties
|
|
122
|
+
value.each_key do |name|
|
|
123
|
+
object_budget&.checkpoint
|
|
124
|
+
next if prior_properties.include?(name) || evaluation&.evaluated_properties&.include?(name)
|
|
125
|
+
|
|
126
|
+
valid = evaluate_child_at(unevaluated, value[name], name, "unevaluatedProperties")
|
|
127
|
+
return Evaluation.invalid if !valid && !collecting_object_errors?
|
|
128
|
+
(evaluation ||= tracked_evaluation).record_property(name)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
return Evaluation.valid unless evaluation
|
|
132
|
+
|
|
133
|
+
evaluation
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private def object_budget = @budget
|
|
137
|
+
private def collecting_object_errors? = @errors
|
|
138
|
+
|
|
139
|
+
private def object_error(keyword, rules, value, name = nil, required_name = nil)
|
|
140
|
+
add_error(keyword) do
|
|
141
|
+
case keyword
|
|
142
|
+
when "maxProperties" then ErrorMessage.size(keyword, rules.max_properties, value.length)
|
|
143
|
+
when "minProperties" then ErrorMessage.size(keyword, rules.min_properties, value.length)
|
|
144
|
+
when "required" then ErrorMessage.required(name)
|
|
145
|
+
when "dependencies", "dependentRequired" then ErrorMessage.dependent_required(name, required_name)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|