@vertz/ui-compiler 0.2.10 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +79 -25
- package/package.json +4 -6
package/dist/index.js
CHANGED
|
@@ -263,11 +263,12 @@ class JsxAnalyzer {
|
|
|
263
263
|
const deps = identifiers.filter((id) => reactiveNames.has(id));
|
|
264
264
|
const uniqueDeps = [...new Set(deps)];
|
|
265
265
|
const hasSignalApiAccess = containsSignalApiPropertyAccess(expr, signalApiVars, plainPropVars, fieldSignalPropVars);
|
|
266
|
+
const hasSignalApiRef = containsSignalApiReference(expr, signalApiVars);
|
|
266
267
|
const hasReactiveSourceAccess = containsReactiveSourceAccess(expr, reactiveSourceVars);
|
|
267
268
|
results.push({
|
|
268
269
|
start: expr.getStart(),
|
|
269
270
|
end: expr.getEnd(),
|
|
270
|
-
reactive: uniqueDeps.length > 0 || hasSignalApiAccess || hasReactiveSourceAccess,
|
|
271
|
+
reactive: uniqueDeps.length > 0 || hasSignalApiAccess || hasSignalApiRef || hasReactiveSourceAccess,
|
|
271
272
|
deps: uniqueDeps
|
|
272
273
|
});
|
|
273
274
|
}
|
|
@@ -309,6 +310,19 @@ function containsSignalApiPropertyAccess(node, signalApiVars, plainPropVars, fie
|
|
|
309
310
|
}
|
|
310
311
|
return false;
|
|
311
312
|
}
|
|
313
|
+
function containsSignalApiReference(node, signalApiVars) {
|
|
314
|
+
if (signalApiVars.size === 0)
|
|
315
|
+
return false;
|
|
316
|
+
const callExprs = node.getDescendantsOfKind(SyntaxKind4.CallExpression);
|
|
317
|
+
for (const call of callExprs) {
|
|
318
|
+
for (const arg of call.getArguments()) {
|
|
319
|
+
if (arg.isKind(SyntaxKind4.Identifier) && signalApiVars.has(arg.getText())) {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
312
326
|
function containsReactiveSourceAccess(node, reactiveSourceVars) {
|
|
313
327
|
if (reactiveSourceVars.size === 0)
|
|
314
328
|
return false;
|
|
@@ -527,7 +541,8 @@ class ReactivityAnalyzer {
|
|
|
527
541
|
consts.set(syntheticName, {
|
|
528
542
|
start: decl.getStart(),
|
|
529
543
|
end: decl.getEnd(),
|
|
530
|
-
deps: []
|
|
544
|
+
deps: [],
|
|
545
|
+
propertyAccesses: new Map
|
|
531
546
|
});
|
|
532
547
|
}
|
|
533
548
|
}
|
|
@@ -539,12 +554,21 @@ class ReactivityAnalyzer {
|
|
|
539
554
|
if (signalApiConfig && syntheticName) {
|
|
540
555
|
const isSignalProp = signalApiConfig.signalProperties.has(propName);
|
|
541
556
|
const deps2 = isSignalProp ? [syntheticName] : [];
|
|
542
|
-
const
|
|
557
|
+
const propAccesses = new Map;
|
|
558
|
+
if (isSignalProp) {
|
|
559
|
+
propAccesses.set(syntheticName, new Set([propName]));
|
|
560
|
+
}
|
|
561
|
+
const entry2 = {
|
|
562
|
+
start: decl.getStart(),
|
|
563
|
+
end: decl.getEnd(),
|
|
564
|
+
deps: deps2,
|
|
565
|
+
propertyAccesses: propAccesses
|
|
566
|
+
};
|
|
543
567
|
consts.set(bindingName, entry2);
|
|
544
568
|
destructuredFromMap.set(bindingName, syntheticName);
|
|
545
569
|
} else {
|
|
546
|
-
const deps2 = init ?
|
|
547
|
-
const entry2 = { start: decl.getStart(), end: decl.getEnd(), deps: deps2 };
|
|
570
|
+
const { refs: deps2, propertyAccesses: propertyAccesses2 } = init ? collectDeps(init) : { refs: [], propertyAccesses: new Map };
|
|
571
|
+
const entry2 = { start: decl.getStart(), end: decl.getEnd(), deps: deps2, propertyAccesses: propertyAccesses2 };
|
|
548
572
|
if (isLet) {
|
|
549
573
|
lets.set(bindingName, entry2);
|
|
550
574
|
} else if (isConst) {
|
|
@@ -555,8 +579,8 @@ class ReactivityAnalyzer {
|
|
|
555
579
|
continue;
|
|
556
580
|
}
|
|
557
581
|
const name = decl.getName();
|
|
558
|
-
const deps = init ?
|
|
559
|
-
const entry = { start: decl.getStart(), end: decl.getEnd(), deps };
|
|
582
|
+
const { refs: deps, propertyAccesses } = init ? collectDeps(init) : { refs: [], propertyAccesses: new Map };
|
|
583
|
+
const entry = { start: decl.getStart(), end: decl.getEnd(), deps, propertyAccesses };
|
|
560
584
|
let callInit = init;
|
|
561
585
|
if (callInit?.isKind(SyntaxKind6.NonNullExpression)) {
|
|
562
586
|
callInit = callInit.getExpression();
|
|
@@ -614,7 +638,20 @@ class ReactivityAnalyzer {
|
|
|
614
638
|
for (const [name, info] of consts) {
|
|
615
639
|
if (computeds.has(name))
|
|
616
640
|
continue;
|
|
617
|
-
|
|
641
|
+
if (signalApiVars.has(name))
|
|
642
|
+
continue;
|
|
643
|
+
const dependsOnReactive = info.deps.some((dep) => {
|
|
644
|
+
if (signals.has(dep) || computeds.has(dep) || reactiveSourceVars.has(dep))
|
|
645
|
+
return true;
|
|
646
|
+
const apiConfig = signalApiVars.get(dep);
|
|
647
|
+
if (apiConfig) {
|
|
648
|
+
const accessed = info.propertyAccesses.get(dep);
|
|
649
|
+
if (!accessed || accessed.size === 0)
|
|
650
|
+
return false;
|
|
651
|
+
return [...accessed].some((prop) => apiConfig.signalProperties.has(prop));
|
|
652
|
+
}
|
|
653
|
+
return false;
|
|
654
|
+
});
|
|
618
655
|
if (dependsOnReactive) {
|
|
619
656
|
computeds.add(name);
|
|
620
657
|
changed = true;
|
|
@@ -678,9 +715,27 @@ function addIdentifiers(node, refs) {
|
|
|
678
715
|
addIdentifiers(child, refs);
|
|
679
716
|
}
|
|
680
717
|
}
|
|
681
|
-
function
|
|
718
|
+
function collectDeps(node) {
|
|
682
719
|
const refs = [];
|
|
720
|
+
const propertyAccesses = new Map;
|
|
683
721
|
const walk = (n) => {
|
|
722
|
+
if (n.isKind(SyntaxKind6.PropertyAccessExpression)) {
|
|
723
|
+
const expr = n.getExpression();
|
|
724
|
+
const propName = n.getName();
|
|
725
|
+
if (expr.isKind(SyntaxKind6.Identifier)) {
|
|
726
|
+
const varName = expr.getText();
|
|
727
|
+
refs.push(varName);
|
|
728
|
+
let props = propertyAccesses.get(varName);
|
|
729
|
+
if (!props) {
|
|
730
|
+
props = new Set;
|
|
731
|
+
propertyAccesses.set(varName, props);
|
|
732
|
+
}
|
|
733
|
+
props.add(propName);
|
|
734
|
+
} else {
|
|
735
|
+
walk(expr);
|
|
736
|
+
}
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
684
739
|
if (n.isKind(SyntaxKind6.Identifier)) {
|
|
685
740
|
refs.push(n.getText());
|
|
686
741
|
}
|
|
@@ -689,7 +744,7 @@ function collectIdentifierRefs(node) {
|
|
|
689
744
|
}
|
|
690
745
|
};
|
|
691
746
|
walk(node);
|
|
692
|
-
return refs;
|
|
747
|
+
return { refs, propertyAccesses };
|
|
693
748
|
}
|
|
694
749
|
function buildImportAliasMap(sourceFile) {
|
|
695
750
|
const signalApiAliases = new Map;
|
|
@@ -1110,6 +1165,9 @@ function transformComputedReads(source, bodyNode, computeds) {
|
|
|
1110
1165
|
|
|
1111
1166
|
// src/transformers/jsx-transformer.ts
|
|
1112
1167
|
import { SyntaxKind as SyntaxKind10 } from "ts-morph";
|
|
1168
|
+
function isLiteralExpression(node) {
|
|
1169
|
+
return node.isKind(SyntaxKind10.StringLiteral) || node.isKind(SyntaxKind10.NumericLiteral) || node.isKind(SyntaxKind10.TrueKeyword) || node.isKind(SyntaxKind10.FalseKeyword) || node.isKind(SyntaxKind10.NullKeyword) || node.isKind(SyntaxKind10.NoSubstitutionTemplateLiteral);
|
|
1170
|
+
}
|
|
1113
1171
|
function cleanJsxText(raw) {
|
|
1114
1172
|
if (!raw.includes(`
|
|
1115
1173
|
`) && !raw.includes("\r")) {
|
|
@@ -1220,7 +1278,7 @@ function transformJsxElement(node, reactiveNames, jsxMap, source, formVarNames =
|
|
|
1220
1278
|
for (const attr of attrs) {
|
|
1221
1279
|
if (!attr.isKind(SyntaxKind10.JsxAttribute))
|
|
1222
1280
|
continue;
|
|
1223
|
-
const attrStmt = processAttribute(attr, elVar,
|
|
1281
|
+
const attrStmt = processAttribute(attr, elVar, source);
|
|
1224
1282
|
if (attrStmt)
|
|
1225
1283
|
statements.push(attrStmt);
|
|
1226
1284
|
}
|
|
@@ -1266,7 +1324,7 @@ function transformSelfClosingElement(node, reactiveNames, jsxMap, source, formVa
|
|
|
1266
1324
|
for (const attr of attrs) {
|
|
1267
1325
|
if (!attr.isKind(SyntaxKind10.JsxAttribute))
|
|
1268
1326
|
continue;
|
|
1269
|
-
const attrStmt = processAttribute(attr, elVar,
|
|
1327
|
+
const attrStmt = processAttribute(attr, elVar, source);
|
|
1270
1328
|
if (attrStmt)
|
|
1271
1329
|
statements.push(attrStmt);
|
|
1272
1330
|
}
|
|
@@ -1295,7 +1353,7 @@ ${statements.map((s) => ` ${s};`).join(`
|
|
|
1295
1353
|
return ${fragVar};
|
|
1296
1354
|
})()`;
|
|
1297
1355
|
}
|
|
1298
|
-
function processAttribute(attr, elVar,
|
|
1356
|
+
function processAttribute(attr, elVar, source) {
|
|
1299
1357
|
if (!attr.isKind(SyntaxKind10.JsxAttribute))
|
|
1300
1358
|
return null;
|
|
1301
1359
|
const attrName = attr.getNameNode().getText();
|
|
@@ -1315,10 +1373,9 @@ function processAttribute(attr, elVar, jsxMap, source) {
|
|
|
1315
1373
|
return `${elVar}.setAttribute(${JSON.stringify(attrName)}, ${init.getText()})`;
|
|
1316
1374
|
}
|
|
1317
1375
|
if (init.isKind(SyntaxKind10.JsxExpression)) {
|
|
1318
|
-
const exprInfo = jsxMap.get(init.getStart());
|
|
1319
1376
|
const exprNode = init.getExpression();
|
|
1320
1377
|
const exprText = exprNode ? source.slice(exprNode.getStart(), exprNode.getEnd()) : "";
|
|
1321
|
-
if (
|
|
1378
|
+
if (exprNode && !isLiteralExpression(exprNode)) {
|
|
1322
1379
|
return `__attr(${elVar}, ${JSON.stringify(attrName)}, () => ${exprText})`;
|
|
1323
1380
|
}
|
|
1324
1381
|
return `{ const __v = ${exprText}; if (__v != null && __v !== false) ${elVar}.setAttribute(${JSON.stringify(attrName)}, __v === true ? "" : __v); }`;
|
|
@@ -1337,18 +1394,20 @@ function transformChild(child, reactiveNames, jsxMap, parentVar, source, formVar
|
|
|
1337
1394
|
const exprNode = child.getExpression();
|
|
1338
1395
|
if (!exprNode)
|
|
1339
1396
|
return null;
|
|
1340
|
-
if (
|
|
1397
|
+
if (!isLiteralExpression(exprNode)) {
|
|
1341
1398
|
const conditionalCode = tryTransformConditional(exprNode, reactiveNames, jsxMap, source);
|
|
1342
1399
|
if (conditionalCode) {
|
|
1343
1400
|
return `__append(${parentVar}, ${conditionalCode})`;
|
|
1344
1401
|
}
|
|
1402
|
+
}
|
|
1403
|
+
if (exprInfo?.reactive) {
|
|
1345
1404
|
const listCode = tryTransformList(exprNode, reactiveNames, jsxMap, parentVar, source);
|
|
1346
1405
|
if (listCode) {
|
|
1347
1406
|
return listCode;
|
|
1348
1407
|
}
|
|
1349
1408
|
}
|
|
1350
1409
|
const exprText = sliceWithTransformedJsx(exprNode, reactiveNames, jsxMap, source, formVarNames);
|
|
1351
|
-
if (
|
|
1410
|
+
if (!isLiteralExpression(exprNode)) {
|
|
1352
1411
|
return `__append(${parentVar}, __child(() => ${exprText}))`;
|
|
1353
1412
|
}
|
|
1354
1413
|
return `__insert(${parentVar}, ${exprText})`;
|
|
@@ -1367,18 +1426,17 @@ function transformChildAsValue(child, reactiveNames, jsxMap, source, formVarName
|
|
|
1367
1426
|
return `__staticText(${JSON.stringify(text)})`;
|
|
1368
1427
|
}
|
|
1369
1428
|
if (child.isKind(SyntaxKind10.JsxExpression)) {
|
|
1370
|
-
const exprInfo = jsxMap.get(child.getStart());
|
|
1371
1429
|
const exprNode = child.getExpression();
|
|
1372
1430
|
if (!exprNode)
|
|
1373
1431
|
return null;
|
|
1374
|
-
if (
|
|
1432
|
+
if (!isLiteralExpression(exprNode)) {
|
|
1375
1433
|
const conditionalCode = tryTransformConditional(exprNode, reactiveNames, jsxMap, source);
|
|
1376
1434
|
if (conditionalCode) {
|
|
1377
1435
|
return conditionalCode;
|
|
1378
1436
|
}
|
|
1379
1437
|
}
|
|
1380
1438
|
const exprText = sliceWithTransformedJsx(exprNode, reactiveNames, jsxMap, source, formVarNames);
|
|
1381
|
-
if (
|
|
1439
|
+
if (!isLiteralExpression(exprNode)) {
|
|
1382
1440
|
return `__child(() => ${exprText})`;
|
|
1383
1441
|
}
|
|
1384
1442
|
return exprText;
|
|
@@ -1571,10 +1629,9 @@ function buildPropsObject(element, jsxMap, source, reactiveNames, formVarNames,
|
|
|
1571
1629
|
continue;
|
|
1572
1630
|
}
|
|
1573
1631
|
if (init.isKind(SyntaxKind10.JsxExpression)) {
|
|
1574
|
-
const exprInfo = jsxMap.get(init.getStart());
|
|
1575
1632
|
const exprNode = init.getExpression();
|
|
1576
1633
|
const exprText = exprNode ? sliceWithTransformedJsx(exprNode, reactiveNames, jsxMap, source, formVarNames) : "";
|
|
1577
|
-
if (
|
|
1634
|
+
if (exprNode && !isLiteralExpression(exprNode)) {
|
|
1578
1635
|
props.push(`get ${name}() { return ${exprText}; }`);
|
|
1579
1636
|
} else {
|
|
1580
1637
|
props.push(`${name}: ${exprText}`);
|
|
@@ -1891,9 +1948,6 @@ function compile(source, optionsOrFilename) {
|
|
|
1891
1948
|
if (jsxExpressions.length > 0) {
|
|
1892
1949
|
usedFeatures.add("__element");
|
|
1893
1950
|
usedFeatures.add("__child");
|
|
1894
|
-
}
|
|
1895
|
-
if (jsxExpressions.some((e) => e.reactive)) {
|
|
1896
|
-
usedFeatures.add("__text");
|
|
1897
1951
|
usedFeatures.add("__attr");
|
|
1898
1952
|
}
|
|
1899
1953
|
const hasEvents = sourceFile.getDescendantsOfKind(SyntaxKind12.JsxAttribute).some((attr) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertz/ui-compiler",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Vertz UI compiler — SSR and build-time optimizations",
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "bunup",
|
|
25
25
|
"test": "bun test",
|
|
26
|
-
"test:watch": "
|
|
26
|
+
"test:watch": "bun test --watch",
|
|
27
27
|
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@ampproject/remapping": "^2.3.0",
|
|
31
|
-
"@vertz/ui": "^0.2.
|
|
31
|
+
"@vertz/ui": "^0.2.11",
|
|
32
32
|
"magic-string": "^0.30.0",
|
|
33
33
|
"ts-morph": "^27.0.2"
|
|
34
34
|
},
|
|
@@ -36,10 +36,8 @@
|
|
|
36
36
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
37
37
|
"@types/node": "^25.3.1",
|
|
38
38
|
"bun-types": "^1.3.10",
|
|
39
|
-
"@vitest/coverage-v8": "^4.0.18",
|
|
40
39
|
"bunup": "^0.16.31",
|
|
41
|
-
"typescript": "^5.7.0"
|
|
42
|
-
"vitest": "^4.0.18"
|
|
40
|
+
"typescript": "^5.7.0"
|
|
43
41
|
},
|
|
44
42
|
"engines": {
|
|
45
43
|
"node": ">=22"
|