herb 0.9.5-arm-linux-gnu → 0.9.7-arm-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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/ext/herb/extension.c +8 -0
  3. data/ext/herb/extension_helpers.c +1 -0
  4. data/lib/herb/3.0/herb.so +0 -0
  5. data/lib/herb/3.1/herb.so +0 -0
  6. data/lib/herb/3.2/herb.so +0 -0
  7. data/lib/herb/3.3/herb.so +0 -0
  8. data/lib/herb/3.4/herb.so +0 -0
  9. data/lib/herb/4.0/herb.so +0 -0
  10. data/lib/herb/action_view/helper_registry.rb +8107 -0
  11. data/lib/herb/parser_options.rb +7 -2
  12. data/lib/herb/project.rb +2 -5
  13. data/lib/herb/version.rb +1 -1
  14. data/sig/herb/action_view/helper_registry.rbs +1144 -0
  15. data/sig/herb/parser_options.rbs +6 -2
  16. data/src/analyze/action_view/generated_handlers.c +355 -0
  17. data/src/analyze/action_view/generated_handlers.h +16 -0
  18. data/src/analyze/action_view/helper_registry.c +7244 -0
  19. data/src/analyze/action_view/image_tag.c +4 -31
  20. data/src/analyze/action_view/javascript_include_tag.c +1 -42
  21. data/src/analyze/action_view/javascript_tag.c +0 -52
  22. data/src/analyze/action_view/registry.c +2 -2
  23. data/src/analyze/action_view/tag_helpers.c +8 -120
  24. data/src/analyze/action_view/turbo_frame_tag.c +1 -36
  25. data/src/analyze/analyze.c +7 -0
  26. data/src/analyze/postfix_conditionals.c +326 -0
  27. data/src/analyze/ternary_conditionals.c +265 -0
  28. data/src/include/analyze/action_view/helper_registry.h +325 -0
  29. data/src/include/analyze/action_view/tag_helpers.h +0 -1
  30. data/src/include/analyze/postfix_conditionals.h +9 -0
  31. data/src/include/analyze/ternary_conditionals.h +15 -0
  32. data/src/include/parser/parser.h +1 -0
  33. data/src/include/version.h +1 -1
  34. data/src/parser.c +1 -0
  35. data/templates/java/org/herb/ast/HelperRegistry.java.erb +258 -0
  36. data/templates/javascript/packages/core/src/action-view-helpers.ts.erb +171 -0
  37. data/templates/javascript/packages/core/src/nodes.ts.erb +5 -1
  38. data/templates/lib/herb/action_view/helper_registry.rb.erb +288 -0
  39. data/templates/rust/src/action_view_helpers.rs.erb +154 -0
  40. data/templates/src/analyze/action_view/generated_handlers.c.erb +230 -0
  41. data/templates/src/analyze/action_view/generated_handlers.h.erb +12 -0
  42. data/templates/src/analyze/action_view/helper_registry.c.erb +114 -0
  43. data/templates/src/include/analyze/action_view/helper_registry.h.erb +82 -0
  44. data/templates/template.rb +338 -1
  45. metadata +19 -3
  46. data/src/analyze/action_view/content_tag.c +0 -78
  47. data/src/analyze/action_view/tag.c +0 -87
