herb 0.8.10-arm-linux-gnu → 0.9.1-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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +11 -3
  3. data/README.md +64 -34
  4. data/Rakefile +48 -40
  5. data/config.yml +473 -34
  6. data/ext/herb/error_helpers.c +535 -140
  7. data/ext/herb/error_helpers.h +1 -0
  8. data/ext/herb/extconf.rb +67 -28
  9. data/ext/herb/extension.c +321 -51
  10. data/ext/herb/extension.h +1 -0
  11. data/ext/herb/extension_helpers.c +24 -14
  12. data/ext/herb/extension_helpers.h +2 -2
  13. data/ext/herb/nodes.c +647 -270
  14. data/ext/herb/nodes.h +1 -0
  15. data/herb.gemspec +3 -2
  16. data/lib/herb/3.0/herb.so +0 -0
  17. data/lib/herb/3.1/herb.so +0 -0
  18. data/lib/herb/3.2/herb.so +0 -0
  19. data/lib/herb/3.3/herb.so +0 -0
  20. data/lib/herb/3.4/herb.so +0 -0
  21. data/lib/herb/4.0/herb.so +0 -0
  22. data/lib/herb/ast/helpers.rb +3 -3
  23. data/lib/herb/ast/node.rb +15 -2
  24. data/lib/herb/ast/nodes.rb +1530 -179
  25. data/lib/herb/bootstrap.rb +87 -0
  26. data/lib/herb/cli.rb +341 -31
  27. data/lib/herb/configuration.rb +248 -0
  28. data/lib/herb/defaults.yml +32 -0
  29. data/lib/herb/engine/compiler.rb +78 -11
  30. data/lib/herb/engine/debug_visitor.rb +13 -3
  31. data/lib/herb/engine/error_formatter.rb +13 -9
  32. data/lib/herb/engine/parser_error_overlay.rb +10 -6
  33. data/lib/herb/engine/validator.rb +8 -3
  34. data/lib/herb/engine/validators/nesting_validator.rb +2 -2
  35. data/lib/herb/engine.rb +119 -43
  36. data/lib/herb/errors.rb +808 -88
  37. data/lib/herb/lex_result.rb +1 -0
  38. data/lib/herb/location.rb +7 -3
  39. data/lib/herb/parse_result.rb +12 -2
  40. data/lib/herb/parser_options.rb +62 -0
  41. data/lib/herb/position.rb +1 -0
  42. data/lib/herb/prism_inspect.rb +120 -0
  43. data/lib/herb/project.rb +923 -331
  44. data/lib/herb/range.rb +1 -0
  45. data/lib/herb/token.rb +7 -1
  46. data/lib/herb/version.rb +1 -1
  47. data/lib/herb/visitor.rb +47 -2
  48. data/lib/herb/warnings.rb +6 -1
  49. data/lib/herb.rb +35 -3
  50. data/sig/herb/ast/helpers.rbs +2 -2
  51. data/sig/herb/ast/node.rbs +12 -2
  52. data/sig/herb/ast/nodes.rbs +773 -128
  53. data/sig/herb/bootstrap.rbs +31 -0
  54. data/sig/herb/configuration.rbs +89 -0
  55. data/sig/herb/engine/compiler.rbs +9 -1
  56. data/sig/herb/engine/debug_visitor.rbs +2 -0
  57. data/sig/herb/engine/validator.rbs +5 -1
  58. data/sig/herb/engine.rbs +21 -3
  59. data/sig/herb/errors.rbs +372 -63
  60. data/sig/herb/location.rbs +4 -0
  61. data/sig/herb/parse_result.rbs +4 -2
  62. data/sig/herb/parser_options.rbs +46 -0
  63. data/sig/herb/position.rbs +1 -0
  64. data/sig/herb/prism_inspect.rbs +28 -0
  65. data/sig/herb/range.rbs +1 -0
  66. data/sig/herb/token.rbs +6 -0
  67. data/sig/herb/visitor.rbs +31 -4
  68. data/sig/herb/warnings.rbs +6 -1
  69. data/sig/herb.rbs +14 -0
  70. data/sig/herb_c_extension.rbs +5 -2
  71. data/sig/rubyvm.rbs +5 -0
  72. data/sig/serialized_ast_errors.rbs +82 -6
  73. data/sig/serialized_ast_nodes.rbs +91 -6
  74. data/src/analyze/action_view/attribute_extraction_helpers.c +303 -0
  75. data/src/analyze/action_view/content_tag.c +78 -0
  76. data/src/analyze/action_view/link_to.c +167 -0
  77. data/src/analyze/action_view/registry.c +83 -0
  78. data/src/analyze/action_view/tag.c +70 -0
  79. data/src/analyze/action_view/tag_helper_node_builders.c +305 -0
  80. data/src/analyze/action_view/tag_helpers.c +815 -0
  81. data/src/analyze/action_view/turbo_frame_tag.c +88 -0
  82. data/src/analyze/analyze.c +885 -0
  83. data/src/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
  84. data/src/analyze/builders.c +343 -0
  85. data/src/analyze/conditional_elements.c +594 -0
  86. data/src/analyze/conditional_open_tags.c +640 -0
  87. data/src/analyze/control_type.c +250 -0
  88. data/src/{analyze_helpers.c → analyze/helpers.c} +48 -23
  89. data/src/analyze/invalid_structures.c +193 -0
  90. data/src/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
  91. data/src/analyze/parse_errors.c +84 -0
  92. data/src/analyze/prism_annotate.c +399 -0
  93. data/src/analyze/render_nodes.c +761 -0
  94. data/src/{analyze_transform.c → analyze/transform.c} +24 -3
  95. data/src/ast_node.c +17 -7
  96. data/src/ast_nodes.c +759 -387
  97. data/src/ast_pretty_print.c +264 -6
  98. data/src/errors.c +1454 -519
  99. data/src/extract.c +145 -49
  100. data/src/herb.c +52 -34
  101. data/src/html_util.c +241 -12
  102. data/src/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
  103. data/src/include/analyze/action_view/tag_helper_handler.h +43 -0
  104. data/src/include/analyze/action_view/tag_helper_node_builders.h +70 -0
  105. data/src/include/analyze/action_view/tag_helpers.h +38 -0
  106. data/src/include/{analyze.h → analyze/analyze.h} +14 -4
  107. data/src/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  108. data/src/include/analyze/builders.h +27 -0
  109. data/src/include/analyze/conditional_elements.h +9 -0
  110. data/src/include/analyze/conditional_open_tags.h +9 -0
  111. data/src/include/analyze/control_type.h +14 -0
  112. data/src/include/{analyze_helpers.h → analyze/helpers.h} +4 -2
  113. data/src/include/analyze/invalid_structures.h +11 -0
  114. data/src/include/analyze/prism_annotate.h +16 -0
  115. data/src/include/analyze/render_nodes.h +11 -0
  116. data/src/include/ast_node.h +11 -5
  117. data/src/include/ast_nodes.h +154 -38
  118. data/src/include/ast_pretty_print.h +5 -0
  119. data/src/include/element_source.h +3 -8
  120. data/src/include/errors.h +206 -55
  121. data/src/include/extract.h +21 -5
  122. data/src/include/herb.h +18 -6
  123. data/src/include/herb_prism_node.h +13 -0
  124. data/src/include/html_util.h +7 -2
  125. data/src/include/io.h +3 -1
  126. data/src/include/lex_helpers.h +29 -0
  127. data/src/include/lexer.h +1 -1
  128. data/src/include/lexer_peek_helpers.h +87 -13
  129. data/src/include/lexer_struct.h +2 -0
  130. data/src/include/location.h +2 -1
  131. data/src/include/parser.h +28 -2
  132. data/src/include/parser_helpers.h +19 -3
  133. data/src/include/pretty_print.h +10 -5
  134. data/src/include/prism_context.h +45 -0
  135. data/src/include/prism_helpers.h +10 -7
  136. data/src/include/prism_serialized.h +12 -0
  137. data/src/include/token.h +16 -4
  138. data/src/include/token_struct.h +10 -3
  139. data/src/include/utf8.h +2 -1
  140. data/src/include/util/hb_allocator.h +78 -0
  141. data/src/include/util/hb_arena.h +6 -1
  142. data/src/include/util/hb_arena_debug.h +12 -1
  143. data/src/include/util/hb_array.h +7 -3
  144. data/src/include/util/hb_buffer.h +6 -4
  145. data/src/include/util/hb_foreach.h +79 -0
  146. data/src/include/util/hb_narray.h +8 -4
  147. data/src/include/util/hb_string.h +56 -9
  148. data/src/include/util.h +6 -3
  149. data/src/include/version.h +1 -1
  150. data/src/io.c +3 -2
  151. data/src/lexer.c +42 -30
  152. data/src/lexer_peek_helpers.c +12 -74
  153. data/src/location.c +2 -2
  154. data/src/main.c +53 -28
  155. data/src/parser.c +784 -247
  156. data/src/parser_helpers.c +110 -23
  157. data/src/parser_match_tags.c +129 -48
  158. data/src/pretty_print.c +29 -24
  159. data/src/prism_helpers.c +30 -27
  160. data/src/ruby_parser.c +2 -0
  161. data/src/token.c +151 -66
  162. data/src/token_matchers.c +0 -1
  163. data/src/utf8.c +7 -6
  164. data/src/util/hb_allocator.c +341 -0
  165. data/src/util/hb_arena.c +81 -56
  166. data/src/util/hb_arena_debug.c +32 -17
  167. data/src/util/hb_array.c +30 -15
  168. data/src/util/hb_buffer.c +17 -21
  169. data/src/util/hb_narray.c +22 -7
  170. data/src/util/hb_string.c +49 -35
  171. data/src/util.c +21 -11
  172. data/src/visitor.c +67 -0
  173. data/templates/ext/herb/error_helpers.c.erb +24 -11
  174. data/templates/ext/herb/error_helpers.h.erb +1 -0
  175. data/templates/ext/herb/nodes.c.erb +50 -16
  176. data/templates/ext/herb/nodes.h.erb +1 -0
  177. data/templates/java/error_helpers.c.erb +1 -1
  178. data/templates/java/nodes.c.erb +30 -8
  179. data/templates/java/org/herb/ast/Errors.java.erb +24 -1
  180. data/templates/java/org/herb/ast/Nodes.java.erb +80 -21
  181. data/templates/javascript/packages/core/src/errors.ts.erb +16 -3
  182. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +3 -1
  183. data/templates/javascript/packages/core/src/nodes.ts.erb +109 -32
  184. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +13 -4
  185. data/templates/javascript/packages/node/extension/nodes.cpp.erb +43 -4
  186. data/templates/lib/herb/ast/nodes.rb.erb +95 -32
  187. data/templates/lib/herb/errors.rb.erb +15 -3
  188. data/templates/lib/herb/visitor.rb.erb +2 -2
  189. data/templates/rust/src/ast/nodes.rs.erb +97 -44
  190. data/templates/rust/src/errors.rs.erb +2 -1
  191. data/templates/rust/src/nodes.rs.erb +168 -16
  192. data/templates/rust/src/union_types.rs.erb +60 -0
  193. data/templates/rust/src/visitor.rs.erb +81 -0
  194. data/templates/src/{analyze_missing_end.c.erb → analyze/missing_end.c.erb} +9 -6
  195. data/templates/src/{analyze_transform.c.erb → analyze/transform.c.erb} +2 -2
  196. data/templates/src/ast_nodes.c.erb +34 -26
  197. data/templates/src/ast_pretty_print.c.erb +24 -5
  198. data/templates/src/errors.c.erb +60 -54
  199. data/templates/src/include/ast_nodes.h.erb +6 -2
  200. data/templates/src/include/ast_pretty_print.h.erb +5 -0
  201. data/templates/src/include/errors.h.erb +15 -11
  202. data/templates/src/include/util/hb_foreach.h.erb +20 -0
  203. data/templates/src/parser_match_tags.c.erb +10 -4
  204. data/templates/src/visitor.c.erb +2 -2
  205. data/templates/template.rb +204 -29
  206. data/templates/wasm/error_helpers.cpp.erb +9 -5
  207. data/templates/wasm/nodes.cpp.erb +41 -4
  208. metadata +60 -16
  209. data/src/analyze.c +0 -1608
  210. data/src/element_source.c +0 -12
  211. data/src/include/util/hb_system.h +0 -9
  212. data/src/util/hb_system.c +0 -30
