@herb-tools/rewriter 0.9.2 → 0.9.4
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.
- package/dist/index.cjs +808 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +808 -17
- package/dist/index.esm.js.map +1 -1
- package/dist/loader.cjs +809 -16
- package/dist/loader.cjs.map +1 -1
- package/dist/loader.esm.js +809 -17
- package/dist/loader.esm.js.map +1 -1
- package/dist/types/built-ins/action-view-tag-helper-to-html.d.ts +1 -1
- package/dist/types/built-ins/erb-string-to-direct-output.d.ts +21 -0
- package/dist/types/built-ins/index.d.ts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/rewriter-factories.d.ts +2 -0
- package/package.json +4 -4
- package/src/built-ins/action-view-tag-helper-to-html.ts +54 -10
- package/src/built-ins/erb-string-to-direct-output.ts +176 -0
- package/src/built-ins/html-to-action-view-tag-helper.ts +19 -4
- package/src/built-ins/index.ts +5 -0
- package/src/index.ts +2 -0
- package/src/rewriter-factories.ts +5 -0
package/dist/index.cjs
CHANGED
|
@@ -168,6 +168,9 @@ class Token {
|
|
|
168
168
|
static from(token) {
|
|
169
169
|
return new Token(token.value, Range.from(token.range), Location.from(token.location), token.type);
|
|
170
170
|
}
|
|
171
|
+
static synthetic(value, type = "SYNTETHIC") {
|
|
172
|
+
return new Token(value, Range.zero, Location.zero, type);
|
|
173
|
+
}
|
|
171
174
|
constructor(value, range, location, type) {
|
|
172
175
|
this.value = value;
|
|
173
176
|
this.range = range;
|
|
@@ -202,7 +205,7 @@ class Token {
|
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
// NOTE: This file is generated by the templates/template.rb script and should not
|
|
205
|
-
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.
|
|
208
|
+
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.4/templates/javascript/packages/core/src/errors.ts.erb
|
|
206
209
|
class HerbError {
|
|
207
210
|
type;
|
|
208
211
|
message;
|
|
@@ -1476,6 +1479,284 @@ class RenderLayoutWithoutBlockError extends HerbError {
|
|
|
1476
1479
|
return output;
|
|
1477
1480
|
}
|
|
1478
1481
|
}
|
|
1482
|
+
class StrictLocalsPositionalArgumentError extends HerbError {
|
|
1483
|
+
name;
|
|
1484
|
+
static from(data) {
|
|
1485
|
+
return new StrictLocalsPositionalArgumentError({
|
|
1486
|
+
type: data.type,
|
|
1487
|
+
message: data.message,
|
|
1488
|
+
location: Location.from(data.location),
|
|
1489
|
+
name: data.name,
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
constructor(props) {
|
|
1493
|
+
super(props.type, props.message, props.location);
|
|
1494
|
+
this.name = props.name;
|
|
1495
|
+
}
|
|
1496
|
+
toJSON() {
|
|
1497
|
+
return {
|
|
1498
|
+
...super.toJSON(),
|
|
1499
|
+
type: "STRICT_LOCALS_POSITIONAL_ARGUMENT_ERROR",
|
|
1500
|
+
name: this.name,
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
toMonacoDiagnostic() {
|
|
1504
|
+
return {
|
|
1505
|
+
line: this.location.start.line,
|
|
1506
|
+
column: this.location.start.column,
|
|
1507
|
+
endLine: this.location.end.line,
|
|
1508
|
+
endColumn: this.location.end.column,
|
|
1509
|
+
message: this.message,
|
|
1510
|
+
severity: 'error'
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
treeInspect() {
|
|
1514
|
+
let output = "";
|
|
1515
|
+
output += `@ StrictLocalsPositionalArgumentError ${this.location.treeInspectWithLabel()}\n`;
|
|
1516
|
+
output += `├── message: "${this.message}"\n`;
|
|
1517
|
+
output += `└── name: ${JSON.stringify(this.name)}\n`;
|
|
1518
|
+
return output;
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
class StrictLocalsBlockArgumentError extends HerbError {
|
|
1522
|
+
name;
|
|
1523
|
+
static from(data) {
|
|
1524
|
+
return new StrictLocalsBlockArgumentError({
|
|
1525
|
+
type: data.type,
|
|
1526
|
+
message: data.message,
|
|
1527
|
+
location: Location.from(data.location),
|
|
1528
|
+
name: data.name,
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
constructor(props) {
|
|
1532
|
+
super(props.type, props.message, props.location);
|
|
1533
|
+
this.name = props.name;
|
|
1534
|
+
}
|
|
1535
|
+
toJSON() {
|
|
1536
|
+
return {
|
|
1537
|
+
...super.toJSON(),
|
|
1538
|
+
type: "STRICT_LOCALS_BLOCK_ARGUMENT_ERROR",
|
|
1539
|
+
name: this.name,
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
toMonacoDiagnostic() {
|
|
1543
|
+
return {
|
|
1544
|
+
line: this.location.start.line,
|
|
1545
|
+
column: this.location.start.column,
|
|
1546
|
+
endLine: this.location.end.line,
|
|
1547
|
+
endColumn: this.location.end.column,
|
|
1548
|
+
message: this.message,
|
|
1549
|
+
severity: 'error'
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
treeInspect() {
|
|
1553
|
+
let output = "";
|
|
1554
|
+
output += `@ StrictLocalsBlockArgumentError ${this.location.treeInspectWithLabel()}\n`;
|
|
1555
|
+
output += `├── message: "${this.message}"\n`;
|
|
1556
|
+
output += `└── name: ${JSON.stringify(this.name)}\n`;
|
|
1557
|
+
return output;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
class StrictLocalsSplatArgumentError extends HerbError {
|
|
1561
|
+
name;
|
|
1562
|
+
static from(data) {
|
|
1563
|
+
return new StrictLocalsSplatArgumentError({
|
|
1564
|
+
type: data.type,
|
|
1565
|
+
message: data.message,
|
|
1566
|
+
location: Location.from(data.location),
|
|
1567
|
+
name: data.name,
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
constructor(props) {
|
|
1571
|
+
super(props.type, props.message, props.location);
|
|
1572
|
+
this.name = props.name;
|
|
1573
|
+
}
|
|
1574
|
+
toJSON() {
|
|
1575
|
+
return {
|
|
1576
|
+
...super.toJSON(),
|
|
1577
|
+
type: "STRICT_LOCALS_SPLAT_ARGUMENT_ERROR",
|
|
1578
|
+
name: this.name,
|
|
1579
|
+
};
|
|
1580
|
+
}
|
|
1581
|
+
toMonacoDiagnostic() {
|
|
1582
|
+
return {
|
|
1583
|
+
line: this.location.start.line,
|
|
1584
|
+
column: this.location.start.column,
|
|
1585
|
+
endLine: this.location.end.line,
|
|
1586
|
+
endColumn: this.location.end.column,
|
|
1587
|
+
message: this.message,
|
|
1588
|
+
severity: 'error'
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
treeInspect() {
|
|
1592
|
+
let output = "";
|
|
1593
|
+
output += `@ StrictLocalsSplatArgumentError ${this.location.treeInspectWithLabel()}\n`;
|
|
1594
|
+
output += `├── message: "${this.message}"\n`;
|
|
1595
|
+
output += `└── name: ${JSON.stringify(this.name)}\n`;
|
|
1596
|
+
return output;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
class StrictLocalsMissingParenthesisError extends HerbError {
|
|
1600
|
+
rest;
|
|
1601
|
+
static from(data) {
|
|
1602
|
+
return new StrictLocalsMissingParenthesisError({
|
|
1603
|
+
type: data.type,
|
|
1604
|
+
message: data.message,
|
|
1605
|
+
location: Location.from(data.location),
|
|
1606
|
+
rest: data.rest,
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
constructor(props) {
|
|
1610
|
+
super(props.type, props.message, props.location);
|
|
1611
|
+
this.rest = props.rest;
|
|
1612
|
+
}
|
|
1613
|
+
toJSON() {
|
|
1614
|
+
return {
|
|
1615
|
+
...super.toJSON(),
|
|
1616
|
+
type: "STRICT_LOCALS_MISSING_PARENTHESIS_ERROR",
|
|
1617
|
+
rest: this.rest,
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
toMonacoDiagnostic() {
|
|
1621
|
+
return {
|
|
1622
|
+
line: this.location.start.line,
|
|
1623
|
+
column: this.location.start.column,
|
|
1624
|
+
endLine: this.location.end.line,
|
|
1625
|
+
endColumn: this.location.end.column,
|
|
1626
|
+
message: this.message,
|
|
1627
|
+
severity: 'error'
|
|
1628
|
+
};
|
|
1629
|
+
}
|
|
1630
|
+
treeInspect() {
|
|
1631
|
+
let output = "";
|
|
1632
|
+
output += `@ StrictLocalsMissingParenthesisError ${this.location.treeInspectWithLabel()}\n`;
|
|
1633
|
+
output += `├── message: "${this.message}"\n`;
|
|
1634
|
+
output += `└── rest: ${JSON.stringify(this.rest)}\n`;
|
|
1635
|
+
return output;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
class StrictLocalsDuplicateDeclarationError extends HerbError {
|
|
1639
|
+
static from(data) {
|
|
1640
|
+
return new StrictLocalsDuplicateDeclarationError({
|
|
1641
|
+
type: data.type,
|
|
1642
|
+
message: data.message,
|
|
1643
|
+
location: Location.from(data.location),
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
constructor(props) {
|
|
1647
|
+
super(props.type, props.message, props.location);
|
|
1648
|
+
}
|
|
1649
|
+
toJSON() {
|
|
1650
|
+
return {
|
|
1651
|
+
...super.toJSON(),
|
|
1652
|
+
type: "STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR",
|
|
1653
|
+
};
|
|
1654
|
+
}
|
|
1655
|
+
toMonacoDiagnostic() {
|
|
1656
|
+
return {
|
|
1657
|
+
line: this.location.start.line,
|
|
1658
|
+
column: this.location.start.column,
|
|
1659
|
+
endLine: this.location.end.line,
|
|
1660
|
+
endColumn: this.location.end.column,
|
|
1661
|
+
message: this.message,
|
|
1662
|
+
severity: 'error'
|
|
1663
|
+
};
|
|
1664
|
+
}
|
|
1665
|
+
treeInspect() {
|
|
1666
|
+
let output = "";
|
|
1667
|
+
output += `@ StrictLocalsDuplicateDeclarationError ${this.location.treeInspectWithLabel()}\n`;
|
|
1668
|
+
output += `└── message: "${this.message}"\n`;
|
|
1669
|
+
return output;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
class VoidElementContentError extends HerbError {
|
|
1673
|
+
tag_name;
|
|
1674
|
+
helper_name;
|
|
1675
|
+
content_type;
|
|
1676
|
+
static from(data) {
|
|
1677
|
+
return new VoidElementContentError({
|
|
1678
|
+
type: data.type,
|
|
1679
|
+
message: data.message,
|
|
1680
|
+
location: Location.from(data.location),
|
|
1681
|
+
tag_name: data.tag_name ? Token.from(data.tag_name) : null,
|
|
1682
|
+
helper_name: data.helper_name,
|
|
1683
|
+
content_type: data.content_type,
|
|
1684
|
+
});
|
|
1685
|
+
}
|
|
1686
|
+
constructor(props) {
|
|
1687
|
+
super(props.type, props.message, props.location);
|
|
1688
|
+
this.tag_name = props.tag_name;
|
|
1689
|
+
this.helper_name = props.helper_name;
|
|
1690
|
+
this.content_type = props.content_type;
|
|
1691
|
+
}
|
|
1692
|
+
toJSON() {
|
|
1693
|
+
return {
|
|
1694
|
+
...super.toJSON(),
|
|
1695
|
+
type: "VOID_ELEMENT_CONTENT_ERROR",
|
|
1696
|
+
tag_name: this.tag_name ? this.tag_name.toJSON() : null,
|
|
1697
|
+
helper_name: this.helper_name,
|
|
1698
|
+
content_type: this.content_type,
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
toMonacoDiagnostic() {
|
|
1702
|
+
return {
|
|
1703
|
+
line: this.location.start.line,
|
|
1704
|
+
column: this.location.start.column,
|
|
1705
|
+
endLine: this.location.end.line,
|
|
1706
|
+
endColumn: this.location.end.column,
|
|
1707
|
+
message: this.message,
|
|
1708
|
+
severity: 'error'
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1711
|
+
treeInspect() {
|
|
1712
|
+
let output = "";
|
|
1713
|
+
output += `@ VoidElementContentError ${this.location.treeInspectWithLabel()}\n`;
|
|
1714
|
+
output += `├── message: "${this.message}"\n`;
|
|
1715
|
+
output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
|
|
1716
|
+
output += `├── helper_name: ${JSON.stringify(this.helper_name)}\n`;
|
|
1717
|
+
output += `└── content_type: ${JSON.stringify(this.content_type)}\n`;
|
|
1718
|
+
return output;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
class DotNotationCasingError extends HerbError {
|
|
1722
|
+
segment;
|
|
1723
|
+
static from(data) {
|
|
1724
|
+
return new DotNotationCasingError({
|
|
1725
|
+
type: data.type,
|
|
1726
|
+
message: data.message,
|
|
1727
|
+
location: Location.from(data.location),
|
|
1728
|
+
segment: data.segment ? Token.from(data.segment) : null,
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
constructor(props) {
|
|
1732
|
+
super(props.type, props.message, props.location);
|
|
1733
|
+
this.segment = props.segment;
|
|
1734
|
+
}
|
|
1735
|
+
toJSON() {
|
|
1736
|
+
return {
|
|
1737
|
+
...super.toJSON(),
|
|
1738
|
+
type: "DOT_NOTATION_CASING_ERROR",
|
|
1739
|
+
segment: this.segment ? this.segment.toJSON() : null,
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
toMonacoDiagnostic() {
|
|
1743
|
+
return {
|
|
1744
|
+
line: this.location.start.line,
|
|
1745
|
+
column: this.location.start.column,
|
|
1746
|
+
endLine: this.location.end.line,
|
|
1747
|
+
endColumn: this.location.end.column,
|
|
1748
|
+
message: this.message,
|
|
1749
|
+
severity: 'error'
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
treeInspect() {
|
|
1753
|
+
let output = "";
|
|
1754
|
+
output += `@ DotNotationCasingError ${this.location.treeInspectWithLabel()}\n`;
|
|
1755
|
+
output += `├── message: "${this.message}"\n`;
|
|
1756
|
+
output += `└── segment: ${this.segment ? this.segment.treeInspect() : "∅"}\n`;
|
|
1757
|
+
return output;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1479
1760
|
function fromSerializedError(error) {
|
|
1480
1761
|
switch (error.type) {
|
|
1481
1762
|
case "UNEXPECTED_ERROR": return UnexpectedError.from(error);
|
|
@@ -1508,6 +1789,13 @@ function fromSerializedError(error) {
|
|
|
1508
1789
|
case "RENDER_INVALID_AS_OPTION_ERROR": return RenderInvalidAsOptionError.from(error);
|
|
1509
1790
|
case "RENDER_OBJECT_AND_COLLECTION_ERROR": return RenderObjectAndCollectionError.from(error);
|
|
1510
1791
|
case "RENDER_LAYOUT_WITHOUT_BLOCK_ERROR": return RenderLayoutWithoutBlockError.from(error);
|
|
1792
|
+
case "STRICT_LOCALS_POSITIONAL_ARGUMENT_ERROR": return StrictLocalsPositionalArgumentError.from(error);
|
|
1793
|
+
case "STRICT_LOCALS_BLOCK_ARGUMENT_ERROR": return StrictLocalsBlockArgumentError.from(error);
|
|
1794
|
+
case "STRICT_LOCALS_SPLAT_ARGUMENT_ERROR": return StrictLocalsSplatArgumentError.from(error);
|
|
1795
|
+
case "STRICT_LOCALS_MISSING_PARENTHESIS_ERROR": return StrictLocalsMissingParenthesisError.from(error);
|
|
1796
|
+
case "STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR": return StrictLocalsDuplicateDeclarationError.from(error);
|
|
1797
|
+
case "VOID_ELEMENT_CONTENT_ERROR": return VoidElementContentError.from(error);
|
|
1798
|
+
case "DOT_NOTATION_CASING_ERROR": return DotNotationCasingError.from(error);
|
|
1511
1799
|
default:
|
|
1512
1800
|
throw new Error(`Unknown node type: ${error.type}`);
|
|
1513
1801
|
}
|
|
@@ -20096,7 +20384,7 @@ function deserializePrismNode(bytes, source) {
|
|
|
20096
20384
|
}
|
|
20097
20385
|
|
|
20098
20386
|
// NOTE: This file is generated by the templates/template.rb script and should not
|
|
20099
|
-
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.
|
|
20387
|
+
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.4/templates/javascript/packages/core/src/nodes.ts.erb
|
|
20100
20388
|
class Node {
|
|
20101
20389
|
type;
|
|
20102
20390
|
location;
|
|
@@ -21717,6 +22005,9 @@ class ERBBlockNode extends Node {
|
|
|
21717
22005
|
tag_closing;
|
|
21718
22006
|
prism_node;
|
|
21719
22007
|
body;
|
|
22008
|
+
rescue_clause;
|
|
22009
|
+
else_clause;
|
|
22010
|
+
ensure_clause;
|
|
21720
22011
|
end_node;
|
|
21721
22012
|
static get type() {
|
|
21722
22013
|
return "AST_ERB_BLOCK_NODE";
|
|
@@ -21731,6 +22022,9 @@ class ERBBlockNode extends Node {
|
|
|
21731
22022
|
tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
|
|
21732
22023
|
prism_node: data.prism_node ? new Uint8Array(data.prism_node) : null,
|
|
21733
22024
|
body: (data.body || []).map(node => fromSerializedNode(node)),
|
|
22025
|
+
rescue_clause: data.rescue_clause ? fromSerializedNode((data.rescue_clause)) : null,
|
|
22026
|
+
else_clause: data.else_clause ? fromSerializedNode((data.else_clause)) : null,
|
|
22027
|
+
ensure_clause: data.ensure_clause ? fromSerializedNode((data.ensure_clause)) : null,
|
|
21734
22028
|
end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
|
|
21735
22029
|
});
|
|
21736
22030
|
}
|
|
@@ -21741,6 +22035,9 @@ class ERBBlockNode extends Node {
|
|
|
21741
22035
|
this.tag_closing = props.tag_closing;
|
|
21742
22036
|
this.prism_node = props.prism_node;
|
|
21743
22037
|
this.body = props.body;
|
|
22038
|
+
this.rescue_clause = props.rescue_clause;
|
|
22039
|
+
this.else_clause = props.else_clause;
|
|
22040
|
+
this.ensure_clause = props.ensure_clause;
|
|
21744
22041
|
this.end_node = props.end_node;
|
|
21745
22042
|
}
|
|
21746
22043
|
accept(visitor) {
|
|
@@ -21749,6 +22046,9 @@ class ERBBlockNode extends Node {
|
|
|
21749
22046
|
childNodes() {
|
|
21750
22047
|
return [
|
|
21751
22048
|
...this.body,
|
|
22049
|
+
this.rescue_clause,
|
|
22050
|
+
this.else_clause,
|
|
22051
|
+
this.ensure_clause,
|
|
21752
22052
|
this.end_node,
|
|
21753
22053
|
];
|
|
21754
22054
|
}
|
|
@@ -21764,6 +22064,9 @@ class ERBBlockNode extends Node {
|
|
|
21764
22064
|
return [
|
|
21765
22065
|
...this.errors,
|
|
21766
22066
|
...this.body.map(node => node.recursiveErrors()),
|
|
22067
|
+
this.rescue_clause ? this.rescue_clause.recursiveErrors() : [],
|
|
22068
|
+
this.else_clause ? this.else_clause.recursiveErrors() : [],
|
|
22069
|
+
this.ensure_clause ? this.ensure_clause.recursiveErrors() : [],
|
|
21767
22070
|
this.end_node ? this.end_node.recursiveErrors() : [],
|
|
21768
22071
|
].flat();
|
|
21769
22072
|
}
|
|
@@ -21776,6 +22079,9 @@ class ERBBlockNode extends Node {
|
|
|
21776
22079
|
tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
|
|
21777
22080
|
prism_node: this.prism_node ? Array.from(this.prism_node) : null,
|
|
21778
22081
|
body: this.body.map(node => node.toJSON()),
|
|
22082
|
+
rescue_clause: this.rescue_clause ? this.rescue_clause.toJSON() : null,
|
|
22083
|
+
else_clause: this.else_clause ? this.else_clause.toJSON() : null,
|
|
22084
|
+
ensure_clause: this.ensure_clause ? this.ensure_clause.toJSON() : null,
|
|
21779
22085
|
end_node: this.end_node ? this.end_node.toJSON() : null,
|
|
21780
22086
|
};
|
|
21781
22087
|
}
|
|
@@ -21790,6 +22096,9 @@ class ERBBlockNode extends Node {
|
|
|
21790
22096
|
output += `├── prism_node: ${this.source ? inspectPrismSerialized(this.prism_node, this.source, "│ ") : `(${this.prism_node.length} bytes)`}\n`;
|
|
21791
22097
|
}
|
|
21792
22098
|
output += `├── body: ${this.inspectArray(this.body, "│ ")}`;
|
|
22099
|
+
output += `├── rescue_clause: ${this.inspectNode(this.rescue_clause, "│ ")}`;
|
|
22100
|
+
output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
|
|
22101
|
+
output += `├── ensure_clause: ${this.inspectNode(this.ensure_clause, "│ ")}`;
|
|
21793
22102
|
output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
|
|
21794
22103
|
return output;
|
|
21795
22104
|
}
|
|
@@ -22859,6 +23168,150 @@ class ERBRenderNode extends Node {
|
|
|
22859
23168
|
return output;
|
|
22860
23169
|
}
|
|
22861
23170
|
}
|
|
23171
|
+
class RubyStrictLocalNode extends Node {
|
|
23172
|
+
name;
|
|
23173
|
+
default_value;
|
|
23174
|
+
required;
|
|
23175
|
+
double_splat;
|
|
23176
|
+
static get type() {
|
|
23177
|
+
return "AST_RUBY_STRICT_LOCAL_NODE";
|
|
23178
|
+
}
|
|
23179
|
+
static from(data) {
|
|
23180
|
+
return new RubyStrictLocalNode({
|
|
23181
|
+
type: data.type,
|
|
23182
|
+
location: Location.from(data.location),
|
|
23183
|
+
errors: (data.errors || []).map(error => HerbError.from(error)),
|
|
23184
|
+
name: data.name ? Token.from(data.name) : null,
|
|
23185
|
+
default_value: data.default_value ? fromSerializedNode((data.default_value)) : null,
|
|
23186
|
+
required: data.required,
|
|
23187
|
+
double_splat: data.double_splat,
|
|
23188
|
+
});
|
|
23189
|
+
}
|
|
23190
|
+
constructor(props) {
|
|
23191
|
+
super(props.type, props.location, props.errors);
|
|
23192
|
+
this.name = props.name;
|
|
23193
|
+
this.default_value = props.default_value;
|
|
23194
|
+
this.required = props.required;
|
|
23195
|
+
this.double_splat = props.double_splat;
|
|
23196
|
+
}
|
|
23197
|
+
accept(visitor) {
|
|
23198
|
+
visitor.visitRubyStrictLocalNode(this);
|
|
23199
|
+
}
|
|
23200
|
+
childNodes() {
|
|
23201
|
+
return [
|
|
23202
|
+
this.default_value,
|
|
23203
|
+
];
|
|
23204
|
+
}
|
|
23205
|
+
compactChildNodes() {
|
|
23206
|
+
return this.childNodes().filter(node => node !== null && node !== undefined);
|
|
23207
|
+
}
|
|
23208
|
+
recursiveErrors() {
|
|
23209
|
+
return [
|
|
23210
|
+
...this.errors,
|
|
23211
|
+
this.default_value ? this.default_value.recursiveErrors() : [],
|
|
23212
|
+
].flat();
|
|
23213
|
+
}
|
|
23214
|
+
toJSON() {
|
|
23215
|
+
return {
|
|
23216
|
+
...super.toJSON(),
|
|
23217
|
+
type: "AST_RUBY_STRICT_LOCAL_NODE",
|
|
23218
|
+
name: this.name ? this.name.toJSON() : null,
|
|
23219
|
+
default_value: this.default_value ? this.default_value.toJSON() : null,
|
|
23220
|
+
required: this.required,
|
|
23221
|
+
double_splat: this.double_splat,
|
|
23222
|
+
};
|
|
23223
|
+
}
|
|
23224
|
+
treeInspect() {
|
|
23225
|
+
let output = "";
|
|
23226
|
+
output += `@ RubyStrictLocalNode ${this.location.treeInspectWithLabel()}\n`;
|
|
23227
|
+
output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
|
|
23228
|
+
output += `├── name: ${this.name ? this.name.treeInspect() : "∅"}\n`;
|
|
23229
|
+
output += `├── default_value: ${this.inspectNode(this.default_value, "│ ")}`;
|
|
23230
|
+
output += `├── required: ${typeof this.required === 'boolean' ? String(this.required) : "∅"}\n`;
|
|
23231
|
+
output += `└── double_splat: ${typeof this.double_splat === 'boolean' ? String(this.double_splat) : "∅"}\n`;
|
|
23232
|
+
return output;
|
|
23233
|
+
}
|
|
23234
|
+
}
|
|
23235
|
+
class ERBStrictLocalsNode extends Node {
|
|
23236
|
+
tag_opening;
|
|
23237
|
+
content;
|
|
23238
|
+
tag_closing;
|
|
23239
|
+
// no-op for analyzed_ruby
|
|
23240
|
+
prism_node;
|
|
23241
|
+
locals;
|
|
23242
|
+
static get type() {
|
|
23243
|
+
return "AST_ERB_STRICT_LOCALS_NODE";
|
|
23244
|
+
}
|
|
23245
|
+
static from(data) {
|
|
23246
|
+
return new ERBStrictLocalsNode({
|
|
23247
|
+
type: data.type,
|
|
23248
|
+
location: Location.from(data.location),
|
|
23249
|
+
errors: (data.errors || []).map(error => HerbError.from(error)),
|
|
23250
|
+
tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
|
|
23251
|
+
content: data.content ? Token.from(data.content) : null,
|
|
23252
|
+
tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
|
|
23253
|
+
// no-op for analyzed_ruby
|
|
23254
|
+
prism_node: data.prism_node ? new Uint8Array(data.prism_node) : null,
|
|
23255
|
+
locals: (data.locals || []).map(node => fromSerializedNode(node)),
|
|
23256
|
+
});
|
|
23257
|
+
}
|
|
23258
|
+
constructor(props) {
|
|
23259
|
+
super(props.type, props.location, props.errors);
|
|
23260
|
+
this.tag_opening = props.tag_opening;
|
|
23261
|
+
this.content = props.content;
|
|
23262
|
+
this.tag_closing = props.tag_closing;
|
|
23263
|
+
// no-op for analyzed_ruby
|
|
23264
|
+
this.prism_node = props.prism_node;
|
|
23265
|
+
this.locals = props.locals;
|
|
23266
|
+
}
|
|
23267
|
+
accept(visitor) {
|
|
23268
|
+
visitor.visitERBStrictLocalsNode(this);
|
|
23269
|
+
}
|
|
23270
|
+
childNodes() {
|
|
23271
|
+
return [
|
|
23272
|
+
...this.locals,
|
|
23273
|
+
];
|
|
23274
|
+
}
|
|
23275
|
+
compactChildNodes() {
|
|
23276
|
+
return this.childNodes().filter(node => node !== null && node !== undefined);
|
|
23277
|
+
}
|
|
23278
|
+
get prismNode() {
|
|
23279
|
+
if (!this.prism_node || !this.source)
|
|
23280
|
+
return null;
|
|
23281
|
+
return deserializePrismNode(this.prism_node, this.source);
|
|
23282
|
+
}
|
|
23283
|
+
recursiveErrors() {
|
|
23284
|
+
return [
|
|
23285
|
+
...this.errors,
|
|
23286
|
+
...this.locals.map(node => node.recursiveErrors()),
|
|
23287
|
+
].flat();
|
|
23288
|
+
}
|
|
23289
|
+
toJSON() {
|
|
23290
|
+
return {
|
|
23291
|
+
...super.toJSON(),
|
|
23292
|
+
type: "AST_ERB_STRICT_LOCALS_NODE",
|
|
23293
|
+
tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
|
|
23294
|
+
content: this.content ? this.content.toJSON() : null,
|
|
23295
|
+
tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
|
|
23296
|
+
// no-op for analyzed_ruby
|
|
23297
|
+
prism_node: this.prism_node ? Array.from(this.prism_node) : null,
|
|
23298
|
+
locals: this.locals.map(node => node.toJSON()),
|
|
23299
|
+
};
|
|
23300
|
+
}
|
|
23301
|
+
treeInspect() {
|
|
23302
|
+
let output = "";
|
|
23303
|
+
output += `@ ERBStrictLocalsNode ${this.location.treeInspectWithLabel()}\n`;
|
|
23304
|
+
output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
|
|
23305
|
+
output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
|
|
23306
|
+
output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
|
|
23307
|
+
output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
|
|
23308
|
+
if (this.prism_node) {
|
|
23309
|
+
output += `├── prism_node: ${this.source ? inspectPrismSerialized(this.prism_node, this.source, "│ ") : `(${this.prism_node.length} bytes)`}\n`;
|
|
23310
|
+
}
|
|
23311
|
+
output += `└── locals: ${this.inspectArray(this.locals, " ")}`;
|
|
23312
|
+
return output;
|
|
23313
|
+
}
|
|
23314
|
+
}
|
|
22862
23315
|
class ERBYieldNode extends Node {
|
|
22863
23316
|
tag_opening;
|
|
22864
23317
|
content;
|
|
@@ -23024,6 +23477,8 @@ function fromSerializedNode(node) {
|
|
|
23024
23477
|
case "AST_ERB_UNLESS_NODE": return ERBUnlessNode.from(node);
|
|
23025
23478
|
case "AST_RUBY_RENDER_LOCAL_NODE": return RubyRenderLocalNode.from(node);
|
|
23026
23479
|
case "AST_ERB_RENDER_NODE": return ERBRenderNode.from(node);
|
|
23480
|
+
case "AST_RUBY_STRICT_LOCAL_NODE": return RubyStrictLocalNode.from(node);
|
|
23481
|
+
case "AST_ERB_STRICT_LOCALS_NODE": return ERBStrictLocalsNode.from(node);
|
|
23027
23482
|
case "AST_ERB_YIELD_NODE": return ERBYieldNode.from(node);
|
|
23028
23483
|
case "AST_ERB_IN_NODE": return ERBInNode.from(node);
|
|
23029
23484
|
default:
|
|
@@ -23074,9 +23529,12 @@ const DEFAULT_PARSER_OPTIONS = {
|
|
|
23074
23529
|
strict: true,
|
|
23075
23530
|
action_view_helpers: false,
|
|
23076
23531
|
render_nodes: false,
|
|
23532
|
+
strict_locals: false,
|
|
23077
23533
|
prism_nodes: false,
|
|
23078
23534
|
prism_nodes_deep: false,
|
|
23079
23535
|
prism_program: false,
|
|
23536
|
+
dot_notation_tags: false,
|
|
23537
|
+
html: true,
|
|
23080
23538
|
};
|
|
23081
23539
|
/**
|
|
23082
23540
|
* Represents the parser options used during parsing.
|
|
@@ -23092,12 +23550,18 @@ class ParserOptions {
|
|
|
23092
23550
|
action_view_helpers;
|
|
23093
23551
|
/** Whether ActionView render call detection was enabled during parsing. */
|
|
23094
23552
|
render_nodes;
|
|
23553
|
+
/** Whether strict locals analysis was enabled during parsing. */
|
|
23554
|
+
strict_locals;
|
|
23095
23555
|
/** Whether Prism node serialization was enabled during parsing. */
|
|
23096
23556
|
prism_nodes;
|
|
23097
23557
|
/** Whether deep Prism node serialization was enabled during parsing. */
|
|
23098
23558
|
prism_nodes_deep;
|
|
23099
23559
|
/** Whether the full Prism ProgramNode was serialized on the DocumentNode. */
|
|
23100
23560
|
prism_program;
|
|
23561
|
+
/** Whether dot-notation component tags (e.g. Dialog.Button) are parsed as HTML elements. */
|
|
23562
|
+
dot_notation_tags;
|
|
23563
|
+
/** Whether HTML tag parsing is enabled during parsing. When false, HTML-like content is treated as literal text. */
|
|
23564
|
+
html;
|
|
23101
23565
|
static from(options) {
|
|
23102
23566
|
return new ParserOptions(options);
|
|
23103
23567
|
}
|
|
@@ -23107,9 +23571,12 @@ class ParserOptions {
|
|
|
23107
23571
|
this.analyze = options.analyze ?? DEFAULT_PARSER_OPTIONS.analyze;
|
|
23108
23572
|
this.action_view_helpers = options.action_view_helpers ?? DEFAULT_PARSER_OPTIONS.action_view_helpers;
|
|
23109
23573
|
this.render_nodes = options.render_nodes ?? DEFAULT_PARSER_OPTIONS.render_nodes;
|
|
23574
|
+
this.strict_locals = options.strict_locals ?? DEFAULT_PARSER_OPTIONS.strict_locals;
|
|
23110
23575
|
this.prism_nodes = options.prism_nodes ?? DEFAULT_PARSER_OPTIONS.prism_nodes;
|
|
23111
23576
|
this.prism_nodes_deep = options.prism_nodes_deep ?? DEFAULT_PARSER_OPTIONS.prism_nodes_deep;
|
|
23112
23577
|
this.prism_program = options.prism_program ?? DEFAULT_PARSER_OPTIONS.prism_program;
|
|
23578
|
+
this.dot_notation_tags = options.dot_notation_tags ?? DEFAULT_PARSER_OPTIONS.dot_notation_tags;
|
|
23579
|
+
this.html = options.html ?? DEFAULT_PARSER_OPTIONS.html;
|
|
23113
23580
|
}
|
|
23114
23581
|
}
|
|
23115
23582
|
|
|
@@ -23186,7 +23653,7 @@ class ParseResult extends Result {
|
|
|
23186
23653
|
}
|
|
23187
23654
|
|
|
23188
23655
|
// NOTE: This file is generated by the templates/template.rb script and should not
|
|
23189
|
-
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.
|
|
23656
|
+
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.4/templates/javascript/packages/core/src/node-type-guards.ts.erb
|
|
23190
23657
|
/**
|
|
23191
23658
|
* Type guard functions for AST nodes.
|
|
23192
23659
|
* These functions provide type checking by combining both instanceof
|
|
@@ -23497,6 +23964,22 @@ function isERBRenderNode(node) {
|
|
|
23497
23964
|
return false;
|
|
23498
23965
|
return node instanceof ERBRenderNode || node.type === "AST_ERB_RENDER_NODE" || node.constructor.type === "AST_ERB_RENDER_NODE";
|
|
23499
23966
|
}
|
|
23967
|
+
/**
|
|
23968
|
+
* Checks if a node is a RubyStrictLocalNode
|
|
23969
|
+
*/
|
|
23970
|
+
function isRubyStrictLocalNode(node) {
|
|
23971
|
+
if (!node)
|
|
23972
|
+
return false;
|
|
23973
|
+
return node instanceof RubyStrictLocalNode || node.type === "AST_RUBY_STRICT_LOCAL_NODE" || node.constructor.type === "AST_RUBY_STRICT_LOCAL_NODE";
|
|
23974
|
+
}
|
|
23975
|
+
/**
|
|
23976
|
+
* Checks if a node is a ERBStrictLocalsNode
|
|
23977
|
+
*/
|
|
23978
|
+
function isERBStrictLocalsNode(node) {
|
|
23979
|
+
if (!node)
|
|
23980
|
+
return false;
|
|
23981
|
+
return node instanceof ERBStrictLocalsNode || node.type === "AST_ERB_STRICT_LOCALS_NODE" || node.constructor.type === "AST_ERB_STRICT_LOCALS_NODE";
|
|
23982
|
+
}
|
|
23500
23983
|
/**
|
|
23501
23984
|
* Checks if a node is a ERBYieldNode
|
|
23502
23985
|
*/
|
|
@@ -23513,6 +23996,31 @@ function isERBInNode(node) {
|
|
|
23513
23996
|
return false;
|
|
23514
23997
|
return node instanceof ERBInNode || node.type === "AST_ERB_IN_NODE" || node.constructor.type === "AST_ERB_IN_NODE";
|
|
23515
23998
|
}
|
|
23999
|
+
/**
|
|
24000
|
+
* Checks if a node is any ERB node type
|
|
24001
|
+
*/
|
|
24002
|
+
function isERBNode(node) {
|
|
24003
|
+
return isERBOpenTagNode(node) ||
|
|
24004
|
+
isERBContentNode(node) ||
|
|
24005
|
+
isERBEndNode(node) ||
|
|
24006
|
+
isERBElseNode(node) ||
|
|
24007
|
+
isERBIfNode(node) ||
|
|
24008
|
+
isERBBlockNode(node) ||
|
|
24009
|
+
isERBWhenNode(node) ||
|
|
24010
|
+
isERBCaseNode(node) ||
|
|
24011
|
+
isERBCaseMatchNode(node) ||
|
|
24012
|
+
isERBWhileNode(node) ||
|
|
24013
|
+
isERBUntilNode(node) ||
|
|
24014
|
+
isERBForNode(node) ||
|
|
24015
|
+
isERBRescueNode(node) ||
|
|
24016
|
+
isERBEnsureNode(node) ||
|
|
24017
|
+
isERBBeginNode(node) ||
|
|
24018
|
+
isERBUnlessNode(node) ||
|
|
24019
|
+
isERBRenderNode(node) ||
|
|
24020
|
+
isERBStrictLocalsNode(node) ||
|
|
24021
|
+
isERBYieldNode(node) ||
|
|
24022
|
+
isERBInNode(node);
|
|
24023
|
+
}
|
|
23516
24024
|
/**
|
|
23517
24025
|
* Map of node classes to their corresponding type guard functions
|
|
23518
24026
|
*
|
|
@@ -23562,6 +24070,8 @@ const NODE_TYPE_GUARDS = new Map([
|
|
|
23562
24070
|
[ERBUnlessNode, isERBUnlessNode],
|
|
23563
24071
|
[RubyRenderLocalNode, isRubyRenderLocalNode],
|
|
23564
24072
|
[ERBRenderNode, isERBRenderNode],
|
|
24073
|
+
[RubyStrictLocalNode, isRubyStrictLocalNode],
|
|
24074
|
+
[ERBStrictLocalsNode, isERBStrictLocalsNode],
|
|
23565
24075
|
[ERBYieldNode, isERBYieldNode],
|
|
23566
24076
|
[ERBInNode, isERBInNode],
|
|
23567
24077
|
]);
|
|
@@ -23614,6 +24124,8 @@ const AST_TYPE_GUARDS = new Map([
|
|
|
23614
24124
|
["AST_ERB_UNLESS_NODE", isERBUnlessNode],
|
|
23615
24125
|
["AST_RUBY_RENDER_LOCAL_NODE", isRubyRenderLocalNode],
|
|
23616
24126
|
["AST_ERB_RENDER_NODE", isERBRenderNode],
|
|
24127
|
+
["AST_RUBY_STRICT_LOCAL_NODE", isRubyStrictLocalNode],
|
|
24128
|
+
["AST_ERB_STRICT_LOCALS_NODE", isERBStrictLocalsNode],
|
|
23617
24129
|
["AST_ERB_YIELD_NODE", isERBYieldNode],
|
|
23618
24130
|
["AST_ERB_IN_NODE", isERBInNode],
|
|
23619
24131
|
]);
|
|
@@ -23671,6 +24183,17 @@ function isToken(object) {
|
|
|
23671
24183
|
function isParseResult(object) {
|
|
23672
24184
|
return (object instanceof ParseResult) || (object?.constructor?.name === "ParseResult" && "value" in object);
|
|
23673
24185
|
}
|
|
24186
|
+
|
|
24187
|
+
/**
|
|
24188
|
+
* Checks if a node is an ERB output node (generates content: <%= %> or <%== %>)
|
|
24189
|
+
*/
|
|
24190
|
+
function isERBOutputNode(node) {
|
|
24191
|
+
if (!isERBNode(node))
|
|
24192
|
+
return false;
|
|
24193
|
+
if (!node.tag_opening?.value)
|
|
24194
|
+
return false;
|
|
24195
|
+
return ["<%=", "<%=="].includes(node.tag_opening?.value);
|
|
24196
|
+
}
|
|
23674
24197
|
/**
|
|
23675
24198
|
* Extracts a static string from an array of literal nodes
|
|
23676
24199
|
* Returns null if any node is not a literal node
|
|
@@ -23730,12 +24253,88 @@ function getNodesBeforePosition(nodes, position, inclusive = false) {
|
|
|
23730
24253
|
function getNodesAfterPosition(nodes, position, inclusive = true) {
|
|
23731
24254
|
return nodes.filter(node => node.location && isPositionAfter(node.location.start, position, inclusive));
|
|
23732
24255
|
}
|
|
24256
|
+
// --- AST Mutation Utilities ---
|
|
24257
|
+
const CHILD_ARRAY_PROPS = ["children", "body", "statements", "conditions"];
|
|
24258
|
+
const LINKED_NODE_PROPS = ["subsequent", "else_clause"];
|
|
24259
|
+
/**
|
|
24260
|
+
* Finds the array containing a target node in the AST, along with its index.
|
|
24261
|
+
* Traverses child arrays and linked node properties (e.g., `subsequent`, `else_clause`).
|
|
24262
|
+
*
|
|
24263
|
+
* Useful for autofix operations that need to splice nodes in/out of their parent array.
|
|
24264
|
+
*
|
|
24265
|
+
* @param root - The root node to search from
|
|
24266
|
+
* @param target - The node to find
|
|
24267
|
+
* @returns The containing array and the target's index, or null if not found
|
|
24268
|
+
*/
|
|
24269
|
+
function findParentArray(root, target) {
|
|
24270
|
+
const search = (node) => {
|
|
24271
|
+
const record = node;
|
|
24272
|
+
for (const prop of CHILD_ARRAY_PROPS) {
|
|
24273
|
+
const array = record[prop];
|
|
24274
|
+
if (Array.isArray(array)) {
|
|
24275
|
+
const index = array.indexOf(target);
|
|
24276
|
+
if (index !== -1) {
|
|
24277
|
+
return { array, index };
|
|
24278
|
+
}
|
|
24279
|
+
}
|
|
24280
|
+
}
|
|
24281
|
+
for (const prop of CHILD_ARRAY_PROPS) {
|
|
24282
|
+
const array = record[prop];
|
|
24283
|
+
if (Array.isArray(array)) {
|
|
24284
|
+
for (const child of array) {
|
|
24285
|
+
if (child && typeof child === 'object' && 'type' in child) {
|
|
24286
|
+
const result = search(child);
|
|
24287
|
+
if (result) {
|
|
24288
|
+
return result;
|
|
24289
|
+
}
|
|
24290
|
+
}
|
|
24291
|
+
}
|
|
24292
|
+
}
|
|
24293
|
+
}
|
|
24294
|
+
for (const prop of LINKED_NODE_PROPS) {
|
|
24295
|
+
const value = record[prop];
|
|
24296
|
+
if (value && typeof value === 'object' && 'type' in value) {
|
|
24297
|
+
const result = search(value);
|
|
24298
|
+
if (result) {
|
|
24299
|
+
return result;
|
|
24300
|
+
}
|
|
24301
|
+
}
|
|
24302
|
+
}
|
|
24303
|
+
return null;
|
|
24304
|
+
};
|
|
24305
|
+
return search(root);
|
|
24306
|
+
}
|
|
24307
|
+
/**
|
|
24308
|
+
* Creates a synthetic LiteralNode with the given content and zero location.
|
|
24309
|
+
* Useful for inserting whitespace or newlines during AST mutations.
|
|
24310
|
+
*/
|
|
24311
|
+
function createLiteral(content) {
|
|
24312
|
+
return new LiteralNode({
|
|
24313
|
+
type: "AST_LITERAL_NODE",
|
|
24314
|
+
content,
|
|
24315
|
+
location: Location.zero,
|
|
24316
|
+
errors: [],
|
|
24317
|
+
});
|
|
24318
|
+
}
|
|
23733
24319
|
function createSyntheticToken(value, type = "TOKEN_SYNTHETIC") {
|
|
23734
24320
|
return new Token(value, Range.zero, Location.zero, type);
|
|
23735
24321
|
}
|
|
24322
|
+
function createERBOutputNode(expression, tagOpening = "<%=", tagClosing = "%>") {
|
|
24323
|
+
return new ERBContentNode({
|
|
24324
|
+
type: "AST_ERB_CONTENT_NODE",
|
|
24325
|
+
tag_opening: createSyntheticToken(tagOpening),
|
|
24326
|
+
content: createSyntheticToken(expression),
|
|
24327
|
+
tag_closing: createSyntheticToken(tagClosing),
|
|
24328
|
+
parsed: false,
|
|
24329
|
+
valid: true,
|
|
24330
|
+
prism_node: null,
|
|
24331
|
+
location: Location.zero,
|
|
24332
|
+
errors: [],
|
|
24333
|
+
});
|
|
24334
|
+
}
|
|
23736
24335
|
|
|
23737
24336
|
// NOTE: This file is generated by the templates/template.rb script and should not
|
|
23738
|
-
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.
|
|
24337
|
+
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.4/templates/javascript/packages/core/src/visitor.ts.erb
|
|
23739
24338
|
class Visitor {
|
|
23740
24339
|
visit(node) {
|
|
23741
24340
|
if (!node)
|
|
@@ -23923,6 +24522,15 @@ class Visitor {
|
|
|
23923
24522
|
this.visitERBNode(node);
|
|
23924
24523
|
this.visitChildNodes(node);
|
|
23925
24524
|
}
|
|
24525
|
+
visitRubyStrictLocalNode(node) {
|
|
24526
|
+
this.visitNode(node);
|
|
24527
|
+
this.visitChildNodes(node);
|
|
24528
|
+
}
|
|
24529
|
+
visitERBStrictLocalsNode(node) {
|
|
24530
|
+
this.visitNode(node);
|
|
24531
|
+
this.visitERBNode(node);
|
|
24532
|
+
this.visitChildNodes(node);
|
|
24533
|
+
}
|
|
23926
24534
|
visitERBYieldNode(node) {
|
|
23927
24535
|
this.visitNode(node);
|
|
23928
24536
|
this.visitERBNode(node);
|
|
@@ -23955,6 +24563,34 @@ function createWhitespaceNode() {
|
|
|
23955
24563
|
});
|
|
23956
24564
|
}
|
|
23957
24565
|
class ActionViewTagHelperToHTMLVisitor extends Visitor {
|
|
24566
|
+
shallow;
|
|
24567
|
+
includeBody;
|
|
24568
|
+
constructor(options = {}) {
|
|
24569
|
+
super();
|
|
24570
|
+
this.shallow = options.shallow ?? false;
|
|
24571
|
+
this.includeBody = options.includeBody ?? true;
|
|
24572
|
+
}
|
|
24573
|
+
visitHTMLOpenTagNode(node) {
|
|
24574
|
+
const newChildren = [];
|
|
24575
|
+
for (let index = 0; index < node.children.length; index++) {
|
|
24576
|
+
const child = node.children[index];
|
|
24577
|
+
if (isHTMLAttributeNode(child)) {
|
|
24578
|
+
if (child.equals && child.equals.value !== "=") {
|
|
24579
|
+
asMutable(child).equals = createSyntheticToken("=");
|
|
24580
|
+
}
|
|
24581
|
+
if (child.value) {
|
|
24582
|
+
this.transformAttributeValue(child.value);
|
|
24583
|
+
}
|
|
24584
|
+
const previous = index > 0 ? node.children[index - 1] : null;
|
|
24585
|
+
if (!previous || !isWhitespaceNode(previous)) {
|
|
24586
|
+
newChildren.push(createWhitespaceNode());
|
|
24587
|
+
}
|
|
24588
|
+
}
|
|
24589
|
+
newChildren.push(child);
|
|
24590
|
+
}
|
|
24591
|
+
asMutable(node).children = newChildren;
|
|
24592
|
+
this.visitChildNodes(node);
|
|
24593
|
+
}
|
|
23958
24594
|
visitHTMLElementNode(node) {
|
|
23959
24595
|
if (!node.element_source) {
|
|
23960
24596
|
this.visitChildNodes(node);
|
|
@@ -24025,7 +24661,10 @@ class ActionViewTagHelperToHTMLVisitor extends Visitor {
|
|
|
24025
24661
|
asMutable(node).close_tag = htmlCloseTag;
|
|
24026
24662
|
}
|
|
24027
24663
|
asMutable(node).element_source = "HTML";
|
|
24028
|
-
if (
|
|
24664
|
+
if (!this.includeBody) {
|
|
24665
|
+
asMutable(node).body = [];
|
|
24666
|
+
}
|
|
24667
|
+
else if (node.body) {
|
|
24029
24668
|
asMutable(node).body = node.body.map(child => {
|
|
24030
24669
|
if (isRubyLiteralNode(child)) {
|
|
24031
24670
|
return new ERBContentNode({
|
|
@@ -24040,7 +24679,9 @@ class ActionViewTagHelperToHTMLVisitor extends Visitor {
|
|
|
24040
24679
|
prism_node: null
|
|
24041
24680
|
});
|
|
24042
24681
|
}
|
|
24043
|
-
this.
|
|
24682
|
+
if (!this.shallow) {
|
|
24683
|
+
this.visit(child);
|
|
24684
|
+
}
|
|
24044
24685
|
return child;
|
|
24045
24686
|
});
|
|
24046
24687
|
}
|
|
@@ -24066,11 +24707,11 @@ class ActionViewTagHelperToHTMLVisitor extends Visitor {
|
|
|
24066
24707
|
return child;
|
|
24067
24708
|
});
|
|
24068
24709
|
mutableValue.children = newChildren;
|
|
24069
|
-
|
|
24070
|
-
|
|
24071
|
-
|
|
24072
|
-
|
|
24073
|
-
|
|
24710
|
+
}
|
|
24711
|
+
if (!value.quoted) {
|
|
24712
|
+
mutableValue.quoted = true;
|
|
24713
|
+
mutableValue.open_quote = createSyntheticToken('"');
|
|
24714
|
+
mutableValue.close_quote = createSyntheticToken('"');
|
|
24074
24715
|
}
|
|
24075
24716
|
}
|
|
24076
24717
|
}
|
|
@@ -24081,11 +24722,132 @@ class ActionViewTagHelperToHTMLRewriter extends ASTRewriter {
|
|
|
24081
24722
|
get description() {
|
|
24082
24723
|
return "Converts ActionView tag helpers to raw HTML elements";
|
|
24083
24724
|
}
|
|
24725
|
+
rewrite(node, context) {
|
|
24726
|
+
const visitor = new ActionViewTagHelperToHTMLVisitor({ shallow: context.shallow, includeBody: context.includeBody });
|
|
24727
|
+
visitor.visit(node);
|
|
24728
|
+
return node;
|
|
24729
|
+
}
|
|
24730
|
+
}
|
|
24731
|
+
|
|
24732
|
+
const STRING_NODE_TYPE = "StringNode";
|
|
24733
|
+
const INTERPOLATED_STRING_NODE_TYPE = "InterpolatedStringNode";
|
|
24734
|
+
const EMBEDDED_STATEMENTS_NODE_TYPE = "EmbeddedStatementsNode";
|
|
24735
|
+
class ERBStringToDirectOutputVisitor extends Visitor {
|
|
24736
|
+
root;
|
|
24737
|
+
constructor(root) {
|
|
24738
|
+
super();
|
|
24739
|
+
this.root = root;
|
|
24740
|
+
}
|
|
24741
|
+
visitERBContentNode(node) {
|
|
24742
|
+
if (!isERBOutputNode(node)) {
|
|
24743
|
+
this.visitChildNodes(node);
|
|
24744
|
+
return;
|
|
24745
|
+
}
|
|
24746
|
+
const prismNode = node.prismNode;
|
|
24747
|
+
if (!prismNode) {
|
|
24748
|
+
this.visitChildNodes(node);
|
|
24749
|
+
return;
|
|
24750
|
+
}
|
|
24751
|
+
const source = node.source;
|
|
24752
|
+
if (!source) {
|
|
24753
|
+
this.visitChildNodes(node);
|
|
24754
|
+
return;
|
|
24755
|
+
}
|
|
24756
|
+
if (!ERBStringToDirectOutputRewriter.isStringOutputNode(prismNode)) {
|
|
24757
|
+
this.visitChildNodes(node);
|
|
24758
|
+
return;
|
|
24759
|
+
}
|
|
24760
|
+
const replacementParts = ERBStringToDirectOutputRewriter.extractReplacementParts(prismNode, source);
|
|
24761
|
+
if (!replacementParts) {
|
|
24762
|
+
this.visitChildNodes(node);
|
|
24763
|
+
return;
|
|
24764
|
+
}
|
|
24765
|
+
const tagOpening = node.tag_opening?.value ?? "<%=";
|
|
24766
|
+
const tagClosing = node.tag_closing?.value ?? "%>";
|
|
24767
|
+
const parentInfo = findParentArray(this.root, node);
|
|
24768
|
+
if (!parentInfo) {
|
|
24769
|
+
this.visitChildNodes(node);
|
|
24770
|
+
return;
|
|
24771
|
+
}
|
|
24772
|
+
const { array: parentArray, index: nodeIndex } = parentInfo;
|
|
24773
|
+
const replacementNodes = [];
|
|
24774
|
+
for (const part of replacementParts) {
|
|
24775
|
+
if (part.type === "text") {
|
|
24776
|
+
replacementNodes.push(createLiteral(part.content));
|
|
24777
|
+
}
|
|
24778
|
+
else {
|
|
24779
|
+
replacementNodes.push(createERBOutputNode(` ${part.expression.trim()} `, tagOpening, tagClosing));
|
|
24780
|
+
}
|
|
24781
|
+
}
|
|
24782
|
+
parentArray.splice(nodeIndex, 1, ...replacementNodes);
|
|
24783
|
+
}
|
|
24784
|
+
}
|
|
24785
|
+
class ERBStringToDirectOutputRewriter extends ASTRewriter {
|
|
24786
|
+
get name() {
|
|
24787
|
+
return "erb-string-to-direct-output";
|
|
24788
|
+
}
|
|
24789
|
+
get description() {
|
|
24790
|
+
return "Replaces ERB string output with direct text and expression tags";
|
|
24791
|
+
}
|
|
24084
24792
|
rewrite(node, _context) {
|
|
24085
|
-
const visitor = new
|
|
24793
|
+
const visitor = new ERBStringToDirectOutputVisitor(node);
|
|
24086
24794
|
visitor.visit(node);
|
|
24087
24795
|
return node;
|
|
24088
24796
|
}
|
|
24797
|
+
static isStringOutputNode(prismNode) {
|
|
24798
|
+
const nodeType = prismNode.constructor.name;
|
|
24799
|
+
return nodeType === STRING_NODE_TYPE || nodeType === INTERPOLATED_STRING_NODE_TYPE;
|
|
24800
|
+
}
|
|
24801
|
+
static extractStringContent(stringNode, source) {
|
|
24802
|
+
const unescapedValue = stringNode.unescaped?.value;
|
|
24803
|
+
if (typeof unescapedValue === "string") {
|
|
24804
|
+
return unescapedValue;
|
|
24805
|
+
}
|
|
24806
|
+
const location = stringNode.contentLoc;
|
|
24807
|
+
if (location) {
|
|
24808
|
+
return source.substring(location.startOffset, location.startOffset + location.length);
|
|
24809
|
+
}
|
|
24810
|
+
return "";
|
|
24811
|
+
}
|
|
24812
|
+
static extractExpressionSource(embeddedNode, source) {
|
|
24813
|
+
const openingLocation = embeddedNode.openingLoc;
|
|
24814
|
+
const closingLocation = embeddedNode.closingLoc;
|
|
24815
|
+
if (!openingLocation || !closingLocation)
|
|
24816
|
+
return null;
|
|
24817
|
+
const expressionStart = openingLocation.startOffset + openingLocation.length;
|
|
24818
|
+
const expressionEnd = closingLocation.startOffset;
|
|
24819
|
+
return source.substring(expressionStart, expressionEnd);
|
|
24820
|
+
}
|
|
24821
|
+
static extractReplacementParts(prismNode, source) {
|
|
24822
|
+
const nodeType = prismNode.constructor.name;
|
|
24823
|
+
if (nodeType === STRING_NODE_TYPE) {
|
|
24824
|
+
const textContent = this.extractStringContent(prismNode, source);
|
|
24825
|
+
return [{ type: "text", content: textContent }];
|
|
24826
|
+
}
|
|
24827
|
+
if (nodeType === INTERPOLATED_STRING_NODE_TYPE) {
|
|
24828
|
+
const parts = prismNode.parts;
|
|
24829
|
+
if (!parts || parts.length === 0)
|
|
24830
|
+
return null;
|
|
24831
|
+
const replacementParts = [];
|
|
24832
|
+
for (const part of parts) {
|
|
24833
|
+
const partType = part.constructor.name;
|
|
24834
|
+
if (partType === STRING_NODE_TYPE) {
|
|
24835
|
+
const textContent = this.extractStringContent(part, source);
|
|
24836
|
+
if (textContent) {
|
|
24837
|
+
replacementParts.push({ type: "text", content: textContent });
|
|
24838
|
+
}
|
|
24839
|
+
}
|
|
24840
|
+
else if (partType === EMBEDDED_STATEMENTS_NODE_TYPE) {
|
|
24841
|
+
const expression = this.extractExpressionSource(part, source);
|
|
24842
|
+
if (expression) {
|
|
24843
|
+
replacementParts.push({ type: "expression", expression });
|
|
24844
|
+
}
|
|
24845
|
+
}
|
|
24846
|
+
}
|
|
24847
|
+
return replacementParts.length > 0 ? replacementParts : null;
|
|
24848
|
+
}
|
|
24849
|
+
return null;
|
|
24850
|
+
}
|
|
24089
24851
|
}
|
|
24090
24852
|
|
|
24091
24853
|
function serializeAttributeValue(value) {
|
|
@@ -24175,9 +24937,10 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
|
|
|
24175
24937
|
const isAnchor = tagName.value === "a";
|
|
24176
24938
|
const isTurboFrame = tagName.value === "turbo-frame";
|
|
24177
24939
|
const isScript = tagName.value === "script";
|
|
24940
|
+
const isImg = tagName.value === "img";
|
|
24178
24941
|
const attributes = openTag.children.filter(child => !isWhitespaceNode(child));
|
|
24179
|
-
const hasSrcAttribute = isScript && attributes.some(child => isHTMLAttributeNode(child) && getStaticAttributeName(child.name) === "src");
|
|
24180
|
-
const { attributes: attributesString, href, id, src } = serializeAttributes(attributes, { extractHref: isAnchor, extractId: isTurboFrame, extractSrc: isScript });
|
|
24942
|
+
const hasSrcAttribute = (isScript || isImg) && attributes.some(child => isHTMLAttributeNode(child) && getStaticAttributeName(child.name) === "src");
|
|
24943
|
+
const { attributes: attributesString, href, id, src } = serializeAttributes(attributes, { extractHref: isAnchor, extractId: isTurboFrame, extractSrc: isScript || isImg });
|
|
24181
24944
|
const hasBody = node.body && node.body.length > 0 && !node.is_void;
|
|
24182
24945
|
const isInlineContent = hasBody && isTextOnlyBody(node.body);
|
|
24183
24946
|
let content;
|
|
@@ -24198,6 +24961,10 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
|
|
|
24198
24961
|
content = this.buildJavascriptTagContent(node, attributesString, isInlineContent);
|
|
24199
24962
|
elementSource = "ActionView::Helpers::JavaScriptHelper#javascript_tag";
|
|
24200
24963
|
}
|
|
24964
|
+
else if (isImg) {
|
|
24965
|
+
content = this.buildImageTagContent(attributesString, src);
|
|
24966
|
+
elementSource = "ActionView::Helpers::AssetTagHelper#image_tag";
|
|
24967
|
+
}
|
|
24201
24968
|
else {
|
|
24202
24969
|
content = this.buildTagContent(tagName.value, node, attributesString, isInlineContent);
|
|
24203
24970
|
elementSource = "ActionView::Helpers::TagHelper#tag";
|
|
@@ -24215,7 +24982,7 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
|
|
|
24215
24982
|
asMutable(node).open_tag = erbOpenTag;
|
|
24216
24983
|
asMutable(node).element_source = elementSource;
|
|
24217
24984
|
const isInlineLiteralContent = isScript && hasBody && node.body.length === 1 && isLiteralNode(node.body[0]) && !node.body[0].content.includes("\n");
|
|
24218
|
-
const isInlineForm = isInlineContent || isInlineLiteralContent || (isTurboFrame && !hasBody) || (isScript && hasSrcAttribute);
|
|
24985
|
+
const isInlineForm = isInlineContent || isInlineLiteralContent || (isTurboFrame && !hasBody) || (isScript && hasSrcAttribute) || isImg;
|
|
24219
24986
|
if (node.is_void) {
|
|
24220
24987
|
asMutable(node).close_tag = null;
|
|
24221
24988
|
}
|
|
@@ -24299,6 +25066,15 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
|
|
|
24299
25066
|
const argString = args.join(", ");
|
|
24300
25067
|
return argString ? ` javascript_include_tag ${argString} ` : ` javascript_include_tag `;
|
|
24301
25068
|
}
|
|
25069
|
+
buildImageTagContent(attributes, source) {
|
|
25070
|
+
const args = [];
|
|
25071
|
+
if (source)
|
|
25072
|
+
args.push(source);
|
|
25073
|
+
if (attributes)
|
|
25074
|
+
args.push(attributes);
|
|
25075
|
+
const argString = args.join(", ");
|
|
25076
|
+
return argString ? ` image_tag ${argString} ` : ` image_tag `;
|
|
25077
|
+
}
|
|
24302
25078
|
buildLinkToContent(node, attribute, href, isInlineContent) {
|
|
24303
25079
|
const args = [];
|
|
24304
25080
|
if (isInlineContent && isHTMLTextNode(node.body[0])) {
|
|
@@ -24322,7 +25098,7 @@ class HTMLToActionViewTagHelperRewriter extends ASTRewriter {
|
|
|
24322
25098
|
return "html-to-action-view-tag-helper";
|
|
24323
25099
|
}
|
|
24324
25100
|
get description() {
|
|
24325
|
-
return "Converts raw HTML elements to ActionView tag helpers (tag.*, turbo_frame_tag, javascript_tag, javascript_include_tag)";
|
|
25101
|
+
return "Converts raw HTML elements to ActionView tag helpers (tag.*, turbo_frame_tag, javascript_tag, javascript_include_tag, image_tag)";
|
|
24326
25102
|
}
|
|
24327
25103
|
rewrite(node, _context) {
|
|
24328
25104
|
const visitor = new HTMLToActionViewTagHelperVisitor();
|
|
@@ -24749,6 +25525,15 @@ class IdentityPrinter extends Printer {
|
|
|
24749
25525
|
if (node.body) {
|
|
24750
25526
|
node.body.forEach(child => this.visit(child));
|
|
24751
25527
|
}
|
|
25528
|
+
if (node.rescue_clause) {
|
|
25529
|
+
this.visit(node.rescue_clause);
|
|
25530
|
+
}
|
|
25531
|
+
if (node.else_clause) {
|
|
25532
|
+
this.visit(node.else_clause);
|
|
25533
|
+
}
|
|
25534
|
+
if (node.ensure_clause) {
|
|
25535
|
+
this.visit(node.ensure_clause);
|
|
25536
|
+
}
|
|
24752
25537
|
if (node.end_node) {
|
|
24753
25538
|
this.visit(node.end_node);
|
|
24754
25539
|
}
|
|
@@ -24852,6 +25637,12 @@ class IdentityPrinter extends Printer {
|
|
|
24852
25637
|
visitRubyRenderLocalNode(_node) {
|
|
24853
25638
|
// extracted metadata, nothing to print
|
|
24854
25639
|
}
|
|
25640
|
+
visitERBStrictLocalsNode(node) {
|
|
25641
|
+
this.printERBNode(node);
|
|
25642
|
+
}
|
|
25643
|
+
visitRubyStrictLocalNode(_node) {
|
|
25644
|
+
// extracted metadata, nothing to print
|
|
25645
|
+
}
|
|
24855
25646
|
visitERBYieldNode(node) {
|
|
24856
25647
|
this.printERBNode(node);
|
|
24857
25648
|
}
|
|
@@ -24982,6 +25773,7 @@ function rewriteString(herb, template, rewriters, options = {}) {
|
|
|
24982
25773
|
|
|
24983
25774
|
exports.ASTRewriter = ASTRewriter;
|
|
24984
25775
|
exports.ActionViewTagHelperToHTMLRewriter = ActionViewTagHelperToHTMLRewriter;
|
|
25776
|
+
exports.ERBStringToDirectOutputRewriter = ERBStringToDirectOutputRewriter;
|
|
24985
25777
|
exports.HTMLToActionViewTagHelperRewriter = HTMLToActionViewTagHelperRewriter;
|
|
24986
25778
|
exports.StringRewriter = StringRewriter;
|
|
24987
25779
|
exports.asMutable = asMutable;
|