ripple 0.2.139 → 0.2.141
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 +8 -3
- package/src/compiler/phases/2-analyze/index.js +11 -9
- package/src/compiler/phases/3-transform/client/index.js +193 -56
- package/src/compiler/phases/3-transform/segments.js +31 -74
- package/src/compiler/utils.js +22 -11
- package/src/runtime/date.js +1 -1
- package/src/runtime/internal/client/bindings.js +9 -9
- package/src/runtime/internal/client/for.js +2 -2
- package/src/runtime/internal/client/index.js +3 -1
- package/src/runtime/internal/client/render.js +23 -23
- package/src/runtime/internal/client/runtime.js +70 -59
- package/src/runtime/map.js +182 -182
- package/src/runtime/media-query.js +1 -1
- package/src/runtime/proxy.js +279 -279
- package/src/runtime/set.js +168 -168
- package/src/runtime/url-search-params.js +5 -5
- package/src/runtime/url.js +18 -18
- package/src/utils/builders.js +1 -0
- package/tests/client/basic/basic.get-set.test.ripple +37 -49
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.ripple.snap +4 -4
- package/tests/client/composite/composite.props.test.ripple +44 -2
- package/types/index.d.ts +1 -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.141",
|
|
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.141"
|
|
85
85
|
}
|
|
86
86
|
}
|
|
@@ -169,14 +169,18 @@ function RipplePlugin(config) {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
if (inComponent) {
|
|
172
|
-
//
|
|
173
|
-
//
|
|
172
|
+
// Check if we're inside a nested function (arrow function, function expression, etc.)
|
|
173
|
+
// We need to distinguish between being inside a function vs just being in nested scopes
|
|
174
|
+
// (like for loops, if blocks, JSX elements, etc.)
|
|
175
|
+
const nestedFunctionContext = this.context.some((ctx) => ctx.token === 'function');
|
|
176
|
+
|
|
177
|
+
// Inside nested functions, treat < as relational/generic operator
|
|
174
178
|
// BUT: if the < is followed by /, it's a closing JSX tag, not a less-than operator
|
|
175
179
|
const nextChar =
|
|
176
180
|
this.pos + 1 < this.input.length ? this.input.charCodeAt(this.pos + 1) : -1;
|
|
177
181
|
const isClosingTag = nextChar === 47; // '/'
|
|
178
182
|
|
|
179
|
-
if (
|
|
183
|
+
if (nestedFunctionContext && !isClosingTag) {
|
|
180
184
|
// Inside function - treat as TypeScript generic, not JSX
|
|
181
185
|
++this.pos;
|
|
182
186
|
return this.finishToken(tt.relational, '<');
|
|
@@ -987,6 +991,7 @@ function RipplePlugin(config) {
|
|
|
987
991
|
this.finishNode(id, 'Identifier');
|
|
988
992
|
node.name = id;
|
|
989
993
|
node.value = id;
|
|
994
|
+
node.shorthand = true; // Mark as shorthand since name and value are the same
|
|
990
995
|
this.next();
|
|
991
996
|
this.expect(tt.braceR);
|
|
992
997
|
return this.finishNode(node, 'Attribute');
|
|
@@ -109,7 +109,7 @@ const visitors = {
|
|
|
109
109
|
const parent = context.path.at(-1);
|
|
110
110
|
|
|
111
111
|
if (
|
|
112
|
-
is_reference(node, /** @type {Node} */(parent)) &&
|
|
112
|
+
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
113
113
|
binding &&
|
|
114
114
|
context.state.inside_server_block &&
|
|
115
115
|
context.state.scope.server_block
|
|
@@ -144,7 +144,7 @@ const visitors = {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
if (
|
|
147
|
-
is_reference(node, /** @type {Node} */(parent)) &&
|
|
147
|
+
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
148
148
|
node.tracked &&
|
|
149
149
|
binding?.node !== node
|
|
150
150
|
) {
|
|
@@ -155,7 +155,7 @@ const visitors = {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
if (
|
|
158
|
-
is_reference(node, /** @type {Node} */(parent)) &&
|
|
158
|
+
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
159
159
|
node.tracked &&
|
|
160
160
|
binding?.node !== node
|
|
161
161
|
) {
|
|
@@ -191,7 +191,7 @@ const visitors = {
|
|
|
191
191
|
error(
|
|
192
192
|
`Directly accessing internal property "${propertyName}" of a tracked object is not allowed. Use \`get(${node.object.name})\` or \`@${node.object.name}\` instead.`,
|
|
193
193
|
context.state.analysis.module.filename,
|
|
194
|
-
node.property
|
|
194
|
+
node.property,
|
|
195
195
|
);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
@@ -205,7 +205,7 @@ const visitors = {
|
|
|
205
205
|
`Accessing a tracked object directly is not allowed, use the \`@\` prefix to read the value inside a tracked object - for example \`@${node.object.name}${node.property.type === 'Identifier' ? `.${node.property.name}` : ''}\``,
|
|
206
206
|
context.state.analysis.module.filename,
|
|
207
207
|
node,
|
|
208
|
-
)
|
|
208
|
+
);
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
|
|
@@ -259,8 +259,11 @@ const visitors = {
|
|
|
259
259
|
const callee = declarator.init.callee;
|
|
260
260
|
// Check if it's a call to `track` or `tracked`
|
|
261
261
|
if (
|
|
262
|
-
(callee.type === 'Identifier' &&
|
|
263
|
-
|
|
262
|
+
(callee.type === 'Identifier' &&
|
|
263
|
+
(callee.name === 'track' || callee.name === 'tracked')) ||
|
|
264
|
+
(callee.type === 'MemberExpression' &&
|
|
265
|
+
callee.property.type === 'Identifier' &&
|
|
266
|
+
(callee.property.name === 'track' || callee.property.name === 'tracked'))
|
|
264
267
|
) {
|
|
265
268
|
binding.metadata = { ...binding.metadata, is_tracked_object: true };
|
|
266
269
|
}
|
|
@@ -623,7 +626,6 @@ const visitors = {
|
|
|
623
626
|
context.state.analysis.module.filename,
|
|
624
627
|
node,
|
|
625
628
|
);
|
|
626
|
-
|
|
627
629
|
},
|
|
628
630
|
|
|
629
631
|
Element(node, context) {
|
|
@@ -829,7 +831,7 @@ const visitors = {
|
|
|
829
831
|
error(
|
|
830
832
|
'`await` is not allowed in client-side control-flow statements',
|
|
831
833
|
context.state.analysis.module.filename,
|
|
832
|
-
node
|
|
834
|
+
node,
|
|
833
835
|
);
|
|
834
836
|
}
|
|
835
837
|
}
|
|
@@ -190,9 +190,17 @@ const visitors = {
|
|
|
190
190
|
const binding = context.state.scope.get(node.name);
|
|
191
191
|
if (binding?.metadata?.is_dynamic_component) {
|
|
192
192
|
// Capitalize the identifier for TypeScript
|
|
193
|
-
const
|
|
194
|
-
const
|
|
195
|
-
|
|
193
|
+
const capitalized_name = node.name.charAt(0).toUpperCase() + node.name.slice(1);
|
|
194
|
+
const capitalized_node = {
|
|
195
|
+
...node,
|
|
196
|
+
name: capitalized_name,
|
|
197
|
+
metadata: {
|
|
198
|
+
...node.metadata,
|
|
199
|
+
original_name: node.name,
|
|
200
|
+
is_capitalized: true,
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
return b.member(capitalized_node, b.literal('#v'), true);
|
|
196
204
|
}
|
|
197
205
|
return b.member(node, b.literal('#v'), true);
|
|
198
206
|
}
|
|
@@ -525,13 +533,74 @@ const visitors = {
|
|
|
525
533
|
|
|
526
534
|
VariableDeclarator(node, context) {
|
|
527
535
|
// In TypeScript mode, capitalize identifiers that are used as dynamic components
|
|
528
|
-
if (context.state.to_ts
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
536
|
+
if (context.state.to_ts) {
|
|
537
|
+
/**
|
|
538
|
+
* Recursively capitalize identifiers in patterns (ArrayPattern, ObjectPattern)
|
|
539
|
+
* @param {any} pattern - The pattern node to process
|
|
540
|
+
* @returns {any} The transformed pattern
|
|
541
|
+
*/
|
|
542
|
+
const capitalize_pattern = (pattern) => {
|
|
543
|
+
if (pattern.type === 'Identifier') {
|
|
544
|
+
const binding = context.state.scope.get(pattern.name);
|
|
545
|
+
if (binding?.metadata?.is_dynamic_component) {
|
|
546
|
+
const capitalized_name = pattern.name.charAt(0).toUpperCase() + pattern.name.slice(1);
|
|
547
|
+
// Add metadata to track the original name for Volar mappings
|
|
548
|
+
return {
|
|
549
|
+
...pattern,
|
|
550
|
+
name: capitalized_name,
|
|
551
|
+
metadata: {
|
|
552
|
+
...pattern.metadata,
|
|
553
|
+
original_name: pattern.name,
|
|
554
|
+
is_capitalized: true,
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
return pattern;
|
|
559
|
+
} else if (pattern.type === 'ArrayPattern') {
|
|
560
|
+
return {
|
|
561
|
+
...pattern,
|
|
562
|
+
elements: pattern.elements.map((element) =>
|
|
563
|
+
element ? capitalize_pattern(element) : element,
|
|
564
|
+
),
|
|
565
|
+
};
|
|
566
|
+
} else if (pattern.type === 'ObjectPattern') {
|
|
567
|
+
return {
|
|
568
|
+
...pattern,
|
|
569
|
+
properties: pattern.properties.map((prop) => {
|
|
570
|
+
if (prop.type === 'Property') {
|
|
571
|
+
return {
|
|
572
|
+
...prop,
|
|
573
|
+
value: capitalize_pattern(prop.value),
|
|
574
|
+
};
|
|
575
|
+
} else if (prop.type === 'RestElement') {
|
|
576
|
+
return {
|
|
577
|
+
...prop,
|
|
578
|
+
argument: capitalize_pattern(prop.argument),
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
return prop;
|
|
582
|
+
}),
|
|
583
|
+
};
|
|
584
|
+
} else if (pattern.type === 'RestElement') {
|
|
585
|
+
return {
|
|
586
|
+
...pattern,
|
|
587
|
+
argument: capitalize_pattern(pattern.argument),
|
|
588
|
+
};
|
|
589
|
+
} else if (pattern.type === 'AssignmentPattern') {
|
|
590
|
+
return {
|
|
591
|
+
...pattern,
|
|
592
|
+
left: capitalize_pattern(pattern.left),
|
|
593
|
+
right: context.visit(pattern.right),
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
return pattern;
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
const transformed_id = capitalize_pattern(node.id);
|
|
600
|
+
if (transformed_id !== node.id) {
|
|
532
601
|
return {
|
|
533
602
|
...node,
|
|
534
|
-
id:
|
|
603
|
+
id: transformed_id,
|
|
535
604
|
init: node.init ? context.visit(node.init) : null,
|
|
536
605
|
};
|
|
537
606
|
}
|
|
@@ -938,7 +1007,7 @@ const visitors = {
|
|
|
938
1007
|
let expression = visit(class_attribute.value, { ...state, metadata });
|
|
939
1008
|
|
|
940
1009
|
const hash_arg = scoping_hash ? b.literal(scoping_hash) : undefined;
|
|
941
|
-
const is_html = context.state.
|
|
1010
|
+
const is_html = context.state.namespace === 'html' && node.id.name !== 'svg';
|
|
942
1011
|
|
|
943
1012
|
if (metadata.tracking) {
|
|
944
1013
|
local_updates.push(
|
|
@@ -1244,7 +1313,6 @@ const visitors = {
|
|
|
1244
1313
|
/** @type {Expression} */ (context.visit(left)),
|
|
1245
1314
|
/** @type {Expression} */ (context.visit(right)),
|
|
1246
1315
|
),
|
|
1247
|
-
b.id('__block'),
|
|
1248
1316
|
);
|
|
1249
1317
|
}
|
|
1250
1318
|
|
|
@@ -1265,7 +1333,6 @@ const visitors = {
|
|
|
1265
1333
|
),
|
|
1266
1334
|
/** @type {Expression} */ (context.visit(right)),
|
|
1267
1335
|
),
|
|
1268
|
-
b.id('__block'),
|
|
1269
1336
|
);
|
|
1270
1337
|
}
|
|
1271
1338
|
|
|
@@ -1291,7 +1358,6 @@ const visitors = {
|
|
|
1291
1358
|
node.prefix ? '_$_.update_pre_property' : '_$_.update_property',
|
|
1292
1359
|
context.visit(argument.object, { ...context.state, metadata: { tracking: false } }),
|
|
1293
1360
|
argument.computed ? context.visit(argument.property) : b.literal(argument.property.name),
|
|
1294
|
-
b.id('__block'),
|
|
1295
1361
|
node.operator === '--' ? b.literal(-1) : undefined,
|
|
1296
1362
|
);
|
|
1297
1363
|
}
|
|
@@ -1300,7 +1366,6 @@ const visitors = {
|
|
|
1300
1366
|
return b.call(
|
|
1301
1367
|
node.prefix ? '_$_.update_pre' : '_$_.update',
|
|
1302
1368
|
context.visit(argument, { ...context.state, metadata: { tracking: null } }),
|
|
1303
|
-
b.id('__block'),
|
|
1304
1369
|
node.operator === '--' ? b.literal(-1) : undefined,
|
|
1305
1370
|
);
|
|
1306
1371
|
}
|
|
@@ -1309,7 +1374,6 @@ const visitors = {
|
|
|
1309
1374
|
return b.call(
|
|
1310
1375
|
node.prefix ? '_$_.update_pre' : '_$_.update',
|
|
1311
1376
|
context.visit(argument.argument, { ...context.state, metadata: { tracking: null } }),
|
|
1312
|
-
b.id('__block'),
|
|
1313
1377
|
node.operator === '--' ? b.literal(-1) : undefined,
|
|
1314
1378
|
);
|
|
1315
1379
|
}
|
|
@@ -1740,7 +1804,10 @@ function transform_ts_child(node, context) {
|
|
|
1740
1804
|
}
|
|
1741
1805
|
jsx_name.loc = attr.name.loc || name.loc;
|
|
1742
1806
|
|
|
1743
|
-
|
|
1807
|
+
const jsx_attr = b.jsx_attribute(jsx_name, b.jsx_expression_container(value));
|
|
1808
|
+
// Preserve shorthand flag from parser (set for {identifier} syntax)
|
|
1809
|
+
jsx_attr.shorthand = attr.shorthand ?? false;
|
|
1810
|
+
return jsx_attr;
|
|
1744
1811
|
} else if (attr.type === 'SpreadAttribute') {
|
|
1745
1812
|
const metadata = { await: false };
|
|
1746
1813
|
const argument = visit(attr.argument, { ...state, metadata });
|
|
@@ -1783,31 +1850,78 @@ function transform_ts_child(node, context) {
|
|
|
1783
1850
|
closing_type = node.selfClosing ? undefined : type_expression;
|
|
1784
1851
|
} else {
|
|
1785
1852
|
opening_type = b.jsx_id(type_expression);
|
|
1786
|
-
//
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
},
|
|
1792
|
-
end: {
|
|
1793
|
-
line: node.loc.start.line,
|
|
1794
|
-
column: node.loc.start.column + 2 + type_expression.length,
|
|
1795
|
-
},
|
|
1796
|
-
};
|
|
1797
|
-
|
|
1798
|
-
if (!node.selfClosing) {
|
|
1799
|
-
closing_type = b.jsx_id(type_expression);
|
|
1800
|
-
closing_type.loc = {
|
|
1853
|
+
// For tracked identifiers (dynamic components), adjust the loc to skip the '@' prefix
|
|
1854
|
+
// and add metadata for mapping
|
|
1855
|
+
if (node.id.tracked && node.id.loc) {
|
|
1856
|
+
// The original identifier loc includes the '@', so we need to skip it
|
|
1857
|
+
opening_type.loc = {
|
|
1801
1858
|
start: {
|
|
1802
|
-
line: node.loc.
|
|
1803
|
-
column: node.loc.
|
|
1859
|
+
line: node.id.loc.start.line,
|
|
1860
|
+
column: node.id.loc.start.column + 1, // Skip '@'
|
|
1861
|
+
},
|
|
1862
|
+
end: node.id.loc.end,
|
|
1863
|
+
};
|
|
1864
|
+
// Add metadata if this was capitalized
|
|
1865
|
+
if (node.metadata?.ts_name && node.metadata?.original_name) {
|
|
1866
|
+
opening_type.metadata = {
|
|
1867
|
+
original_name: node.metadata.original_name,
|
|
1868
|
+
is_capitalized: true,
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
} else {
|
|
1872
|
+
// Use node.id.loc if available, otherwise create a loc based on the element's position
|
|
1873
|
+
opening_type.loc = node.id.loc || {
|
|
1874
|
+
start: {
|
|
1875
|
+
line: node.loc.start.line,
|
|
1876
|
+
column: node.loc.start.column + 2, // After "<@"
|
|
1804
1877
|
},
|
|
1805
1878
|
end: {
|
|
1806
|
-
line: node.loc.
|
|
1807
|
-
column: node.loc.
|
|
1879
|
+
line: node.loc.start.line,
|
|
1880
|
+
column: node.loc.start.column + 2 + type_expression.length,
|
|
1808
1881
|
},
|
|
1809
1882
|
};
|
|
1810
1883
|
}
|
|
1884
|
+
|
|
1885
|
+
if (!node.selfClosing) {
|
|
1886
|
+
closing_type = b.jsx_id(type_expression);
|
|
1887
|
+
// For tracked identifiers, also adjust closing tag location
|
|
1888
|
+
if (node.id.tracked && node.id.loc) {
|
|
1889
|
+
// Calculate position relative to closing tag
|
|
1890
|
+
// Format: </@identifier>
|
|
1891
|
+
const closing_tag_start = node.loc.end.column - type_expression.length - 3; // </@
|
|
1892
|
+
closing_type.loc = {
|
|
1893
|
+
start: {
|
|
1894
|
+
line: node.loc.end.line,
|
|
1895
|
+
column: closing_tag_start + 3, // Skip '</@'
|
|
1896
|
+
},
|
|
1897
|
+
end: {
|
|
1898
|
+
line: node.loc.end.line,
|
|
1899
|
+
column:
|
|
1900
|
+
closing_tag_start +
|
|
1901
|
+
3 +
|
|
1902
|
+
(node.metadata?.original_name?.length || type_expression.length),
|
|
1903
|
+
},
|
|
1904
|
+
};
|
|
1905
|
+
// Add metadata if this was capitalized
|
|
1906
|
+
if (node.metadata?.ts_name && node.metadata?.original_name) {
|
|
1907
|
+
closing_type.metadata = {
|
|
1908
|
+
original_name: node.metadata.original_name,
|
|
1909
|
+
is_capitalized: true,
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
} else {
|
|
1913
|
+
closing_type.loc = {
|
|
1914
|
+
start: {
|
|
1915
|
+
line: node.loc.end.line,
|
|
1916
|
+
column: node.loc.end.column - type_expression.length - 1,
|
|
1917
|
+
},
|
|
1918
|
+
end: {
|
|
1919
|
+
line: node.loc.end.line,
|
|
1920
|
+
column: node.loc.end.column - 1,
|
|
1921
|
+
},
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1811
1925
|
}
|
|
1812
1926
|
|
|
1813
1927
|
const jsxElement = b.jsx_element(
|
|
@@ -2219,6 +2333,22 @@ function create_tsx_with_typescript_support() {
|
|
|
2219
2333
|
|
|
2220
2334
|
return {
|
|
2221
2335
|
...base_tsx,
|
|
2336
|
+
// Custom handler for ArrayPattern to ensure typeAnnotation is visited
|
|
2337
|
+
// esrap's TypeScript handler doesn't visit typeAnnotation for ArrayPattern (only for ObjectPattern)
|
|
2338
|
+
ArrayPattern(node, context) {
|
|
2339
|
+
context.write('[');
|
|
2340
|
+
for (let i = 0; i < node.elements.length; i++) {
|
|
2341
|
+
if (i > 0) context.write(', ');
|
|
2342
|
+
if (node.elements[i]) {
|
|
2343
|
+
context.visit(node.elements[i]);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
context.write(']');
|
|
2347
|
+
// Visit type annotation if present
|
|
2348
|
+
if (node.typeAnnotation) {
|
|
2349
|
+
context.visit(node.typeAnnotation);
|
|
2350
|
+
}
|
|
2351
|
+
},
|
|
2222
2352
|
// Custom handler for FunctionDeclaration to support component->function mapping
|
|
2223
2353
|
// Needed for volar mappings and intellisense on function or component keyword
|
|
2224
2354
|
FunctionDeclaration(node, context) {
|
|
@@ -2396,12 +2526,13 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
2396
2526
|
|
|
2397
2527
|
const language_handler = to_ts ? create_tsx_with_typescript_support() : tsx();
|
|
2398
2528
|
|
|
2399
|
-
const js =
|
|
2400
|
-
print
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2529
|
+
const js =
|
|
2530
|
+
/** @type {ReturnType<typeof print> & { post_processing_changes?: PostProcessingChanges, line_offsets?: number[] }} */ (
|
|
2531
|
+
print(program, language_handler, {
|
|
2532
|
+
sourceMapContent: source,
|
|
2533
|
+
sourceMapSource: path.basename(filename),
|
|
2534
|
+
})
|
|
2535
|
+
);
|
|
2405
2536
|
|
|
2406
2537
|
// Post-process TypeScript output to remove 'declare' from function overload signatures
|
|
2407
2538
|
// Function overload signatures in regular .ts files should not have 'declare' keyword
|
|
@@ -2427,7 +2558,10 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
2427
2558
|
*/
|
|
2428
2559
|
const offset_to_line = (offset) => {
|
|
2429
2560
|
for (let i = 0; i < line_offsets.length; i++) {
|
|
2430
|
-
if (
|
|
2561
|
+
if (
|
|
2562
|
+
offset >= line_offsets[i] &&
|
|
2563
|
+
(i === line_offsets.length - 1 || offset < line_offsets[i + 1])
|
|
2564
|
+
) {
|
|
2431
2565
|
return i + 1;
|
|
2432
2566
|
}
|
|
2433
2567
|
}
|
|
@@ -2440,22 +2574,25 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
2440
2574
|
// Remove 'export declare function' -> 'export function' (for overloads only, not implementations)
|
|
2441
2575
|
// Match: export declare function name(...): type;
|
|
2442
2576
|
// Don't match: export declare function name(...): type { (has body)
|
|
2443
|
-
js.code = js.code.replace(
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2577
|
+
js.code = js.code.replace(
|
|
2578
|
+
/^(export\s+)declare\s+(function\s+\w+[^{\n]*;)$/gm,
|
|
2579
|
+
(match, p1, p2, offset) => {
|
|
2580
|
+
const replacement = p1 + p2;
|
|
2581
|
+
const line = offset_to_line(offset);
|
|
2582
|
+
const delta = replacement.length - match.length; // negative (removing 'declare ')
|
|
2583
|
+
|
|
2584
|
+
// Track first change offset and total delta per line
|
|
2585
|
+
if (!line_deltas.has(line)) {
|
|
2586
|
+
line_deltas.set(line, { offset, delta });
|
|
2587
|
+
} else {
|
|
2588
|
+
// Additional change on same line - accumulate delta
|
|
2589
|
+
// @ts-ignore
|
|
2590
|
+
line_deltas.get(line).delta += delta;
|
|
2591
|
+
}
|
|
2456
2592
|
|
|
2457
|
-
|
|
2458
|
-
|
|
2593
|
+
return replacement;
|
|
2594
|
+
},
|
|
2595
|
+
);
|
|
2459
2596
|
|
|
2460
2597
|
post_processing_changes = line_deltas;
|
|
2461
2598
|
}
|
|
@@ -70,26 +70,6 @@ export function convert_source_map_to_mappings(ast, source, generated_code, esra
|
|
|
70
70
|
return line_offsets[line - 1] + column;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
// Map to track capitalized names: original name -> capitalized name
|
|
74
|
-
/** @type {Map<string, string>} */
|
|
75
|
-
const capitalized_names = new Map();
|
|
76
|
-
// Reverse map: capitalized name -> original name
|
|
77
|
-
/** @type {Map<string, string>} */
|
|
78
|
-
const reverse_capitalized_names = new Map();
|
|
79
|
-
|
|
80
|
-
// Pre-walk to collect capitalized names from JSXElement nodes (transformed AST)
|
|
81
|
-
// These are identifiers that are used as dynamic components/elements
|
|
82
|
-
walk(ast, null, {
|
|
83
|
-
_(node, { next }) {
|
|
84
|
-
// Check JSXElement nodes with metadata (preserved from Element nodes)
|
|
85
|
-
if (node.type === 'JSXElement' && node.metadata?.ts_name && node.metadata?.original_name) {
|
|
86
|
-
capitalized_names.set(node.metadata.original_name, node.metadata.ts_name);
|
|
87
|
-
reverse_capitalized_names.set(node.metadata.ts_name, node.metadata.original_name);
|
|
88
|
-
}
|
|
89
|
-
next();
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
73
|
const adjusted_source_map = build_source_to_generated_map(
|
|
94
74
|
esrap_source_map,
|
|
95
75
|
post_processing_changes,
|
|
@@ -110,51 +90,30 @@ export function convert_source_map_to_mappings(ast, source, generated_code, esra
|
|
|
110
90
|
walk(ast, null, {
|
|
111
91
|
_(node, { visit }) {
|
|
112
92
|
// Collect key node types: Identifiers, Literals, and JSX Elements
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
93
|
+
if (node.type === 'Identifier') {
|
|
94
|
+
// Only create mappings for identifiers with location info (from source)
|
|
95
|
+
// Synthesized identifiers (created by builders) don't have .loc and are skipped
|
|
96
|
+
if (node.name && node.loc) {
|
|
116
97
|
// Check if this identifier has tracked_shorthand metadata (e.g., TrackedMap -> #Map)
|
|
117
98
|
if (node.metadata?.tracked_shorthand) {
|
|
118
99
|
tokens.push({ source: node.metadata.tracked_shorthand, generated: node.name, loc: node.loc });
|
|
100
|
+
} else if (node.metadata?.is_capitalized) {
|
|
101
|
+
// This identifier was capitalized during transformation
|
|
102
|
+
// Map the original lowercase name to the capitalized generated name
|
|
103
|
+
tokens.push({ source: node.metadata.original_name, generated: node.name, loc: node.loc });
|
|
119
104
|
} else {
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
if (original_name) {
|
|
123
|
-
// This is a capitalized name in generated code, map to lowercase in source
|
|
124
|
-
tokens.push({ source: original_name, generated: node.name, loc: node.loc });
|
|
125
|
-
} else {
|
|
126
|
-
// Check if this identifier should be capitalized (forward lookup)
|
|
127
|
-
const cap_name = capitalized_names.get(node.name);
|
|
128
|
-
if (cap_name) {
|
|
129
|
-
tokens.push({ source: node.name, generated: cap_name, loc: node.loc });
|
|
130
|
-
} else {
|
|
131
|
-
// Check if this identifier should be capitalized (forward lookup)
|
|
132
|
-
const cap_name = capitalized_names.get(node.name);
|
|
133
|
-
if (cap_name) {
|
|
134
|
-
tokens.push({ source: node.name, generated: cap_name, loc: node.loc });
|
|
135
|
-
} else {
|
|
136
|
-
// Store token with .loc for accurate positioning
|
|
137
|
-
tokens.push({ source: node.name, generated: node.name, loc: node.loc });
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
105
|
+
// No transformation - source and generated names are the same
|
|
106
|
+
tokens.push({ source: node.name, generated: node.name, loc: node.loc });
|
|
141
107
|
}
|
|
142
108
|
}
|
|
143
109
|
return; // Leaf node, don't traverse further
|
|
144
|
-
} else if (node.type === 'JSXIdentifier'
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
tokens.push({ source: originalName, generated: node.name, loc: node.loc });
|
|
110
|
+
} else if (node.type === 'JSXIdentifier') {
|
|
111
|
+
// JSXIdentifiers can also be capitalized (for dynamic components)
|
|
112
|
+
if (node.loc && node.name) {
|
|
113
|
+
if (node.metadata?.is_capitalized) {
|
|
114
|
+
tokens.push({ source: node.metadata.original_name, generated: node.name, loc: node.loc });
|
|
150
115
|
} else {
|
|
151
|
-
|
|
152
|
-
const capitalizedName = capitalized_names.get(node.name);
|
|
153
|
-
if (capitalizedName) {
|
|
154
|
-
tokens.push({ source: node.name, generated: capitalizedName, loc: node.loc });
|
|
155
|
-
} else {
|
|
156
|
-
tokens.push({ source: node.name, generated: node.name, loc: node.loc });
|
|
157
|
-
}
|
|
116
|
+
tokens.push({ source: node.name, generated: node.name, loc: node.loc });
|
|
158
117
|
}
|
|
159
118
|
}
|
|
160
119
|
return; // Leaf node, don't traverse further
|
|
@@ -242,11 +201,18 @@ export function convert_source_map_to_mappings(ast, source, generated_code, esra
|
|
|
242
201
|
return;
|
|
243
202
|
} else if (node.type === 'JSXAttribute') {
|
|
244
203
|
// Visit name and value in source order
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
204
|
+
// For shorthand attributes ({ count }), key and value are the same node, only visit once
|
|
205
|
+
if (node.shorthand) {
|
|
206
|
+
if (node.value) {
|
|
207
|
+
visit(node.value);
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
if (node.name) {
|
|
211
|
+
visit(node.name);
|
|
212
|
+
}
|
|
213
|
+
if (node.value) {
|
|
214
|
+
visit(node.value);
|
|
215
|
+
}
|
|
250
216
|
}
|
|
251
217
|
return;
|
|
252
218
|
} else if (node.type === 'JSXSpreadAttribute') {
|
|
@@ -282,19 +248,10 @@ export function convert_source_map_to_mappings(ast, source, generated_code, esra
|
|
|
282
248
|
// 3. Push closing tag name (not visited by AST walker)
|
|
283
249
|
if (!node.openingElement?.selfClosing && node.closingElement?.name?.type === 'JSXIdentifier') {
|
|
284
250
|
const closingNameNode = node.closingElement.name;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const originalName = reverse_capitalized_names.get(closingName);
|
|
288
|
-
if (originalName) {
|
|
289
|
-
tokens.push({ source: originalName, generated: closingName, loc: closingNameNode.loc });
|
|
251
|
+
if (closingNameNode.metadata?.is_capitalized) {
|
|
252
|
+
tokens.push({ source: closingNameNode.metadata.original_name, generated: closingNameNode.name, loc: closingNameNode.loc });
|
|
290
253
|
} else {
|
|
291
|
-
|
|
292
|
-
const capitalizedName = capitalized_names.get(closingName);
|
|
293
|
-
if (capitalizedName) {
|
|
294
|
-
tokens.push({ source: closingName, generated: capitalizedName, loc: closingNameNode.loc });
|
|
295
|
-
} else {
|
|
296
|
-
tokens.push({ source: closingName, generated: closingName, loc: closingNameNode.loc });
|
|
297
|
-
}
|
|
254
|
+
tokens.push({ source: closingNameNode.name, generated: closingNameNode.name, loc: closingNameNode.loc });
|
|
298
255
|
}
|
|
299
256
|
}
|
|
300
257
|
|