ripple 0.2.134 → 0.2.135
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/package.json +2 -2
- package/src/compiler/phases/1-parse/index.js +290 -69
- package/src/compiler/phases/3-transform/client/index.js +212 -59
- package/src/runtime/internal/client/blocks.js +17 -2
- package/src/utils/builders.js +17 -0
- package/tests/client/basic/basic.components.test.ripple +30 -20
- package/tests/client/compiler/compiler.basic.test.ripple +93 -64
- package/tests/client/dynamic-elements.test.ripple +120 -1
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Ripple is an elegant TypeScript UI framework",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.135",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -81,6 +81,6 @@
|
|
|
81
81
|
"typescript": "^5.9.2"
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
84
|
-
"ripple": "0.2.
|
|
84
|
+
"ripple": "0.2.135"
|
|
85
85
|
}
|
|
86
86
|
}
|
|
@@ -33,7 +33,8 @@ function isWhitespaceTextNode(node) {
|
|
|
33
33
|
if (!node || node.type !== 'Text') {
|
|
34
34
|
return false;
|
|
35
35
|
}
|
|
36
|
-
const value =
|
|
36
|
+
const value =
|
|
37
|
+
typeof node.value === 'string' ? node.value : typeof node.raw === 'string' ? node.raw : '';
|
|
37
38
|
return /^\s*$/.test(value);
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -64,7 +65,9 @@ function RipplePlugin(config) {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
const children = Array.isArray(container.children) ? container.children : [];
|
|
67
|
-
const hasMeaningfulChildren = children.some(
|
|
68
|
+
const hasMeaningfulChildren = children.some(
|
|
69
|
+
(child) => child && !isWhitespaceTextNode(child),
|
|
70
|
+
);
|
|
68
71
|
|
|
69
72
|
if (hasMeaningfulChildren) {
|
|
70
73
|
return null;
|
|
@@ -497,6 +500,25 @@ function RipplePlugin(config) {
|
|
|
497
500
|
|
|
498
501
|
return super.parseExprAtom(refDestructuringErrors, forNew, forInit);
|
|
499
502
|
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Override to track parenthesized expressions in metadata
|
|
506
|
+
* This allows the prettier plugin to preserve parentheses where they existed
|
|
507
|
+
*/
|
|
508
|
+
parseParenAndDistinguishExpression(canBeArrow, forInit) {
|
|
509
|
+
const startPos = this.start;
|
|
510
|
+
const expr = super.parseParenAndDistinguishExpression(canBeArrow, forInit);
|
|
511
|
+
|
|
512
|
+
// If the expression's start position is after the opening paren,
|
|
513
|
+
// it means it was wrapped in parentheses. Mark it in metadata.
|
|
514
|
+
if (expr && expr.start > startPos) {
|
|
515
|
+
expr.metadata ??= {};
|
|
516
|
+
expr.metadata.parenthesized = true;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return expr;
|
|
520
|
+
}
|
|
521
|
+
|
|
500
522
|
/**
|
|
501
523
|
* Parse `@(expression)` syntax for unboxing tracked values
|
|
502
524
|
* Creates a TrackedExpression node with the argument property
|
|
@@ -995,6 +1017,10 @@ function RipplePlugin(config) {
|
|
|
995
1017
|
}
|
|
996
1018
|
|
|
997
1019
|
jsx_parseElementName() {
|
|
1020
|
+
if (this.type?.label === 'jsxTagEnd') {
|
|
1021
|
+
return '';
|
|
1022
|
+
}
|
|
1023
|
+
|
|
998
1024
|
let node = this.jsx_parseNamespacedName();
|
|
999
1025
|
|
|
1000
1026
|
if (node.type === 'JSXNamespacedName') {
|
|
@@ -1004,8 +1030,39 @@ function RipplePlugin(config) {
|
|
|
1004
1030
|
if (this.eat(tt.dot)) {
|
|
1005
1031
|
let memberExpr = this.startNodeAt(node.start, node.loc && node.loc.start);
|
|
1006
1032
|
memberExpr.object = node;
|
|
1007
|
-
|
|
1008
|
-
|
|
1033
|
+
|
|
1034
|
+
// Check for .@[expression] syntax for tracked computed member access
|
|
1035
|
+
// After eating the dot, check if the current token is @ followed by [
|
|
1036
|
+
if (this.type.label === '@') {
|
|
1037
|
+
// Check if the next character after @ is [
|
|
1038
|
+
const nextChar = this.input.charCodeAt(this.pos);
|
|
1039
|
+
|
|
1040
|
+
if (nextChar === 91) { // [ character
|
|
1041
|
+
memberExpr.computed = true;
|
|
1042
|
+
|
|
1043
|
+
// Consume the @ token
|
|
1044
|
+
this.next();
|
|
1045
|
+
|
|
1046
|
+
// Now this.type should be bracketL
|
|
1047
|
+
// Consume the [ and parse the expression inside
|
|
1048
|
+
this.expect(tt.bracketL);
|
|
1049
|
+
|
|
1050
|
+
// Parse the expression inside brackets
|
|
1051
|
+
memberExpr.property = this.parseExpression();
|
|
1052
|
+
memberExpr.property.tracked = true;
|
|
1053
|
+
|
|
1054
|
+
// Expect closing bracket
|
|
1055
|
+
this.expect(tt.bracketR);
|
|
1056
|
+
} else {
|
|
1057
|
+
// @ not followed by [, treat as regular tracked identifier
|
|
1058
|
+
memberExpr.property = this.jsx_parseIdentifier();
|
|
1059
|
+
memberExpr.computed = false;
|
|
1060
|
+
}
|
|
1061
|
+
} else {
|
|
1062
|
+
// Regular dot notation
|
|
1063
|
+
memberExpr.property = this.jsx_parseIdentifier();
|
|
1064
|
+
memberExpr.computed = false;
|
|
1065
|
+
}
|
|
1009
1066
|
while (this.eat(tt.dot)) {
|
|
1010
1067
|
let newMemberExpr = this.startNodeAt(
|
|
1011
1068
|
memberExpr.start,
|
|
@@ -1029,7 +1086,7 @@ function RipplePlugin(config) {
|
|
|
1029
1086
|
var t = this.jsx_parseExpressionContainer();
|
|
1030
1087
|
return (
|
|
1031
1088
|
'JSXEmptyExpression' === t.expression.type &&
|
|
1032
|
-
|
|
1089
|
+
this.raise(t.start, 'attributes must only be assigned a non-empty expression'),
|
|
1033
1090
|
t
|
|
1034
1091
|
);
|
|
1035
1092
|
case tok.jsxTagStart:
|
|
@@ -1202,14 +1259,14 @@ function RipplePlugin(config) {
|
|
|
1202
1259
|
this.raise(
|
|
1203
1260
|
this.pos,
|
|
1204
1261
|
'Unexpected token `' +
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1262
|
+
this.input[this.pos] +
|
|
1263
|
+
'`. Did you mean `' +
|
|
1264
|
+
(ch === 62 ? '>' : '}') +
|
|
1265
|
+
'` or ' +
|
|
1266
|
+
'`{"' +
|
|
1267
|
+
this.input[this.pos] +
|
|
1268
|
+
'"}' +
|
|
1269
|
+
'`?',
|
|
1213
1270
|
);
|
|
1214
1271
|
}
|
|
1215
1272
|
|
|
@@ -1528,7 +1585,18 @@ function RipplePlugin(config) {
|
|
|
1528
1585
|
} else {
|
|
1529
1586
|
const node = this.parseStatement(null);
|
|
1530
1587
|
body.push(node);
|
|
1588
|
+
|
|
1589
|
+
// Ensure we're not in JSX context before recursing
|
|
1590
|
+
// This is important when elements are parsed at statement level
|
|
1591
|
+
const tokContexts = this.acornTypeScript?.tokContexts;
|
|
1592
|
+
if (tokContexts && this.curContext) {
|
|
1593
|
+
const curContext = this.curContext();
|
|
1594
|
+
if (curContext === tokContexts.tc_expr) {
|
|
1595
|
+
this.context.pop();
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1531
1598
|
}
|
|
1599
|
+
|
|
1532
1600
|
this.parseTemplateBody(body);
|
|
1533
1601
|
}
|
|
1534
1602
|
|
|
@@ -1687,6 +1755,16 @@ function RipplePlugin(config) {
|
|
|
1687
1755
|
* @returns {{ onComment: Function, add_comments: Function }} Comment handler functions
|
|
1688
1756
|
*/
|
|
1689
1757
|
function get_comment_handlers(source, comments, index = 0) {
|
|
1758
|
+
function getNextNonWhitespaceCharacter(text, startIndex) {
|
|
1759
|
+
for (let i = startIndex; i < text.length; i++) {
|
|
1760
|
+
const char = text[i];
|
|
1761
|
+
if (char !== ' ' && char !== '\t' && char !== '\n' && char !== '\r') {
|
|
1762
|
+
return char;
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
return null;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1690
1768
|
return {
|
|
1691
1769
|
onComment: (block, value, start, end, start_loc, end_loc, metadata) => {
|
|
1692
1770
|
if (block && /\n/.test(value)) {
|
|
@@ -1717,34 +1795,66 @@ function get_comment_handlers(source, comments, index = 0) {
|
|
|
1717
1795
|
|
|
1718
1796
|
comments = comments
|
|
1719
1797
|
.filter((comment) => comment.start >= index)
|
|
1720
|
-
.map(({ type, value, start, end, loc, context }) => ({
|
|
1798
|
+
.map(({ type, value, start, end, loc, context }) => ({
|
|
1799
|
+
type,
|
|
1800
|
+
value,
|
|
1801
|
+
start,
|
|
1802
|
+
end,
|
|
1803
|
+
loc,
|
|
1804
|
+
context,
|
|
1805
|
+
}));
|
|
1721
1806
|
|
|
1722
1807
|
walk(ast, null, {
|
|
1723
1808
|
_(node, { next, path }) {
|
|
1724
1809
|
let comment;
|
|
1725
1810
|
|
|
1726
|
-
|
|
1811
|
+
const metadata =
|
|
1812
|
+
/** @type {{ commentContainerId?: number, elementLeadingComments?: CommentWithLocation[] }} */ (
|
|
1813
|
+
node?.metadata
|
|
1814
|
+
);
|
|
1727
1815
|
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1816
|
+
if (metadata && metadata.commentContainerId !== undefined) {
|
|
1817
|
+
while (
|
|
1818
|
+
comments[0] &&
|
|
1819
|
+
comments[0].context &&
|
|
1820
|
+
comments[0].context.containerId === metadata.commentContainerId &&
|
|
1821
|
+
comments[0].context.beforeMeaningfulChild
|
|
1822
|
+
) {
|
|
1823
|
+
const elementComment = /** @type {CommentWithLocation & { context?: any }} */ (
|
|
1824
|
+
comments.shift()
|
|
1825
|
+
);
|
|
1826
|
+
(metadata.elementLeadingComments ||= []).push(elementComment);
|
|
1738
1827
|
}
|
|
1828
|
+
}
|
|
1739
1829
|
|
|
1740
1830
|
while (comments[0] && comments[0].start < node.start) {
|
|
1741
1831
|
comment = /** @type {CommentWithLocation} */ (comments.shift());
|
|
1832
|
+
|
|
1833
|
+
// Skip leading comments for BlockStatement that is a function body
|
|
1834
|
+
// These comments should be dangling on the function instead
|
|
1835
|
+
if (node.type === 'BlockStatement') {
|
|
1836
|
+
const parent = path.at(-1);
|
|
1837
|
+
if (
|
|
1838
|
+
parent &&
|
|
1839
|
+
(parent.type === 'FunctionDeclaration' ||
|
|
1840
|
+
parent.type === 'FunctionExpression' ||
|
|
1841
|
+
parent.type === 'ArrowFunctionExpression') &&
|
|
1842
|
+
parent.body === node
|
|
1843
|
+
) {
|
|
1844
|
+
// This is a function body - don't attach comment, let it be handled by function
|
|
1845
|
+
(parent.comments ||= []).push(comment);
|
|
1846
|
+
continue;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1742
1850
|
if (comment.loc) {
|
|
1743
1851
|
const ancestorElements = path
|
|
1744
1852
|
.filter((ancestor) => ancestor && ancestor.type === 'Element' && ancestor.loc)
|
|
1745
1853
|
.sort((a, b) => a.loc.start.line - b.loc.start.line);
|
|
1746
1854
|
|
|
1747
|
-
const targetAncestor = ancestorElements.find(
|
|
1855
|
+
const targetAncestor = ancestorElements.find(
|
|
1856
|
+
(ancestor) => comment.loc.start.line < ancestor.loc.start.line,
|
|
1857
|
+
);
|
|
1748
1858
|
|
|
1749
1859
|
if (targetAncestor) {
|
|
1750
1860
|
targetAncestor.metadata ??= {};
|
|
@@ -1755,72 +1865,183 @@ function get_comment_handlers(source, comments, index = 0) {
|
|
|
1755
1865
|
(node.leadingComments ||= []).push(comment);
|
|
1756
1866
|
}
|
|
1757
1867
|
|
|
1758
|
-
|
|
1868
|
+
next();
|
|
1759
1869
|
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1870
|
+
if (comments[0]) {
|
|
1871
|
+
if (node.type === 'BlockStatement' && node.body.length === 0) {
|
|
1872
|
+
// Collect all comments that fall within this empty block
|
|
1873
|
+
while (comments[0] && comments[0].start < node.end && comments[0].end < node.end) {
|
|
1874
|
+
comment = /** @type {CommentWithLocation} */ (comments.shift());
|
|
1875
|
+
(node.innerComments ||= []).push(comment);
|
|
1876
|
+
}
|
|
1877
|
+
if (node.innerComments && node.innerComments.length > 0) {
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
// Handle empty Element nodes the same way as empty BlockStatements
|
|
1882
|
+
if (node.type === 'Element' && (!node.children || node.children.length === 0)) {
|
|
1883
|
+
if (comments[0].start < node.end && comments[0].end < node.end) {
|
|
1884
|
+
comment = /** @type {CommentWithLocation} */ (comments.shift());
|
|
1885
|
+
(node.innerComments ||= []).push(comment);
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
const parent = /** @type {any} */ (path.at(-1));
|
|
1891
|
+
|
|
1892
|
+
if (parent === undefined || node.end !== parent.end) {
|
|
1780
1893
|
const slice = source.slice(node.end, comments[0].start);
|
|
1781
1894
|
|
|
1782
1895
|
// Check if this node is the last item in an array-like structure
|
|
1783
1896
|
let is_last_in_array = false;
|
|
1784
1897
|
let array_prop = null;
|
|
1785
1898
|
|
|
1786
|
-
if (
|
|
1899
|
+
if (
|
|
1900
|
+
parent?.type === 'BlockStatement' ||
|
|
1901
|
+
parent?.type === 'Program' ||
|
|
1902
|
+
parent?.type === 'Component' ||
|
|
1903
|
+
parent?.type === 'ClassBody'
|
|
1904
|
+
) {
|
|
1787
1905
|
array_prop = 'body';
|
|
1788
|
-
} else if (parent?.type === '
|
|
1906
|
+
} else if (parent?.type === 'SwitchStatement') {
|
|
1907
|
+
array_prop = 'cases';
|
|
1908
|
+
} else if (parent?.type === 'SwitchCase') {
|
|
1909
|
+
array_prop = 'consequent';
|
|
1910
|
+
} else if (
|
|
1911
|
+
parent?.type === 'ArrayExpression' ||
|
|
1912
|
+
parent?.type === 'TrackedArrayExpression'
|
|
1913
|
+
) {
|
|
1789
1914
|
array_prop = 'elements';
|
|
1790
|
-
} else if (
|
|
1915
|
+
} else if (
|
|
1916
|
+
parent?.type === 'ObjectExpression' ||
|
|
1917
|
+
parent?.type === 'TrackedObjectExpression'
|
|
1918
|
+
) {
|
|
1791
1919
|
array_prop = 'properties';
|
|
1920
|
+
} else if (
|
|
1921
|
+
parent?.type === 'FunctionDeclaration' ||
|
|
1922
|
+
parent?.type === 'FunctionExpression' ||
|
|
1923
|
+
parent?.type === 'ArrowFunctionExpression'
|
|
1924
|
+
) {
|
|
1925
|
+
array_prop = 'params';
|
|
1926
|
+
} else if (
|
|
1927
|
+
parent?.type === 'CallExpression' ||
|
|
1928
|
+
parent?.type === 'OptionalCallExpression' ||
|
|
1929
|
+
parent?.type === 'NewExpression'
|
|
1930
|
+
) {
|
|
1931
|
+
array_prop = 'arguments';
|
|
1792
1932
|
}
|
|
1793
|
-
|
|
1794
1933
|
if (array_prop && Array.isArray(parent[array_prop])) {
|
|
1795
|
-
is_last_in_array =
|
|
1934
|
+
is_last_in_array =
|
|
1935
|
+
parent[array_prop].indexOf(node) === parent[array_prop].length - 1;
|
|
1796
1936
|
}
|
|
1797
1937
|
|
|
1798
1938
|
if (is_last_in_array) {
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1939
|
+
const isParam = array_prop === 'params';
|
|
1940
|
+
const isArgument = array_prop === 'arguments';
|
|
1941
|
+
if (isParam || isArgument) {
|
|
1942
|
+
while (comments.length) {
|
|
1943
|
+
const potentialComment = comments[0];
|
|
1944
|
+
if (parent && potentialComment.start >= parent.end) {
|
|
1945
|
+
break;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
const nextChar = getNextNonWhitespaceCharacter(source, potentialComment.end);
|
|
1949
|
+
if (nextChar === ')') {
|
|
1950
|
+
(node.trailingComments ||= []).push(
|
|
1951
|
+
/** @type {CommentWithLocation} */(comments.shift()),
|
|
1952
|
+
);
|
|
1953
|
+
continue;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
break;
|
|
1957
|
+
}
|
|
1958
|
+
} else {
|
|
1959
|
+
// Special case: There can be multiple trailing comments after the last node in a block,
|
|
1960
|
+
// and they can be separated by newlines
|
|
1961
|
+
let end = node.end;
|
|
1962
|
+
|
|
1963
|
+
while (comments.length) {
|
|
1964
|
+
const comment = comments[0];
|
|
1965
|
+
if (parent && comment.start >= parent.end) break;
|
|
1966
|
+
|
|
1967
|
+
(node.trailingComments ||= []).push(comment);
|
|
1968
|
+
comments.shift();
|
|
1969
|
+
end = comment.end;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
} else if (node.end <= comments[0].start) {
|
|
1973
|
+
const onlySimpleWhitespace = /^[,) \t]*$/.test(slice);
|
|
1974
|
+
const onlyWhitespace = /^\s*$/.test(slice);
|
|
1975
|
+
const hasBlankLine = /\n\s*\n/.test(slice);
|
|
1976
|
+
const nodeEndLine = node.loc?.end?.line ?? null;
|
|
1977
|
+
const commentStartLine = comments[0].loc?.start?.line ?? null;
|
|
1978
|
+
const isImmediateNextLine =
|
|
1979
|
+
nodeEndLine !== null &&
|
|
1980
|
+
commentStartLine !== null &&
|
|
1981
|
+
commentStartLine === nodeEndLine + 1;
|
|
1982
|
+
const isSwitchCaseSibling = array_prop === 'cases';
|
|
1983
|
+
|
|
1984
|
+
if (isSwitchCaseSibling && !is_last_in_array) {
|
|
1985
|
+
if (
|
|
1986
|
+
nodeEndLine !== null &&
|
|
1987
|
+
commentStartLine !== null &&
|
|
1988
|
+
nodeEndLine === commentStartLine
|
|
1989
|
+
) {
|
|
1990
|
+
node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())];
|
|
1991
|
+
}
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1802
1994
|
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1995
|
+
if (
|
|
1996
|
+
onlySimpleWhitespace ||
|
|
1997
|
+
(onlyWhitespace && !hasBlankLine && isImmediateNextLine)
|
|
1998
|
+
) {
|
|
1999
|
+
// Check if this is a block comment that's inline with the next statement
|
|
2000
|
+
// e.g., /** @type {SomeType} */ (a) = 5;
|
|
2001
|
+
// These should be leading comments, not trailing
|
|
2002
|
+
if (
|
|
2003
|
+
comments[0].type === 'Block' &&
|
|
2004
|
+
!is_last_in_array &&
|
|
2005
|
+
array_prop &&
|
|
2006
|
+
parent[array_prop]
|
|
2007
|
+
) {
|
|
2008
|
+
const currentIndex = parent[array_prop].indexOf(node);
|
|
2009
|
+
const nextSibling = parent[array_prop][currentIndex + 1];
|
|
2010
|
+
|
|
2011
|
+
if (nextSibling && nextSibling.loc) {
|
|
2012
|
+
const commentEndLine = comments[0].loc?.end?.line;
|
|
2013
|
+
const nextSiblingStartLine = nextSibling.loc?.start?.line;
|
|
2014
|
+
|
|
2015
|
+
// If comment ends on same line as next sibling starts, it's inline with next
|
|
2016
|
+
if (commentEndLine === nextSiblingStartLine) {
|
|
2017
|
+
// Leave it for next sibling's leading comments
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
1806
2022
|
|
|
1807
|
-
|
|
1808
|
-
comments
|
|
1809
|
-
|
|
2023
|
+
// For function parameters, only attach as trailing comment if it's on the same line
|
|
2024
|
+
// Comments on next line after comma should be leading comments of next parameter
|
|
2025
|
+
const isParam = array_prop === 'params';
|
|
2026
|
+
if (isParam) {
|
|
2027
|
+
// Check if comment is on same line as the node
|
|
2028
|
+
const nodeEndLine = source.slice(0, node.end).split('\n').length;
|
|
2029
|
+
const commentStartLine = source.slice(0, comments[0].start).split('\n').length;
|
|
2030
|
+
if (nodeEndLine === commentStartLine) {
|
|
2031
|
+
node.trailingComments = [
|
|
2032
|
+
/** @type {CommentWithLocation} */ (comments.shift()),
|
|
2033
|
+
];
|
|
2034
|
+
}
|
|
2035
|
+
// Otherwise leave it for next parameter's leading comments
|
|
2036
|
+
} else {
|
|
2037
|
+
node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())];
|
|
2038
|
+
}
|
|
1810
2039
|
}
|
|
1811
|
-
} else if (node.end <= comments[0].start && /^[,) \t]*$/.test(slice)) {
|
|
1812
|
-
node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())];
|
|
1813
2040
|
}
|
|
1814
2041
|
}
|
|
1815
2042
|
}
|
|
1816
2043
|
},
|
|
1817
2044
|
});
|
|
1818
|
-
|
|
1819
|
-
// Special case: Trailing comments after the root node (which can only happen for expression tags or for Program nodes).
|
|
1820
|
-
// Adding them ensures that we can later detect the end of the expression tag correctly.
|
|
1821
|
-
if (comments.length > 0 && (comments[0].start >= ast.end || ast.type === 'Program')) {
|
|
1822
|
-
(ast.trailingComments ||= []).push(...comments.splice(0));
|
|
1823
|
-
}
|
|
1824
2045
|
},
|
|
1825
2046
|
};
|
|
1826
2047
|
}
|