sinwan-compiler 0.2.8 → 0.2.9
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/{chunk-v4zrz7j7.js → chunk-6dnsvgyf.js} +66 -10
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/docs/README.md +1 -0
- package/docs/plugins.md +1 -0
- package/docs/transform.md +2 -0
- package/package.json +1 -1
|
@@ -300,6 +300,35 @@ function analyzeObjectLiteralSpread(spread, fullScope, calleeReactive) {
|
|
|
300
300
|
function isMemberLike(node) {
|
|
301
301
|
return t.isMemberExpression(node) || t.isOptionalMemberExpression(node);
|
|
302
302
|
}
|
|
303
|
+
function isFunctionLike(node) {
|
|
304
|
+
return t.isArrowFunctionExpression(node) || t.isFunctionExpression(node);
|
|
305
|
+
}
|
|
306
|
+
function isCallLike(node) {
|
|
307
|
+
return t.isCallExpression(node) || t.isOptionalCallExpression(node);
|
|
308
|
+
}
|
|
309
|
+
var COMPILER_BINDING_CALLEES = new Set([
|
|
310
|
+
"_$bindText",
|
|
311
|
+
"_$bindAttr",
|
|
312
|
+
"_$bindStyle",
|
|
313
|
+
"_$bindClass",
|
|
314
|
+
"_$unwrap"
|
|
315
|
+
]);
|
|
316
|
+
function isCompilerBindingCall(node) {
|
|
317
|
+
const callee = node.callee;
|
|
318
|
+
return t.isIdentifier(callee) && COMPILER_BINDING_CALLEES.has(callee.name);
|
|
319
|
+
}
|
|
320
|
+
function visitCallCalleeAndArgs(node, visitExpr) {
|
|
321
|
+
if (isCompilerBindingCall(node))
|
|
322
|
+
return;
|
|
323
|
+
visitExpr(node.callee, true);
|
|
324
|
+
for (const arg of node.arguments) {
|
|
325
|
+
if (t.isSpreadElement(arg)) {
|
|
326
|
+
visitExpr(arg.argument, true);
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
visitExpr(arg, true);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
303
332
|
function getMemberExpressionRootAndPath(node) {
|
|
304
333
|
const path = [];
|
|
305
334
|
let current = node;
|
|
@@ -437,11 +466,23 @@ function containsReactiveValue2(expr, scope) {
|
|
|
437
466
|
}
|
|
438
467
|
function containsReactiveRead(expr, scope) {
|
|
439
468
|
let found = false;
|
|
440
|
-
function visit(node) {
|
|
469
|
+
function visit(node, enterFunction) {
|
|
441
470
|
if (found)
|
|
442
471
|
return;
|
|
443
472
|
if (!node || typeof node !== "object")
|
|
444
473
|
return;
|
|
474
|
+
if (isFunctionLike(node)) {
|
|
475
|
+
if (!enterFunction)
|
|
476
|
+
return;
|
|
477
|
+
for (const param of node.params) {
|
|
478
|
+
visit(param, false);
|
|
479
|
+
}
|
|
480
|
+
visit(node.body, false);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (t.isJSXElement(node) || t.isJSXFragment(node)) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
445
486
|
if (isMemberLike(node) || t.isTSNonNullExpression(node) || t.isIdentifier(node)) {
|
|
446
487
|
if (isReactiveRead(node, scope)) {
|
|
447
488
|
found = true;
|
|
@@ -452,7 +493,8 @@ function containsReactiveRead(expr, scope) {
|
|
|
452
493
|
found = true;
|
|
453
494
|
return;
|
|
454
495
|
}
|
|
455
|
-
if (
|
|
496
|
+
if (isCallLike(node)) {
|
|
497
|
+
visitCallCalleeAndArgs(node, visit);
|
|
456
498
|
return;
|
|
457
499
|
}
|
|
458
500
|
for (const key of Object.keys(node)) {
|
|
@@ -462,14 +504,14 @@ function containsReactiveRead(expr, scope) {
|
|
|
462
504
|
if (Array.isArray(value)) {
|
|
463
505
|
for (const item of value) {
|
|
464
506
|
if (item && typeof item === "object")
|
|
465
|
-
visit(item);
|
|
507
|
+
visit(item, false);
|
|
466
508
|
}
|
|
467
509
|
} else if (value && typeof value === "object") {
|
|
468
|
-
visit(value);
|
|
510
|
+
visit(value, false);
|
|
469
511
|
}
|
|
470
512
|
}
|
|
471
513
|
}
|
|
472
|
-
visit(expr);
|
|
514
|
+
visit(expr, false);
|
|
473
515
|
return found;
|
|
474
516
|
}
|
|
475
517
|
function getComponentExpressionInfo(exprPath) {
|
|
@@ -561,11 +603,21 @@ function transformPropMemberAccess(expr, scope) {
|
|
|
561
603
|
parent.object = resolveRoot(rootName);
|
|
562
604
|
}
|
|
563
605
|
}
|
|
564
|
-
function visit(node) {
|
|
606
|
+
function visit(node, enterFunction) {
|
|
565
607
|
if (!node || typeof node !== "object")
|
|
566
608
|
return;
|
|
567
|
-
if (
|
|
609
|
+
if (isFunctionLike(node)) {
|
|
610
|
+
if (!enterFunction)
|
|
611
|
+
return;
|
|
612
|
+
for (const param of node.params) {
|
|
613
|
+
visit(param, false);
|
|
614
|
+
}
|
|
615
|
+
visit(node.body, false);
|
|
568
616
|
return;
|
|
617
|
+
}
|
|
618
|
+
if (t.isJSXElement(node) || t.isJSXFragment(node)) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
569
621
|
if (isMemberLike(node)) {
|
|
570
622
|
const rootPath = getMemberExpressionRootAndPath(node);
|
|
571
623
|
if (rootPath) {
|
|
@@ -578,6 +630,10 @@ function transformPropMemberAccess(expr, scope) {
|
|
|
578
630
|
}
|
|
579
631
|
return;
|
|
580
632
|
}
|
|
633
|
+
if (isCallLike(node)) {
|
|
634
|
+
visitCallCalleeAndArgs(node, visit);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
581
637
|
for (const key of Object.keys(node)) {
|
|
582
638
|
if (key === "loc" || key === "start" || key === "end" || key === "leadingComments" || key === "trailingComments")
|
|
583
639
|
continue;
|
|
@@ -585,14 +641,14 @@ function transformPropMemberAccess(expr, scope) {
|
|
|
585
641
|
if (Array.isArray(value)) {
|
|
586
642
|
for (const item of value) {
|
|
587
643
|
if (item && typeof item === "object")
|
|
588
|
-
visit(item);
|
|
644
|
+
visit(item, false);
|
|
589
645
|
}
|
|
590
646
|
} else if (value && typeof value === "object") {
|
|
591
|
-
visit(value);
|
|
647
|
+
visit(value, false);
|
|
592
648
|
}
|
|
593
649
|
}
|
|
594
650
|
}
|
|
595
|
-
visit(expr);
|
|
651
|
+
visit(expr, false);
|
|
596
652
|
return changed;
|
|
597
653
|
}
|
|
598
654
|
function wrapExpression(expr) {
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
package/docs/README.md
CHANGED
package/docs/plugins.md
CHANGED
|
@@ -51,6 +51,7 @@ The Vite plugin sets `resolve.dedupe: ["sinwan"]` for the same duplicate-runtime
|
|
|
51
51
|
| Option | Default | Role |
|
|
52
52
|
| ------ | ------- | ---- |
|
|
53
53
|
| `hoist` | `true` | Template hoisting |
|
|
54
|
+
| `dev` | Bun: `NODE_ENV !== "production"` at `sinwan()`; Vite: `config.mode !== "production"` | Warn when hoisting is skipped. Pass `false` for library/`Bun.build` production bundles. |
|
|
54
55
|
| `explicitBindings` | `false` | `_$bind*` helpers instead of bare `() =>` |
|
|
55
56
|
| `analyze` | unset | Path to CLI JSON (production) |
|
|
56
57
|
| `cache` | `true` | Incremental analyzer in dev. `false` turns it off. An object sets `root`, `tsConfigPath`, `bunfigPath`, `workspaces`, `cachePath` |
|
package/docs/transform.md
CHANGED
|
@@ -72,12 +72,14 @@ Reads the compiler wraps:
|
|
|
72
72
|
- `useState` getters: `count()`
|
|
73
73
|
- `useFetch` signal values: `f.data.value` (not the shell `f` or `f.data`)
|
|
74
74
|
- Calls to a **local** function whose body reads one of the above
|
|
75
|
+
- Reads **inside call callbacks** that run while the JSX expression is evaluated: `.map` / `.filter` / `Array.from` callbacks, IIFEs, and default parameters of those callbacks. `<For each={keys.map((k) => groups[query.value])}>` becomes `each={() => keys.map(...)}`. Nested JSX inside those callbacks is a separate wrap site (`items.map((i) => <span>{count.value}</span>)` wraps the inner text, not the whole map).
|
|
75
76
|
|
|
76
77
|
Not wrapped:
|
|
77
78
|
|
|
78
79
|
- Literals and plain identifiers
|
|
79
80
|
- Event-handler functions (`onClick={fn}` or `onClick={() => …}`)
|
|
80
81
|
- Nested function *values* passed as props (`title={() => s.value}` stays a render prop)
|
|
82
|
+
- Functions stored as object/array values (`{ onClick: () => s.value }`) or returned from a factory (`const make = () => () => s.value`)
|
|
81
83
|
- `useFetch` methods such as `abort` / `execute`
|
|
82
84
|
- Static values the [analyzer](analyzer.md) proved never change
|
|
83
85
|
|