@herb-tools/rewriter 0.9.3 → 0.9.5

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.
@@ -207,7 +207,7 @@ class Token {
207
207
  }
208
208
 
209
209
  // NOTE: This file is generated by the templates/template.rb script and should not
210
- // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.3/templates/javascript/packages/core/src/errors.ts.erb
210
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.5/templates/javascript/packages/core/src/errors.ts.erb
211
211
  class HerbError {
212
212
  type;
213
213
  message;
@@ -20355,6 +20355,17 @@ function inspectPrismSerialized(bytes, source, prefix = "") {
20355
20355
  }
20356
20356
  }
20357
20357
 
20358
+ /**
20359
+ * Checks if a Prism node is of a specific type by comparing constructor names.
20360
+ *
20361
+ * This is preferred over `instanceof` because `@ruby/prism` classes may be
20362
+ * duplicated across bundled packages, causing `instanceof` checks to fail.
20363
+ */
20364
+ function isPrismNodeType(node, type) {
20365
+ if (!node)
20366
+ return false;
20367
+ return node.constructor?.name === type;
20368
+ }
20358
20369
  /**
20359
20370
  * Deserialize a Prism parse result from the raw bytes produced by pm_serialize().
20360
20371
  *
@@ -20386,7 +20397,7 @@ function deserializePrismNode(bytes, source) {
20386
20397
  }
20387
20398
 
20388
20399
  // NOTE: This file is generated by the templates/template.rb script and should not
20389
- // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.3/templates/javascript/packages/core/src/nodes.ts.erb
20400
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.5/templates/javascript/packages/core/src/nodes.ts.erb
20390
20401
  class Node {
20391
20402
  type;
20392
20403
  location;
@@ -22007,6 +22018,7 @@ class ERBBlockNode extends Node {
22007
22018
  tag_closing;
22008
22019
  prism_node;
22009
22020
  body;
22021
+ block_arguments;
22010
22022
  rescue_clause;
22011
22023
  else_clause;
22012
22024
  ensure_clause;
@@ -22024,6 +22036,7 @@ class ERBBlockNode extends Node {
22024
22036
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
22025
22037
  prism_node: data.prism_node ? new Uint8Array(data.prism_node) : null,
22026
22038
  body: (data.body || []).map(node => fromSerializedNode(node)),
22039
+ block_arguments: (data.block_arguments || []).map(node => fromSerializedNode(node)),
22027
22040
  rescue_clause: data.rescue_clause ? fromSerializedNode((data.rescue_clause)) : null,
22028
22041
  else_clause: data.else_clause ? fromSerializedNode((data.else_clause)) : null,
22029
22042
  ensure_clause: data.ensure_clause ? fromSerializedNode((data.ensure_clause)) : null,
@@ -22037,6 +22050,7 @@ class ERBBlockNode extends Node {
22037
22050
  this.tag_closing = props.tag_closing;
22038
22051
  this.prism_node = props.prism_node;
22039
22052
  this.body = props.body;
22053
+ this.block_arguments = props.block_arguments;
22040
22054
  this.rescue_clause = props.rescue_clause;
22041
22055
  this.else_clause = props.else_clause;
22042
22056
  this.ensure_clause = props.ensure_clause;
@@ -22048,6 +22062,7 @@ class ERBBlockNode extends Node {
22048
22062
  childNodes() {
22049
22063
  return [
22050
22064
  ...this.body,
22065
+ ...this.block_arguments,
22051
22066
  this.rescue_clause,
22052
22067
  this.else_clause,
22053
22068
  this.ensure_clause,
@@ -22066,6 +22081,7 @@ class ERBBlockNode extends Node {
22066
22081
  return [
22067
22082
  ...this.errors,
22068
22083
  ...this.body.map(node => node.recursiveErrors()),
22084
+ ...this.block_arguments.map(node => node.recursiveErrors()),
22069
22085
  this.rescue_clause ? this.rescue_clause.recursiveErrors() : [],
22070
22086
  this.else_clause ? this.else_clause.recursiveErrors() : [],
22071
22087
  this.ensure_clause ? this.ensure_clause.recursiveErrors() : [],
@@ -22081,6 +22097,7 @@ class ERBBlockNode extends Node {
22081
22097
  tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
22082
22098
  prism_node: this.prism_node ? Array.from(this.prism_node) : null,
22083
22099
  body: this.body.map(node => node.toJSON()),
22100
+ block_arguments: this.block_arguments.map(node => node.toJSON()),
22084
22101
  rescue_clause: this.rescue_clause ? this.rescue_clause.toJSON() : null,
22085
22102
  else_clause: this.else_clause ? this.else_clause.toJSON() : null,
22086
22103
  ensure_clause: this.ensure_clause ? this.ensure_clause.toJSON() : null,
@@ -22098,6 +22115,7 @@ class ERBBlockNode extends Node {
22098
22115
  output += `├── prism_node: ${this.source ? inspectPrismSerialized(this.prism_node, this.source, "│ ") : `(${this.prism_node.length} bytes)`}\n`;
22099
22116
  }
22100
22117
  output += `├── body: ${this.inspectArray(this.body, "│ ")}`;
22118
+ output += `├── block_arguments: ${this.inspectArray(this.block_arguments, "│ ")}`;
22101
22119
  output += `├── rescue_clause: ${this.inspectNode(this.rescue_clause, "│ ")}`;
22102
22120
  output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
22103
22121
  output += `├── ensure_clause: ${this.inspectNode(this.ensure_clause, "│ ")}`;
@@ -23005,12 +23023,7 @@ class RubyRenderLocalNode extends Node {
23005
23023
  return output;
23006
23024
  }
23007
23025
  }
23008
- class ERBRenderNode extends Node {
23009
- tag_opening;
23010
- content;
23011
- tag_closing;
23012
- // no-op for analyzed_ruby
23013
- prism_node;
23026
+ class RubyRenderKeywordsNode extends Node {
23014
23027
  partial;
23015
23028
  template_path;
23016
23029
  layout;
@@ -23030,18 +23043,13 @@ class ERBRenderNode extends Node {
23030
23043
  content_type;
23031
23044
  locals;
23032
23045
  static get type() {
23033
- return "AST_ERB_RENDER_NODE";
23046
+ return "AST_RUBY_RENDER_KEYWORDS_NODE";
23034
23047
  }
23035
23048
  static from(data) {
23036
- return new ERBRenderNode({
23049
+ return new RubyRenderKeywordsNode({
23037
23050
  type: data.type,
23038
23051
  location: Location.from(data.location),
23039
23052
  errors: (data.errors || []).map(error => HerbError.from(error)),
23040
- tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
23041
- content: data.content ? Token.from(data.content) : null,
23042
- tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
23043
- // no-op for analyzed_ruby
23044
- prism_node: data.prism_node ? new Uint8Array(data.prism_node) : null,
23045
23053
  partial: data.partial ? Token.from(data.partial) : null,
23046
23054
  template_path: data.template_path ? Token.from(data.template_path) : null,
23047
23055
  layout: data.layout ? Token.from(data.layout) : null,
@@ -23064,11 +23072,6 @@ class ERBRenderNode extends Node {
23064
23072
  }
23065
23073
  constructor(props) {
23066
23074
  super(props.type, props.location, props.errors);
23067
- this.tag_opening = props.tag_opening;
23068
- this.content = props.content;
23069
- this.tag_closing = props.tag_closing;
23070
- // no-op for analyzed_ruby
23071
- this.prism_node = props.prism_node;
23072
23075
  this.partial = props.partial;
23073
23076
  this.template_path = props.template_path;
23074
23077
  this.layout = props.layout;
@@ -23089,7 +23092,7 @@ class ERBRenderNode extends Node {
23089
23092
  this.locals = props.locals;
23090
23093
  }
23091
23094
  accept(visitor) {
23092
- visitor.visitERBRenderNode(this);
23095
+ visitor.visitRubyRenderKeywordsNode(this);
23093
23096
  }
23094
23097
  childNodes() {
23095
23098
  return [
@@ -23099,11 +23102,6 @@ class ERBRenderNode extends Node {
23099
23102
  compactChildNodes() {
23100
23103
  return this.childNodes().filter(node => node !== null && node !== undefined);
23101
23104
  }
23102
- get prismNode() {
23103
- if (!this.prism_node || !this.source)
23104
- return null;
23105
- return deserializePrismNode(this.prism_node, this.source);
23106
- }
23107
23105
  recursiveErrors() {
23108
23106
  return [
23109
23107
  ...this.errors,
@@ -23113,12 +23111,7 @@ class ERBRenderNode extends Node {
23113
23111
  toJSON() {
23114
23112
  return {
23115
23113
  ...super.toJSON(),
23116
- type: "AST_ERB_RENDER_NODE",
23117
- tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
23118
- content: this.content ? this.content.toJSON() : null,
23119
- tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
23120
- // no-op for analyzed_ruby
23121
- prism_node: this.prism_node ? Array.from(this.prism_node) : null,
23114
+ type: "AST_RUBY_RENDER_KEYWORDS_NODE",
23122
23115
  partial: this.partial ? this.partial.toJSON() : null,
23123
23116
  template_path: this.template_path ? this.template_path.toJSON() : null,
23124
23117
  layout: this.layout ? this.layout.toJSON() : null,
@@ -23141,14 +23134,8 @@ class ERBRenderNode extends Node {
23141
23134
  }
23142
23135
  treeInspect() {
23143
23136
  let output = "";
23144
- output += `@ ERBRenderNode ${this.location.treeInspectWithLabel()}\n`;
23137
+ output += `@ RubyRenderKeywordsNode ${this.location.treeInspectWithLabel()}\n`;
23145
23138
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
23146
- output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
23147
- output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
23148
- output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
23149
- if (this.prism_node) {
23150
- output += `├── prism_node: ${this.source ? inspectPrismSerialized(this.prism_node, this.source, "│ ") : `(${this.prism_node.length} bytes)`}\n`;
23151
- }
23152
23139
  output += `├── partial: ${this.partial ? this.partial.treeInspect() : "∅"}\n`;
23153
23140
  output += `├── template_path: ${this.template_path ? this.template_path.treeInspect() : "∅"}\n`;
23154
23141
  output += `├── layout: ${this.layout ? this.layout.treeInspect() : "∅"}\n`;
@@ -23170,34 +23157,156 @@ class ERBRenderNode extends Node {
23170
23157
  return output;
23171
23158
  }
23172
23159
  }
23173
- class RubyStrictLocalNode extends Node {
23160
+ class ERBRenderNode extends Node {
23161
+ tag_opening;
23162
+ content;
23163
+ tag_closing;
23164
+ // no-op for analyzed_ruby
23165
+ prism_node;
23166
+ keywords;
23167
+ body;
23168
+ block_arguments;
23169
+ rescue_clause;
23170
+ else_clause;
23171
+ ensure_clause;
23172
+ end_node;
23173
+ static get type() {
23174
+ return "AST_ERB_RENDER_NODE";
23175
+ }
23176
+ static from(data) {
23177
+ return new ERBRenderNode({
23178
+ type: data.type,
23179
+ location: Location.from(data.location),
23180
+ errors: (data.errors || []).map(error => HerbError.from(error)),
23181
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
23182
+ content: data.content ? Token.from(data.content) : null,
23183
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
23184
+ // no-op for analyzed_ruby
23185
+ prism_node: data.prism_node ? new Uint8Array(data.prism_node) : null,
23186
+ keywords: data.keywords ? fromSerializedNode((data.keywords)) : null,
23187
+ body: (data.body || []).map(node => fromSerializedNode(node)),
23188
+ block_arguments: (data.block_arguments || []).map(node => fromSerializedNode(node)),
23189
+ rescue_clause: data.rescue_clause ? fromSerializedNode((data.rescue_clause)) : null,
23190
+ else_clause: data.else_clause ? fromSerializedNode((data.else_clause)) : null,
23191
+ ensure_clause: data.ensure_clause ? fromSerializedNode((data.ensure_clause)) : null,
23192
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
23193
+ });
23194
+ }
23195
+ constructor(props) {
23196
+ super(props.type, props.location, props.errors);
23197
+ this.tag_opening = props.tag_opening;
23198
+ this.content = props.content;
23199
+ this.tag_closing = props.tag_closing;
23200
+ // no-op for analyzed_ruby
23201
+ this.prism_node = props.prism_node;
23202
+ this.keywords = props.keywords;
23203
+ this.body = props.body;
23204
+ this.block_arguments = props.block_arguments;
23205
+ this.rescue_clause = props.rescue_clause;
23206
+ this.else_clause = props.else_clause;
23207
+ this.ensure_clause = props.ensure_clause;
23208
+ this.end_node = props.end_node;
23209
+ }
23210
+ accept(visitor) {
23211
+ visitor.visitERBRenderNode(this);
23212
+ }
23213
+ childNodes() {
23214
+ return [
23215
+ this.keywords,
23216
+ ...this.body,
23217
+ ...this.block_arguments,
23218
+ this.rescue_clause,
23219
+ this.else_clause,
23220
+ this.ensure_clause,
23221
+ this.end_node,
23222
+ ];
23223
+ }
23224
+ compactChildNodes() {
23225
+ return this.childNodes().filter(node => node !== null && node !== undefined);
23226
+ }
23227
+ get prismNode() {
23228
+ if (!this.prism_node || !this.source)
23229
+ return null;
23230
+ return deserializePrismNode(this.prism_node, this.source);
23231
+ }
23232
+ recursiveErrors() {
23233
+ return [
23234
+ ...this.errors,
23235
+ this.keywords ? this.keywords.recursiveErrors() : [],
23236
+ ...this.body.map(node => node.recursiveErrors()),
23237
+ ...this.block_arguments.map(node => node.recursiveErrors()),
23238
+ this.rescue_clause ? this.rescue_clause.recursiveErrors() : [],
23239
+ this.else_clause ? this.else_clause.recursiveErrors() : [],
23240
+ this.ensure_clause ? this.ensure_clause.recursiveErrors() : [],
23241
+ this.end_node ? this.end_node.recursiveErrors() : [],
23242
+ ].flat();
23243
+ }
23244
+ toJSON() {
23245
+ return {
23246
+ ...super.toJSON(),
23247
+ type: "AST_ERB_RENDER_NODE",
23248
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
23249
+ content: this.content ? this.content.toJSON() : null,
23250
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
23251
+ // no-op for analyzed_ruby
23252
+ prism_node: this.prism_node ? Array.from(this.prism_node) : null,
23253
+ keywords: this.keywords ? this.keywords.toJSON() : null,
23254
+ body: this.body.map(node => node.toJSON()),
23255
+ block_arguments: this.block_arguments.map(node => node.toJSON()),
23256
+ rescue_clause: this.rescue_clause ? this.rescue_clause.toJSON() : null,
23257
+ else_clause: this.else_clause ? this.else_clause.toJSON() : null,
23258
+ ensure_clause: this.ensure_clause ? this.ensure_clause.toJSON() : null,
23259
+ end_node: this.end_node ? this.end_node.toJSON() : null,
23260
+ };
23261
+ }
23262
+ treeInspect() {
23263
+ let output = "";
23264
+ output += `@ ERBRenderNode ${this.location.treeInspectWithLabel()}\n`;
23265
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
23266
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
23267
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
23268
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
23269
+ if (this.prism_node) {
23270
+ output += `├── prism_node: ${this.source ? inspectPrismSerialized(this.prism_node, this.source, "│ ") : `(${this.prism_node.length} bytes)`}\n`;
23271
+ }
23272
+ output += `├── keywords: ${this.inspectNode(this.keywords, "│ ")}`;
23273
+ output += `├── body: ${this.inspectArray(this.body, "│ ")}`;
23274
+ output += `├── block_arguments: ${this.inspectArray(this.block_arguments, "│ ")}`;
23275
+ output += `├── rescue_clause: ${this.inspectNode(this.rescue_clause, "│ ")}`;
23276
+ output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
23277
+ output += `├── ensure_clause: ${this.inspectNode(this.ensure_clause, "│ ")}`;
23278
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
23279
+ return output;
23280
+ }
23281
+ }
23282
+ class RubyParameterNode extends Node {
23174
23283
  name;
23175
23284
  default_value;
23285
+ kind;
23176
23286
  required;
23177
- double_splat;
23178
23287
  static get type() {
23179
- return "AST_RUBY_STRICT_LOCAL_NODE";
23288
+ return "AST_RUBY_PARAMETER_NODE";
23180
23289
  }
23181
23290
  static from(data) {
23182
- return new RubyStrictLocalNode({
23291
+ return new RubyParameterNode({
23183
23292
  type: data.type,
23184
23293
  location: Location.from(data.location),
23185
23294
  errors: (data.errors || []).map(error => HerbError.from(error)),
23186
23295
  name: data.name ? Token.from(data.name) : null,
23187
23296
  default_value: data.default_value ? fromSerializedNode((data.default_value)) : null,
23297
+ kind: data.kind,
23188
23298
  required: data.required,
23189
- double_splat: data.double_splat,
23190
23299
  });
23191
23300
  }
23192
23301
  constructor(props) {
23193
23302
  super(props.type, props.location, props.errors);
23194
23303
  this.name = props.name;
23195
23304
  this.default_value = props.default_value;
23305
+ this.kind = props.kind;
23196
23306
  this.required = props.required;
23197
- this.double_splat = props.double_splat;
23198
23307
  }
23199
23308
  accept(visitor) {
23200
- visitor.visitRubyStrictLocalNode(this);
23309
+ visitor.visitRubyParameterNode(this);
23201
23310
  }
23202
23311
  childNodes() {
23203
23312
  return [
@@ -23216,21 +23325,21 @@ class RubyStrictLocalNode extends Node {
23216
23325
  toJSON() {
23217
23326
  return {
23218
23327
  ...super.toJSON(),
23219
- type: "AST_RUBY_STRICT_LOCAL_NODE",
23328
+ type: "AST_RUBY_PARAMETER_NODE",
23220
23329
  name: this.name ? this.name.toJSON() : null,
23221
23330
  default_value: this.default_value ? this.default_value.toJSON() : null,
23331
+ kind: this.kind,
23222
23332
  required: this.required,
23223
- double_splat: this.double_splat,
23224
23333
  };
23225
23334
  }
23226
23335
  treeInspect() {
23227
23336
  let output = "";
23228
- output += `@ RubyStrictLocalNode ${this.location.treeInspectWithLabel()}\n`;
23337
+ output += `@ RubyParameterNode ${this.location.treeInspectWithLabel()}\n`;
23229
23338
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
23230
23339
  output += `├── name: ${this.name ? this.name.treeInspect() : "∅"}\n`;
23231
23340
  output += `├── default_value: ${this.inspectNode(this.default_value, "│ ")}`;
23232
- output += `├── required: ${typeof this.required === 'boolean' ? String(this.required) : "∅"}\n`;
23233
- output += `└── double_splat: ${typeof this.double_splat === 'boolean' ? String(this.double_splat) : "∅"}\n`;
23341
+ output += `├── kind: ${this.kind ? JSON.stringify(this.kind) : "∅"}\n`;
23342
+ output += `└── required: ${typeof this.required === 'boolean' ? String(this.required) : "∅"}\n`;
23234
23343
  return output;
23235
23344
  }
23236
23345
  }
@@ -23478,8 +23587,9 @@ function fromSerializedNode(node) {
23478
23587
  case "AST_ERB_BEGIN_NODE": return ERBBeginNode.from(node);
23479
23588
  case "AST_ERB_UNLESS_NODE": return ERBUnlessNode.from(node);
23480
23589
  case "AST_RUBY_RENDER_LOCAL_NODE": return RubyRenderLocalNode.from(node);
23590
+ case "AST_RUBY_RENDER_KEYWORDS_NODE": return RubyRenderKeywordsNode.from(node);
23481
23591
  case "AST_ERB_RENDER_NODE": return ERBRenderNode.from(node);
23482
- case "AST_RUBY_STRICT_LOCAL_NODE": return RubyStrictLocalNode.from(node);
23592
+ case "AST_RUBY_PARAMETER_NODE": return RubyParameterNode.from(node);
23483
23593
  case "AST_ERB_STRICT_LOCALS_NODE": return ERBStrictLocalsNode.from(node);
23484
23594
  case "AST_ERB_YIELD_NODE": return ERBYieldNode.from(node);
23485
23595
  case "AST_ERB_IN_NODE": return ERBInNode.from(node);
@@ -23655,7 +23765,7 @@ class ParseResult extends Result {
23655
23765
  }
23656
23766
 
23657
23767
  // NOTE: This file is generated by the templates/template.rb script and should not
23658
- // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.3/templates/javascript/packages/core/src/node-type-guards.ts.erb
23768
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.5/templates/javascript/packages/core/src/node-type-guards.ts.erb
23659
23769
  /**
23660
23770
  * Type guard functions for AST nodes.
23661
23771
  * These functions provide type checking by combining both instanceof
@@ -23958,6 +24068,14 @@ function isRubyRenderLocalNode(node) {
23958
24068
  return false;
23959
24069
  return node instanceof RubyRenderLocalNode || node.type === "AST_RUBY_RENDER_LOCAL_NODE" || node.constructor.type === "AST_RUBY_RENDER_LOCAL_NODE";
23960
24070
  }
24071
+ /**
24072
+ * Checks if a node is a RubyRenderKeywordsNode
24073
+ */
24074
+ function isRubyRenderKeywordsNode(node) {
24075
+ if (!node)
24076
+ return false;
24077
+ return node instanceof RubyRenderKeywordsNode || node.type === "AST_RUBY_RENDER_KEYWORDS_NODE" || node.constructor.type === "AST_RUBY_RENDER_KEYWORDS_NODE";
24078
+ }
23961
24079
  /**
23962
24080
  * Checks if a node is a ERBRenderNode
23963
24081
  */
