anyvali 0.0.1
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 +7 -0
- data/README.md +339 -0
- data/lib/anyvali/anyvali_document.rb +43 -0
- data/lib/anyvali/format/validators.rb +89 -0
- data/lib/anyvali/interchange/exporter.rb +40 -0
- data/lib/anyvali/interchange/importer.rb +201 -0
- data/lib/anyvali/issue_codes.rb +20 -0
- data/lib/anyvali/parse/coercion.rb +93 -0
- data/lib/anyvali/parse/coercion_config.rb +19 -0
- data/lib/anyvali/parse/defaults.rb +21 -0
- data/lib/anyvali/parse_result.rb +21 -0
- data/lib/anyvali/schema.rb +132 -0
- data/lib/anyvali/schemas/any_schema.rb +15 -0
- data/lib/anyvali/schemas/array_schema.rb +77 -0
- data/lib/anyvali/schemas/bool_schema.rb +22 -0
- data/lib/anyvali/schemas/enum_schema.rb +50 -0
- data/lib/anyvali/schemas/int_schema.rb +9 -0
- data/lib/anyvali/schemas/intersection_schema.rb +65 -0
- data/lib/anyvali/schemas/literal_schema.rb +52 -0
- data/lib/anyvali/schemas/never_schema.rb +20 -0
- data/lib/anyvali/schemas/null_schema.rb +22 -0
- data/lib/anyvali/schemas/nullable_schema.rb +40 -0
- data/lib/anyvali/schemas/number_schema.rb +214 -0
- data/lib/anyvali/schemas/object_schema.rb +150 -0
- data/lib/anyvali/schemas/optional_schema.rb +47 -0
- data/lib/anyvali/schemas/record_schema.rb +51 -0
- data/lib/anyvali/schemas/ref_schema.rb +58 -0
- data/lib/anyvali/schemas/string_schema.rb +113 -0
- data/lib/anyvali/schemas/tuple_schema.rb +72 -0
- data/lib/anyvali/schemas/union_schema.rb +50 -0
- data/lib/anyvali/schemas/unknown_schema.rb +15 -0
- data/lib/anyvali/validation_context.rb +11 -0
- data/lib/anyvali/validation_error.rb +13 -0
- data/lib/anyvali/validation_issue.rb +45 -0
- data/lib/anyvali.rb +176 -0
- metadata +107 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnyVali
|
|
4
|
+
class RefSchema < Schema
|
|
5
|
+
attr_reader :ref
|
|
6
|
+
|
|
7
|
+
def initialize(ref:, **kwargs)
|
|
8
|
+
@ref = ref
|
|
9
|
+
super(kind: "ref", **kwargs)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_node
|
|
13
|
+
{ "kind" => "ref", "ref" => @ref }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def safe_parse(input, path: [], context: nil)
|
|
17
|
+
context ||= ValidationContext.new
|
|
18
|
+
resolved = resolve(context)
|
|
19
|
+
if resolved.nil?
|
|
20
|
+
issues = [ValidationIssue.new(
|
|
21
|
+
code: IssueCodes::UNSUPPORTED_SCHEMA_KIND,
|
|
22
|
+
path: path,
|
|
23
|
+
expected: @ref,
|
|
24
|
+
received: "unresolved ref"
|
|
25
|
+
)]
|
|
26
|
+
return ParseResult.new(value: nil, issues: issues)
|
|
27
|
+
end
|
|
28
|
+
resolved.safe_parse(input, path: path, context: context)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
protected
|
|
32
|
+
|
|
33
|
+
def validate(value, path, issues, context)
|
|
34
|
+
# Handled in safe_parse override
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def dup_with(**overrides)
|
|
38
|
+
attrs = {
|
|
39
|
+
ref: @ref,
|
|
40
|
+
kind: @kind,
|
|
41
|
+
constraints: @constraints,
|
|
42
|
+
coerce_config: @coerce_config,
|
|
43
|
+
default_value: @default_value,
|
|
44
|
+
has_default: @has_default,
|
|
45
|
+
custom_validators: @custom_validators
|
|
46
|
+
}.merge(overrides)
|
|
47
|
+
self.class.new(**attrs)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def resolve(context)
|
|
53
|
+
# ref format: "#/definitions/Name"
|
|
54
|
+
name = @ref.sub("#/definitions/", "")
|
|
55
|
+
context.definitions[name]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnyVali
|
|
4
|
+
class StringSchema < Schema
|
|
5
|
+
def initialize(constraints: {}, **kwargs)
|
|
6
|
+
super(kind: "string", constraints: constraints, **kwargs)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def min_length(n)
|
|
10
|
+
dup_with(constraints: @constraints.merge("minLength" => n))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def max_length(n)
|
|
14
|
+
dup_with(constraints: @constraints.merge("maxLength" => n))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def pattern(re)
|
|
18
|
+
pat = re.is_a?(Regexp) ? re.source : re
|
|
19
|
+
dup_with(constraints: @constraints.merge("pattern" => pat))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def starts_with(prefix)
|
|
23
|
+
dup_with(constraints: @constraints.merge("startsWith" => prefix))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ends_with(suffix)
|
|
27
|
+
dup_with(constraints: @constraints.merge("endsWith" => suffix))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def includes(substr)
|
|
31
|
+
dup_with(constraints: @constraints.merge("includes" => substr))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def format(fmt)
|
|
35
|
+
dup_with(constraints: @constraints.merge("format" => fmt))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
protected
|
|
39
|
+
|
|
40
|
+
def validate(value, path, issues, context)
|
|
41
|
+
unless value.is_a?(String)
|
|
42
|
+
issues << ValidationIssue.new(
|
|
43
|
+
code: IssueCodes::INVALID_TYPE,
|
|
44
|
+
path: path,
|
|
45
|
+
expected: "string",
|
|
46
|
+
received: Schema.type_name(value)
|
|
47
|
+
)
|
|
48
|
+
return
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if @constraints["minLength"] && value.length < @constraints["minLength"]
|
|
52
|
+
issues << ValidationIssue.new(
|
|
53
|
+
code: IssueCodes::TOO_SMALL,
|
|
54
|
+
path: path,
|
|
55
|
+
expected: @constraints["minLength"].to_s,
|
|
56
|
+
received: value.length.to_s
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if @constraints["maxLength"] && value.length > @constraints["maxLength"]
|
|
61
|
+
issues << ValidationIssue.new(
|
|
62
|
+
code: IssueCodes::TOO_LARGE,
|
|
63
|
+
path: path,
|
|
64
|
+
expected: @constraints["maxLength"].to_s,
|
|
65
|
+
received: value.length.to_s
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if @constraints["pattern"]
|
|
70
|
+
re = Regexp.new(@constraints["pattern"])
|
|
71
|
+
unless re.match?(value)
|
|
72
|
+
issues << ValidationIssue.new(
|
|
73
|
+
code: IssueCodes::INVALID_STRING,
|
|
74
|
+
path: path,
|
|
75
|
+
expected: @constraints["pattern"],
|
|
76
|
+
received: value
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if @constraints["startsWith"] && !value.start_with?(@constraints["startsWith"])
|
|
82
|
+
issues << ValidationIssue.new(
|
|
83
|
+
code: IssueCodes::INVALID_STRING,
|
|
84
|
+
path: path,
|
|
85
|
+
expected: @constraints["startsWith"],
|
|
86
|
+
received: value
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if @constraints["endsWith"] && !value.end_with?(@constraints["endsWith"])
|
|
91
|
+
issues << ValidationIssue.new(
|
|
92
|
+
code: IssueCodes::INVALID_STRING,
|
|
93
|
+
path: path,
|
|
94
|
+
expected: @constraints["endsWith"],
|
|
95
|
+
received: value
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if @constraints["includes"] && !value.include?(@constraints["includes"])
|
|
100
|
+
issues << ValidationIssue.new(
|
|
101
|
+
code: IssueCodes::INVALID_STRING,
|
|
102
|
+
path: path,
|
|
103
|
+
expected: @constraints["includes"],
|
|
104
|
+
received: value
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
if @constraints["format"]
|
|
109
|
+
Format::Validators.validate(value, @constraints["format"], path, issues)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnyVali
|
|
4
|
+
class TupleSchema < Schema
|
|
5
|
+
attr_reader :element_schemas
|
|
6
|
+
|
|
7
|
+
def initialize(elements:, **kwargs)
|
|
8
|
+
@element_schemas = elements.freeze
|
|
9
|
+
super(kind: "tuple", **kwargs)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_node
|
|
13
|
+
node = super
|
|
14
|
+
node["elements"] = @element_schemas.map(&:to_node)
|
|
15
|
+
node
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
|
|
20
|
+
def validate(value, path, issues, context)
|
|
21
|
+
unless value.is_a?(Array)
|
|
22
|
+
issues << ValidationIssue.new(
|
|
23
|
+
code: IssueCodes::INVALID_TYPE,
|
|
24
|
+
path: path,
|
|
25
|
+
expected: "tuple",
|
|
26
|
+
received: Schema.type_name(value)
|
|
27
|
+
)
|
|
28
|
+
return
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
expected_len = @element_schemas.length
|
|
32
|
+
if value.length < expected_len
|
|
33
|
+
issues << ValidationIssue.new(
|
|
34
|
+
code: IssueCodes::TOO_SMALL,
|
|
35
|
+
path: path,
|
|
36
|
+
expected: expected_len.to_s,
|
|
37
|
+
received: value.length.to_s
|
|
38
|
+
)
|
|
39
|
+
return
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if value.length > expected_len
|
|
43
|
+
issues << ValidationIssue.new(
|
|
44
|
+
code: IssueCodes::TOO_LARGE,
|
|
45
|
+
path: path,
|
|
46
|
+
expected: expected_len.to_s,
|
|
47
|
+
received: value.length.to_s
|
|
48
|
+
)
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
@element_schemas.each_with_index do |schema, i|
|
|
53
|
+
result = schema.safe_parse(value[i], path: path + [i], context: context)
|
|
54
|
+
issues.concat(result.issues) if result.failure?
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def dup_with(**overrides)
|
|
59
|
+
elements = overrides.delete(:elements) || @element_schemas
|
|
60
|
+
attrs = {
|
|
61
|
+
elements: elements,
|
|
62
|
+
kind: @kind,
|
|
63
|
+
constraints: @constraints,
|
|
64
|
+
coerce_config: @coerce_config,
|
|
65
|
+
default_value: @default_value,
|
|
66
|
+
has_default: @has_default,
|
|
67
|
+
custom_validators: @custom_validators
|
|
68
|
+
}.merge(overrides)
|
|
69
|
+
self.class.new(**attrs)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnyVali
|
|
4
|
+
class UnionSchema < Schema
|
|
5
|
+
attr_reader :variant_schemas
|
|
6
|
+
|
|
7
|
+
def initialize(variants:, **kwargs)
|
|
8
|
+
@variant_schemas = variants.freeze
|
|
9
|
+
super(kind: "union", **kwargs)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_node
|
|
13
|
+
node = super
|
|
14
|
+
node["variants"] = @variant_schemas.map(&:to_node)
|
|
15
|
+
node
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
|
|
20
|
+
def validate(value, path, issues, context)
|
|
21
|
+
@variant_schemas.each do |schema|
|
|
22
|
+
result = schema.safe_parse(value, path: path, context: context)
|
|
23
|
+
return if result.success?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# No variant matched
|
|
27
|
+
expected = @variant_schemas.map(&:kind).join(" | ")
|
|
28
|
+
issues << ValidationIssue.new(
|
|
29
|
+
code: IssueCodes::INVALID_UNION,
|
|
30
|
+
path: path,
|
|
31
|
+
expected: expected,
|
|
32
|
+
received: Schema.type_name(value)
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def dup_with(**overrides)
|
|
37
|
+
variants = overrides.delete(:variants) || @variant_schemas
|
|
38
|
+
attrs = {
|
|
39
|
+
variants: variants,
|
|
40
|
+
kind: @kind,
|
|
41
|
+
constraints: @constraints,
|
|
42
|
+
coerce_config: @coerce_config,
|
|
43
|
+
default_value: @default_value,
|
|
44
|
+
has_default: @has_default,
|
|
45
|
+
custom_validators: @custom_validators
|
|
46
|
+
}.merge(overrides)
|
|
47
|
+
self.class.new(**attrs)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnyVali
|
|
4
|
+
class UnknownSchema < Schema
|
|
5
|
+
def initialize(**kwargs)
|
|
6
|
+
super(kind: "unknown", **kwargs)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
protected
|
|
10
|
+
|
|
11
|
+
def validate(value, path, issues, context)
|
|
12
|
+
# unknown accepts everything
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnyVali
|
|
4
|
+
class ValidationError < StandardError
|
|
5
|
+
attr_reader :issues
|
|
6
|
+
|
|
7
|
+
def initialize(issues)
|
|
8
|
+
@issues = issues
|
|
9
|
+
messages = issues.map { |i| "#{i.code} at #{i.path.inspect}: expected #{i.expected}, received #{i.received}" }
|
|
10
|
+
super("Validation failed: #{messages.join('; ')}")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AnyVali
|
|
4
|
+
class ValidationIssue
|
|
5
|
+
attr_reader :code, :message, :path, :expected, :received, :meta
|
|
6
|
+
|
|
7
|
+
def initialize(code:, message: nil, path: [], expected: nil, received: nil, meta: nil)
|
|
8
|
+
@code = code
|
|
9
|
+
@message = message || default_message(code)
|
|
10
|
+
@path = path.freeze
|
|
11
|
+
@expected = expected
|
|
12
|
+
@received = received
|
|
13
|
+
@meta = meta
|
|
14
|
+
freeze
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_h
|
|
18
|
+
h = { "code" => @code, "path" => @path.dup }
|
|
19
|
+
h["expected"] = @expected unless @expected.nil?
|
|
20
|
+
h["received"] = @received unless @received.nil?
|
|
21
|
+
h["message"] = @message if @message
|
|
22
|
+
h["meta"] = @meta if @meta
|
|
23
|
+
h
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def default_message(code)
|
|
29
|
+
case code
|
|
30
|
+
when IssueCodes::INVALID_TYPE then "Invalid type"
|
|
31
|
+
when IssueCodes::REQUIRED then "Required field missing"
|
|
32
|
+
when IssueCodes::UNKNOWN_KEY then "Unknown key"
|
|
33
|
+
when IssueCodes::TOO_SMALL then "Value too small"
|
|
34
|
+
when IssueCodes::TOO_LARGE then "Value too large"
|
|
35
|
+
when IssueCodes::INVALID_STRING then "Invalid string"
|
|
36
|
+
when IssueCodes::INVALID_NUMBER then "Invalid number"
|
|
37
|
+
when IssueCodes::INVALID_LITERAL then "Invalid literal"
|
|
38
|
+
when IssueCodes::INVALID_UNION then "Invalid union"
|
|
39
|
+
when IssueCodes::COERCION_FAILED then "Coercion failed"
|
|
40
|
+
when IssueCodes::DEFAULT_INVALID then "Default value is invalid"
|
|
41
|
+
else "Validation failed"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/anyvali.rb
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "anyvali/issue_codes"
|
|
4
|
+
require_relative "anyvali/validation_issue"
|
|
5
|
+
require_relative "anyvali/parse_result"
|
|
6
|
+
require_relative "anyvali/validation_error"
|
|
7
|
+
require_relative "anyvali/validation_context"
|
|
8
|
+
require_relative "anyvali/anyvali_document"
|
|
9
|
+
require_relative "anyvali/schema"
|
|
10
|
+
|
|
11
|
+
require_relative "anyvali/parse/coercion"
|
|
12
|
+
require_relative "anyvali/parse/coercion_config"
|
|
13
|
+
require_relative "anyvali/parse/defaults"
|
|
14
|
+
|
|
15
|
+
require_relative "anyvali/format/validators"
|
|
16
|
+
|
|
17
|
+
require_relative "anyvali/schemas/string_schema"
|
|
18
|
+
require_relative "anyvali/schemas/number_schema"
|
|
19
|
+
require_relative "anyvali/schemas/int_schema"
|
|
20
|
+
require_relative "anyvali/schemas/bool_schema"
|
|
21
|
+
require_relative "anyvali/schemas/null_schema"
|
|
22
|
+
require_relative "anyvali/schemas/any_schema"
|
|
23
|
+
require_relative "anyvali/schemas/unknown_schema"
|
|
24
|
+
require_relative "anyvali/schemas/never_schema"
|
|
25
|
+
require_relative "anyvali/schemas/literal_schema"
|
|
26
|
+
require_relative "anyvali/schemas/enum_schema"
|
|
27
|
+
require_relative "anyvali/schemas/array_schema"
|
|
28
|
+
require_relative "anyvali/schemas/tuple_schema"
|
|
29
|
+
require_relative "anyvali/schemas/object_schema"
|
|
30
|
+
require_relative "anyvali/schemas/record_schema"
|
|
31
|
+
require_relative "anyvali/schemas/union_schema"
|
|
32
|
+
require_relative "anyvali/schemas/intersection_schema"
|
|
33
|
+
require_relative "anyvali/schemas/optional_schema"
|
|
34
|
+
require_relative "anyvali/schemas/nullable_schema"
|
|
35
|
+
require_relative "anyvali/schemas/ref_schema"
|
|
36
|
+
|
|
37
|
+
require_relative "anyvali/interchange/exporter"
|
|
38
|
+
require_relative "anyvali/interchange/importer"
|
|
39
|
+
|
|
40
|
+
module AnyVali
|
|
41
|
+
VERSION = "0.0.1"
|
|
42
|
+
|
|
43
|
+
module_function
|
|
44
|
+
|
|
45
|
+
# Builder methods
|
|
46
|
+
|
|
47
|
+
def string
|
|
48
|
+
StringSchema.new
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def number
|
|
52
|
+
NumberSchema.new(kind: "number")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def float32
|
|
56
|
+
NumberSchema.new(kind: "float32")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def float64
|
|
60
|
+
NumberSchema.new(kind: "float64")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def int_
|
|
64
|
+
IntSchema.new(kind: "int")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def int8
|
|
68
|
+
IntSchema.new(kind: "int8")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def int16
|
|
72
|
+
IntSchema.new(kind: "int16")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def int32
|
|
76
|
+
IntSchema.new(kind: "int32")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def int64
|
|
80
|
+
IntSchema.new(kind: "int64")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def uint8
|
|
84
|
+
IntSchema.new(kind: "uint8")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def uint16
|
|
88
|
+
IntSchema.new(kind: "uint16")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def uint32
|
|
92
|
+
IntSchema.new(kind: "uint32")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def uint64
|
|
96
|
+
IntSchema.new(kind: "uint64")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def bool
|
|
100
|
+
BoolSchema.new
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def null
|
|
104
|
+
NullSchema.new
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def any
|
|
108
|
+
AnySchema.new
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def unknown
|
|
112
|
+
UnknownSchema.new
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def never
|
|
116
|
+
NeverSchema.new
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def literal(value)
|
|
120
|
+
LiteralSchema.new(value: value)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def enum_(*values)
|
|
124
|
+
EnumSchema.new(values: values.flatten)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def array(items)
|
|
128
|
+
ArraySchema.new(items: items)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def tuple(*elements)
|
|
132
|
+
TupleSchema.new(elements: elements.flatten)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def object(properties:, required: [], unknown_keys: "reject")
|
|
136
|
+
ObjectSchema.new(properties: properties, required: required, unknown_keys: unknown_keys)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def record(values)
|
|
140
|
+
RecordSchema.new(values: values)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def union(*variants)
|
|
144
|
+
UnionSchema.new(variants: variants.flatten)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def intersection(*schemas)
|
|
148
|
+
IntersectionSchema.new(all_of: schemas.flatten)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def optional(schema)
|
|
152
|
+
OptionalSchema.new(schema: schema)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def nullable(schema)
|
|
156
|
+
NullableSchema.new(schema: schema)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def ref(ref_path)
|
|
160
|
+
RefSchema.new(ref: ref_path)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Interchange
|
|
164
|
+
|
|
165
|
+
def export(schema, mode: :portable, definitions: {})
|
|
166
|
+
Interchange::Exporter.export(schema, mode: mode, definitions: definitions)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def import(doc)
|
|
170
|
+
Interchange::Importer.import(doc)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def import_schema(doc)
|
|
174
|
+
Interchange::Importer.import_schema(doc)
|
|
175
|
+
end
|
|
176
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: anyvali
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- AnyVali Contributors
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-30 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: minitest
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '13.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '13.0'
|
|
41
|
+
description: AnyVali Ruby SDK - native validation with portable schema interchange
|
|
42
|
+
across 10 languages
|
|
43
|
+
email:
|
|
44
|
+
- hello@anyvali.com
|
|
45
|
+
executables: []
|
|
46
|
+
extensions: []
|
|
47
|
+
extra_rdoc_files: []
|
|
48
|
+
files:
|
|
49
|
+
- README.md
|
|
50
|
+
- lib/anyvali.rb
|
|
51
|
+
- lib/anyvali/anyvali_document.rb
|
|
52
|
+
- lib/anyvali/format/validators.rb
|
|
53
|
+
- lib/anyvali/interchange/exporter.rb
|
|
54
|
+
- lib/anyvali/interchange/importer.rb
|
|
55
|
+
- lib/anyvali/issue_codes.rb
|
|
56
|
+
- lib/anyvali/parse/coercion.rb
|
|
57
|
+
- lib/anyvali/parse/coercion_config.rb
|
|
58
|
+
- lib/anyvali/parse/defaults.rb
|
|
59
|
+
- lib/anyvali/parse_result.rb
|
|
60
|
+
- lib/anyvali/schema.rb
|
|
61
|
+
- lib/anyvali/schemas/any_schema.rb
|
|
62
|
+
- lib/anyvali/schemas/array_schema.rb
|
|
63
|
+
- lib/anyvali/schemas/bool_schema.rb
|
|
64
|
+
- lib/anyvali/schemas/enum_schema.rb
|
|
65
|
+
- lib/anyvali/schemas/int_schema.rb
|
|
66
|
+
- lib/anyvali/schemas/intersection_schema.rb
|
|
67
|
+
- lib/anyvali/schemas/literal_schema.rb
|
|
68
|
+
- lib/anyvali/schemas/never_schema.rb
|
|
69
|
+
- lib/anyvali/schemas/null_schema.rb
|
|
70
|
+
- lib/anyvali/schemas/nullable_schema.rb
|
|
71
|
+
- lib/anyvali/schemas/number_schema.rb
|
|
72
|
+
- lib/anyvali/schemas/object_schema.rb
|
|
73
|
+
- lib/anyvali/schemas/optional_schema.rb
|
|
74
|
+
- lib/anyvali/schemas/record_schema.rb
|
|
75
|
+
- lib/anyvali/schemas/ref_schema.rb
|
|
76
|
+
- lib/anyvali/schemas/string_schema.rb
|
|
77
|
+
- lib/anyvali/schemas/tuple_schema.rb
|
|
78
|
+
- lib/anyvali/schemas/union_schema.rb
|
|
79
|
+
- lib/anyvali/schemas/unknown_schema.rb
|
|
80
|
+
- lib/anyvali/validation_context.rb
|
|
81
|
+
- lib/anyvali/validation_error.rb
|
|
82
|
+
- lib/anyvali/validation_issue.rb
|
|
83
|
+
homepage: https://anyvali.com
|
|
84
|
+
licenses:
|
|
85
|
+
- MIT
|
|
86
|
+
metadata:
|
|
87
|
+
source_code_uri: https://github.com/BetterCorp/AnyVali
|
|
88
|
+
post_install_message:
|
|
89
|
+
rdoc_options: []
|
|
90
|
+
require_paths:
|
|
91
|
+
- lib
|
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 3.0.0
|
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - ">="
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
102
|
+
requirements: []
|
|
103
|
+
rubygems_version: 3.5.22
|
|
104
|
+
signing_key:
|
|
105
|
+
specification_version: 4
|
|
106
|
+
summary: Native validation with portable schema interchange
|
|
107
|
+
test_files: []
|