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.
@@ -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 trackReactiveImports(ast) {
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(path2) {
61
- const source = path2.node.source.value;
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 path2.node.specifiers) {
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(path2, names, scope) {
131
- path2.traverse({
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
- path2.traverse({
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
- path2.traverse({
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 getAllPropNames(params) {
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
- if (decl.init && t.isObjectExpression(decl.init)) {
273
- return decl.init;
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 && containsReactiveValue(prop.value, fullScope)) {
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 path2 = [];
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
- path2.push(current.property.name);
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: path2.reverse() };
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 binding2 = scope.bindings.get(node.name);
323
- if (!binding2)
323
+ const binding = scope.bindings.get(node.name);
324
+ if (!binding)
324
325
  return false;
325
- if (binding2.kind === "prop") {
326
+ if (binding.kind === "prop") {
326
327
  return true;
327
328
  }
328
- if (binding2.kind === "mutable" && binding2.path.length > 0) {
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 isReactiveValue(node, scope) {
363
+ function isReactiveValue2(node, scope) {
363
364
  if (t.isTSNonNullExpression(node)) {
364
- return isReactiveValue(node.expression, scope);
365
+ return isReactiveValue2(node.expression, scope);
365
366
  }
366
367
  if (t.isIdentifier(node)) {
367
- const binding2 = scope.bindings.get(node.name);
368
- if (!binding2)
368
+ const binding = scope.bindings.get(node.name);
369
+ if (!binding)
369
370
  return false;
370
- return binding2.kind === "prop" || binding2.kind === "signal" || binding2.kind === "computed" || binding2.kind === "mutable";
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 containsReactiveValue(expr, scope) {
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 (isReactiveValue(node, scope)) {
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(info, componentNames, reactiveProps, importedReactiveProps) {
507
- if (!info.isComponent || !info.componentName || !info.attributeName) {
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(info.componentName);
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(info.attributeName);
516
+ return props.has(attributeName);
519
517
  }
520
- const importedProps = importedReactiveProps.get(info.componentName);
518
+ const importedProps = importedReactiveProps.get(componentName);
521
519
  if (!importedProps)
522
520
  return false;
523
- return importedProps.has(info.attributeName);
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 collectComponentFunctions(ast, ccNames) {
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(path2) {
626
- const callee = path2.node.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 = path2.node.arguments[0];
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 = path2.parentPath;
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(path2) {
654
- const declaration = path2.node.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(path2) {
671
- const decl = path2.node.declaration;
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 computeLocalScopes(ast, names) {
679
+ function computeLocalScopes2(ast, names) {
691
680
  const scopes = new Map;
692
681
  traverse(ast, {
693
- Function(path2) {
682
+ Function(path) {
694
683
  const scope = { bindings: new Map };
695
- trackLocalScopeBindings(path2, names, scope);
696
- scopes.set(path2.node, scope);
684
+ trackLocalScopeBindings(path, names, scope);
685
+ scopes.set(path.node, scope);
697
686
  }
698
687
  });
699
688
  return scopes;
700
689
  }
701
- function collectComponentCallGraph(ast, componentNames) {
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(path2) {
707
- const name = path2.node.openingElement.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 = path2.findParent((p) => p.isFunction());
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 path2.node.openingElement.attributes) {
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 path2.node.children) {
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 buildFullScope(localScopes, fn, reactiveProps) {
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 propagateReactiveProps(localScopes, callGraph, componentFunctions) {
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 (containsReactiveValue(prop.value, localScope)) {
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 = buildFullScope(localScopes, callerFn, callerReactive);
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 (containsReactiveValue(prop.value, fullScope)) {
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 = getAllPropNames(site.callee.params[0]);
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 wrapReactiveExpressions(ast, options = {}) {
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 = loadMetadata(options.analyze);
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 = propagateReactiveProps(localScopes, callGraph, componentFunctions);
1011
+ const reactiveProps = propagateReactiveProps2(localScopes, callGraph, componentFunctions);
1032
1012
  let needsResolve = false;
1033
1013
  traverse(ast, {
1034
- Function(path2) {
1035
- const scope = localScopes.get(path2.node);
1014
+ Function(path) {
1015
+ const scope = localScopes.get(path.node);
1036
1016
  if (!scope)
1037
1017
  return;
1038
- const isComponent = componentFunctions.has(path2.node);
1018
+ const isComponent = componentFunctions.has(path.node);
1039
1019
  if (isComponent) {
1040
- const isExported = exported.has(path2.node);
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(path2.node);
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, path2.node.params[0], props);
1031
+ trackPropBindings(scope, path.node.params[0], props);
1052
1032
  } else {
1053
- const allProps = getAllPropNames(path2.node.params[0]);
1054
- trackPropBindings(scope, path2.node.params[0], allProps);
1033
+ const allProps = getAllPropNames2(path.node.params[0]);
1034
+ trackPropBindings(scope, path.node.params[0], allProps);
1055
1035
  }
1056
- } else if (reactiveProps.has(path2.node)) {
1057
- const props = reactiveProps.get(path2.node);
1058
- trackPropBindings(scope, path2.node.params[0], props);
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 = getAllPropNames(path2.node.params[0]);
1061
- trackPropBindings(scope, path2.node.params[0], allProps);
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
- path2.traverse({
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
- for (const item of val) {
1130
- if (item && typeof item === "object" && containsJsx(item, enterFunctions)) {
1131
- return true;
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(path2) {
1171
- const source = path2.node.source.value;
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 path2.node.specifiers) {
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 autoWrapComponents(ast, filename) {
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 "not-candidate";
1173
+ return false;
1196
1174
  const fn = fnPath.node;
1197
1175
  if (!isComponentArity(fn))
1198
- return "not-candidate";
1176
+ return false;
1199
1177
  if (!functionReturnsJsx(fnPath))
1200
- return "not-candidate";
1201
- return "wrapped";
1178
+ return false;
1179
+ return true;
1202
1180
  };
1203
1181
  traverse2(ast, {
1204
- ExportNamedDeclaration(path2) {
1205
- const decl = path2.node.declaration;
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
- if (!isComponentName(name))
1211
- return;
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
- path2.replaceWith(t2.exportNamedDeclaration(varDecl, []));
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 path2.get("declaration.declarations")) {
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 (!isComponentArity(init))
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(path2) {
1250
- const decl = path2.node.declaration;
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
- if (!isComponentName(name))
1254
- return;
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
- path2.replaceWithMultiple([fnDecl, exportDefault]);
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 = path2.get("declaration");
1268
- if (!isComponentArity(decl))
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
- path2.node.declaration = ccCall(fnExpr, ccName ?? "cc");
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 = path2.get("declaration");
1279
- if (!isComponentArity(decl))
1280
- return;
1281
- if (!functionReturnsJsx(declPath))
1244
+ const declPath = path.get("declaration");
1245
+ if (!wrapIfCandidate(declPath, null))
1282
1246
  return;
1283
- path2.node.declaration = ccCall(decl, ccName ?? "cc");
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(path3) {
1307
- const node = path3.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
- path3.stop();
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
- localCallGraph.set(callerFn, sites.map((s) => {
1374
+ const restored = [];
1375
+ for (const s of sites) {
1411
1376
  const callee = findFunctionByRef(ast, s.callee);
1412
1377
  if (!callee)
1413
- throw new Error("Failed to restore callee");
1414
- return {
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(path3) {
1463
- const source = path3.node.source.value;
1464
- for (const spec of path3.node.specifiers) {
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(path3) {
1481
- const name = path3.node.openingElement.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 = path3.findParent((p) => p.isFunction());
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 path3.node.openingElement.attributes) {
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 path3.node.children) {
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 analyzeModule(code, filePath) {
1508
+ function analyzeModule2(code, filePath) {
1543
1509
  const ast = parse(code, {
1544
1510
  sourceType: "module",
1545
1511
  plugins: ["jsx", "typescript"]
1546
1512
  });
1547
- autoWrapComponents(ast, filePath);
1548
- const names = trackReactiveImports(ast);
1513
+ autoWrapComponents2(ast, filePath);
1514
+ const names = trackReactiveImports2(ast);
1549
1515
  const {
1550
1516
  functions,
1551
1517
  names: componentNames,
1552
1518
  exported
1553
- } = collectComponentFunctions(ast, names.cc);
1554
- const localScopes = computeLocalScopes(ast, names);
1555
- const localCallGraph = collectComponentCallGraph(ast, componentNames);
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(path3) {
1567
- const decl = path3.node.declaration;
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 analyzeProject(options) {
1924
+ function analyzeProject2(options) {
1959
1925
  const extensions = options.extensions ?? [".tsx", ".ts", ".jsx", ".js"];
1960
- const resolve3 = options.resolve ?? createResolver(options.root, extensions, options.tsConfigPath, options.bunfigPath, options.workspaces);
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, analyzeModule(code, 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, analyzeModule(code, 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 = analyzeModule(code, filePath);
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, resolve3, globalLocalScopes, globalCallGraph, globalComponentFunctions, ensureAnalyzed);
1968
+ const reactiveProps = buildProjectReactiveProps(modules, resolve, globalLocalScopes, globalCallGraph, globalComponentFunctions, ensureAnalyzed);
2003
1969
  return { modules, reactiveProps };
2004
1970
  }
2005
- function buildProjectReactiveProps(modules, resolve3, globalLocalScopes, globalCallGraph, globalComponentFunctions, ensureAnalyzed) {
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 = resolve3(site.source, mod.filePath);
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 list2 = globalCallGraph.get(callerFn) ?? [];
2023
- list2.push(...sites);
2024
- globalCallGraph.set(callerFn, list2);
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 = propagateReactiveProps(globalLocalScopes, globalCallGraph, globalComponentFunctions);
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 AnalyzerCache {
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 = analyzeModule(code, filePath);
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 affectedImporters = new Set(this.importers.get(filePath) ?? []);
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(affectedImporters);
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 = analyzeModule(code, filePath);
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 analyze(options) {
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 = analyzeProject({
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 loadMetadata(filePath) {
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 [filePath2, fileMap] of Object.entries(raw)) {
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(filePath2, map);
2267
+ result.set(filePath, map);
2321
2268
  }
2322
2269
  return result;
2323
2270
  }
2324
2271
 
2325
2272
  // src/cli.ts
2326
- function runAnalyzeCli(args = process.argv.slice(2)) {
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
- analyze({ root, outFile, tsConfigPath, bunfigPath, workspaces });
2302
+ analyze2({ root, outFile, tsConfigPath, bunfigPath, workspaces });
2356
2303
  console.log(`[sinwan] analyzed ${root} -> ${outFile}`);
2357
2304
  }
2358
- if (import.meta.main) {
2359
- runAnalyzeCli();
2305
+ function runCliIfMain2(isMain = import.meta.main, args) {
2306
+ if (!isMain)
2307
+ return;
2308
+ runAnalyzeCli2(args);
2360
2309
  }
2310
+ runCliIfMain2();
2361
2311
 
2362
- export { autoWrapComponents, analyzeModule, analyzeProject, AnalyzerCache, analyze, loadMetadata, trackReactiveImports, getAllPropNames, isReactiveValue, containsReactiveValue, collectComponentFunctions, computeLocalScopes, collectComponentCallGraph, buildFullScope, propagateReactiveProps, wrapReactiveExpressions, runAnalyzeCli };
2312
+ export { autoWrapComponents2, analyzeModule2, analyzeProject2, AnalyzerCache2, analyze2, loadMetadata2, trackReactiveImports2, getAllPropNames2, isReactiveValue2, containsReactiveValue2, collectComponentFunctions2, computeLocalScopes2, collectComponentCallGraph2, buildFullScope2, propagateReactiveProps2, wrapReactiveExpressions2, runAnalyzeCli2, runCliIfMain2 };