@weapp-vite/ast 6.8.0 → 6.9.0
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 +39 -1
- package/dist/babelCore.d.mts +2 -0
- package/dist/babelCore.mjs +2 -0
- package/dist/babelNodes.d.mts +3 -1
- package/dist/babelNodes.mjs +13 -1
- package/dist/babelTraverse.d.mts +2 -0
- package/dist/babelTraverse.mjs +2 -0
- package/dist/babelTypes.d.mts +1 -0
- package/dist/babelTypes.mjs +2 -0
- package/dist/index.d.mts +5 -3
- package/dist/index.mjs +5 -3
- package/dist/operations/jsxAutoComponents.d.mts +2 -1
- package/dist/operations/jsxAutoComponents.mjs +3 -3
- package/dist/operations/onPageScroll.d.mts +11 -0
- package/dist/operations/onPageScroll.mjs +259 -0
- package/dist/operations/setDataPick.d.mts +13 -0
- package/dist/operations/setDataPick.mjs +287 -0
- package/package.json +33 -6
package/README.md
CHANGED
|
@@ -63,15 +63,53 @@ const result = collectJsxAutoComponentsFromCode(code, {
|
|
|
63
63
|
})
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
##
|
|
66
|
+
## 稳定 API
|
|
67
|
+
|
|
68
|
+
建议优先从根入口导入稳定 API:
|
|
67
69
|
|
|
68
70
|
- `parseJsLikeWithEngine`
|
|
69
71
|
- `collectComponentPropsFromCode`
|
|
70
72
|
- `collectFeatureFlagsFromCode`
|
|
71
73
|
- `collectJsxAutoComponentsFromCode`
|
|
74
|
+
- `collectJsxImportedComponentsAndDefaultExportFromBabelAst`
|
|
75
|
+
- `collectJsxTemplateTagsFromBabelExpression`
|
|
72
76
|
- `mayContainPlatformApiAccess`
|
|
73
77
|
- `collectRequireTokens`
|
|
74
78
|
- `collectScriptSetupImportsFromCode`
|
|
79
|
+
- `unwrapTypeScriptExpression`
|
|
80
|
+
- `getObjectPropertyByKey`
|
|
81
|
+
- `getRenderPropertyFromComponentOptions`
|
|
82
|
+
- `resolveRenderExpressionFromComponentOptions`
|
|
83
|
+
|
|
84
|
+
## 子路径导出
|
|
85
|
+
|
|
86
|
+
如果需要更细粒度地按能力引用,也可以使用这些子路径导出:
|
|
87
|
+
|
|
88
|
+
- `@weapp-vite/ast/babel`
|
|
89
|
+
- `@weapp-vite/ast/babelNodes`
|
|
90
|
+
- `@weapp-vite/ast/engine`
|
|
91
|
+
- `@weapp-vite/ast/types`
|
|
92
|
+
- `@weapp-vite/ast/operations/componentProps`
|
|
93
|
+
- `@weapp-vite/ast/operations/featureFlags`
|
|
94
|
+
- `@weapp-vite/ast/operations/jsxAutoComponents`
|
|
95
|
+
- `@weapp-vite/ast/operations/platformApi`
|
|
96
|
+
- `@weapp-vite/ast/operations/require`
|
|
97
|
+
- `@weapp-vite/ast/operations/scriptSetupImports`
|
|
98
|
+
|
|
99
|
+
默认建议:
|
|
100
|
+
|
|
101
|
+
- 业务侧优先使用根入口
|
|
102
|
+
- 只有在需要低层 helper 或做更细粒度 tree-shaking 时,再使用子路径导入
|
|
103
|
+
|
|
104
|
+
## 发布校验
|
|
105
|
+
|
|
106
|
+
包内可直接运行以下命令做独立校验:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pnpm build
|
|
110
|
+
pnpm test
|
|
111
|
+
pnpm run check:release
|
|
112
|
+
```
|
|
75
113
|
|
|
76
114
|
## 相关链接
|
|
77
115
|
|
package/dist/babelNodes.d.mts
CHANGED
|
@@ -5,6 +5,8 @@ import { Expression, ObjectExpression, ObjectMethod, ObjectProperty, PrivateName
|
|
|
5
5
|
declare function unwrapTypeScriptExpression(exp: Expression): Expression;
|
|
6
6
|
declare function toStaticObjectKey(key: Expression | PrivateName | t.Identifier): string | null;
|
|
7
7
|
declare function getObjectPropertyByKey(node: ObjectExpression, key: string): ObjectMethod | ObjectProperty | null;
|
|
8
|
+
declare function getRenderPropertyFromComponentOptions(componentExpr: Expression): ObjectMethod | ObjectProperty | null;
|
|
8
9
|
declare function resolveRenderableExpression(node: ObjectMethod | ObjectProperty): Expression | null;
|
|
10
|
+
declare function resolveRenderExpressionFromComponentOptions(componentExpr: Expression): Expression | null;
|
|
9
11
|
//#endregion
|
|
10
|
-
export { getObjectPropertyByKey, resolveRenderableExpression, toStaticObjectKey, unwrapTypeScriptExpression };
|
|
12
|
+
export { getObjectPropertyByKey, getRenderPropertyFromComponentOptions, resolveRenderExpressionFromComponentOptions, resolveRenderableExpression, toStaticObjectKey, unwrapTypeScriptExpression };
|
package/dist/babelNodes.mjs
CHANGED
|
@@ -31,6 +31,13 @@ function getObjectPropertyByKey(node, key) {
|
|
|
31
31
|
}
|
|
32
32
|
return null;
|
|
33
33
|
}
|
|
34
|
+
function getRenderPropertyFromComponentOptions(componentExpr) {
|
|
35
|
+
if (!t.isObjectExpression(componentExpr)) return null;
|
|
36
|
+
const renderNode = getObjectPropertyByKey(componentExpr, "render");
|
|
37
|
+
if (!renderNode) return null;
|
|
38
|
+
if (!t.isObjectMethod(renderNode) && !t.isObjectProperty(renderNode)) return null;
|
|
39
|
+
return renderNode;
|
|
40
|
+
}
|
|
34
41
|
function resolveRenderableExpression(node) {
|
|
35
42
|
if (t.isObjectMethod(node)) {
|
|
36
43
|
for (const statement of node.body.body) if (t.isReturnStatement(statement) && statement.argument) return unwrapTypeScriptExpression(statement.argument);
|
|
@@ -50,5 +57,10 @@ function resolveRenderableExpression(node) {
|
|
|
50
57
|
}
|
|
51
58
|
return null;
|
|
52
59
|
}
|
|
60
|
+
function resolveRenderExpressionFromComponentOptions(componentExpr) {
|
|
61
|
+
const renderNode = getRenderPropertyFromComponentOptions(componentExpr);
|
|
62
|
+
if (!renderNode) return null;
|
|
63
|
+
return resolveRenderableExpression(renderNode);
|
|
64
|
+
}
|
|
53
65
|
//#endregion
|
|
54
|
-
export { getObjectPropertyByKey, resolveRenderableExpression, toStaticObjectKey, unwrapTypeScriptExpression };
|
|
66
|
+
export { getObjectPropertyByKey, getRenderPropertyFromComponentOptions, resolveRenderExpressionFromComponentOptions, resolveRenderableExpression, toStaticObjectKey, unwrapTypeScriptExpression };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "@babel/types";
|
package/dist/index.d.mts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { BABEL_TS_MODULE_PARSER_OPTIONS, BABEL_TS_MODULE_PLUGINS, generate, getVisitorKeys, parse, parseJsLike, traverse } from "./babel.mjs";
|
|
2
|
-
import { getObjectPropertyByKey, resolveRenderableExpression, toStaticObjectKey, unwrapTypeScriptExpression } from "./babelNodes.mjs";
|
|
2
|
+
import { getObjectPropertyByKey, getRenderPropertyFromComponentOptions, resolveRenderExpressionFromComponentOptions, resolveRenderableExpression, toStaticObjectKey, unwrapTypeScriptExpression } from "./babelNodes.mjs";
|
|
3
3
|
import { AstEngineName, AstParserLike, WeappAstConfig } from "./types.mjs";
|
|
4
4
|
import { parseJsLikeWithEngine } from "./engine.mjs";
|
|
5
5
|
import { ComponentPropMap, collectComponentPropsFromCode } from "./operations/componentProps.mjs";
|
|
6
6
|
import { FeatureFlagOptions, collectFeatureFlagsFromCode } from "./operations/featureFlags.mjs";
|
|
7
|
-
import { JsxAutoComponentAnalysisOptions, JsxAutoComponentContext, JsxBabelModuleAnalysisOptions, JsxImportedComponent, collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst } from "./operations/jsxAutoComponents.mjs";
|
|
7
|
+
import { JsxAutoComponentAnalysisOptions, JsxAutoComponentContext, JsxBabelModuleAnalysisOptions, JsxImportedComponent, collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst, collectJsxTemplateTagsFromBabelExpression } from "./operations/jsxAutoComponents.mjs";
|
|
8
|
+
import { collectOnPageScrollPerformanceWarnings } from "./operations/onPageScroll.mjs";
|
|
8
9
|
import { mayContainPlatformApiAccess, platformApiIdentifiers } from "./operations/platformApi.mjs";
|
|
9
10
|
import { RequireToken, collectRequireTokens, mayContainStaticRequireLiteral } from "./operations/require.mjs";
|
|
10
11
|
import { ScriptSetupImport, collectScriptSetupImportsFromCode } from "./operations/scriptSetupImports.mjs";
|
|
12
|
+
import { collectSetDataPickKeysFromTemplateCode } from "./operations/setDataPick.mjs";
|
|
11
13
|
import * as _babel_types0 from "@babel/types";
|
|
12
14
|
import * as oxc_parser0 from "oxc-parser";
|
|
13
15
|
|
|
@@ -29,4 +31,4 @@ declare const oxcAstEngine: {
|
|
|
29
31
|
parseJsLike(code: string, filename?: string): oxc_parser0.Program;
|
|
30
32
|
};
|
|
31
33
|
//#endregion
|
|
32
|
-
export { type AstEngineName, type AstParserLike, BABEL_TS_MODULE_PARSER_OPTIONS, BABEL_TS_MODULE_PLUGINS, type ComponentPropMap, type FeatureFlagOptions, type JsxAutoComponentAnalysisOptions, type JsxAutoComponentContext, type JsxBabelModuleAnalysisOptions, type JsxImportedComponent, type RequireToken, type ScriptSetupImport, type WeappAstConfig, babelAstEngine, collectComponentPropsFromCode, collectFeatureFlagsFromCode, collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst, collectRequireTokens, collectScriptSetupImportsFromCode, generate, getObjectPropertyByKey, getVisitorKeys, mayContainPlatformApiAccess, mayContainStaticRequireLiteral, oxcAstEngine, parse, parseJsLike, parseJsLikeWithEngine, platformApiIdentifiers, resolveRenderableExpression, toStaticObjectKey, traverse, unwrapTypeScriptExpression };
|
|
34
|
+
export { type AstEngineName, type AstParserLike, BABEL_TS_MODULE_PARSER_OPTIONS, BABEL_TS_MODULE_PLUGINS, type ComponentPropMap, type FeatureFlagOptions, type JsxAutoComponentAnalysisOptions, type JsxAutoComponentContext, type JsxBabelModuleAnalysisOptions, type JsxImportedComponent, type RequireToken, type ScriptSetupImport, type WeappAstConfig, babelAstEngine, collectComponentPropsFromCode, collectFeatureFlagsFromCode, collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst, collectJsxTemplateTagsFromBabelExpression, collectOnPageScrollPerformanceWarnings, collectRequireTokens, collectScriptSetupImportsFromCode, collectSetDataPickKeysFromTemplateCode, generate, getObjectPropertyByKey, getRenderPropertyFromComponentOptions, getVisitorKeys, mayContainPlatformApiAccess, mayContainStaticRequireLiteral, oxcAstEngine, parse, parseJsLike, parseJsLikeWithEngine, platformApiIdentifiers, resolveRenderExpressionFromComponentOptions, resolveRenderableExpression, toStaticObjectKey, traverse, unwrapTypeScriptExpression };
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { BABEL_TS_MODULE_PARSER_OPTIONS, BABEL_TS_MODULE_PLUGINS, generate, getVisitorKeys, parse, parseJsLike, traverse } from "./babel.mjs";
|
|
2
|
-
import { getObjectPropertyByKey, resolveRenderableExpression, toStaticObjectKey, unwrapTypeScriptExpression } from "./babelNodes.mjs";
|
|
2
|
+
import { getObjectPropertyByKey, getRenderPropertyFromComponentOptions, resolveRenderExpressionFromComponentOptions, resolveRenderableExpression, toStaticObjectKey, unwrapTypeScriptExpression } from "./babelNodes.mjs";
|
|
3
3
|
import { n as oxcAstEngine, r as babelAstEngine, t as parseJsLikeWithEngine } from "./engine-DHqNPCDA.mjs";
|
|
4
4
|
import { collectComponentPropsFromCode } from "./operations/componentProps.mjs";
|
|
5
5
|
import { collectFeatureFlagsFromCode } from "./operations/featureFlags.mjs";
|
|
6
|
-
import { collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst } from "./operations/jsxAutoComponents.mjs";
|
|
6
|
+
import { collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst, collectJsxTemplateTagsFromBabelExpression } from "./operations/jsxAutoComponents.mjs";
|
|
7
|
+
import { collectOnPageScrollPerformanceWarnings } from "./operations/onPageScroll.mjs";
|
|
7
8
|
import { mayContainPlatformApiAccess, platformApiIdentifiers } from "./operations/platformApi.mjs";
|
|
8
9
|
import { collectRequireTokens, mayContainStaticRequireLiteral } from "./operations/require.mjs";
|
|
9
10
|
import { collectScriptSetupImportsFromCode } from "./operations/scriptSetupImports.mjs";
|
|
10
|
-
|
|
11
|
+
import { collectSetDataPickKeysFromTemplateCode } from "./operations/setDataPick.mjs";
|
|
12
|
+
export { BABEL_TS_MODULE_PARSER_OPTIONS, BABEL_TS_MODULE_PLUGINS, babelAstEngine, collectComponentPropsFromCode, collectFeatureFlagsFromCode, collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst, collectJsxTemplateTagsFromBabelExpression, collectOnPageScrollPerformanceWarnings, collectRequireTokens, collectScriptSetupImportsFromCode, collectSetDataPickKeysFromTemplateCode, generate, getObjectPropertyByKey, getRenderPropertyFromComponentOptions, getVisitorKeys, mayContainPlatformApiAccess, mayContainStaticRequireLiteral, oxcAstEngine, parse, parseJsLike, parseJsLikeWithEngine, platformApiIdentifiers, resolveRenderExpressionFromComponentOptions, resolveRenderableExpression, toStaticObjectKey, traverse, unwrapTypeScriptExpression };
|
|
@@ -28,9 +28,10 @@ declare function collectJsxImportedComponentsAndDefaultExportFromBabelAst(ast: t
|
|
|
28
28
|
importedComponents: JsxImportedComponent[];
|
|
29
29
|
exportDefaultExpression: null;
|
|
30
30
|
};
|
|
31
|
+
declare function collectJsxTemplateTagsFromBabelExpression(renderExpression: Expression, isCollectableTag: (tag: string) => boolean): Set<string>;
|
|
31
32
|
/**
|
|
32
33
|
* 从 JSX 源码中收集自动 usingComponents 所需的导入组件与模板标签。
|
|
33
34
|
*/
|
|
34
35
|
declare function collectJsxAutoComponentsFromCode(source: string, options: JsxAutoComponentAnalysisOptions): JsxAutoComponentContext;
|
|
35
36
|
//#endregion
|
|
36
|
-
export { JsxAutoComponentAnalysisOptions, JsxAutoComponentContext, JsxBabelModuleAnalysisOptions, JsxImportedComponent, collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst };
|
|
37
|
+
export { JsxAutoComponentAnalysisOptions, JsxAutoComponentContext, JsxBabelModuleAnalysisOptions, JsxImportedComponent, collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst, collectJsxTemplateTagsFromBabelExpression };
|
|
@@ -91,7 +91,7 @@ function collectJsxImportedComponentsAndDefaultExportFromBabelAst(ast, options =
|
|
|
91
91
|
exportDefaultExpression
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
-
function
|
|
94
|
+
function collectJsxTemplateTagsFromBabelExpression(renderExpression, isCollectableTag) {
|
|
95
95
|
const tags = /* @__PURE__ */ new Set();
|
|
96
96
|
function walk(node) {
|
|
97
97
|
if (t.isJSXElement(node)) {
|
|
@@ -209,7 +209,7 @@ function collectWithBabel(source, options) {
|
|
|
209
209
|
importedComponents
|
|
210
210
|
};
|
|
211
211
|
return {
|
|
212
|
-
templateTags:
|
|
212
|
+
templateTags: collectJsxTemplateTagsFromBabelExpression(renderExpression, options.isCollectableTag),
|
|
213
213
|
importedComponents
|
|
214
214
|
};
|
|
215
215
|
}
|
|
@@ -302,4 +302,4 @@ function collectJsxAutoComponentsFromCode(source, options) {
|
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
//#endregion
|
|
305
|
-
export { collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst };
|
|
305
|
+
export { collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst, collectJsxTemplateTagsFromBabelExpression };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AstEngineName } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/operations/onPageScroll.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* 静态检测 onPageScroll 中的常见性能风险并返回告警文案。
|
|
6
|
+
*/
|
|
7
|
+
declare function collectOnPageScrollPerformanceWarnings(code: string, filename: string, options?: {
|
|
8
|
+
engine?: AstEngineName;
|
|
9
|
+
}): string[];
|
|
10
|
+
//#endregion
|
|
11
|
+
export { collectOnPageScrollPerformanceWarnings };
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { parseJsLike, traverse } from "../babel.mjs";
|
|
2
|
+
import { t as parseJsLikeWithEngine } from "../engine-DHqNPCDA.mjs";
|
|
3
|
+
//#region src/operations/onPageScroll.ts
|
|
4
|
+
function isStaticPropertyName(key) {
|
|
5
|
+
if (key.type === "Identifier") return key.name;
|
|
6
|
+
if (key.type === "StringLiteral") return key.value;
|
|
7
|
+
}
|
|
8
|
+
function getMemberExpressionPropertyName(node) {
|
|
9
|
+
if (node.computed) return node.property.type === "StringLiteral" ? node.property.value : void 0;
|
|
10
|
+
return node.property.type === "Identifier" ? node.property.name : void 0;
|
|
11
|
+
}
|
|
12
|
+
function isOnPageScrollCallee(callee, hookNames, namespaceImports) {
|
|
13
|
+
if (callee.type === "Identifier") return hookNames.has(callee.name);
|
|
14
|
+
if (callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") {
|
|
15
|
+
const object = callee.object;
|
|
16
|
+
const propName = getMemberExpressionPropertyName(callee);
|
|
17
|
+
return object.type === "Identifier" && namespaceImports.has(object.name) && propName === "onPageScroll";
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function getCallExpressionCalleeName(callee) {
|
|
22
|
+
if (callee.type === "Identifier") return callee.name;
|
|
23
|
+
if (callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") return getMemberExpressionPropertyName(callee);
|
|
24
|
+
}
|
|
25
|
+
function collectPageScrollInspection(functionPath, node) {
|
|
26
|
+
const inspection = {
|
|
27
|
+
empty: node.body.type === "BlockStatement" && node.body.body.length === 0,
|
|
28
|
+
hasSetDataCall: false,
|
|
29
|
+
syncApis: /* @__PURE__ */ new Set()
|
|
30
|
+
};
|
|
31
|
+
functionPath.traverse({
|
|
32
|
+
Function(innerPath) {
|
|
33
|
+
if (innerPath !== functionPath) innerPath.skip();
|
|
34
|
+
},
|
|
35
|
+
CallExpression(callPath) {
|
|
36
|
+
const callee = callPath.node.callee;
|
|
37
|
+
if (getCallExpressionCalleeName(callee) === "setData") inspection.hasSetDataCall = true;
|
|
38
|
+
if (callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") {
|
|
39
|
+
const object = callee.object;
|
|
40
|
+
if (object.type === "Identifier" && object.name === "wx") {
|
|
41
|
+
const propertyName = getMemberExpressionPropertyName(callee);
|
|
42
|
+
if (propertyName && propertyName.endsWith("Sync")) inspection.syncApis.add(`wx.${propertyName}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
OptionalCallExpression(callPath) {
|
|
47
|
+
const callee = callPath.node.callee;
|
|
48
|
+
if (getCallExpressionCalleeName(callee) === "setData") inspection.hasSetDataCall = true;
|
|
49
|
+
if (callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") {
|
|
50
|
+
const object = callee.object;
|
|
51
|
+
if (object.type === "Identifier" && object.name === "wx") {
|
|
52
|
+
const propertyName = getMemberExpressionPropertyName(callee);
|
|
53
|
+
if (propertyName && propertyName.endsWith("Sync")) inspection.syncApis.add(`wx.${propertyName}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return inspection;
|
|
59
|
+
}
|
|
60
|
+
function createWarningPrefix(filename, line, column) {
|
|
61
|
+
return `[weapp-vite][onPageScroll] ${filename}:${typeof line === "number" && typeof column === "number" ? `${line}:${column}` : "?:?"}`;
|
|
62
|
+
}
|
|
63
|
+
function getOxcStaticPropertyName(node) {
|
|
64
|
+
if (!node) return;
|
|
65
|
+
if (node.type === "Identifier") return node.name;
|
|
66
|
+
if ((node.type === "StringLiteral" || node.type === "Literal") && typeof node.value === "string") return node.value;
|
|
67
|
+
}
|
|
68
|
+
function getOxcMemberExpressionPropertyName(node) {
|
|
69
|
+
if (!node || node.type !== "MemberExpression") return;
|
|
70
|
+
if (node.computed) return getOxcStaticPropertyName(node.property);
|
|
71
|
+
return node.property?.type === "Identifier" ? node.property.name : void 0;
|
|
72
|
+
}
|
|
73
|
+
function isOxcFunctionLike(node) {
|
|
74
|
+
return node?.type === "FunctionExpression" || node?.type === "ArrowFunctionExpression";
|
|
75
|
+
}
|
|
76
|
+
function isOxcOnPageScrollCallee(callee, hookNames, namespaceImports) {
|
|
77
|
+
if (!callee) return false;
|
|
78
|
+
if (callee.type === "Identifier") return hookNames.has(callee.name);
|
|
79
|
+
if (callee.type === "MemberExpression") {
|
|
80
|
+
const propName = getOxcMemberExpressionPropertyName(callee);
|
|
81
|
+
return callee.object?.type === "Identifier" && namespaceImports.has(callee.object.name) && propName === "onPageScroll";
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
function getOxcCallExpressionCalleeName(callee) {
|
|
86
|
+
if (!callee) return;
|
|
87
|
+
if (callee.type === "Identifier") return callee.name;
|
|
88
|
+
if (callee.type === "MemberExpression") return getOxcMemberExpressionPropertyName(callee);
|
|
89
|
+
}
|
|
90
|
+
function createLineStartOffsets(code) {
|
|
91
|
+
const offsets = [0];
|
|
92
|
+
for (let index = 0; index < code.length; index += 1) if (code.charCodeAt(index) === 10) offsets.push(index + 1);
|
|
93
|
+
return offsets;
|
|
94
|
+
}
|
|
95
|
+
function getLocationFromOffset(offset, lineStarts) {
|
|
96
|
+
if (typeof offset !== "number" || offset < 0) return;
|
|
97
|
+
let low = 0;
|
|
98
|
+
let high = lineStarts.length - 1;
|
|
99
|
+
while (low <= high) {
|
|
100
|
+
const mid = Math.floor((low + high) / 2);
|
|
101
|
+
if (lineStarts[mid] <= offset) low = mid + 1;
|
|
102
|
+
else high = mid - 1;
|
|
103
|
+
}
|
|
104
|
+
const lineIndex = Math.max(0, low - 1);
|
|
105
|
+
return {
|
|
106
|
+
line: lineIndex + 1,
|
|
107
|
+
column: offset - lineStarts[lineIndex] + 1
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function collectPageScrollInspectionWithOxc(node) {
|
|
111
|
+
const inspection = {
|
|
112
|
+
empty: node.body?.type === "BlockStatement" && node.body.body.length === 0,
|
|
113
|
+
hasSetDataCall: false,
|
|
114
|
+
syncApis: /* @__PURE__ */ new Set()
|
|
115
|
+
};
|
|
116
|
+
const root = node.body?.type === "BlockStatement" ? node.body : node.body;
|
|
117
|
+
function visit(current, allowNestedFunctions = false) {
|
|
118
|
+
if (!current) return;
|
|
119
|
+
if (!allowNestedFunctions && (current.type === "FunctionExpression" || current.type === "ArrowFunctionExpression")) return;
|
|
120
|
+
if (current.type === "CallExpression") {
|
|
121
|
+
if (getOxcCallExpressionCalleeName(current.callee) === "setData") inspection.hasSetDataCall = true;
|
|
122
|
+
if (current.callee?.type === "MemberExpression" && current.callee.object?.type === "Identifier" && current.callee.object.name === "wx") {
|
|
123
|
+
const propertyName = getOxcMemberExpressionPropertyName(current.callee);
|
|
124
|
+
if (propertyName && propertyName.endsWith("Sync")) inspection.syncApis.add(`wx.${propertyName}`);
|
|
125
|
+
}
|
|
126
|
+
} else if (current.type === "ChainExpression") {
|
|
127
|
+
visit(current.expression, allowNestedFunctions);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
for (const value of Object.values(current)) {
|
|
131
|
+
if (!value) continue;
|
|
132
|
+
if (Array.isArray(value)) {
|
|
133
|
+
for (const child of value) if (child && typeof child === "object" && typeof child.type === "string") visit(child);
|
|
134
|
+
} else if (typeof value === "object" && typeof value.type === "string") visit(value);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (root) visit(root, true);
|
|
138
|
+
return inspection;
|
|
139
|
+
}
|
|
140
|
+
function collectWithOxc(code, filename) {
|
|
141
|
+
const ast = parseJsLikeWithEngine(code, {
|
|
142
|
+
engine: "oxc",
|
|
143
|
+
filename: "inline.ts"
|
|
144
|
+
});
|
|
145
|
+
const onPageScrollHookNames = new Set(["onPageScroll"]);
|
|
146
|
+
const namespaceImports = /* @__PURE__ */ new Set();
|
|
147
|
+
for (const statement of ast.body ?? []) {
|
|
148
|
+
if (statement?.type !== "ImportDeclaration" || statement.source?.value !== "wevu") continue;
|
|
149
|
+
for (const specifier of statement.specifiers ?? []) if (specifier.type === "ImportSpecifier" && specifier.imported?.type === "Identifier" && specifier.imported.name === "onPageScroll" && specifier.local?.type === "Identifier") onPageScrollHookNames.add(specifier.local.name);
|
|
150
|
+
else if (specifier.type === "ImportNamespaceSpecifier" && specifier.local?.type === "Identifier") namespaceImports.add(specifier.local.name);
|
|
151
|
+
}
|
|
152
|
+
const lineStarts = createLineStartOffsets(code);
|
|
153
|
+
const warnings = [];
|
|
154
|
+
const warningSet = /* @__PURE__ */ new Set();
|
|
155
|
+
const addWarning = (warning) => {
|
|
156
|
+
if (warningSet.has(warning)) return;
|
|
157
|
+
warningSet.add(warning);
|
|
158
|
+
warnings.push(warning);
|
|
159
|
+
};
|
|
160
|
+
const reportInspection = (node, sourceLabel, startOffset = node.start) => {
|
|
161
|
+
const inspection = collectPageScrollInspectionWithOxc(node);
|
|
162
|
+
const loc = getLocationFromOffset(startOffset, lineStarts);
|
|
163
|
+
const prefix = createWarningPrefix(filename, loc?.line, loc?.column);
|
|
164
|
+
if (inspection.empty) addWarning(`${prefix} 检测到空的 ${sourceLabel} 回调,建议移除无效监听以降低滚动时调度开销。`);
|
|
165
|
+
if (inspection.hasSetDataCall) addWarning(`${prefix} 检测到 ${sourceLabel} 内调用 setData,建议改用节流、IntersectionObserver 或合并更新。`);
|
|
166
|
+
for (const syncApi of inspection.syncApis) addWarning(`${prefix} 检测到 ${sourceLabel} 内调用同步 API(${syncApi}),可能阻塞渲染线程。`);
|
|
167
|
+
};
|
|
168
|
+
function visit(node) {
|
|
169
|
+
if (!node) return;
|
|
170
|
+
if (node.type === "Property" && !node.computed && getOxcStaticPropertyName(node.key) === "onPageScroll" && isOxcFunctionLike(node.value)) {
|
|
171
|
+
const startOffset = node.method ? node.key?.end : node.value.start;
|
|
172
|
+
reportInspection(node.value, "onPageScroll", startOffset);
|
|
173
|
+
} else if (node.type === "CallExpression" && isOxcOnPageScrollCallee(node.callee, onPageScrollHookNames, namespaceImports)) {
|
|
174
|
+
const arg0 = node.arguments?.[0];
|
|
175
|
+
if (arg0 && arg0.type !== "SpreadElement" && isOxcFunctionLike(arg0)) reportInspection(arg0, "onPageScroll(...)");
|
|
176
|
+
} else if (node.type === "ChainExpression" && node.expression?.type === "CallExpression") {
|
|
177
|
+
const arg0 = node.expression.arguments?.[0];
|
|
178
|
+
if (isOxcOnPageScrollCallee(node.expression.callee, onPageScrollHookNames, namespaceImports) && arg0 && arg0.type !== "SpreadElement" && isOxcFunctionLike(arg0)) reportInspection(arg0, "onPageScroll(...)");
|
|
179
|
+
}
|
|
180
|
+
for (const value of Object.values(node)) {
|
|
181
|
+
if (!value) continue;
|
|
182
|
+
if (Array.isArray(value)) {
|
|
183
|
+
for (const child of value) if (child && typeof child === "object" && typeof child.type === "string") visit(child);
|
|
184
|
+
} else if (typeof value === "object" && typeof value.type === "string") visit(value);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
visit(ast);
|
|
188
|
+
return warnings;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 静态检测 onPageScroll 中的常见性能风险并返回告警文案。
|
|
192
|
+
*/
|
|
193
|
+
function collectOnPageScrollPerformanceWarnings(code, filename, options) {
|
|
194
|
+
if (options?.engine === "oxc") try {
|
|
195
|
+
return collectWithOxc(code, filename);
|
|
196
|
+
} catch {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
let ast;
|
|
200
|
+
try {
|
|
201
|
+
ast = parseJsLike(code);
|
|
202
|
+
} catch {
|
|
203
|
+
return [];
|
|
204
|
+
}
|
|
205
|
+
const onPageScrollHookNames = new Set(["onPageScroll"]);
|
|
206
|
+
const namespaceImports = /* @__PURE__ */ new Set();
|
|
207
|
+
for (const statement of ast.program.body) {
|
|
208
|
+
if (statement.type !== "ImportDeclaration" || statement.source.value !== "wevu") continue;
|
|
209
|
+
for (const specifier of statement.specifiers) {
|
|
210
|
+
if (specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier" && specifier.imported.name === "onPageScroll") onPageScrollHookNames.add(specifier.local.name);
|
|
211
|
+
if (specifier.type === "ImportNamespaceSpecifier") namespaceImports.add(specifier.local.name);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const warnings = [];
|
|
215
|
+
const warningSet = /* @__PURE__ */ new Set();
|
|
216
|
+
const addWarning = (warning) => {
|
|
217
|
+
if (warningSet.has(warning)) return;
|
|
218
|
+
warningSet.add(warning);
|
|
219
|
+
warnings.push(warning);
|
|
220
|
+
};
|
|
221
|
+
const reportInspection = (functionPath, node, sourceLabel) => {
|
|
222
|
+
const inspection = collectPageScrollInspection(functionPath, node);
|
|
223
|
+
const line = node.loc?.start.line;
|
|
224
|
+
const prefix = createWarningPrefix(filename, line, typeof node.loc?.start.column === "number" ? node.loc.start.column + 1 : void 0);
|
|
225
|
+
if (inspection.empty) addWarning(`${prefix} 检测到空的 ${sourceLabel} 回调,建议移除无效监听以降低滚动时调度开销。`);
|
|
226
|
+
if (inspection.hasSetDataCall) addWarning(`${prefix} 检测到 ${sourceLabel} 内调用 setData,建议改用节流、IntersectionObserver 或合并更新。`);
|
|
227
|
+
for (const syncApi of inspection.syncApis) addWarning(`${prefix} 检测到 ${sourceLabel} 内调用同步 API(${syncApi}),可能阻塞渲染线程。`);
|
|
228
|
+
};
|
|
229
|
+
traverse(ast, {
|
|
230
|
+
ObjectMethod(path) {
|
|
231
|
+
if (isStaticPropertyName(path.node.key) !== "onPageScroll") return;
|
|
232
|
+
reportInspection(path, path.node, "onPageScroll");
|
|
233
|
+
},
|
|
234
|
+
ObjectProperty(path) {
|
|
235
|
+
if (path.node.computed) return;
|
|
236
|
+
if (isStaticPropertyName(path.node.key) !== "onPageScroll") return;
|
|
237
|
+
const value = path.node.value;
|
|
238
|
+
if (value.type !== "FunctionExpression" && value.type !== "ArrowFunctionExpression") return;
|
|
239
|
+
reportInspection(path.get("value"), value, "onPageScroll");
|
|
240
|
+
},
|
|
241
|
+
CallExpression(path) {
|
|
242
|
+
if (!isOnPageScrollCallee(path.node.callee, onPageScrollHookNames, namespaceImports)) return;
|
|
243
|
+
const arg0 = path.node.arguments[0];
|
|
244
|
+
if (!arg0 || arg0.type === "SpreadElement") return;
|
|
245
|
+
if (arg0.type !== "FunctionExpression" && arg0.type !== "ArrowFunctionExpression") return;
|
|
246
|
+
reportInspection(path.get("arguments.0"), arg0, "onPageScroll(...)");
|
|
247
|
+
},
|
|
248
|
+
OptionalCallExpression(path) {
|
|
249
|
+
if (!isOnPageScrollCallee(path.node.callee, onPageScrollHookNames, namespaceImports)) return;
|
|
250
|
+
const arg0 = path.node.arguments[0];
|
|
251
|
+
if (!arg0 || arg0.type === "SpreadElement") return;
|
|
252
|
+
if (arg0.type !== "FunctionExpression" && arg0.type !== "ArrowFunctionExpression") return;
|
|
253
|
+
reportInspection(path.get("arguments.0"), arg0, "onPageScroll(...)");
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
return warnings;
|
|
257
|
+
}
|
|
258
|
+
//#endregion
|
|
259
|
+
export { collectOnPageScrollPerformanceWarnings };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AstEngineName } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/operations/setDataPick.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* 从编译后的 WXML 模板提取渲染相关的顶层 key。
|
|
6
|
+
*
|
|
7
|
+
* 根据 AST 引擎从编译后的 WXML 模板提取渲染相关的顶层 key。
|
|
8
|
+
*/
|
|
9
|
+
declare function collectSetDataPickKeysFromTemplateCode(template: string, options?: {
|
|
10
|
+
astEngine?: AstEngineName;
|
|
11
|
+
}): string[];
|
|
12
|
+
//#endregion
|
|
13
|
+
export { collectSetDataPickKeysFromTemplateCode };
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { BABEL_TS_MODULE_PARSER_OPTIONS, parse, traverse } from "../babel.mjs";
|
|
2
|
+
import { t as parseJsLikeWithEngine } from "../engine-DHqNPCDA.mjs";
|
|
3
|
+
//#region src/operations/setDataPick.ts
|
|
4
|
+
const TEMPLATE_MUSTACHE_RE = /\{\{([\s\S]*?)\}\}/g;
|
|
5
|
+
const WX_FOR_TAG_RE = /<[^>]*\bwx:for\s*=\s*(?:"[^"]*"|'[^']*')[^>]*>/g;
|
|
6
|
+
const WX_FOR_ITEM_RE = /\bwx:for-item\s*=\s*(?:"([^"]+)"|'([^']+)')/;
|
|
7
|
+
const WX_FOR_INDEX_RE = /\bwx:for-index\s*=\s*(?:"([^"]+)"|'([^']+)')/;
|
|
8
|
+
const JS_GLOBAL_IDENTIFIERS = new Set([
|
|
9
|
+
"undefined",
|
|
10
|
+
"NaN",
|
|
11
|
+
"Infinity",
|
|
12
|
+
"globalThis",
|
|
13
|
+
"Math",
|
|
14
|
+
"Number",
|
|
15
|
+
"String",
|
|
16
|
+
"Boolean",
|
|
17
|
+
"Object",
|
|
18
|
+
"Array",
|
|
19
|
+
"Date",
|
|
20
|
+
"JSON",
|
|
21
|
+
"RegExp",
|
|
22
|
+
"Map",
|
|
23
|
+
"Set",
|
|
24
|
+
"WeakMap",
|
|
25
|
+
"WeakSet",
|
|
26
|
+
"parseInt",
|
|
27
|
+
"parseFloat",
|
|
28
|
+
"isNaN",
|
|
29
|
+
"isFinite",
|
|
30
|
+
"decodeURI",
|
|
31
|
+
"decodeURIComponent",
|
|
32
|
+
"encodeURI",
|
|
33
|
+
"encodeURIComponent"
|
|
34
|
+
]);
|
|
35
|
+
function collectLoopScopeAliases(template) {
|
|
36
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
37
|
+
const tagMatches = template.match(WX_FOR_TAG_RE) ?? [];
|
|
38
|
+
for (const tag of tagMatches) {
|
|
39
|
+
const itemMatch = tag.match(WX_FOR_ITEM_RE);
|
|
40
|
+
if (itemMatch) {
|
|
41
|
+
const itemAlias = (itemMatch[1] ?? itemMatch[2] ?? "").trim();
|
|
42
|
+
if (itemAlias) aliases.add(itemAlias);
|
|
43
|
+
} else aliases.add("item");
|
|
44
|
+
const indexMatch = tag.match(WX_FOR_INDEX_RE);
|
|
45
|
+
if (indexMatch) {
|
|
46
|
+
const indexAlias = (indexMatch[1] ?? indexMatch[2] ?? "").trim();
|
|
47
|
+
if (indexAlias) aliases.add(indexAlias);
|
|
48
|
+
} else aliases.add("index");
|
|
49
|
+
}
|
|
50
|
+
return aliases;
|
|
51
|
+
}
|
|
52
|
+
function extractTemplateExpressions(template) {
|
|
53
|
+
const expressions = [];
|
|
54
|
+
let match = TEMPLATE_MUSTACHE_RE.exec(template);
|
|
55
|
+
while (match) {
|
|
56
|
+
const expression = (match[1] ?? "").trim();
|
|
57
|
+
if (expression) expressions.push(expression);
|
|
58
|
+
match = TEMPLATE_MUSTACHE_RE.exec(template);
|
|
59
|
+
}
|
|
60
|
+
TEMPLATE_MUSTACHE_RE.lastIndex = 0;
|
|
61
|
+
return expressions;
|
|
62
|
+
}
|
|
63
|
+
function collectIdentifiersFromExpression(expression) {
|
|
64
|
+
const collected = /* @__PURE__ */ new Set();
|
|
65
|
+
let ast;
|
|
66
|
+
try {
|
|
67
|
+
ast = parse(`const __weappViteExpr = (${expression});`, {
|
|
68
|
+
...BABEL_TS_MODULE_PARSER_OPTIONS,
|
|
69
|
+
sourceType: "module"
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
return collected;
|
|
73
|
+
}
|
|
74
|
+
traverse(ast, {
|
|
75
|
+
Identifier(path) {
|
|
76
|
+
if (!path.isReferencedIdentifier()) return;
|
|
77
|
+
const name = path.node.name;
|
|
78
|
+
if (name === "__weappViteExpr") return;
|
|
79
|
+
if (path.scope.hasBinding(name, true)) return;
|
|
80
|
+
if (JS_GLOBAL_IDENTIFIERS.has(name)) return;
|
|
81
|
+
collected.add(name);
|
|
82
|
+
},
|
|
83
|
+
MemberExpression(path) {
|
|
84
|
+
const member = path.node;
|
|
85
|
+
if (member.computed || member.object.type !== "ThisExpression" || member.property.type !== "Identifier") return;
|
|
86
|
+
collected.add(member.property.name);
|
|
87
|
+
},
|
|
88
|
+
OptionalMemberExpression(path) {
|
|
89
|
+
const member = path.node;
|
|
90
|
+
if (member.computed || member.object.type !== "ThisExpression" || member.property.type !== "Identifier") return;
|
|
91
|
+
collected.add(member.property.name);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return collected;
|
|
95
|
+
}
|
|
96
|
+
function collectPatternBindingNames(node, bindings) {
|
|
97
|
+
if (!node) return;
|
|
98
|
+
if (node.type === "Identifier") {
|
|
99
|
+
bindings.add(node.name);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (node.type === "RestElement") {
|
|
103
|
+
collectPatternBindingNames(node.argument, bindings);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (node.type === "AssignmentPattern") {
|
|
107
|
+
collectPatternBindingNames(node.left, bindings);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (node.type === "ArrayPattern") {
|
|
111
|
+
for (const element of node.elements ?? []) collectPatternBindingNames(element, bindings);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (node.type === "ObjectPattern") for (const property of node.properties ?? []) if (property?.type === "RestElement") collectPatternBindingNames(property.argument, bindings);
|
|
115
|
+
else collectPatternBindingNames(property?.value, bindings);
|
|
116
|
+
}
|
|
117
|
+
function collectIdentifiersFromExpressionWithOxc(expression) {
|
|
118
|
+
const collected = /* @__PURE__ */ new Set();
|
|
119
|
+
let ast;
|
|
120
|
+
try {
|
|
121
|
+
ast = parseJsLikeWithEngine(`const __weappViteExpr = (${expression});`, {
|
|
122
|
+
engine: "oxc",
|
|
123
|
+
filename: "inline.ts"
|
|
124
|
+
});
|
|
125
|
+
} catch {
|
|
126
|
+
return collected;
|
|
127
|
+
}
|
|
128
|
+
const scopes = [/* @__PURE__ */ new Set()];
|
|
129
|
+
function hasBinding(name) {
|
|
130
|
+
return scopes.some((scope) => scope.has(name));
|
|
131
|
+
}
|
|
132
|
+
function visit(node) {
|
|
133
|
+
if (!node) return;
|
|
134
|
+
if (node.type === "ReturnStatement") {
|
|
135
|
+
visit(node.argument);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (node.type === "IfStatement") {
|
|
139
|
+
visit(node.test);
|
|
140
|
+
visit(node.consequent);
|
|
141
|
+
visit(node.alternate);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
switch (node.type) {
|
|
145
|
+
case "Program":
|
|
146
|
+
for (const statement of node.body ?? []) visit(statement);
|
|
147
|
+
return;
|
|
148
|
+
case "ExpressionStatement":
|
|
149
|
+
visit(node.expression);
|
|
150
|
+
return;
|
|
151
|
+
case "ParenthesizedExpression":
|
|
152
|
+
case "TSAsExpression":
|
|
153
|
+
case "TSSatisfiesExpression":
|
|
154
|
+
case "TSNonNullExpression":
|
|
155
|
+
visit(node.expression);
|
|
156
|
+
return;
|
|
157
|
+
case "VariableDeclaration":
|
|
158
|
+
for (const declaration of node.declarations ?? []) visit(declaration);
|
|
159
|
+
return;
|
|
160
|
+
case "VariableDeclarator": {
|
|
161
|
+
const bindings = /* @__PURE__ */ new Set();
|
|
162
|
+
collectPatternBindingNames(node.id, bindings);
|
|
163
|
+
const currentScope = scopes.at(-1);
|
|
164
|
+
for (const binding of bindings) currentScope?.add(binding);
|
|
165
|
+
visit(node.init);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
case "Identifier":
|
|
169
|
+
if (node.name !== "__weappViteExpr" && !hasBinding(node.name) && !JS_GLOBAL_IDENTIFIERS.has(node.name)) collected.add(node.name);
|
|
170
|
+
return;
|
|
171
|
+
case "ChainExpression":
|
|
172
|
+
visit(node.expression);
|
|
173
|
+
return;
|
|
174
|
+
case "MemberExpression":
|
|
175
|
+
if (node.object?.type === "ThisExpression" && !node.computed && node.property?.type === "Identifier") {
|
|
176
|
+
collected.add(node.property.name);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
visit(node.object);
|
|
180
|
+
if (node.computed) visit(node.property);
|
|
181
|
+
return;
|
|
182
|
+
case "CallExpression":
|
|
183
|
+
case "NewExpression":
|
|
184
|
+
visit(node.callee);
|
|
185
|
+
for (const argument of node.arguments ?? []) if (argument?.type === "SpreadElement") visit(argument.argument);
|
|
186
|
+
else visit(argument);
|
|
187
|
+
return;
|
|
188
|
+
case "ArrayExpression":
|
|
189
|
+
for (const element of node.elements ?? []) if (element?.type === "SpreadElement") visit(element.argument);
|
|
190
|
+
else visit(element);
|
|
191
|
+
return;
|
|
192
|
+
case "ObjectExpression":
|
|
193
|
+
for (const property of node.properties ?? []) visit(property);
|
|
194
|
+
return;
|
|
195
|
+
case "ObjectProperty":
|
|
196
|
+
case "Property":
|
|
197
|
+
if (node.computed) visit(node.key);
|
|
198
|
+
visit(node.value);
|
|
199
|
+
return;
|
|
200
|
+
case "SpreadProperty":
|
|
201
|
+
case "SpreadElement":
|
|
202
|
+
visit(node.argument);
|
|
203
|
+
return;
|
|
204
|
+
case "TemplateLiteral":
|
|
205
|
+
for (const expressionNode of node.expressions ?? []) visit(expressionNode);
|
|
206
|
+
return;
|
|
207
|
+
case "TaggedTemplateExpression":
|
|
208
|
+
visit(node.tag);
|
|
209
|
+
visit(node.quasi);
|
|
210
|
+
return;
|
|
211
|
+
case "UnaryExpression":
|
|
212
|
+
case "UpdateExpression":
|
|
213
|
+
case "AwaitExpression":
|
|
214
|
+
visit(node.argument);
|
|
215
|
+
return;
|
|
216
|
+
case "BinaryExpression":
|
|
217
|
+
case "LogicalExpression":
|
|
218
|
+
case "AssignmentExpression":
|
|
219
|
+
visit(node.left);
|
|
220
|
+
visit(node.right);
|
|
221
|
+
return;
|
|
222
|
+
case "ConditionalExpression":
|
|
223
|
+
visit(node.test);
|
|
224
|
+
visit(node.consequent);
|
|
225
|
+
visit(node.alternate);
|
|
226
|
+
return;
|
|
227
|
+
case "SequenceExpression":
|
|
228
|
+
for (const expressionNode of node.expressions ?? []) visit(expressionNode);
|
|
229
|
+
return;
|
|
230
|
+
case "ArrowFunctionExpression":
|
|
231
|
+
case "FunctionExpression": {
|
|
232
|
+
const nextScope = /* @__PURE__ */ new Set();
|
|
233
|
+
if (node.type === "FunctionExpression" && node.id?.type === "Identifier") nextScope.add(node.id.name);
|
|
234
|
+
for (const parameter of node.params ?? []) collectPatternBindingNames(parameter, nextScope);
|
|
235
|
+
scopes.unshift(nextScope);
|
|
236
|
+
visit(node.body);
|
|
237
|
+
scopes.shift();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
case "BlockStatement":
|
|
241
|
+
scopes.unshift(/* @__PURE__ */ new Set());
|
|
242
|
+
for (const statement of node.body ?? []) visit(statement);
|
|
243
|
+
scopes.shift();
|
|
244
|
+
break;
|
|
245
|
+
default: break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
visit(ast);
|
|
249
|
+
return collected;
|
|
250
|
+
}
|
|
251
|
+
function collectWithBabel(template) {
|
|
252
|
+
const templateExpressions = extractTemplateExpressions(template);
|
|
253
|
+
if (!templateExpressions.length) return [];
|
|
254
|
+
const loopAliases = collectLoopScopeAliases(template);
|
|
255
|
+
const keys = /* @__PURE__ */ new Set();
|
|
256
|
+
for (const expression of templateExpressions) {
|
|
257
|
+
const identifiers = collectIdentifiersFromExpression(expression);
|
|
258
|
+
for (const identifier of identifiers) if (!loopAliases.has(identifier)) keys.add(identifier);
|
|
259
|
+
}
|
|
260
|
+
return [...keys].sort((a, b) => a.localeCompare(b));
|
|
261
|
+
}
|
|
262
|
+
function collectWithOxc(template) {
|
|
263
|
+
const templateExpressions = extractTemplateExpressions(template);
|
|
264
|
+
if (!templateExpressions.length) return [];
|
|
265
|
+
const loopAliases = collectLoopScopeAliases(template);
|
|
266
|
+
const keys = /* @__PURE__ */ new Set();
|
|
267
|
+
for (const expression of templateExpressions) {
|
|
268
|
+
const identifiers = collectIdentifiersFromExpressionWithOxc(expression);
|
|
269
|
+
for (const identifier of identifiers) if (!loopAliases.has(identifier)) keys.add(identifier);
|
|
270
|
+
}
|
|
271
|
+
return [...keys].sort((a, b) => a.localeCompare(b));
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 从编译后的 WXML 模板提取渲染相关的顶层 key。
|
|
275
|
+
*
|
|
276
|
+
* 根据 AST 引擎从编译后的 WXML 模板提取渲染相关的顶层 key。
|
|
277
|
+
*/
|
|
278
|
+
function collectSetDataPickKeysFromTemplateCode(template, options) {
|
|
279
|
+
const engine = options?.astEngine ?? "babel";
|
|
280
|
+
try {
|
|
281
|
+
return engine === "oxc" ? collectWithOxc(template) : collectWithBabel(template);
|
|
282
|
+
} catch {
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
//#endregion
|
|
287
|
+
export { collectSetDataPickKeysFromTemplateCode };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weapp-vite/ast",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "6.
|
|
4
|
+
"version": "6.9.0",
|
|
5
5
|
"description": "weapp-vite 共享 AST 分析工具包,统一 Babel/Oxc 解析与常用分析操作",
|
|
6
6
|
"author": "ice breaker <1324318532@qq.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -32,6 +32,18 @@
|
|
|
32
32
|
"types": "./dist/babel.d.mts",
|
|
33
33
|
"import": "./dist/babel.mjs"
|
|
34
34
|
},
|
|
35
|
+
"./babelCore": {
|
|
36
|
+
"types": "./dist/babelCore.d.mts",
|
|
37
|
+
"import": "./dist/babelCore.mjs"
|
|
38
|
+
},
|
|
39
|
+
"./babelTraverse": {
|
|
40
|
+
"types": "./dist/babelTraverse.d.mts",
|
|
41
|
+
"import": "./dist/babelTraverse.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./babelTypes": {
|
|
44
|
+
"types": "./dist/babelTypes.d.mts",
|
|
45
|
+
"import": "./dist/babelTypes.mjs"
|
|
46
|
+
},
|
|
35
47
|
"./babelNodes": {
|
|
36
48
|
"types": "./dist/babelNodes.d.mts",
|
|
37
49
|
"import": "./dist/babelNodes.mjs"
|
|
@@ -44,10 +56,15 @@
|
|
|
44
56
|
"types": "./dist/types.d.mts",
|
|
45
57
|
"import": "./dist/types.mjs"
|
|
46
58
|
},
|
|
59
|
+
"./package.json": "./package.json",
|
|
47
60
|
"./operations/platformApi": {
|
|
48
61
|
"types": "./dist/operations/platformApi.d.mts",
|
|
49
62
|
"import": "./dist/operations/platformApi.mjs"
|
|
50
63
|
},
|
|
64
|
+
"./operations/onPageScroll": {
|
|
65
|
+
"types": "./dist/operations/onPageScroll.d.mts",
|
|
66
|
+
"import": "./dist/operations/onPageScroll.mjs"
|
|
67
|
+
},
|
|
51
68
|
"./operations/componentProps": {
|
|
52
69
|
"types": "./dist/operations/componentProps.d.mts",
|
|
53
70
|
"import": "./dist/operations/componentProps.mjs"
|
|
@@ -67,21 +84,30 @@
|
|
|
67
84
|
"./operations/scriptSetupImports": {
|
|
68
85
|
"types": "./dist/operations/scriptSetupImports.d.mts",
|
|
69
86
|
"import": "./dist/operations/scriptSetupImports.mjs"
|
|
87
|
+
},
|
|
88
|
+
"./operations/setDataPick": {
|
|
89
|
+
"types": "./dist/operations/setDataPick.d.mts",
|
|
90
|
+
"import": "./dist/operations/setDataPick.mjs"
|
|
70
91
|
}
|
|
71
92
|
},
|
|
72
93
|
"main": "./dist/index.mjs",
|
|
73
94
|
"module": "./dist/index.mjs",
|
|
74
95
|
"types": "./dist/index.d.mts",
|
|
75
96
|
"files": [
|
|
97
|
+
"README.md",
|
|
76
98
|
"dist"
|
|
77
99
|
],
|
|
100
|
+
"engines": {
|
|
101
|
+
"node": ">=20"
|
|
102
|
+
},
|
|
78
103
|
"dependencies": {
|
|
104
|
+
"@babel/core": "^7.29.0",
|
|
79
105
|
"@babel/generator": "^7.29.1",
|
|
80
106
|
"@babel/parser": "^7.29.0",
|
|
81
107
|
"@babel/traverse": "^7.29.0",
|
|
82
108
|
"@babel/types": "^7.29.0",
|
|
83
|
-
"@oxc-project/types": "^0.
|
|
84
|
-
"oxc-parser": "^0.
|
|
109
|
+
"@oxc-project/types": "^0.120.0",
|
|
110
|
+
"oxc-parser": "^0.120.0",
|
|
85
111
|
"oxc-walker": "^0.7.0"
|
|
86
112
|
},
|
|
87
113
|
"publishConfig": {
|
|
@@ -91,9 +117,10 @@
|
|
|
91
117
|
"scripts": {
|
|
92
118
|
"dev": "tsdown -w",
|
|
93
119
|
"build": "tsdown",
|
|
94
|
-
"
|
|
95
|
-
"test
|
|
96
|
-
"
|
|
120
|
+
"check:release": "pnpm build && pnpm typecheck && pnpm test && npm pack --dry-run . --cache ../../.cache/npm",
|
|
121
|
+
"test": "vitest run --config ./vitest.config.ts",
|
|
122
|
+
"test:dev": "vitest --config ./vitest.config.ts",
|
|
123
|
+
"typecheck": "tsc --noEmit -p ./tsconfig.json",
|
|
97
124
|
"release": "pnpm publish",
|
|
98
125
|
"lint": "eslint .",
|
|
99
126
|
"lint:fix": "eslint . --fix"
|