sinwan-compiler 0.2.3 → 0.2.5
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/README.md +37 -14
- package/dist/analyze.d.ts +0 -1
- package/dist/{chunk-w580fdrf.js → chunk-m4rk009c.js} +169 -219
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +5 -3
- package/dist/index.js +51 -40
- package/dist/reactive-wrap.d.ts +4 -0
- package/dist/transform.d.ts +3 -3
- package/docs/README.md +38 -19
- package/docs/analyzer.md +63 -52
- package/docs/api.md +77 -26
- package/docs/architecture.md +52 -49
- package/docs/cli.md +24 -17
- package/docs/plugins.md +35 -32
- package/docs/transform.md +109 -34
- package/package.json +2 -2
|
@@ -46,7 +46,7 @@ function isBuiltinReactiveProp(componentName, attrName) {
|
|
|
46
46
|
function isBuiltinControlFlowComponent(componentName) {
|
|
47
47
|
return !!componentName && BUILTIN_REACTIVE_PROPS.has(componentName);
|
|
48
48
|
}
|
|
49
|
-
function
|
|
49
|
+
function trackReactiveImports2(ast) {
|
|
50
50
|
const names = {
|
|
51
51
|
createMutable: new Set,
|
|
52
52
|
createStore: new Set,
|
|
@@ -57,13 +57,13 @@ function trackReactiveImports(ast) {
|
|
|
57
57
|
cc: new Set
|
|
58
58
|
};
|
|
59
59
|
traverse(ast, {
|
|
60
|
-
ImportDeclaration(
|
|
61
|
-
const source =
|
|
60
|
+
ImportDeclaration(path) {
|
|
61
|
+
const source = path.node.source.value;
|
|
62
62
|
const reactiveAllowed = REACTIVE_SOURCE_MODULES[source];
|
|
63
63
|
const componentAllowed = COMPONENT_FACTORY_MODULES[source];
|
|
64
64
|
if (!reactiveAllowed && !componentAllowed)
|
|
65
65
|
return;
|
|
66
|
-
for (const spec of
|
|
66
|
+
for (const spec of path.node.specifiers) {
|
|
67
67
|
if (!t.isImportSpecifier(spec))
|
|
68
68
|
continue;
|
|
69
69
|
const imported = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
@@ -127,8 +127,8 @@ function isUseFetchCall(expr, names) {
|
|
|
127
127
|
}
|
|
128
128
|
return false;
|
|
129
129
|
}
|
|
130
|
-
function trackLocalScopeBindings(
|
|
131
|
-
|
|
130
|
+
function trackLocalScopeBindings(path, names, scope) {
|
|
131
|
+
path.traverse({
|
|
132
132
|
VariableDeclarator(p) {
|
|
133
133
|
const id = p.node.id;
|
|
134
134
|
const init = p.node.init;
|
|
@@ -174,7 +174,7 @@ function trackLocalScopeBindings(path2, names, scope) {
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
});
|
|
177
|
-
|
|
177
|
+
path.traverse({
|
|
178
178
|
VariableDeclarator(p) {
|
|
179
179
|
const id = p.node.id;
|
|
180
180
|
const init = p.node.init;
|
|
@@ -200,7 +200,7 @@ function trackLocalScopeBindings(path2, names, scope) {
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
});
|
|
203
|
-
|
|
203
|
+
path.traverse({
|
|
204
204
|
"FunctionDeclaration|VariableDeclarator"(p) {
|
|
205
205
|
const node = p.node;
|
|
206
206
|
let fn = null;
|
|
@@ -242,7 +242,7 @@ function trackPropBindings(scope, params, reactiveProps) {
|
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
|
-
function
|
|
245
|
+
function getAllPropNames2(params) {
|
|
246
246
|
if (!params)
|
|
247
247
|
return new Set;
|
|
248
248
|
if (t.isIdentifier(params))
|
|
@@ -269,9 +269,10 @@ function resolveLocalObjectLiteral(fn, name) {
|
|
|
269
269
|
for (const decl of stmt.declarations) {
|
|
270
270
|
if (!t.isIdentifier(decl.id) || decl.id.name !== name)
|
|
271
271
|
continue;
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
272
|
+
const init = decl.init;
|
|
273
|
+
if (!t.isObjectExpression(init))
|
|
274
|
+
continue;
|
|
275
|
+
return init;
|
|
275
276
|
}
|
|
276
277
|
}
|
|
277
278
|
return null;
|
|
@@ -281,7 +282,7 @@ function analyzeObjectLiteralSpread(spread, fullScope, calleeReactive) {
|
|
|
281
282
|
if (t.isObjectProperty(prop) && !prop.computed) {
|
|
282
283
|
const key = prop.key;
|
|
283
284
|
const name = t.isIdentifier(key) ? key.name : t.isStringLiteral(key) ? key.value : null;
|
|
284
|
-
if (name &&
|
|
285
|
+
if (name && containsReactiveValue2(prop.value, fullScope)) {
|
|
285
286
|
calleeReactive.add(name);
|
|
286
287
|
}
|
|
287
288
|
}
|
|
@@ -291,7 +292,7 @@ function isMemberLike(node) {
|
|
|
291
292
|
return t.isMemberExpression(node) || t.isOptionalMemberExpression(node);
|
|
292
293
|
}
|
|
293
294
|
function getMemberExpressionRootAndPath(node) {
|
|
294
|
-
const
|
|
295
|
+
const path = [];
|
|
295
296
|
let current = node;
|
|
296
297
|
while (true) {
|
|
297
298
|
if (t.isTSNonNullExpression(current)) {
|
|
@@ -303,14 +304,14 @@ function getMemberExpressionRootAndPath(node) {
|
|
|
303
304
|
return null;
|
|
304
305
|
if (!t.isIdentifier(current.property))
|
|
305
306
|
return null;
|
|
306
|
-
|
|
307
|
+
path.push(current.property.name);
|
|
307
308
|
current = current.object;
|
|
308
309
|
continue;
|
|
309
310
|
}
|
|
310
311
|
break;
|
|
311
312
|
}
|
|
312
313
|
if (t.isIdentifier(current)) {
|
|
313
|
-
return { root: current.name, path:
|
|
314
|
+
return { root: current.name, path: path.reverse() };
|
|
314
315
|
}
|
|
315
316
|
return null;
|
|
316
317
|
}
|
|
@@ -319,13 +320,13 @@ function isReactiveRead(node, scope) {
|
|
|
319
320
|
return isReactiveRead(node.expression, scope);
|
|
320
321
|
}
|
|
321
322
|
if (t.isIdentifier(node)) {
|
|
322
|
-
const
|
|
323
|
-
if (!
|
|
323
|
+
const binding = scope.bindings.get(node.name);
|
|
324
|
+
if (!binding)
|
|
324
325
|
return false;
|
|
325
|
-
if (
|
|
326
|
+
if (binding.kind === "prop") {
|
|
326
327
|
return true;
|
|
327
328
|
}
|
|
328
|
-
if (
|
|
329
|
+
if (binding.kind === "mutable" && binding.path.length > 0) {
|
|
329
330
|
return true;
|
|
330
331
|
}
|
|
331
332
|
return false;
|
|
@@ -359,15 +360,15 @@ function isGetterCall(node, scope) {
|
|
|
359
360
|
const binding = scope.bindings.get(callee.name);
|
|
360
361
|
return binding?.kind === "getter";
|
|
361
362
|
}
|
|
362
|
-
function
|
|
363
|
+
function isReactiveValue2(node, scope) {
|
|
363
364
|
if (t.isTSNonNullExpression(node)) {
|
|
364
|
-
return
|
|
365
|
+
return isReactiveValue2(node.expression, scope);
|
|
365
366
|
}
|
|
366
367
|
if (t.isIdentifier(node)) {
|
|
367
|
-
const
|
|
368
|
-
if (!
|
|
368
|
+
const binding = scope.bindings.get(node.name);
|
|
369
|
+
if (!binding)
|
|
369
370
|
return false;
|
|
370
|
-
return
|
|
371
|
+
return binding.kind === "prop" || binding.kind === "signal" || binding.kind === "computed" || binding.kind === "mutable";
|
|
371
372
|
}
|
|
372
373
|
if (!isMemberLike(node))
|
|
373
374
|
return false;
|
|
@@ -388,7 +389,7 @@ function isReactiveValue(node, scope) {
|
|
|
388
389
|
}
|
|
389
390
|
return false;
|
|
390
391
|
}
|
|
391
|
-
function
|
|
392
|
+
function containsReactiveValue2(expr, scope) {
|
|
392
393
|
let found = false;
|
|
393
394
|
function visit(node) {
|
|
394
395
|
if (found)
|
|
@@ -396,7 +397,7 @@ function containsReactiveValue(expr, scope) {
|
|
|
396
397
|
if (!node || typeof node !== "object")
|
|
397
398
|
return;
|
|
398
399
|
if (isMemberLike(node) || t.isTSNonNullExpression(node) || t.isIdentifier(node)) {
|
|
399
|
-
if (
|
|
400
|
+
if (isReactiveValue2(node, scope)) {
|
|
400
401
|
found = true;
|
|
401
402
|
return;
|
|
402
403
|
}
|
|
@@ -503,24 +504,21 @@ function getComponentExpressionInfo(exprPath) {
|
|
|
503
504
|
}
|
|
504
505
|
return { isComponent: true, componentName, attributeName };
|
|
505
506
|
}
|
|
506
|
-
function isReactiveComponentProp(
|
|
507
|
-
if (
|
|
508
|
-
return false;
|
|
509
|
-
}
|
|
510
|
-
if (isBuiltinReactiveProp(info.componentName, info.attributeName)) {
|
|
507
|
+
function isReactiveComponentProp(componentName, attributeName, componentNames, reactiveProps, importedReactiveProps) {
|
|
508
|
+
if (isBuiltinReactiveProp(componentName, attributeName)) {
|
|
511
509
|
return true;
|
|
512
510
|
}
|
|
513
|
-
const componentFn = componentNames.get(
|
|
511
|
+
const componentFn = componentNames.get(componentName);
|
|
514
512
|
if (componentFn) {
|
|
515
513
|
const props = reactiveProps.get(componentFn);
|
|
516
514
|
if (!props)
|
|
517
515
|
return false;
|
|
518
|
-
return props.has(
|
|
516
|
+
return props.has(attributeName);
|
|
519
517
|
}
|
|
520
|
-
const importedProps = importedReactiveProps.get(
|
|
518
|
+
const importedProps = importedReactiveProps.get(componentName);
|
|
521
519
|
if (!importedProps)
|
|
522
520
|
return false;
|
|
523
|
-
return importedProps.has(
|
|
521
|
+
return importedProps.has(attributeName);
|
|
524
522
|
}
|
|
525
523
|
function shouldWrap(expr, scope) {
|
|
526
524
|
if (t.isArrowFunctionExpression(expr) || t.isFunctionExpression(expr))
|
|
@@ -615,43 +613,34 @@ function createBindingDescriptor(expr, exprPath, options) {
|
|
|
615
613
|
}
|
|
616
614
|
return t.callExpression(t.identifier("_$bindText"), [wrapExpression(expr)]);
|
|
617
615
|
}
|
|
618
|
-
function
|
|
616
|
+
function collectComponentFunctions2(ast, ccNames) {
|
|
619
617
|
const functions = new Set;
|
|
620
618
|
const names = new Map;
|
|
621
619
|
const exported = new Set;
|
|
622
620
|
if (ccNames.size === 0)
|
|
623
621
|
return { functions, names, exported };
|
|
624
622
|
traverse(ast, {
|
|
625
|
-
CallExpression(
|
|
626
|
-
const callee =
|
|
623
|
+
CallExpression(path) {
|
|
624
|
+
const callee = path.node.callee;
|
|
627
625
|
if (!t.isIdentifier(callee) || !ccNames.has(callee.name))
|
|
628
626
|
return;
|
|
629
|
-
const firstArg =
|
|
627
|
+
const firstArg = path.node.arguments[0];
|
|
630
628
|
if (!firstArg || !t.isFunction(firstArg))
|
|
631
629
|
return;
|
|
632
630
|
const componentFn = firstArg;
|
|
633
631
|
functions.add(componentFn);
|
|
634
|
-
const parent =
|
|
632
|
+
const parent = path.parentPath;
|
|
635
633
|
if (parent && parent.isVariableDeclarator && parent.isVariableDeclarator()) {
|
|
636
634
|
const id = parent.node.id;
|
|
637
635
|
if (t.isIdentifier(id)) {
|
|
638
636
|
names.set(id.name, componentFn);
|
|
639
637
|
}
|
|
640
|
-
} else if (parent && parent.isExportNamedDeclaration && parent.isExportNamedDeclaration()) {
|
|
641
|
-
const declaration = parent.node.declaration;
|
|
642
|
-
if (t.isVariableDeclaration(declaration)) {
|
|
643
|
-
for (const decl of declaration.declarations) {
|
|
644
|
-
if (t.isIdentifier(decl.id)) {
|
|
645
|
-
names.set(decl.id.name, componentFn);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
638
|
}
|
|
650
639
|
}
|
|
651
640
|
});
|
|
652
641
|
traverse(ast, {
|
|
653
|
-
ExportNamedDeclaration(
|
|
654
|
-
const declaration =
|
|
642
|
+
ExportNamedDeclaration(path) {
|
|
643
|
+
const declaration = path.node.declaration;
|
|
655
644
|
if (!t.isVariableDeclaration(declaration))
|
|
656
645
|
return;
|
|
657
646
|
for (const decl of declaration.declarations) {
|
|
@@ -667,8 +656,8 @@ function collectComponentFunctions(ast, ccNames) {
|
|
|
667
656
|
exported.add(firstArg);
|
|
668
657
|
}
|
|
669
658
|
},
|
|
670
|
-
ExportDefaultDeclaration(
|
|
671
|
-
const decl =
|
|
659
|
+
ExportDefaultDeclaration(path) {
|
|
660
|
+
const decl = path.node.declaration;
|
|
672
661
|
if (t.isIdentifier(decl)) {
|
|
673
662
|
const componentFn = names.get(decl.name);
|
|
674
663
|
if (componentFn) {
|
|
@@ -687,36 +676,36 @@ function collectComponentFunctions(ast, ccNames) {
|
|
|
687
676
|
});
|
|
688
677
|
return { functions, names, exported };
|
|
689
678
|
}
|
|
690
|
-
function
|
|
679
|
+
function computeLocalScopes2(ast, names) {
|
|
691
680
|
const scopes = new Map;
|
|
692
681
|
traverse(ast, {
|
|
693
|
-
Function(
|
|
682
|
+
Function(path) {
|
|
694
683
|
const scope = { bindings: new Map };
|
|
695
|
-
trackLocalScopeBindings(
|
|
696
|
-
scopes.set(
|
|
684
|
+
trackLocalScopeBindings(path, names, scope);
|
|
685
|
+
scopes.set(path.node, scope);
|
|
697
686
|
}
|
|
698
687
|
});
|
|
699
688
|
return scopes;
|
|
700
689
|
}
|
|
701
|
-
function
|
|
690
|
+
function collectComponentCallGraph2(ast, componentNames) {
|
|
702
691
|
const callGraph = new Map;
|
|
703
692
|
if (componentNames.size === 0)
|
|
704
693
|
return callGraph;
|
|
705
694
|
traverse(ast, {
|
|
706
|
-
JSXElement(
|
|
707
|
-
const name =
|
|
695
|
+
JSXElement(path) {
|
|
696
|
+
const name = path.node.openingElement.name;
|
|
708
697
|
if (!t.isJSXIdentifier(name))
|
|
709
698
|
return;
|
|
710
699
|
const callee = componentNames.get(name.name);
|
|
711
700
|
if (!callee)
|
|
712
701
|
return;
|
|
713
|
-
const callerPath =
|
|
702
|
+
const callerPath = path.findParent((p) => p.isFunction());
|
|
714
703
|
const callerFn = callerPath ? callerPath.node : null;
|
|
715
704
|
if (!callerFn)
|
|
716
705
|
return;
|
|
717
706
|
const props = [];
|
|
718
707
|
const spreads = [];
|
|
719
|
-
for (const attr of
|
|
708
|
+
for (const attr of path.node.openingElement.attributes) {
|
|
720
709
|
if (t.isJSXSpreadAttribute(attr)) {
|
|
721
710
|
if (attr.argument) {
|
|
722
711
|
spreads.push(attr.argument);
|
|
@@ -736,7 +725,7 @@ function collectComponentCallGraph(ast, componentNames) {
|
|
|
736
725
|
}
|
|
737
726
|
}
|
|
738
727
|
const childExprs = [];
|
|
739
|
-
for (const child of
|
|
728
|
+
for (const child of path.node.children) {
|
|
740
729
|
if (t.isJSXExpressionContainer(child)) {
|
|
741
730
|
const expr = child.expression;
|
|
742
731
|
if (!expr || t.isJSXEmptyExpression(expr))
|
|
@@ -756,7 +745,7 @@ function collectComponentCallGraph(ast, componentNames) {
|
|
|
756
745
|
});
|
|
757
746
|
return callGraph;
|
|
758
747
|
}
|
|
759
|
-
function
|
|
748
|
+
function buildFullScope2(localScopes, fn, reactiveProps) {
|
|
760
749
|
const localScope = localScopes.get(fn);
|
|
761
750
|
if (!localScope)
|
|
762
751
|
return null;
|
|
@@ -764,7 +753,7 @@ function buildFullScope(localScopes, fn, reactiveProps) {
|
|
|
764
753
|
trackPropBindings(fullScope, fn.params[0], reactiveProps);
|
|
765
754
|
return fullScope;
|
|
766
755
|
}
|
|
767
|
-
function
|
|
756
|
+
function propagateReactiveProps2(localScopes, callGraph, componentFunctions) {
|
|
768
757
|
const reactiveProps = new Map;
|
|
769
758
|
for (const [callerFn, sites] of callGraph) {
|
|
770
759
|
const localScope = localScopes.get(callerFn);
|
|
@@ -773,7 +762,7 @@ function propagateReactiveProps(localScopes, callGraph, componentFunctions) {
|
|
|
773
762
|
for (const site of sites) {
|
|
774
763
|
const calleeReactive = reactiveProps.get(site.callee) ?? new Set;
|
|
775
764
|
for (const prop of site.props) {
|
|
776
|
-
if (
|
|
765
|
+
if (containsReactiveValue2(prop.value, localScope)) {
|
|
777
766
|
calleeReactive.add(prop.name);
|
|
778
767
|
}
|
|
779
768
|
}
|
|
@@ -785,7 +774,7 @@ function propagateReactiveProps(localScopes, callGraph, componentFunctions) {
|
|
|
785
774
|
const callerFn = worklist.values().next().value;
|
|
786
775
|
worklist.delete(callerFn);
|
|
787
776
|
const callerReactive = reactiveProps.get(callerFn) ?? new Set;
|
|
788
|
-
const fullScope =
|
|
777
|
+
const fullScope = buildFullScope2(localScopes, callerFn, callerReactive);
|
|
789
778
|
if (!fullScope)
|
|
790
779
|
continue;
|
|
791
780
|
const sites = callGraph.get(callerFn) ?? [];
|
|
@@ -793,7 +782,7 @@ function propagateReactiveProps(localScopes, callGraph, componentFunctions) {
|
|
|
793
782
|
const calleeReactive = reactiveProps.get(site.callee) ?? new Set;
|
|
794
783
|
const initialSize = calleeReactive.size;
|
|
795
784
|
for (const prop of site.props) {
|
|
796
|
-
if (
|
|
785
|
+
if (containsReactiveValue2(prop.value, fullScope)) {
|
|
797
786
|
calleeReactive.add(prop.name);
|
|
798
787
|
}
|
|
799
788
|
}
|
|
@@ -802,7 +791,7 @@ function propagateReactiveProps(localScopes, callGraph, componentFunctions) {
|
|
|
802
791
|
if (resolved) {
|
|
803
792
|
analyzeObjectLiteralSpread(resolved, fullScope, calleeReactive);
|
|
804
793
|
} else {
|
|
805
|
-
const allCalleeProps =
|
|
794
|
+
const allCalleeProps = getAllPropNames2(site.callee.params[0]);
|
|
806
795
|
for (const propName of allCalleeProps) {
|
|
807
796
|
calleeReactive.add(propName);
|
|
808
797
|
}
|
|
@@ -816,13 +805,13 @@ function propagateReactiveProps(localScopes, callGraph, componentFunctions) {
|
|
|
816
805
|
}
|
|
817
806
|
return reactiveProps;
|
|
818
807
|
}
|
|
819
|
-
function
|
|
808
|
+
function wrapReactiveExpressions2(ast, options = {}) {
|
|
820
809
|
let metadata = null;
|
|
821
810
|
if (options.analyzeMetadata) {
|
|
822
811
|
metadata = options.analyzeMetadata;
|
|
823
812
|
} else if (options.analyze && options.filename) {
|
|
824
813
|
try {
|
|
825
|
-
metadata =
|
|
814
|
+
metadata = loadMetadata2(options.analyze);
|
|
826
815
|
} catch {
|
|
827
816
|
metadata = null;
|
|
828
817
|
}
|
|
@@ -906,15 +895,6 @@ function wrapReactiveExpressions(ast, options = {}) {
|
|
|
906
895
|
if (t.isIdentifier(id)) {
|
|
907
896
|
componentNames.set(id.name, componentFn);
|
|
908
897
|
}
|
|
909
|
-
} else if (parent && parent.isExportNamedDeclaration && parent.isExportNamedDeclaration()) {
|
|
910
|
-
const declaration = parent.node.declaration;
|
|
911
|
-
if (t.isVariableDeclaration(declaration)) {
|
|
912
|
-
for (const decl of declaration.declarations) {
|
|
913
|
-
if (t.isIdentifier(decl.id)) {
|
|
914
|
-
componentNames.set(decl.id.name, componentFn);
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
898
|
}
|
|
919
899
|
},
|
|
920
900
|
ExportNamedDeclaration(p) {
|
|
@@ -1028,48 +1008,48 @@ function wrapReactiveExpressions(ast, options = {}) {
|
|
|
1028
1008
|
const hasAnyImport = Object.values(names).some((s) => s.size > 0);
|
|
1029
1009
|
if (!hasAnyImport)
|
|
1030
1010
|
return;
|
|
1031
|
-
const reactiveProps =
|
|
1011
|
+
const reactiveProps = propagateReactiveProps2(localScopes, callGraph, componentFunctions);
|
|
1032
1012
|
let needsResolve = false;
|
|
1033
1013
|
traverse(ast, {
|
|
1034
|
-
Function(
|
|
1035
|
-
const scope = localScopes.get(
|
|
1014
|
+
Function(path) {
|
|
1015
|
+
const scope = localScopes.get(path.node);
|
|
1036
1016
|
if (!scope)
|
|
1037
1017
|
return;
|
|
1038
|
-
const isComponent = componentFunctions.has(
|
|
1018
|
+
const isComponent = componentFunctions.has(path.node);
|
|
1039
1019
|
if (isComponent) {
|
|
1040
|
-
const isExported = exported.has(
|
|
1020
|
+
const isExported = exported.has(path.node);
|
|
1041
1021
|
if (isExported) {
|
|
1042
1022
|
let props = null;
|
|
1043
1023
|
if (metadata && absoluteFilename) {
|
|
1044
1024
|
const fileProps = metadata.get(absoluteFilename);
|
|
1045
|
-
const exportName = exportNameByFn.get(
|
|
1025
|
+
const exportName = exportNameByFn.get(path.node);
|
|
1046
1026
|
if (fileProps && exportName) {
|
|
1047
1027
|
props = fileProps.get(exportName) ?? null;
|
|
1048
1028
|
}
|
|
1049
1029
|
}
|
|
1050
1030
|
if (props) {
|
|
1051
|
-
trackPropBindings(scope,
|
|
1031
|
+
trackPropBindings(scope, path.node.params[0], props);
|
|
1052
1032
|
} else {
|
|
1053
|
-
const allProps =
|
|
1054
|
-
trackPropBindings(scope,
|
|
1033
|
+
const allProps = getAllPropNames2(path.node.params[0]);
|
|
1034
|
+
trackPropBindings(scope, path.node.params[0], allProps);
|
|
1055
1035
|
}
|
|
1056
|
-
} else if (reactiveProps.has(
|
|
1057
|
-
const props = reactiveProps.get(
|
|
1058
|
-
trackPropBindings(scope,
|
|
1036
|
+
} else if (reactiveProps.has(path.node)) {
|
|
1037
|
+
const props = reactiveProps.get(path.node);
|
|
1038
|
+
trackPropBindings(scope, path.node.params[0], props);
|
|
1059
1039
|
} else {
|
|
1060
|
-
const allProps =
|
|
1061
|
-
trackPropBindings(scope,
|
|
1040
|
+
const allProps = getAllPropNames2(path.node.params[0]);
|
|
1041
|
+
trackPropBindings(scope, path.node.params[0], allProps);
|
|
1062
1042
|
}
|
|
1063
1043
|
}
|
|
1064
1044
|
if (scope.bindings.size === 0)
|
|
1065
1045
|
return;
|
|
1066
|
-
|
|
1046
|
+
path.traverse({
|
|
1067
1047
|
JSXExpressionContainer(exprPath) {
|
|
1068
1048
|
const expr = exprPath.node.expression;
|
|
1069
1049
|
const compInfo = getComponentExpressionInfo(exprPath);
|
|
1070
1050
|
if (compInfo.isComponent) {
|
|
1071
1051
|
if (compInfo.attributeName !== null) {
|
|
1072
|
-
if (!isReactiveComponentProp(compInfo, componentNames, reactiveProps, importedReactiveProps)) {
|
|
1052
|
+
if (!compInfo.componentName || !isReactiveComponentProp(compInfo.componentName, compInfo.attributeName, componentNames, reactiveProps, importedReactiveProps)) {
|
|
1073
1053
|
return;
|
|
1074
1054
|
}
|
|
1075
1055
|
} else {
|
|
@@ -1126,11 +1106,9 @@ function containsJsx(node, enterFunctions) {
|
|
|
1126
1106
|
continue;
|
|
1127
1107
|
const val = node[key];
|
|
1128
1108
|
if (Array.isArray(val)) {
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1109
|
+
const foundInArray = val.some((item) => Boolean(item) && typeof item === "object" && containsJsx(item, enterFunctions));
|
|
1110
|
+
if (foundInArray)
|
|
1111
|
+
return true;
|
|
1134
1112
|
} else if (val && typeof val === "object" && containsJsx(val, enterFunctions)) {
|
|
1135
1113
|
return true;
|
|
1136
1114
|
}
|
|
@@ -1167,11 +1145,11 @@ function isComponentArity(fn) {
|
|
|
1167
1145
|
function collectCcAliases(ast) {
|
|
1168
1146
|
const aliases = new Set;
|
|
1169
1147
|
traverse2(ast, {
|
|
1170
|
-
ImportDeclaration(
|
|
1171
|
-
const source =
|
|
1148
|
+
ImportDeclaration(path) {
|
|
1149
|
+
const source = path.node.source.value;
|
|
1172
1150
|
if (!CC_SOURCE_MODULES.has(source))
|
|
1173
1151
|
return;
|
|
1174
|
-
for (const spec of
|
|
1152
|
+
for (const spec of path.node.specifiers) {
|
|
1175
1153
|
if (!t2.isImportSpecifier(spec))
|
|
1176
1154
|
continue;
|
|
1177
1155
|
const imported = t2.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
@@ -1186,44 +1164,40 @@ function collectCcAliases(ast) {
|
|
|
1186
1164
|
function ccCall(arg, ccName) {
|
|
1187
1165
|
return t2.callExpression(t2.identifier(ccName), [arg]);
|
|
1188
1166
|
}
|
|
1189
|
-
function
|
|
1167
|
+
function autoWrapComponents2(ast, filename) {
|
|
1190
1168
|
const { aliases, alreadyImported } = collectCcAliases(ast);
|
|
1191
1169
|
const ccName = aliases.values().next().value;
|
|
1192
1170
|
let changed = false;
|
|
1193
1171
|
const wrapIfCandidate = (fnPath, name) => {
|
|
1194
1172
|
if (name !== null && !isComponentName(name))
|
|
1195
|
-
return
|
|
1173
|
+
return false;
|
|
1196
1174
|
const fn = fnPath.node;
|
|
1197
1175
|
if (!isComponentArity(fn))
|
|
1198
|
-
return
|
|
1176
|
+
return false;
|
|
1199
1177
|
if (!functionReturnsJsx(fnPath))
|
|
1200
|
-
return
|
|
1201
|
-
return
|
|
1178
|
+
return false;
|
|
1179
|
+
return true;
|
|
1202
1180
|
};
|
|
1203
1181
|
traverse2(ast, {
|
|
1204
|
-
ExportNamedDeclaration(
|
|
1205
|
-
const decl =
|
|
1182
|
+
ExportNamedDeclaration(path) {
|
|
1183
|
+
const decl = path.node.declaration;
|
|
1206
1184
|
if (!decl)
|
|
1207
1185
|
return;
|
|
1208
1186
|
if (t2.isFunctionDeclaration(decl) && decl.id) {
|
|
1209
1187
|
const name = decl.id.name;
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
const fnPath = path2.get("declaration");
|
|
1213
|
-
if (!isComponentArity(decl))
|
|
1214
|
-
return;
|
|
1215
|
-
if (!functionReturnsJsx(fnPath))
|
|
1188
|
+
const fnPath = path.get("declaration");
|
|
1189
|
+
if (!wrapIfCandidate(fnPath, name))
|
|
1216
1190
|
return;
|
|
1217
1191
|
const fnExpr = t2.functionExpression(decl.id, decl.params, decl.body, decl.generator, decl.async);
|
|
1218
1192
|
const varDecl = t2.variableDeclaration("const", [
|
|
1219
1193
|
t2.variableDeclarator(t2.identifier(name), ccCall(fnExpr, ccName ?? "cc"))
|
|
1220
1194
|
]);
|
|
1221
|
-
|
|
1195
|
+
path.replaceWith(t2.exportNamedDeclaration(varDecl, []));
|
|
1222
1196
|
changed = true;
|
|
1223
1197
|
return;
|
|
1224
1198
|
}
|
|
1225
1199
|
if (t2.isVariableDeclaration(decl)) {
|
|
1226
|
-
for (const dPath of
|
|
1200
|
+
for (const dPath of path.get("declaration.declarations")) {
|
|
1227
1201
|
const id = dPath.node.id;
|
|
1228
1202
|
if (!t2.isIdentifier(id) || !isComponentName(id.name))
|
|
1229
1203
|
continue;
|
|
@@ -1236,9 +1210,7 @@ function autoWrapComponents(ast, filename) {
|
|
|
1236
1210
|
if (!t2.isFunction(init))
|
|
1237
1211
|
continue;
|
|
1238
1212
|
const initPath = dPath.get("init");
|
|
1239
|
-
if (!
|
|
1240
|
-
continue;
|
|
1241
|
-
if (!functionReturnsJsx(initPath))
|
|
1213
|
+
if (!wrapIfCandidate(initPath, id.name))
|
|
1242
1214
|
continue;
|
|
1243
1215
|
dPath.node.init = ccCall(init, ccName ?? "cc");
|
|
1244
1216
|
changed = true;
|
|
@@ -1246,41 +1218,33 @@ function autoWrapComponents(ast, filename) {
|
|
|
1246
1218
|
return;
|
|
1247
1219
|
}
|
|
1248
1220
|
},
|
|
1249
|
-
ExportDefaultDeclaration(
|
|
1250
|
-
const decl =
|
|
1221
|
+
ExportDefaultDeclaration(path) {
|
|
1222
|
+
const decl = path.node.declaration;
|
|
1251
1223
|
if (t2.isFunctionDeclaration(decl) && decl.id) {
|
|
1252
1224
|
const name = decl.id.name;
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
const fnPath = path2.get("declaration");
|
|
1256
|
-
if (!isComponentArity(decl))
|
|
1257
|
-
return;
|
|
1258
|
-
if (!functionReturnsJsx(fnPath))
|
|
1225
|
+
const fnPath = path.get("declaration");
|
|
1226
|
+
if (!wrapIfCandidate(fnPath, name))
|
|
1259
1227
|
return;
|
|
1260
1228
|
const fnDecl = t2.functionDeclaration(decl.id, decl.params, decl.body, decl.generator, decl.async);
|
|
1261
1229
|
const exportDefault = t2.exportDefaultDeclaration(ccCall(t2.identifier(name), ccName ?? "cc"));
|
|
1262
|
-
|
|
1230
|
+
path.replaceWithMultiple([fnDecl, exportDefault]);
|
|
1263
1231
|
changed = true;
|
|
1264
1232
|
return;
|
|
1265
1233
|
}
|
|
1266
1234
|
if (t2.isFunctionDeclaration(decl) && !decl.id) {
|
|
1267
|
-
const fnPath =
|
|
1268
|
-
if (!
|
|
1269
|
-
return;
|
|
1270
|
-
if (!functionReturnsJsx(fnPath))
|
|
1235
|
+
const fnPath = path.get("declaration");
|
|
1236
|
+
if (!wrapIfCandidate(fnPath, null))
|
|
1271
1237
|
return;
|
|
1272
1238
|
const fnExpr = t2.functionExpression(null, decl.params, decl.body, decl.generator, decl.async);
|
|
1273
|
-
|
|
1239
|
+
path.node.declaration = ccCall(fnExpr, ccName ?? "cc");
|
|
1274
1240
|
changed = true;
|
|
1275
1241
|
return;
|
|
1276
1242
|
}
|
|
1277
1243
|
if (t2.isArrowFunctionExpression(decl) || t2.isFunctionExpression(decl)) {
|
|
1278
|
-
const declPath =
|
|
1279
|
-
if (!
|
|
1280
|
-
return;
|
|
1281
|
-
if (!functionReturnsJsx(declPath))
|
|
1244
|
+
const declPath = path.get("declaration");
|
|
1245
|
+
if (!wrapIfCandidate(declPath, null))
|
|
1282
1246
|
return;
|
|
1283
|
-
|
|
1247
|
+
path.node.declaration = ccCall(decl, ccName ?? "cc");
|
|
1284
1248
|
changed = true;
|
|
1285
1249
|
return;
|
|
1286
1250
|
}
|
|
@@ -1303,11 +1267,11 @@ function refKey(ref) {
|
|
|
1303
1267
|
function findFunctionByRef(ast, ref) {
|
|
1304
1268
|
let found = null;
|
|
1305
1269
|
traverse3(ast, {
|
|
1306
|
-
Function(
|
|
1307
|
-
const node =
|
|
1270
|
+
Function(path) {
|
|
1271
|
+
const node = path.node;
|
|
1308
1272
|
if (node.start === ref.start && node.end === ref.end) {
|
|
1309
1273
|
found = node;
|
|
1310
|
-
|
|
1274
|
+
path.stop();
|
|
1311
1275
|
}
|
|
1312
1276
|
}
|
|
1313
1277
|
});
|
|
@@ -1407,16 +1371,18 @@ function restoreModule(filePath, serialized) {
|
|
|
1407
1371
|
const callerFn = findFunctionByRef(ast, ref);
|
|
1408
1372
|
if (!callerFn)
|
|
1409
1373
|
return null;
|
|
1410
|
-
|
|
1374
|
+
const restored = [];
|
|
1375
|
+
for (const s of sites) {
|
|
1411
1376
|
const callee = findFunctionByRef(ast, s.callee);
|
|
1412
1377
|
if (!callee)
|
|
1413
|
-
|
|
1414
|
-
|
|
1378
|
+
return null;
|
|
1379
|
+
restored.push({
|
|
1415
1380
|
callee,
|
|
1416
1381
|
props: s.props,
|
|
1417
1382
|
spreads: s.spreads
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
localCallGraph.set(callerFn, restored);
|
|
1420
1386
|
}
|
|
1421
1387
|
const importedCallSites = [];
|
|
1422
1388
|
for (const s of serialized.importedCallSites) {
|
|
@@ -1459,9 +1425,9 @@ function parseRefKey(key) {
|
|
|
1459
1425
|
function collectImports(ast) {
|
|
1460
1426
|
const imports = new Map;
|
|
1461
1427
|
traverse3(ast, {
|
|
1462
|
-
ImportDeclaration(
|
|
1463
|
-
const source =
|
|
1464
|
-
for (const spec of
|
|
1428
|
+
ImportDeclaration(path) {
|
|
1429
|
+
const source = path.node.source.value;
|
|
1430
|
+
for (const spec of path.node.specifiers) {
|
|
1465
1431
|
if (t3.isImportSpecifier(spec)) {
|
|
1466
1432
|
const localName = spec.local.name;
|
|
1467
1433
|
const importedName = t3.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
@@ -1477,8 +1443,8 @@ function collectImports(ast) {
|
|
|
1477
1443
|
function collectImportedCallSites(ast, componentNames, imports) {
|
|
1478
1444
|
const sites = [];
|
|
1479
1445
|
traverse3(ast, {
|
|
1480
|
-
JSXElement(
|
|
1481
|
-
const name =
|
|
1446
|
+
JSXElement(path) {
|
|
1447
|
+
const name = path.node.openingElement.name;
|
|
1482
1448
|
if (!t3.isJSXIdentifier(name))
|
|
1483
1449
|
return;
|
|
1484
1450
|
const tagName = name.name;
|
|
@@ -1489,13 +1455,13 @@ function collectImportedCallSites(ast, componentNames, imports) {
|
|
|
1489
1455
|
const importInfo = imports.get(tagName);
|
|
1490
1456
|
if (!importInfo)
|
|
1491
1457
|
return;
|
|
1492
|
-
const callerPath =
|
|
1458
|
+
const callerPath = path.findParent((p) => p.isFunction());
|
|
1493
1459
|
if (!callerPath)
|
|
1494
1460
|
return;
|
|
1495
1461
|
const callerFn = callerPath.node;
|
|
1496
1462
|
const props = [];
|
|
1497
1463
|
const spreads = [];
|
|
1498
|
-
for (const attr of
|
|
1464
|
+
for (const attr of path.node.openingElement.attributes) {
|
|
1499
1465
|
if (t3.isJSXSpreadAttribute(attr)) {
|
|
1500
1466
|
if (attr.argument) {
|
|
1501
1467
|
spreads.push(attr.argument);
|
|
@@ -1515,7 +1481,7 @@ function collectImportedCallSites(ast, componentNames, imports) {
|
|
|
1515
1481
|
}
|
|
1516
1482
|
}
|
|
1517
1483
|
const childExprs = [];
|
|
1518
|
-
for (const child of
|
|
1484
|
+
for (const child of path.node.children) {
|
|
1519
1485
|
if (t3.isJSXExpressionContainer(child)) {
|
|
1520
1486
|
const expr = child.expression;
|
|
1521
1487
|
if (!expr || t3.isJSXEmptyExpression(expr))
|
|
@@ -1539,20 +1505,20 @@ function collectImportedCallSites(ast, componentNames, imports) {
|
|
|
1539
1505
|
});
|
|
1540
1506
|
return sites;
|
|
1541
1507
|
}
|
|
1542
|
-
function
|
|
1508
|
+
function analyzeModule2(code, filePath) {
|
|
1543
1509
|
const ast = parse(code, {
|
|
1544
1510
|
sourceType: "module",
|
|
1545
1511
|
plugins: ["jsx", "typescript"]
|
|
1546
1512
|
});
|
|
1547
|
-
|
|
1548
|
-
const names =
|
|
1513
|
+
autoWrapComponents2(ast, filePath);
|
|
1514
|
+
const names = trackReactiveImports2(ast);
|
|
1549
1515
|
const {
|
|
1550
1516
|
functions,
|
|
1551
1517
|
names: componentNames,
|
|
1552
1518
|
exported
|
|
1553
|
-
} =
|
|
1554
|
-
const localScopes =
|
|
1555
|
-
const localCallGraph =
|
|
1519
|
+
} = collectComponentFunctions2(ast, names.cc);
|
|
1520
|
+
const localScopes = computeLocalScopes2(ast, names);
|
|
1521
|
+
const localCallGraph = collectComponentCallGraph2(ast, componentNames);
|
|
1556
1522
|
const imports = collectImports(ast);
|
|
1557
1523
|
const importedCallSites = collectImportedCallSites(ast, componentNames, imports);
|
|
1558
1524
|
const exports = new Map;
|
|
@@ -1563,8 +1529,8 @@ function analyzeModule(code, filePath) {
|
|
|
1563
1529
|
}
|
|
1564
1530
|
}
|
|
1565
1531
|
traverse3(ast, {
|
|
1566
|
-
ExportDefaultDeclaration(
|
|
1567
|
-
const decl =
|
|
1532
|
+
ExportDefaultDeclaration(path) {
|
|
1533
|
+
const decl = path.node.declaration;
|
|
1568
1534
|
if (t3.isIdentifier(decl)) {
|
|
1569
1535
|
const fn = componentNames.get(decl.name);
|
|
1570
1536
|
if (fn)
|
|
@@ -1955,20 +1921,20 @@ function findFiles(root, extensions) {
|
|
|
1955
1921
|
walk(root);
|
|
1956
1922
|
return files;
|
|
1957
1923
|
}
|
|
1958
|
-
function
|
|
1924
|
+
function analyzeProject2(options) {
|
|
1959
1925
|
const extensions = options.extensions ?? [".tsx", ".ts", ".jsx", ".js"];
|
|
1960
|
-
const
|
|
1926
|
+
const resolve = options.resolve ?? createResolver(options.root, extensions, options.tsConfigPath, options.bunfigPath, options.workspaces);
|
|
1961
1927
|
const modules = new Map;
|
|
1962
1928
|
const providedFiles = options.files;
|
|
1963
1929
|
if (providedFiles) {
|
|
1964
1930
|
for (const [filePath, code] of Object.entries(providedFiles)) {
|
|
1965
|
-
modules.set(filePath,
|
|
1931
|
+
modules.set(filePath, analyzeModule2(code, filePath));
|
|
1966
1932
|
}
|
|
1967
1933
|
} else {
|
|
1968
1934
|
const files = findFiles(options.root, extensions);
|
|
1969
1935
|
for (const file of files) {
|
|
1970
1936
|
const code = fs.readFileSync(file, "utf-8");
|
|
1971
|
-
modules.set(file,
|
|
1937
|
+
modules.set(file, analyzeModule2(code, file));
|
|
1972
1938
|
}
|
|
1973
1939
|
}
|
|
1974
1940
|
function ensureAnalyzed(filePath) {
|
|
@@ -1976,7 +1942,7 @@ function analyzeProject(options) {
|
|
|
1976
1942
|
return modules.get(filePath);
|
|
1977
1943
|
try {
|
|
1978
1944
|
const code = fs.readFileSync(filePath, "utf-8");
|
|
1979
|
-
const mod =
|
|
1945
|
+
const mod = analyzeModule2(code, filePath);
|
|
1980
1946
|
modules.set(filePath, mod);
|
|
1981
1947
|
return mod;
|
|
1982
1948
|
} catch {
|
|
@@ -1999,13 +1965,13 @@ function analyzeProject(options) {
|
|
|
1999
1965
|
globalCallGraph.set(callerFn, list);
|
|
2000
1966
|
}
|
|
2001
1967
|
}
|
|
2002
|
-
const reactiveProps = buildProjectReactiveProps(modules,
|
|
1968
|
+
const reactiveProps = buildProjectReactiveProps(modules, resolve, globalLocalScopes, globalCallGraph, globalComponentFunctions, ensureAnalyzed);
|
|
2003
1969
|
return { modules, reactiveProps };
|
|
2004
1970
|
}
|
|
2005
|
-
function buildProjectReactiveProps(modules,
|
|
1971
|
+
function buildProjectReactiveProps(modules, resolve, globalLocalScopes, globalCallGraph, globalComponentFunctions, ensureAnalyzed) {
|
|
2006
1972
|
for (const mod of modules.values()) {
|
|
2007
1973
|
for (const site of mod.importedCallSites) {
|
|
2008
|
-
const resolvedFile =
|
|
1974
|
+
const resolvedFile = resolve(site.source, mod.filePath);
|
|
2009
1975
|
if (!resolvedFile)
|
|
2010
1976
|
continue;
|
|
2011
1977
|
let targetMod = modules.get(resolvedFile);
|
|
@@ -2019,9 +1985,9 @@ function buildProjectReactiveProps(modules, resolve3, globalLocalScopes, globalC
|
|
|
2019
1985
|
globalComponentFunctions.add(fn);
|
|
2020
1986
|
}
|
|
2021
1987
|
for (const [callerFn, sites] of targetMod.localCallGraph) {
|
|
2022
|
-
const
|
|
2023
|
-
|
|
2024
|
-
globalCallGraph.set(callerFn,
|
|
1988
|
+
const list = globalCallGraph.get(callerFn) ?? [];
|
|
1989
|
+
list.push(...sites);
|
|
1990
|
+
globalCallGraph.set(callerFn, list);
|
|
2025
1991
|
}
|
|
2026
1992
|
}
|
|
2027
1993
|
}
|
|
@@ -2039,7 +2005,7 @@ function buildProjectReactiveProps(modules, resolve3, globalLocalScopes, globalC
|
|
|
2039
2005
|
globalCallGraph.set(site.caller, list);
|
|
2040
2006
|
}
|
|
2041
2007
|
}
|
|
2042
|
-
const globalReactiveProps =
|
|
2008
|
+
const globalReactiveProps = propagateReactiveProps2(globalLocalScopes, globalCallGraph, globalComponentFunctions);
|
|
2043
2009
|
const reactiveProps = new Map;
|
|
2044
2010
|
for (const mod of modules.values()) {
|
|
2045
2011
|
const fileMap = new Map;
|
|
@@ -2056,7 +2022,7 @@ function buildProjectReactiveProps(modules, resolve3, globalLocalScopes, globalC
|
|
|
2056
2022
|
return reactiveProps;
|
|
2057
2023
|
}
|
|
2058
2024
|
|
|
2059
|
-
class
|
|
2025
|
+
class AnalyzerCache2 {
|
|
2060
2026
|
root;
|
|
2061
2027
|
extensions;
|
|
2062
2028
|
tsConfigPath;
|
|
@@ -2095,7 +2061,7 @@ class AnalyzerCache {
|
|
|
2095
2061
|
}
|
|
2096
2062
|
update(filePath, code) {
|
|
2097
2063
|
const oldMod = this.modules.get(filePath);
|
|
2098
|
-
const newMod =
|
|
2064
|
+
const newMod = analyzeModule2(code, filePath);
|
|
2099
2065
|
this.modules.set(filePath, newMod);
|
|
2100
2066
|
if (oldMod)
|
|
2101
2067
|
this.removeImporters(oldMod);
|
|
@@ -2105,12 +2071,19 @@ class AnalyzerCache {
|
|
|
2105
2071
|
}
|
|
2106
2072
|
remove(filePath) {
|
|
2107
2073
|
const oldMod = this.modules.get(filePath);
|
|
2108
|
-
const
|
|
2074
|
+
const affected = new Set(this.importers.get(filePath) ?? []);
|
|
2075
|
+
if (oldMod) {
|
|
2076
|
+
for (const site of oldMod.importedCallSites) {
|
|
2077
|
+
const resolved = this.resolve(site.source, oldMod.filePath);
|
|
2078
|
+
if (resolved)
|
|
2079
|
+
affected.add(resolved);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2109
2082
|
this.modules.delete(filePath);
|
|
2110
2083
|
this.importers.delete(filePath);
|
|
2111
2084
|
if (oldMod)
|
|
2112
2085
|
this.removeImporters(oldMod);
|
|
2113
|
-
this.recomputeFor(
|
|
2086
|
+
this.recomputeFor(affected);
|
|
2114
2087
|
this.save();
|
|
2115
2088
|
}
|
|
2116
2089
|
save() {
|
|
@@ -2186,7 +2159,7 @@ class AnalyzerCache {
|
|
|
2186
2159
|
return this.modules.get(filePath);
|
|
2187
2160
|
try {
|
|
2188
2161
|
const code = fs.readFileSync(filePath, "utf-8");
|
|
2189
|
-
const mod =
|
|
2162
|
+
const mod = analyzeModule2(code, filePath);
|
|
2190
2163
|
this.modules.set(filePath, mod);
|
|
2191
2164
|
return mod;
|
|
2192
2165
|
} catch {
|
|
@@ -2254,37 +2227,11 @@ class AnalyzerCache {
|
|
|
2254
2227
|
}
|
|
2255
2228
|
}
|
|
2256
2229
|
}
|
|
2257
|
-
recompute() {
|
|
2258
|
-
const affected = this.collectAffected(Array.from(this.modules.keys()));
|
|
2259
|
-
const subgraphModules = new Map;
|
|
2260
|
-
for (const filePath of affected) {
|
|
2261
|
-
const mod = this.modules.get(filePath);
|
|
2262
|
-
if (mod)
|
|
2263
|
-
subgraphModules.set(filePath, mod);
|
|
2264
|
-
}
|
|
2265
|
-
const globalLocalScopes = new Map;
|
|
2266
|
-
const globalCallGraph = new Map;
|
|
2267
|
-
const globalComponentFunctions = new Set;
|
|
2268
|
-
for (const mod of subgraphModules.values()) {
|
|
2269
|
-
for (const [fn, scope] of mod.localScopes) {
|
|
2270
|
-
globalLocalScopes.set(fn, scope);
|
|
2271
|
-
}
|
|
2272
|
-
for (const fn of mod.componentFunctions) {
|
|
2273
|
-
globalComponentFunctions.add(fn);
|
|
2274
|
-
}
|
|
2275
|
-
for (const [callerFn, sites] of mod.localCallGraph) {
|
|
2276
|
-
const list = globalCallGraph.get(callerFn) ?? [];
|
|
2277
|
-
list.push(...sites);
|
|
2278
|
-
globalCallGraph.set(callerFn, list);
|
|
2279
|
-
}
|
|
2280
|
-
}
|
|
2281
|
-
this.reactiveProps = buildProjectReactiveProps(subgraphModules, this.resolve, globalLocalScopes, globalCallGraph, globalComponentFunctions);
|
|
2282
|
-
}
|
|
2283
2230
|
}
|
|
2284
|
-
function
|
|
2231
|
+
function analyze2(options) {
|
|
2285
2232
|
const tsConfigPath = options.tsConfigPath ?? path2.join(options.root, "tsconfig.json");
|
|
2286
2233
|
const bunfigPath = options.bunfigPath ?? path2.join(options.root, "bunfig.toml");
|
|
2287
|
-
const project =
|
|
2234
|
+
const project = analyzeProject2({
|
|
2288
2235
|
root: options.root,
|
|
2289
2236
|
extensions: options.extensions,
|
|
2290
2237
|
resolve: options.resolve,
|
|
@@ -2306,24 +2253,24 @@ function analyze(options) {
|
|
|
2306
2253
|
}
|
|
2307
2254
|
fs.writeFileSync(options.outFile, JSON.stringify(serialized, null, 2));
|
|
2308
2255
|
}
|
|
2309
|
-
function
|
|
2256
|
+
function loadMetadata2(filePath) {
|
|
2310
2257
|
if (!fs.existsSync(filePath)) {
|
|
2311
2258
|
return new Map;
|
|
2312
2259
|
}
|
|
2313
2260
|
const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
2314
2261
|
const result = new Map;
|
|
2315
|
-
for (const [
|
|
2262
|
+
for (const [filePath, fileMap] of Object.entries(raw)) {
|
|
2316
2263
|
const map = new Map;
|
|
2317
2264
|
for (const [exportName, props] of Object.entries(fileMap)) {
|
|
2318
2265
|
map.set(exportName, new Set(props));
|
|
2319
2266
|
}
|
|
2320
|
-
result.set(
|
|
2267
|
+
result.set(filePath, map);
|
|
2321
2268
|
}
|
|
2322
2269
|
return result;
|
|
2323
2270
|
}
|
|
2324
2271
|
|
|
2325
2272
|
// src/cli.ts
|
|
2326
|
-
function
|
|
2273
|
+
function runAnalyzeCli2(args = process.argv.slice(2)) {
|
|
2327
2274
|
let command;
|
|
2328
2275
|
let root;
|
|
2329
2276
|
let outFile;
|
|
@@ -2352,11 +2299,14 @@ function runAnalyzeCli(args = process.argv.slice(2)) {
|
|
|
2352
2299
|
}
|
|
2353
2300
|
root = root ?? process.cwd();
|
|
2354
2301
|
outFile = outFile ?? path3.join(root, ".sinwan/reactive-props.json");
|
|
2355
|
-
|
|
2302
|
+
analyze2({ root, outFile, tsConfigPath, bunfigPath, workspaces });
|
|
2356
2303
|
console.log(`[sinwan] analyzed ${root} -> ${outFile}`);
|
|
2357
2304
|
}
|
|
2358
|
-
|
|
2359
|
-
|
|
2305
|
+
function runCliIfMain2(isMain = import.meta.main, args) {
|
|
2306
|
+
if (!isMain)
|
|
2307
|
+
return;
|
|
2308
|
+
runAnalyzeCli2(args);
|
|
2360
2309
|
}
|
|
2310
|
+
runCliIfMain2();
|
|
2361
2311
|
|
|
2362
|
-
export {
|
|
2312
|
+
export { autoWrapComponents2, analyzeModule2, analyzeProject2, AnalyzerCache2, analyze2, loadMetadata2, trackReactiveImports2, getAllPropNames2, isReactiveValue2, containsReactiveValue2, collectComponentFunctions2, computeLocalScopes2, collectComponentCallGraph2, buildFullScope2, propagateReactiveProps2, wrapReactiveExpressions2, runAnalyzeCli2, runCliIfMain2 };
|