herb 0.8.10-arm-linux-gnu → 0.9.0-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 (209) 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 +317 -34
  6. data/ext/herb/error_helpers.c +367 -140
  7. data/ext/herb/error_helpers.h +1 -0
  8. data/ext/herb/extconf.rb +67 -28
  9. data/ext/herb/extension.c +317 -51
  10. data/ext/herb/extension.h +1 -0
  11. data/ext/herb/extension_helpers.c +23 -14
  12. data/ext/herb/extension_helpers.h +2 -2
  13. data/ext/herb/nodes.c +537 -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 +1132 -157
  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 +82 -35
  36. data/lib/herb/errors.rb +563 -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 +57 -0
  41. data/lib/herb/position.rb +1 -0
  42. data/lib/herb/prism_inspect.rb +116 -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 +37 -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 +641 -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 +17 -3
  59. data/sig/herb/errors.rbs +258 -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 +42 -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 +25 -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/serialized_ast_errors.rbs +54 -6
  72. data/sig/serialized_ast_nodes.rbs +60 -6
  73. data/src/analyze/action_view/attribute_extraction_helpers.c +290 -0
  74. data/src/analyze/action_view/content_tag.c +70 -0
  75. data/src/analyze/action_view/link_to.c +143 -0
  76. data/src/analyze/action_view/registry.c +60 -0
  77. data/src/analyze/action_view/tag.c +64 -0
  78. data/src/analyze/action_view/tag_helper_node_builders.c +305 -0
  79. data/src/analyze/action_view/tag_helpers.c +748 -0
  80. data/src/analyze/action_view/turbo_frame_tag.c +88 -0
  81. data/src/analyze/analyze.c +882 -0
  82. data/src/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
  83. data/src/analyze/builders.c +343 -0
  84. data/src/analyze/conditional_elements.c +594 -0
  85. data/src/analyze/conditional_open_tags.c +640 -0
  86. data/src/analyze/control_type.c +250 -0
  87. data/src/{analyze_helpers.c → analyze/helpers.c} +48 -23
  88. data/src/analyze/invalid_structures.c +193 -0
  89. data/src/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
  90. data/src/analyze/parse_errors.c +84 -0
  91. data/src/analyze/prism_annotate.c +397 -0
  92. data/src/{analyze_transform.c → analyze/transform.c} +17 -3
  93. data/src/ast_node.c +17 -7
  94. data/src/ast_nodes.c +662 -387
  95. data/src/ast_pretty_print.c +190 -6
  96. data/src/errors.c +1076 -520
  97. data/src/extract.c +145 -49
  98. data/src/herb.c +52 -34
  99. data/src/html_util.c +241 -12
  100. data/src/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
  101. data/src/include/analyze/action_view/tag_helper_handler.h +41 -0
  102. data/src/include/analyze/action_view/tag_helper_node_builders.h +70 -0
  103. data/src/include/analyze/action_view/tag_helpers.h +38 -0
  104. data/src/include/{analyze.h → analyze/analyze.h} +14 -4
  105. data/src/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  106. data/src/include/analyze/builders.h +27 -0
  107. data/src/include/analyze/conditional_elements.h +9 -0
  108. data/src/include/analyze/conditional_open_tags.h +9 -0
  109. data/src/include/analyze/control_type.h +14 -0
  110. data/src/include/{analyze_helpers.h → analyze/helpers.h} +4 -2
  111. data/src/include/analyze/invalid_structures.h +11 -0
  112. data/src/include/analyze/prism_annotate.h +16 -0
  113. data/src/include/ast_node.h +11 -5
  114. data/src/include/ast_nodes.h +117 -38
  115. data/src/include/ast_pretty_print.h +5 -0
  116. data/src/include/element_source.h +3 -8
  117. data/src/include/errors.h +148 -55
  118. data/src/include/extract.h +21 -5
  119. data/src/include/herb.h +18 -6
  120. data/src/include/herb_prism_node.h +13 -0
  121. data/src/include/html_util.h +7 -2
  122. data/src/include/io.h +3 -1
  123. data/src/include/lex_helpers.h +29 -0
  124. data/src/include/lexer.h +1 -1
  125. data/src/include/lexer_peek_helpers.h +87 -13
  126. data/src/include/lexer_struct.h +2 -0
  127. data/src/include/location.h +2 -1
  128. data/src/include/parser.h +27 -2
  129. data/src/include/parser_helpers.h +19 -3
  130. data/src/include/pretty_print.h +10 -5
  131. data/src/include/prism_context.h +45 -0
  132. data/src/include/prism_helpers.h +10 -7
  133. data/src/include/prism_serialized.h +12 -0
  134. data/src/include/token.h +16 -4
  135. data/src/include/token_struct.h +10 -3
  136. data/src/include/utf8.h +2 -1
  137. data/src/include/util/hb_allocator.h +78 -0
  138. data/src/include/util/hb_arena.h +6 -1
  139. data/src/include/util/hb_arena_debug.h +12 -1
  140. data/src/include/util/hb_array.h +7 -3
  141. data/src/include/util/hb_buffer.h +6 -4
  142. data/src/include/util/hb_foreach.h +79 -0
  143. data/src/include/util/hb_narray.h +8 -4
  144. data/src/include/util/hb_string.h +56 -9
  145. data/src/include/util.h +6 -3
  146. data/src/include/version.h +1 -1
  147. data/src/io.c +3 -2
  148. data/src/lexer.c +42 -30
  149. data/src/lexer_peek_helpers.c +12 -74
  150. data/src/location.c +2 -2
  151. data/src/main.c +53 -28
  152. data/src/parser.c +783 -247
  153. data/src/parser_helpers.c +110 -23
  154. data/src/parser_match_tags.c +109 -48
  155. data/src/pretty_print.c +29 -24
  156. data/src/prism_helpers.c +30 -27
  157. data/src/ruby_parser.c +2 -0
  158. data/src/token.c +151 -66
  159. data/src/token_matchers.c +0 -1
  160. data/src/utf8.c +7 -6
  161. data/src/util/hb_allocator.c +341 -0
  162. data/src/util/hb_arena.c +81 -56
  163. data/src/util/hb_arena_debug.c +32 -17
  164. data/src/util/hb_array.c +30 -15
  165. data/src/util/hb_buffer.c +17 -21
  166. data/src/util/hb_narray.c +22 -7
  167. data/src/util/hb_string.c +49 -35
  168. data/src/util.c +21 -11
  169. data/src/visitor.c +47 -0
  170. data/templates/ext/herb/error_helpers.c.erb +24 -11
  171. data/templates/ext/herb/error_helpers.h.erb +1 -0
  172. data/templates/ext/herb/nodes.c.erb +50 -16
  173. data/templates/ext/herb/nodes.h.erb +1 -0
  174. data/templates/java/error_helpers.c.erb +1 -1
  175. data/templates/java/nodes.c.erb +30 -8
  176. data/templates/java/org/herb/ast/Errors.java.erb +24 -1
  177. data/templates/java/org/herb/ast/Nodes.java.erb +80 -21
  178. data/templates/javascript/packages/core/src/errors.ts.erb +16 -3
  179. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +3 -1
  180. data/templates/javascript/packages/core/src/nodes.ts.erb +109 -32
  181. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +13 -4
  182. data/templates/javascript/packages/node/extension/nodes.cpp.erb +43 -4
  183. data/templates/lib/herb/ast/nodes.rb.erb +88 -31
  184. data/templates/lib/herb/errors.rb.erb +15 -3
  185. data/templates/lib/herb/visitor.rb.erb +2 -2
  186. data/templates/rust/src/ast/nodes.rs.erb +97 -44
  187. data/templates/rust/src/errors.rs.erb +2 -1
  188. data/templates/rust/src/nodes.rs.erb +167 -15
  189. data/templates/rust/src/union_types.rs.erb +60 -0
  190. data/templates/rust/src/visitor.rs.erb +81 -0
  191. data/templates/src/{analyze_missing_end.c.erb → analyze/missing_end.c.erb} +9 -6
  192. data/templates/src/{analyze_transform.c.erb → analyze/transform.c.erb} +2 -2
  193. data/templates/src/ast_nodes.c.erb +34 -26
  194. data/templates/src/ast_pretty_print.c.erb +24 -5
  195. data/templates/src/errors.c.erb +60 -54
  196. data/templates/src/include/ast_nodes.h.erb +6 -2
  197. data/templates/src/include/ast_pretty_print.h.erb +5 -0
  198. data/templates/src/include/errors.h.erb +15 -11
  199. data/templates/src/include/util/hb_foreach.h.erb +20 -0
  200. data/templates/src/parser_match_tags.c.erb +10 -4
  201. data/templates/src/visitor.c.erb +2 -2
  202. data/templates/template.rb +204 -29
  203. data/templates/wasm/error_helpers.cpp.erb +9 -5
  204. data/templates/wasm/nodes.cpp.erb +41 -4
  205. metadata +57 -16
  206. data/src/analyze.c +0 -1608
  207. data/src/element_source.c +0 -12
  208. data/src/include/util/hb_system.h +0 -9
  209. 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