@@ -1,7 +1,8 @@
1
1
  import { Location } from "./location.js"
2
2
  import { Token, SerializedToken } from "./token.js"
3
3
  import { HerbError } from "./errors.js"
4
- import { convertToUTF8 } from "./util.js"
4
+ import { deserializePrismNode, inspectPrismSerialized } from "./prism/index.js"
5
+ import type { PrismNode } from "./prism/index.js"
5
6
 
6
7
  import type { SerializedLocation } from "./location.js"
7
8
  import type { SerializedHerbError } from "./errors.js"
@@ -25,6 +26,7 @@ export abstract class Node implements BaseNodeProps {
25
26
  readonly type: NodeType
26
27
  readonly location: Location
27
28
  readonly errors: HerbError[]
29
+ source: string | null = null
28
30
 
29
31
  static from(node: SerializedNode): Node {
30
32
  return fromSerializedNode(node)
@@ -40,6 +42,11 @@ export abstract class Node implements BaseNodeProps {
40
42
  this.errors = errors
41
43
  }
42
44
 
45
+ setSource(source: string): void {
46
+ this.source = source
47
+ this.compactChildNodes().forEach(child => child.setSource(source))
48
+ }
49
+
43
50
  toJSON(): SerializedNode {
44
51
  return {
45
52
  type: this.type,
@@ -145,15 +152,19 @@ export interface Serialized<%= node.name %> extends SerializedNode {
145
152
  <%= field.name %>: string;
146
153
  <%- when Herb::Template::LocationField -%>
147
154
  <%= field.name %>: SerializedLocation | null;
148
- <%- when Herb::Template::NodeField -%>
155
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
149
156
  <%- if field.specific_kind -%>
150
157
  <%= field.name %>: Serialized<%= field.specific_kind %> | null;
158
+ <%- elsif field.union_kind -%>
159
+ <%= field.name %>: <%= field.union_kind.map { |k| "Serialized#{k}" }.join(" | ") %> | null;
151
160
  <%- else -%>
152
161
  <%= field.name %>: SerializedNode | null;
153
162
  <%- end -%>
154
163
  <%- when Herb::Template::ArrayField -%>
155
164
  <%= field.name %>: SerializedNode[];
156
- <%- when Herb::Template::PrismNodeField, Herb::Template::AnalyzedRubyField -%>
165
+ <%- when Herb::Template::PrismSerializedField, Herb::Template::PrismNodeField -%>
166
+ <%= field.name %>: number[] | null;
167
+ <%- when Herb::Template::AnalyzedRubyField, Herb::Template::PrismContextField -%>
157
168
  // no-op for <%= field.name %>
158
169
  <%- else -%>
159
170
  <% raise "Unhandled class #{field.class}" %>
@@ -161,7 +172,8 @@ export interface Serialized<%= node.name %> extends SerializedNode {
161
172
  <%- end -%>
162
173
  }
163
174
 
164
- export interface <%= node.name %>Props extends BaseNodeProps {
175
+ export interface <%= node.name %>Props extends Omit<BaseNodeProps, 'type'> {
176
+ type: "<%= node.type %>";
165
177
  <%- node.fields.each do |field| -%>
166
178
  <%- case field -%>
167
179
  <%- when Herb::Template::StringField -%>
@@ -174,9 +186,11 @@ export interface <%= node.name %>Props extends BaseNodeProps {
174
186
  <%= field.name %>: string;
175
187
  <%- when Herb::Template::LocationField -%>
176
188
  <%= field.name %>: Location | null;
177
- <%- when Herb::Template::NodeField -%>
189
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
178
190
  <%- if field.specific_kind -%>
179
191
  <%= field.name %>: <%= field.specific_kind %> | null;
192
+ <%- elsif field.union_kind -%>
193
+ <%= field.name %>: <%= field.union_kind.join(" | ") %> | null;
180
194
  <%- else -%>
181
195
  <%= field.name %>: Node | null;
182
196
  <%- end -%>
@@ -186,7 +200,9 @@ export interface <%= node.name %>Props extends BaseNodeProps {
186
200
  <%- else -%>
187
201
  <%= field.name %>: any[];
188
202
  <%- end -%>
189
- <%- when Herb::Template::PrismNodeField, Herb::Template::AnalyzedRubyField -%>
203
+ <%- when Herb::Template::PrismSerializedField, Herb::Template::PrismNodeField -%>
204
+ <%= field.name %>: Uint8Array | null;
205
+ <%- when Herb::Template::AnalyzedRubyField, Herb::Template::PrismContextField -%>
190
206
  // no-op for <%= field.name %>
191
207
  <%- else -%>
192
208
  <% raise "Unhandled class #{field.class}" %>
@@ -195,6 +211,7 @@ export interface <%= node.name %>Props extends BaseNodeProps {
195
211
  }
196
212
 
197
213
  export class <%= node.name %> extends Node {
214
+ declare readonly type: "<%= node.type %>";
198
215
  <%- node.fields.each do |field| -%>
199
216
  <%- case field -%>
200
217
  <%- when Herb::Template::StringField -%>
@@ -207,9 +224,11 @@ export class <%= node.name %> extends Node {
207
224
  readonly <%= field.name %>: string;
208
225
  <%- when Herb::Template::LocationField -%>
209
226
  readonly <%= field.name %>: Location | null;
210
- <%- when Herb::Template::NodeField -%>
227
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
211
228
  <%- if field.specific_kind -%>
212
229
  readonly <%= field.name %>: <%= field.specific_kind %> | null;
230
+ <%- elsif field.union_kind -%>
231
+ readonly <%= field.name %>: <%= field.union_kind.join(" | ") %> | null;
213
232
  <%- else -%>
214
233
  readonly <%= field.name %>: Node | null;
215
234
  <%- end -%>
@@ -219,7 +238,9 @@ export class <%= node.name %> extends Node {
219
238
  <%- else -%>
220
239
  readonly <%= field.name %>: Node[];
221
240
  <%- end -%>
222
- <%- when Herb::Template::PrismNodeField, Herb::Template::AnalyzedRubyField -%>
241
+ <%- when Herb::Template::PrismSerializedField, Herb::Template::PrismNodeField -%>
242
+ readonly <%= field.name %>: Uint8Array | null;
243
+ <%- when Herb::Template::AnalyzedRubyField, Herb::Template::PrismContextField -%>
223
244
  // no-op for <%= field.name %>
224
245
  <%- else -%>
225
246
  <% raise "Unhandled class #{field.class}" %>
@@ -247,11 +268,19 @@ export class <%= node.name %> extends Node {
247
268
  <%= field.name %>: data.<%= field.name %>,
248
269
  <%- when Herb::Template::LocationField -%>
249
270
  <%= field.name %>: data.<%= field.name %> ? Location.from(data.<%= field.name %>) : null,
250
- <%- when Herb::Template::NodeField -%>
271
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
272
+ <%- if field.union_kind -%>
273
+ <%= field.name %>: data.<%= field.name %> ? fromSerializedNode((data.<%= field.name %>)) as <%= field.union_kind.join(" | ") %> : null,
274
+ <%- elsif field.specific_kind -%>
275
+ <%= field.name %>: data.<%= field.name %> ? fromSerializedNode((data.<%= field.name %>)) as <%= field.specific_kind %> : null,
276
+ <%- else -%>
251
277
  <%= field.name %>: data.<%= field.name %> ? fromSerializedNode((data.<%= field.name %>)) : null,
278
+ <%- end -%>
252
279
  <%- when Herb::Template::ArrayField -%>
253
280
  <%= field.name %>: (data.<%= field.name %> || []).map(node => fromSerializedNode(node)),
254
- <%- when Herb::Template::PrismNodeField, Herb::Template::AnalyzedRubyField -%>
281
+ <%- when Herb::Template::PrismSerializedField, Herb::Template::PrismNodeField -%>
282
+ <%= field.name %>: data.<%= field.name %> ? new Uint8Array(data.<%= field.name %>) : null,
283
+ <%- when Herb::Template::AnalyzedRubyField, Herb::Template::PrismContextField -%>
255
284
  // no-op for <%= field.name %>
256
285
  <%- else -%>
257
286
  <% raise "Unhandled class #{field.class}" %>
@@ -268,17 +297,19 @@ export class <%= node.name %> extends Node {
268
297
  this.<%= field.name %> = props.<%= field.name %>;
269
298
  <%- when Herb::Template::TokenField -%>
270
299
  this.<%= field.name %> = props.<%= field.name %>;
271
- <%- when Herb::Template::NodeField -%>
300
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
272
301
  this.<%= field.name %> = props.<%= field.name %>;
273
302
  <%- when Herb::Template::StringField -%>
274
- this.<%= field.name %> = convertToUTF8(props.<%= field.name %>);
303
+ this.<%= field.name %> = props.<%= field.name %>;
275
304
  <%- when Herb::Template::BooleanField -%>
276
305
  this.<%= field.name %> = props.<%= field.name %>;
277
306
  <%- when Herb::Template::ElementSourceField -%>
278
307
  this.<%= field.name %> = props.<%= field.name %>;
279
308
  <%- when Herb::Template::LocationField -%>
280
309
  this.<%= field.name %> = props.<%= field.name %>;
281
- <%- when Herb::Template::PrismNodeField, Herb::Template::AnalyzedRubyField -%>
310
+ <%- when Herb::Template::PrismSerializedField, Herb::Template::PrismNodeField -%>
311
+ this.<%= field.name %> = props.<%= field.name %>;
312
+ <%- when Herb::Template::AnalyzedRubyField, Herb::Template::PrismContextField -%>
282
313
  // no-op for <%= field.name %>
283
314
  <%- else -%>
284
315
  <% raise "Unhandled class #{field.class}" %>
@@ -294,7 +325,7 @@ export class <%= node.name %> extends Node {
294
325
  return [
295
326
  <%- node.fields.each do |field| -%>
296
327
  <%- case field -%>
297
- <%- when Herb::Template::NodeField -%>
328
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
298
329
  this.<%= field.name %>,
299
330
  <%- when Herb::Template::ArrayField -%>
300
331
  ...this.<%= field.name %>,
@@ -307,12 +338,20 @@ export class <%= node.name %> extends Node {
307
338
  return this.childNodes().filter(node => node !== null && node !== undefined)
308
339
  }
309
340
 
341
+ <%- if node.fields.any? { |f| f.is_a?(Herb::Template::PrismSerializedField) || f.is_a?(Herb::Template::PrismNodeField) } -%>
342
+ <%- prism_field = node.fields.find { |f| f.is_a?(Herb::Template::PrismSerializedField) || f.is_a?(Herb::Template::PrismNodeField) } -%>
343
+ get prismNode(): PrismNode | null {
344
+ if (!this.<%= prism_field.name %> || !this.source) return null;
345
+ return deserializePrismNode(this.<%= prism_field.name %>, this.source);
346
+ }
347
+ <%- end -%>
348
+
310
349
  recursiveErrors(): HerbError[] {
311
350
  return [
312
351
  ...this.errors,
313
352
  <%- node.fields.each do |field| -%>
314
353
  <%- case field -%>
315
- <%- when Herb::Template::NodeField -%>
354
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
316
355
  this.<%= field.name %> ? this.<%= field.name %>.recursiveErrors() : [],
317
356
  <%- when Herb::Template::ArrayField -%>
318
357
  ...this.<%= field.name %>.map(node => node.recursiveErrors()),
@@ -337,11 +376,13 @@ export class <%= node.name %> extends Node {
337
376
  <%= field.name %>: this.<%= field.name %>,
338
377
  <%- when Herb::Template::LocationField -%>
339
378
  <%= field.name %>: this.<%= field.name %> ? this.<%= field.name %>.toJSON() : null,
340
- <%- when Herb::Template::NodeField -%>
379
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
341
380
  <%= field.name %>: this.<%= field.name %> ? this.<%= field.name %>.toJSON() : null,
342
381
  <%- when Herb::Template::ArrayField -%>
343
382
  <%= field.name %>: this.<%= field.name %>.map(node => node.toJSON()),
344
- <%- when Herb::Template::PrismNodeField, Herb::Template::AnalyzedRubyField -%>
383
+ <%- when Herb::Template::PrismSerializedField, Herb::Template::PrismNodeField -%>
384
+ <%= field.name %>: this.<%= field.name %> ? Array.from(this.<%= field.name %>) : null,
385
+ <%- when Herb::Template::AnalyzedRubyField, Herb::Template::PrismContextField -%>
345
386
  // no-op for <%= field.name %>
346
387
  <%- else -%>
347
388
  <% raise "Unhandled class #{field.class}" %>
@@ -355,29 +396,65 @@ export class <%= node.name %> extends Node {
355
396
 
356
397
  output += `@ <%= node.name %> ${this.location.treeInspectWithLabel()}\n`;
357
398
  output += `├── errors: ${this.inspectArray(this.errors, "<%= node.fields.any? ? "│ " : " " %>")}`;
358
- <%- node.fields.each do |field| -%>
359
- <%- symbol = node.fields.last == field ? "└──" : "├──" -%>
360
- <%- name = "#{symbol} #{field.name}: " -%>
399
+ <%- node.field_visibilities.each do |visibility| -%>
400
+ <%- field = visibility.field -%>
401
+ <%- next if field.always_invisible? -%>
402
+ <%- if field.conditionally_invisible? -%>
403
+ if (this.<%= field.name %>) {
404
+ output += `<%= visibility.symbol.strip %> <%= field.name %>: ${this.source ? inspectPrismSerialized(this.<%= field.name %>, this.source, "<%= visibility.prefix %>") : `(${this.<%= field.name %>.length} bytes)`}\n`;
405
+ }
406
+ <%- else -%>
407
+ <%- if visibility.dynamic_last? -%>
408
+ {
409
+ const isLast = !this.<%= visibility.prism_field_name %>;
410
+ const symbol = isLast ? "└──" : "├──";
411
+ <%- end -%>
361
412
  <%- case field -%>
362
- <%- when Herb::Template::StringField -%>
363
- output += `<%= name %>${this.<%= field.name %> ? JSON.stringify(this.<%= field.name %>) : "∅"}\n`;
413
+ <%- when Herb::Template::StringField, Herb::Template::ElementSourceField -%>
414
+ <%- if visibility.dynamic_last? -%>
415
+ output += `${symbol} <%= field.name %>: ${this.<%= field.name %> ? JSON.stringify(this.<%= field.name %>) : "∅"}\n`;
416
+ <%- else -%>
417
+ output += `<%= visibility.symbol.strip %> <%= field.name %>: ${this.<%= field.name %> ? JSON.stringify(this.<%= field.name %>) : "∅"}\n`;
418
+ <%- end -%>
364
419
  <%- when Herb::Template::TokenField -%>
365
- output += `<%= name %>${this.<%= field.name %> ? this.<%= field.name %>.treeInspect() : "∅"}\n`;
420
+ <%- if visibility.dynamic_last? -%>
421
+ output += `${symbol} <%= field.name %>: ${this.<%= field.name %> ? this.<%= field.name %>.treeInspect() : "∅"}\n`;
422
+ <%- else -%>
423
+ output += `<%= visibility.symbol.strip %> <%= field.name %>: ${this.<%= field.name %> ? this.<%= field.name %>.treeInspect() : "∅"}\n`;
424
+ <%- end -%>
366
425
  <%- when Herb::Template::BooleanField -%>
367
- output += `<%= name %>${typeof this.<%= field.name %> === 'boolean' ? String(this.<%= field.name %>) : "∅"}\n`;
368
- <%- when Herb::Template::ElementSourceField -%>
369
- output += `<%= name %>${this.<%= field.name %> ? JSON.stringify(this.<%= field.name %>) : "∅"}\n`;
426
+ <%- if visibility.dynamic_last? -%>
427
+ output += `${symbol} <%= field.name %>: ${typeof this.<%= field.name %> === 'boolean' ? String(this.<%= field.name %>) : "∅"}\n`;
428
+ <%- else -%>
429
+ output += `<%= visibility.symbol.strip %> <%= field.name %>: ${typeof this.<%= field.name %> === 'boolean' ? String(this.<%= field.name %>) : "∅"}\n`;
430
+ <%- end -%>
370
431
  <%- when Herb::Template::LocationField -%>
371
- output += `<%= name %>${this.<%= field.name %> ? "(location: " + this.<%= field.name %>.treeInspect() + ")" : "∅"}\n`;
372
- <%- when Herb::Template::NodeField -%>
373
- output += `<%= name %>${this.inspectNode(this.<%= field.name %>, "<%= (node.fields.last == field) ? " " : "│ " %>")}`;
432
+ <%- if visibility.dynamic_last? -%>
433
+ output += `${symbol} <%= field.name %>: ${this.<%= field.name %> ? "(location: " + this.<%= field.name %>.treeInspect() + ")" : "∅"}\n`;
434
+ <%- else -%>
435
+ output += `<%= visibility.symbol.strip %> <%= field.name %>: ${this.<%= field.name %> ? "(location: " + this.<%= field.name %>.treeInspect() + ")" : "∅"}\n`;
436
+ <%- end -%>
437
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
438
+ <%- if visibility.dynamic_last? -%>
439
+ const childPrefix = isLast ? " " : "│ ";
440
+ output += `${symbol} <%= field.name %>: ${this.inspectNode(this.<%= field.name %>, childPrefix)}`;
441
+ <%- else -%>
442
+ output += `<%= visibility.symbol.strip %> <%= field.name %>: ${this.inspectNode(this.<%= field.name %>, "<%= visibility.prefix %>")}`;
443
+ <%- end -%>
374
444
  <%- when Herb::Template::ArrayField -%>
375
- output += `<%= name %>${this.inspectArray(this.<%= field.name %>, "<%= (node.fields.last == field) ? " " : "│ " %>")}`;
376
- <%- when Herb::Template::PrismNodeField, Herb::Template::AnalyzedRubyField -%>
377
- // no-op for <%= field.name %>
445
+ <%- if visibility.dynamic_last? -%>
446
+ const childPrefix = isLast ? " " : "│ ";
447
+ output += `${symbol} <%= field.name %>: ${this.inspectArray(this.<%= field.name %>, childPrefix)}`;
448
+ <%- else -%>
449
+ output += `<%= visibility.symbol.strip %> <%= field.name %>: ${this.inspectArray(this.<%= field.name %>, "<%= visibility.prefix %>")}`;
450
+ <%- end -%>
378
451
  <%- else -%>
379
452
  <% raise "Unhandled class #{field.class}" %>
380
453
  <%- end -%>
454
+ <%- if visibility.dynamic_last? -%>
455
+ }
456
+ <%- end -%>
457
+ <%- end -%>
381
458
  <%- end -%>
382
459
 
383
460
  return output
@@ -26,10 +26,10 @@ napi_value <%= error.name %>FromCStruct(napi_env env, <%= error.struct_type %>*
26
26
  napi_value result;
27
27
  napi_create_object(env, &result);
28
28
 
29
- napi_value type = CreateString(env, error_type_to_string(&<%= error.human %>->base));
29
+ napi_value type = CreateStringFromHbString(env, error_type_to_string(&<%= error.human %>->base));
30
30
  napi_set_named_property(env, result, "type", type);
31
31
 
32
- napi_value message = CreateString(env, <%= error.human %>->base.message);
32
+ napi_value message = CreateStringFromHbString(env, <%= error.human %>->base.message);
33
33
  napi_set_named_property(env, result, "message", message);
34
34
 
35
35
  napi_value location = CreateLocation(env, <%= error.human %>->base.location);
@@ -38,7 +38,7 @@ napi_value <%= error.name %>FromCStruct(napi_env env, <%= error.struct_type %>*
38
38
  <%- error.fields.each do |field| -%>
39
39
  <%- case field -%>
40
40
  <%- when Herb::Template::StringField -%>
41
- napi_value <%= field.name %> = CreateString(env, <%= error.human %>-><%= field.name %>);
41
+ napi_value <%= field.name %> = CreateStringFromHbString(env, <%= error.human %>-><%= field.name %>);
42
42
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
43
43
 
44
44
  <%- when Herb::Template::NodeField -%>
@@ -50,7 +50,7 @@ napi_value <%= error.name %>FromCStruct(napi_env env, <%= error.struct_type %>*
50
50
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
51
51
 
52
52
  <%- when Herb::Template::TokenTypeField -%>
53
- napi_value <%= field.name %> = CreateString(env, token_type_to_string(<%= error.human %>-><%= field.name %>));
53
+ napi_value <%= field.name %> = CreateStringFromHbString(env, token_type_to_string(<%= error.human %>-><%= field.name %>));
54
54
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
55
55
 
56
56
  <%- when Herb::Template::BooleanField -%>
@@ -58,6 +58,15 @@ napi_value <%= error.name %>FromCStruct(napi_env env, <%= error.struct_type %>*
58
58
  napi_get_boolean(env, <%= error.human %>-><%= field.name %>, &<%= field.name %>);
59
59
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
60
60
 
61
+ <%- when Herb::Template::PositionField -%>
62
+ napi_value <%= field.name %> = CreatePosition(env, <%= error.human %>-><%= field.name %>);
63
+ napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
64
+
65
+ <%- when Herb::Template::SizeTField -%>
66
+ napi_value <%= field.name %>;
67
+ napi_create_uint32(env, (uint32_t)<%= error.human %>-><%= field.name %>, &<%= field.name %>);
68
+ napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
69
+
61
70
  <%- when Herb::Template::ArrayField -%>
62
71
  napi_value <%= field.name %> = NodesArrayFromCArray(env, <%= error.human %>-><%= field.name %>);
63
72
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
@@ -37,10 +37,10 @@ napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %
37
37
  <%- node.fields.each do |field| -%>
38
38
  <%- case field -%>
39
39
  <%- when Herb::Template::StringField -%>
40
- napi_value <%= field.name %> = CreateString(env, <%= node.human %>-><%= field.name %>);
40
+ napi_value <%= field.name %> = CreateStringFromHbString(env, <%= node.human %>-><%= field.name %>);
41
41
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
42
42
 
43
- <%- when Herb::Template::NodeField -%>
43
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
44
44
  napi_value <%= field.name %> = NodeFromCStruct(env, (AST_NODE_T*) <%= node.human %>-><%= field.name %>);
45
45
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
46
46
 
@@ -58,7 +58,7 @@ napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %
58
58
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
59
59
 
60
60
  <%- when Herb::Template::ElementSourceField -%>
61
- napi_value <%= field.name %> = CreateStringFromHbString(env, element_source_to_string(<%= node.human %>-><%= field.name %>));
61
+ napi_value <%= field.name %> = CreateStringFromHbString(env, <%= node.human %>-><%= field.name %>);
62
62
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
63
63
 
64
64
  <%- when Herb::Template::LocationField -%>
@@ -70,7 +70,44 @@ napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %
70
70
  }
71
71
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
72
72
 
73
+ <%- when Herb::Template::PrismSerializedField -%>
74
+ napi_value <%= field.name %>;
75
+ if (<%= node.human %>-><%= field.name %>.data != NULL && <%= node.human %>-><%= field.name %>.length > 0) {
76
+ void* buffer_data;
77
+ napi_create_buffer_copy(env, <%= node.human %>-><%= field.name %>.length,
78
+ <%= node.human %>-><%= field.name %>.data, &buffer_data, &<%= field.name %>);
79
+ } else {
80
+ napi_get_null(env, &<%= field.name %>);
81
+ }
82
+ napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
83
+
84
+ <%- when Herb::Template::PrismNodeField -%>
85
+ napi_value <%= field.name %>;
86
+ if (<%= node.human %>-><%= field.name %>.node != NULL && <%= node.human %>-><%= field.name %>.parser != NULL) {
87
+ pm_buffer_t pm_buffer = { 0 };
88
+ pm_serialize(<%= node.human %>-><%= field.name %>.parser, <%= node.human %>-><%= field.name %>.node, &pm_buffer);
89
+
90
+ if (pm_buffer.length > 0) {
91
+ void* buffer_data;
92
+ napi_create_buffer_copy(env, pm_buffer.length, pm_buffer.value, &buffer_data, &<%= field.name %>);
93
+ } else {
94
+ napi_get_null(env, &<%= field.name %>);
95
+ }
96
+
97
+ pm_buffer_free(&pm_buffer);
98
+ } else {
99
+ napi_get_null(env, &<%= field.name %>);
100
+ }
101
+ napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
102
+
103
+ <%- when Herb::Template::AnalyzedRubyField, Herb::Template::PrismContextField, Herb::Template::VoidPointerField -%>
104
+ /* <%= field.name %> is internal parser state, not exposed to JavaScript */
105
+ napi_value <%= field.name %>;
106
+ napi_get_null(env, &<%= field.name %>);
107
+ napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
108
+
73
109
  <%- else -%>
110
+ /* Unhandled field type: <%= field.class.name %> */
74
111
  napi_value <%= field.name %>;
75
112
  napi_get_null(env, &<%= field.name %>);
76
113
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
@@ -87,11 +124,13 @@ napi_value NodesArrayFromCArray(napi_env env, hb_array_T* array) {
87
124
  napi_create_array(env, &result);
88
125
 
89
126
  if (array) {
127
+ uint32_t index = 0;
128
+
90
129
  for (size_t i = 0; i < hb_array_size(array); i++) {
91
130
  AST_NODE_T* child_node = (AST_NODE_T*) hb_array_get(array, i);
92
131
  if (child_node) {
93
132
  napi_value js_child = NodeFromCStruct(env, child_node);
94
- napi_set_element(env, result, i, js_child);
133
+ napi_set_element(env, result, index++, js_child);
95
134
  }
96
135
  }
97
136
  }
@@ -1,11 +1,20 @@
1
+ require_relative "../prism_inspect"
2
+
1
3
  module Herb
2
4
  module AST
3
5
  <%- nodes.each do |node| -%>
6
+ #: type serialized_<%= node.human %> = {
7
+ <%- node.fields.each do |field| -%>
8
+ <%- is_nilable = !%w[Array[Herb::AST::Node] Array[Herb::AST::ERBWhenNode] Array[Herb::AST::ERBInNode] bool nil].include?(field.ruby_type) -%>
9
+ #| <%= field.name %>: <%= field.ruby_type %><%= if is_nilable then "?" end %>,
10
+ <%- end -%>
11
+ #| }
4
12
  class <%= node.name -%> < Node
5
13
  include Colors
6
14
 
7
15
  <%- node.fields.each do |field| -%>
8
- attr_reader :<%= field.name %> #: <%= field.ruby_type %>
16
+ <%- is_nilable = !%w[Array[Herb::AST::Node] Array[Herb::AST::ERBWhenNode] Array[Herb::AST::ERBInNode] bool nil].include?(field.ruby_type) -%>
17
+ attr_reader :<%= field.name %> #: <%= field.ruby_type %><%= if is_nilable then "?" end %>
9
18
  <%- end -%>
10
19
 
11
20
  #: (<%= ["String", "Location", "Array[Herb::Errors::Error]", *node.fields.map(&:ruby_type)].join(", ") %>) -> void
@@ -13,13 +22,32 @@ module Herb
13
22
  super(type, location, errors)
14
23
  <%- node.fields.each do |field| -%>
15
24
  <%- if field.is_a?(Herb::Template::StringField) -%>
16
- @<%= field.name %> = <%= field.name %>.force_encoding("utf-8")
25
+ @<%= field.name %> = <%= field.name %>&.force_encoding("utf-8")
17
26
  <%- else -%>
18
27
  @<%= field.name %> = <%= field.name %>
19
28
  <%- end -%>
20
29
  <%- end -%>
21
30
  end
22
31
 
32
+ <%- if node.fields.any? { |f| f.is_a?(Herb::Template::PrismSerializedField) || f.is_a?(Herb::Template::PrismNodeField) } -%>
33
+ <%- prism_field = node.fields.find { |f| f.is_a?(Herb::Template::PrismSerializedField) || f.is_a?(Herb::Template::PrismNodeField) } -%>
34
+ #: () -> Prism::node?
35
+ def deserialized_prism_node
36
+ prism_node = @<%= prism_field.name %>
37
+ return nil unless prism_node
38
+ return nil unless source
39
+
40
+ begin
41
+ require "prism"
42
+ rescue LoadError
43
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
44
+ return nil
45
+ end
46
+
47
+ Prism.load(source, prism_node).value
48
+ end
49
+
50
+ <%- end -%>
23
51
  #: () -> serialized_<%= node.human %>
24
52
  def to_hash
25
53
  super.merge({
@@ -37,10 +65,10 @@ module Herb
37
65
  #: () -> Array[Herb::AST::Node?]
38
66
  def child_nodes
39
67
  [<%= node.fields.map { |field|
40
- if field.is_a?(Herb::Template::NodeField)
68
+ if field.is_a?(Herb::Template::NodeField) || field.is_a?(Herb::Template::BorrowedNodeField)
41
69
  field.name
42
- elsif field.is_a?(Herb::Template::ArrayField) && field.specific_kind.end_with?("Node")
43
- "*#{field.name}"
70
+ elsif field.is_a?(Herb::Template::ArrayField) && (field.specific_kind&.end_with?("Node") || field.union_kind&.all? { |k| k.end_with?("Node") })
71
+ "*(#{field.name} || [])"
44
72
  else
45
73
  nil
46
74
  end
@@ -72,56 +100,91 @@ module Herb
72
100
 
73
101
  output += inspect_errors(prefix: "<%= node.fields.any? ? "│ " : " " %>")
74
102
 
75
- <%- node.fields.each do |field| -%>
76
- <%- symbol = node.fields.last == field ? "└──" : "├──" -%>
103
+ <%- node.field_visibilities.each do |visibility| -%>
104
+ <%- field = visibility.field -%>
105
+ <%- next if field.always_invisible? -%>
106
+ <%- if field.conditionally_invisible? -%>
107
+ if <%= field.name %> && source
108
+ output += white("<%= visibility.symbol.strip %> prism_node: ")
109
+ output += Herb::PrismInspect.inspect_prism_serialized(<%= field.name %>, source, "<%= visibility.prefix %>")
110
+ output += "\n"
111
+ end
112
+ <%- else -%>
113
+ <%- if visibility.dynamic_last? -%>
114
+ dynamic_symbol = <%= visibility.prism_field_name %> ? "├──" : "└──"
115
+ <%- end -%>
77
116
  <%- case field -%>
78
117
  <%- when Herb::Template::StringField -%>
79
- output += white("<%= symbol %> <%= field.name %>: ") + green("#{<%= field.name %>.inspect}\n")
118
+ <%- if visibility.dynamic_last? -%>
119
+ output += white("#{dynamic_symbol} <%= field.name %>: ") + green("#{<%= field.name %>.inspect}\n")
120
+ <%- else -%>
121
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ") + green("#{<%= field.name %>.inspect}\n")
122
+ <%- end -%>
80
123
  <%- when Herb::Template::TokenField -%>
81
- output += white("<%= symbol %> <%= field.name %>: ")
124
+ <%- if visibility.dynamic_last? -%>
125
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
126
+ <%- else -%>
127
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
128
+ <%- end -%>
82
129
  output += <%= field.name %> ? <%= field.name %>.tree_inspect : magenta("∅")
83
130
  output += "\n"
84
131
  <%- when Herb::Template::BooleanField -%>
85
- output += white("<%= symbol %> <%= field.name %>: ")
132
+ <%- if visibility.dynamic_last? -%>
133
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
134
+ <%- else -%>
135
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
136
+ <%- end -%>
86
137
  output += [true, false].include?(<%= field.name %>) ? bold(magenta(<%= field.name %>.to_s)) : magenta("∅")
87
138
  output += "\n"
88
139
  <%- when Herb::Template::LocationField -%>
89
- output += white("<%= symbol %> <%= field.name %>: ")
140
+ <%- if visibility.dynamic_last? -%>
141
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
142
+ <%- else -%>
143
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
144
+ <%- end -%>
90
145
  output += <%= field.name %> ? dimmed("(location: #{<%= field.name %>.tree_inspect})") : magenta("∅")
91
146
  output += "\n"
92
147
  <%- when Herb::Template::ElementSourceField -%>
93
- output += white("<%= symbol %> <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
94
- <%- when Herb::Template::PrismNodeField -%>
95
- # no-op for <%= field.name %>
96
- <%- when Herb::Template::AnalyzedRubyField -%>
97
- # no-op for <%= field.name %>
98
- <%- when Herb::Template::NodeField -%>
99
- output += white("<%= symbol %> <%= field.name %>: ")
148
+ <%- if visibility.dynamic_last? -%>
149
+ output += white("#{dynamic_symbol} <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
150
+ <%- else -%>
151
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
152
+ <%- end -%>
153
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
154
+ <%- if visibility.dynamic_last? -%>
155
+ dynamic_prefix = <%= visibility.prism_field_name %> ? "│ " : " "
156
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
100
157
  if <%= field.name %>
101
- <%- prefix = (node.fields.last == field) ? " " : "│ " -%>
102
158
  output += "\n"
103
- <%- if (node.fields.last == field) -%>
104
- output += " └── "
105
- <%- else -%>
106
- output += "│ └── "
107
- <%- end -%>
108
- output += <%= field.name %>.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "<%= prefix %>").delete_prefix("<%= prefix %>")
109
- <%- if false -%>
110
- <%- unless node.fields.last == field -%>
159
+ output += dynamic_prefix + "└── "
160
+ output += <%= field.name %>.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, dynamic_prefix).delete_prefix(dynamic_prefix)
161
+ else
162
+ output += magenta("∅\n")
163
+ end
164
+ <%- else -%>
165
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
166
+ if <%= field.name %>
111
167
  output += "\n"
112
- output += white("<%= prefix %>\n")
113
- <%- end -%>
114
- <%- end -%>
168
+ output += "<%= visibility.prefix %>└── "
169
+ output += <%= field.name %>.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "<%= visibility.prefix %>").delete_prefix("<%= visibility.prefix %>")
115
170
  else
116
171
  output += magenta("∅\n")
117
172
  end
173
+ <%- end -%>
118
174
  <%- when Herb::Template::ArrayField -%>
119
- output += white("<%= symbol %> <%= field.name %>: ")
120
- output += inspect_array(<%= field.name %>, prefix: "<%= (node.fields.last == field) ? " " : "" %>", indent: indent, depth: depth + 1, depth_limit: depth_limit)
175
+ <%- if visibility.dynamic_last? -%>
176
+ dynamic_prefix = <%= visibility.prism_field_name %> ? "" : " "
177
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
178
+ output += inspect_array(<%= field.name %>, prefix: dynamic_prefix, indent: indent, depth: depth + 1, depth_limit: depth_limit)
179
+ <%- else -%>
180
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
181
+ output += inspect_array(<%= field.name %>, prefix: "<%= visibility.prefix %>", indent: indent, depth: depth + 1, depth_limit: depth_limit)
182
+ <%- end -%>
121
183
  <%- else -%>
122
184
  <%- raise "Unhandled type: #{field.class}" -%>
123
185
  <%- end -%>
124
186
  <%- end -%>
187
+ <%- end -%>
125
188
  output += "\n"
126
189
 
127
190
  output.gsub(/^/, " " * indent)