@@ -0,0 +1,171 @@
1
+ export enum HelperType {
2
+ <%- helpers.each do |helper| -%>
3
+ <%= helper.camel_case_name %> = "<%= helper.name %>",
4
+ <%- end -%>
5
+ }
6
+
7
+ export type HelperDetectStyle = "call_name" | "receiver_call"
8
+ export type HelperOutput = "html" | "text" | "url" | "boolean" | "void" | "object"
9
+
10
+ export interface HelperArgument {
11
+ readonly name: string
12
+ readonly position: number
13
+ readonly type: string
14
+ readonly optional: boolean
15
+ readonly default: string | null
16
+ readonly splat: boolean
17
+ readonly description: string
18
+ }
19
+
20
+ export interface HelperOption {
21
+ readonly name: string
22
+ readonly type: string
23
+ readonly mapsTo: string | null
24
+ readonly description: string
25
+ }
26
+
27
+ export interface HelperImplicitAttribute {
28
+ readonly name: string
29
+ readonly source: string
30
+ readonly sourceWithBlock: string | null
31
+ readonly wrapper: string
32
+ readonly skipWrappingFor: string[]
33
+ }
34
+
35
+ export interface HelperEntry {
36
+ readonly name: string
37
+ readonly type: HelperType
38
+ readonly source: string
39
+ readonly gem: string
40
+ readonly output: HelperOutput
41
+ readonly visibility: "public" | "internal"
42
+ readonly tagName: string | null
43
+ readonly isVoid: boolean
44
+ readonly supportsBlock: boolean
45
+ readonly preferredForTag: boolean
46
+ readonly supported: boolean
47
+ readonly detectStyle: HelperDetectStyle
48
+ readonly description: string
49
+ readonly signature: string
50
+ readonly documentationURL: string
51
+ readonly implicitAttribute: HelperImplicitAttribute | null
52
+ readonly arguments: HelperArgument[]
53
+ readonly options: HelperOption[]
54
+ readonly specialBehaviors: string[]
55
+ readonly aliases: string[]
56
+ }
57
+
58
+ <%- helpers.each do |helper| -%>
59
+ const <%= helper.lower_camel_case_name %>Entry: HelperEntry = {
60
+ name: "<%= helper.name %>",
61
+ type: HelperType.<%= helper.camel_case_name %>,
62
+ source: "<%= helper.source %>",
63
+ gem: "<%= helper.gem %>",
64
+ output: "<%= helper.output %>",
65
+ visibility: "<%= helper.visibility %>",
66
+ tagName: <%= helper.tag_name ? "\"#{helper.tag_name}\"" : "null" %>,
67
+ isVoid: <%= helper.void? %>,
68
+ supportsBlock: <%= helper.supports_block %>,
69
+ preferredForTag: <%= helper.preferred_for_tag %>,
70
+ supported: <%= helper.supported %>,
71
+ detectStyle: "<%= helper.detect_style || "call_name" %>",
72
+ description: "<%= helper.escaped_description %>",
73
+ signature: "<%= helper.escaped_signature %>",
74
+ documentationURL: "<%= helper.documentation_url %>",
75
+ <%- if helper.implicit_attribute? -%>
76
+ implicitAttribute: {
77
+ name: "<%= helper.implicit_attribute.name %>",
78
+ source: "<%= helper.implicit_attribute.source %>",
79
+ sourceWithBlock: <%= helper.implicit_attribute.source_with_block ? "\"#{helper.implicit_attribute.source_with_block}\"" : "null" %>,
80
+ wrapper: "<%= helper.implicit_attribute.wrapper %>",
81
+ skipWrappingFor: [<%= helper.implicit_attribute.skip_wrapping_for.map { |s| "\"#{s}\"" }.join(", ") %>],
82
+ },
83
+ <%- else -%>
84
+ implicitAttribute: null,
85
+ <%- end -%>
86
+ arguments: [
87
+ <%- helper.arguments.each do |arg| -%>
88
+ { name: "<%= arg.name %>", position: <%= arg.position %>, type: "<%= arg.type_display %>", optional: <%= arg.optional %>, default: <%= arg.default ? "\"#{arg.escaped_default}\"" : "null" %>, splat: <%= arg.splat %>, description: "<%= arg.escaped_description %>" },
89
+ <%- end -%>
90
+ ],
91
+ options: [
92
+ <%- helper.options.each do |opt| -%>
93
+ { name: "<%= opt.name %>", type: "<%= opt.type_display %>", mapsTo: <%= opt.maps_to ? "\"#{opt.maps_to}\"" : "null" %>, description: "<%= opt.escaped_description %>" },
94
+ <%- end -%>
95
+ ],
96
+ specialBehaviors: [<%= helper.special_behaviors.map { |b| "\"#{b}\"" }.join(", ") %>],
97
+ aliases: [<%= helper.aliases.map { |a| "\"#{a}\"" }.join(", ") %>],
98
+ }
99
+
100
+ <%- end -%>
101
+ export const HELPER_REGISTRY: Record<string, HelperEntry> = {
102
+ <%- helpers.each do |helper| -%>
103
+ "<%= helper.name %>": <%= helper.lower_camel_case_name %>Entry,
104
+ <%- helper.aliases.each do |alias_name| -%>
105
+ "<%= alias_name %>": <%= helper.lower_camel_case_name %>Entry,
106
+ <%- end -%>
107
+ <%- end -%>
108
+ }
109
+
110
+ export const HELPER_BY_SOURCE: Record<string, HelperEntry> = {
111
+ <%- helpers.each do |helper| -%>
112
+ "<%= helper.source %>": <%= helper.lower_camel_case_name %>Entry,
113
+ <%- end -%>
114
+ }
115
+
116
+ <%- helpers_by_tag = helpers.select(&:static_tag_name?).group_by(&:tag_name) -%>
117
+ export const HELPERS_BY_TAG_NAME: Record<string, HelperEntry[]> = {
118
+ <%- helpers_by_tag.each do |tag_name, helpers| -%>
119
+ "<%= tag_name %>": [<%= helpers.map { |h| "#{h.lower_camel_case_name}Entry" }.join(", ") %>],
120
+ <%- end -%>
121
+ }
122
+
123
+ export function getHelper(name: string): HelperEntry | undefined {
124
+ return HELPER_REGISTRY[name]
125
+ }
126
+
127
+ export function getHelperBySource(source: string): HelperEntry | undefined {
128
+ return HELPER_BY_SOURCE[source]
129
+ }
130
+
131
+ export function getHelperEntries(): HelperEntry[] {
132
+ return Object.values(HELPER_REGISTRY)
133
+ }
134
+
135
+ export function isHelperSupported(name: string): boolean {
136
+ return HELPER_REGISTRY[name]?.supported ?? false
137
+ }
138
+
139
+ export function helperExists(name: string): boolean {
140
+ return name in HELPER_REGISTRY
141
+ }
142
+
143
+ export function getHelpersForTag(tagName: string): HelperEntry[] {
144
+ return HELPERS_BY_TAG_NAME[tagName] ?? []
145
+ }
146
+
147
+ export function findPreferredHelperForTag(tagName: string): HelperEntry | undefined {
148
+ const helpers = HELPERS_BY_TAG_NAME[tagName]
149
+ if (!helpers) return undefined
150
+
151
+ return helpers.find(entry => entry.preferredForTag) ?? helpers[0]
152
+ }
153
+
154
+ export function getSupportedHelpers(): HelperEntry[] {
155
+ return Object.values(HELPER_REGISTRY).filter(entry => entry.supported)
156
+ }
157
+
158
+ export function getHelpersByGem(gem: string): HelperEntry[] {
159
+ return Object.values(HELPER_REGISTRY).filter(entry => entry.gem === gem)
160
+ }
161
+
162
+ export function getHelpersByOutput(output: HelperOutput): HelperEntry[] {
163
+ return Object.values(HELPER_REGISTRY).filter(entry => entry.output === output)
164
+ }
165
+
166
+ export function getHelpersByModule(moduleName: string): HelperEntry[] {
167
+ return Object.values(HELPER_REGISTRY).filter(entry => {
168
+ const parts = entry.source.split("#")[0].split("::")
169
+ return parts[parts.length - 1] === moduleName
170
+ })
171
+ }
@@ -318,7 +318,11 @@ export class <%= node.name %> extends Node {
318
318
  }
