nxt_schema 0.1.0 → 1.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/.ruby-version +1 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +40 -42
- data/README.md +267 -121
- data/lib/nxt_schema.rb +60 -51
- data/lib/nxt_schema/callable.rb +21 -55
- data/lib/nxt_schema/dsl.rb +41 -31
- data/lib/nxt_schema/error.rb +4 -0
- data/lib/nxt_schema/errors/{error.rb → coercion_error.rb} +1 -2
- data/lib/nxt_schema/errors/invalid.rb +16 -0
- data/lib/nxt_schema/errors/invalid_options.rb +6 -0
- data/lib/nxt_schema/node/any_of.rb +39 -0
- data/lib/nxt_schema/node/base.rb +66 -267
- data/lib/nxt_schema/node/collection.rb +40 -56
- data/lib/nxt_schema/node/error_store.rb +41 -0
- data/lib/nxt_schema/node/errors/schema_error.rb +15 -0
- data/lib/nxt_schema/node/errors/validation_error.rb +15 -0
- data/lib/nxt_schema/node/leaf.rb +8 -36
- data/lib/nxt_schema/node/schema.rb +70 -103
- data/lib/nxt_schema/registry.rb +12 -74
- data/lib/nxt_schema/registry/proxy.rb +21 -0
- data/lib/nxt_schema/template/any_of.rb +50 -0
- data/lib/nxt_schema/template/base.rb +220 -0
- data/lib/nxt_schema/template/collection.rb +23 -0
- data/lib/nxt_schema/template/has_sub_nodes.rb +87 -0
- data/lib/nxt_schema/template/leaf.rb +13 -0
- data/lib/nxt_schema/template/maybe_evaluator.rb +28 -0
- data/lib/nxt_schema/template/on_evaluator.rb +25 -0
- data/lib/nxt_schema/template/schema.rb +22 -0
- data/lib/nxt_schema/template/sub_nodes.rb +22 -0
- data/lib/nxt_schema/template/type_resolver.rb +39 -0
- data/lib/nxt_schema/template/type_system_resolver.rb +22 -0
- data/lib/nxt_schema/types.rb +7 -4
- data/lib/nxt_schema/undefined.rb +4 -2
- data/lib/nxt_schema/validators/{equality.rb → equal_to.rb} +2 -2
- data/lib/nxt_schema/validators/error_messages.rb +42 -0
- data/lib/nxt_schema/{error_messages → validators/error_messages}/en.yaml +6 -5
- data/lib/nxt_schema/validators/{excluded.rb → excluded_in.rb} +1 -1
- data/lib/nxt_schema/validators/{included.rb → included_in.rb} +1 -1
- data/lib/nxt_schema/validators/includes.rb +1 -1
- data/lib/nxt_schema/validators/optional_node.rb +11 -6
- data/lib/nxt_schema/validators/registry.rb +1 -7
- data/lib/nxt_schema/{node → validators}/validate_with_proxy.rb +3 -3
- data/lib/nxt_schema/validators/validator.rb +2 -2
- data/lib/nxt_schema/version.rb +1 -1
- data/nxt_schema.gemspec +1 -0
- metadata +44 -21
- data/lib/nxt_schema/callable_or_value.rb +0 -72
- data/lib/nxt_schema/error_messages.rb +0 -40
- data/lib/nxt_schema/errors.rb +0 -4
- data/lib/nxt_schema/errors/invalid_options_error.rb +0 -5
- data/lib/nxt_schema/errors/schema_not_applied_error.rb +0 -5
- data/lib/nxt_schema/node/constructor.rb +0 -9
- data/lib/nxt_schema/node/default_value_evaluator.rb +0 -20
- data/lib/nxt_schema/node/error.rb +0 -13
- data/lib/nxt_schema/node/has_subnodes.rb +0 -97
- data/lib/nxt_schema/node/maybe_evaluator.rb +0 -23
- data/lib/nxt_schema/node/template_store.rb +0 -15
- data/lib/nxt_schema/node/type_resolver.rb +0 -24
data/lib/nxt_schema.rb
CHANGED
@@ -1,69 +1,78 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require "active_support/all"
|
1
|
+
require 'nxt_schema/version'
|
2
|
+
require 'active_support/all'
|
4
3
|
require 'dry-types'
|
5
4
|
require 'nxt_registry'
|
5
|
+
require 'nxt_init'
|
6
6
|
require 'yaml'
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
require_relative 'nxt_schema/types'
|
9
|
+
require_relative 'nxt_schema/callable'
|
10
|
+
require_relative 'nxt_schema/node'
|
11
|
+
require_relative 'nxt_schema/undefined'
|
12
|
+
require_relative 'nxt_schema/error'
|
13
|
+
require_relative 'nxt_schema/errors/invalid'
|
14
|
+
require_relative 'nxt_schema/errors/invalid_options'
|
15
|
+
require_relative 'nxt_schema/errors/coercion_error'
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
require_relative 'nxt_schema/validators/registry'
|
18
|
+
require_relative 'nxt_schema/validators/validate_with_proxy'
|
19
|
+
require_relative 'nxt_schema/validators/error_messages'
|
20
|
+
require_relative 'nxt_schema/validators/validator'
|
21
|
+
require_relative 'nxt_schema/validators/attribute'
|
22
|
+
require_relative 'nxt_schema/validators/equal_to'
|
23
|
+
require_relative 'nxt_schema/validators/optional_node'
|
24
|
+
require_relative 'nxt_schema/validators/greater_than'
|
25
|
+
require_relative 'nxt_schema/validators/greater_than_or_equal'
|
26
|
+
require_relative 'nxt_schema/validators/less_than'
|
27
|
+
require_relative 'nxt_schema/validators/less_than_or_equal'
|
28
|
+
require_relative 'nxt_schema/validators/pattern'
|
29
|
+
require_relative 'nxt_schema/validators/included_in'
|
30
|
+
require_relative 'nxt_schema/validators/includes'
|
31
|
+
require_relative 'nxt_schema/validators/excluded_in'
|
32
|
+
require_relative 'nxt_schema/validators/excludes'
|
33
|
+
require_relative 'nxt_schema/validators/query'
|
20
34
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
require "nxt_schema/validators/includes"
|
33
|
-
require "nxt_schema/validators/excluded"
|
34
|
-
require "nxt_schema/validators/excludes"
|
35
|
-
require "nxt_schema/validators/query"
|
35
|
+
require_relative 'nxt_schema/template/on_evaluator'
|
36
|
+
require_relative 'nxt_schema/template/maybe_evaluator'
|
37
|
+
require_relative 'nxt_schema/template/type_resolver'
|
38
|
+
require_relative 'nxt_schema/template/type_system_resolver'
|
39
|
+
require_relative 'nxt_schema/template/base'
|
40
|
+
require_relative 'nxt_schema/template/sub_nodes'
|
41
|
+
require_relative 'nxt_schema/template/has_sub_nodes'
|
42
|
+
require_relative 'nxt_schema/template/any_of'
|
43
|
+
require_relative 'nxt_schema/template/collection'
|
44
|
+
require_relative 'nxt_schema/template/schema'
|
45
|
+
require_relative 'nxt_schema/template/leaf'
|
36
46
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
require "nxt_schema/dsl"
|
47
|
+
require_relative 'nxt_schema/node/errors/schema_error'
|
48
|
+
require_relative 'nxt_schema/node/errors/validation_error'
|
49
|
+
require_relative 'nxt_schema/node/error_store'
|
50
|
+
require_relative 'nxt_schema/node/base'
|
51
|
+
require_relative 'nxt_schema/node/any_of'
|
52
|
+
require_relative 'nxt_schema/node/leaf'
|
53
|
+
require_relative 'nxt_schema/node/collection'
|
54
|
+
require_relative 'nxt_schema/node/schema'
|
55
|
+
require_relative 'nxt_schema/dsl'
|
56
|
+
require_relative 'nxt_schema/registry/proxy'
|
57
|
+
require_relative 'nxt_schema/registry'
|
49
58
|
|
50
59
|
module NxtSchema
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
extend Dsl
|
61
|
+
|
62
|
+
def register_error_messages(*paths)
|
63
|
+
Validators::ErrorMessages.load(paths)
|
55
64
|
end
|
56
65
|
|
57
|
-
def
|
58
|
-
NxtSchema::
|
66
|
+
def register_validator(validator, *keys)
|
67
|
+
keys.each { |key| NxtSchema::Validators::REGISTRY.register(key, validator) }
|
59
68
|
end
|
60
69
|
|
61
|
-
def
|
62
|
-
|
70
|
+
def register_type(key, type)
|
71
|
+
NxtSchema::Types.registry(:types).register(key, type)
|
63
72
|
end
|
64
73
|
|
65
74
|
# Load default messages
|
66
|
-
ErrorMessages.load
|
75
|
+
Validators::ErrorMessages.load
|
67
76
|
|
68
|
-
module_function :
|
77
|
+
module_function :register_error_messages, :register_validator, :register_type
|
69
78
|
end
|
data/lib/nxt_schema/callable.rb
CHANGED
@@ -1,74 +1,40 @@
|
|
1
1
|
module NxtSchema
|
2
2
|
class Callable
|
3
|
-
def initialize(
|
4
|
-
@
|
5
|
-
|
6
|
-
|
7
|
-
self.type = :method
|
8
|
-
elsif callee.respond_to?(:call)
|
9
|
-
self.type = :proc
|
10
|
-
self.context = callee.binding
|
11
|
-
else
|
12
|
-
raise ArgumentError, "Callee is nor symbol nor a proc: #{callee}"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def bind!(execution_context)
|
17
|
-
self.context = execution_context
|
18
|
-
ensure_context_not_missing
|
19
|
-
self
|
3
|
+
def initialize(callable, target = nil, *args)
|
4
|
+
@callable = callable
|
5
|
+
@target = target
|
6
|
+
@args = args
|
20
7
|
end
|
21
8
|
|
22
|
-
def
|
23
|
-
return
|
9
|
+
def call
|
10
|
+
return callable if value?
|
11
|
+
return callable.call(*args_from_arity) if proc?
|
24
12
|
|
25
|
-
|
26
|
-
ensure_context_not_missing
|
27
|
-
self
|
13
|
+
target.send(callable, *args_from_arity)
|
28
14
|
end
|
29
15
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
def call(*args)
|
34
|
-
ensure_context_not_missing
|
35
|
-
|
36
|
-
args = args.take(arity)
|
16
|
+
def method?
|
17
|
+
@method ||= callable.class.in?([Symbol, String]) && target.respond_to?(callable)
|
18
|
+
end
|
37
19
|
|
38
|
-
|
39
|
-
|
40
|
-
else
|
41
|
-
context.instance_exec(*args, &callee)
|
42
|
-
end
|
20
|
+
def proc?
|
21
|
+
@proc ||= callable.respond_to?(:call)
|
43
22
|
end
|
44
23
|
|
45
|
-
def
|
46
|
-
|
47
|
-
callee.arity
|
48
|
-
elsif method?
|
49
|
-
method = context.send(:method, callee)
|
50
|
-
method.arity
|
51
|
-
else
|
52
|
-
raise ArgumentError, "Can't resolve arity from #{callee}"
|
53
|
-
end
|
24
|
+
def value?
|
25
|
+
!method? && !proc?
|
54
26
|
end
|
55
27
|
|
56
28
|
private
|
57
29
|
|
58
|
-
|
59
|
-
type == :proc
|
60
|
-
end
|
30
|
+
attr_reader :callable, :target, :args
|
61
31
|
|
62
|
-
def
|
63
|
-
|
32
|
+
def arity
|
33
|
+
proc? ? callable.arity : 0
|
64
34
|
end
|
65
35
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
raise ArgumentError, "Missing context: #{context}"
|
36
|
+
def args_from_arity
|
37
|
+
@args_from_arity ||= ([target] + args).take(arity)
|
70
38
|
end
|
71
|
-
|
72
|
-
attr_accessor :context, :callee, :type
|
73
39
|
end
|
74
|
-
end
|
40
|
+
end
|
data/lib/nxt_schema/dsl.rb
CHANGED
@@ -1,38 +1,48 @@
|
|
1
1
|
module NxtSchema
|
2
|
-
|
3
|
-
|
4
|
-
end
|
2
|
+
module Dsl
|
3
|
+
DEFAULT_OPTIONS = { type_system: NxtSchema::Types }.freeze
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
def collection(name = :root, type: NxtSchema::Template::Collection::DEFAULT_TYPE, **options, &block)
|
6
|
+
NxtSchema::Template::Collection.new(
|
7
|
+
name: name,
|
8
|
+
type: type,
|
9
|
+
parent_node: nil,
|
10
|
+
**DEFAULT_OPTIONS.merge(options),
|
11
|
+
&block
|
12
|
+
)
|
13
|
+
end
|
9
14
|
|
10
|
-
|
11
|
-
Node::Schema.new(
|
12
|
-
name: name,
|
13
|
-
parent_node: nil,
|
14
|
-
**options.merge(
|
15
|
-
type_system: NxtSchema::Types::Params,
|
16
|
-
).reverse_merge(transform_keys: :to_sym),
|
17
|
-
&block
|
18
|
-
)
|
19
|
-
end
|
15
|
+
alias nodes collection
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
17
|
+
def schema(name = :roots, type: NxtSchema::Template::Schema::DEFAULT_TYPE, **options, &block)
|
18
|
+
NxtSchema::Template::Schema.new(
|
19
|
+
name: name,
|
20
|
+
type: type,
|
21
|
+
parent_node: nil,
|
22
|
+
**DEFAULT_OPTIONS.merge(options),
|
23
|
+
&block
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def any_of(name = :roots, **options, &block)
|
28
|
+
NxtSchema::Template::AnyOf.new(
|
29
|
+
name: name,
|
30
|
+
parent_node: nil,
|
31
|
+
**DEFAULT_OPTIONS.merge(options),
|
32
|
+
&block
|
33
|
+
)
|
34
|
+
end
|
31
35
|
|
32
|
-
|
33
|
-
alias_method :root, :schema
|
34
|
-
alias_method :nodes, :collection
|
35
|
-
alias_method :roots, :collection
|
36
|
+
# schema root with NxtSchema::Types::Params type system
|
36
37
|
|
37
|
-
|
38
|
+
def params(name = :params, type: NxtSchema::Template::Schema::DEFAULT_TYPE, **options, &block)
|
39
|
+
NxtSchema::Template::Schema.new(
|
40
|
+
name: name,
|
41
|
+
type: type,
|
42
|
+
parent_node: nil,
|
43
|
+
**options.merge(type_system: NxtSchema::Types::Params),
|
44
|
+
&block
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
38
48
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module NxtSchema
|
2
|
+
module Node
|
3
|
+
class AnyOf < Node::Base
|
4
|
+
def valid?
|
5
|
+
valid_node.present?
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
child_nodes.map(&:call)
|
10
|
+
|
11
|
+
if valid?
|
12
|
+
self.output = valid_node.output
|
13
|
+
else
|
14
|
+
child_nodes.each do |node|
|
15
|
+
merge_errors(node)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
delegate :[], to: :child_nodes
|
25
|
+
|
26
|
+
def valid_node
|
27
|
+
child_nodes.find(&:valid?)
|
28
|
+
end
|
29
|
+
|
30
|
+
def child_nodes
|
31
|
+
@child_nodes ||= nodes.map { |node| node.build_node(input: input, context: context, parent: self) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def nodes
|
35
|
+
@nodes ||= node.sub_nodes.values
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/nxt_schema/node/base.rb
CHANGED
@@ -1,317 +1,116 @@
|
|
1
1
|
module NxtSchema
|
2
2
|
module Node
|
3
3
|
class Base
|
4
|
-
def initialize(
|
5
|
-
@
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@
|
16
|
-
@
|
17
|
-
@errors = {}
|
18
|
-
@context = nil
|
19
|
-
@applied = false
|
20
|
-
@input = nil
|
21
|
-
@value = NxtSchema::Undefined.new
|
22
|
-
@locale = options.fetch(:locale) { parent_node&.locale || 'en' }
|
4
|
+
def initialize(node:, input: Undefined.new, parent:, context:, error_key:)
|
5
|
+
@node = node
|
6
|
+
@input = input
|
7
|
+
@parent = parent
|
8
|
+
@output = nil
|
9
|
+
@error_key = error_key
|
10
|
+
@context = context || parent&.context
|
11
|
+
@coerced = false
|
12
|
+
@coerced_nodes = parent&.coerced_nodes || []
|
13
|
+
@is_root = parent.nil?
|
14
|
+
@root = parent.nil? ? self : parent.root
|
15
|
+
@errors = ErrorStore.new(self)
|
16
|
+
@locale = node.options.fetch(:locale) { parent&.locale || 'en' }.to_s
|
23
17
|
|
24
|
-
|
25
|
-
|
18
|
+
@index = error_key
|
19
|
+
resolve_error_key(error_key)
|
26
20
|
end
|
27
21
|
|
28
|
-
attr_accessor :
|
29
|
-
|
30
|
-
:options,
|
31
|
-
:type,
|
32
|
-
:schema_errors,
|
33
|
-
:namespace,
|
34
|
-
:errors,
|
35
|
-
:validations,
|
36
|
-
:schema_errors_key,
|
37
|
-
:level,
|
38
|
-
:validation_errors,
|
39
|
-
:all_nodes,
|
40
|
-
:value,
|
41
|
-
:type_system,
|
42
|
-
:root,
|
43
|
-
:context,
|
44
|
-
:applied,
|
45
|
-
:input,
|
46
|
-
:additional_keys_strategy,
|
47
|
-
:locale
|
22
|
+
attr_accessor :output, :node, :input
|
23
|
+
attr_reader :parent, :context, :error_key, :coerced, :coerced_nodes, :root, :errors, :locale, :index
|
48
24
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
def parent(level = 1)
|
53
|
-
level.times.inject(self) { |acc| acc.parent_node }
|
54
|
-
end
|
55
|
-
|
56
|
-
alias_method :up, :parent
|
57
|
-
|
58
|
-
def default(default_value, &block)
|
59
|
-
options.merge!(default: default_value)
|
60
|
-
evaluate_block(block) if block_given?
|
61
|
-
self
|
25
|
+
def call
|
26
|
+
raise NotImplementedError, 'Implement this in our sub class'
|
62
27
|
end
|
63
28
|
|
64
|
-
|
65
|
-
if value.is_a?(NxtSchema::Undefined)
|
66
|
-
@meta
|
67
|
-
else
|
68
|
-
@meta = value
|
69
|
-
self
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def value_or_default_value(value)
|
74
|
-
if !value && options.key?(:default)
|
75
|
-
DefaultValueEvaluator.new(self, options.fetch(:default)).call
|
76
|
-
else
|
77
|
-
value
|
78
|
-
end
|
79
|
-
end
|
29
|
+
delegate :name, :options, to: :node
|
80
30
|
|
81
|
-
def
|
82
|
-
|
83
|
-
evaluate_block(block) if block_given?
|
84
|
-
self
|
31
|
+
def root?
|
32
|
+
@is_root
|
85
33
|
end
|
86
34
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
options.merge!(optional: optional_value)
|
91
|
-
evaluate_block(block) if block_given?
|
92
|
-
self
|
35
|
+
def valid?
|
36
|
+
errors.empty?
|
93
37
|
end
|
94
38
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
options.merge!(presence: presence_value)
|
99
|
-
evaluate_block(block) if block_given?
|
100
|
-
self
|
39
|
+
def add_error(error)
|
40
|
+
errors.add_validation_error(message: error)
|
101
41
|
end
|
102
42
|
|
103
|
-
def
|
104
|
-
|
105
|
-
presence_option = options[:presence]
|
106
|
-
|
107
|
-
options[:presence] = if presence_option.respond_to?(:call)
|
108
|
-
Callable.new(presence_option).call(self, value)
|
109
|
-
else
|
110
|
-
presence_option
|
111
|
-
end
|
112
|
-
end
|
43
|
+
def add_schema_error(error)
|
44
|
+
errors.add_schema_error(message: error)
|
113
45
|
end
|
114
46
|
|
115
|
-
def
|
116
|
-
|
117
|
-
validator = validator(key, *args)
|
118
|
-
elsif key.respond_to?(:call)
|
119
|
-
validator = key
|
120
|
-
else
|
121
|
-
raise ArgumentError, "Don't know how to resolve validator from: #{key}"
|
122
|
-
end
|
123
|
-
|
124
|
-
add_validators(validator)
|
125
|
-
evaluate_block(block) if block_given?
|
126
|
-
self
|
47
|
+
def merge_errors(node)
|
48
|
+
errors.merge_errors(node)
|
127
49
|
end
|
128
50
|
|
129
|
-
def
|
130
|
-
|
131
|
-
validation_errors[index] << error
|
132
|
-
false
|
133
|
-
end
|
51
|
+
def run_validations
|
52
|
+
return false unless coerced?
|
134
53
|
|
135
|
-
|
136
|
-
|
137
|
-
|
54
|
+
node.validations.each do |validation|
|
55
|
+
args = [self, input]
|
56
|
+
validation.call(*args.take(validation.arity))
|
138
57
|
end
|
139
|
-
|
140
|
-
# we have to start from the bottom, leafs before others on the same level
|
141
|
-
sorted_nodes.reverse_each(&:apply_validations)
|
142
58
|
end
|
143
59
|
|
144
|
-
def
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
schema_errors.reject! { |_, v| v.empty? }
|
149
|
-
|
150
|
-
# TODO: Is this correct? - Do not apply validations when maybe criteria applies?
|
151
|
-
unless schema_errors[schema_errors_key]&.any? && !maybe_criteria_applies?(value)
|
152
|
-
build_validations
|
60
|
+
def up(levels = 1)
|
61
|
+
0.upto(levels - 1).inject(self) do |acc, _|
|
62
|
+
parent = acc.send(:parent)
|
63
|
+
break acc unless parent
|
153
64
|
|
154
|
-
|
155
|
-
args = [self, value]
|
156
|
-
validation.call(*args.take(validation.arity))
|
157
|
-
end
|
65
|
+
parent
|
158
66
|
end
|
159
|
-
|
160
|
-
if self.is_a?(NxtSchema::Node::Collection) && value.respond_to?(:each)
|
161
|
-
value.each_with_index do |item, index|
|
162
|
-
validation_errors[index]&.reject! { |_, v| v.empty? }
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
validation_errors.reject! { |_, v| v.empty? }
|
167
|
-
|
168
|
-
self
|
169
|
-
end
|
170
|
-
|
171
|
-
def build_validations
|
172
|
-
validations_from_options = Array(options.fetch(:validate, []))
|
173
|
-
self.validations = validations_from_options
|
174
|
-
end
|
175
|
-
|
176
|
-
def schema_errors?
|
177
|
-
schema_errors.reject! { |_, v| v.empty? }
|
178
|
-
schema_errors.any?
|
179
|
-
end
|
180
|
-
|
181
|
-
def validation_errors?
|
182
|
-
validation_errors.reject! { |_, v| v.empty? }
|
183
|
-
validation_errors.any?
|
184
|
-
end
|
185
|
-
|
186
|
-
def root?
|
187
|
-
@is_root
|
188
|
-
end
|
189
|
-
|
190
|
-
def leaf?
|
191
|
-
false
|
192
|
-
end
|
193
|
-
|
194
|
-
def valid?
|
195
|
-
raise SchemaNotAppliedError, 'Schema was not applied yet' unless applied?
|
196
|
-
|
197
|
-
validation_errors.empty?
|
198
|
-
end
|
199
|
-
|
200
|
-
def add_validators(validator)
|
201
|
-
options[:validate] ||= []
|
202
|
-
options[:validate] = Array(options.fetch(:validate, []))
|
203
|
-
options[:validate] << validator
|
204
|
-
end
|
205
|
-
|
206
|
-
def validator(key, *args)
|
207
|
-
Validators::Registry::VALIDATORS.resolve(key).new(*args).build
|
208
|
-
end
|
209
|
-
|
210
|
-
def validate_with(&block)
|
211
|
-
add_validators(
|
212
|
-
->(node) { NxtSchema::Node::ValidateWithProxy.new(node).validate(&block) }
|
213
|
-
)
|
214
67
|
end
|
215
68
|
|
216
69
|
private
|
217
70
|
|
218
|
-
|
219
|
-
return if all_nodes.key?(object_id)
|
71
|
+
attr_writer :coerced, :root
|
220
72
|
|
221
|
-
|
222
|
-
|
223
|
-
|
73
|
+
def coerce_input
|
74
|
+
output = input.is_a?(Undefined) && node.omnipresent? ? input : node.type.call(input)
|
75
|
+
self.output = output
|
224
76
|
|
225
|
-
|
226
|
-
|
77
|
+
rescue Dry::Types::CoercionError, NxtSchema::Errors::CoercionError => error
|
78
|
+
add_schema_error(error.message)
|
227
79
|
end
|
228
80
|
|
229
|
-
def
|
230
|
-
self.
|
81
|
+
def apply_on_evaluators
|
82
|
+
node.on_evaluators.each { |evaluator| evaluator.call(input, self, context) { |result| self.input = result } }
|
231
83
|
end
|
232
84
|
|
233
|
-
def
|
234
|
-
|
235
|
-
|
85
|
+
def maybe_evaluator_applies?
|
86
|
+
@maybe_evaluator_applies ||= node.maybe_evaluators.inject(false) do |acc, evaluator|
|
87
|
+
result = (acc || evaluator.call(input, self, context))
|
236
88
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
def maybe_criteria_applies?(value)
|
241
|
-
@maybe_criteria_applies ||= begin
|
242
|
-
options.key?(:maybe) && MaybeEvaluator.new(self, options.fetch(:maybe), value).call
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
def self_without_empty_schema_errors
|
247
|
-
schema_errors.reject! { |_, v| v.empty? }
|
248
|
-
validate_all_nodes if root?
|
249
|
-
self.errors = flat_validation_errors(validation_errors, name)
|
250
|
-
self
|
251
|
-
end
|
252
|
-
|
253
|
-
def flat_validation_errors(errors, namespace, acc = {})
|
254
|
-
errors.each_with_object(acc) do |(key, val), acc|
|
255
|
-
current_namespace = [namespace, key].reject { |namespace| namespace == schema_errors_key }.compact.join('.')
|
256
|
-
|
257
|
-
if val.is_a?(::Hash)
|
258
|
-
flat_validation_errors(val, current_namespace, acc)
|
259
|
-
else
|
260
|
-
acc[current_namespace] ||= []
|
261
|
-
acc[current_namespace] += Array(val)
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def name_from_index
|
267
|
-
if parent_node
|
268
|
-
if parent_node.is_a?(NxtSchema::Node::Collection)
|
269
|
-
size + 1
|
89
|
+
if result
|
90
|
+
self.output = input
|
91
|
+
break true
|
270
92
|
else
|
271
|
-
|
93
|
+
false
|
272
94
|
end
|
273
|
-
else
|
274
|
-
:root
|
275
95
|
end
|
276
96
|
end
|
277
97
|
|
278
|
-
def
|
279
|
-
|
280
|
-
instance_exec(&block)
|
281
|
-
else
|
282
|
-
evaluator_args = [self, value]
|
283
|
-
block.call(*evaluator_args.take(block.arity))
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
def resolve_type_system
|
288
|
-
type_system = options.fetch(:type_system) { parent_node&.type_system }
|
98
|
+
def register_as_coerced_when_no_errors
|
99
|
+
return unless valid?
|
289
100
|
|
290
|
-
self.
|
291
|
-
|
292
|
-
elsif type_system.is_a?(Symbol) || type_system.is_a?(String)
|
293
|
-
"NxtSchema::Types::#{type_system.to_s.classify}".constantize
|
294
|
-
else
|
295
|
-
NxtSchema::Types
|
296
|
-
end
|
101
|
+
self.coerced = true
|
102
|
+
coerced_nodes << self
|
297
103
|
end
|
298
104
|
|
299
|
-
def
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
def type_resolver
|
304
|
-
@type_resolver ||= begin
|
305
|
-
if root?
|
306
|
-
TypeResolver.new
|
307
|
-
else
|
308
|
-
raise NoMethodError, 'type_resolver is only available on root node'
|
309
|
-
end
|
310
|
-
end
|
105
|
+
def resolve_error_key(key)
|
106
|
+
parts = [parent&.error_key].compact
|
107
|
+
parts << (key.present? ? "#{node.name}[#{key}]" : node.name)
|
108
|
+
@error_key = parts.join('.')
|
311
109
|
end
|
312
110
|
|
313
|
-
def
|
314
|
-
|
111
|
+
def coerced?(&block)
|
112
|
+
block.call(self) if @coerced && block_given?
|
113
|
+
@coerced
|
315
114
|
end
|
316
115
|
end
|
317
116
|
end
|