@@ -20,6 +29,19 @@ module Herb
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
+ require "prism"
41
+ Prism.load(source, prism_node).value
42
+ end
43
+
44
+ <%- end -%>
23
45
  #: () -> serialized_<%= node.human %>
24
46
  def to_hash
25
47
  super.merge({
@@ -37,10 +59,10 @@ module Herb
37
59
  #: () -> Array[Herb::AST::Node?]
38
60
  def child_nodes
39
61
  [<%= node.fields.map { |field|
40
- if field.is_a?(Herb::Template::NodeField)
62
+ if field.is_a?(Herb::Template::NodeField) || field.is_a?(Herb::Template::BorrowedNodeField)
41
63
  field.name
42
- elsif field.is_a?(Herb::Template::ArrayField) && field.specific_kind.end_with?("Node")
43
- "*#{field.name}"
64
+ elsif field.is_a?(Herb::Template::ArrayField) && (field.specific_kind&.end_with?("Node") || field.union_kind&.all? { |k| k.end_with?("Node") })
65
+ "*(#{field.name} || [])"
44
66
  else
45
67
  nil
46
68
  end
@@ -72,56 +94,91 @@ module Herb
72
94
 
73
95
  output += inspect_errors(prefix: "<%= node.fields.any? ? "│ " : " " %>")
74
96
 
75
- <%- node.fields.each do |field| -%>
76
- <%- symbol = node.fields.last == field ? "└──" : "├──" -%>
97
+ <%- node.field_visibilities.each do |visibility| -%>
98
+ <%- field = visibility.field -%>
99
+ <%- next if field.always_invisible? -%>
100
+ <%- if field.conditionally_invisible? -%>
101
+ if <%= field.name %> && source
102
+ output += white("<%= visibility.symbol.strip %> prism_node: ")
103
+ output += Herb::PrismInspect.inspect_prism_serialized(<%= field.name %>, source, "<%= visibility.prefix %>")
104
+ output += "\n"
105
+ end
106
+ <%- else -%>
107
+ <%- if visibility.dynamic_last? -%>
108
+ dynamic_symbol = <%= visibility.prism_field_name %> ? "├──" : "└──"
109
+ <%- end -%>
77
110
  <%- case field -%>
78
111
  <%- when Herb::Template::StringField -%>
79
- output += white("<%= symbol %> <%= field.name %>: ") + green("#{<%= field.name %>.inspect}\n")
112
+ <%- if visibility.dynamic_last? -%>
113
+ output += white("#{dynamic_symbol} <%= field.name %>: ") + green("#{<%= field.name %>.inspect}\n")
114
+ <%- else -%>
115
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ") + green("#{<%= field.name %>.inspect}\n")
116
+ <%- end -%>
80
117
  <%- when Herb::Template::TokenField -%>
81
- output += white("<%= symbol %> <%= field.name %>: ")
118
+ <%- if visibility.dynamic_last? -%>
119
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
120
+ <%- else -%>
121
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
122
+ <%- end -%>
82
123
  output += <%= field.name %> ? <%= field.name %>.tree_inspect : magenta("∅")
83
124
  output += "\n"
84
125
  <%- when Herb::Template::BooleanField -%>
85
- output += white("<%= symbol %> <%= field.name %>: ")
126
+ <%- if visibility.dynamic_last? -%>
127
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
128
+ <%- else -%>
129
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
130
+ <%- end -%>
86
131
  output += [true, false].include?(<%= field.name %>) ? bold(magenta(<%= field.name %>.to_s)) : magenta("∅")
87
132
  output += "\n"
88
133
  <%- when Herb::Template::LocationField -%>
89
- output += white("<%= symbol %> <%= field.name %>: ")
134
+ <%- if visibility.dynamic_last? -%>
135
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
136
+ <%- else -%>
137
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
138
+ <%- end -%>
90
139
  output += <%= field.name %> ? dimmed("(location: #{<%= field.name %>.tree_inspect})") : magenta("∅")
91
140
  output += "\n"
92
141
  <%- 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 %>: ")
142
+ <%- if visibility.dynamic_last? -%>
143
+ output += white("#{dynamic_symbol} <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
144
+ <%- else -%>
145
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
146
+ <%- end -%>
147
+ <%- when Herb::Template::NodeField, Herb::Template::BorrowedNodeField -%>
148
+ <%- if visibility.dynamic_last? -%>
149
+ dynamic_prefix = <%= visibility.prism_field_name %> ? "│ " : " "
150
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
100
151
  if <%= field.name %>
101
- <%- prefix = (node.fields.last == field) ? " " : "│ " -%>
102
152
  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 -%>
153
+ output += dynamic_prefix + "└── "
154
+ 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)
155
+ else
156
+ output += magenta("∅\n")
157
+ end
158
+ <%- else -%>
159
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
160
+ if <%= field.name %>
111
161
  output += "\n"
112
- output += white("<%= prefix %>\n")
113
- <%- end -%>
114
- <%- end -%>
162
+ output += "<%= visibility.prefix %>└── "
163
+ 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
164
  else
116
165
  output += magenta("∅\n")
117
166
  end
167
+ <%- end -%>
118
168
  <%- 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)
169
+ <%- if visibility.dynamic_last? -%>
170
+ dynamic_prefix = <%= visibility.prism_field_name %> ? "" : " "
171
+ output += white("#{dynamic_symbol} <%= field.name %>: ")
172
+ output += inspect_array(<%= field.name %>, prefix: dynamic_prefix, indent: indent, depth: depth + 1, depth_limit: depth_limit)
173
+ <%- else -%>
174
+ output += white("<%= visibility.symbol.strip %> <%= field.name %>: ")
175
+ output += inspect_array(<%= field.name %>, prefix: "<%= visibility.prefix %>", indent: indent, depth: depth + 1, depth_limit: depth_limit)
176
+ <%- end -%>
121
177
  <%- else -%>
122
178
  <%- raise "Unhandled type: #{field.class}" -%>
123
179
  <%- end -%>
124
180
  <%- end -%>
181
+ <%- end -%>
125
182
  output += "\n"
126
183
 
127
184
  output.gsub(/^/, " " * indent)
@@ -1,5 +1,10 @@
1
- <%- base_arguments = [["type", "String"], ["location", "Location"], ["message", "String"]] -%>
1
+ <%- base_arguments = [["type", "String"], ["location", "Location?"], ["message", "String"]] -%>
2
2
  module Herb
3
+ #: type serialized_error = {
4
+ #| type: String,
5
+ #| location: serialized_location?,
6
+ #| message: String
7
+ #| }
3
8
  module Errors
4
9
  class Error
5
10
  <%- base_arguments.each do |argument, type| -%>
@@ -49,7 +54,12 @@ module Herb
49
54
  <%- if error.fields.any? -%>
50
55
 
51
56
  <%- error.fields.each do |field| -%>
52
- attr_reader :<%= field.name %> #: <%= field.ruby_type %>
57
+ #| <%= "#{field.name}: #{field.ruby_type}?," %>
58
+ <%- end -%>
59
+ #| }
60
+
61
+ <%- error.fields.each do |field| -%>
62
+ attr_reader :<%= field.name %> #: <%= field.ruby_type %>?
53
63
  <%- end -%>
54
64
 
55
65
  #: (<%= [*base_arguments.map(&:last), *error.fields.map(&:ruby_type)].join(", ") %>) -> void
@@ -81,7 +91,7 @@ module Herb
81
91
  def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
82
92
  output = +""
83
93
 
84
- output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
94
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
85
95
  <%- symbol = error.fields.none? ? "└──" : "├──" -%>
86
96
  output += white("<%= symbol %> message: #{green(message.inspect)}\n")
87
97
  <%- error.fields.each do |field| -%>
@@ -99,6 +109,8 @@ module Herb
99
109
  output += white("<%= symbol %> <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
100
110
  <%- when Herb::Template::StringField -%>
101
111
  output += white("<%= symbol %> <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
112
+ <%- when Herb::Template::SizeTField -%>
113
+ output += white("<%= symbol %> <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
102
114
  <%- else -%>
103
115
  output += white("<%= symbol %> <%= field.name %>: ") + '#{<%= field.name %>.class}'\n"
104
116
  <%- end -%>