@weapp-vite/ast 6.8.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/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/babel.d.mts +21 -0
- package/dist/babel.mjs +64 -0
- package/dist/babelNodes.d.mts +10 -0
- package/dist/babelNodes.mjs +54 -0
- package/dist/engine-DHqNPCDA.mjs +37 -0
- package/dist/engine.d.mts +13 -0
- package/dist/engine.mjs +2 -0
- package/dist/index.d.mts +32 -0
- package/dist/index.mjs +10 -0
- package/dist/operations/componentProps.d.mts +12 -0
- package/dist/operations/componentProps.mjs +170 -0
- package/dist/operations/featureFlags.d.mts +14 -0
- package/dist/operations/featureFlags.mjs +97 -0
- package/dist/operations/jsxAutoComponents.d.mts +36 -0
- package/dist/operations/jsxAutoComponents.mjs +305 -0
- package/dist/operations/platformApi.d.mts +13 -0
- package/dist/operations/platformApi.mjs +35 -0
- package/dist/operations/require.d.mts +24 -0
- package/dist/operations/require.mjs +54 -0
- package/dist/operations/scriptSetupImports.d.mts +17 -0
- package/dist/operations/scriptSetupImports.mjs +80 -0
- package/dist/types.d.mts +24 -0
- package/dist/types.mjs +1 -0
- package/package.json +101 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AstEngineName } from "../types.mjs";
|
|
2
|
+
import * as t from "@babel/types";
|
|
3
|
+
import { Expression, ObjectExpression } from "@babel/types";
|
|
4
|
+
|
|
5
|
+
//#region src/operations/jsxAutoComponents.d.ts
|
|
6
|
+
interface JsxImportedComponent {
|
|
7
|
+
localName: string;
|
|
8
|
+
importSource: string;
|
|
9
|
+
importedName?: string;
|
|
10
|
+
kind: 'default' | 'named';
|
|
11
|
+
}
|
|
12
|
+
interface JsxAutoComponentContext {
|
|
13
|
+
templateTags: Set<string>;
|
|
14
|
+
importedComponents: JsxImportedComponent[];
|
|
15
|
+
}
|
|
16
|
+
interface JsxAutoComponentAnalysisOptions {
|
|
17
|
+
astEngine?: AstEngineName;
|
|
18
|
+
isCollectableTag: (tag: string) => boolean;
|
|
19
|
+
isDefineComponentSource?: (source: string) => boolean;
|
|
20
|
+
resolveBabelComponentExpression?: (declaration: t.Declaration | t.Expression | null, defineComponentDecls: Map<string, ObjectExpression>, defineComponentAliases: Set<string>) => Expression | null;
|
|
21
|
+
resolveBabelRenderExpression?: (componentExpr: Expression) => Expression | null;
|
|
22
|
+
}
|
|
23
|
+
interface JsxBabelModuleAnalysisOptions {
|
|
24
|
+
isDefineComponentSource?: (source: string) => boolean;
|
|
25
|
+
resolveBabelComponentExpression?: (declaration: t.Declaration | t.Expression | null, defineComponentDecls: Map<string, ObjectExpression>, defineComponentAliases: Set<string>) => Expression | null;
|
|
26
|
+
}
|
|
27
|
+
declare function collectJsxImportedComponentsAndDefaultExportFromBabelAst(ast: t.File, options?: JsxBabelModuleAnalysisOptions): {
|
|
28
|
+
importedComponents: JsxImportedComponent[];
|
|
29
|
+
exportDefaultExpression: null;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* 从 JSX 源码中收集自动 usingComponents 所需的导入组件与模板标签。
|
|
33
|
+
*/
|
|
34
|
+
declare function collectJsxAutoComponentsFromCode(source: string, options: JsxAutoComponentAnalysisOptions): JsxAutoComponentContext;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { JsxAutoComponentAnalysisOptions, JsxAutoComponentContext, JsxBabelModuleAnalysisOptions, JsxImportedComponent, collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst };
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { BABEL_TS_MODULE_PARSER_OPTIONS, parse, traverse } from "../babel.mjs";
|
|
2
|
+
import { getObjectPropertyByKey, resolveRenderableExpression } from "../babelNodes.mjs";
|
|
3
|
+
import * as t from "@babel/types";
|
|
4
|
+
import { parseSync } from "oxc-parser";
|
|
5
|
+
import { walk } from "oxc-walker";
|
|
6
|
+
//#region src/operations/jsxAutoComponents.ts
|
|
7
|
+
function defaultIsDefineComponentSource(source) {
|
|
8
|
+
return source === "vue";
|
|
9
|
+
}
|
|
10
|
+
function defaultResolveBabelComponentExpression(declaration, defineComponentDecls, defineComponentAliases) {
|
|
11
|
+
if (!declaration) return null;
|
|
12
|
+
if (t.isObjectExpression(declaration)) return declaration;
|
|
13
|
+
if (t.isCallExpression(declaration) && t.isIdentifier(declaration.callee) && defineComponentAliases.has(declaration.callee.name)) {
|
|
14
|
+
const arg = declaration.arguments[0];
|
|
15
|
+
if (t.isObjectExpression(arg)) return arg;
|
|
16
|
+
if (t.isIdentifier(arg)) return defineComponentDecls.get(arg.name) ?? null;
|
|
17
|
+
}
|
|
18
|
+
if (t.isIdentifier(declaration)) return defineComponentDecls.get(declaration.name) ?? null;
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
function defaultResolveBabelRenderExpression(componentExpr) {
|
|
22
|
+
if (!t.isObjectExpression(componentExpr)) return null;
|
|
23
|
+
const renderNode = getObjectPropertyByKey(componentExpr, "render");
|
|
24
|
+
if (!renderNode) return null;
|
|
25
|
+
if (!t.isObjectMethod(renderNode) && !t.isObjectProperty(renderNode)) return null;
|
|
26
|
+
return resolveRenderableExpression(renderNode);
|
|
27
|
+
}
|
|
28
|
+
function collectJsxImportedComponentsAndDefaultExportFromBabelAst(ast, options = {}) {
|
|
29
|
+
const resolvedOptions = {
|
|
30
|
+
isDefineComponentSource: options.isDefineComponentSource ?? defaultIsDefineComponentSource,
|
|
31
|
+
resolveBabelComponentExpression: options.resolveBabelComponentExpression ?? defaultResolveBabelComponentExpression
|
|
32
|
+
};
|
|
33
|
+
const defineComponentAliases = new Set(["defineComponent", "_defineComponent"]);
|
|
34
|
+
const defineComponentDecls = /* @__PURE__ */ new Map();
|
|
35
|
+
const imports = /* @__PURE__ */ new Map();
|
|
36
|
+
let exportDefaultExpression = null;
|
|
37
|
+
traverse(ast, {
|
|
38
|
+
ImportDeclaration(path) {
|
|
39
|
+
const source = path.node.source.value;
|
|
40
|
+
if (resolvedOptions.isDefineComponentSource(source)) for (const specifier of path.node.specifiers) {
|
|
41
|
+
if (!t.isImportSpecifier(specifier)) continue;
|
|
42
|
+
if (!t.isIdentifier(specifier.imported, { name: "defineComponent" })) continue;
|
|
43
|
+
defineComponentAliases.add(specifier.local.name);
|
|
44
|
+
}
|
|
45
|
+
if (path.node.importKind === "type") return;
|
|
46
|
+
if (!t.isStringLiteral(path.node.source)) return;
|
|
47
|
+
const importSource = path.node.source.value;
|
|
48
|
+
for (const specifier of path.node.specifiers) {
|
|
49
|
+
if ("importKind" in specifier && specifier.importKind === "type") continue;
|
|
50
|
+
if (!("local" in specifier) || !t.isIdentifier(specifier.local)) continue;
|
|
51
|
+
const localName = specifier.local.name;
|
|
52
|
+
if (t.isImportDefaultSpecifier(specifier)) {
|
|
53
|
+
imports.set(localName, {
|
|
54
|
+
localName,
|
|
55
|
+
importSource,
|
|
56
|
+
importedName: "default",
|
|
57
|
+
kind: "default"
|
|
58
|
+
});
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (!t.isImportSpecifier(specifier)) continue;
|
|
62
|
+
const importedName = t.isIdentifier(specifier.imported) ? specifier.imported.name : t.isStringLiteral(specifier.imported) ? specifier.imported.value : void 0;
|
|
63
|
+
imports.set(localName, {
|
|
64
|
+
localName,
|
|
65
|
+
importSource,
|
|
66
|
+
importedName,
|
|
67
|
+
kind: "named"
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
VariableDeclarator(path) {
|
|
72
|
+
if (!t.isIdentifier(path.node.id) || !path.node.init) return;
|
|
73
|
+
if (t.isObjectExpression(path.node.init)) {
|
|
74
|
+
defineComponentDecls.set(path.node.id.name, t.cloneNode(path.node.init, true));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!t.isCallExpression(path.node.init)) return;
|
|
78
|
+
const callee = path.node.init.callee;
|
|
79
|
+
if (!t.isIdentifier(callee) || !defineComponentAliases.has(callee.name)) return;
|
|
80
|
+
const first = path.node.init.arguments[0];
|
|
81
|
+
if (t.isObjectExpression(first)) defineComponentDecls.set(path.node.id.name, t.cloneNode(first, true));
|
|
82
|
+
},
|
|
83
|
+
ExportDefaultDeclaration(path) {
|
|
84
|
+
const declaration = path.node.declaration;
|
|
85
|
+
if (t.isDeclaration(declaration)) return;
|
|
86
|
+
exportDefaultExpression = resolvedOptions.resolveBabelComponentExpression(declaration, defineComponentDecls, defineComponentAliases);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
importedComponents: [...imports.values()],
|
|
91
|
+
exportDefaultExpression
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function collectJsxTemplateTags(renderExpression, isCollectableTag) {
|
|
95
|
+
const tags = /* @__PURE__ */ new Set();
|
|
96
|
+
function walk(node) {
|
|
97
|
+
if (t.isJSXElement(node)) {
|
|
98
|
+
const { name } = node.openingElement;
|
|
99
|
+
if (!t.isJSXMemberExpression(name)) {
|
|
100
|
+
let tag = null;
|
|
101
|
+
if (t.isJSXIdentifier(name)) tag = name.name;
|
|
102
|
+
else if (t.isJSXNamespacedName(name)) tag = `${name.namespace.name}:${name.name.name}`;
|
|
103
|
+
if (tag && isCollectableTag(tag)) tags.add(tag);
|
|
104
|
+
}
|
|
105
|
+
for (const child of node.children) walk(child);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (t.isJSXFragment(node)) {
|
|
109
|
+
for (const child of node.children) walk(child);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (t.isJSXExpressionContainer(node) && !t.isJSXEmptyExpression(node.expression)) {
|
|
113
|
+
walk(node.expression);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (t.isConditionalExpression(node)) {
|
|
117
|
+
walk(node.consequent);
|
|
118
|
+
walk(node.alternate);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (t.isLogicalExpression(node)) {
|
|
122
|
+
walk(node.left);
|
|
123
|
+
walk(node.right);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (t.isCallExpression(node)) {
|
|
127
|
+
for (const arg of node.arguments) if (t.isExpression(arg)) walk(arg);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (t.isArrowFunctionExpression(node) || t.isFunctionExpression(node)) {
|
|
131
|
+
if (t.isBlockStatement(node.body)) {
|
|
132
|
+
for (const stmt of node.body.body) if (t.isReturnStatement(stmt) && stmt.argument) walk(stmt.argument);
|
|
133
|
+
} else walk(node.body);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (t.isArrayExpression(node)) {
|
|
137
|
+
for (const element of node.elements) if (element && t.isExpression(element)) walk(element);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (t.isParenthesizedExpression(node) || t.isTSAsExpression(node) || t.isTSSatisfiesExpression(node) || t.isTSNonNullExpression(node)) walk(node.expression);
|
|
141
|
+
}
|
|
142
|
+
walk(renderExpression);
|
|
143
|
+
return tags;
|
|
144
|
+
}
|
|
145
|
+
function unwrapOxcExpression(node) {
|
|
146
|
+
let current = node;
|
|
147
|
+
while (current && (current.type === "TSAsExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSNonNullExpression" || current.type === "ParenthesizedExpression")) current = current.expression;
|
|
148
|
+
return current;
|
|
149
|
+
}
|
|
150
|
+
function getOxcStaticPropertyName(node) {
|
|
151
|
+
const current = unwrapOxcExpression(node);
|
|
152
|
+
if (!current) return;
|
|
153
|
+
if (current.type === "Identifier") return current.name;
|
|
154
|
+
if (current.type === "StringLiteral") return current.value;
|
|
155
|
+
if (current.type === "Literal" && typeof current.value === "string") return current.value;
|
|
156
|
+
}
|
|
157
|
+
function resolveOxcComponentExpression(declaration, defineComponentDecls, defineComponentAliases) {
|
|
158
|
+
const normalized = unwrapOxcExpression(declaration);
|
|
159
|
+
if (!normalized) return null;
|
|
160
|
+
if (normalized.type === "ObjectExpression") return normalized;
|
|
161
|
+
if (normalized.type === "Identifier") return defineComponentDecls.get(normalized.name) ?? null;
|
|
162
|
+
if (normalized.type === "CallExpression" && normalized.callee?.type === "Identifier" && defineComponentAliases.has(normalized.callee.name)) {
|
|
163
|
+
const first = normalized.arguments?.[0];
|
|
164
|
+
const unwrappedFirst = unwrapOxcExpression(first);
|
|
165
|
+
if (unwrappedFirst?.type === "ObjectExpression") return unwrappedFirst;
|
|
166
|
+
if (unwrappedFirst?.type === "Identifier") return defineComponentDecls.get(unwrappedFirst.name) ?? null;
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
function resolveOxcRenderExpression(componentExpr) {
|
|
171
|
+
if (componentExpr?.type !== "ObjectExpression") return null;
|
|
172
|
+
let renderProperty = null;
|
|
173
|
+
for (const property of componentExpr.properties ?? []) if (getOxcStaticPropertyName(property?.key) === "render") {
|
|
174
|
+
renderProperty = property;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (!renderProperty) return null;
|
|
178
|
+
const normalizedValue = unwrapOxcExpression(renderProperty.value ?? renderProperty);
|
|
179
|
+
if (!normalizedValue || normalizedValue.type !== "FunctionExpression" && normalizedValue.type !== "ArrowFunctionExpression") return null;
|
|
180
|
+
if (normalizedValue.body?.type === "BlockStatement") {
|
|
181
|
+
for (const statement of normalizedValue.body.body ?? []) if (statement.type === "ReturnStatement" && statement.argument) return unwrapOxcExpression(statement.argument);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
return unwrapOxcExpression(normalizedValue.body);
|
|
185
|
+
}
|
|
186
|
+
function collectJsxTemplateTagsFromOxc(renderExpression, isCollectableTag) {
|
|
187
|
+
const tags = /* @__PURE__ */ new Set();
|
|
188
|
+
walk(renderExpression, { enter(node) {
|
|
189
|
+
if (node.type === "JSXElement") {
|
|
190
|
+
const name = node.openingElement?.name;
|
|
191
|
+
if (!name || name.type === "JSXMemberExpression") return;
|
|
192
|
+
let tag = null;
|
|
193
|
+
if (name.type === "JSXIdentifier") tag = name.name;
|
|
194
|
+
else if (name.type === "JSXNamespacedName") tag = `${name.namespace.name}:${name.name.name}`;
|
|
195
|
+
if (tag && isCollectableTag(tag)) tags.add(tag);
|
|
196
|
+
}
|
|
197
|
+
} });
|
|
198
|
+
return tags;
|
|
199
|
+
}
|
|
200
|
+
function collectWithBabel(source, options) {
|
|
201
|
+
const { importedComponents, exportDefaultExpression } = collectJsxImportedComponentsAndDefaultExportFromBabelAst(parse(source, BABEL_TS_MODULE_PARSER_OPTIONS), options);
|
|
202
|
+
if (!exportDefaultExpression) return {
|
|
203
|
+
templateTags: /* @__PURE__ */ new Set(),
|
|
204
|
+
importedComponents
|
|
205
|
+
};
|
|
206
|
+
const renderExpression = options.resolveBabelRenderExpression(exportDefaultExpression);
|
|
207
|
+
if (!renderExpression) return {
|
|
208
|
+
templateTags: /* @__PURE__ */ new Set(),
|
|
209
|
+
importedComponents
|
|
210
|
+
};
|
|
211
|
+
return {
|
|
212
|
+
templateTags: collectJsxTemplateTags(renderExpression, options.isCollectableTag),
|
|
213
|
+
importedComponents
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function collectWithOxc(source, options) {
|
|
217
|
+
const ast = parseSync("inline.tsx", source).program;
|
|
218
|
+
const defineComponentAliases = new Set(["defineComponent", "_defineComponent"]);
|
|
219
|
+
const defineComponentDecls = /* @__PURE__ */ new Map();
|
|
220
|
+
const imports = /* @__PURE__ */ new Map();
|
|
221
|
+
let exportDefaultExpression = null;
|
|
222
|
+
for (const statement of ast.body ?? []) {
|
|
223
|
+
if (statement?.type === "ImportDeclaration") {
|
|
224
|
+
const importSource = statement.source?.value;
|
|
225
|
+
if (typeof importSource === "string" && options.isDefineComponentSource(importSource)) {
|
|
226
|
+
for (const specifier of statement.specifiers ?? []) if (specifier?.type === "ImportSpecifier" && specifier.imported?.type === "Identifier" && specifier.imported.name === "defineComponent" && specifier.local?.type === "Identifier") defineComponentAliases.add(specifier.local.name);
|
|
227
|
+
}
|
|
228
|
+
if (statement.importKind === "type" || typeof importSource !== "string") continue;
|
|
229
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
230
|
+
if (specifier?.importKind === "type" || specifier?.local?.type !== "Identifier") continue;
|
|
231
|
+
const localName = specifier.local.name;
|
|
232
|
+
if (specifier.type === "ImportDefaultSpecifier") {
|
|
233
|
+
imports.set(localName, {
|
|
234
|
+
localName,
|
|
235
|
+
importSource,
|
|
236
|
+
importedName: "default",
|
|
237
|
+
kind: "default"
|
|
238
|
+
});
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (specifier.type !== "ImportSpecifier") continue;
|
|
242
|
+
const importedName = specifier.imported?.type === "Identifier" ? specifier.imported.name : specifier.imported?.type === "StringLiteral" ? specifier.imported.value : void 0;
|
|
243
|
+
imports.set(localName, {
|
|
244
|
+
localName,
|
|
245
|
+
importSource,
|
|
246
|
+
importedName,
|
|
247
|
+
kind: "named"
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (statement?.type === "VariableDeclaration") {
|
|
253
|
+
for (const declaration of statement.declarations ?? []) {
|
|
254
|
+
if (declaration?.id?.type !== "Identifier" || !declaration.init) continue;
|
|
255
|
+
const init = unwrapOxcExpression(declaration.init);
|
|
256
|
+
if (init?.type === "ObjectExpression") {
|
|
257
|
+
defineComponentDecls.set(declaration.id.name, init);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (init?.type === "CallExpression" && init.callee?.type === "Identifier" && defineComponentAliases.has(init.callee.name)) {
|
|
261
|
+
const first = unwrapOxcExpression(init.arguments?.[0]);
|
|
262
|
+
if (first?.type === "ObjectExpression") defineComponentDecls.set(declaration.id.name, first);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (statement?.type === "ExportDefaultDeclaration") exportDefaultExpression = resolveOxcComponentExpression(statement.declaration, defineComponentDecls, defineComponentAliases);
|
|
268
|
+
}
|
|
269
|
+
const importedComponents = [...imports.values()];
|
|
270
|
+
if (!exportDefaultExpression) return {
|
|
271
|
+
templateTags: /* @__PURE__ */ new Set(),
|
|
272
|
+
importedComponents
|
|
273
|
+
};
|
|
274
|
+
const renderExpression = resolveOxcRenderExpression(exportDefaultExpression);
|
|
275
|
+
if (!renderExpression) return {
|
|
276
|
+
templateTags: /* @__PURE__ */ new Set(),
|
|
277
|
+
importedComponents
|
|
278
|
+
};
|
|
279
|
+
return {
|
|
280
|
+
templateTags: collectJsxTemplateTagsFromOxc(renderExpression, options.isCollectableTag),
|
|
281
|
+
importedComponents
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* 从 JSX 源码中收集自动 usingComponents 所需的导入组件与模板标签。
|
|
286
|
+
*/
|
|
287
|
+
function collectJsxAutoComponentsFromCode(source, options) {
|
|
288
|
+
const normalizedOptions = {
|
|
289
|
+
astEngine: options.astEngine ?? "babel",
|
|
290
|
+
isCollectableTag: options.isCollectableTag,
|
|
291
|
+
isDefineComponentSource: options.isDefineComponentSource ?? defaultIsDefineComponentSource,
|
|
292
|
+
resolveBabelComponentExpression: options.resolveBabelComponentExpression ?? defaultResolveBabelComponentExpression,
|
|
293
|
+
resolveBabelRenderExpression: options.resolveBabelRenderExpression ?? defaultResolveBabelRenderExpression
|
|
294
|
+
};
|
|
295
|
+
try {
|
|
296
|
+
return normalizedOptions.astEngine === "oxc" ? collectWithOxc(source, normalizedOptions) : collectWithBabel(source, normalizedOptions);
|
|
297
|
+
} catch {
|
|
298
|
+
return {
|
|
299
|
+
templateTags: /* @__PURE__ */ new Set(),
|
|
300
|
+
importedComponents: []
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
//#endregion
|
|
305
|
+
export { collectJsxAutoComponentsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AstEngineName, AstParserLike } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/operations/platformApi.d.ts
|
|
4
|
+
declare const platformApiIdentifiers: Set<string>;
|
|
5
|
+
/**
|
|
6
|
+
* 使用统一 AST 入口做平台 API 访问预判。
|
|
7
|
+
*/
|
|
8
|
+
declare function mayContainPlatformApiAccess(code: string, options?: {
|
|
9
|
+
engine?: AstEngineName;
|
|
10
|
+
parserLike?: AstParserLike;
|
|
11
|
+
}): boolean;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { mayContainPlatformApiAccess, platformApiIdentifiers };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { t as parseJsLikeWithEngine } from "../engine-DHqNPCDA.mjs";
|
|
2
|
+
import { walk } from "oxc-walker";
|
|
3
|
+
//#region src/operations/platformApi.ts
|
|
4
|
+
const platformApiIdentifiers = new Set([
|
|
5
|
+
"wx",
|
|
6
|
+
"my",
|
|
7
|
+
"tt",
|
|
8
|
+
"swan",
|
|
9
|
+
"jd",
|
|
10
|
+
"xhs"
|
|
11
|
+
]);
|
|
12
|
+
/**
|
|
13
|
+
* 使用统一 AST 入口做平台 API 访问预判。
|
|
14
|
+
*/
|
|
15
|
+
function mayContainPlatformApiAccess(code, options) {
|
|
16
|
+
const engine = options?.engine ?? "babel";
|
|
17
|
+
if (engine !== "oxc") return true;
|
|
18
|
+
try {
|
|
19
|
+
const ast = parseJsLikeWithEngine(code, {
|
|
20
|
+
engine,
|
|
21
|
+
filename: "inline.ts",
|
|
22
|
+
parserLike: options?.parserLike
|
|
23
|
+
});
|
|
24
|
+
let found = false;
|
|
25
|
+
walk(ast, { enter(node) {
|
|
26
|
+
if (found) return;
|
|
27
|
+
if (node.type === "MemberExpression" && node.object.type === "Identifier" && platformApiIdentifiers.has(node.object.name)) found = true;
|
|
28
|
+
} });
|
|
29
|
+
return found;
|
|
30
|
+
} catch {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { mayContainPlatformApiAccess, platformApiIdentifiers };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AstEngineName, AstParserLike } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/operations/require.d.ts
|
|
4
|
+
interface RequireToken {
|
|
5
|
+
start: number;
|
|
6
|
+
end: number;
|
|
7
|
+
value: string;
|
|
8
|
+
async?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 收集 `require.async()` 依赖字面量。
|
|
12
|
+
*/
|
|
13
|
+
declare function collectRequireTokens(ast: unknown): {
|
|
14
|
+
requireTokens: RequireToken[];
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* 使用统一 AST 入口预判是否存在可静态分析的 `require("...")` / ``require(`...`)``。
|
|
18
|
+
*/
|
|
19
|
+
declare function mayContainStaticRequireLiteral(code: string, options?: {
|
|
20
|
+
engine?: AstEngineName;
|
|
21
|
+
parserLike?: AstParserLike;
|
|
22
|
+
}): boolean;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { RequireToken, collectRequireTokens, mayContainStaticRequireLiteral };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { t as parseJsLikeWithEngine } from "../engine-DHqNPCDA.mjs";
|
|
2
|
+
import { walk } from "oxc-walker";
|
|
3
|
+
//#region src/operations/require.ts
|
|
4
|
+
function getStaticRequireLiteralValue(node) {
|
|
5
|
+
if (!node) return null;
|
|
6
|
+
if (node.type === "Literal" || node.type === "StringLiteral") return typeof node.value === "string" ? node.value : null;
|
|
7
|
+
if (node.type === "TemplateLiteral" && Array.isArray(node.expressions) && node.expressions.length === 0 && Array.isArray(node.quasis) && node.quasis.length === 1) return node.quasis[0]?.value?.cooked ?? node.quasis[0]?.value?.raw ?? null;
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 收集 `require.async()` 依赖字面量。
|
|
12
|
+
*/
|
|
13
|
+
function collectRequireTokens(ast) {
|
|
14
|
+
const requireTokens = [];
|
|
15
|
+
walk(ast, { enter(node) {
|
|
16
|
+
if (node.type === "CallExpression") {
|
|
17
|
+
if (node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && node.callee.object.name === "require" && node.callee.property.type === "Identifier" && node.callee.property.name === "async") {
|
|
18
|
+
const argv0 = node.arguments[0];
|
|
19
|
+
if (argv0 && argv0.type === "Literal" && typeof argv0.value === "string") requireTokens.push({
|
|
20
|
+
start: argv0.start,
|
|
21
|
+
end: argv0.end,
|
|
22
|
+
value: argv0.value,
|
|
23
|
+
async: true
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} });
|
|
28
|
+
return { requireTokens };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 使用统一 AST 入口预判是否存在可静态分析的 `require("...")` / ``require(`...`)``。
|
|
32
|
+
*/
|
|
33
|
+
function mayContainStaticRequireLiteral(code, options) {
|
|
34
|
+
const engine = options?.engine ?? "babel";
|
|
35
|
+
if (engine !== "oxc") return true;
|
|
36
|
+
try {
|
|
37
|
+
const ast = parseJsLikeWithEngine(code, {
|
|
38
|
+
engine,
|
|
39
|
+
filename: "inline.ts",
|
|
40
|
+
parserLike: options?.parserLike
|
|
41
|
+
});
|
|
42
|
+
let found = false;
|
|
43
|
+
walk(ast, { enter(node) {
|
|
44
|
+
if (found || node.type !== "CallExpression") return;
|
|
45
|
+
if (node.callee.type !== "Identifier" || node.callee.name !== "require") return;
|
|
46
|
+
if (typeof getStaticRequireLiteralValue(node.arguments?.[0]) === "string") found = true;
|
|
47
|
+
} });
|
|
48
|
+
return found;
|
|
49
|
+
} catch {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { collectRequireTokens, mayContainStaticRequireLiteral };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AstEngineName } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/operations/scriptSetupImports.d.ts
|
|
4
|
+
interface ScriptSetupImport {
|
|
5
|
+
localName: string;
|
|
6
|
+
importSource: string;
|
|
7
|
+
importedName?: string;
|
|
8
|
+
kind: 'default' | 'named';
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 收集 `<script setup>` 中会参与自动 usingComponents 的导入声明。
|
|
12
|
+
*/
|
|
13
|
+
declare function collectScriptSetupImportsFromCode(scriptSetup: string, templateComponentNames: Set<string>, options?: {
|
|
14
|
+
astEngine?: AstEngineName;
|
|
15
|
+
}): ScriptSetupImport[];
|
|
16
|
+
//#endregion
|
|
17
|
+
export { ScriptSetupImport, collectScriptSetupImportsFromCode };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { BABEL_TS_MODULE_PARSER_OPTIONS, parse } from "../babel.mjs";
|
|
2
|
+
import { t as parseJsLikeWithEngine } from "../engine-DHqNPCDA.mjs";
|
|
3
|
+
//#region src/operations/scriptSetupImports.ts
|
|
4
|
+
function collectWithOxc(scriptSetup, templateComponentNames) {
|
|
5
|
+
const results = [];
|
|
6
|
+
const ast = parseJsLikeWithEngine(scriptSetup, {
|
|
7
|
+
engine: "oxc",
|
|
8
|
+
filename: "inline.ts"
|
|
9
|
+
});
|
|
10
|
+
for (const node of ast.body ?? []) {
|
|
11
|
+
if (node?.type !== "ImportDeclaration" || node.importKind === "type") continue;
|
|
12
|
+
const importSource = node.source?.value;
|
|
13
|
+
if (typeof importSource !== "string") continue;
|
|
14
|
+
for (const specifier of node.specifiers ?? []) {
|
|
15
|
+
if (specifier?.importKind === "type" || specifier?.local?.type !== "Identifier") continue;
|
|
16
|
+
const localName = specifier.local.name;
|
|
17
|
+
if (!templateComponentNames.has(localName)) continue;
|
|
18
|
+
if (specifier.type === "ImportDefaultSpecifier") results.push({
|
|
19
|
+
localName,
|
|
20
|
+
importSource,
|
|
21
|
+
importedName: "default",
|
|
22
|
+
kind: "default"
|
|
23
|
+
});
|
|
24
|
+
else if (specifier.type === "ImportSpecifier") {
|
|
25
|
+
const importedName = specifier.imported?.type === "Identifier" ? specifier.imported.name : specifier.imported?.type === "StringLiteral" ? specifier.imported.value : void 0;
|
|
26
|
+
results.push({
|
|
27
|
+
localName,
|
|
28
|
+
importSource,
|
|
29
|
+
importedName,
|
|
30
|
+
kind: "named"
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return results;
|
|
36
|
+
}
|
|
37
|
+
function collectWithBabel(scriptSetup, templateComponentNames) {
|
|
38
|
+
const results = [];
|
|
39
|
+
const ast = parse(scriptSetup, BABEL_TS_MODULE_PARSER_OPTIONS);
|
|
40
|
+
for (const node of ast.program.body) {
|
|
41
|
+
if (node.type !== "ImportDeclaration") continue;
|
|
42
|
+
if (node.importKind === "type") continue;
|
|
43
|
+
const importSource = node.source.value;
|
|
44
|
+
for (const specifier of node.specifiers) {
|
|
45
|
+
if (specifier.importKind === "type") continue;
|
|
46
|
+
const localName = specifier.local?.name;
|
|
47
|
+
if (!localName || !templateComponentNames.has(localName)) continue;
|
|
48
|
+
if (specifier.type === "ImportDefaultSpecifier") results.push({
|
|
49
|
+
localName,
|
|
50
|
+
importSource,
|
|
51
|
+
importedName: "default",
|
|
52
|
+
kind: "default"
|
|
53
|
+
});
|
|
54
|
+
else if (specifier.type === "ImportSpecifier") {
|
|
55
|
+
const imported = specifier.imported;
|
|
56
|
+
const importedName = imported?.type === "Identifier" ? imported.name : imported?.type === "StringLiteral" ? imported.value : void 0;
|
|
57
|
+
results.push({
|
|
58
|
+
localName,
|
|
59
|
+
importSource,
|
|
60
|
+
importedName,
|
|
61
|
+
kind: "named"
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return results;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 收集 `<script setup>` 中会参与自动 usingComponents 的导入声明。
|
|
70
|
+
*/
|
|
71
|
+
function collectScriptSetupImportsFromCode(scriptSetup, templateComponentNames, options) {
|
|
72
|
+
const engine = options?.astEngine ?? "babel";
|
|
73
|
+
try {
|
|
74
|
+
return engine === "oxc" ? collectWithOxc(scriptSetup, templateComponentNames) : collectWithBabel(scriptSetup, templateComponentNames);
|
|
75
|
+
} catch {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { collectScriptSetupImportsFromCode };
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* AST 引擎名称。
|
|
4
|
+
*/
|
|
5
|
+
type AstEngineName = 'babel' | 'oxc';
|
|
6
|
+
/**
|
|
7
|
+
* AST 相关配置。
|
|
8
|
+
*/
|
|
9
|
+
interface WeappAstConfig {
|
|
10
|
+
/**
|
|
11
|
+
* AST 引擎。
|
|
12
|
+
* - `babel`: 默认兼容模式
|
|
13
|
+
* - `oxc`: 优先使用 Oxc 做解析/分析
|
|
14
|
+
*/
|
|
15
|
+
engine?: AstEngineName;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 兼容 Rolldown/Vite `this.parse` 形状的解析器。
|
|
19
|
+
*/
|
|
20
|
+
interface AstParserLike {
|
|
21
|
+
parse?: (input: string, options?: unknown) => unknown;
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { AstEngineName, AstParserLike, WeappAstConfig };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|