sinwan-compiler 0.2.2 → 0.2.4
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/auto-cc.d.ts +34 -0
- package/dist/{chunk-3bqqn28f.js → chunk-w580fdrf.js} +599 -85
- package/dist/cli.js +1 -1
- package/dist/exports.d.ts +27 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +154 -33
- package/dist/reactive-wrap.d.ts +16 -3
- package/dist/transform.d.ts +22 -0
- package/package.json +1 -1
|
@@ -4,8 +4,8 @@ import * as path3 from "path";
|
|
|
4
4
|
|
|
5
5
|
// src/analyze.ts
|
|
6
6
|
import { parse } from "@babel/parser";
|
|
7
|
-
import * as
|
|
8
|
-
import
|
|
7
|
+
import * as t3 from "@babel/types";
|
|
8
|
+
import _traverse3 from "@babel/traverse";
|
|
9
9
|
import * as fs from "fs";
|
|
10
10
|
import * as path2 from "path";
|
|
11
11
|
|
|
@@ -17,7 +17,8 @@ var traverse = typeof _traverse === "function" ? _traverse : _traverse.default ?
|
|
|
17
17
|
var REACTIVE_SOURCE_MODULES = {
|
|
18
18
|
"sinwan/store": new Set(["createMutable", "createStore"]),
|
|
19
19
|
"sinwan/reactivity": new Set(["signal", "computed"]),
|
|
20
|
-
"sinwan/react": new Set(["useState"])
|
|
20
|
+
"sinwan/react": new Set(["useState"]),
|
|
21
|
+
"sinwan/hook": new Set(["useFetch"])
|
|
21
22
|
};
|
|
22
23
|
var COMPONENT_FACTORY_MODULES = {
|
|
23
24
|
sinwan: new Set(["cc"]),
|
|
@@ -42,6 +43,9 @@ function isBuiltinReactiveProp(componentName, attrName) {
|
|
|
42
43
|
return false;
|
|
43
44
|
return entry.reactiveProps.has(attrName);
|
|
44
45
|
}
|
|
46
|
+
function isBuiltinControlFlowComponent(componentName) {
|
|
47
|
+
return !!componentName && BUILTIN_REACTIVE_PROPS.has(componentName);
|
|
48
|
+
}
|
|
45
49
|
function trackReactiveImports(ast) {
|
|
46
50
|
const names = {
|
|
47
51
|
createMutable: new Set,
|
|
@@ -49,6 +53,7 @@ function trackReactiveImports(ast) {
|
|
|
49
53
|
signal: new Set,
|
|
50
54
|
computed: new Set,
|
|
51
55
|
useState: new Set,
|
|
56
|
+
useFetch: new Set,
|
|
52
57
|
cc: new Set
|
|
53
58
|
};
|
|
54
59
|
traverse(ast, {
|
|
@@ -96,6 +101,32 @@ function isReactiveSourceCall(expr, names) {
|
|
|
96
101
|
}
|
|
97
102
|
return null;
|
|
98
103
|
}
|
|
104
|
+
var USEFETCH_CHAIN_METHODS = new Set([
|
|
105
|
+
"json",
|
|
106
|
+
"text",
|
|
107
|
+
"blob",
|
|
108
|
+
"arrayBuffer",
|
|
109
|
+
"formData",
|
|
110
|
+
"get",
|
|
111
|
+
"put",
|
|
112
|
+
"post",
|
|
113
|
+
"delete",
|
|
114
|
+
"patch",
|
|
115
|
+
"head",
|
|
116
|
+
"options"
|
|
117
|
+
]);
|
|
118
|
+
function isUseFetchCall(expr, names) {
|
|
119
|
+
if (!t.isCallExpression(expr))
|
|
120
|
+
return false;
|
|
121
|
+
const callee = expr.callee;
|
|
122
|
+
if (t.isIdentifier(callee)) {
|
|
123
|
+
return names.useFetch.has(callee.name);
|
|
124
|
+
}
|
|
125
|
+
if (t.isMemberExpression(callee) && !callee.computed && t.isIdentifier(callee.property) && USEFETCH_CHAIN_METHODS.has(callee.property.name)) {
|
|
126
|
+
return isUseFetchCall(callee.object, names);
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
99
130
|
function trackLocalScopeBindings(path2, names, scope) {
|
|
100
131
|
path2.traverse({
|
|
101
132
|
VariableDeclarator(p) {
|
|
@@ -104,27 +135,42 @@ function trackLocalScopeBindings(path2, names, scope) {
|
|
|
104
135
|
if (!init)
|
|
105
136
|
return;
|
|
106
137
|
const source = isReactiveSourceCall(init, names);
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
138
|
+
if (source) {
|
|
139
|
+
if (source.isArray) {
|
|
140
|
+
if (t.isArrayPattern(id) && id.elements[0]) {
|
|
141
|
+
const first = id.elements[0];
|
|
142
|
+
if (t.isIdentifier(first)) {
|
|
143
|
+
scope.bindings.set(first.name, { kind: source.kind });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (t.isIdentifier(id)) {
|
|
149
|
+
if (source.kind === "mutable") {
|
|
150
|
+
scope.bindings.set(id.name, {
|
|
151
|
+
kind: "mutable",
|
|
152
|
+
root: id.name,
|
|
153
|
+
path: []
|
|
154
|
+
});
|
|
155
|
+
} else {
|
|
156
|
+
scope.bindings.set(id.name, { kind: source.kind });
|
|
114
157
|
}
|
|
115
158
|
}
|
|
116
159
|
return;
|
|
117
160
|
}
|
|
118
|
-
if (
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
161
|
+
if (isUseFetchCall(init, names)) {
|
|
162
|
+
if (t.isObjectPattern(id)) {
|
|
163
|
+
for (const prop of id.properties) {
|
|
164
|
+
if (t.isObjectProperty(prop) && !prop.computed && t.isIdentifier(prop.value)) {
|
|
165
|
+
scope.bindings.set(prop.value.name, {
|
|
166
|
+
kind: "signal"
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
} else if (t.isIdentifier(id)) {
|
|
171
|
+
scope.bindings.set(id.name, { kind: "signalObject" });
|
|
127
172
|
}
|
|
173
|
+
return;
|
|
128
174
|
}
|
|
129
175
|
}
|
|
130
176
|
});
|
|
@@ -241,16 +287,27 @@ function analyzeObjectLiteralSpread(spread, fullScope, calleeReactive) {
|
|
|
241
287
|
}
|
|
242
288
|
}
|
|
243
289
|
}
|
|
290
|
+
function isMemberLike(node) {
|
|
291
|
+
return t.isMemberExpression(node) || t.isOptionalMemberExpression(node);
|
|
292
|
+
}
|
|
244
293
|
function getMemberExpressionRootAndPath(node) {
|
|
245
294
|
const path2 = [];
|
|
246
295
|
let current = node;
|
|
247
|
-
while (
|
|
248
|
-
if (current
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
296
|
+
while (true) {
|
|
297
|
+
if (t.isTSNonNullExpression(current)) {
|
|
298
|
+
current = current.expression;
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (isMemberLike(current)) {
|
|
302
|
+
if (current.computed)
|
|
303
|
+
return null;
|
|
304
|
+
if (!t.isIdentifier(current.property))
|
|
305
|
+
return null;
|
|
306
|
+
path2.push(current.property.name);
|
|
307
|
+
current = current.object;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
break;
|
|
254
311
|
}
|
|
255
312
|
if (t.isIdentifier(current)) {
|
|
256
313
|
return { root: current.name, path: path2.reverse() };
|
|
@@ -258,6 +315,9 @@ function getMemberExpressionRootAndPath(node) {
|
|
|
258
315
|
return null;
|
|
259
316
|
}
|
|
260
317
|
function isReactiveRead(node, scope) {
|
|
318
|
+
if (t.isTSNonNullExpression(node)) {
|
|
319
|
+
return isReactiveRead(node.expression, scope);
|
|
320
|
+
}
|
|
261
321
|
if (t.isIdentifier(node)) {
|
|
262
322
|
const binding2 = scope.bindings.get(node.name);
|
|
263
323
|
if (!binding2)
|
|
@@ -270,6 +330,8 @@ function isReactiveRead(node, scope) {
|
|
|
270
330
|
}
|
|
271
331
|
return false;
|
|
272
332
|
}
|
|
333
|
+
if (!isMemberLike(node))
|
|
334
|
+
return false;
|
|
273
335
|
const rootPath = getMemberExpressionRootAndPath(node);
|
|
274
336
|
if (!rootPath)
|
|
275
337
|
return false;
|
|
@@ -285,6 +347,9 @@ function isReactiveRead(node, scope) {
|
|
|
285
347
|
if (binding.kind === "signal" || binding.kind === "computed") {
|
|
286
348
|
return rootPath.path[0] === "value";
|
|
287
349
|
}
|
|
350
|
+
if (binding.kind === "signalObject") {
|
|
351
|
+
return rootPath.path.length >= 2 && rootPath.path[1] === "value";
|
|
352
|
+
}
|
|
288
353
|
return false;
|
|
289
354
|
}
|
|
290
355
|
function isGetterCall(node, scope) {
|
|
@@ -295,12 +360,17 @@ function isGetterCall(node, scope) {
|
|
|
295
360
|
return binding?.kind === "getter";
|
|
296
361
|
}
|
|
297
362
|
function isReactiveValue(node, scope) {
|
|
363
|
+
if (t.isTSNonNullExpression(node)) {
|
|
364
|
+
return isReactiveValue(node.expression, scope);
|
|
365
|
+
}
|
|
298
366
|
if (t.isIdentifier(node)) {
|
|
299
367
|
const binding2 = scope.bindings.get(node.name);
|
|
300
368
|
if (!binding2)
|
|
301
369
|
return false;
|
|
302
370
|
return binding2.kind === "prop" || binding2.kind === "signal" || binding2.kind === "computed" || binding2.kind === "mutable";
|
|
303
371
|
}
|
|
372
|
+
if (!isMemberLike(node))
|
|
373
|
+
return false;
|
|
304
374
|
const rootPath = getMemberExpressionRootAndPath(node);
|
|
305
375
|
if (!rootPath)
|
|
306
376
|
return false;
|
|
@@ -313,6 +383,9 @@ function isReactiveValue(node, scope) {
|
|
|
313
383
|
if (binding.kind === "signal" || binding.kind === "computed") {
|
|
314
384
|
return rootPath.path[0] === "value";
|
|
315
385
|
}
|
|
386
|
+
if (binding.kind === "signalObject") {
|
|
387
|
+
return rootPath.path.length >= 2 && rootPath.path[1] === "value";
|
|
388
|
+
}
|
|
316
389
|
return false;
|
|
317
390
|
}
|
|
318
391
|
function containsReactiveValue(expr, scope) {
|
|
@@ -322,7 +395,7 @@ function containsReactiveValue(expr, scope) {
|
|
|
322
395
|
return;
|
|
323
396
|
if (!node || typeof node !== "object")
|
|
324
397
|
return;
|
|
325
|
-
if (t.
|
|
398
|
+
if (isMemberLike(node) || t.isTSNonNullExpression(node) || t.isIdentifier(node)) {
|
|
326
399
|
if (isReactiveValue(node, scope)) {
|
|
327
400
|
found = true;
|
|
328
401
|
return;
|
|
@@ -359,7 +432,7 @@ function containsReactiveRead(expr, scope) {
|
|
|
359
432
|
return;
|
|
360
433
|
if (!node || typeof node !== "object")
|
|
361
434
|
return;
|
|
362
|
-
if (t.
|
|
435
|
+
if (isMemberLike(node) || t.isTSNonNullExpression(node) || t.isIdentifier(node)) {
|
|
363
436
|
if (isReactiveRead(node, scope)) {
|
|
364
437
|
found = true;
|
|
365
438
|
return;
|
|
@@ -430,7 +503,7 @@ function getComponentExpressionInfo(exprPath) {
|
|
|
430
503
|
}
|
|
431
504
|
return { isComponent: true, componentName, attributeName };
|
|
432
505
|
}
|
|
433
|
-
function isReactiveComponentProp(info, componentNames, reactiveProps) {
|
|
506
|
+
function isReactiveComponentProp(info, componentNames, reactiveProps, importedReactiveProps) {
|
|
434
507
|
if (!info.isComponent || !info.componentName || !info.attributeName) {
|
|
435
508
|
return false;
|
|
436
509
|
}
|
|
@@ -438,12 +511,16 @@ function isReactiveComponentProp(info, componentNames, reactiveProps) {
|
|
|
438
511
|
return true;
|
|
439
512
|
}
|
|
440
513
|
const componentFn = componentNames.get(info.componentName);
|
|
441
|
-
if (
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
514
|
+
if (componentFn) {
|
|
515
|
+
const props = reactiveProps.get(componentFn);
|
|
516
|
+
if (!props)
|
|
517
|
+
return false;
|
|
518
|
+
return props.has(info.attributeName);
|
|
519
|
+
}
|
|
520
|
+
const importedProps = importedReactiveProps.get(info.componentName);
|
|
521
|
+
if (!importedProps)
|
|
445
522
|
return false;
|
|
446
|
-
return
|
|
523
|
+
return importedProps.has(info.attributeName);
|
|
447
524
|
}
|
|
448
525
|
function shouldWrap(expr, scope) {
|
|
449
526
|
if (t.isArrowFunctionExpression(expr) || t.isFunctionExpression(expr))
|
|
@@ -452,6 +529,65 @@ function shouldWrap(expr, scope) {
|
|
|
452
529
|
return false;
|
|
453
530
|
return containsReactiveRead(expr, scope);
|
|
454
531
|
}
|
|
532
|
+
var RESOLVE_HELPER = "_$unwrap";
|
|
533
|
+
function transformPropMemberAccess(expr, scope) {
|
|
534
|
+
let changed = false;
|
|
535
|
+
function resolveRoot(rootName) {
|
|
536
|
+
return t.callExpression(t.identifier(RESOLVE_HELPER), [
|
|
537
|
+
t.identifier(rootName)
|
|
538
|
+
]);
|
|
539
|
+
}
|
|
540
|
+
function replaceMemberRoot(node, rootName) {
|
|
541
|
+
let current = node;
|
|
542
|
+
let parent = null;
|
|
543
|
+
while (true) {
|
|
544
|
+
if (t.isTSNonNullExpression(current)) {
|
|
545
|
+
current = current.expression;
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
if (!isMemberLike(current))
|
|
549
|
+
break;
|
|
550
|
+
parent = current;
|
|
551
|
+
current = current.object;
|
|
552
|
+
}
|
|
553
|
+
if (parent && t.isIdentifier(current) && current.name === rootName) {
|
|
554
|
+
parent.object = resolveRoot(rootName);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function visit(node) {
|
|
558
|
+
if (!node || typeof node !== "object")
|
|
559
|
+
return;
|
|
560
|
+
if (t.isArrowFunctionExpression(node) || t.isFunctionExpression(node))
|
|
561
|
+
return;
|
|
562
|
+
if (isMemberLike(node)) {
|
|
563
|
+
const rootPath = getMemberExpressionRootAndPath(node);
|
|
564
|
+
if (rootPath) {
|
|
565
|
+
const binding = scope.bindings.get(rootPath.root);
|
|
566
|
+
if (binding && binding.kind === "prop") {
|
|
567
|
+
replaceMemberRoot(node, rootPath.root);
|
|
568
|
+
changed = true;
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
for (const key of Object.keys(node)) {
|
|
575
|
+
if (key === "loc" || key === "start" || key === "end" || key === "leadingComments" || key === "trailingComments")
|
|
576
|
+
continue;
|
|
577
|
+
const value = node[key];
|
|
578
|
+
if (Array.isArray(value)) {
|
|
579
|
+
for (const item of value) {
|
|
580
|
+
if (item && typeof item === "object")
|
|
581
|
+
visit(item);
|
|
582
|
+
}
|
|
583
|
+
} else if (value && typeof value === "object") {
|
|
584
|
+
visit(value);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
visit(expr);
|
|
589
|
+
return changed;
|
|
590
|
+
}
|
|
455
591
|
function wrapExpression(expr) {
|
|
456
592
|
return t.arrowFunctionExpression([], expr);
|
|
457
593
|
}
|
|
@@ -681,53 +817,219 @@ function propagateReactiveProps(localScopes, callGraph, componentFunctions) {
|
|
|
681
817
|
return reactiveProps;
|
|
682
818
|
}
|
|
683
819
|
function wrapReactiveExpressions(ast, options = {}) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
} = collectComponentFunctions(ast, names.cc);
|
|
693
|
-
const localScopes = computeLocalScopes(ast, names);
|
|
694
|
-
const callGraph = collectComponentCallGraph(ast, componentNames);
|
|
695
|
-
const reactiveProps = propagateReactiveProps(localScopes, callGraph, componentFunctions);
|
|
696
|
-
const exportNameByFn = new Map;
|
|
697
|
-
for (const [localName, fn] of componentNames) {
|
|
698
|
-
if (exported.has(fn)) {
|
|
699
|
-
exportNameByFn.set(fn, localName);
|
|
820
|
+
let metadata = null;
|
|
821
|
+
if (options.analyzeMetadata) {
|
|
822
|
+
metadata = options.analyzeMetadata;
|
|
823
|
+
} else if (options.analyze && options.filename) {
|
|
824
|
+
try {
|
|
825
|
+
metadata = loadMetadata(options.analyze);
|
|
826
|
+
} catch {
|
|
827
|
+
metadata = null;
|
|
700
828
|
}
|
|
701
829
|
}
|
|
830
|
+
const absoluteFilename = options.filename ? path.resolve(options.filename) : null;
|
|
831
|
+
const resolveImport = options.resolveImport;
|
|
832
|
+
const names = {
|
|
833
|
+
createMutable: new Set,
|
|
834
|
+
createStore: new Set,
|
|
835
|
+
signal: new Set,
|
|
836
|
+
computed: new Set,
|
|
837
|
+
useState: new Set,
|
|
838
|
+
useFetch: new Set,
|
|
839
|
+
cc: new Set
|
|
840
|
+
};
|
|
841
|
+
const componentFunctions = new Set;
|
|
842
|
+
const componentNames = new Map;
|
|
843
|
+
const exported = new Set;
|
|
844
|
+
const localScopes = new Map;
|
|
845
|
+
const callGraph = new Map;
|
|
846
|
+
const rawCallGraph = new Map;
|
|
847
|
+
const importedReactiveProps = new Map;
|
|
848
|
+
const exportNameByFn = new Map;
|
|
849
|
+
let hasUnwrapImport = false;
|
|
702
850
|
traverse(ast, {
|
|
703
|
-
|
|
704
|
-
const
|
|
851
|
+
ImportDeclaration(p) {
|
|
852
|
+
const source = p.node.source.value;
|
|
853
|
+
const reactiveAllowed = REACTIVE_SOURCE_MODULES[source];
|
|
854
|
+
const componentAllowed = COMPONENT_FACTORY_MODULES[source];
|
|
855
|
+
if (reactiveAllowed || componentAllowed) {
|
|
856
|
+
for (const spec of p.node.specifiers) {
|
|
857
|
+
if (!t.isImportSpecifier(spec))
|
|
858
|
+
continue;
|
|
859
|
+
const imported = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
860
|
+
if (reactiveAllowed?.has(imported)) {
|
|
861
|
+
names[imported].add(spec.local.name);
|
|
862
|
+
} else if (componentAllowed?.has(imported)) {
|
|
863
|
+
names.cc.add(spec.local.name);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (source === "sinwan/reactivity") {
|
|
868
|
+
for (const spec of p.node.specifiers) {
|
|
869
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported) && spec.imported.name === "unwrap") {
|
|
870
|
+
hasUnwrapImport = true;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (metadata && absoluteFilename && resolveImport && source.startsWith(".")) {
|
|
875
|
+
const resolved = resolveImport(source, absoluteFilename);
|
|
876
|
+
if (resolved) {
|
|
877
|
+
const fileProps = metadata.get(resolved);
|
|
878
|
+
if (fileProps) {
|
|
879
|
+
for (const spec of p.node.specifiers) {
|
|
880
|
+
if (!t.isImportSpecifier(spec))
|
|
881
|
+
continue;
|
|
882
|
+
const imported = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
883
|
+
if (!imported || !/^[A-Z]/.test(imported))
|
|
884
|
+
continue;
|
|
885
|
+
const props = fileProps.get(imported);
|
|
886
|
+
if (props && props.size > 0) {
|
|
887
|
+
importedReactiveProps.set(spec.local.name, new Set(props));
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
},
|
|
894
|
+
CallExpression(p) {
|
|
895
|
+
const callee = p.node.callee;
|
|
896
|
+
if (!t.isIdentifier(callee) || !names.cc.has(callee.name))
|
|
897
|
+
return;
|
|
898
|
+
const firstArg = p.node.arguments[0];
|
|
899
|
+
if (!firstArg || !t.isFunction(firstArg))
|
|
900
|
+
return;
|
|
901
|
+
const componentFn = firstArg;
|
|
902
|
+
componentFunctions.add(componentFn);
|
|
903
|
+
const parent = p.parentPath;
|
|
904
|
+
if (parent && parent.isVariableDeclarator && parent.isVariableDeclarator()) {
|
|
905
|
+
const id = parent.node.id;
|
|
906
|
+
if (t.isIdentifier(id)) {
|
|
907
|
+
componentNames.set(id.name, componentFn);
|
|
908
|
+
}
|
|
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
|
+
}
|
|
919
|
+
},
|
|
920
|
+
ExportNamedDeclaration(p) {
|
|
921
|
+
const declaration = p.node.declaration;
|
|
922
|
+
if (!t.isVariableDeclaration(declaration))
|
|
923
|
+
return;
|
|
924
|
+
for (const decl of declaration.declarations) {
|
|
925
|
+
const init = decl.init;
|
|
926
|
+
if (!init || !t.isCallExpression(init))
|
|
927
|
+
continue;
|
|
928
|
+
const callee = init.callee;
|
|
929
|
+
if (!t.isIdentifier(callee) || !names.cc.has(callee.name))
|
|
930
|
+
continue;
|
|
931
|
+
const firstArg = init.arguments[0];
|
|
932
|
+
if (!firstArg || !t.isFunction(firstArg))
|
|
933
|
+
continue;
|
|
934
|
+
exported.add(firstArg);
|
|
935
|
+
}
|
|
936
|
+
},
|
|
937
|
+
ExportDefaultDeclaration(p) {
|
|
938
|
+
const decl = p.node.declaration;
|
|
705
939
|
if (t.isIdentifier(decl)) {
|
|
706
940
|
const fn = componentNames.get(decl.name);
|
|
707
|
-
if (fn)
|
|
941
|
+
if (fn) {
|
|
942
|
+
exported.add(fn);
|
|
708
943
|
exportNameByFn.set(fn, "default");
|
|
944
|
+
}
|
|
709
945
|
} else if (t.isCallExpression(decl)) {
|
|
710
946
|
const callee = decl.callee;
|
|
711
947
|
if (t.isIdentifier(callee) && names.cc.has(callee.name)) {
|
|
712
948
|
const firstArg = decl.arguments[0];
|
|
713
949
|
if (firstArg && t.isFunction(firstArg)) {
|
|
950
|
+
exported.add(firstArg);
|
|
714
951
|
exportNameByFn.set(firstArg, "default");
|
|
715
952
|
}
|
|
716
953
|
}
|
|
717
954
|
}
|
|
955
|
+
},
|
|
956
|
+
Function(p) {
|
|
957
|
+
const scope = { bindings: new Map };
|
|
958
|
+
trackLocalScopeBindings(p, names, scope);
|
|
959
|
+
localScopes.set(p.node, scope);
|
|
960
|
+
},
|
|
961
|
+
JSXElement(p) {
|
|
962
|
+
const name = p.node.openingElement.name;
|
|
963
|
+
if (!t.isJSXIdentifier(name))
|
|
964
|
+
return;
|
|
965
|
+
const callerPath = p.findParent((pp) => pp.isFunction());
|
|
966
|
+
const callerFn = callerPath ? callerPath.node : null;
|
|
967
|
+
if (!callerFn)
|
|
968
|
+
return;
|
|
969
|
+
const props = [];
|
|
970
|
+
const spreads = [];
|
|
971
|
+
for (const attr of p.node.openingElement.attributes) {
|
|
972
|
+
if (t.isJSXSpreadAttribute(attr)) {
|
|
973
|
+
if (attr.argument) {
|
|
974
|
+
spreads.push(attr.argument);
|
|
975
|
+
}
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
if (t.isJSXAttribute(attr)) {
|
|
979
|
+
const attrName = attr.name.name;
|
|
980
|
+
if (!attrName)
|
|
981
|
+
continue;
|
|
982
|
+
if (t.isJSXExpressionContainer(attr.value)) {
|
|
983
|
+
const expr = attr.value.expression;
|
|
984
|
+
if (!expr || t.isJSXEmptyExpression(expr))
|
|
985
|
+
continue;
|
|
986
|
+
props.push({ name: attrName, value: expr });
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const childExprs = [];
|
|
991
|
+
for (const child of p.node.children) {
|
|
992
|
+
if (t.isJSXExpressionContainer(child)) {
|
|
993
|
+
const expr = child.expression;
|
|
994
|
+
if (!expr || t.isJSXEmptyExpression(expr))
|
|
995
|
+
continue;
|
|
996
|
+
childExprs.push(expr);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if (childExprs.length === 1) {
|
|
1000
|
+
props.push({ name: "children", value: childExprs[0] });
|
|
1001
|
+
} else if (childExprs.length > 1) {
|
|
1002
|
+
props.push({ name: "children", value: t.arrayExpression(childExprs) });
|
|
1003
|
+
}
|
|
1004
|
+
const sites = rawCallGraph.get(callerFn) ?? [];
|
|
1005
|
+
sites.push({ calleeName: name.name, props, spreads });
|
|
1006
|
+
rawCallGraph.set(callerFn, sites);
|
|
718
1007
|
}
|
|
719
1008
|
});
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1009
|
+
for (const [callerFn, sites] of rawCallGraph) {
|
|
1010
|
+
const resolved = [];
|
|
1011
|
+
for (const site of sites) {
|
|
1012
|
+
const callee = componentNames.get(site.calleeName);
|
|
1013
|
+
if (callee) {
|
|
1014
|
+
resolved.push({ callee, props: site.props, spreads: site.spreads });
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
if (resolved.length > 0) {
|
|
1018
|
+
callGraph.set(callerFn, resolved);
|
|
728
1019
|
}
|
|
729
1020
|
}
|
|
730
|
-
const
|
|
1021
|
+
for (const [localName, fn] of componentNames) {
|
|
1022
|
+
if (exported.has(fn)) {
|
|
1023
|
+
if (!exportNameByFn.has(fn)) {
|
|
1024
|
+
exportNameByFn.set(fn, localName);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
const hasAnyImport = Object.values(names).some((s) => s.size > 0);
|
|
1029
|
+
if (!hasAnyImport)
|
|
1030
|
+
return;
|
|
1031
|
+
const reactiveProps = propagateReactiveProps(localScopes, callGraph, componentFunctions);
|
|
1032
|
+
let needsResolve = false;
|
|
731
1033
|
traverse(ast, {
|
|
732
1034
|
Function(path2) {
|
|
733
1035
|
const scope = localScopes.get(path2.node);
|
|
@@ -766,21 +1068,232 @@ function wrapReactiveExpressions(ast, options = {}) {
|
|
|
766
1068
|
const expr = exprPath.node.expression;
|
|
767
1069
|
const compInfo = getComponentExpressionInfo(exprPath);
|
|
768
1070
|
if (compInfo.isComponent) {
|
|
769
|
-
if (
|
|
770
|
-
|
|
1071
|
+
if (compInfo.attributeName !== null) {
|
|
1072
|
+
if (!isReactiveComponentProp(compInfo, componentNames, reactiveProps, importedReactiveProps)) {
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
} else {
|
|
1076
|
+
if (!isBuiltinControlFlowComponent(compInfo.componentName)) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
771
1079
|
}
|
|
772
1080
|
}
|
|
773
1081
|
if (shouldWrap(expr, scope)) {
|
|
1082
|
+
if (transformPropMemberAccess(expr, scope)) {
|
|
1083
|
+
needsResolve = true;
|
|
1084
|
+
}
|
|
774
1085
|
exprPath.replaceWith(t.jsxExpressionContainer(createBindingDescriptor(expr, exprPath, options)));
|
|
775
1086
|
}
|
|
776
1087
|
}
|
|
777
1088
|
});
|
|
778
1089
|
}
|
|
779
1090
|
});
|
|
1091
|
+
if (needsResolve && !hasUnwrapImport) {
|
|
1092
|
+
ast.program.body.unshift(t.importDeclaration([
|
|
1093
|
+
t.importSpecifier(t.identifier(RESOLVE_HELPER), t.identifier("unwrap"))
|
|
1094
|
+
], t.stringLiteral("sinwan/reactivity")));
|
|
1095
|
+
}
|
|
780
1096
|
}
|
|
781
1097
|
|
|
782
|
-
// src/
|
|
1098
|
+
// src/auto-cc.ts
|
|
1099
|
+
import * as t2 from "@babel/types";
|
|
1100
|
+
import _traverse2 from "@babel/traverse";
|
|
783
1101
|
var traverse2 = typeof _traverse2 === "function" ? _traverse2 : _traverse2.default ?? _traverse2;
|
|
1102
|
+
var CC_SOURCE_MODULES = new Set(["sinwan", "sinwan/component"]);
|
|
1103
|
+
var EXCLUDE_KEYS = new Set([
|
|
1104
|
+
"loc",
|
|
1105
|
+
"start",
|
|
1106
|
+
"end",
|
|
1107
|
+
"type",
|
|
1108
|
+
"leadingComments",
|
|
1109
|
+
"trailingComments",
|
|
1110
|
+
"innerComments",
|
|
1111
|
+
"extra"
|
|
1112
|
+
]);
|
|
1113
|
+
function isComponentName(name) {
|
|
1114
|
+
return !!name && /^[A-Z]/.test(name);
|
|
1115
|
+
}
|
|
1116
|
+
function containsJsx(node, enterFunctions) {
|
|
1117
|
+
if (!node || typeof node !== "object")
|
|
1118
|
+
return false;
|
|
1119
|
+
if (t2.isJSXElement(node) || t2.isJSXFragment(node))
|
|
1120
|
+
return true;
|
|
1121
|
+
if (!enterFunctions && (t2.isFunctionExpression(node) || t2.isArrowFunctionExpression(node) || t2.isFunctionDeclaration(node))) {
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
for (const key of Object.keys(node)) {
|
|
1125
|
+
if (EXCLUDE_KEYS.has(key))
|
|
1126
|
+
continue;
|
|
1127
|
+
const val = node[key];
|
|
1128
|
+
if (Array.isArray(val)) {
|
|
1129
|
+
for (const item of val) {
|
|
1130
|
+
if (item && typeof item === "object" && containsJsx(item, enterFunctions)) {
|
|
1131
|
+
return true;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
} else if (val && typeof val === "object" && containsJsx(val, enterFunctions)) {
|
|
1135
|
+
return true;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
return false;
|
|
1139
|
+
}
|
|
1140
|
+
function functionReturnsJsx(fnPath) {
|
|
1141
|
+
const fn = fnPath.node;
|
|
1142
|
+
if (t2.isArrowFunctionExpression(fn) && !t2.isBlockStatement(fn.body)) {
|
|
1143
|
+
return containsJsx(fn.body, false);
|
|
1144
|
+
}
|
|
1145
|
+
let found = false;
|
|
1146
|
+
fnPath.traverse({
|
|
1147
|
+
ReturnStatement(p) {
|
|
1148
|
+
if (p.node.argument && containsJsx(p.node.argument, false)) {
|
|
1149
|
+
found = true;
|
|
1150
|
+
p.stop();
|
|
1151
|
+
}
|
|
1152
|
+
},
|
|
1153
|
+
Function(p) {
|
|
1154
|
+
p.skip();
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
return found;
|
|
1158
|
+
}
|
|
1159
|
+
function isComponentArity(fn) {
|
|
1160
|
+
if (t2.isFunctionDeclaration(fn) && fn.generator)
|
|
1161
|
+
return false;
|
|
1162
|
+
if ((t2.isFunctionExpression(fn) || t2.isArrowFunctionExpression(fn)) && fn.generator) {
|
|
1163
|
+
return false;
|
|
1164
|
+
}
|
|
1165
|
+
return fn.params.length <= 1;
|
|
1166
|
+
}
|
|
1167
|
+
function collectCcAliases(ast) {
|
|
1168
|
+
const aliases = new Set;
|
|
1169
|
+
traverse2(ast, {
|
|
1170
|
+
ImportDeclaration(path2) {
|
|
1171
|
+
const source = path2.node.source.value;
|
|
1172
|
+
if (!CC_SOURCE_MODULES.has(source))
|
|
1173
|
+
return;
|
|
1174
|
+
for (const spec of path2.node.specifiers) {
|
|
1175
|
+
if (!t2.isImportSpecifier(spec))
|
|
1176
|
+
continue;
|
|
1177
|
+
const imported = t2.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
1178
|
+
if (imported === "cc") {
|
|
1179
|
+
aliases.add(spec.local.name);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
return { aliases, alreadyImported: aliases.size > 0 };
|
|
1185
|
+
}
|
|
1186
|
+
function ccCall(arg, ccName) {
|
|
1187
|
+
return t2.callExpression(t2.identifier(ccName), [arg]);
|
|
1188
|
+
}
|
|
1189
|
+
function autoWrapComponents(ast, filename) {
|
|
1190
|
+
const { aliases, alreadyImported } = collectCcAliases(ast);
|
|
1191
|
+
const ccName = aliases.values().next().value;
|
|
1192
|
+
let changed = false;
|
|
1193
|
+
const wrapIfCandidate = (fnPath, name) => {
|
|
1194
|
+
if (name !== null && !isComponentName(name))
|
|
1195
|
+
return "not-candidate";
|
|
1196
|
+
const fn = fnPath.node;
|
|
1197
|
+
if (!isComponentArity(fn))
|
|
1198
|
+
return "not-candidate";
|
|
1199
|
+
if (!functionReturnsJsx(fnPath))
|
|
1200
|
+
return "not-candidate";
|
|
1201
|
+
return "wrapped";
|
|
1202
|
+
};
|
|
1203
|
+
traverse2(ast, {
|
|
1204
|
+
ExportNamedDeclaration(path2) {
|
|
1205
|
+
const decl = path2.node.declaration;
|
|
1206
|
+
if (!decl)
|
|
1207
|
+
return;
|
|
1208
|
+
if (t2.isFunctionDeclaration(decl) && decl.id) {
|
|
1209
|
+
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))
|
|
1216
|
+
return;
|
|
1217
|
+
const fnExpr = t2.functionExpression(decl.id, decl.params, decl.body, decl.generator, decl.async);
|
|
1218
|
+
const varDecl = t2.variableDeclaration("const", [
|
|
1219
|
+
t2.variableDeclarator(t2.identifier(name), ccCall(fnExpr, ccName ?? "cc"))
|
|
1220
|
+
]);
|
|
1221
|
+
path2.replaceWith(t2.exportNamedDeclaration(varDecl, []));
|
|
1222
|
+
changed = true;
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
if (t2.isVariableDeclaration(decl)) {
|
|
1226
|
+
for (const dPath of path2.get("declaration.declarations")) {
|
|
1227
|
+
const id = dPath.node.id;
|
|
1228
|
+
if (!t2.isIdentifier(id) || !isComponentName(id.name))
|
|
1229
|
+
continue;
|
|
1230
|
+
const init = dPath.node.init;
|
|
1231
|
+
if (!init)
|
|
1232
|
+
continue;
|
|
1233
|
+
if (t2.isCallExpression(init) && t2.isIdentifier(init.callee) && aliases.has(init.callee.name)) {
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
if (!t2.isFunction(init))
|
|
1237
|
+
continue;
|
|
1238
|
+
const initPath = dPath.get("init");
|
|
1239
|
+
if (!isComponentArity(init))
|
|
1240
|
+
continue;
|
|
1241
|
+
if (!functionReturnsJsx(initPath))
|
|
1242
|
+
continue;
|
|
1243
|
+
dPath.node.init = ccCall(init, ccName ?? "cc");
|
|
1244
|
+
changed = true;
|
|
1245
|
+
}
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
},
|
|
1249
|
+
ExportDefaultDeclaration(path2) {
|
|
1250
|
+
const decl = path2.node.declaration;
|
|
1251
|
+
if (t2.isFunctionDeclaration(decl) && decl.id) {
|
|
1252
|
+
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))
|
|
1259
|
+
return;
|
|
1260
|
+
const fnDecl = t2.functionDeclaration(decl.id, decl.params, decl.body, decl.generator, decl.async);
|
|
1261
|
+
const exportDefault = t2.exportDefaultDeclaration(ccCall(t2.identifier(name), ccName ?? "cc"));
|
|
1262
|
+
path2.replaceWithMultiple([fnDecl, exportDefault]);
|
|
1263
|
+
changed = true;
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
if (t2.isFunctionDeclaration(decl) && !decl.id) {
|
|
1267
|
+
const fnPath = path2.get("declaration");
|
|
1268
|
+
if (!isComponentArity(decl))
|
|
1269
|
+
return;
|
|
1270
|
+
if (!functionReturnsJsx(fnPath))
|
|
1271
|
+
return;
|
|
1272
|
+
const fnExpr = t2.functionExpression(null, decl.params, decl.body, decl.generator, decl.async);
|
|
1273
|
+
path2.node.declaration = ccCall(fnExpr, ccName ?? "cc");
|
|
1274
|
+
changed = true;
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
if (t2.isArrowFunctionExpression(decl) || t2.isFunctionExpression(decl)) {
|
|
1278
|
+
const declPath = path2.get("declaration");
|
|
1279
|
+
if (!isComponentArity(decl))
|
|
1280
|
+
return;
|
|
1281
|
+
if (!functionReturnsJsx(declPath))
|
|
1282
|
+
return;
|
|
1283
|
+
path2.node.declaration = ccCall(decl, ccName ?? "cc");
|
|
1284
|
+
changed = true;
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
});
|
|
1289
|
+
if (changed && !alreadyImported) {
|
|
1290
|
+
ast.program.body.unshift(t2.importDeclaration([t2.importSpecifier(t2.identifier("cc"), t2.identifier("cc"))], t2.stringLiteral("sinwan/component")));
|
|
1291
|
+
}
|
|
1292
|
+
return changed;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
// src/analyze.ts
|
|
1296
|
+
var traverse3 = typeof _traverse3 === "function" ? _traverse3 : _traverse3.default ?? _traverse3;
|
|
784
1297
|
function functionRef(fn) {
|
|
785
1298
|
return { start: fn.start ?? -1, end: fn.end ?? -1 };
|
|
786
1299
|
}
|
|
@@ -789,7 +1302,7 @@ function refKey(ref) {
|
|
|
789
1302
|
}
|
|
790
1303
|
function findFunctionByRef(ast, ref) {
|
|
791
1304
|
let found = null;
|
|
792
|
-
|
|
1305
|
+
traverse3(ast, {
|
|
793
1306
|
Function(path3) {
|
|
794
1307
|
const node = path3.node;
|
|
795
1308
|
if (node.start === ref.start && node.end === ref.end) {
|
|
@@ -945,15 +1458,15 @@ function parseRefKey(key) {
|
|
|
945
1458
|
}
|
|
946
1459
|
function collectImports(ast) {
|
|
947
1460
|
const imports = new Map;
|
|
948
|
-
|
|
1461
|
+
traverse3(ast, {
|
|
949
1462
|
ImportDeclaration(path3) {
|
|
950
1463
|
const source = path3.node.source.value;
|
|
951
1464
|
for (const spec of path3.node.specifiers) {
|
|
952
|
-
if (
|
|
1465
|
+
if (t3.isImportSpecifier(spec)) {
|
|
953
1466
|
const localName = spec.local.name;
|
|
954
|
-
const importedName =
|
|
1467
|
+
const importedName = t3.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
955
1468
|
imports.set(localName, { source, importedName });
|
|
956
|
-
} else if (
|
|
1469
|
+
} else if (t3.isImportDefaultSpecifier(spec)) {
|
|
957
1470
|
imports.set(spec.local.name, { source, importedName: "default" });
|
|
958
1471
|
}
|
|
959
1472
|
}
|
|
@@ -963,10 +1476,10 @@ function collectImports(ast) {
|
|
|
963
1476
|
}
|
|
964
1477
|
function collectImportedCallSites(ast, componentNames, imports) {
|
|
965
1478
|
const sites = [];
|
|
966
|
-
|
|
1479
|
+
traverse3(ast, {
|
|
967
1480
|
JSXElement(path3) {
|
|
968
1481
|
const name = path3.node.openingElement.name;
|
|
969
|
-
if (!
|
|
1482
|
+
if (!t3.isJSXIdentifier(name))
|
|
970
1483
|
return;
|
|
971
1484
|
const tagName = name.name;
|
|
972
1485
|
if (!/^[A-Z]/.test(tagName))
|
|
@@ -983,19 +1496,19 @@ function collectImportedCallSites(ast, componentNames, imports) {
|
|
|
983
1496
|
const props = [];
|
|
984
1497
|
const spreads = [];
|
|
985
1498
|
for (const attr of path3.node.openingElement.attributes) {
|
|
986
|
-
if (
|
|
1499
|
+
if (t3.isJSXSpreadAttribute(attr)) {
|
|
987
1500
|
if (attr.argument) {
|
|
988
1501
|
spreads.push(attr.argument);
|
|
989
1502
|
}
|
|
990
1503
|
continue;
|
|
991
1504
|
}
|
|
992
|
-
if (
|
|
1505
|
+
if (t3.isJSXAttribute(attr)) {
|
|
993
1506
|
const attrName = attr.name.name;
|
|
994
1507
|
if (!attrName)
|
|
995
1508
|
continue;
|
|
996
|
-
if (
|
|
1509
|
+
if (t3.isJSXExpressionContainer(attr.value)) {
|
|
997
1510
|
const expr = attr.value.expression;
|
|
998
|
-
if (!expr ||
|
|
1511
|
+
if (!expr || t3.isJSXEmptyExpression(expr))
|
|
999
1512
|
continue;
|
|
1000
1513
|
props.push({ name: attrName, value: expr });
|
|
1001
1514
|
}
|
|
@@ -1003,9 +1516,9 @@ function collectImportedCallSites(ast, componentNames, imports) {
|
|
|
1003
1516
|
}
|
|
1004
1517
|
const childExprs = [];
|
|
1005
1518
|
for (const child of path3.node.children) {
|
|
1006
|
-
if (
|
|
1519
|
+
if (t3.isJSXExpressionContainer(child)) {
|
|
1007
1520
|
const expr = child.expression;
|
|
1008
|
-
if (!expr ||
|
|
1521
|
+
if (!expr || t3.isJSXEmptyExpression(expr))
|
|
1009
1522
|
continue;
|
|
1010
1523
|
childExprs.push(expr);
|
|
1011
1524
|
}
|
|
@@ -1013,7 +1526,7 @@ function collectImportedCallSites(ast, componentNames, imports) {
|
|
|
1013
1526
|
if (childExprs.length === 1) {
|
|
1014
1527
|
props.push({ name: "children", value: childExprs[0] });
|
|
1015
1528
|
} else if (childExprs.length > 1) {
|
|
1016
|
-
props.push({ name: "children", value:
|
|
1529
|
+
props.push({ name: "children", value: t3.arrayExpression(childExprs) });
|
|
1017
1530
|
}
|
|
1018
1531
|
sites.push({
|
|
1019
1532
|
caller: callerFn,
|
|
@@ -1031,6 +1544,7 @@ function analyzeModule(code, filePath) {
|
|
|
1031
1544
|
sourceType: "module",
|
|
1032
1545
|
plugins: ["jsx", "typescript"]
|
|
1033
1546
|
});
|
|
1547
|
+
autoWrapComponents(ast, filePath);
|
|
1034
1548
|
const names = trackReactiveImports(ast);
|
|
1035
1549
|
const {
|
|
1036
1550
|
functions,
|
|
@@ -1048,18 +1562,18 @@ function analyzeModule(code, filePath) {
|
|
|
1048
1562
|
exports.set(localName, fn);
|
|
1049
1563
|
}
|
|
1050
1564
|
}
|
|
1051
|
-
|
|
1565
|
+
traverse3(ast, {
|
|
1052
1566
|
ExportDefaultDeclaration(path3) {
|
|
1053
1567
|
const decl = path3.node.declaration;
|
|
1054
|
-
if (
|
|
1568
|
+
if (t3.isIdentifier(decl)) {
|
|
1055
1569
|
const fn = componentNames.get(decl.name);
|
|
1056
1570
|
if (fn)
|
|
1057
1571
|
defaultExport = fn;
|
|
1058
|
-
} else if (
|
|
1572
|
+
} else if (t3.isCallExpression(decl)) {
|
|
1059
1573
|
const callee = decl.callee;
|
|
1060
|
-
if (
|
|
1574
|
+
if (t3.isIdentifier(callee) && names.cc.has(callee.name)) {
|
|
1061
1575
|
const firstArg = decl.arguments[0];
|
|
1062
|
-
if (firstArg &&
|
|
1576
|
+
if (firstArg && t3.isFunction(firstArg)) {
|
|
1063
1577
|
defaultExport = firstArg;
|
|
1064
1578
|
}
|
|
1065
1579
|
}
|
|
@@ -1845,4 +2359,4 @@ if (import.meta.main) {
|
|
|
1845
2359
|
runAnalyzeCli();
|
|
1846
2360
|
}
|
|
1847
2361
|
|
|
1848
|
-
export { analyzeModule, analyzeProject, AnalyzerCache, analyze, loadMetadata, trackReactiveImports, getAllPropNames, isReactiveValue, containsReactiveValue, collectComponentFunctions, computeLocalScopes, collectComponentCallGraph, buildFullScope, propagateReactiveProps, wrapReactiveExpressions, runAnalyzeCli };
|
|
2362
|
+
export { autoWrapComponents, analyzeModule, analyzeProject, AnalyzerCache, analyze, loadMetadata, trackReactiveImports, getAllPropNames, isReactiveValue, containsReactiveValue, collectComponentFunctions, computeLocalScopes, collectComponentCallGraph, buildFullScope, propagateReactiveProps, wrapReactiveExpressions, runAnalyzeCli };
|