319
319
 
320
320
  accept(visitor: Visitor): void {
321
- visitor.visit<%= node.name %>(this)
321
+ const visitMethod = visitor.visit<%= node.name %> as ((node: <%= node.name %>) => void) | undefined
322
+
323
+ if (typeof visitMethod === "function") {
324
+ visitMethod.call(visitor, this)
325
+ }
322
326
  }
323
327
 
324
328
  childNodes(): (Node | null | undefined)[] {
@@ -0,0 +1,288 @@
1
+ module Herb
2
+ module ActionView
3
+ module HelperType
4
+ <%- helpers.each do |helper| -%>
5
+ <%= helper.constant_name %> = :<%= helper.name %>
6
+ <%- end -%>
7
+
8
+ ALL = [
9
+ <%- helpers.each do |helper| -%>
10
+ <%= helper.constant_name %>,
11
+ <%- end -%>
12
+ ].freeze #: Array[Symbol]
13
+ end
14
+
15
+ class HelperArgument
16
+ attr_reader :name #: String
17
+ attr_reader :position #: Integer
18
+ attr_reader :type #: String
19
+ attr_reader :default #: String?
20
+ attr_reader :description #: String
21
+
22
+ #: (String, Integer, String, bool, String?, bool, String) -> void
23
+ def initialize(name, position, type, optional, default, splat, description)
24
+ @name = name
25
+ @position = position
26
+ @type = type
27
+ @optional = optional
28
+ @default = default
29
+ @splat = splat
30
+ @description = description
31
+ end
32
+
33
+ #: () -> bool
34
+ def optional? = @optional
35
+
36
+ #: () -> bool
37
+ def splat? = @splat
38
+ end
39
+
40
+ class HelperOption
41
+ attr_reader :name #: String
42
+ attr_reader :type #: String
43
+ attr_reader :maps_to #: String?
44
+ attr_reader :description #: String
45
+
46
+ #: (String, String, String?, String) -> void
47
+ def initialize(name, type, maps_to, description)
48
+ @name = name
49
+ @type = type
50
+ @maps_to = maps_to
51
+ @description = description
52
+ end
53
+
54
+ #: () -> bool
55
+ def maps_to_data_attribute? = maps_to&.start_with?("data-") || false
56
+
57
+ #: () -> bool
58
+ def maps_to_aria_attribute? = maps_to&.start_with?("aria-") || false
59
+ end
60
+
61
+ class HelperImplicitAttribute
62
+ attr_reader :name #: String
63
+ attr_reader :source #: String
64
+ attr_reader :source_with_block #: String?
65
+ attr_reader :wrapper #: String
66
+ attr_reader :skip_wrapping_for #: Array[String]
67
+
68
+ #: (String, String, String?, String, Array[String]) -> void
69
+ def initialize(name, source, source_with_block, wrapper, skip_wrapping_for)
70
+ @name = name
71
+ @source = source
72
+ @source_with_block = source_with_block
73
+ @wrapper = wrapper
74
+ @skip_wrapping_for = skip_wrapping_for
75
+ end
76
+ end
77
+
78
+ class HelperEntry
79
+ attr_reader :name #: String
80
+ attr_reader :type #: Symbol
81
+ attr_reader :source #: String
82
+ attr_reader :gem #: String
83
+ attr_reader :output #: Symbol
84
+ attr_reader :visibility #: String
85
+ attr_reader :tag_name #: String?
86
+ attr_reader :detect_style #: Symbol
87
+ attr_reader :description #: String
88
+ attr_reader :signature #: String
89
+ attr_reader :documentation_url #: String
90
+ attr_reader :implicit_attribute #: HelperImplicitAttribute?
91
+ attr_reader :arguments #: Array[HelperArgument]
92
+ attr_reader :options #: Array[HelperOption]
93
+ attr_reader :special_behaviors #: Array[Symbol]
94
+ attr_reader :aliases #: Array[String]
95
+
96
+ #: (name: String, type: Symbol, source: String, gem: String, output: Symbol, visibility: String, tag_name: String?, is_void: bool, supports_block: bool, preferred_for_tag: bool, supported: bool, detect_style: Symbol, description: String, signature: String, documentation_url: String, implicit_attribute: HelperImplicitAttribute?, arguments: Array[HelperArgument], options: Array[HelperOption], special_behaviors: Array[Symbol], aliases: Array[String]) -> void
97
+ def initialize( # rubocop:disable Metrics/ParameterLists
98
+ name:, type:, source:, gem:, output:, visibility:, tag_name:, is_void:, supports_block:,
99
+ preferred_for_tag:, supported:, detect_style:, description:, signature:, documentation_url:,
100
+ implicit_attribute:, arguments:, options:, special_behaviors:, aliases:
101
+ )
102
+ @name = name
103
+ @type = type
104
+ @source = source
105
+ @gem = gem
106
+ @output = output
107
+ @visibility = visibility
108
+ @tag_name = tag_name
109
+ @is_void = is_void
110
+ @supports_block = supports_block
111
+ @preferred_for_tag = preferred_for_tag
112
+ @supported = supported
113
+ @detect_style = detect_style
114
+ @description = description
115
+ @signature = signature
116
+ @documentation_url = documentation_url
117
+ @implicit_attribute = implicit_attribute
118
+ @arguments = arguments
119
+ @options = options
120
+ @special_behaviors = special_behaviors
121
+ @aliases = aliases
122
+ end
123
+
124
+ #: () -> bool
125
+ def void? = @is_void
126
+
127
+ #: () -> bool
128
+ def supports_block? = @supports_block
129
+
130
+ #: () -> bool
131
+ def preferred_for_tag? = @preferred_for_tag
132
+
133
+ #: () -> bool
134
+ def supported? = @supported
135
+
136
+ #: () -> bool
137
+ def static_tag_name? = !@tag_name.nil?
138
+
139
+ #: () -> bool
140
+ def implicit_attribute? = !@implicit_attribute.nil?
141
+
142
+ #: () -> bool
143
+ def call_name_detect? = @detect_style == :call_name
144
+
145
+ #: () -> bool
146
+ def receiver_call_detect? = @detect_style == :receiver_call
147
+ end
148
+
149
+ module HelperRegistry
150
+ <%- helpers.each do |helper| -%>
151
+ <%= helper.constant_name %> = HelperEntry.new(
152
+ name: "<%= helper.name %>",
153
+ type: HelperType::<%= helper.constant_name %>,
154
+ source: "<%= helper.source %>",
155
+ gem: "<%= helper.gem %>",
156
+ output: :<%= helper.output %>,
157
+ visibility: "<%= helper.visibility %>",
158
+ tag_name: <%= helper.tag_name ? "\"#{helper.tag_name}\"" : "nil" %>,
159
+ is_void: <%= helper.void? %>,
160
+ supports_block: <%= helper.supports_block %>,
161
+ preferred_for_tag: <%= helper.preferred_for_tag %>,
162
+ supported: <%= helper.supported %>,
163
+ detect_style: :<%= helper.detect_style || "call_name" %>,
164
+ description: "<%= helper.escaped_description %>",
165
+ signature: "<%= helper.escaped_signature %>",
166
+ documentation_url: "<%= helper.documentation_url %>",
167
+ <%- if helper.implicit_attribute? -%>
168
+ implicit_attribute: HelperImplicitAttribute.new(
169
+ "<%= helper.implicit_attribute.name %>",
170
+ "<%= helper.implicit_attribute.source %>",
171
+ <%= helper.implicit_attribute.source_with_block ? "\"#{helper.implicit_attribute.source_with_block}\"" : "nil" %>,
172
+ "<%= helper.implicit_attribute.wrapper %>",
173
+ [<%= helper.implicit_attribute.skip_wrapping_for.map { |s| "\"#{s}\"" }.join(", ") %>]
174
+ ),
175
+ <%- else -%>
176
+ implicit_attribute: nil,
177
+ <%- end -%>
178
+ arguments: [
179
+ <%- helper.arguments.each do |arg| -%>
180
+ HelperArgument.new("<%= arg.name %>", <%= arg.position %>, "<%= arg.type_display %>", <%= arg.optional %>, <%= arg.default ? "\"#{arg.escaped_default}\"" : "nil" %>, <%= arg.splat %>, "<%= arg.escaped_description %>"),
181
+ <%- end -%>
182
+ ],
183
+ options: [
184
+ <%- helper.options.each do |opt| -%>
185
+ HelperOption.new("<%= opt.name %>", "<%= opt.type_display %>", <%= opt.maps_to ? "\"#{opt.maps_to}\"" : "nil" %>, "<%= opt.escaped_description %>"),
186
+ <%- end -%>
187
+ ],
188
+ special_behaviors: [<%= helper.special_behaviors.map { |b| ":#{b}" }.join(", ") %>],
189
+ aliases: [<%= helper.aliases.map { |a| "\"#{a}\"" }.join(", ") %>],
190
+ ).freeze #: HelperEntry
191
+
192
+ <%- end -%>
193
+ ENTRIES = {
194
+ <%- helpers.each do |helper| -%>
195
+ "<%= helper.name %>" => <%= helper.constant_name %>,
196
+ <%- helper.aliases.each do |alias_name| -%>
197
+ "<%= alias_name %>" => <%= helper.constant_name %>,
198
+ <%- end -%>
199
+ <%- end -%>
200
+ }.freeze #: Hash[String, HelperEntry]
201
+
202
+ BY_SOURCE = {
203
+ <%- helpers.each do |helper| -%>
204
+ "<%= helper.source %>" => <%= helper.constant_name %>,
205
+ <%- end -%>
206
+ }.freeze #: Hash[String, HelperEntry]
207
+
208
+ <%- helpers_by_tag = helpers.select(&:static_tag_name?).group_by(&:tag_name) -%>
209
+
210
+ BY_TAG_NAME = {
211
+ <%- helpers_by_tag.each do |tag_name, helpers| -%>
212
+ "<%= tag_name %>" => [<%= helpers.map(&:constant_name).join(", ") %>].freeze,
213
+ <%- end -%>
214
+ }.freeze #: Hash[String, Array[HelperEntry]]
215
+
216
+ class << self
217
+ #: (String) -> HelperEntry?
218
+ def get(name)
219
+ ENTRIES[name.to_s]
220
+ end
221
+
222
+ #: (String) -> HelperEntry?
223
+ def find_by_source(source)
224
+ BY_SOURCE[source]
225
+ end
226
+
227
+ #: () -> Array[HelperEntry]
228
+ def entries
229
+ ENTRIES.values
230
+ end
231
+
232
+ #: () { (HelperEntry) -> void } -> void
233
+ def each(&block)
234
+ entries.each(&block)
235
+ end
236
+
237
+ #: (String) -> Array[HelperEntry]
238
+ def helpers_for_tag(tag_name)
239
+ BY_TAG_NAME[tag_name] || []
240
+ end
241
+
242
+ #: (String) -> HelperEntry?
243
+ def find_preferred_for_tag(tag_name)
244
+ helpers = BY_TAG_NAME[tag_name]
245
+ return nil unless helpers
246
+
247
+ helpers.find(&:preferred_for_tag?) || helpers.first
248
+ end
249
+
250
+ #: () -> Integer
251
+ def count
252
+ ENTRIES.size
253
+ end
254
+
255
+ #: (String) -> bool
256
+ def supported?(name)
257
+ entry = get(name)
258
+ entry&.supported? || false
259
+ end
260
+
261
+ #: (String) -> bool
262
+ def exists?(name)
263
+ ENTRIES.key?(name.to_s)
264
+ end
265
+
266
+ #: () -> Array[HelperEntry]
267
+ def supported
268
+ entries.select(&:supported?)
269
+ end
270
+
271
+ #: (String) -> Array[HelperEntry]
272
+ def by_gem(gem_name)
273
+ entries.select { |entry| entry.gem == gem_name }
274
+ end
275
+
276
+ #: (Symbol) -> Array[HelperEntry]
277
+ def by_output(output)
278
+ entries.select { |entry| entry.output == output }
279
+ end
280
+
281
+ #: (String) -> Array[HelperEntry]
282
+ def by_module(module_name)
283
+ entries.select { |entry| entry.source.split("#").first.split("::").last == module_name }
284
+ end
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,154 @@
1
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2
+ pub enum HelperType {
3
+ <%- helpers.each do |helper| -%>
4
+ /// `<%= helper.name %>` — <%= helper.source %>
5
+ <%= helper.camel_case_name %>,
6
+ <%- end -%>
7
+ }
8
+
9
+ impl HelperType {
10
+ pub fn as_str(&self) -> &'static str {
11
+ match self {
12
+ <%- helpers.each do |helper| -%>
13
+ HelperType::<%= helper.camel_case_name %> => "<%= helper.name %>",
14
+ <%- end -%>
15
+ }
16
+ }
17
+
18
+ pub fn from_name(name: &str) -> Option<HelperType> {
19
+ match name {
20
+ <%- helpers.each do |helper| -%>
21
+ "<%= helper.name %>" => Some(HelperType::<%= helper.camel_case_name %>),
22
+ <%- end -%>
23
+ _ => None,
24
+ }
25
+ }
26
+ }
27
+
28
+ #[derive(Debug, Clone)]
29
+ pub struct HelperArgument {
30
+ pub name: &'static str,
31
+ pub position: usize,
32
+ pub argument_type: &'static str,
33
+ pub optional: bool,
34
+ pub default: Option<&'static str>,
35
+ pub splat: bool,
36
+ pub description: &'static str,
37
+ }
38
+
39
+ #[derive(Debug, Clone)]
40
+ pub struct HelperOption {
41
+ pub name: &'static str,
42
+ pub option_type: &'static str,
43
+ pub maps_to: Option<&'static str>,
44
+ pub description: &'static str,
45
+ }
46
+
47
+ #[derive(Debug, Clone)]
48
+ pub struct HelperImplicitAttribute {
49
+ pub name: &'static str,
50
+ pub source: &'static str,
51
+ pub source_with_block: Option<&'static str>,
52
+ pub wrapper: &'static str,
53
+ pub skip_wrapping_for: &'static [&'static str],
54
+ }
55
+
56
+ #[derive(Debug, Clone)]
57
+ pub struct HelperEntry {
58
+ pub name: &'static str,
59
+ pub helper_type: HelperType,
60
+ pub source: &'static str,
61
+ pub gem: &'static str,
62
+ pub output: &'static str,
63
+ pub visibility: &'static str,
64
+ pub tag_name: Option<&'static str>,
65
+ pub is_void: bool,
66
+ pub supports_block: bool,
67
+ pub preferred_for_tag: bool,
68
+ pub supported: bool,
69
+ pub detect_style: &'static str,
70
+ pub description: &'static str,
71
+ pub signature: &'static str,
72
+ pub documentation_url: &'static str,
73
+ pub implicit_attribute: Option<&'static HelperImplicitAttribute>,
74
+ pub arguments: &'static [HelperArgument],
75
+ pub options: &'static [HelperOption],
76
+ pub special_behaviors: &'static [&'static str],
77
+ pub aliases: &'static [&'static str],
78
+ }
79
+
80
+ <%- helpers.each do |helper| -%>
81
+ <%- if helper.implicit_attribute? -%>
82
+ static <%= helper.constant_name %>_IMPLICIT_ATTR: HelperImplicitAttribute = HelperImplicitAttribute {
83
+ name: "<%= helper.implicit_attribute.name %>",
84
+ source: "<%= helper.implicit_attribute.source %>",
85
+ source_with_block: <%= helper.implicit_attribute.source_with_block ? "Some(\"#{helper.implicit_attribute.source_with_block}\")" : "None" %>,
86
+ wrapper: "<%= helper.implicit_attribute.wrapper %>",
87
+ skip_wrapping_for: &[<%= helper.implicit_attribute.skip_wrapping_for.map { |s| "\"#{s}\"" }.join(", ") %>],
88
+ };
89
+
90
+ <%- end -%>
91
+ <%- end -%>
92
+
93
+ static REGISTRY: [HelperEntry; <%= helpers.size %>] = [
94
+ <%- helpers.each do |helper| -%>
95
+ HelperEntry {
96
+ name: "<%= helper.name %>",
97
+ helper_type: HelperType::<%= helper.camel_case_name %>,
98
+ source: "<%= helper.source %>",
99
+ gem: "<%= helper.gem %>",
100
+ output: "<%= helper.output %>",
101
+ visibility: "<%= helper.visibility %>",
102
+ tag_name: <%= helper.tag_name ? "Some(\"#{helper.tag_name}\")" : "None" %>,
103
+ is_void: <%= helper.void? %>,
104
+ supports_block: <%= helper.supports_block %>,
105
+ preferred_for_tag: <%= helper.preferred_for_tag %>,
106
+ supported: <%= helper.supported %>,
107
+ detect_style: "<%= helper.detect_style || "call_name" %>",
108
+ description: "<%= helper.escaped_description %>",
109
+ signature: "<%= helper.escaped_signature %>",
110
+ documentation_url: "<%= helper.documentation_url %>",
111
+ implicit_attribute: <%= helper.implicit_attribute? ? "Some(&#{helper.constant_name}_IMPLICIT_ATTR)" : "None" %>,
112
+ arguments: &[
113
+ <%- helper.arguments.each do |arg| -%>
114
+ HelperArgument { name: "<%= arg.name %>", position: <%= arg.position %>, argument_type: "<%= arg.type_display %>", optional: <%= arg.optional %>, default: <%= arg.default ? "Some(\"#{arg.escaped_default}\")" : "None" %>, splat: <%= arg.splat %>, description: "<%= arg.escaped_description %>" },
115
+ <%- end -%>
116
+ ],
117
+ options: &[
118
+ <%- helper.options.each do |opt| -%>
119
+ HelperOption { name: "<%= opt.name %>", option_type: "<%= opt.type_display %>", maps_to: <%= opt.maps_to ? "Some(\"#{opt.maps_to}\")" : "None" %>, description: "<%= opt.escaped_description %>" },
120
+ <%- end -%>
121
+ ],
122
+ special_behaviors: &[<%= helper.special_behaviors.map { |b| "\"#{b}\"" }.join(", ") %>],
123
+ aliases: &[<%= helper.aliases.map { |a| "\"#{a}\"" }.join(", ") %>],
124
+ },
125
+ <%- end -%>
126
+ ];
127
+
128
+ pub fn get(helper_type: HelperType) -> &'static HelperEntry {
129
+ &REGISTRY[helper_type as usize]
130
+ }
131
+
132
+ pub fn find_by_name(name: &str) -> Option<&'static HelperEntry> {
133
+ REGISTRY.iter().find(|entry| entry.name == name)
134
+ }
135
+
136
+ pub fn find_by_source(source: &str) -> Option<&'static HelperEntry> {
137
+ REGISTRY.iter().find(|entry| entry.source == source)
138
+ }
139
+
140
+ pub fn helpers_for_tag(tag_name: &str) -> Vec<&'static HelperEntry> {
141
+ REGISTRY.iter().filter(|entry| entry.tag_name == Some(tag_name)).collect()
142
+ }
143
+
144
+ pub fn find_preferred_for_tag(tag_name: &str) -> Option<&'static HelperEntry> {
145
+ REGISTRY.iter().find(|entry| entry.tag_name == Some(tag_name) && entry.preferred_for_tag)
146
+ }
147
+
148
+ pub fn entries() -> &'static [HelperEntry] {
149
+ &REGISTRY
150
+ }
151
+
152
+ pub fn count() -> usize {
153
+ REGISTRY.len()
154
+ }