vident 1.0.1 → 2.0.0
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/CHANGELOG.md +54 -0
- data/README.md +49 -18
- data/lib/vident/caching.rb +4 -110
- data/lib/vident/capabilities/caching.rb +98 -0
- data/lib/vident/capabilities/child_element_rendering.rb +92 -0
- data/lib/vident/capabilities/class_list_building.rb +23 -0
- data/lib/vident/capabilities/declarable.rb +39 -0
- data/lib/vident/capabilities/identifiable.rb +54 -0
- data/lib/vident/capabilities/inspectable.rb +17 -0
- data/lib/vident/capabilities/root_element_rendering.rb +31 -0
- data/lib/vident/capabilities/stimulus_data_emitting.rb +98 -0
- data/lib/vident/capabilities/stimulus_declaring.rb +79 -0
- data/lib/vident/capabilities/stimulus_draft.rb +51 -0
- data/lib/vident/capabilities/stimulus_mutation.rb +60 -0
- data/lib/vident/capabilities/stimulus_parsing.rb +144 -0
- data/lib/vident/capabilities/tailwind.rb +18 -0
- data/lib/vident/component.rb +14 -76
- data/lib/vident/engine.rb +6 -5
- data/lib/vident/error.rb +16 -0
- data/lib/vident/internals/action_builder.rb +97 -0
- data/lib/vident/internals/attribute_writer.rb +17 -0
- data/lib/vident/internals/class_list_builder.rb +62 -0
- data/lib/vident/internals/declaration.rb +13 -0
- data/lib/vident/internals/declarations.rb +64 -0
- data/lib/vident/internals/draft.rb +47 -0
- data/lib/vident/internals/dsl.rb +172 -0
- data/lib/vident/internals/plan.rb +9 -0
- data/lib/vident/internals/registry.rb +37 -0
- data/lib/vident/internals/resolver.rb +316 -0
- data/lib/vident/internals/target_builder.rb +23 -0
- data/lib/vident/stable_id.rb +3 -3
- data/lib/vident/stimulus/action.rb +127 -0
- data/lib/vident/stimulus/base.rb +26 -0
- data/lib/vident/stimulus/class_map.rb +57 -0
- data/lib/vident/stimulus/collection.rb +40 -0
- data/lib/vident/stimulus/combinable.rb +30 -0
- data/lib/vident/stimulus/controller.rb +45 -0
- data/lib/vident/stimulus/naming.rb +9 -9
- data/lib/vident/stimulus/null.rb +7 -0
- data/lib/vident/stimulus/outlet.rb +93 -0
- data/lib/vident/stimulus/param.rb +56 -0
- data/lib/vident/stimulus/target.rb +48 -0
- data/lib/vident/stimulus/value.rb +57 -0
- data/lib/vident/stimulus_null.rb +4 -8
- data/lib/vident/tailwind.rb +4 -17
- data/lib/vident/types.rb +28 -0
- data/lib/vident/version.rb +1 -6
- data/lib/vident.rb +44 -36
- data/skills/vident/SKILL.md +133 -21
- data/skills/vident/api-reference.md +662 -0
- data/skills/vident/examples.md +505 -0
- metadata +40 -28
- data/lib/vident/child_element_helper.rb +0 -64
- data/lib/vident/class_list_builder.rb +0 -112
- data/lib/vident/component_attribute_resolver.rb +0 -87
- data/lib/vident/component_class_lists.rb +0 -34
- data/lib/vident/stimulus/primitive.rb +0 -38
- data/lib/vident/stimulus.rb +0 -31
- data/lib/vident/stimulus_action.rb +0 -133
- data/lib/vident/stimulus_action_collection.rb +0 -11
- data/lib/vident/stimulus_attribute_base.rb +0 -67
- data/lib/vident/stimulus_attributes.rb +0 -129
- data/lib/vident/stimulus_builder.rb +0 -119
- data/lib/vident/stimulus_class.rb +0 -59
- data/lib/vident/stimulus_class_collection.rb +0 -11
- data/lib/vident/stimulus_collection_base.rb +0 -51
- data/lib/vident/stimulus_component.rb +0 -75
- data/lib/vident/stimulus_controller.rb +0 -41
- data/lib/vident/stimulus_controller_collection.rb +0 -14
- data/lib/vident/stimulus_data_attribute_builder.rb +0 -32
- data/lib/vident/stimulus_helper.rb +0 -66
- data/lib/vident/stimulus_outlet.rb +0 -90
- data/lib/vident/stimulus_outlet_collection.rb +0 -11
- data/lib/vident/stimulus_param.rb +0 -42
- data/lib/vident/stimulus_param_collection.rb +0 -11
- data/lib/vident/stimulus_target.rb +0 -47
- data/lib/vident/stimulus_target_collection.rb +0 -18
- data/lib/vident/stimulus_value.rb +0 -39
- data/lib/vident/stimulus_value_collection.rb +0 -11
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "declaration"
|
|
4
|
+
|
|
5
|
+
module Vident
|
|
6
|
+
module Internals
|
|
7
|
+
# Fluent builder returned by `action(...)`. If no chain methods are called,
|
|
8
|
+
# raw args pass through untouched so bare `action :click` still works.
|
|
9
|
+
class ActionBuilder
|
|
10
|
+
KWARG_KEYS = %i[on call_method modifier keyboard window on_controller when].freeze
|
|
11
|
+
|
|
12
|
+
def initialize(*args, **meta)
|
|
13
|
+
@args = args
|
|
14
|
+
unknown = meta.keys - KWARG_KEYS
|
|
15
|
+
raise ArgumentError, "action: unknown option(s) #{unknown.inspect}. Valid: #{KWARG_KEYS.inspect}" unless unknown.empty?
|
|
16
|
+
|
|
17
|
+
@event = meta[:on]
|
|
18
|
+
@method_name = meta[:call_method]
|
|
19
|
+
@modifiers = meta.key?(:modifier) ? Array(meta[:modifier]) : nil
|
|
20
|
+
@keyboard = meta[:keyboard]
|
|
21
|
+
@window = meta.fetch(:window, false)
|
|
22
|
+
@controller_ref = meta[:on_controller]
|
|
23
|
+
@when_proc = meta[:when]
|
|
24
|
+
@touched = !meta.empty?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def on(event)
|
|
28
|
+
@event = event
|
|
29
|
+
@touched = true
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def call_method(name)
|
|
34
|
+
@method_name = name
|
|
35
|
+
@touched = true
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def modifier(*mods)
|
|
40
|
+
(@modifiers ||= []).concat(mods)
|
|
41
|
+
@touched = true
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def keyboard(str)
|
|
46
|
+
@keyboard = str
|
|
47
|
+
@touched = true
|
|
48
|
+
self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def window
|
|
52
|
+
@window = true
|
|
53
|
+
@touched = true
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def on_controller(ref)
|
|
58
|
+
@controller_ref = ref
|
|
59
|
+
@touched = true
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def when(callable = nil, &block)
|
|
64
|
+
@when_proc = block || callable
|
|
65
|
+
self
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def to_declaration
|
|
69
|
+
return Declaration.new(args: @args.freeze, when_proc: @when_proc, meta: {}.freeze) unless @touched
|
|
70
|
+
Declaration.new(args: [build_descriptor].freeze, when_proc: @when_proc, meta: {}.freeze)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def build_descriptor
|
|
76
|
+
h = base_descriptor.dup
|
|
77
|
+
h[:event] = @event if @event
|
|
78
|
+
h[:method] = @method_name if @method_name
|
|
79
|
+
h[:options] = @modifiers.dup if @modifiers
|
|
80
|
+
h[:keyboard] = @keyboard if @keyboard
|
|
81
|
+
h[:window] = true if @window
|
|
82
|
+
h[:controller] = @controller_ref if @controller_ref
|
|
83
|
+
h
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def base_descriptor
|
|
87
|
+
case @args
|
|
88
|
+
in [Symbol => m] then {method: m}
|
|
89
|
+
in [Symbol => e, Symbol => m] then {event: e, method: m}
|
|
90
|
+
in [Symbol => e, String => ctrl, Symbol => m] then {event: e, method: m, controller: ctrl}
|
|
91
|
+
in [Hash => h] then h
|
|
92
|
+
else {}
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "registry"
|
|
4
|
+
|
|
5
|
+
module Vident
|
|
6
|
+
module Internals
|
|
7
|
+
module AttributeWriter
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def call(plan)
|
|
11
|
+
Registry::KINDS.reduce({}) do |acc, kind|
|
|
12
|
+
acc.merge(kind.value_class.to_data_hash(plan.public_send(kind.name)))
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "set"
|
|
4
|
+
|
|
5
|
+
module Vident
|
|
6
|
+
module Internals
|
|
7
|
+
# Builds the root element's CSS class list with a 6-tier precedence cascade.
|
|
8
|
+
# Tiers (left-to-right): component_name, then the highest-priority non-nil of
|
|
9
|
+
# root_element_classes / root_element_attributes[:classes] / root_element(class:) /
|
|
10
|
+
# html_options[:class], then classes: prop (always appended), then stimulus class maps.
|
|
11
|
+
module ClassListBuilder
|
|
12
|
+
CLASSNAME_SEPARATOR = " "
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def call(
|
|
17
|
+
component_name: nil,
|
|
18
|
+
root_element_classes: nil,
|
|
19
|
+
root_element_attributes_classes: nil,
|
|
20
|
+
root_element_html_class: nil,
|
|
21
|
+
html_options_class: nil,
|
|
22
|
+
classes_prop: nil,
|
|
23
|
+
stimulus_classes: nil,
|
|
24
|
+
stimulus_class_names: nil,
|
|
25
|
+
tailwind_merger: nil
|
|
26
|
+
)
|
|
27
|
+
parts = []
|
|
28
|
+
parts << component_name if component_name
|
|
29
|
+
|
|
30
|
+
if html_options_class
|
|
31
|
+
parts.concat(Array.wrap(html_options_class))
|
|
32
|
+
elsif root_element_html_class
|
|
33
|
+
parts.concat(Array.wrap(root_element_html_class))
|
|
34
|
+
elsif root_element_attributes_classes
|
|
35
|
+
parts.concat(Array.wrap(root_element_attributes_classes))
|
|
36
|
+
elsif root_element_classes
|
|
37
|
+
parts.concat(Array.wrap(root_element_classes))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
parts.concat(Array.wrap(classes_prop)) if classes_prop
|
|
41
|
+
|
|
42
|
+
parts.compact!
|
|
43
|
+
|
|
44
|
+
if stimulus_classes && stimulus_class_names && !stimulus_class_names.empty?
|
|
45
|
+
parts.concat(stimulus_class_css(stimulus_classes, stimulus_class_names))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
flattened = parts.flat_map { |s| s.to_s.split(/\s+/) }.reject(&:empty?)
|
|
49
|
+
deduped = flattened.uniq
|
|
50
|
+
return nil if deduped.empty?
|
|
51
|
+
|
|
52
|
+
joined = deduped.join(CLASSNAME_SEPARATOR)
|
|
53
|
+
tailwind_merger ? tailwind_merger.merge(joined) : joined
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def stimulus_class_css(class_maps, names)
|
|
57
|
+
names_set = names.map { |n| n.to_s.dasherize }.to_set
|
|
58
|
+
class_maps.select { |cm| names_set.include?(cm.name) }.map(&:css)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Vident
|
|
4
|
+
module Internals
|
|
5
|
+
# One unresolved DSL entry; the Resolver parses it into typed Stimulus
|
|
6
|
+
# value objects at instance init time.
|
|
7
|
+
Declaration = Data.define(:args, :when_proc, :meta) do
|
|
8
|
+
def self.of(*args, when_proc: nil, **meta)
|
|
9
|
+
new(args: args.freeze, when_proc: when_proc, meta: meta.freeze)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "declaration"
|
|
4
|
+
|
|
5
|
+
module Vident
|
|
6
|
+
module Internals
|
|
7
|
+
# Frozen per-class aggregate of raw `Declaration` entries from `stimulus do` blocks.
|
|
8
|
+
# Keyed kinds use `[key, Declaration]` pairs so later same-key entries replace earlier ones;
|
|
9
|
+
# positional kinds are flat arrays where later blocks append.
|
|
10
|
+
class Declarations < Data.define(
|
|
11
|
+
:controllers,
|
|
12
|
+
:actions,
|
|
13
|
+
:targets,
|
|
14
|
+
:outlets,
|
|
15
|
+
:values,
|
|
16
|
+
:params,
|
|
17
|
+
:class_maps,
|
|
18
|
+
:values_from_props
|
|
19
|
+
)
|
|
20
|
+
EMPTY_ARRAY = [].freeze
|
|
21
|
+
|
|
22
|
+
def self.empty = @empty ||= new(
|
|
23
|
+
controllers: EMPTY_ARRAY,
|
|
24
|
+
actions: EMPTY_ARRAY,
|
|
25
|
+
targets: EMPTY_ARRAY,
|
|
26
|
+
outlets: EMPTY_ARRAY,
|
|
27
|
+
values: EMPTY_ARRAY,
|
|
28
|
+
params: EMPTY_ARRAY,
|
|
29
|
+
class_maps: EMPTY_ARRAY,
|
|
30
|
+
values_from_props: EMPTY_ARRAY
|
|
31
|
+
).freeze
|
|
32
|
+
|
|
33
|
+
def any?
|
|
34
|
+
!controllers.empty? || !actions.empty? || !targets.empty? ||
|
|
35
|
+
!outlets.empty? || !values.empty? || !params.empty? ||
|
|
36
|
+
!class_maps.empty? || !values_from_props.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def merge(other)
|
|
40
|
+
self.class.new(
|
|
41
|
+
controllers: concat_positional(controllers, other.controllers),
|
|
42
|
+
actions: concat_positional(actions, other.actions),
|
|
43
|
+
targets: concat_positional(targets, other.targets),
|
|
44
|
+
outlets: merge_keyed(outlets, other.outlets),
|
|
45
|
+
values: merge_keyed(values, other.values),
|
|
46
|
+
params: merge_keyed(params, other.params),
|
|
47
|
+
class_maps: merge_keyed(class_maps, other.class_maps),
|
|
48
|
+
values_from_props: (values_from_props + other.values_from_props).uniq.freeze
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def concat_positional(a, b) = (a + b).freeze
|
|
55
|
+
|
|
56
|
+
def merge_keyed(a, b)
|
|
57
|
+
merged = {}
|
|
58
|
+
a.each { |(k, d)| merged[k] = d }
|
|
59
|
+
b.each { |(k, d)| merged[k] = d }
|
|
60
|
+
merged.to_a.freeze
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "registry"
|
|
4
|
+
require_relative "plan"
|
|
5
|
+
|
|
6
|
+
module Vident
|
|
7
|
+
module Internals
|
|
8
|
+
# Per-instance mutable accumulator; seals into a frozen Plan once rendering begins.
|
|
9
|
+
class Draft
|
|
10
|
+
def initialize(**collections)
|
|
11
|
+
@collections = Registry.names.to_h { |name| [name, []] }
|
|
12
|
+
collections.each { |k, v| @collections[k] = v.dup if @collections.key?(k) }
|
|
13
|
+
@sealed = false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
Registry.each do |kind|
|
|
17
|
+
define_method(kind.name) { @collections[kind.name] }
|
|
18
|
+
|
|
19
|
+
define_method(:"add_#{kind.name}") do |value_or_values|
|
|
20
|
+
raise_if_sealed!
|
|
21
|
+
Array(value_or_values).each { |v| @collections[kind.name] << v }
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def sealed? = @sealed
|
|
27
|
+
|
|
28
|
+
def seal!
|
|
29
|
+
return @plan if @sealed
|
|
30
|
+
@sealed = true
|
|
31
|
+
@collections.each_value(&:freeze)
|
|
32
|
+
@collections.freeze
|
|
33
|
+
@plan = Plan.new(**@collections)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def plan = seal!
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def raise_if_sealed!
|
|
41
|
+
return unless @sealed
|
|
42
|
+
raise ::Vident::StateError,
|
|
43
|
+
"cannot modify stimulus attributes after rendering has begun"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "declaration"
|
|
4
|
+
require_relative "declarations"
|
|
5
|
+
require_relative "action_builder"
|
|
6
|
+
require_relative "target_builder"
|
|
7
|
+
|
|
8
|
+
module Vident
|
|
9
|
+
module Internals
|
|
10
|
+
# Block receiver for `stimulus do ... end`. Records raw Declaration entries;
|
|
11
|
+
# parsing into typed Stimulus value objects is deferred to the Resolver.
|
|
12
|
+
class DSL
|
|
13
|
+
attr_reader :caller_location
|
|
14
|
+
|
|
15
|
+
def initialize(caller_location: nil)
|
|
16
|
+
@caller_location = caller_location
|
|
17
|
+
@controllers = []
|
|
18
|
+
@actions = []
|
|
19
|
+
@targets = []
|
|
20
|
+
@outlets = []
|
|
21
|
+
@values = []
|
|
22
|
+
@params = []
|
|
23
|
+
@class_maps = []
|
|
24
|
+
@values_from_props = []
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# ---- plural (kwargs) forms --------------------------------------
|
|
28
|
+
|
|
29
|
+
def controllers(*args)
|
|
30
|
+
args.each do |arg|
|
|
31
|
+
case arg
|
|
32
|
+
in Array
|
|
33
|
+
controller(*arg)
|
|
34
|
+
else
|
|
35
|
+
controller(arg)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def actions(*names)
|
|
42
|
+
names.each do |name|
|
|
43
|
+
case name
|
|
44
|
+
in Array
|
|
45
|
+
action(*name)
|
|
46
|
+
else
|
|
47
|
+
action(name)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
self
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def targets(*names)
|
|
54
|
+
names.each do |name|
|
|
55
|
+
case name
|
|
56
|
+
in Array
|
|
57
|
+
target(*name)
|
|
58
|
+
else
|
|
59
|
+
target(name)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
self
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def values(**hash)
|
|
66
|
+
hash.each { |k, v| record_keyed(@values, k, v) }
|
|
67
|
+
self
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def params(**hash)
|
|
71
|
+
hash.each { |k, v| record_keyed(@params, k, v) }
|
|
72
|
+
self
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def classes(**hash)
|
|
76
|
+
hash.each { |k, v| record_keyed(@class_maps, k, v) }
|
|
77
|
+
self
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Positional Hash arg supports keys like `"admin--users"` that can't be Ruby kwargs.
|
|
81
|
+
def outlets(positional = nil, **hash)
|
|
82
|
+
if positional.is_a?(Hash)
|
|
83
|
+
positional.each { |k, v| record_keyed(@outlets, k, v) }
|
|
84
|
+
elsif !positional.nil?
|
|
85
|
+
raise ArgumentError, "outlets: positional arg must be a Hash, got #{positional.class}"
|
|
86
|
+
end
|
|
87
|
+
hash.each { |k, v| record_keyed(@outlets, k, v) }
|
|
88
|
+
self
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def values_from_props(*names)
|
|
92
|
+
@values_from_props.concat(names.map(&:to_sym))
|
|
93
|
+
self
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# ---- singular forms --------------------------------------------
|
|
97
|
+
|
|
98
|
+
def controller(*args, **meta)
|
|
99
|
+
@controllers << Declaration.of(*args, **meta)
|
|
100
|
+
self
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def action(*args, **meta)
|
|
104
|
+
builder = ActionBuilder.new(*args, **meta)
|
|
105
|
+
@actions << builder
|
|
106
|
+
builder
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def target(*args)
|
|
110
|
+
builder = TargetBuilder.new(*args)
|
|
111
|
+
@targets << builder
|
|
112
|
+
builder
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def value(name, *args, **meta)
|
|
116
|
+
entry = [name, Declaration.of(*args, **meta)]
|
|
117
|
+
replace_or_append(@values, entry)
|
|
118
|
+
self
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def param(name, *args, **meta)
|
|
122
|
+
entry = [name, Declaration.of(*args, **meta)]
|
|
123
|
+
replace_or_append(@params, entry)
|
|
124
|
+
self
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def outlet(name, *args, **meta)
|
|
128
|
+
entry = [name, Declaration.of(*args, **meta)]
|
|
129
|
+
replace_or_append(@outlets, entry)
|
|
130
|
+
self
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def class_map(name, *args, **meta)
|
|
134
|
+
entry = [name, Declaration.of(*args, **meta)]
|
|
135
|
+
replace_or_append(@class_maps, entry)
|
|
136
|
+
self
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# ---- folding ----------------------------------------------------
|
|
140
|
+
|
|
141
|
+
def to_declarations
|
|
142
|
+
Declarations.new(
|
|
143
|
+
controllers: @controllers.dup.freeze,
|
|
144
|
+
actions: @actions.map(&:to_declaration).freeze,
|
|
145
|
+
targets: @targets.map(&:to_declaration).freeze,
|
|
146
|
+
outlets: @outlets.dup.freeze,
|
|
147
|
+
values: @values.dup.freeze,
|
|
148
|
+
params: @params.dup.freeze,
|
|
149
|
+
class_maps: @class_maps.dup.freeze,
|
|
150
|
+
values_from_props: @values_from_props.dup.freeze
|
|
151
|
+
).freeze
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
private
|
|
155
|
+
|
|
156
|
+
def record_keyed(bucket, key, value)
|
|
157
|
+
entry = [key, Declaration.of(value)]
|
|
158
|
+
replace_or_append(bucket, entry)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def replace_or_append(bucket, entry)
|
|
162
|
+
key = entry.first
|
|
163
|
+
idx = bucket.index { |(k, _)| k == key }
|
|
164
|
+
if idx
|
|
165
|
+
bucket[idx] = entry
|
|
166
|
+
else
|
|
167
|
+
bucket << entry
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../stimulus/controller"
|
|
4
|
+
require_relative "../stimulus/action"
|
|
5
|
+
require_relative "../stimulus/target"
|
|
6
|
+
require_relative "../stimulus/outlet"
|
|
7
|
+
require_relative "../stimulus/value"
|
|
8
|
+
require_relative "../stimulus/param"
|
|
9
|
+
require_relative "../stimulus/class_map"
|
|
10
|
+
|
|
11
|
+
module Vident
|
|
12
|
+
module Internals
|
|
13
|
+
module Registry
|
|
14
|
+
Kind = Data.define(:name, :plural_name, :singular_name, :value_class, :keyed) do
|
|
15
|
+
alias_method :keyed?, :keyed
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
KINDS = [
|
|
19
|
+
Kind.new(:controllers, :controllers, :controller, Vident::Stimulus::Controller, false),
|
|
20
|
+
Kind.new(:actions, :actions, :action, Vident::Stimulus::Action, false),
|
|
21
|
+
Kind.new(:targets, :targets, :target, Vident::Stimulus::Target, false),
|
|
22
|
+
Kind.new(:outlets, :outlets, :outlet, Vident::Stimulus::Outlet, true),
|
|
23
|
+
Kind.new(:values, :values, :value, Vident::Stimulus::Value, true),
|
|
24
|
+
Kind.new(:params, :params, :param, Vident::Stimulus::Param, true),
|
|
25
|
+
Kind.new(:class_maps, :classes, :class, Vident::Stimulus::ClassMap, true)
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
BY_NAME = KINDS.to_h { |k| [k.name, k] }.freeze
|
|
29
|
+
|
|
30
|
+
def self.fetch(name) = BY_NAME.fetch(name)
|
|
31
|
+
|
|
32
|
+
def self.each(&block) = KINDS.each(&block)
|
|
33
|
+
|
|
34
|
+
def self.names = BY_NAME.keys
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|