@barefootjs/jsx 0.32.0 → 0.33.1
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/adapters/dangerous-inner-html.d.ts.map +1 -1
- package/dist/adapters/parsed-expr-emitter.d.ts +22 -0
- package/dist/adapters/parsed-expr-emitter.d.ts.map +1 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/expression-parser.d.ts +29 -6
- package/dist/expression-parser.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +274 -80
- package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-inner-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-loop-child-arm.d.ts +8 -0
- package/dist/ir-to-client-js/control-flow/plan/build-loop-child-arm.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-reactive-effects.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/inner-loop.d.ts +12 -0
- package/dist/ir-to-client-js/control-flow/plan/inner-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/inner-loop.d.ts +1 -0
- package/dist/ir-to-client-js/control-flow/stringify/inner-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts.map +1 -1
- package/dist/ir-to-client-js/element-refs.d.ts.map +1 -1
- package/dist/ir-to-client-js/emit-reactive.d.ts.map +1 -1
- package/dist/ir-to-client-js/imports.d.ts +2 -2
- package/dist/ir-to-client-js/imports.d.ts.map +1 -1
- package/dist/ir-to-client-js/phases/provider-and-child-inits.d.ts.map +1 -1
- package/dist/ir-to-client-js/types.d.ts +21 -0
- package/dist/ir-to-client-js/types.d.ts.map +1 -1
- package/dist/query-href-lowering.d.ts.map +1 -1
- package/dist/ssr-seed-plan.d.ts.map +1 -1
- package/dist/static-literal.d.ts.map +1 -1
- package/dist/to-locale-date-lowering.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +2 -4
- package/src/__tests__/child-components-in-map.test.ts +11 -3
- package/src/__tests__/client-js-generation.test.ts +37 -1
- package/src/__tests__/expression-parser.test.ts +43 -6
- package/src/__tests__/inline-jsx-callback.test.ts +55 -0
- package/src/__tests__/ir-jsx-props.test.ts +148 -0
- package/src/__tests__/issue-2705-branch-inner-loop-container.test.ts +91 -0
- package/src/__tests__/markup-prop-brand.test.ts +49 -0
- package/src/__tests__/nested-loop-conditional.test.ts +20 -11
- package/src/__tests__/return-through-local-var.test.ts +269 -0
- package/src/__tests__/serialize-parsed-expr.test.ts +17 -3
- package/src/__tests__/ssr-defaults.test.ts +41 -0
- package/src/__tests__/ssr-seed-plan.test.ts +12 -2
- package/src/adapters/dangerous-inner-html.ts +1 -0
- package/src/adapters/parsed-expr-emitter.ts +49 -3
- package/src/analyzer.ts +71 -0
- package/src/errors.ts +17 -1
- package/src/expression-parser.ts +200 -89
- package/src/index.ts +2 -2
- package/src/ir-to-client-js/collect-elements.ts +31 -20
- package/src/ir-to-client-js/control-flow/plan/build-inner-loop.ts +19 -0
- package/src/ir-to-client-js/control-flow/plan/build-loop-child-arm.ts +22 -3
- package/src/ir-to-client-js/control-flow/plan/build-reactive-effects.ts +5 -2
- package/src/ir-to-client-js/control-flow/plan/inner-loop.ts +12 -0
- package/src/ir-to-client-js/control-flow/stringify/inner-loop.ts +9 -0
- package/src/ir-to-client-js/control-flow/stringify/lazy-row.ts +7 -1
- package/src/ir-to-client-js/element-refs.ts +8 -0
- package/src/ir-to-client-js/emit-reactive.ts +91 -23
- package/src/ir-to-client-js/imports.ts +5 -0
- package/src/ir-to-client-js/index.ts +4 -0
- package/src/ir-to-client-js/phases/provider-and-child-inits.ts +5 -1
- package/src/ir-to-client-js/types.ts +21 -0
- package/src/jsx-to-ir.ts +161 -9
- package/src/query-href-lowering.ts +4 -0
- package/src/rich-type-refusal.ts +1 -1
- package/src/ssr-defaults.ts +51 -2
- package/src/ssr-seed-plan.ts +20 -3
- package/src/static-literal.ts +15 -1
- package/src/to-locale-date-lowering.ts +4 -0
package/dist/index.js
CHANGED
|
@@ -523,7 +523,7 @@ function convertNode(node, raw) {
|
|
|
523
523
|
}
|
|
524
524
|
if (n === undefined || Number.isNaN(n)) {
|
|
525
525
|
const parsedDepth = convertNode(depthNode, raw);
|
|
526
|
-
if (checkSupport(parsedDepth).supported) {
|
|
526
|
+
if (checkSupport(parsedDepth, "rendered").supported) {
|
|
527
527
|
depthExpr = parsedDepth;
|
|
528
528
|
flatDepth = 1;
|
|
529
529
|
} else {
|
|
@@ -617,10 +617,12 @@ function convertNode(node, raw) {
|
|
|
617
617
|
const k = objectLiteralKeyName(prop.name);
|
|
618
618
|
if (k === null)
|
|
619
619
|
return { kind: "unsupported", raw, reason: `Unsupported syntax: ${ts2.SyntaxKind[node.kind]}` };
|
|
620
|
-
properties.push({ key: k.key, keyKind: k.keyKind, shorthand: false, value: convertNode(prop.initializer, raw) });
|
|
620
|
+
properties.push({ kind: "prop", key: k.key, keyKind: k.keyKind, shorthand: false, value: convertNode(prop.initializer, raw) });
|
|
621
621
|
} else if (ts2.isShorthandPropertyAssignment(prop)) {
|
|
622
622
|
const key = prop.name.text;
|
|
623
|
-
properties.push({ key, keyKind: "identifier", shorthand: true, value: { kind: "identifier", name: key } });
|
|
623
|
+
properties.push({ kind: "prop", key, keyKind: "identifier", shorthand: true, value: { kind: "identifier", name: key } });
|
|
624
|
+
} else if (ts2.isSpreadAssignment(prop)) {
|
|
625
|
+
properties.push({ kind: "spread", expr: convertNode(prop.expression, raw) });
|
|
624
626
|
} else {
|
|
625
627
|
return { kind: "unsupported", raw, reason: `Unsupported syntax: ${ts2.SyntaxKind[node.kind]}` };
|
|
626
628
|
}
|
|
@@ -1300,14 +1302,26 @@ function getUnaryOperatorString(op) {
|
|
|
1300
1302
|
}
|
|
1301
1303
|
}
|
|
1302
1304
|
function isSupported(expr) {
|
|
1303
|
-
return checkSupport(expr);
|
|
1305
|
+
return checkSupport(expr, "rendered");
|
|
1304
1306
|
}
|
|
1305
|
-
function
|
|
1307
|
+
function isSupportedValue(expr) {
|
|
1308
|
+
return checkSupport(expr, "value");
|
|
1309
|
+
}
|
|
1310
|
+
function checkSupport(expr, pos) {
|
|
1306
1311
|
switch (expr.kind) {
|
|
1307
1312
|
case "unsupported":
|
|
1308
1313
|
return { supported: false, reason: expr.reason };
|
|
1309
|
-
case "object-literal":
|
|
1310
|
-
|
|
1314
|
+
case "object-literal": {
|
|
1315
|
+
if (pos !== "value") {
|
|
1316
|
+
return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
|
|
1317
|
+
}
|
|
1318
|
+
for (const prop of expr.properties) {
|
|
1319
|
+
const propSupport = checkSupport(prop.kind === "spread" ? prop.expr : prop.value, pos);
|
|
1320
|
+
if (!propSupport.supported)
|
|
1321
|
+
return propSupport;
|
|
1322
|
+
}
|
|
1323
|
+
return { supported: true, level: "L2" };
|
|
1324
|
+
}
|
|
1311
1325
|
case "identifier":
|
|
1312
1326
|
return { supported: true, level: "L1" };
|
|
1313
1327
|
case "literal":
|
|
@@ -1317,7 +1331,7 @@ function checkSupport(expr) {
|
|
|
1317
1331
|
return { supported: false, reason: "Standalone arrow functions / regex literals are not supported" };
|
|
1318
1332
|
case "array-literal": {
|
|
1319
1333
|
for (const el of expr.elements) {
|
|
1320
|
-
const elSupport = checkSupport(el);
|
|
1334
|
+
const elSupport = checkSupport(el, pos);
|
|
1321
1335
|
if (!elSupport.supported)
|
|
1322
1336
|
return elSupport;
|
|
1323
1337
|
}
|
|
@@ -1330,16 +1344,16 @@ function checkSupport(expr) {
|
|
|
1330
1344
|
reason: `String.prototype.${expr.method} supports only a string pattern + string replacement (the regex form is deferred); use a string pattern or wrap the expression in /* @client */`
|
|
1331
1345
|
};
|
|
1332
1346
|
}
|
|
1333
|
-
const objSupport = checkSupport(expr.object);
|
|
1347
|
+
const objSupport = checkSupport(expr.object, pos);
|
|
1334
1348
|
if (!objSupport.supported)
|
|
1335
1349
|
return objSupport;
|
|
1336
1350
|
for (const arg of expr.args) {
|
|
1337
|
-
const argSupport = checkSupport(arg);
|
|
1351
|
+
const argSupport = checkSupport(arg, pos);
|
|
1338
1352
|
if (!argSupport.supported)
|
|
1339
1353
|
return argSupport;
|
|
1340
1354
|
}
|
|
1341
1355
|
if (expr.method === "flat" && expr.depthExpr) {
|
|
1342
|
-
const depthSupport = checkSupport(expr.depthExpr);
|
|
1356
|
+
const depthSupport = checkSupport(expr.depthExpr, pos);
|
|
1343
1357
|
if (!depthSupport.supported)
|
|
1344
1358
|
return depthSupport;
|
|
1345
1359
|
}
|
|
@@ -1348,10 +1362,10 @@ function checkSupport(expr) {
|
|
|
1348
1362
|
case "call": {
|
|
1349
1363
|
const cb = asCallbackMethodCall(expr);
|
|
1350
1364
|
if (cb) {
|
|
1351
|
-
const objSupport = checkSupport(cb.object);
|
|
1365
|
+
const objSupport = checkSupport(cb.object, pos);
|
|
1352
1366
|
if (!objSupport.supported)
|
|
1353
1367
|
return objSupport;
|
|
1354
|
-
const bodySupport = checkSupport(cb.arrow.body);
|
|
1368
|
+
const bodySupport = checkSupport(cb.arrow.body, pos);
|
|
1355
1369
|
if (!bodySupport.supported) {
|
|
1356
1370
|
return {
|
|
1357
1371
|
supported: false,
|
|
@@ -1360,13 +1374,13 @@ function checkSupport(expr) {
|
|
|
1360
1374
|
};
|
|
1361
1375
|
}
|
|
1362
1376
|
for (const rest of cb.args) {
|
|
1363
|
-
const restSupport = checkSupport(rest);
|
|
1377
|
+
const restSupport = checkSupport(rest, pos);
|
|
1364
1378
|
if (!restSupport.supported)
|
|
1365
1379
|
return restSupport;
|
|
1366
1380
|
}
|
|
1367
1381
|
return { supported: true, level: "L5" };
|
|
1368
1382
|
}
|
|
1369
|
-
const calleeSupport = checkSupport(expr.callee);
|
|
1383
|
+
const calleeSupport = checkSupport(expr.callee, pos);
|
|
1370
1384
|
if (!calleeSupport.supported) {
|
|
1371
1385
|
return calleeSupport;
|
|
1372
1386
|
}
|
|
@@ -1385,7 +1399,7 @@ function checkSupport(expr) {
|
|
|
1385
1399
|
return { supported: true, level: "L1" };
|
|
1386
1400
|
}
|
|
1387
1401
|
for (const arg of expr.args) {
|
|
1388
|
-
const argSupport = checkSupport(arg);
|
|
1402
|
+
const argSupport = checkSupport(arg, pos);
|
|
1389
1403
|
if (!argSupport.supported) {
|
|
1390
1404
|
return argSupport;
|
|
1391
1405
|
}
|
|
@@ -1393,7 +1407,7 @@ function checkSupport(expr) {
|
|
|
1393
1407
|
return { supported: true, level: "L2" };
|
|
1394
1408
|
}
|
|
1395
1409
|
case "member": {
|
|
1396
|
-
const objSupport = checkSupport(expr.object);
|
|
1410
|
+
const objSupport = checkSupport(expr.object, pos);
|
|
1397
1411
|
if (!objSupport.supported) {
|
|
1398
1412
|
return objSupport;
|
|
1399
1413
|
}
|
|
@@ -1403,19 +1417,19 @@ function checkSupport(expr) {
|
|
|
1403
1417
|
return { supported: true, level: "L2" };
|
|
1404
1418
|
}
|
|
1405
1419
|
case "index-access": {
|
|
1406
|
-
const objSupport = checkSupport(expr.object);
|
|
1420
|
+
const objSupport = checkSupport(expr.object, pos);
|
|
1407
1421
|
if (!objSupport.supported)
|
|
1408
1422
|
return objSupport;
|
|
1409
|
-
const indexSupport = checkSupport(expr.index);
|
|
1423
|
+
const indexSupport = checkSupport(expr.index, pos);
|
|
1410
1424
|
if (!indexSupport.supported)
|
|
1411
1425
|
return indexSupport;
|
|
1412
1426
|
return { supported: true, level: "L2" };
|
|
1413
1427
|
}
|
|
1414
1428
|
case "binary": {
|
|
1415
|
-
const leftSupport = checkSupport(expr.left);
|
|
1429
|
+
const leftSupport = checkSupport(expr.left, pos);
|
|
1416
1430
|
if (!leftSupport.supported)
|
|
1417
1431
|
return leftSupport;
|
|
1418
|
-
const rightSupport = checkSupport(expr.right);
|
|
1432
|
+
const rightSupport = checkSupport(expr.right, pos);
|
|
1419
1433
|
if (!rightSupport.supported)
|
|
1420
1434
|
return rightSupport;
|
|
1421
1435
|
if (["===", "==", "!==", "!=", ">", "<", ">=", "<="].includes(expr.op)) {
|
|
@@ -1427,7 +1441,7 @@ function checkSupport(expr) {
|
|
|
1427
1441
|
return { supported: false, reason: `Unknown operator: ${expr.op}` };
|
|
1428
1442
|
}
|
|
1429
1443
|
case "unary": {
|
|
1430
|
-
const argSupport = checkSupport(expr.argument);
|
|
1444
|
+
const argSupport = checkSupport(expr.argument, pos);
|
|
1431
1445
|
if (!argSupport.supported)
|
|
1432
1446
|
return argSupport;
|
|
1433
1447
|
if (expr.op === "!") {
|
|
@@ -1439,25 +1453,25 @@ function checkSupport(expr) {
|
|
|
1439
1453
|
return { supported: false, reason: `Unsupported unary operator: ${expr.op}` };
|
|
1440
1454
|
}
|
|
1441
1455
|
case "logical": {
|
|
1442
|
-
const leftSupport = checkSupport(expr.left);
|
|
1456
|
+
const leftSupport = checkSupport(expr.left, pos);
|
|
1443
1457
|
if (!leftSupport.supported)
|
|
1444
1458
|
return leftSupport;
|
|
1445
1459
|
if (expr.op === "??" && expr.right.kind === "object-literal" && expr.right.properties.length === 0) {
|
|
1446
1460
|
return { supported: true, level: "L4" };
|
|
1447
1461
|
}
|
|
1448
|
-
const rightSupport = checkSupport(expr.right);
|
|
1462
|
+
const rightSupport = checkSupport(expr.right, pos);
|
|
1449
1463
|
if (!rightSupport.supported)
|
|
1450
1464
|
return rightSupport;
|
|
1451
1465
|
return { supported: true, level: "L4" };
|
|
1452
1466
|
}
|
|
1453
1467
|
case "conditional": {
|
|
1454
|
-
const testSupport = checkSupport(expr.test);
|
|
1468
|
+
const testSupport = checkSupport(expr.test, pos);
|
|
1455
1469
|
if (!testSupport.supported)
|
|
1456
1470
|
return testSupport;
|
|
1457
|
-
const consSupport = checkSupport(expr.consequent);
|
|
1471
|
+
const consSupport = checkSupport(expr.consequent, pos);
|
|
1458
1472
|
if (!consSupport.supported)
|
|
1459
1473
|
return consSupport;
|
|
1460
|
-
const altSupport = checkSupport(expr.alternate);
|
|
1474
|
+
const altSupport = checkSupport(expr.alternate, pos);
|
|
1461
1475
|
if (!altSupport.supported)
|
|
1462
1476
|
return altSupport;
|
|
1463
1477
|
return { supported: true, level: "L4" };
|
|
@@ -1465,7 +1479,7 @@ function checkSupport(expr) {
|
|
|
1465
1479
|
case "template-literal": {
|
|
1466
1480
|
for (const part of expr.parts) {
|
|
1467
1481
|
if (part.type === "expression") {
|
|
1468
|
-
const partSupport = checkSupport(part.expr);
|
|
1482
|
+
const partSupport = checkSupport(part.expr, pos);
|
|
1469
1483
|
if (!partSupport.supported)
|
|
1470
1484
|
return partSupport;
|
|
1471
1485
|
}
|
|
@@ -1618,7 +1632,7 @@ function isPureInit(e, pureCallNames) {
|
|
|
1618
1632
|
case "array-literal":
|
|
1619
1633
|
return e.elements.every(pure);
|
|
1620
1634
|
case "object-literal":
|
|
1621
|
-
return e.properties.every((p) => pure(p.value));
|
|
1635
|
+
return e.properties.every((p) => pure(p.kind === "spread" ? p.expr : p.value));
|
|
1622
1636
|
case "call":
|
|
1623
1637
|
return e.callee.kind === "identifier" && e.args.length === 0 && pureCallNames !== undefined && pureCallNames.has(e.callee.name);
|
|
1624
1638
|
case "array-method":
|
|
@@ -1672,7 +1686,7 @@ function usesPerPath(name, expr) {
|
|
|
1672
1686
|
}
|
|
1673
1687
|
return add(walk(e.object), sum(e.args));
|
|
1674
1688
|
case "object-literal":
|
|
1675
|
-
return sum(e.properties.map((p) => p.value));
|
|
1689
|
+
return sum(e.properties.map((p) => p.kind === "spread" ? p.expr : p.value));
|
|
1676
1690
|
case "arrow":
|
|
1677
1691
|
return walk(e.body).max > 0 ? { min: 0, max: Number.POSITIVE_INFINITY } : { min: 0, max: 0 };
|
|
1678
1692
|
}
|
|
@@ -1738,7 +1752,7 @@ function inlineBinding(expr, name, value) {
|
|
|
1738
1752
|
case "object-literal":
|
|
1739
1753
|
return {
|
|
1740
1754
|
kind: "object-literal",
|
|
1741
|
-
properties: e.properties.map((p) => ({ ...p, value: walk(p.value, enclosing) })
|
|
1755
|
+
properties: e.properties.map((p) => p.kind === "spread" ? { ...p, expr: walk(p.expr, enclosing) } : { ...p, value: walk(p.value, enclosing) }),
|
|
1742
1756
|
raw: e.raw
|
|
1743
1757
|
};
|
|
1744
1758
|
case "literal":
|
|
@@ -1971,7 +1985,7 @@ function materializeGetterCalls(expr, names) {
|
|
|
1971
1985
|
return {
|
|
1972
1986
|
kind: "object-literal",
|
|
1973
1987
|
raw: expr.raw,
|
|
1974
|
-
properties: expr.properties.map((p) => ({ ...p, value: rw(p.value) })
|
|
1988
|
+
properties: expr.properties.map((p) => p.kind === "spread" ? { ...p, expr: rw(p.expr) } : { ...p, value: rw(p.value) })
|
|
1975
1989
|
};
|
|
1976
1990
|
case "arrow":
|
|
1977
1991
|
return { kind: "arrow", params: expr.params, body: rw(expr.body) };
|
|
@@ -2029,7 +2043,7 @@ function freeVarsInBody(body, params) {
|
|
|
2029
2043
|
return;
|
|
2030
2044
|
case "object-literal":
|
|
2031
2045
|
for (const p of e.properties)
|
|
2032
|
-
visit(p.value, bound);
|
|
2046
|
+
visit(p.kind === "spread" ? p.expr : p.value, bound);
|
|
2033
2047
|
return;
|
|
2034
2048
|
case "array-method":
|
|
2035
2049
|
if (e.method === "includes" || e.method === "join") {
|
|
@@ -2104,7 +2118,7 @@ function freeIdentifiers(expr) {
|
|
|
2104
2118
|
return true;
|
|
2105
2119
|
case "object-literal":
|
|
2106
2120
|
for (const p of e.properties)
|
|
2107
|
-
if (!visit(p.value, bound))
|
|
2121
|
+
if (!visit(p.kind === "spread" ? p.expr : p.value, bound))
|
|
2108
2122
|
return false;
|
|
2109
2123
|
return true;
|
|
2110
2124
|
case "arrow": {
|
|
@@ -2251,10 +2265,17 @@ function toEvalNode(e) {
|
|
|
2251
2265
|
case "object-literal": {
|
|
2252
2266
|
const properties = [];
|
|
2253
2267
|
for (const p of e.properties) {
|
|
2268
|
+
if (p.kind === "spread") {
|
|
2269
|
+
const spreadExpr = toEvalNode(p.expr);
|
|
2270
|
+
if (!spreadExpr)
|
|
2271
|
+
return null;
|
|
2272
|
+
properties.push({ kind: "spread", expr: spreadExpr });
|
|
2273
|
+
continue;
|
|
2274
|
+
}
|
|
2254
2275
|
const value = toEvalNode(p.value);
|
|
2255
2276
|
if (!value)
|
|
2256
2277
|
return null;
|
|
2257
|
-
properties.push({ key: p.key, value });
|
|
2278
|
+
properties.push({ kind: "prop", key: p.key, value });
|
|
2258
2279
|
}
|
|
2259
2280
|
return { kind: "object-literal", properties };
|
|
2260
2281
|
}
|
|
@@ -5613,6 +5634,7 @@ var ErrorCodes = {
|
|
|
5613
5634
|
MISSING_KEY_IN_LIST: "BF023",
|
|
5614
5635
|
MISSING_KEY_IN_NESTED_LIST: "BF024",
|
|
5615
5636
|
UNSUPPORTED_DESTRUCTURE_REST: "BF025",
|
|
5637
|
+
RETURN_VALUE_NOT_JSX: "BF027",
|
|
5616
5638
|
PROPS_DESTRUCTURING: "BF043",
|
|
5617
5639
|
SIGNAL_GETTER_NOT_CALLED: "BF044",
|
|
5618
5640
|
JSX_IN_LOCAL_FUNCTION: "BF045",
|
|
@@ -5644,6 +5666,7 @@ var errorMessages = {
|
|
|
5644
5666
|
[ErrorCodes.MISSING_KEY_IN_LIST]: "Missing key attribute in list rendering. Add a key prop for efficient updates",
|
|
5645
5667
|
[ErrorCodes.MISSING_KEY_IN_NESTED_LIST]: "Nested .map() loop requires key attribute for event delegation. Add a key prop to elements in the inner loop",
|
|
5646
5668
|
[ErrorCodes.UNSUPPORTED_DESTRUCTURE_REST]: "Computed property key in .map() callback destructure is not supported. Rewrite the callback to destructure explicit bindings (e.g., `({ a, b }) => ...`) so the compiler can rewrite references to per-item signal accessors.",
|
|
5669
|
+
[ErrorCodes.RETURN_VALUE_NOT_JSX]: "Component's return value is not recognized as JSX — return the JSX expression directly instead of binding it to a local variable first.",
|
|
5647
5670
|
[ErrorCodes.PROPS_DESTRUCTURING]: "Props destructuring in function parameters breaks reactivity. Use props object directly.",
|
|
5648
5671
|
[ErrorCodes.SIGNAL_GETTER_NOT_CALLED]: "Signal/memo getter passed without calling it. Use getter() to read the value.",
|
|
5649
5672
|
[ErrorCodes.JSX_IN_LOCAL_FUNCTION]: "Local function returns JSX but cannot be inlined. Extract it as a top-level PascalCase component or use a single return statement.",
|
|
@@ -6285,6 +6308,14 @@ function visitComponentBody(node, ctx) {
|
|
|
6285
6308
|
}
|
|
6286
6309
|
}
|
|
6287
6310
|
if (isTopLevel && (ts9.isTryStatement(node) || ts9.isSwitchStatement(node) || ts9.isForStatement(node) || ts9.isForInStatement(node) || ts9.isForOfStatement(node) || ts9.isWhileStatement(node) || ts9.isDoStatement(node) || ts9.isThrowStatement(node) || ts9.isBlock(node) && node.parent === ctx.componentBodyBlock)) {
|
|
6311
|
+
if (ts9.isBlock(node)) {
|
|
6312
|
+
const returnedLocal = findBlockBodyReturnedJsxLocalName(node);
|
|
6313
|
+
if (returnedLocal) {
|
|
6314
|
+
ctx.errors.push(createError(ErrorCodes.RETURN_VALUE_NOT_JSX, getSourceLocation(node, ctx.sourceFile, ctx.filePath), {
|
|
6315
|
+
message: `Component '${ctx.componentName ?? "(unknown)"}' return value is not recognized ` + `as JSX — return the JSX expression directly instead of binding it to a local ` + `variable first (\`return ${returnedLocal}\` after \`const ${returnedLocal} = ` + `<jsx/>\` is not resolved at return position).`
|
|
6316
|
+
}));
|
|
6317
|
+
}
|
|
6318
|
+
}
|
|
6288
6319
|
collectInitStatement(node, ctx);
|
|
6289
6320
|
return;
|
|
6290
6321
|
}
|
|
@@ -6320,6 +6351,31 @@ function unwrapJsxTransparent(expr) {
|
|
|
6320
6351
|
}
|
|
6321
6352
|
return current;
|
|
6322
6353
|
}
|
|
6354
|
+
function findBlockBodyReturnedJsxLocalName(block) {
|
|
6355
|
+
const stmts = block.statements;
|
|
6356
|
+
const last = stmts[stmts.length - 1];
|
|
6357
|
+
if (!last || !ts9.isReturnStatement(last) || !last.expression)
|
|
6358
|
+
return null;
|
|
6359
|
+
const returned = unwrapJsxTransparent(last.expression);
|
|
6360
|
+
if (!ts9.isIdentifier(returned))
|
|
6361
|
+
return null;
|
|
6362
|
+
const name = returned.text;
|
|
6363
|
+
for (const stmt of stmts) {
|
|
6364
|
+
if (!ts9.isVariableStatement(stmt))
|
|
6365
|
+
continue;
|
|
6366
|
+
for (const decl of stmt.declarationList.declarations) {
|
|
6367
|
+
if (!ts9.isIdentifier(decl.name) || decl.name.text !== name || !decl.initializer)
|
|
6368
|
+
continue;
|
|
6369
|
+
let init = decl.initializer;
|
|
6370
|
+
while (ts9.isParenthesizedExpression(init))
|
|
6371
|
+
init = init.expression;
|
|
6372
|
+
if (ts9.isJsxElement(init) || ts9.isJsxSelfClosingElement(init) || ts9.isJsxFragment(init) || initializerShapeContainsJsx(init) || isMapLikeCallWithJsx(init)) {
|
|
6373
|
+
return name;
|
|
6374
|
+
}
|
|
6375
|
+
}
|
|
6376
|
+
}
|
|
6377
|
+
return null;
|
|
6378
|
+
}
|
|
6323
6379
|
function extractJsxFromExpression(expr) {
|
|
6324
6380
|
const inner = unwrapJsxTransparent(expr);
|
|
6325
6381
|
if (ts9.isJsxElement(inner) || ts9.isJsxFragment(inner) || ts9.isJsxSelfClosingElement(inner)) {
|
|
@@ -10114,6 +10170,8 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
|
10114
10170
|
let tz = null;
|
|
10115
10171
|
const probeOptions = {};
|
|
10116
10172
|
for (const prop of options.properties) {
|
|
10173
|
+
if (prop.kind === "spread")
|
|
10174
|
+
return null;
|
|
10117
10175
|
if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
|
|
10118
10176
|
return null;
|
|
10119
10177
|
const value = String(prop.value.value);
|
|
@@ -10687,8 +10745,14 @@ function buildIRRoot(analyzer) {
|
|
|
10687
10745
|
}
|
|
10688
10746
|
ctx.isRoot = false;
|
|
10689
10747
|
const ir = transformJsxExpression(jsxReturn, ctx);
|
|
10690
|
-
if (ir === null)
|
|
10748
|
+
if (ir === null) {
|
|
10749
|
+
if (ts13.isIdentifier(jsxReturn) && (analyzer.jsxConstants.has(jsxReturn.text) || analyzer.inlineableJsxConsts.has(jsxReturn.text))) {
|
|
10750
|
+
analyzer.errors.push(createError(ErrorCodes.RETURN_VALUE_NOT_JSX, getSourceLocation(jsxReturn, analyzer.sourceFile, analyzer.filePath), {
|
|
10751
|
+
message: `Component '${analyzer.componentName ?? "(unknown)"}' return value is not recognized ` + `as JSX — return the JSX expression directly instead of binding it to a local variable ` + `first (\`return ${jsxReturn.text}\` after \`const ${jsxReturn.text} = <jsx/>\` is not ` + `resolved at return position).`
|
|
10752
|
+
}));
|
|
10753
|
+
}
|
|
10691
10754
|
return null;
|
|
10755
|
+
}
|
|
10692
10756
|
return wrapInScopeElement(ir);
|
|
10693
10757
|
}
|
|
10694
10758
|
function needsScopeWrapper(ir) {
|
|
@@ -11879,7 +11943,10 @@ function resolveCallbackMethodFunctionReferences(expr, analyzer, bound = EMPTY_B
|
|
|
11879
11943
|
...e.method === "flat" && e.depthExpr ? { depthExpr: visit2(e.depthExpr, bound2) } : {}
|
|
11880
11944
|
};
|
|
11881
11945
|
case "object-literal":
|
|
11882
|
-
return {
|
|
11946
|
+
return {
|
|
11947
|
+
...e,
|
|
11948
|
+
properties: e.properties.map((p) => p.kind === "spread" ? { ...p, expr: visit2(p.expr, bound2) } : { ...p, value: visit2(p.value, bound2) })
|
|
11949
|
+
};
|
|
11883
11950
|
case "arrow": {
|
|
11884
11951
|
const inner = e.params.length === 0 ? bound2 : new Set([...bound2, ...e.params]);
|
|
11885
11952
|
return { ...e, body: visit2(e.body, inner) };
|
|
@@ -13800,6 +13867,35 @@ function getStringValue(node) {
|
|
|
13800
13867
|
}
|
|
13801
13868
|
return null;
|
|
13802
13869
|
}
|
|
13870
|
+
function unwrapTransparentTsWrappers(node) {
|
|
13871
|
+
let n = node;
|
|
13872
|
+
while (ts13.isParenthesizedExpression(n) || ts13.isAsExpression(n) || ts13.isSatisfiesExpression(n) || ts13.isNonNullExpression(n)) {
|
|
13873
|
+
n = n.expression;
|
|
13874
|
+
}
|
|
13875
|
+
return n;
|
|
13876
|
+
}
|
|
13877
|
+
function expressionWrapsJsx(node) {
|
|
13878
|
+
const n = unwrapTransparentTsWrappers(node);
|
|
13879
|
+
if (ts13.isJsxElement(n) || ts13.isJsxSelfClosingElement(n) || ts13.isJsxFragment(n))
|
|
13880
|
+
return true;
|
|
13881
|
+
if (ts13.isConditionalExpression(n)) {
|
|
13882
|
+
return expressionWrapsJsx(n.whenTrue) || expressionWrapsJsx(n.whenFalse);
|
|
13883
|
+
}
|
|
13884
|
+
if (ts13.isArrayLiteralExpression(n)) {
|
|
13885
|
+
return n.elements.some((el) => expressionWrapsJsx(ts13.isSpreadElement(el) ? el.expression : el));
|
|
13886
|
+
}
|
|
13887
|
+
return false;
|
|
13888
|
+
}
|
|
13889
|
+
function reportNakedJsxWrapperProp(ctx, attr, propName, jsxExpr) {
|
|
13890
|
+
const shape = ts13.isConditionalExpression(jsxExpr) ? "a ternary" : "an array literal";
|
|
13891
|
+
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(attr, ctx.sourceFile, ctx.filePath), {
|
|
13892
|
+
message: `Prop '${propName}' is ${shape} wrapping JSX (${jsxExpr.getText(ctx.sourceFile)}). ` + `This shape is not compiled — only a JSX element/fragment given DIRECTLY as the prop value is.`,
|
|
13893
|
+
suggestion: {
|
|
13894
|
+
message: `Move the conditional/array out of the prop position: compute it in a local ` + `const and pass it as the component's children instead of a named prop ` + `(e.g. const ${propName} = ${jsxExpr.getText(ctx.sourceFile)}; <Comp>{${propName}}</Comp>). ` + `Wrapping the ternary/array in a fragment at the prop position ` + `(${propName}={<>{${jsxExpr.getText(ctx.sourceFile)}}</>}) is NOT a safe escape here: it compiles, ` + `but the child's own reactive prop getter receives the branch's HTML unbranded and re-escapes it as ` + `text on the child's very next reactive run, corrupting the DOM (a narrower gap #2651's door ` + `inventory left open — tracked separately).`,
|
|
13895
|
+
escape: [{ kind: "rewrite" }]
|
|
13896
|
+
}
|
|
13897
|
+
}));
|
|
13898
|
+
}
|
|
13803
13899
|
function processComponentProps(attributes, ctx) {
|
|
13804
13900
|
const props = [];
|
|
13805
13901
|
for (const attr of attributes.properties) {
|
|
@@ -13811,10 +13907,7 @@ function processComponentProps(attributes, ctx) {
|
|
|
13811
13907
|
continue;
|
|
13812
13908
|
const name = attr.name.getText(ctx.sourceFile);
|
|
13813
13909
|
if (attr.initializer && ts13.isJsxExpression(attr.initializer) && attr.initializer.expression) {
|
|
13814
|
-
|
|
13815
|
-
while (ts13.isParenthesizedExpression(jsxExpr)) {
|
|
13816
|
-
jsxExpr = jsxExpr.expression;
|
|
13817
|
-
}
|
|
13910
|
+
const jsxExpr = unwrapTransparentTsWrappers(attr.initializer.expression);
|
|
13818
13911
|
if (ts13.isJsxElement(jsxExpr) || ts13.isJsxSelfClosingElement(jsxExpr) || ts13.isJsxFragment(jsxExpr)) {
|
|
13819
13912
|
const prevInsideComponentChildren = ctx.insideComponentChildren;
|
|
13820
13913
|
ctx.insideComponentChildren = true;
|
|
@@ -13829,6 +13922,10 @@ function processComponentProps(attributes, ctx) {
|
|
|
13829
13922
|
continue;
|
|
13830
13923
|
}
|
|
13831
13924
|
}
|
|
13925
|
+
if ((ts13.isConditionalExpression(jsxExpr) || ts13.isArrayLiteralExpression(jsxExpr)) && expressionWrapsJsx(jsxExpr)) {
|
|
13926
|
+
reportNakedJsxWrapperProp(ctx, attr, name, jsxExpr);
|
|
13927
|
+
continue;
|
|
13928
|
+
}
|
|
13832
13929
|
}
|
|
13833
13930
|
let value = getAttributeValue(attr, ctx);
|
|
13834
13931
|
if (value.kind === "template") {
|
|
@@ -14910,10 +15007,11 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
|
|
|
14910
15007
|
const innerPreambleNames = preambleNamesOf(n);
|
|
14911
15008
|
if (ctx) {
|
|
14912
15009
|
for (const child of n.children) {
|
|
14913
|
-
bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx, n.param, n.paramBindings,
|
|
14914
|
-
bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx, n.param, n.paramBindings,
|
|
15010
|
+
bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx, n.param, n.paramBindings, true, innerPreambleNames, n.index));
|
|
15011
|
+
bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx, n.param, n.paramBindings, true, innerPreambleNames, n.index));
|
|
14915
15012
|
bindings.refs.push(...collectLoopChildRefs(child));
|
|
14916
15013
|
}
|
|
15014
|
+
bindings.conditionals.push(...collectLoopChildConditionals({ type: "fragment", children: n.children, loc: n.loc }, ctx, siblingOffsets, n.param, n.paramBindings, innerPreambleNames, n.index));
|
|
14917
15015
|
}
|
|
14918
15016
|
let childComponents;
|
|
14919
15017
|
if (collectBindings) {
|
|
@@ -14937,9 +15035,6 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
|
|
|
14937
15035
|
for (const child of n.children) {
|
|
14938
15036
|
bindings.events.push(...collectLoopChildEventsWithNesting(child));
|
|
14939
15037
|
}
|
|
14940
|
-
if (ctx) {
|
|
14941
|
-
bindings.conditionals.push(...collectLoopChildConditionals({ type: "fragment", children: n.children, loc: n.loc }, ctx, siblingOffsets, n.param, n.paramBindings, innerPreambleNames, n.index));
|
|
14942
|
-
}
|
|
14943
15038
|
}
|
|
14944
15039
|
result.push({
|
|
14945
15040
|
kind: "nested",
|
|
@@ -16075,6 +16170,7 @@ var RUNTIME_IMPORT_CANDIDATES = [
|
|
|
16075
16170
|
"mapArrayLazy",
|
|
16076
16171
|
"patchLeaf",
|
|
16077
16172
|
"createDisposableEffect",
|
|
16173
|
+
"findCondContainer",
|
|
16078
16174
|
"createComponent",
|
|
16079
16175
|
"renderChild",
|
|
16080
16176
|
"registerComponent",
|
|
@@ -17974,7 +18070,8 @@ function emitProviderAndChildInits(lines, ctx) {
|
|
|
17974
18070
|
lines.push(` upsertChild(__scope, '${registryName}', '${child.slotId}', ${child.propsExpr})`);
|
|
17975
18071
|
continue;
|
|
17976
18072
|
}
|
|
17977
|
-
const
|
|
18073
|
+
const isCommentRoot = child.slotId !== null && child.slotId === ctx.commentScopeRootSlotId;
|
|
18074
|
+
const scopeRef = !child.slotId || isCommentRoot ? "__scope" : `_${varSlotId(child.slotId)}`;
|
|
17978
18075
|
lines.push(` initChild('${registryName}', ${scopeRef}, ${child.propsExpr})`);
|
|
17979
18076
|
}
|
|
17980
18077
|
}
|
|
@@ -18626,6 +18723,7 @@ function buildBranchInnerLoopsPlan(args) {
|
|
|
18626
18723
|
const {
|
|
18627
18724
|
innerLoops,
|
|
18628
18725
|
scopeVar,
|
|
18726
|
+
condSlotId,
|
|
18629
18727
|
outerLoopParam,
|
|
18630
18728
|
outerLoopParamBindings,
|
|
18631
18729
|
wrapOuter
|
|
@@ -18640,7 +18738,7 @@ function buildBranchInnerLoopsPlan(args) {
|
|
|
18640
18738
|
const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
|
|
18641
18739
|
const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings);
|
|
18642
18740
|
const csl = inner.containerSlotId;
|
|
18643
|
-
const containerExpr = csl ? `(${scopeVar}.querySelector('[bf="${csl}"]') ?? ${scopeVar}.querySelector(\`[${BF_HOST2}="\${__scopeId}"][${BF_AT2}="${csl}"]\`) ?? ${scopeVar})` : scopeVar
|
|
18741
|
+
const containerExpr = csl ? `(${scopeVar}.querySelector('[bf="${csl}"]') ?? ${scopeVar}.querySelector(\`[${BF_HOST2}="\${__scopeId}"][${BF_AT2}="${csl}"]\`) ?? ${scopeVar})` : `findCondContainer(${scopeVar}, '${condSlotId}')`;
|
|
18644
18742
|
const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
|
|
18645
18743
|
const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
|
|
18646
18744
|
const wrapIRNode = (node) => {
|
|
@@ -18724,13 +18822,15 @@ function buildLoopChildConditionalsPlan(args) {
|
|
|
18724
18822
|
branch: cond.whenTrue,
|
|
18725
18823
|
wrap,
|
|
18726
18824
|
loopParam,
|
|
18727
|
-
loopParamBindings
|
|
18825
|
+
loopParamBindings,
|
|
18826
|
+
condId: cond.slotId
|
|
18728
18827
|
}),
|
|
18729
18828
|
whenFalseArm: buildLoopChildArmPlan({
|
|
18730
18829
|
branch: cond.whenFalse,
|
|
18731
18830
|
wrap,
|
|
18732
18831
|
loopParam,
|
|
18733
|
-
loopParamBindings
|
|
18832
|
+
loopParamBindings,
|
|
18833
|
+
condId: cond.slotId
|
|
18734
18834
|
})
|
|
18735
18835
|
});
|
|
18736
18836
|
}
|
|
@@ -18770,7 +18870,7 @@ function buildArmTextsPlan(texts, wrap) {
|
|
|
18770
18870
|
}));
|
|
18771
18871
|
}
|
|
18772
18872
|
function buildLoopChildArmPlan(args) {
|
|
18773
|
-
const { branch, wrap, loopParam, loopParamBindings } = args;
|
|
18873
|
+
const { branch, wrap, loopParam, loopParamBindings, condId } = args;
|
|
18774
18874
|
return {
|
|
18775
18875
|
events: buildBranchEventBindingsPlan({
|
|
18776
18876
|
events: branch.events,
|
|
@@ -18783,6 +18883,7 @@ function buildLoopChildArmPlan(args) {
|
|
|
18783
18883
|
innerLoops: buildBranchInnerLoopsPlan({
|
|
18784
18884
|
innerLoops: branch.innerLoops,
|
|
18785
18885
|
scopeVar: "__branchScope",
|
|
18886
|
+
condSlotId: condId,
|
|
18786
18887
|
outerLoopParam: loopParam,
|
|
18787
18888
|
outerLoopParamBindings: loopParamBindings,
|
|
18788
18889
|
wrapOuter: wrap
|
|
@@ -18836,8 +18937,8 @@ function buildReactiveEffectsPlan(args) {
|
|
|
18836
18937
|
wrappedCondition: wrap(cond.condition),
|
|
18837
18938
|
whenTrueTemplateHtml: addCondAttrToTemplate(wrap(cond.whenTrueHtml), cond.slotId),
|
|
18838
18939
|
whenFalseTemplateHtml: addCondAttrToTemplate(wrap(cond.whenFalseHtml), cond.slotId),
|
|
18839
|
-
whenTrueArm: buildOuterArm(cond.whenTrue, wrap, loopParam, loopParamBindings, profileComponentName),
|
|
18840
|
-
whenFalseArm: buildOuterArm(cond.whenFalse, wrap, loopParam, loopParamBindings, profileComponentName),
|
|
18940
|
+
whenTrueArm: buildOuterArm(cond.whenTrue, wrap, loopParam, loopParamBindings, cond.slotId, profileComponentName),
|
|
18941
|
+
whenFalseArm: buildOuterArm(cond.whenFalse, wrap, loopParam, loopParamBindings, cond.slotId, profileComponentName),
|
|
18841
18942
|
...cond.readsPreamble && { readsPreamble: true }
|
|
18842
18943
|
});
|
|
18843
18944
|
}
|
|
@@ -18849,7 +18950,7 @@ function buildReactiveEffectsPlan(args) {
|
|
|
18849
18950
|
profileComponentName
|
|
18850
18951
|
};
|
|
18851
18952
|
}
|
|
18852
|
-
function buildOuterArm(branch, wrap, loopParam, loopParamBindings, profileComponentName) {
|
|
18953
|
+
function buildOuterArm(branch, wrap, loopParam, loopParamBindings, condSlotId, profileComponentName) {
|
|
18853
18954
|
return {
|
|
18854
18955
|
events: buildBranchEventBindingsPlan({
|
|
18855
18956
|
events: branch.events,
|
|
@@ -18863,6 +18964,7 @@ function buildOuterArm(branch, wrap, loopParam, loopParamBindings, profileCompon
|
|
|
18863
18964
|
innerLoops: buildBranchInnerLoopsPlan({
|
|
18864
18965
|
innerLoops: branch.innerLoops,
|
|
18865
18966
|
scopeVar: "__branchScope",
|
|
18967
|
+
condSlotId,
|
|
18866
18968
|
outerLoopParam: loopParam,
|
|
18867
18969
|
outerLoopParamBindings: loopParamBindings,
|
|
18868
18970
|
wrapOuter: wrap
|
|
@@ -18964,6 +19066,7 @@ function buildInnerLoopsPlan(args) {
|
|
|
18964
19066
|
}
|
|
18965
19067
|
function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, outerLoopParamBindings) {
|
|
18966
19068
|
const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
|
|
19069
|
+
const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings);
|
|
18967
19070
|
const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
|
|
18968
19071
|
const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
|
|
18969
19072
|
const wrapIRNode = (node) => {
|
|
@@ -19025,6 +19128,13 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
|
|
|
19025
19128
|
}));
|
|
19026
19129
|
}
|
|
19027
19130
|
const childRefs = buildChildRefBindings(inner.bindings.refs, inner.param, inner.paramBindings);
|
|
19131
|
+
const conditionals = buildLoopChildConditionalsPlan({
|
|
19132
|
+
conditionals: inner.bindings.conditionals,
|
|
19133
|
+
scopeVar: `__innerEl${uidSuffix}`,
|
|
19134
|
+
wrap: wrapBoth,
|
|
19135
|
+
loopParam: inner.param,
|
|
19136
|
+
loopParamBindings: inner.paramBindings
|
|
19137
|
+
});
|
|
19028
19138
|
return {
|
|
19029
19139
|
mode: "reactive",
|
|
19030
19140
|
keyFn: loopKeyFn(inner),
|
|
@@ -19037,6 +19147,7 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
|
|
|
19037
19147
|
events,
|
|
19038
19148
|
reactiveTexts,
|
|
19039
19149
|
reactiveAttrs,
|
|
19150
|
+
conditionals,
|
|
19040
19151
|
childRefs
|
|
19041
19152
|
};
|
|
19042
19153
|
}
|
|
@@ -19989,6 +20100,17 @@ function bindingIdArg(ctx, slotId) {
|
|
|
19989
20100
|
return "";
|
|
19990
20101
|
return `, ${JSON.stringify(`${ctx.componentName}#binding:${slotId}`)}`;
|
|
19991
20102
|
}
|
|
20103
|
+
function emitValueUpdateStatements(target, expression) {
|
|
20104
|
+
return [
|
|
20105
|
+
`const __val = String(${expression})`,
|
|
20106
|
+
`if ('value' in ${target}) { if (${target}.value !== __val) ${target}.value = __val } else { ${target}.setAttribute('value', __val) }`
|
|
20107
|
+
];
|
|
20108
|
+
}
|
|
20109
|
+
function emitChildValueMirrorStatements(target, expression) {
|
|
20110
|
+
return [
|
|
20111
|
+
`if ('value' in ${target}) { const __val = String(${expression}); if (${target}.value !== __val) ${target}.value = __val }`
|
|
20112
|
+
];
|
|
20113
|
+
}
|
|
19992
20114
|
function emitAttrUpdate(target, attrName, expression, meta) {
|
|
19993
20115
|
const htmlName = toHtmlAttrName(attrName);
|
|
19994
20116
|
if (attrName === "dangerouslySetInnerHTML" || htmlName === "dangerouslySetInnerHTML") {
|
|
@@ -20007,10 +20129,7 @@ function emitAttrUpdate(target, attrName, expression, meta) {
|
|
|
20007
20129
|
];
|
|
20008
20130
|
}
|
|
20009
20131
|
if (htmlName === "value") {
|
|
20010
|
-
return
|
|
20011
|
-
`const __val = String(${expression})`,
|
|
20012
|
-
`if (${target}.value !== __val) ${target}.value = __val`
|
|
20013
|
-
];
|
|
20132
|
+
return emitValueUpdateStatements(target, expression);
|
|
20014
20133
|
}
|
|
20015
20134
|
if (isBooleanAttr(htmlName)) {
|
|
20016
20135
|
return [`${target}.${htmlName} = !!(${expression})`];
|
|
@@ -20258,30 +20377,30 @@ function emitReactivePropBindings(lines, ctx) {
|
|
|
20258
20377
|
propsBySlot.get(prop.slotId).push(prop);
|
|
20259
20378
|
}
|
|
20260
20379
|
for (const [slotId, props] of propsBySlot) {
|
|
20261
|
-
const
|
|
20262
|
-
lines.push(` if (
|
|
20380
|
+
const ref = slotId === ctx.commentScopeRootSlotId ? "__scope" : `_${varSlotId(slotId)}`;
|
|
20381
|
+
lines.push(` if (${ref}) {`);
|
|
20263
20382
|
for (const prop of props) {
|
|
20264
20383
|
const value = `${prop.expression}()`;
|
|
20265
20384
|
if (prop.propName === "selected") {
|
|
20266
20385
|
if (prop.componentName === "TabsContent") {
|
|
20267
|
-
lines.push(`
|
|
20386
|
+
lines.push(` ${ref}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
|
|
20268
20387
|
lines.push(` if (${value}) {`);
|
|
20269
|
-
lines.push(`
|
|
20388
|
+
lines.push(` ${ref}.classList.remove('hidden')`);
|
|
20270
20389
|
lines.push(` } else {`);
|
|
20271
|
-
lines.push(`
|
|
20390
|
+
lines.push(` ${ref}.classList.add('hidden')`);
|
|
20272
20391
|
lines.push(` }`);
|
|
20273
20392
|
} else {
|
|
20274
|
-
lines.push(`
|
|
20275
|
-
lines.push(`
|
|
20276
|
-
lines.push(`
|
|
20393
|
+
lines.push(` ${ref}.setAttribute('aria-selected', String(${value}))`);
|
|
20394
|
+
lines.push(` ${ref}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
|
|
20395
|
+
lines.push(` ${ref}.setAttribute('tabindex', ${value} ? '0' : '-1')`);
|
|
20277
20396
|
}
|
|
20278
20397
|
} else if (prop.propName === "value") {
|
|
20279
|
-
|
|
20280
|
-
|
|
20398
|
+
for (const stmt of emitChildValueMirrorStatements(ref, value))
|
|
20399
|
+
lines.push(` ${stmt}`);
|
|
20281
20400
|
} else if (isBooleanAttr(prop.propName)) {
|
|
20282
|
-
lines.push(`
|
|
20401
|
+
lines.push(` ${ref}.${prop.propName} = !!(${value})`);
|
|
20283
20402
|
} else {
|
|
20284
|
-
lines.push(`
|
|
20403
|
+
lines.push(` ${ref}.setAttribute('${prop.propName}', String(${value}))`);
|
|
20285
20404
|
}
|
|
20286
20405
|
}
|
|
20287
20406
|
lines.push(` }`);
|
|
@@ -20304,13 +20423,17 @@ function emitReactiveChildProps(lines, ctx) {
|
|
|
20304
20423
|
}
|
|
20305
20424
|
for (const [, props] of propsByComponent) {
|
|
20306
20425
|
const first = props[0];
|
|
20426
|
+
const isCommentRoot = first.slotId !== null && first.slotId === ctx.commentScopeRootSlotId;
|
|
20307
20427
|
const varSuffix = first.slotId ? varSlotId(first.slotId).replace(/-/g, "_") : first.componentName;
|
|
20308
|
-
const varName = `__${first.componentName}_${varSuffix}El`;
|
|
20309
|
-
|
|
20310
|
-
|
|
20428
|
+
const varName = isCommentRoot ? "__scope" : `__${first.componentName}_${varSuffix}El`;
|
|
20429
|
+
if (!isCommentRoot) {
|
|
20430
|
+
const selectorArg = first.slotId ? first.slotId : first.componentName;
|
|
20431
|
+
lines.push(` const [${varName}] = $c(__scope, '${selectorArg}')`);
|
|
20432
|
+
}
|
|
20311
20433
|
lines.push(` if (${varName}) {`);
|
|
20312
20434
|
for (const prop of props) {
|
|
20313
|
-
|
|
20435
|
+
const stmts = toHtmlAttrName(prop.attrName) === "value" ? emitChildValueMirrorStatements(varName, prop.expression) : emitAttrUpdate(varName, prop.attrName, prop.expression, prop);
|
|
20436
|
+
for (const stmt of stmts) {
|
|
20314
20437
|
lines.push(` ${stmt}`);
|
|
20315
20438
|
}
|
|
20316
20439
|
}
|
|
@@ -20871,8 +20994,9 @@ function seedDiffersExpr(target, a) {
|
|
|
20871
20994
|
return `${target}.getAttribute('style') !== styleToCss(__x)`;
|
|
20872
20995
|
if (html === "class")
|
|
20873
20996
|
return `${target}.getAttribute('class') !== (__x != null ? String(__x) : null)`;
|
|
20874
|
-
if (html === "value")
|
|
20875
|
-
return
|
|
20997
|
+
if (html === "value") {
|
|
20998
|
+
return `('value' in ${target} ? ${target}.value !== String(__x) : ${target}.getAttribute('value') !== String(__x))`;
|
|
20999
|
+
}
|
|
20876
21000
|
if (isBooleanAttr(html))
|
|
20877
21001
|
return `${target}.${html} !== !!(__x)`;
|
|
20878
21002
|
if (a.meta.presenceOrUndefined) {
|
|
@@ -21230,6 +21354,9 @@ function emitReactive(lines, inner, indent, pc) {
|
|
|
21230
21354
|
}
|
|
21231
21355
|
lines.push(`${indent} }${profileBindingId(pc, attr.slotId)}) }`);
|
|
21232
21356
|
}
|
|
21357
|
+
if (emit.conditionals.length > 0) {
|
|
21358
|
+
stringifyLoopChildConditionals(lines, emit.conditionals, `${indent} `, pc);
|
|
21359
|
+
}
|
|
21233
21360
|
emitLoopChildRefs(lines, emit.childRefs, {
|
|
21234
21361
|
indent: `${indent} `,
|
|
21235
21362
|
elVar: `__innerEl${uid}`,
|
|
@@ -21993,6 +22120,9 @@ function generateElementRefs(ctx) {
|
|
|
21993
22120
|
for (const slotId of componentSlots) {
|
|
21994
22121
|
regularSlots.delete(slotId);
|
|
21995
22122
|
}
|
|
22123
|
+
if (ctx.commentScopeRootSlotId) {
|
|
22124
|
+
componentSlots.delete(ctx.commentScopeRootSlotId);
|
|
22125
|
+
}
|
|
21996
22126
|
if (regularSlots.size === 0 && componentSlots.size === 0)
|
|
21997
22127
|
return "";
|
|
21998
22128
|
const refLines = [];
|
|
@@ -22479,6 +22609,7 @@ function createContext(ir, scope, adapterCapabilities, profile) {
|
|
|
22479
22609
|
refElements: [],
|
|
22480
22610
|
childInits: [],
|
|
22481
22611
|
deferredChildSlots: new Set,
|
|
22612
|
+
commentScopeRootSlotId: ir.root.type === "component" ? ir.root.slotId : null,
|
|
22482
22613
|
reactiveProps: [],
|
|
22483
22614
|
reactiveChildProps: [],
|
|
22484
22615
|
reactiveAttrs: [],
|
|
@@ -23480,12 +23611,38 @@ function evalNode(node, ctx) {
|
|
|
23480
23611
|
const baseResult = evalNode(node.expression, ctx);
|
|
23481
23612
|
if (baseResult === undefined)
|
|
23482
23613
|
return;
|
|
23483
|
-
|
|
23614
|
+
if (baseResult === UNRESOLVED || baseResult === null || typeof baseResult !== "object") {
|
|
23615
|
+
return UNRESOLVED;
|
|
23616
|
+
}
|
|
23617
|
+
const proto = Object.getPrototypeOf(baseResult);
|
|
23618
|
+
if (proto !== Object.prototype && proto !== null)
|
|
23619
|
+
return UNRESOLVED;
|
|
23620
|
+
const key = node.name.text;
|
|
23621
|
+
return Object.prototype.hasOwnProperty.call(baseResult, key) ? baseResult[key] : undefined;
|
|
23484
23622
|
}
|
|
23485
23623
|
if (ts22.isCallExpression(node)) {
|
|
23486
23624
|
if (node.arguments.length === 0 && ts22.isIdentifier(node.expression) && node.expression.text in ctx.bindings) {
|
|
23487
23625
|
return ctx.bindings[node.expression.text];
|
|
23488
23626
|
}
|
|
23627
|
+
if (ts22.isPropertyAccessExpression(node.expression) && node.expression.name.text === "map" && node.arguments.length === 1) {
|
|
23628
|
+
const arrow = node.arguments[0];
|
|
23629
|
+
if (ts22.isArrowFunction(arrow) && arrow.parameters.length === 1 && ts22.isIdentifier(arrow.parameters[0].name) && !ts22.isBlock(arrow.body)) {
|
|
23630
|
+
const recv = evalNode(node.expression.expression, ctx);
|
|
23631
|
+
if (Array.isArray(recv)) {
|
|
23632
|
+
const paramName = arrow.parameters[0].name.text;
|
|
23633
|
+
const mapped = [];
|
|
23634
|
+
for (const item of recv) {
|
|
23635
|
+
const localBindings = { ...ctx.bindings, [paramName]: item };
|
|
23636
|
+
const v = evalNode(arrow.body, { ...ctx, bindings: localBindings });
|
|
23637
|
+
if (v === UNRESOLVED)
|
|
23638
|
+
return UNRESOLVED;
|
|
23639
|
+
mapped.push(v === undefined ? null : v);
|
|
23640
|
+
}
|
|
23641
|
+
return mapped;
|
|
23642
|
+
}
|
|
23643
|
+
}
|
|
23644
|
+
return UNRESOLVED;
|
|
23645
|
+
}
|
|
23489
23646
|
if (ts22.isPropertyAccessExpression(node.expression) && node.expression.name.text === "join") {
|
|
23490
23647
|
const recv = evalNode(node.expression.expression, ctx);
|
|
23491
23648
|
if (Array.isArray(recv)) {
|
|
@@ -23989,7 +24146,7 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
|
|
|
23989
24146
|
|
|
23990
24147
|
// src/ssr-seed-plan.ts
|
|
23991
24148
|
function classify2(name, origin, expr, parsed, available) {
|
|
23992
|
-
if (!
|
|
24149
|
+
if (!isSupportedValue(parsed).supported)
|
|
23993
24150
|
return { kind: "opaque", name, origin };
|
|
23994
24151
|
const frees = freeIdentifiers(parsed);
|
|
23995
24152
|
if (frees === null)
|
|
@@ -24052,7 +24209,7 @@ function computeSsrSeedPlan(metadata) {
|
|
|
24052
24209
|
}
|
|
24053
24210
|
}
|
|
24054
24211
|
const expr = signal.initialValue.trim();
|
|
24055
|
-
steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify2(signal.getter, "signal", expr, resolveThroughLocalConsts(parseExpression(expr), localConsts), available));
|
|
24212
|
+
steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify2(signal.getter, "signal", expr, resolveThroughLocalConsts(signal.parsed ?? parseExpression(`(${expr})`), localConsts), available));
|
|
24056
24213
|
available.add(signal.getter);
|
|
24057
24214
|
}
|
|
24058
24215
|
for (const memo of metadata.memos) {
|
|
@@ -24216,7 +24373,7 @@ function checkExpr(expr, loc, meta, bindings, matchers, errors, seen) {
|
|
|
24216
24373
|
break;
|
|
24217
24374
|
case "object-literal":
|
|
24218
24375
|
for (const prop of expr.properties)
|
|
24219
|
-
recurse(prop.value);
|
|
24376
|
+
recurse(prop.kind === "spread" ? prop.expr : prop.value);
|
|
24220
24377
|
break;
|
|
24221
24378
|
case "array-method":
|
|
24222
24379
|
recurse(expr.object);
|
|
@@ -25599,6 +25756,26 @@ function isStringConcatBinary(op, left, right, isStringName) {
|
|
|
25599
25756
|
function groupBinaryOperand(operand, emitted) {
|
|
25600
25757
|
return operand.kind === "binary" || operand.kind === "logical" || operand.kind === "conditional" ? `(${emitted})` : emitted;
|
|
25601
25758
|
}
|
|
25759
|
+
function groupObjectLiteralSegments(properties, literalOf, emit) {
|
|
25760
|
+
const segments = [];
|
|
25761
|
+
let run = [];
|
|
25762
|
+
const flushRun = () => {
|
|
25763
|
+
if (run.length > 0) {
|
|
25764
|
+
segments.push(literalOf(run));
|
|
25765
|
+
run = [];
|
|
25766
|
+
}
|
|
25767
|
+
};
|
|
25768
|
+
for (const p of properties) {
|
|
25769
|
+
if (p.kind === "spread") {
|
|
25770
|
+
flushRun();
|
|
25771
|
+
segments.push(emit(p.expr));
|
|
25772
|
+
} else {
|
|
25773
|
+
run.push(p);
|
|
25774
|
+
}
|
|
25775
|
+
}
|
|
25776
|
+
flushRun();
|
|
25777
|
+
return segments;
|
|
25778
|
+
}
|
|
25602
25779
|
function emitParsedExpr(expr, emitter) {
|
|
25603
25780
|
const emit = (child) => emitParsedExpr(child, emitter);
|
|
25604
25781
|
switch (expr.kind) {
|
|
@@ -25745,6 +25922,17 @@ function evaluateStaticLiteral(expr, bindings) {
|
|
|
25745
25922
|
case "object-literal": {
|
|
25746
25923
|
const out = {};
|
|
25747
25924
|
for (const prop of expr.properties) {
|
|
25925
|
+
if (prop.kind === "spread") {
|
|
25926
|
+
const resolved2 = evaluateStaticLiteral(prop.expr, bindings);
|
|
25927
|
+
if (!resolved2)
|
|
25928
|
+
return null;
|
|
25929
|
+
if (resolved2.value === null || resolved2.value === undefined)
|
|
25930
|
+
continue;
|
|
25931
|
+
if (typeof resolved2.value !== "object" || Array.isArray(resolved2.value))
|
|
25932
|
+
return null;
|
|
25933
|
+
Object.assign(out, resolved2.value);
|
|
25934
|
+
continue;
|
|
25935
|
+
}
|
|
25748
25936
|
const resolved = evaluateStaticLiteral(prop.value, bindings);
|
|
25749
25937
|
if (!resolved)
|
|
25750
25938
|
return null;
|
|
@@ -25814,6 +26002,8 @@ function matchQueryHrefCall(callee, args, localNames) {
|
|
|
25814
26002
|
return null;
|
|
25815
26003
|
const triples = [];
|
|
25816
26004
|
for (const p of obj.properties) {
|
|
26005
|
+
if (p.kind === "spread")
|
|
26006
|
+
return null;
|
|
25817
26007
|
const v = p.value;
|
|
25818
26008
|
if (v.kind === "conditional" && isOmitBranch(v.alternate)) {
|
|
25819
26009
|
triples.push({ guard: v.test, key: p.key, value: v.consequent });
|
|
@@ -26001,6 +26191,8 @@ function htmlPropValue(parsed) {
|
|
|
26001
26191
|
if (parsed.properties.length !== 1)
|
|
26002
26192
|
return null;
|
|
26003
26193
|
const [prop] = parsed.properties;
|
|
26194
|
+
if (prop.kind === "spread")
|
|
26195
|
+
return null;
|
|
26004
26196
|
if (prop.key !== "__html")
|
|
26005
26197
|
return null;
|
|
26006
26198
|
return prop.value;
|
|
@@ -28925,6 +29117,7 @@ export {
|
|
|
28925
29117
|
joinProfilerEvents,
|
|
28926
29118
|
isValueReferenceIdentifier,
|
|
28927
29119
|
isValidHelperId,
|
|
29120
|
+
isSupportedValue,
|
|
28928
29121
|
isSupported,
|
|
28929
29122
|
isStringTypedOperand,
|
|
28930
29123
|
isStringConcatBinary,
|
|
@@ -28937,6 +29130,7 @@ export {
|
|
|
28937
29130
|
importsSearchParams,
|
|
28938
29131
|
identifierPath,
|
|
28939
29132
|
hasUnsafeStyleValue,
|
|
29133
|
+
groupObjectLiteralSegments,
|
|
28940
29134
|
groupBinaryOperand,
|
|
28941
29135
|
graphToJSON,
|
|
28942
29136
|
getLoweringPlugins,
|