@@ -23967,12 +24085,12 @@ function isERBRenderNode(node) {
23967
24085
  return node instanceof ERBRenderNode || node.type === "AST_ERB_RENDER_NODE" || node.constructor.type === "AST_ERB_RENDER_NODE";
23968
24086
  }
23969
24087
  /**
23970
- * Checks if a node is a RubyStrictLocalNode
24088
+ * Checks if a node is a RubyParameterNode
23971
24089
  */
23972
- function isRubyStrictLocalNode(node) {
24090
+ function isRubyParameterNode(node) {
23973
24091
  if (!node)
23974
24092
  return false;
23975
- return node instanceof RubyStrictLocalNode || node.type === "AST_RUBY_STRICT_LOCAL_NODE" || node.constructor.type === "AST_RUBY_STRICT_LOCAL_NODE";
24093
+ return node instanceof RubyParameterNode || node.type === "AST_RUBY_PARAMETER_NODE" || node.constructor.type === "AST_RUBY_PARAMETER_NODE";
23976
24094
  }
23977
24095
  /**
23978
24096
  * Checks if a node is a ERBStrictLocalsNode
@@ -23998,6 +24116,31 @@ function isERBInNode(node) {
23998
24116
  return false;
23999
24117
  return node instanceof ERBInNode || node.type === "AST_ERB_IN_NODE" || node.constructor.type === "AST_ERB_IN_NODE";
24000
24118
  }
24119
+ /**
24120
+ * Checks if a node is any ERB node type
24121
+ */
24122
+ function isERBNode(node) {
24123
+ return isERBOpenTagNode(node) ||
24124
+ isERBContentNode(node) ||
24125
+ isERBEndNode(node) ||
24126
+ isERBElseNode(node) ||
24127
+ isERBIfNode(node) ||
24128
+ isERBBlockNode(node) ||
24129
+ isERBWhenNode(node) ||
24130
+ isERBCaseNode(node) ||
24131
+ isERBCaseMatchNode(node) ||
24132
+ isERBWhileNode(node) ||
24133
+ isERBUntilNode(node) ||
24134
+ isERBForNode(node) ||
24135
+ isERBRescueNode(node) ||
24136
+ isERBEnsureNode(node) ||
24137
+ isERBBeginNode(node) ||
24138
+ isERBUnlessNode(node) ||
24139
+ isERBRenderNode(node) ||
24140
+ isERBStrictLocalsNode(node) ||
24141
+ isERBYieldNode(node) ||
24142
+ isERBInNode(node);
24143
+ }
24001
24144
  /**
24002
24145
  * Map of node classes to their corresponding type guard functions
24003
24146
  *
@@ -24046,8 +24189,9 @@ const NODE_TYPE_GUARDS = new Map([
24046
24189
  [ERBBeginNode, isERBBeginNode],
24047
24190
  [ERBUnlessNode, isERBUnlessNode],
24048
24191
  [RubyRenderLocalNode, isRubyRenderLocalNode],
24192
+ [RubyRenderKeywordsNode, isRubyRenderKeywordsNode],
24049
24193
  [ERBRenderNode, isERBRenderNode],
24050
- [RubyStrictLocalNode, isRubyStrictLocalNode],
24194
+ [RubyParameterNode, isRubyParameterNode],
24051
24195
  [ERBStrictLocalsNode, isERBStrictLocalsNode],
24052
24196
  [ERBYieldNode, isERBYieldNode],
24053
24197
  [ERBInNode, isERBInNode],
@@ -24100,8 +24244,9 @@ const AST_TYPE_GUARDS = new Map([
24100
24244
  ["AST_ERB_BEGIN_NODE", isERBBeginNode],
24101
24245
  ["AST_ERB_UNLESS_NODE", isERBUnlessNode],
24102
24246
  ["AST_RUBY_RENDER_LOCAL_NODE", isRubyRenderLocalNode],
24247
+ ["AST_RUBY_RENDER_KEYWORDS_NODE", isRubyRenderKeywordsNode],
24103
24248
  ["AST_ERB_RENDER_NODE", isERBRenderNode],
24104
- ["AST_RUBY_STRICT_LOCAL_NODE", isRubyStrictLocalNode],
24249
+ ["AST_RUBY_PARAMETER_NODE", isRubyParameterNode],
24105
24250
  ["AST_ERB_STRICT_LOCALS_NODE", isERBStrictLocalsNode],
24106
24251
  ["AST_ERB_YIELD_NODE", isERBYieldNode],
24107
24252
  ["AST_ERB_IN_NODE", isERBInNode],
@@ -24160,6 +24305,17 @@ function isToken(object) {
24160
24305
  function isParseResult(object) {
24161
24306
  return (object instanceof ParseResult) || (object?.constructor?.name === "ParseResult" && "value" in object);
24162
24307
  }
24308
+
24309
+ /**
24310
+ * Checks if a node is an ERB output node (generates content: <%= %> or <%== %>)
24311
+ */
24312
+ function isERBOutputNode(node) {
24313
+ if (!isERBNode(node))
24314
+ return false;
24315
+ if (!node.tag_opening?.value)
24316
+ return false;
24317
+ return ["<%=", "<%=="].includes(node.tag_opening?.value);
24318
+ }
24163
24319
  /**
24164
24320
  * Extracts a static string from an array of literal nodes
24165
24321
  * Returns null if any node is not a literal node
@@ -24324,12 +24480,88 @@ function getNodesBeforePosition(nodes, position, inclusive = false) {
24324
24480
  function getNodesAfterPosition(nodes, position, inclusive = true) {
24325
24481
  return nodes.filter(node => node.location && isPositionAfter(node.location.start, position, inclusive));
24326
24482
  }
24483
+ // --- AST Mutation Utilities ---
24484
+ const CHILD_ARRAY_PROPS = ["children", "body", "statements", "conditions"];
24485
+ const LINKED_NODE_PROPS = ["subsequent", "else_clause"];
24486
+ /**
24487
+ * Finds the array containing a target node in the AST, along with its index.
24488
+ * Traverses child arrays and linked node properties (e.g., `subsequent`, `else_clause`).
24489
+ *
24490
+ * Useful for autofix operations that need to splice nodes in/out of their parent array.
24491
+ *
24492
+ * @param root - The root node to search from
24493
+ * @param target - The node to find
24494
+ * @returns The containing array and the target's index, or null if not found
24495
+ */
24496
+ function findParentArray(root, target) {
24497
+ const search = (node) => {
24498
+ const record = node;
24499
+ for (const prop of CHILD_ARRAY_PROPS) {
24500
+ const array = record[prop];
24501
+ if (Array.isArray(array)) {
24502
+ const index = array.indexOf(target);
24503
+ if (index !== -1) {
24504
+ return { array, index };
24505
+ }
24506
+ }
24507
+ }
24508
+ for (const prop of CHILD_ARRAY_PROPS) {
24509
+ const array = record[prop];
24510
+ if (Array.isArray(array)) {
24511
+ for (const child of array) {
24512
+ if (child && typeof child === 'object' && 'type' in child) {
24513
+ const result = search(child);
24514
+ if (result) {
24515
+ return result;
24516
+ }
24517
+ }
24518
+ }
24519
+ }
24520
+ }
24521
+ for (const prop of LINKED_NODE_PROPS) {
24522
+ const value = record[prop];
24523
+ if (value && typeof value === 'object' && 'type' in value) {
24524
+ const result = search(value);
24525
+ if (result) {
24526
+ return result;
24527
+ }
24528
+ }
24529
+ }
24530
+ return null;
24531
+ };
24532
+ return search(root);
24533
+ }
24534
+ /**
24535
+ * Creates a synthetic LiteralNode with the given content and zero location.
24536
+ * Useful for inserting whitespace or newlines during AST mutations.
24537
+ */
24538
+ function createLiteral(content) {
24539
+ return new LiteralNode({
24540
+ type: "AST_LITERAL_NODE",
24541
+ content,
24542
+ location: Location.zero,
24543
+ errors: [],
24544
+ });
24545
+ }
24327
24546
  function createSyntheticToken(value, type = "TOKEN_SYNTHETIC") {
24328
24547
  return new Token(value, Range.zero, Location.zero, type);
24329
24548
  }
24549
+ function createERBOutputNode(expression, tagOpening = "<%=", tagClosing = "%>") {
24550
+ return new ERBContentNode({
24551
+ type: "AST_ERB_CONTENT_NODE",
24552
+ tag_opening: createSyntheticToken(tagOpening),
24553
+ content: createSyntheticToken(expression),
24554
+ tag_closing: createSyntheticToken(tagClosing),
24555
+ parsed: false,
24556
+ valid: true,
24557
+ prism_node: null,
24558
+ location: Location.zero,
24559
+ errors: [],
24560
+ });
24561
+ }
24330
24562
 
24331
24563
  // NOTE: This file is generated by the templates/template.rb script and should not
24332
- // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.3/templates/javascript/packages/core/src/visitor.ts.erb
24564
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.5/templates/javascript/packages/core/src/visitor.ts.erb
24333
24565
  class Visitor {
24334
24566
  visit(node) {
24335
24567
  if (!node)
@@ -24512,12 +24744,16 @@ class Visitor {
24512
24744
  this.visitNode(node);
24513
24745
  this.visitChildNodes(node);
24514
24746
  }
24747
+ visitRubyRenderKeywordsNode(node) {
24748
+ this.visitNode(node);
24749
+ this.visitChildNodes(node);
24750
+ }
24515
24751
  visitERBRenderNode(node) {
24516
24752
  this.visitNode(node);
24517
24753
  this.visitERBNode(node);
24518
24754
  this.visitChildNodes(node);
24519
24755
  }
24520
- visitRubyStrictLocalNode(node) {
24756
+ visitRubyParameterNode(node) {
24521
24757
  this.visitNode(node);
24522
24758
  this.visitChildNodes(node);
24523
24759
  }
@@ -24724,6 +24960,124 @@ class ActionViewTagHelperToHTMLRewriter extends ASTRewriter {
24724
24960
  }
24725
24961
  }
24726
24962
 
24963
+ const STRING_NODE_TYPE = "StringNode";
24964
+ const INTERPOLATED_STRING_NODE_TYPE = "InterpolatedStringNode";
24965
+ const EMBEDDED_STATEMENTS_NODE_TYPE = "EmbeddedStatementsNode";
24966
+ class ERBStringToDirectOutputVisitor extends Visitor {
24967
+ root;
24968
+ constructor(root) {
24969
+ super();
24970
+ this.root = root;
24971
+ }
24972
+ visitERBContentNode(node) {
24973
+ if (!isERBOutputNode(node)) {
24974
+ this.visitChildNodes(node);
24975
+ return;
24976
+ }
24977
+ const prismNode = node.prismNode;
24978
+ if (!prismNode) {
24979
+ this.visitChildNodes(node);
24980
+ return;
24981
+ }
24982
+ const source = node.source;
24983
+ if (!source) {
24984
+ this.visitChildNodes(node);
24985
+ return;
24986
+ }
24987
+ if (!ERBStringToDirectOutputRewriter.isStringOutputNode(prismNode)) {
24988
+ this.visitChildNodes(node);
24989
+ return;
24990
+ }
24991
+ const replacementParts = ERBStringToDirectOutputRewriter.extractReplacementParts(prismNode, source);
24992
+ if (!replacementParts) {
24993
+ this.visitChildNodes(node);
24994
+ return;
24995
+ }
24996
+ const tagOpening = node.tag_opening?.value ?? "<%=";
24997
+ const tagClosing = node.tag_closing?.value ?? "%>";
24998
+ const parentInfo = findParentArray(this.root, node);
24999
+ if (!parentInfo) {
25000
+ this.visitChildNodes(node);
25001
+ return;
25002
+ }
25003
+ const { array: parentArray, index: nodeIndex } = parentInfo;
25004
+ const replacementNodes = [];
25005
+ for (const part of replacementParts) {
25006
+ if (part.type === "text") {
25007
+ replacementNodes.push(createLiteral(part.content));
25008
+ }
25009
+ else {
25010
+ replacementNodes.push(createERBOutputNode(` ${part.expression.trim()} `, tagOpening, tagClosing));
25011
+ }
25012
+ }
25013
+ parentArray.splice(nodeIndex, 1, ...replacementNodes);
25014
+ }
25015
+ }
25016
+ class ERBStringToDirectOutputRewriter extends ASTRewriter {
25017
+ get name() {
25018
+ return "erb-string-to-direct-output";
25019
+ }
25020
+ get description() {
25021
+ return "Replaces ERB string output with direct text and expression tags";
25022
+ }
25023
+ rewrite(node, _context) {
25024
+ const visitor = new ERBStringToDirectOutputVisitor(node);
25025
+ visitor.visit(node);
25026
+ return node;
25027
+ }
25028
+ static isStringOutputNode(prismNode) {
25029
+ return isPrismNodeType(prismNode, STRING_NODE_TYPE) || isPrismNodeType(prismNode, INTERPOLATED_STRING_NODE_TYPE);
25030
+ }
25031
+ static extractStringContent(stringNode, source) {
25032
+ const unescapedValue = stringNode.unescaped?.value;
25033
+ if (typeof unescapedValue === "string") {
25034
+ return unescapedValue;
25035
+ }
25036
+ const location = stringNode.contentLoc;
25037
+ if (location) {
25038
+ return source.substring(location.startOffset, location.startOffset + location.length);
25039
+ }
25040
+ return "";
25041
+ }
25042
+ static extractExpressionSource(embeddedNode, source) {
25043
+ const openingLocation = embeddedNode.openingLoc;
25044
+ const closingLocation = embeddedNode.closingLoc;
25045
+ if (!openingLocation || !closingLocation)
25046
+ return null;
25047
+ const expressionStart = openingLocation.startOffset + openingLocation.length;
25048
+ const expressionEnd = closingLocation.startOffset;
25049
+ return source.substring(expressionStart, expressionEnd);
25050
+ }
25051
+ static extractReplacementParts(prismNode, source) {
25052
+ if (isPrismNodeType(prismNode, STRING_NODE_TYPE)) {
25053
+ const textContent = this.extractStringContent(prismNode, source);
25054
+ return [{ type: "text", content: textContent }];
25055
+ }
25056
+ if (isPrismNodeType(prismNode, INTERPOLATED_STRING_NODE_TYPE)) {
25057
+ const parts = prismNode.parts;
25058
+ if (!parts || parts.length === 0)
25059
+ return null;
25060
+ const replacementParts = [];
25061
+ for (const part of parts) {
25062
+ if (isPrismNodeType(part, STRING_NODE_TYPE)) {
25063
+ const textContent = this.extractStringContent(part, source);
25064
+ if (textContent) {
25065
+ replacementParts.push({ type: "text", content: textContent });
25066
+ }
25067
+ }
25068
+ else if (isPrismNodeType(part, EMBEDDED_STATEMENTS_NODE_TYPE)) {
25069
+ const expression = this.extractExpressionSource(part, source);
25070
+ if (expression) {
25071
+ replacementParts.push({ type: "expression", expression });
25072
+ }
25073
+ }
25074
+ }
25075
+ return replacementParts.length > 0 ? replacementParts : null;
25076
+ }
25077
+ return null;
25078
+ }
25079
+ }
25080
+
24727
25081
  function serializeAttributeValue(value) {
24728
25082
  const hasERB = value.children.some(child => isERBContentNode(child));
24729
25083
  if (hasERB && value.children.length === 1 && isERBContentNode(value.children[0])) {
@@ -25317,12 +25671,12 @@ class IdentityPrinter extends Printer {
25317
25671
  this.visitChildNodes(node);
25318
25672
  }
25319
25673
  visitHTMLAttributeValueNode(node) {
25320
- if (node.quoted && node.open_quote) {
25321
- this.write(node.open_quote.value);
25674
+ if (node.quoted) {
25675
+ this.write(node.open_quote?.value ?? '"');
25322
25676
  }
25323
25677
  this.visitChildNodes(node);
25324
- if (node.quoted && node.close_quote) {
25325
- this.write(node.close_quote.value);
25678
+ if (node.quoted) {
25679
+ this.write(node.close_quote?.value ?? '"');
25326
25680
  }
25327
25681
  }
25328
25682
  visitRubyLiteralNode(node) {
@@ -25507,6 +25861,24 @@ class IdentityPrinter extends Printer {
25507
25861
  }
25508
25862
  visitERBRenderNode(node) {
25509
25863
  this.printERBNode(node);
25864
+ if (node.end_node) {
25865
+ if (node.body) {
25866
+ node.body.forEach(child => this.visit(child));
25867
+ }
25868
+ if (node.rescue_clause) {
25869
+ this.visit(node.rescue_clause);
25870
+ }
25871
+ if (node.else_clause) {
25872
+ this.visit(node.else_clause);
25873
+ }
25874
+ if (node.ensure_clause) {
25875
+ this.visit(node.ensure_clause);
25876
+ }
25877
+ this.visit(node.end_node);
25878
+ }
25879
+ }
25880
+ visitRubyRenderKeywordsNode(_node) {
25881
+ // no-op: extracted metadata, nothing to print
25510
25882
  }
25511
25883
  visitRubyRenderLocalNode(_node) {
25512
25884
  // extracted metadata, nothing to print
@@ -25514,7 +25886,7 @@ class IdentityPrinter extends Printer {
25514
25886
  visitERBStrictLocalsNode(node) {
25515
25887
  this.printERBNode(node);
25516
25888
  }
25517
- visitRubyStrictLocalNode(_node) {
25889
+ visitRubyParameterNode(_node) {
25518
25890
  // extracted metadata, nothing to print
25519
25891
  }
25520
25892
  visitERBYieldNode(node) {
@@ -26065,6 +26437,7 @@ class TailwindClassSorterRewriter extends ASTRewriter {
26065
26437
  */
26066
26438
  const builtinRewriters = [
26067
26439
  ActionViewTagHelperToHTMLRewriter,
26440
+ ERBStringToDirectOutputRewriter,
26068
26441
  HTMLToActionViewTagHelperRewriter,
26069
26442
  TailwindClassSorterRewriter
26070
26443
  ];
@@ -26113,5 +26486,5 @@ async function tailwindClassSorter(options = {}) {
26113
26486
  return rewriter;
26114
26487
  }
26115
26488
 
26116
- export { ASTRewriter, ActionViewTagHelperToHTMLRewriter, CustomRewriterLoader, HTMLToActionViewTagHelperRewriter, StringRewriter, TailwindClassSorterRewriter, asMutable, builtinRewriters, getBuiltinRewriter, getBuiltinRewriterNames, isASTRewriterClass, isRewriterClass, isStringRewriterClass, rewrite, rewriteString, tailwindClassSorter };
26489
+ export { ASTRewriter, ActionViewTagHelperToHTMLRewriter, CustomRewriterLoader, ERBStringToDirectOutputRewriter, HTMLToActionViewTagHelperRewriter, StringRewriter, TailwindClassSorterRewriter, asMutable, builtinRewriters, getBuiltinRewriter, getBuiltinRewriterNames, isASTRewriterClass, isRewriterClass, isStringRewriterClass, rewrite, rewriteString, tailwindClassSorter };
26117
26490
  //# sourceMappingURL=loader.esm.js.map