transone-cli 0.1.0 → 0.2.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 +7 -1
- package/dist/build-mp-kcnx989m.js +2795 -0
- package/dist/build-mp-kcnx989m.js.map +23 -0
- package/dist/cli.js +1 -1
- package/dist/create.d.ts +2 -2
- package/dist/{index-30n2h2ep.js → index-5bdznb52.js} +200 -18
- package/dist/index-5bdznb52.js.map +23 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/mp/analyze.d.ts +15 -0
- package/dist/mp/binding.d.ts +21 -0
- package/dist/mp/build-mp.d.ts +7 -0
- package/dist/mp/compile.d.ts +13 -0
- package/dist/mp/dialect.d.ts +49 -0
- package/dist/mp/errors.d.ts +6 -0
- package/dist/mp/fold.d.ts +15 -0
- package/dist/mp/inline.d.ts +3 -0
- package/dist/mp/jsgen.d.ts +7 -0
- package/dist/mp/methods.d.ts +14 -0
- package/dist/mp/state.d.ts +6 -0
- package/dist/mp/styles.d.ts +15 -0
- package/dist/mp/ts-loader.d.ts +6 -0
- package/dist/mp/types.d.ts +64 -0
- package/dist/mp/wxml.d.ts +31 -0
- package/dist/project-ybacfze8.js.map +1 -1
- package/dist/project.d.ts +1 -1
- package/dist/target/mp-target.d.ts +24 -0
- package/dist/target/registry.d.ts +2 -2
- package/dist/types.d.ts +44 -0
- package/package.json +3 -2
- package/dist/index-30n2h2ep.js.map +0 -21
|
@@ -0,0 +1,2795 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__require
|
|
4
|
+
} from "./index-yb2wsc7f.js";
|
|
5
|
+
|
|
6
|
+
// src/mp/build-mp.ts
|
|
7
|
+
import { cp, mkdir, readdir, rm, writeFile } from "fs/promises";
|
|
8
|
+
import { existsSync as existsSync2 } from "fs";
|
|
9
|
+
import { basename, dirname as dirname3, join as join3, relative, resolve as resolve2 } from "path";
|
|
10
|
+
|
|
11
|
+
// src/mp/ts-loader.ts
|
|
12
|
+
var tsModule = null;
|
|
13
|
+
async function loadTypescript() {
|
|
14
|
+
if (tsModule) {
|
|
15
|
+
return tsModule;
|
|
16
|
+
}
|
|
17
|
+
tsModule = await import("typescript");
|
|
18
|
+
return tsModule;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/mp/analyze.ts
|
|
22
|
+
import { existsSync, readFileSync } from "fs";
|
|
23
|
+
import { dirname, join, resolve } from "path";
|
|
24
|
+
|
|
25
|
+
// src/mp/errors.ts
|
|
26
|
+
class MpCompileError extends Error {
|
|
27
|
+
file;
|
|
28
|
+
constructor(file, message) {
|
|
29
|
+
super(`${message} (${file})`);
|
|
30
|
+
this.name = "MpCompileError";
|
|
31
|
+
this.file = file;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function mpError(file, message) {
|
|
35
|
+
return new MpCompileError(file, message);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/mp/fold.ts
|
|
39
|
+
function foldExpression(ts, node, consts, seen = new Set) {
|
|
40
|
+
node = unwrapParentheses(ts, node);
|
|
41
|
+
if (ts.isStringLiteral(node)) {
|
|
42
|
+
return node.text;
|
|
43
|
+
}
|
|
44
|
+
if (ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
45
|
+
if (node.text.includes("{{")) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
return node.text;
|
|
49
|
+
}
|
|
50
|
+
if (ts.isNumericLiteral(node)) {
|
|
51
|
+
return Number(node.text);
|
|
52
|
+
}
|
|
53
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (node.kind === ts.SyntaxKind.NullKeyword) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (ts.isPrefixUnaryExpression(node)) {
|
|
63
|
+
const operand = foldExpression(ts, node.operand, consts, seen);
|
|
64
|
+
if (operand === undefined) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (node.operator === ts.SyntaxKind.MinusToken) {
|
|
68
|
+
return typeof operand === "number" ? -operand : undefined;
|
|
69
|
+
}
|
|
70
|
+
if (node.operator === ts.SyntaxKind.PlusToken) {
|
|
71
|
+
return typeof operand === "number" ? operand : undefined;
|
|
72
|
+
}
|
|
73
|
+
if (node.operator === ts.SyntaxKind.ExclamationToken) {
|
|
74
|
+
return !operand;
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (ts.isBinaryExpression(node)) {
|
|
79
|
+
const left = foldExpression(ts, node.left, consts, seen);
|
|
80
|
+
const right = foldExpression(ts, node.right, consts, seen);
|
|
81
|
+
if (left === undefined || right === undefined) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
return foldBinary(ts, node.operatorToken.kind, left, right);
|
|
85
|
+
}
|
|
86
|
+
if (ts.isConditionalExpression(node)) {
|
|
87
|
+
const condition = foldExpression(ts, node.condition, consts, seen);
|
|
88
|
+
if (typeof condition !== "boolean") {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
return condition ? foldExpression(ts, node.whenTrue, consts, seen) : foldExpression(ts, node.whenFalse, consts, seen);
|
|
92
|
+
}
|
|
93
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
94
|
+
const items = [];
|
|
95
|
+
for (const element of node.elements) {
|
|
96
|
+
if (ts.isSpreadElement(element)) {
|
|
97
|
+
const spread = foldExpression(ts, element.expression, consts, seen);
|
|
98
|
+
if (!Array.isArray(spread)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
items.push(...spread);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const value = foldExpression(ts, element, consts, seen);
|
|
105
|
+
if (value === undefined) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
items.push(value);
|
|
109
|
+
}
|
|
110
|
+
return items;
|
|
111
|
+
}
|
|
112
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
113
|
+
const result = {};
|
|
114
|
+
for (const property of node.properties) {
|
|
115
|
+
if (ts.isPropertyAssignment(property)) {
|
|
116
|
+
const key = propertyNameText(ts, property.name);
|
|
117
|
+
const value = foldExpression(ts, property.initializer, consts, seen);
|
|
118
|
+
if (key === undefined || value === undefined) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
result[key] = value;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (ts.isShorthandPropertyAssignment(property) && ts.isIdentifier(property.name)) {
|
|
125
|
+
const initializer = consts.get(property.name.text);
|
|
126
|
+
if (!initializer) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const value = foldExpression(ts, initializer, consts, seen);
|
|
130
|
+
if (value === undefined) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
result[property.name.text] = value;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
if (ts.isIdentifier(node)) {
|
|
141
|
+
if (seen.has(node.text)) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const initializer = consts.get(node.text);
|
|
145
|
+
if (!initializer) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
seen.add(node.text);
|
|
149
|
+
const value = foldExpression(ts, initializer, consts, seen);
|
|
150
|
+
seen.delete(node.text);
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
154
|
+
const base = foldExpression(ts, node.expression, consts, seen);
|
|
155
|
+
if (base === undefined) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (Array.isArray(base)) {
|
|
159
|
+
if (node.name.text === "length") {
|
|
160
|
+
return base.length;
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (typeof base === "object" && base !== null) {
|
|
165
|
+
return base[node.name.text];
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (ts.isElementAccessExpression(node)) {
|
|
170
|
+
const base = foldExpression(ts, node.expression, consts, seen);
|
|
171
|
+
const index = foldExpression(ts, node.argumentExpression, consts, seen);
|
|
172
|
+
if (!Array.isArray(base) || typeof index !== "number") {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
return base[index];
|
|
176
|
+
}
|
|
177
|
+
if (ts.isTemplateExpression(node)) {
|
|
178
|
+
let result = "";
|
|
179
|
+
if (node.head.text !== "") {
|
|
180
|
+
result += node.head.text;
|
|
181
|
+
}
|
|
182
|
+
for (const span of node.templateSpans) {
|
|
183
|
+
const value = foldExpression(ts, span.expression, consts, seen);
|
|
184
|
+
if (value === undefined) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
result += String(value);
|
|
188
|
+
result += span.literal.text;
|
|
189
|
+
}
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
function foldBinary(ts, operator, left, right) {
|
|
195
|
+
switch (operator) {
|
|
196
|
+
case ts.SyntaxKind.PlusToken:
|
|
197
|
+
return `${left}${right}`;
|
|
198
|
+
case ts.SyntaxKind.MinusToken:
|
|
199
|
+
return left - right;
|
|
200
|
+
case ts.SyntaxKind.AsteriskToken:
|
|
201
|
+
return left * right;
|
|
202
|
+
case ts.SyntaxKind.SlashToken:
|
|
203
|
+
return left / right;
|
|
204
|
+
case ts.SyntaxKind.PercentToken:
|
|
205
|
+
return left % right;
|
|
206
|
+
case ts.SyntaxKind.EqualsEqualsEqualsToken:
|
|
207
|
+
return left === right;
|
|
208
|
+
case ts.SyntaxKind.ExclamationEqualsEqualsToken:
|
|
209
|
+
return left !== right;
|
|
210
|
+
case ts.SyntaxKind.LessThanToken:
|
|
211
|
+
return left < right;
|
|
212
|
+
case ts.SyntaxKind.LessThanEqualsToken:
|
|
213
|
+
return left <= right;
|
|
214
|
+
case ts.SyntaxKind.GreaterThanToken:
|
|
215
|
+
return left > right;
|
|
216
|
+
case ts.SyntaxKind.GreaterThanEqualsToken:
|
|
217
|
+
return left >= right;
|
|
218
|
+
case ts.SyntaxKind.AmpersandAmpersandToken:
|
|
219
|
+
return Boolean(left) && Boolean(right);
|
|
220
|
+
case ts.SyntaxKind.BarBarToken:
|
|
221
|
+
return Boolean(left) || Boolean(right);
|
|
222
|
+
default:
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function propertyNameText(ts, name) {
|
|
227
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) {
|
|
228
|
+
return name.text;
|
|
229
|
+
}
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
function unwrapParentheses(ts, node) {
|
|
233
|
+
let current = node;
|
|
234
|
+
while (ts.isParenthesizedExpression(current)) {
|
|
235
|
+
current = current.expression;
|
|
236
|
+
}
|
|
237
|
+
return current;
|
|
238
|
+
}
|
|
239
|
+
function isThisExpression(ts, node) {
|
|
240
|
+
return node.kind === ts.SyntaxKind.ThisKeyword;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/mp/analyze.ts
|
|
244
|
+
function readSource(context, filePath) {
|
|
245
|
+
const cached = context.files.get(filePath);
|
|
246
|
+
if (cached) {
|
|
247
|
+
return cached;
|
|
248
|
+
}
|
|
249
|
+
if (!existsSync(filePath)) {
|
|
250
|
+
throw mpError(filePath, "\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
251
|
+
}
|
|
252
|
+
const text = readFileSync(filePath, "utf8");
|
|
253
|
+
const source = context.ts.createSourceFile(filePath, text, context.ts.ScriptTarget.Latest, true, context.ts.ScriptKind.TS);
|
|
254
|
+
context.files.set(filePath, source);
|
|
255
|
+
return source;
|
|
256
|
+
}
|
|
257
|
+
function findRootClass(context, filePath) {
|
|
258
|
+
const { ts } = context;
|
|
259
|
+
const source = readSource(context, filePath);
|
|
260
|
+
const imports = collectImports(context.ts, source);
|
|
261
|
+
const localClasses = collectLocalClasses(context.ts, source);
|
|
262
|
+
for (const expression of topLevelExpressions(ts, source)) {
|
|
263
|
+
if (!context.ts.isCallExpression(expression)) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const calleeName = callName(context.ts, expression.expression);
|
|
267
|
+
const isCreateApp = calleeName === "createApp" || calleeName !== undefined && imports.get(calleeName)?.importedName === "createApp";
|
|
268
|
+
if (!isCreateApp) {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
const rootExpr = createAppRoot(context.ts, expression);
|
|
272
|
+
if (!rootExpr) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
return resolveClassReference(context, { filePath, source }, rootExpr);
|
|
276
|
+
}
|
|
277
|
+
for (const statement of source.statements) {
|
|
278
|
+
if (!context.ts.isClassDeclaration(statement)) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const name = statement.name?.text;
|
|
282
|
+
if (!name || !isExported(context.ts, statement)) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (isComponentSubclass(context, {
|
|
286
|
+
filePath,
|
|
287
|
+
source,
|
|
288
|
+
declaration: statement,
|
|
289
|
+
className: name
|
|
290
|
+
})) {
|
|
291
|
+
return {
|
|
292
|
+
filePath,
|
|
293
|
+
source,
|
|
294
|
+
declaration: statement,
|
|
295
|
+
className: name
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
for (const [name, declaration] of localClasses) {
|
|
300
|
+
if (isComponentSubclass(context, {
|
|
301
|
+
filePath,
|
|
302
|
+
source,
|
|
303
|
+
declaration,
|
|
304
|
+
className: name
|
|
305
|
+
})) {
|
|
306
|
+
return { filePath, source, declaration, className: name };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
throw mpError(filePath, "\u672A\u627E\u5230\u53EF\u7F16\u8BD1\u7684\u9875\u9762\u7EC4\u4EF6\uFF1A\u9700\u8981 createApp({ root }) \u6216\u5BFC\u51FA\u7684 Component \u5B50\u7C7B");
|
|
310
|
+
}
|
|
311
|
+
function resolveClassReference(context, from, expr) {
|
|
312
|
+
const { ts } = context;
|
|
313
|
+
expr = unwrapParentheses(ts, expr);
|
|
314
|
+
if (ts.isClassExpression(expr) || ts.isClassDeclaration(expr)) {
|
|
315
|
+
const name2 = expr.name?.text;
|
|
316
|
+
if (!name2) {
|
|
317
|
+
throw mpError(from.filePath, "\u533F\u540D\u7EC4\u4EF6\u7C7B\u4E0D\u652F\u6301\u7F16\u8BD1\u5230\u5C0F\u7A0B\u5E8F");
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
filePath: from.filePath,
|
|
321
|
+
source: from.source,
|
|
322
|
+
declaration: expr,
|
|
323
|
+
className: name2
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
if (!ts.isIdentifier(expr)) {
|
|
327
|
+
throw mpError(from.filePath, `\u7EC4\u4EF6\u5F15\u7528\u5FC5\u987B\u662F\u7C7B\u540D\u6216\u7C7B\u8868\u8FBE\u5F0F: ${expr.getText().slice(0, 60)}`);
|
|
328
|
+
}
|
|
329
|
+
const name = expr.text;
|
|
330
|
+
const local = collectLocalClasses(ts, from.source).get(name);
|
|
331
|
+
if (local) {
|
|
332
|
+
return {
|
|
333
|
+
filePath: from.filePath,
|
|
334
|
+
source: from.source,
|
|
335
|
+
declaration: local,
|
|
336
|
+
className: name
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
const imports = collectImports(ts, from.source);
|
|
340
|
+
const binding = imports.get(name);
|
|
341
|
+
if (binding) {
|
|
342
|
+
return resolveImportedClass(context, from, name, binding);
|
|
343
|
+
}
|
|
344
|
+
throw mpError(from.filePath, `\u65E0\u6CD5\u89E3\u6790\u7EC4\u4EF6\u6807\u8BC6\u7B26 "${name}"`);
|
|
345
|
+
}
|
|
346
|
+
function isComponentSubclass(context, classSource) {
|
|
347
|
+
const { ts } = context;
|
|
348
|
+
const heritage = classSource.declaration.heritageClauses ?? [];
|
|
349
|
+
const imports = collectImports(ts, classSource.source);
|
|
350
|
+
for (const clause of heritage) {
|
|
351
|
+
if (clause.token !== ts.SyntaxKind.ExtendsKeyword) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
for (const type of clause.types) {
|
|
355
|
+
if (!ts.isExpressionWithTypeArguments(type)) {
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const expression = unwrapParentheses(ts, type.expression);
|
|
359
|
+
if (!ts.isIdentifier(expression)) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const binding = imports.get(expression.text);
|
|
363
|
+
if (binding && binding.specifier.includes("transone")) {
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
if (expression.text === "Component") {
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
function resolveImportedClass(context, from, localName, binding) {
|
|
374
|
+
if (binding.specifier.startsWith(".")) {
|
|
375
|
+
const targetPath = resolveImportPath(from.filePath, binding.specifier);
|
|
376
|
+
if (!targetPath) {
|
|
377
|
+
throw mpError(from.filePath, `\u627E\u4E0D\u5230\u5BFC\u5165\u6587\u4EF6 "${binding.specifier}"\uFF08\u76F8\u5BF9 ${from.filePath}\uFF09`);
|
|
378
|
+
}
|
|
379
|
+
const source = readSource(context, targetPath);
|
|
380
|
+
const importedName = binding.importedName;
|
|
381
|
+
const found = findExportedClass(context, source, importedName, new Set);
|
|
382
|
+
if (!found) {
|
|
383
|
+
throw mpError(targetPath, `\u627E\u4E0D\u5230\u5BFC\u51FA\u7684\u7EC4\u4EF6\u7C7B "${importedName}"\uFF08\u4ECE ${localName} \u5BFC\u5165\uFF09`);
|
|
384
|
+
}
|
|
385
|
+
return {
|
|
386
|
+
filePath: found.filePath,
|
|
387
|
+
source: readSource(context, found.filePath),
|
|
388
|
+
declaration: found.declaration,
|
|
389
|
+
className: importedName
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
return resolvePackageClass(context, from, localName, binding);
|
|
393
|
+
}
|
|
394
|
+
function resolvePackageClass(context, from, localName, binding) {
|
|
395
|
+
const packageInfo = findPackageInfo(from.filePath, binding.specifier);
|
|
396
|
+
if (!packageInfo) {
|
|
397
|
+
throw mpError(from.filePath, `\u65E0\u6CD5\u89E3\u6790\u7EC4\u4EF6\u6765\u6E90 "${binding.specifier}"\uFF1A\u627E\u4E0D\u5230 node_modules \u5305\uFF08\u4EC5\u652F\u6301\u76F8\u5BF9\u8DEF\u5F84\u6216\u5DF2\u5B89\u88C5\u7684\u5305\uFF09`);
|
|
398
|
+
}
|
|
399
|
+
const sourceField = packageInfo.source;
|
|
400
|
+
if (typeof sourceField !== "string" || sourceField.length === 0) {
|
|
401
|
+
throw mpError(from.filePath, `\u5305 "${binding.specifier}" \u7F3A\u5C11 "source" \u5B57\u6BB5\uFF1A\u5C0F\u7A0B\u5E8F\u7F16\u8BD1\u9700\u8981\u53EF\u5206\u6790\u7684 TS \u6E90\u7801\u5165\u53E3\uFF08\u5728 package.json \u58F0\u660E "source": "./lib/index.ts"\uFF09`);
|
|
402
|
+
}
|
|
403
|
+
const targetPath = resolvePackageSource(packageInfo.dir, sourceField);
|
|
404
|
+
if (!targetPath) {
|
|
405
|
+
throw mpError(from.filePath, `\u5305 "${binding.specifier}" \u7684 "source" \u6307\u5411\u7684\u6587\u4EF6\u4E0D\u5B58\u5728: ${sourceField}`);
|
|
406
|
+
}
|
|
407
|
+
const source = readSource(context, targetPath);
|
|
408
|
+
const importedName = binding.importedName;
|
|
409
|
+
const found = findExportedClass(context, source, importedName, new Set);
|
|
410
|
+
if (!found) {
|
|
411
|
+
throw mpError(targetPath, `\u627E\u4E0D\u5230\u5BFC\u51FA\u7684\u7EC4\u4EF6\u7C7B "${importedName}"\uFF08\u4ECE ${localName} \u5BFC\u5165\uFF0C\u5305 "${binding.specifier}"\uFF09`);
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
filePath: found.filePath,
|
|
415
|
+
source: readSource(context, found.filePath),
|
|
416
|
+
declaration: found.declaration,
|
|
417
|
+
className: importedName
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
function findPackageInfo(fromFile, specifier) {
|
|
421
|
+
const segments = specifier.split("/");
|
|
422
|
+
const packageJsonRelative = join("node_modules", ...segments, "package.json");
|
|
423
|
+
let current = dirname(fromFile);
|
|
424
|
+
for (;; ) {
|
|
425
|
+
const candidate = join(current, packageJsonRelative);
|
|
426
|
+
if (existsSync(candidate)) {
|
|
427
|
+
try {
|
|
428
|
+
const json = JSON.parse(readFileSync(candidate, "utf8"));
|
|
429
|
+
return { dir: join(current, "node_modules", ...segments), source: json.source };
|
|
430
|
+
} catch {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
const parent = dirname(current);
|
|
435
|
+
if (parent === current) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
current = parent;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function resolvePackageSource(packageDir, sourceField) {
|
|
442
|
+
const base = resolve(packageDir, sourceField);
|
|
443
|
+
const candidates = [base, `${base}.ts`, `${base}.tsx`];
|
|
444
|
+
return candidates.find((candidate) => existsSync(candidate));
|
|
445
|
+
}
|
|
446
|
+
function findExportedClass(context, source, name, seen) {
|
|
447
|
+
const { ts } = context;
|
|
448
|
+
if (seen.has(source.fileName)) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
seen.add(source.fileName);
|
|
452
|
+
for (const statement of source.statements) {
|
|
453
|
+
if (ts.isClassDeclaration(statement) && statement.name?.text === name) {
|
|
454
|
+
if (isExported(ts, statement)) {
|
|
455
|
+
return { filePath: source.fileName, declaration: statement };
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
for (const statement of source.statements) {
|
|
460
|
+
if (ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
461
|
+
for (const element of statement.exportClause.elements) {
|
|
462
|
+
if (element.name.text !== name) {
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const local = collectLocalClasses(ts, source).get(name);
|
|
466
|
+
if (local) {
|
|
467
|
+
return { filePath: source.fileName, declaration: local };
|
|
468
|
+
}
|
|
469
|
+
if (!statement.moduleSpecifier) {
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
const specifier = statement.moduleSpecifier.getText().replace(/['"]/g, "");
|
|
473
|
+
if (!specifier.startsWith(".")) {
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
const targetPath = resolveImportPath(source.fileName, specifier);
|
|
477
|
+
if (!targetPath) {
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const targetSource = readSource(context, targetPath);
|
|
481
|
+
const reExported = findExportedClass(context, targetSource, element.propertyName?.text ?? element.name.text, seen);
|
|
482
|
+
if (reExported) {
|
|
483
|
+
return reExported;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
function topLevelExpressions(ts, source) {
|
|
491
|
+
const expressions = [];
|
|
492
|
+
for (const statement of source.statements) {
|
|
493
|
+
if (ts.isExpressionStatement(statement)) {
|
|
494
|
+
expressions.push(statement.expression);
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
if (ts.isVariableStatement(statement)) {
|
|
498
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
499
|
+
if (declaration.initializer) {
|
|
500
|
+
expressions.push(declaration.initializer);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return expressions;
|
|
506
|
+
}
|
|
507
|
+
function createAppRoot(ts, call) {
|
|
508
|
+
for (const argument of call.arguments) {
|
|
509
|
+
const object = unwrapParentheses(ts, argument);
|
|
510
|
+
if (!ts.isObjectLiteralExpression(object)) {
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
for (const property of object.properties) {
|
|
514
|
+
if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.text === "root") {
|
|
515
|
+
return property.initializer;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
function collectLocalClasses(ts, source) {
|
|
522
|
+
const classes = new Map;
|
|
523
|
+
for (const statement of source.statements) {
|
|
524
|
+
if (ts.isClassDeclaration(statement) && statement.name) {
|
|
525
|
+
classes.set(statement.name.text, statement);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return classes;
|
|
529
|
+
}
|
|
530
|
+
function collectImports(ts, source) {
|
|
531
|
+
const imports = new Map;
|
|
532
|
+
for (const statement of source.statements) {
|
|
533
|
+
if (!ts.isImportDeclaration(statement)) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const specifier = statement.moduleSpecifier.getText().replace(/['"]/g, "");
|
|
537
|
+
const bindings = statement.importClause?.namedBindings;
|
|
538
|
+
if (!bindings) {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
if (ts.isNamedImports(bindings)) {
|
|
542
|
+
for (const element of bindings.elements) {
|
|
543
|
+
imports.set(element.name.text, {
|
|
544
|
+
specifier,
|
|
545
|
+
importedName: element.propertyName?.text ?? element.name.text
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
} else if (ts.isNamespaceImport(bindings)) {
|
|
549
|
+
imports.set(bindings.name.text, { specifier, importedName: "*" });
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return imports;
|
|
553
|
+
}
|
|
554
|
+
function resolveImportPath(fromFile, specifier) {
|
|
555
|
+
const base = resolve(dirname(fromFile), specifier);
|
|
556
|
+
const candidates = [
|
|
557
|
+
base,
|
|
558
|
+
`${base}.ts`,
|
|
559
|
+
`${base}.tsx`,
|
|
560
|
+
join(base, "index.ts"),
|
|
561
|
+
join(base, "index.tsx")
|
|
562
|
+
];
|
|
563
|
+
return candidates.find((candidate) => existsSync(candidate));
|
|
564
|
+
}
|
|
565
|
+
function isExported(ts, declaration) {
|
|
566
|
+
return (declaration.modifiers ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
|
|
567
|
+
}
|
|
568
|
+
function callName(ts, expression) {
|
|
569
|
+
expression = unwrapParentheses(ts, expression);
|
|
570
|
+
if (ts.isIdentifier(expression)) {
|
|
571
|
+
return expression.text;
|
|
572
|
+
}
|
|
573
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
574
|
+
return expression.name.text;
|
|
575
|
+
}
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// src/mp/binding.ts
|
|
580
|
+
function toBinding(context, node) {
|
|
581
|
+
const { ts } = context;
|
|
582
|
+
node = unwrapParentheses(ts, node);
|
|
583
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
584
|
+
const statePath = thisStatePath(ts, node);
|
|
585
|
+
if (statePath) {
|
|
586
|
+
return statePath;
|
|
587
|
+
}
|
|
588
|
+
const propsPath = thisPropsPath(ts, node);
|
|
589
|
+
if (propsPath) {
|
|
590
|
+
context.onProp?.(propsPath.split(".")[0]);
|
|
591
|
+
return propsPath;
|
|
592
|
+
}
|
|
593
|
+
const folded = foldExpression(ts, node, context.scope.consts);
|
|
594
|
+
if (folded !== undefined) {
|
|
595
|
+
return literalToBinding(folded);
|
|
596
|
+
}
|
|
597
|
+
const base = toBinding(context, node.expression);
|
|
598
|
+
if (!isPathLike(base)) {
|
|
599
|
+
throw mpError(context.filePath, `\u6A21\u677F\u8868\u8FBE\u5F0F\u4E0D\u652F\u6301\u8BE5\u5C5E\u6027\u8BBF\u95EE: ${node.getText()}`);
|
|
600
|
+
}
|
|
601
|
+
return `${base}.${node.name.text}`;
|
|
602
|
+
}
|
|
603
|
+
if (ts.isElementAccessExpression(node)) {
|
|
604
|
+
const folded = foldExpression(ts, node, context.scope.consts);
|
|
605
|
+
if (folded !== undefined) {
|
|
606
|
+
return literalToBinding(folded);
|
|
607
|
+
}
|
|
608
|
+
const base = toBinding(context, node.expression);
|
|
609
|
+
const index = toBinding(context, node.argumentExpression);
|
|
610
|
+
if (!isPathLike(base)) {
|
|
611
|
+
throw mpError(context.filePath, `\u6A21\u677F\u8868\u8FBE\u5F0F\u4E0D\u652F\u6301\u8BE5\u4E0B\u6807\u8BBF\u95EE: ${node.getText()}`);
|
|
612
|
+
}
|
|
613
|
+
return `${base}[${index}]`;
|
|
614
|
+
}
|
|
615
|
+
if (ts.isIdentifier(node)) {
|
|
616
|
+
const { params, locals, consts } = context.scope;
|
|
617
|
+
if (params.has(node.text)) {
|
|
618
|
+
return node.text;
|
|
619
|
+
}
|
|
620
|
+
if (locals.has(node.text)) {
|
|
621
|
+
return toBinding(context, locals.get(node.text));
|
|
622
|
+
}
|
|
623
|
+
if (consts.has(node.text)) {
|
|
624
|
+
const folded = foldExpression(ts, node, consts);
|
|
625
|
+
if (folded !== undefined) {
|
|
626
|
+
return literalToBinding(folded);
|
|
627
|
+
}
|
|
628
|
+
return toBinding(context, consts.get(node.text));
|
|
629
|
+
}
|
|
630
|
+
throw mpError(context.filePath, `\u65E0\u6CD5\u89E3\u6790\u6A21\u677F\u6807\u8BC6\u7B26 "${node.text}"`);
|
|
631
|
+
}
|
|
632
|
+
if (ts.isStringLiteral(node)) {
|
|
633
|
+
return singleQuoted(node.text);
|
|
634
|
+
}
|
|
635
|
+
if (ts.isNumericLiteral(node)) {
|
|
636
|
+
return node.text;
|
|
637
|
+
}
|
|
638
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword) {
|
|
639
|
+
return "true";
|
|
640
|
+
}
|
|
641
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword) {
|
|
642
|
+
return "false";
|
|
643
|
+
}
|
|
644
|
+
if (node.kind === ts.SyntaxKind.NullKeyword) {
|
|
645
|
+
return "null";
|
|
646
|
+
}
|
|
647
|
+
if (ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
648
|
+
if (node.text.includes("{{")) {
|
|
649
|
+
return node.text;
|
|
650
|
+
}
|
|
651
|
+
return singleQuoted(node.text);
|
|
652
|
+
}
|
|
653
|
+
if (ts.isTemplateExpression(node)) {
|
|
654
|
+
const parts = [];
|
|
655
|
+
if (node.head.text !== "") {
|
|
656
|
+
parts.push(singleQuoted(node.head.text));
|
|
657
|
+
}
|
|
658
|
+
for (const span of node.templateSpans) {
|
|
659
|
+
parts.push(toBinding(context, span.expression));
|
|
660
|
+
if (span.literal.text !== "") {
|
|
661
|
+
parts.push(singleQuoted(span.literal.text));
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return parts.join(" + ");
|
|
665
|
+
}
|
|
666
|
+
if (ts.isBinaryExpression(node)) {
|
|
667
|
+
return `(${toBinding(context, node.left)} ${node.operatorToken.getText()} ${toBinding(context, node.right)})`;
|
|
668
|
+
}
|
|
669
|
+
if (ts.isConditionalExpression(node)) {
|
|
670
|
+
return `(${toBinding(context, node.condition)} ? ${toBinding(context, node.whenTrue)} : ${toBinding(context, node.whenFalse)})`;
|
|
671
|
+
}
|
|
672
|
+
if (ts.isPrefixUnaryExpression(node)) {
|
|
673
|
+
const operator = ts.tokenToString(node.operator) ?? String(node.operator);
|
|
674
|
+
return `(${operator}${toBinding(context, node.operand)})`;
|
|
675
|
+
}
|
|
676
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
677
|
+
const folded = foldExpression(ts, node, context.scope.consts);
|
|
678
|
+
if (folded !== undefined) {
|
|
679
|
+
return literalToBinding(folded);
|
|
680
|
+
}
|
|
681
|
+
const items = node.elements.map((element) => toBinding(context, element));
|
|
682
|
+
return `[${items.join(", ")}]`;
|
|
683
|
+
}
|
|
684
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
685
|
+
const folded = foldExpression(ts, node, context.scope.consts);
|
|
686
|
+
if (folded !== undefined) {
|
|
687
|
+
return literalToBinding(folded);
|
|
688
|
+
}
|
|
689
|
+
throw mpError(context.filePath, `\u6A21\u677F\u8868\u8FBE\u5F0F\u4E2D\u7684\u5BF9\u8C61\u5B57\u9762\u91CF\u65E0\u6CD5\u9759\u6001\u6C42\u503C: ${node.getText()}`);
|
|
690
|
+
}
|
|
691
|
+
if (ts.isCallExpression(node)) {
|
|
692
|
+
throw mpError(context.filePath, `\u6A21\u677F\u8868\u8FBE\u5F0F\u4E0D\u652F\u6301\u51FD\u6570\u8C03\u7528\uFF08\u5982 ${node.getText()}\uFF09\uFF1AWXML \u65E0\u6CD5\u6267\u884C\u65B9\u6CD5\uFF0C\u8BF7\u5728\u65B9\u6CD5/state \u4E2D\u9884\u5148\u8BA1\u7B97\u683C\u5F0F\u5316\u7ED3\u679C`);
|
|
693
|
+
}
|
|
694
|
+
throw mpError(context.filePath, `\u4E0D\u652F\u6301\u7684\u6A21\u677F\u8868\u8FBE\u5F0F: ${node.getText() ?? node.kind}`);
|
|
695
|
+
}
|
|
696
|
+
function thisStatePath(ts, node) {
|
|
697
|
+
return thisMemberPath(ts, node, "state");
|
|
698
|
+
}
|
|
699
|
+
function thisPropsPath(ts, node) {
|
|
700
|
+
return thisMemberPath(ts, node, "props");
|
|
701
|
+
}
|
|
702
|
+
function thisMemberPath(ts, node, member) {
|
|
703
|
+
let current = node;
|
|
704
|
+
const parts = [];
|
|
705
|
+
while (ts.isPropertyAccessExpression(current)) {
|
|
706
|
+
parts.unshift(current.name.text);
|
|
707
|
+
current = current.expression;
|
|
708
|
+
if (ts.isPropertyAccessExpression(current) && isThisExpression(ts, current.expression)) {
|
|
709
|
+
if (current.name.text === member) {
|
|
710
|
+
return parts.join(".");
|
|
711
|
+
}
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (ts.isElementAccessExpression(current)) {
|
|
715
|
+
if (!ts.isStringLiteral(current.argumentExpression) || !thisMemberBase(ts, current.expression)) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
parts.unshift(current.argumentExpression.text);
|
|
719
|
+
current = current.expression;
|
|
720
|
+
if (ts.isPropertyAccessExpression(current) && current.name.text === member) {
|
|
721
|
+
return parts.join(".");
|
|
722
|
+
}
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
function thisMemberBase(ts, node) {
|
|
729
|
+
return ts.isPropertyAccessExpression(node) && isThisExpression(ts, node.expression);
|
|
730
|
+
}
|
|
731
|
+
function isPathLike(value) {
|
|
732
|
+
return /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/.test(value);
|
|
733
|
+
}
|
|
734
|
+
function literalToBinding(value) {
|
|
735
|
+
if (typeof value === "string") {
|
|
736
|
+
return singleQuoted(value);
|
|
737
|
+
}
|
|
738
|
+
if (typeof value === "number") {
|
|
739
|
+
return String(value);
|
|
740
|
+
}
|
|
741
|
+
if (typeof value === "boolean") {
|
|
742
|
+
return value ? "true" : "false";
|
|
743
|
+
}
|
|
744
|
+
if (value === null) {
|
|
745
|
+
return "null";
|
|
746
|
+
}
|
|
747
|
+
if (Array.isArray(value)) {
|
|
748
|
+
return `[${value.map(literalToBinding).join(", ")}]`;
|
|
749
|
+
}
|
|
750
|
+
const entries = Object.entries(value).map(([key, item]) => `${key}: ${literalToBinding(item)}`);
|
|
751
|
+
return `{${entries.join(", ")}}`;
|
|
752
|
+
}
|
|
753
|
+
function singleQuoted(value) {
|
|
754
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// src/mp/types.ts
|
|
758
|
+
function warn(context, message) {
|
|
759
|
+
context.warnings.push(message);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// src/mp/wxml.ts
|
|
763
|
+
var ELEMENT_FACTORIES = new Set([
|
|
764
|
+
"h",
|
|
765
|
+
"Tag",
|
|
766
|
+
"Div",
|
|
767
|
+
"Span",
|
|
768
|
+
"P",
|
|
769
|
+
"Button",
|
|
770
|
+
"Input",
|
|
771
|
+
"Section",
|
|
772
|
+
"Main",
|
|
773
|
+
"Header",
|
|
774
|
+
"Footer",
|
|
775
|
+
"Nav",
|
|
776
|
+
"Article",
|
|
777
|
+
"Aside",
|
|
778
|
+
"H1",
|
|
779
|
+
"H2",
|
|
780
|
+
"H3",
|
|
781
|
+
"H4",
|
|
782
|
+
"H5",
|
|
783
|
+
"H6",
|
|
784
|
+
"Strong",
|
|
785
|
+
"Em",
|
|
786
|
+
"Small",
|
|
787
|
+
"Pre",
|
|
788
|
+
"Code",
|
|
789
|
+
"Blockquote",
|
|
790
|
+
"Ul",
|
|
791
|
+
"Ol",
|
|
792
|
+
"Li",
|
|
793
|
+
"A",
|
|
794
|
+
"Img",
|
|
795
|
+
"Form",
|
|
796
|
+
"Label",
|
|
797
|
+
"Textarea",
|
|
798
|
+
"Select",
|
|
799
|
+
"Option",
|
|
800
|
+
"Table",
|
|
801
|
+
"Thead",
|
|
802
|
+
"Tbody",
|
|
803
|
+
"Tr",
|
|
804
|
+
"Th",
|
|
805
|
+
"Td"
|
|
806
|
+
]);
|
|
807
|
+
var SPECIAL_CALLS = new Set(["createComponent", "each", "slot"]);
|
|
808
|
+
var TAG_MAP = {
|
|
809
|
+
div: "view",
|
|
810
|
+
section: "view",
|
|
811
|
+
main: "view",
|
|
812
|
+
header: "view",
|
|
813
|
+
footer: "view",
|
|
814
|
+
article: "view",
|
|
815
|
+
aside: "view",
|
|
816
|
+
nav: "view",
|
|
817
|
+
ul: "view",
|
|
818
|
+
ol: "view",
|
|
819
|
+
li: "view",
|
|
820
|
+
blockquote: "view",
|
|
821
|
+
pre: "view",
|
|
822
|
+
code: "view",
|
|
823
|
+
table: "view",
|
|
824
|
+
thead: "view",
|
|
825
|
+
tbody: "view",
|
|
826
|
+
tr: "view",
|
|
827
|
+
th: "view",
|
|
828
|
+
td: "view",
|
|
829
|
+
p: "view",
|
|
830
|
+
form: "form",
|
|
831
|
+
label: "label",
|
|
832
|
+
h1: "view",
|
|
833
|
+
h2: "view",
|
|
834
|
+
h3: "view",
|
|
835
|
+
h4: "view",
|
|
836
|
+
h5: "view",
|
|
837
|
+
h6: "view",
|
|
838
|
+
span: "text",
|
|
839
|
+
strong: "text",
|
|
840
|
+
em: "text",
|
|
841
|
+
small: "text",
|
|
842
|
+
button: "button",
|
|
843
|
+
input: "input",
|
|
844
|
+
textarea: "textarea",
|
|
845
|
+
img: "image",
|
|
846
|
+
a: "navigator",
|
|
847
|
+
view: "view",
|
|
848
|
+
text: "text",
|
|
849
|
+
image: "image",
|
|
850
|
+
navigator: "navigator",
|
|
851
|
+
"scroll-view": "scroll-view",
|
|
852
|
+
swiper: "swiper",
|
|
853
|
+
"swiper-item": "swiper-item",
|
|
854
|
+
picker: "picker",
|
|
855
|
+
"picker-view": "picker-view",
|
|
856
|
+
"picker-view-column": "picker-view-column",
|
|
857
|
+
switch: "switch",
|
|
858
|
+
checkbox: "checkbox",
|
|
859
|
+
"checkbox-group": "checkbox-group",
|
|
860
|
+
radio: "radio",
|
|
861
|
+
"radio-group": "radio-group",
|
|
862
|
+
slider: "slider",
|
|
863
|
+
progress: "progress",
|
|
864
|
+
icon: "icon",
|
|
865
|
+
"rich-text": "rich-text",
|
|
866
|
+
video: "video",
|
|
867
|
+
camera: "camera",
|
|
868
|
+
"live-player": "live-player",
|
|
869
|
+
"live-pusher": "live-pusher",
|
|
870
|
+
map: "map",
|
|
871
|
+
canvas: "canvas",
|
|
872
|
+
"cover-view": "cover-view",
|
|
873
|
+
"cover-image": "cover-image",
|
|
874
|
+
"movable-view": "movable-view",
|
|
875
|
+
"movable-area": "movable-area",
|
|
876
|
+
"web-view": "web-view",
|
|
877
|
+
ad: "ad",
|
|
878
|
+
"official-account": "official-account",
|
|
879
|
+
"open-data": "open-data",
|
|
880
|
+
scrollView: "scroll-view",
|
|
881
|
+
swiperItem: "swiper-item",
|
|
882
|
+
pickerView: "picker-view",
|
|
883
|
+
pickerViewColumn: "picker-view-column",
|
|
884
|
+
checkboxGroup: "checkbox-group",
|
|
885
|
+
radioGroup: "radio-group",
|
|
886
|
+
richText: "rich-text",
|
|
887
|
+
coverView: "cover-view",
|
|
888
|
+
coverImage: "cover-image",
|
|
889
|
+
movableView: "movable-view",
|
|
890
|
+
movableArea: "movable-area",
|
|
891
|
+
webView: "web-view",
|
|
892
|
+
livePlayer: "live-player",
|
|
893
|
+
officialAccount: "official-account",
|
|
894
|
+
openData: "open-data"
|
|
895
|
+
};
|
|
896
|
+
var EVENT_MAP = {
|
|
897
|
+
click: "tap",
|
|
898
|
+
tap: "tap",
|
|
899
|
+
longpress: "longpress",
|
|
900
|
+
longtap: "longtap",
|
|
901
|
+
input: "input",
|
|
902
|
+
change: "change",
|
|
903
|
+
cancel: "cancel",
|
|
904
|
+
submit: "submit",
|
|
905
|
+
focus: "focus",
|
|
906
|
+
blur: "blur",
|
|
907
|
+
confirm: "confirm",
|
|
908
|
+
load: "load",
|
|
909
|
+
error: "error",
|
|
910
|
+
scroll: "scroll",
|
|
911
|
+
scrolltoupper: "scrolltoupper",
|
|
912
|
+
scrolltolower: "scrolltolower",
|
|
913
|
+
scrollToUpper: "scrolltoupper",
|
|
914
|
+
scrollToLower: "scrolltolower",
|
|
915
|
+
refresherrefresh: "refresherrefresh",
|
|
916
|
+
refresherpulldown: "refresherpulldown",
|
|
917
|
+
refresherrestore: "refresherrestore",
|
|
918
|
+
refresherabort: "refresherabort",
|
|
919
|
+
touchstart: "touchstart",
|
|
920
|
+
touchmove: "touchmove",
|
|
921
|
+
touchend: "touchend",
|
|
922
|
+
touchcancel: "touchcancel",
|
|
923
|
+
touchforcechange: "touchforcechange",
|
|
924
|
+
transitionend: "transitionend",
|
|
925
|
+
animationfinish: "animationfinish",
|
|
926
|
+
animationfail: "animationfail",
|
|
927
|
+
getphonenumber: "getphonenumber",
|
|
928
|
+
getuserinfo: "getuserinfo",
|
|
929
|
+
getcontact: "getcontact",
|
|
930
|
+
openshare: "openshare",
|
|
931
|
+
launchapp: "launchapp",
|
|
932
|
+
message: "message"
|
|
933
|
+
};
|
|
934
|
+
var TAG_KEYS = new Set([
|
|
935
|
+
"props",
|
|
936
|
+
"children",
|
|
937
|
+
"listeners",
|
|
938
|
+
"key",
|
|
939
|
+
"directions"
|
|
940
|
+
]);
|
|
941
|
+
function notUndefined(ts, expression) {
|
|
942
|
+
return expression !== undefined && !(ts.isIdentifier(expression) && expression.text === "undefined");
|
|
943
|
+
}
|
|
944
|
+
function isEventProp(key) {
|
|
945
|
+
return /^on[A-Z]/.test(key) || /^on[a-z]/.test(key);
|
|
946
|
+
}
|
|
947
|
+
function eventNameFromProp(key) {
|
|
948
|
+
return key.slice(2).toLowerCase();
|
|
949
|
+
}
|
|
950
|
+
function compileTemplate(context, classSource, _kind, hoverSelectors = new Set) {
|
|
951
|
+
const { ts } = context;
|
|
952
|
+
const renderMethod = findMethod(context, classSource, "render");
|
|
953
|
+
if (!renderMethod) {
|
|
954
|
+
throw mpError(classSource.filePath, `\u7EC4\u4EF6 ${classSource.className} \u7F3A\u5C11 render() \u65B9\u6CD5`);
|
|
955
|
+
}
|
|
956
|
+
const body = renderMethod.body;
|
|
957
|
+
if (!body) {
|
|
958
|
+
throw mpError(classSource.filePath, "render() \u7F3A\u5C11\u65B9\u6CD5\u4F53");
|
|
959
|
+
}
|
|
960
|
+
const locals = new Map;
|
|
961
|
+
let returnStatement;
|
|
962
|
+
for (const statement of body.statements) {
|
|
963
|
+
if (ts.isVariableStatement(statement)) {
|
|
964
|
+
const isConst = statement.declarationList.flags & ts.NodeFlags.Const;
|
|
965
|
+
if (!isConst) {
|
|
966
|
+
throw mpError(classSource.filePath, "render() \u5185\u53EA\u652F\u6301 const \u5C40\u90E8\u53D8\u91CF\uFF08\u5C0F\u7A0B\u5E8F\u6A21\u677F\u662F\u9759\u6001\u7F16\u8BD1\u7684\uFF09");
|
|
967
|
+
}
|
|
968
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
969
|
+
if (ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
970
|
+
locals.set(declaration.name.text, declaration.initializer);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
continue;
|
|
974
|
+
}
|
|
975
|
+
if (ts.isReturnStatement(statement)) {
|
|
976
|
+
returnStatement = statement;
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
979
|
+
throw mpError(classSource.filePath, `render() \u5185\u4E0D\u652F\u6301\u7684\u8BED\u53E5\uFF08\u53EA\u652F\u6301 const \u58F0\u660E\u4E0E return\uFF09: ${statement.getText().slice(0, 60)}`);
|
|
980
|
+
}
|
|
981
|
+
if (!returnStatement?.expression) {
|
|
982
|
+
throw mpError(classSource.filePath, "render() \u5FC5\u987B\u4EE5 return \u8868\u8FBE\u5F0F\u7ED3\u675F");
|
|
983
|
+
}
|
|
984
|
+
const consts = collectModuleConsts(context, classSource);
|
|
985
|
+
const builder = {
|
|
986
|
+
handlers: new Set,
|
|
987
|
+
usedComponents: new Map,
|
|
988
|
+
propsReferenced: new Set,
|
|
989
|
+
customEvents: new Set,
|
|
990
|
+
emitters: []
|
|
991
|
+
};
|
|
992
|
+
const env = {
|
|
993
|
+
builder,
|
|
994
|
+
scope: { params: new Set, locals, consts },
|
|
995
|
+
indent: 0,
|
|
996
|
+
extraAttrs: [],
|
|
997
|
+
origins: collectFactoryOrigins(ts, classSource.source),
|
|
998
|
+
hoverSelectors
|
|
999
|
+
};
|
|
1000
|
+
const lines = buildNodeLines(context, classSource, returnStatement.expression, env);
|
|
1001
|
+
const header = `<!-- \u7531 transone build --target ${context.dialect.id} \u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u7F16\u8F91 -->`;
|
|
1002
|
+
return {
|
|
1003
|
+
template: [header, ...lines].join(`
|
|
1004
|
+
`) + `
|
|
1005
|
+
`,
|
|
1006
|
+
builder
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
1009
|
+
function buildNodeLines(context, classSource, node, env, depth = 0) {
|
|
1010
|
+
if (depth > 64) {
|
|
1011
|
+
throw mpError(classSource.filePath, "\u6A21\u677F\u5D4C\u5957\u8FC7\u6DF1\uFF08\u53EF\u80FD\u662F\u6807\u8BC6\u7B26\u5FAA\u73AF\u5F15\u7528\uFF09");
|
|
1012
|
+
}
|
|
1013
|
+
const { ts } = context;
|
|
1014
|
+
node = unwrapParentheses(ts, node);
|
|
1015
|
+
node = unwrapTypeAssertions(ts, node);
|
|
1016
|
+
if (node.kind === ts.SyntaxKind.NullKeyword) {
|
|
1017
|
+
return [];
|
|
1018
|
+
}
|
|
1019
|
+
if (ts.isCallExpression(node)) {
|
|
1020
|
+
const localName = callName2(ts, node.expression);
|
|
1021
|
+
const name = (localName && env.origins.get(localName)) ?? localName;
|
|
1022
|
+
if (name === "createComponent") {
|
|
1023
|
+
return compileComponentCall(context, classSource, node, env, depth);
|
|
1024
|
+
}
|
|
1025
|
+
if (name === "each") {
|
|
1026
|
+
return compileEach(context, classSource, node, env, depth);
|
|
1027
|
+
}
|
|
1028
|
+
if (name === "slot") {
|
|
1029
|
+
return compileSlot(context, classSource, node, env);
|
|
1030
|
+
}
|
|
1031
|
+
if (name && ELEMENT_FACTORIES.has(name)) {
|
|
1032
|
+
return compileElementCall(context, classSource, node, env, depth);
|
|
1033
|
+
}
|
|
1034
|
+
throw mpError(classSource.filePath, `\u4E0D\u652F\u6301\u7684\u6E32\u67D3\u8C03\u7528 "${name ?? "?"}"\uFF08\u4EC5\u652F\u6301 h/Tag/\u5143\u7D20\u5FEB\u6377\u65B9\u5F0F/createComponent/each/slot\uFF09`);
|
|
1035
|
+
}
|
|
1036
|
+
if (ts.isIdentifier(node)) {
|
|
1037
|
+
if (env.scope.params.has(node.text)) {
|
|
1038
|
+
return [indent(env.indent) + `{{${node.text}}}`];
|
|
1039
|
+
}
|
|
1040
|
+
const replacement = resolveIdentifierExpression(context, classSource, node, env);
|
|
1041
|
+
if (replacement) {
|
|
1042
|
+
return buildNodeLines(context, classSource, replacement, env, depth + 1);
|
|
1043
|
+
}
|
|
1044
|
+
throw mpError(classSource.filePath, `\u65E0\u6CD5\u89E3\u6790\u6A21\u677F\u6807\u8BC6\u7B26 "${node.text}"`);
|
|
1045
|
+
}
|
|
1046
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
1047
|
+
const componentProp = objectProperty(ts, node, "component");
|
|
1048
|
+
if (componentProp) {
|
|
1049
|
+
return compileComponentObject(context, classSource, node, env, depth);
|
|
1050
|
+
}
|
|
1051
|
+
throw mpError(classSource.filePath, `render() \u4E2D\u4E0D\u652F\u6301\u7684\u5BF9\u8C61\u5B57\u9762\u91CF: ${node.getText().slice(0, 60)}`);
|
|
1052
|
+
}
|
|
1053
|
+
if (ts.isConditionalExpression(node)) {
|
|
1054
|
+
return compileConditional(context, classSource, node, env, depth);
|
|
1055
|
+
}
|
|
1056
|
+
if (ts.isBinaryExpression(node)) {
|
|
1057
|
+
if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
1058
|
+
return compileLogicalAnd(context, classSource, node, env, depth);
|
|
1059
|
+
}
|
|
1060
|
+
throw mpError(classSource.filePath, `render() \u4E2D\u4E0D\u652F\u6301\u7684\u8868\u8FBE\u5F0F\uFF08\u6761\u4EF6\u6E32\u67D3\u8BF7\u7528\u4E09\u5143\u6216 &&\uFF09: ${node.getText().slice(0, 60)}`);
|
|
1061
|
+
}
|
|
1062
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
1063
|
+
const lines = [];
|
|
1064
|
+
for (const element of node.elements) {
|
|
1065
|
+
if (ts.isSpreadElement(element)) {
|
|
1066
|
+
throw mpError(classSource.filePath, "children \u4E2D\u4E0D\u652F\u6301\u5C55\u5F00\u8FD0\u7B97\u7B26");
|
|
1067
|
+
}
|
|
1068
|
+
lines.push(...buildNodeLines(context, classSource, element, env, depth));
|
|
1069
|
+
}
|
|
1070
|
+
return lines;
|
|
1071
|
+
}
|
|
1072
|
+
if (isTextNode(ts, node)) {
|
|
1073
|
+
return [indent(env.indent) + textContent(context, classSource, node, env)];
|
|
1074
|
+
}
|
|
1075
|
+
if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {
|
|
1076
|
+
return [
|
|
1077
|
+
indent(env.indent) + `{{${toBinding(bindingContext(context, classSource, env), node)}}}`
|
|
1078
|
+
];
|
|
1079
|
+
}
|
|
1080
|
+
throw mpError(classSource.filePath, `render() \u4E2D\u4E0D\u652F\u6301\u7684\u8282\u70B9: ${node.getText().slice(0, 60)}`);
|
|
1081
|
+
}
|
|
1082
|
+
function compileElementCall(context, classSource, node, env, depth) {
|
|
1083
|
+
const { ts } = context;
|
|
1084
|
+
const localName = callName2(ts, node.expression);
|
|
1085
|
+
const name = env.origins.get(localName) ?? localName;
|
|
1086
|
+
const args = node.arguments;
|
|
1087
|
+
let tagExpr;
|
|
1088
|
+
let propsExpr;
|
|
1089
|
+
let childrenExpr;
|
|
1090
|
+
let listenersExpr;
|
|
1091
|
+
let directionsExpr;
|
|
1092
|
+
if (name === "h" || name === "Tag") {
|
|
1093
|
+
if (args.length === 0) {
|
|
1094
|
+
throw mpError(classSource.filePath, `${name}() \u7F3A\u5C11\u6807\u7B7E\u53C2\u6570`);
|
|
1095
|
+
}
|
|
1096
|
+
tagExpr = args[0];
|
|
1097
|
+
if (name === "Tag" && args.length >= 2 && ts.isObjectLiteralExpression(args[1])) {
|
|
1098
|
+
const options = args[1];
|
|
1099
|
+
propsExpr = objectProperty(ts, options, "props");
|
|
1100
|
+
childrenExpr = objectProperty(ts, options, "children");
|
|
1101
|
+
listenersExpr = objectProperty(ts, options, "listeners");
|
|
1102
|
+
directionsExpr = objectProperty(ts, options, "directions");
|
|
1103
|
+
} else {
|
|
1104
|
+
propsExpr = args[1];
|
|
1105
|
+
childrenExpr = args[2];
|
|
1106
|
+
listenersExpr = notUndefined(ts, args[3]) ? args[3] : undefined;
|
|
1107
|
+
directionsExpr = notUndefined(ts, args[5]) ? args[5] : undefined;
|
|
1108
|
+
}
|
|
1109
|
+
} else {
|
|
1110
|
+
tagExpr = ts.factory.createStringLiteral(kebabCase(name));
|
|
1111
|
+
const options = args[0];
|
|
1112
|
+
if (options && ts.isObjectLiteralExpression(options)) {
|
|
1113
|
+
propsExpr = objectProperty(ts, options, "props");
|
|
1114
|
+
childrenExpr = objectProperty(ts, options, "children");
|
|
1115
|
+
listenersExpr = objectProperty(ts, options, "listeners");
|
|
1116
|
+
directionsExpr = objectProperty(ts, options, "directions");
|
|
1117
|
+
const directProps = options.properties.filter((property) => ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && !TAG_KEYS.has(property.name.text));
|
|
1118
|
+
if (directProps.length > 0) {
|
|
1119
|
+
propsExpr = ts.factory.createObjectLiteralExpression([
|
|
1120
|
+
...propsExpr && ts.isObjectLiteralExpression(propsExpr) ? propsExpr.properties : [],
|
|
1121
|
+
...directProps
|
|
1122
|
+
]);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
if (!ts.isStringLiteral(tagExpr)) {
|
|
1127
|
+
throw mpError(classSource.filePath, "\u5143\u7D20\u6807\u7B7E\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u5B57\u9762\u91CF");
|
|
1128
|
+
}
|
|
1129
|
+
return compileElement(context, classSource, tagExpr.text, propsExpr, childrenExpr, listenersExpr, directionsExpr, env, depth);
|
|
1130
|
+
}
|
|
1131
|
+
function compileElement(context, classSource, tagName, propsExpr, childrenExpr, listenersExpr, directionsExpr, env, depth) {
|
|
1132
|
+
const { ts } = context;
|
|
1133
|
+
const wxmlTag = TAG_MAP[tagName];
|
|
1134
|
+
if (!wxmlTag) {
|
|
1135
|
+
throw mpError(classSource.filePath, `\u4E0D\u652F\u6301\u7684 HTML \u6807\u7B7E "${tagName}"\uFF08WXML \u4EC5\u652F\u6301\u57FA\u7840\u7EC4\u4EF6\uFF09`);
|
|
1136
|
+
}
|
|
1137
|
+
const attrs = [...env.extraAttrs];
|
|
1138
|
+
if (propsExpr !== undefined) {
|
|
1139
|
+
if (!ts.isObjectLiteralExpression(propsExpr)) {
|
|
1140
|
+
throw mpError(classSource.filePath, `\u5143\u7D20 props \u5FC5\u987B\u662F\u5BF9\u8C61\u5B57\u9762\u91CF`);
|
|
1141
|
+
}
|
|
1142
|
+
for (const property of propsExpr.properties) {
|
|
1143
|
+
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) {
|
|
1144
|
+
throw mpError(classSource.filePath, `\u5143\u7D20 props \u53EA\u652F\u6301\u9759\u6001\u5C5E\u6027\u540D`);
|
|
1145
|
+
}
|
|
1146
|
+
const key = property.name.text;
|
|
1147
|
+
const value = property.initializer;
|
|
1148
|
+
if (key === "key") {
|
|
1149
|
+
continue;
|
|
1150
|
+
}
|
|
1151
|
+
if (key === "class" || key === "className") {
|
|
1152
|
+
attrs.push(compileClassAttr(context, classSource, value, env));
|
|
1153
|
+
continue;
|
|
1154
|
+
}
|
|
1155
|
+
if (key === "style") {
|
|
1156
|
+
attrs.push(compileStyleAttr(context, classSource, value, env));
|
|
1157
|
+
continue;
|
|
1158
|
+
}
|
|
1159
|
+
if (key === "slot") {
|
|
1160
|
+
attrs.push(`slot="${compileLiteralString(context, classSource, value, "slot \u540D\u79F0")}"`);
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
if (isEventProp(key)) {
|
|
1164
|
+
const event = eventNameFromProp(key);
|
|
1165
|
+
attrs.push(compileListener(context, classSource, event, value, env));
|
|
1166
|
+
continue;
|
|
1167
|
+
}
|
|
1168
|
+
attrs.push(compileGenericAttr(context, classSource, key, value, env));
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (listenersExpr !== undefined) {
|
|
1172
|
+
if (!ts.isObjectLiteralExpression(listenersExpr)) {
|
|
1173
|
+
throw mpError(classSource.filePath, "listeners \u5FC5\u987B\u662F\u5BF9\u8C61\u5B57\u9762\u91CF");
|
|
1174
|
+
}
|
|
1175
|
+
for (const property of listenersExpr.properties) {
|
|
1176
|
+
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) {
|
|
1177
|
+
throw mpError(classSource.filePath, "listeners \u53EA\u652F\u6301\u9759\u6001\u4E8B\u4EF6\u540D");
|
|
1178
|
+
}
|
|
1179
|
+
const event = property.name.text.split(".")[0];
|
|
1180
|
+
const hasModifiers = property.name.text !== event;
|
|
1181
|
+
if (hasModifiers) {
|
|
1182
|
+
warn(context, `${classSource.filePath}: \u4E8B\u4EF6\u4FEE\u9970\u7B26 "${property.name.text}" \u5728\u5C0F\u7A0B\u5E8F\u4E2D\u4E0D\u751F\u6548`);
|
|
1183
|
+
}
|
|
1184
|
+
attrs.push(compileListener(context, classSource, event, property.initializer, env));
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
if (directionsExpr !== undefined) {
|
|
1188
|
+
if (!ts.isObjectLiteralExpression(directionsExpr)) {
|
|
1189
|
+
throw mpError(classSource.filePath, "directions \u5FC5\u987B\u662F\u5BF9\u8C61\u5B57\u9762\u91CF");
|
|
1190
|
+
}
|
|
1191
|
+
const ifExpr = objectProperty(ts, directionsExpr, "if");
|
|
1192
|
+
if (ifExpr) {
|
|
1193
|
+
const folded = foldExpression(ts, ifExpr, env.scope.consts);
|
|
1194
|
+
if (folded === false) {
|
|
1195
|
+
return [];
|
|
1196
|
+
}
|
|
1197
|
+
if (folded !== true) {
|
|
1198
|
+
attrs.push(`${context.dialect.directivePrefix}if="{{${toBinding(bindingContext(context, classSource, env), ifExpr)}}}"`);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
const showExpr = objectProperty(ts, directionsExpr, "show");
|
|
1202
|
+
if (showExpr) {
|
|
1203
|
+
const folded = foldExpression(ts, showExpr, env.scope.consts);
|
|
1204
|
+
if (folded === false) {
|
|
1205
|
+
attrs.push("hidden");
|
|
1206
|
+
} else if (folded !== true) {
|
|
1207
|
+
const binding = toBinding(bindingContext(context, classSource, env), showExpr);
|
|
1208
|
+
attrs.push(`hidden="{{!(${binding})}}"`);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
if (objectProperty(ts, directionsExpr, "model")) {
|
|
1212
|
+
throw mpError(classSource.filePath, "directions.model \u53CC\u5411\u7ED1\u5B9A\u6682\u4E0D\u652F\u6301\u7F16\u8BD1\u5230\u5C0F\u7A0B\u5E8F\uFF0C\u8BF7\u6539\u7528 value + bindinput");
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
const openTag = attrs.length > 0 ? `<${wxmlTag} ${attrs.join(" ")}>` : `<${wxmlTag}>`;
|
|
1216
|
+
const lines = [indent(env.indent) + openTag];
|
|
1217
|
+
const childLines = buildNodeLines(context, classSource, childrenExpr ?? ts.factory.createArrayLiteralExpression([]), {
|
|
1218
|
+
...env,
|
|
1219
|
+
indent: env.indent + 1
|
|
1220
|
+
}, depth + 1);
|
|
1221
|
+
lines.push(...childLines);
|
|
1222
|
+
lines.push(indent(env.indent) + `</${wxmlTag}>`);
|
|
1223
|
+
return lines;
|
|
1224
|
+
}
|
|
1225
|
+
function compileConditional(context, classSource, node, env, depth) {
|
|
1226
|
+
const condition = toBinding(bindingContext(context, classSource, env), node.condition);
|
|
1227
|
+
const whenTrue = buildNodeLines(context, classSource, node.whenTrue, env, depth + 1);
|
|
1228
|
+
const whenFalse = buildNodeLines(context, classSource, node.whenFalse, env, depth + 1);
|
|
1229
|
+
const lines = [indent(env.indent) + `<block ${context.dialect.directivePrefix}if="{{${condition}}}">`];
|
|
1230
|
+
lines.push(...whenTrue.map((line) => indent(env.indent + 1) + line));
|
|
1231
|
+
lines.push(indent(env.indent) + "</block>");
|
|
1232
|
+
if (whenFalse.length > 0) {
|
|
1233
|
+
lines.push(indent(env.indent) + `<block ${context.dialect.directivePrefix}else>`);
|
|
1234
|
+
lines.push(...whenFalse.map((line) => indent(env.indent + 1) + line));
|
|
1235
|
+
lines.push(indent(env.indent) + "</block>");
|
|
1236
|
+
}
|
|
1237
|
+
return lines;
|
|
1238
|
+
}
|
|
1239
|
+
function compileLogicalAnd(context, classSource, node, env, depth) {
|
|
1240
|
+
const condition = toBinding(bindingContext(context, classSource, env), node.left);
|
|
1241
|
+
const inner = buildNodeLines(context, classSource, node.right, env, depth + 1);
|
|
1242
|
+
return [
|
|
1243
|
+
indent(env.indent) + `<block ${context.dialect.directivePrefix}if="{{${condition}}}">`,
|
|
1244
|
+
...inner.map((line) => indent(env.indent + 1) + line),
|
|
1245
|
+
indent(env.indent) + "</block>"
|
|
1246
|
+
];
|
|
1247
|
+
}
|
|
1248
|
+
function compileEach(context, classSource, node, env, depth) {
|
|
1249
|
+
const { ts } = context;
|
|
1250
|
+
const [itemsExpr, renderExpr, keyExpr] = node.arguments;
|
|
1251
|
+
if (!itemsExpr || !renderExpr) {
|
|
1252
|
+
throw mpError(classSource.filePath, "each(items, render, key) \u7F3A\u5C11\u53C2\u6570");
|
|
1253
|
+
}
|
|
1254
|
+
if (!ts.isArrowFunction(renderExpr)) {
|
|
1255
|
+
throw mpError(classSource.filePath, "each \u7684 render \u53C2\u6570\u5FC5\u987B\u662F\u7BAD\u5934\u51FD\u6570");
|
|
1256
|
+
}
|
|
1257
|
+
const paramNames = [];
|
|
1258
|
+
for (const parameter of renderExpr.parameters) {
|
|
1259
|
+
if (!ts.isIdentifier(parameter.name)) {
|
|
1260
|
+
throw mpError(classSource.filePath, "each \u7684\u53C2\u6570\u5FC5\u987B\u662F (item, index) \u6807\u8BC6\u7B26");
|
|
1261
|
+
}
|
|
1262
|
+
paramNames.push(parameter.name.text);
|
|
1263
|
+
}
|
|
1264
|
+
if (paramNames.length > 2) {
|
|
1265
|
+
throw mpError(classSource.filePath, "each \u6700\u591A\u63A5\u53D7 (item, index) \u4E24\u4E2A\u53C2\u6570");
|
|
1266
|
+
}
|
|
1267
|
+
const itemsBinding = toBinding(bindingContext(context, classSource, env), itemsExpr);
|
|
1268
|
+
const itemName = paramNames[0] ?? "item";
|
|
1269
|
+
const indexName = paramNames[1] ?? "index";
|
|
1270
|
+
const childScope = {
|
|
1271
|
+
...env.scope,
|
|
1272
|
+
params: new Set([...env.scope.params, itemName, indexName])
|
|
1273
|
+
};
|
|
1274
|
+
let keyAttr = "";
|
|
1275
|
+
if (keyExpr) {
|
|
1276
|
+
const keyBinding = eachKeyBinding(context, classSource, keyExpr, itemName, indexName);
|
|
1277
|
+
if (keyBinding) {
|
|
1278
|
+
keyAttr = ` ${context.dialect.directivePrefix}key="${keyBinding}"`;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
const inner = buildNodeLines(context, classSource, renderExpr.body, {
|
|
1282
|
+
...env,
|
|
1283
|
+
scope: childScope,
|
|
1284
|
+
indent: env.indent + 1
|
|
1285
|
+
}, depth + 1);
|
|
1286
|
+
return [
|
|
1287
|
+
indent(env.indent) + `<block ${context.dialect.directivePrefix}for="{{${itemsBinding}}}" ${context.dialect.directivePrefix}for-item="${itemName}" ${context.dialect.directivePrefix}for-index="${indexName}"${keyAttr}>`,
|
|
1288
|
+
...inner,
|
|
1289
|
+
indent(env.indent) + "</block>"
|
|
1290
|
+
];
|
|
1291
|
+
}
|
|
1292
|
+
function eachKeyBinding(context, classSource, keyExpr, itemName, indexName) {
|
|
1293
|
+
const { ts } = context;
|
|
1294
|
+
keyExpr = unwrapParentheses(ts, keyExpr);
|
|
1295
|
+
if (ts.isArrowFunction(keyExpr)) {
|
|
1296
|
+
const body = arrowBodyExpression(ts, keyExpr);
|
|
1297
|
+
if (body === undefined) {
|
|
1298
|
+
throw mpError(classSource.filePath, "each \u7684 key \u5FC5\u987B\u662F (item) => item.xxx \u6216 (item, index) => index");
|
|
1299
|
+
}
|
|
1300
|
+
keyExpr = body;
|
|
1301
|
+
}
|
|
1302
|
+
if (ts.isIdentifier(keyExpr)) {
|
|
1303
|
+
if (keyExpr.text === indexName) {
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
if (keyExpr.text === itemName) {
|
|
1307
|
+
throw mpError(classSource.filePath, "\u5217\u8868 key \u4E0D\u80FD\u76F4\u63A5\u4F7F\u7528 item\uFF0C\u8BF7\u53D6 item \u7684\u6210\u5458");
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
if (ts.isPropertyAccessExpression(keyExpr) && ts.isIdentifier(keyExpr.expression)) {
|
|
1311
|
+
const base = keyExpr.expression.text;
|
|
1312
|
+
if (base === itemName) {
|
|
1313
|
+
return keyExpr.name.text;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
const nested = eachKeyPath(ts, keyExpr, itemName);
|
|
1317
|
+
if (nested) {
|
|
1318
|
+
return nested;
|
|
1319
|
+
}
|
|
1320
|
+
throw mpError(classSource.filePath, "each \u7684 key \u5FC5\u987B\u662F (item) => item.xxx \u6216 (item, index) => index");
|
|
1321
|
+
}
|
|
1322
|
+
function arrowBodyExpression(ts, arrow) {
|
|
1323
|
+
const body = arrow.body;
|
|
1324
|
+
if (ts.isBlock(body)) {
|
|
1325
|
+
const statements = body.statements.filter((statement) => !ts.isEmptyStatement(statement));
|
|
1326
|
+
if (statements.length === 1 && ts.isReturnStatement(statements[0]) && statements[0].expression) {
|
|
1327
|
+
return statements[0].expression;
|
|
1328
|
+
}
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
return body;
|
|
1332
|
+
}
|
|
1333
|
+
function eachKeyPath(ts, node, itemName) {
|
|
1334
|
+
node = unwrapParentheses(ts, node);
|
|
1335
|
+
if (!ts.isPropertyAccessExpression(node)) {
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
let current = node;
|
|
1339
|
+
const parts = [];
|
|
1340
|
+
while (ts.isPropertyAccessExpression(current)) {
|
|
1341
|
+
parts.unshift(current.name.text);
|
|
1342
|
+
current = current.expression;
|
|
1343
|
+
}
|
|
1344
|
+
if (ts.isIdentifier(current) && current.text === itemName) {
|
|
1345
|
+
return parts.join(".");
|
|
1346
|
+
}
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
function compileComponentCall(context, classSource, node, env, depth) {
|
|
1350
|
+
const { ts } = context;
|
|
1351
|
+
const first = unwrapParentheses(ts, node.arguments[0]);
|
|
1352
|
+
if (ts.isObjectLiteralExpression(first) && objectProperty(ts, first, "component")) {
|
|
1353
|
+
return compileComponentObject(context, classSource, first, env, depth);
|
|
1354
|
+
}
|
|
1355
|
+
const [classExpr, propsExpr, childrenExpr] = node.arguments;
|
|
1356
|
+
if (!classExpr) {
|
|
1357
|
+
throw mpError(classSource.filePath, "createComponent \u7F3A\u5C11\u7EC4\u4EF6\u7C7B\u53C2\u6570");
|
|
1358
|
+
}
|
|
1359
|
+
const directionsExpr = node.arguments[4];
|
|
1360
|
+
return compileComponent(context, classSource, classExpr, propsExpr, childrenExpr, undefined, directionsExpr, env, depth);
|
|
1361
|
+
}
|
|
1362
|
+
function compileComponentObject(context, classSource, node, env, depth) {
|
|
1363
|
+
return compileComponent(context, classSource, objectProperty(context.ts, node, "component"), objectProperty(context.ts, node, "props"), objectProperty(context.ts, node, "children"), objectProperty(context.ts, node, "emitters"), objectProperty(context.ts, node, "directions"), env, depth);
|
|
1364
|
+
}
|
|
1365
|
+
function compileComponent(context, classSource, classExpr, propsExpr, childrenExpr, emittersExpr, directionsExpr, env, depth) {
|
|
1366
|
+
const { ts } = context;
|
|
1367
|
+
const target = resolveClassReference(context, classSource, classExpr);
|
|
1368
|
+
if (!isComponentSubclass(context, target)) {
|
|
1369
|
+
throw mpError(classSource.filePath, `createComponent \u53EA\u63A5\u53D7 Component \u5B50\u7C7B: ${target.className}`);
|
|
1370
|
+
}
|
|
1371
|
+
const tag = kebabCase(target.className);
|
|
1372
|
+
env.builder.usedComponents.set(tag, target);
|
|
1373
|
+
const attrs = [...env.extraAttrs];
|
|
1374
|
+
const callSiteProps = {};
|
|
1375
|
+
if (propsExpr !== undefined) {
|
|
1376
|
+
if (!ts.isObjectLiteralExpression(propsExpr)) {
|
|
1377
|
+
throw mpError(classSource.filePath, "createComponent \u7684 props \u5FC5\u987B\u662F\u5BF9\u8C61\u5B57\u9762\u91CF");
|
|
1378
|
+
}
|
|
1379
|
+
for (const property of propsExpr.properties) {
|
|
1380
|
+
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) {
|
|
1381
|
+
throw mpError(classSource.filePath, "\u7EC4\u4EF6 props \u53EA\u652F\u6301\u9759\u6001\u5C5E\u6027\u540D");
|
|
1382
|
+
}
|
|
1383
|
+
const key = property.name.text;
|
|
1384
|
+
const value = property.initializer;
|
|
1385
|
+
if (ts.isArrowFunction(value) || ts.isFunctionExpression(value)) {
|
|
1386
|
+
throw mpError(classSource.filePath, `\u7EC4\u4EF6 props \u4F20\u51FD\u6570\uFF08${key}\uFF09\u6682\u4E0D\u652F\u6301\u7F16\u8BD1\u5230\u5C0F\u7A0B\u5E8F\uFF0C\u8BF7\u6539\u7528 emitters + this.emit \u6A21\u5F0F`);
|
|
1387
|
+
}
|
|
1388
|
+
callSiteProps[key] = inferPropType(context, classSource, value, env);
|
|
1389
|
+
const folded = foldExpression(ts, value, env.scope.consts);
|
|
1390
|
+
if (folded !== undefined && folded !== null) {
|
|
1391
|
+
attrs.push(`${key}="${escapeAttr(literalToString(folded))}"`);
|
|
1392
|
+
} else {
|
|
1393
|
+
const binding = toBinding(bindingContext(context, classSource, env), value);
|
|
1394
|
+
attrs.push(`${key}="{{${binding}}}"`);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
const existing = context.callSites.get(tag) ?? [];
|
|
1398
|
+
existing.push(callSiteProps);
|
|
1399
|
+
context.callSites.set(tag, existing);
|
|
1400
|
+
}
|
|
1401
|
+
if (emittersExpr !== undefined) {
|
|
1402
|
+
if (!ts.isObjectLiteralExpression(emittersExpr)) {
|
|
1403
|
+
throw mpError(classSource.filePath, "emitters \u5FC5\u987B\u662F\u5BF9\u8C61\u5B57\u9762\u91CF");
|
|
1404
|
+
}
|
|
1405
|
+
for (const property of emittersExpr.properties) {
|
|
1406
|
+
if (!ts.isPropertyAssignment(property)) {
|
|
1407
|
+
throw mpError(classSource.filePath, "emitters \u53EA\u652F\u6301\u9759\u6001\u4E8B\u4EF6\u540D");
|
|
1408
|
+
}
|
|
1409
|
+
const eventName = ts.isIdentifier(property.name) || ts.isStringLiteral(property.name) ? property.name.text : undefined;
|
|
1410
|
+
if (eventName === undefined) {
|
|
1411
|
+
throw mpError(classSource.filePath, "emitters \u53EA\u652F\u6301\u9759\u6001\u4E8B\u4EF6\u540D");
|
|
1412
|
+
}
|
|
1413
|
+
const usage = compileEmitterHandler(context, classSource, property.initializer);
|
|
1414
|
+
if (!usage) {
|
|
1415
|
+
throw mpError(classSource.filePath, "emitters \u5904\u7406\u5668\u53EA\u652F\u6301 () => this.method() \u6216 (value) => this.method(value)");
|
|
1416
|
+
}
|
|
1417
|
+
usage.event = eventName;
|
|
1418
|
+
const key = `__transone_emitter_${eventName}_${env.builder.emitters.length}`;
|
|
1419
|
+
usage.key = key;
|
|
1420
|
+
env.builder.emitters.push(usage);
|
|
1421
|
+
attrs.push(`bind:${eventName}="${key}"`);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
if (directionsExpr !== undefined) {
|
|
1425
|
+
if (!ts.isObjectLiteralExpression(directionsExpr)) {
|
|
1426
|
+
throw mpError(classSource.filePath, "directions \u5FC5\u987B\u662F\u5BF9\u8C61\u5B57\u9762\u91CF");
|
|
1427
|
+
}
|
|
1428
|
+
const ifExpr = objectProperty(ts, directionsExpr, "if");
|
|
1429
|
+
if (ifExpr) {
|
|
1430
|
+
const folded = foldExpression(ts, ifExpr, env.scope.consts);
|
|
1431
|
+
if (folded === false) {
|
|
1432
|
+
return [];
|
|
1433
|
+
}
|
|
1434
|
+
if (folded !== true) {
|
|
1435
|
+
attrs.push(`${context.dialect.directivePrefix}if="{{${toBinding(bindingContext(context, classSource, env), ifExpr)}}}"`);
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
const openTag = attrs.length > 0 ? `<${tag} ${attrs.join(" ")}>` : `<${tag}>`;
|
|
1440
|
+
const lines = [indent(env.indent) + openTag];
|
|
1441
|
+
const childLines = buildNodeLines(context, classSource, childrenExpr ?? ts.factory.createArrayLiteralExpression([]), {
|
|
1442
|
+
...env,
|
|
1443
|
+
indent: env.indent + 1
|
|
1444
|
+
}, depth + 1);
|
|
1445
|
+
lines.push(...childLines);
|
|
1446
|
+
lines.push(indent(env.indent) + `</${tag}>`);
|
|
1447
|
+
return lines;
|
|
1448
|
+
}
|
|
1449
|
+
function compileSlot(context, classSource, node, env) {
|
|
1450
|
+
const nameExpr = node.arguments[0];
|
|
1451
|
+
if (!nameExpr) {
|
|
1452
|
+
return [indent(env.indent) + "<slot/>"];
|
|
1453
|
+
}
|
|
1454
|
+
const name = compileLiteralString(context, classSource, nameExpr, "slot \u540D\u79F0");
|
|
1455
|
+
return [indent(env.indent) + `<slot name="${name}"/>`];
|
|
1456
|
+
}
|
|
1457
|
+
function compileListener(context, classSource, eventName, handlerExpr, env) {
|
|
1458
|
+
const wxmlEvent = EVENT_MAP[eventName];
|
|
1459
|
+
if (!wxmlEvent) {
|
|
1460
|
+
throw mpError(classSource.filePath, `\u4E0D\u652F\u6301\u7684\u5C0F\u7A0B\u5E8F\u4E8B\u4EF6 "${eventName}"\uFF08\u652F\u6301: ${Object.keys(EVENT_MAP).join("/")}\uFF09`);
|
|
1461
|
+
}
|
|
1462
|
+
const method = compileHandlerMethod(context, classSource, handlerExpr);
|
|
1463
|
+
env.builder.handlers.add(method);
|
|
1464
|
+
return `${context.dialect.bindEvent(wxmlEvent)}="${method}"`;
|
|
1465
|
+
}
|
|
1466
|
+
function compileHandlerMethod(context, classSource, handlerExpr) {
|
|
1467
|
+
const { ts } = context;
|
|
1468
|
+
handlerExpr = unwrapParentheses(ts, handlerExpr);
|
|
1469
|
+
if (ts.isPropertyAccessExpression(handlerExpr) && isThisExpression(ts, handlerExpr.expression)) {
|
|
1470
|
+
return handlerExpr.name.text;
|
|
1471
|
+
}
|
|
1472
|
+
if (ts.isArrowFunction(handlerExpr)) {
|
|
1473
|
+
const call = singleMethodCall(ts, handlerExpr.body);
|
|
1474
|
+
if (call && call.args.length === 0) {
|
|
1475
|
+
return call.method;
|
|
1476
|
+
}
|
|
1477
|
+
const arg = call && call.args.length === 1 ? unwrapTypeAssertions(ts, call.args[0]) : undefined;
|
|
1478
|
+
if (call && call.args.length === 1 && handlerExpr.parameters.length === 1 && ts.isIdentifier(handlerExpr.parameters[0].name) && arg !== undefined && ts.isIdentifier(arg) && handlerExpr.parameters[0].name.text === arg.text) {
|
|
1479
|
+
return call.method;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
throw mpError(classSource.filePath, "\u4E8B\u4EF6\u5904\u7406\u5668\u5FC5\u987B\u662F () => this.method()\u3001this.method \u6216 (e) => this.method(e) \u5F62\u5F0F");
|
|
1483
|
+
}
|
|
1484
|
+
function compileEmitterHandler(context, _classSource, handlerExpr) {
|
|
1485
|
+
const { ts } = context;
|
|
1486
|
+
handlerExpr = unwrapParentheses(ts, handlerExpr);
|
|
1487
|
+
if (ts.isPropertyAccessExpression(handlerExpr) && isThisExpression(ts, handlerExpr.expression)) {
|
|
1488
|
+
return { event: "pending", method: handlerExpr.name.text, passArgs: true, key: "" };
|
|
1489
|
+
}
|
|
1490
|
+
if (!ts.isArrowFunction(handlerExpr)) {
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
const call = singleMethodCall(ts, handlerExpr.body);
|
|
1494
|
+
if (!call) {
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
if (call.args.length === 0) {
|
|
1498
|
+
return { event: "pending", method: call.method, passArgs: false, key: "" };
|
|
1499
|
+
}
|
|
1500
|
+
const arg = call.args.length === 1 ? unwrapTypeAssertions(ts, call.args[0]) : undefined;
|
|
1501
|
+
if (call.args.length === 1 && handlerExpr.parameters.length === 1 && ts.isIdentifier(handlerExpr.parameters[0].name) && arg !== undefined && ts.isIdentifier(arg) && handlerExpr.parameters[0].name.text === arg.text) {
|
|
1502
|
+
return { event: "pending", method: call.method, passArgs: true, key: "" };
|
|
1503
|
+
}
|
|
1504
|
+
return;
|
|
1505
|
+
}
|
|
1506
|
+
function singleMethodCall(ts, body) {
|
|
1507
|
+
let callExpr;
|
|
1508
|
+
if (ts.isCallExpression(body)) {
|
|
1509
|
+
callExpr = body;
|
|
1510
|
+
} else if (ts.isBlock(body)) {
|
|
1511
|
+
const statements = body.statements.filter((statement) => !ts.isEmptyStatement(statement));
|
|
1512
|
+
if (statements.length !== 1 || !ts.isExpressionStatement(statements[0])) {
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
const expression = statements[0].expression;
|
|
1516
|
+
if (!ts.isCallExpression(expression)) {
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
callExpr = expression;
|
|
1520
|
+
} else {
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
const callee = callExpr.expression;
|
|
1524
|
+
if (!ts.isPropertyAccessExpression(callee) || !isThisExpression(ts, callee.expression)) {
|
|
1525
|
+
return;
|
|
1526
|
+
}
|
|
1527
|
+
return { method: callee.name.text, args: callExpr.arguments };
|
|
1528
|
+
}
|
|
1529
|
+
function unwrapTypeAssertions(ts, expression) {
|
|
1530
|
+
let node = expression;
|
|
1531
|
+
for (;; ) {
|
|
1532
|
+
if (ts.isAsExpression(node)) {
|
|
1533
|
+
node = node.expression;
|
|
1534
|
+
continue;
|
|
1535
|
+
}
|
|
1536
|
+
if (ts.isTypeAssertionExpression(node)) {
|
|
1537
|
+
node = node.expression;
|
|
1538
|
+
continue;
|
|
1539
|
+
}
|
|
1540
|
+
if (ts.isNonNullExpression(node)) {
|
|
1541
|
+
node = node.expression;
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
return node;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
function compileClassAttr(context, classSource, value, env) {
|
|
1548
|
+
const { ts } = context;
|
|
1549
|
+
const folded = foldExpression(ts, value, env.scope.consts);
|
|
1550
|
+
if (typeof folded === "string") {
|
|
1551
|
+
const hoverClass = hoverClassName(folded, env.hoverSelectors);
|
|
1552
|
+
return hoverClass ? `class="${escapeAttr(folded)}" hover-class="${hoverClass}"` : `class="${escapeAttr(folded)}"`;
|
|
1553
|
+
}
|
|
1554
|
+
if (folded === null) {
|
|
1555
|
+
return "";
|
|
1556
|
+
}
|
|
1557
|
+
const text = rawTemplateText(ts, value);
|
|
1558
|
+
if (text !== undefined) {
|
|
1559
|
+
const hoverClass = hoverClassName(text, env.hoverSelectors);
|
|
1560
|
+
return hoverClass ? `class="${escapeAttr(text)}" hover-class="${hoverClass}"` : `class="${escapeAttr(text)}"`;
|
|
1561
|
+
}
|
|
1562
|
+
return `class="{{${toBinding(bindingContext(context, classSource, env), value)}}}"`;
|
|
1563
|
+
}
|
|
1564
|
+
function hoverClassName(className, hoverSelectors) {
|
|
1565
|
+
for (const single of className.split(/\s+/)) {
|
|
1566
|
+
if (single === "") {
|
|
1567
|
+
continue;
|
|
1568
|
+
}
|
|
1569
|
+
if (hoverSelectors.has(single) || hoverSelectors.has(`.${single}`)) {
|
|
1570
|
+
return `${single.replace(/^\./, "")}-hover`;
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
function compileStyleAttr(context, classSource, value, env) {
|
|
1576
|
+
const { ts } = context;
|
|
1577
|
+
const options = unwrapParentheses(ts, value);
|
|
1578
|
+
if (!ts.isObjectLiteralExpression(options)) {
|
|
1579
|
+
throw mpError(classSource.filePath, "style \u5C5E\u6027\u5FC5\u987B\u662F\u5BF9\u8C61\u5B57\u9762\u91CF");
|
|
1580
|
+
}
|
|
1581
|
+
const declarations = [];
|
|
1582
|
+
for (const property of options.properties) {
|
|
1583
|
+
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) {
|
|
1584
|
+
throw mpError(classSource.filePath, "style \u5C5E\u6027\u53EA\u652F\u6301\u9759\u6001\u952E");
|
|
1585
|
+
}
|
|
1586
|
+
const cssKey = property.name.text.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
1587
|
+
const folded = foldExpression(ts, property.initializer, env.scope.consts);
|
|
1588
|
+
if (typeof folded === "string" || typeof folded === "number") {
|
|
1589
|
+
declarations.push(`${cssKey}: ${String(folded)};`);
|
|
1590
|
+
} else {
|
|
1591
|
+
const unitSplit = splitUnitExpression(ts, property.initializer);
|
|
1592
|
+
if (unitSplit) {
|
|
1593
|
+
declarations.push(`${cssKey}: {{${toBinding(bindingContext(context, classSource, env), unitSplit.expr)}}}${unitSplit.unit};`);
|
|
1594
|
+
} else {
|
|
1595
|
+
declarations.push(`${cssKey}: {{${toBinding(bindingContext(context, classSource, env), property.initializer)}}};`);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
return `style="${escapeAttr(declarations.join(" "))}"`;
|
|
1600
|
+
}
|
|
1601
|
+
function splitUnitExpression(ts, expr) {
|
|
1602
|
+
expr = unwrapParentheses(ts, expr);
|
|
1603
|
+
if (!ts.isBinaryExpression(expr)) {
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
if (expr.operatorToken.kind !== ts.SyntaxKind.PlusToken) {
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
const right = unwrapParentheses(ts, expr.right);
|
|
1610
|
+
if (!ts.isStringLiteral(right)) {
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
const unit = right.text;
|
|
1614
|
+
if (!/^[a-z%]+$/i.test(unit)) {
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
return { expr: expr.left, unit };
|
|
1618
|
+
}
|
|
1619
|
+
function compileGenericAttr(context, classSource, key, value, env) {
|
|
1620
|
+
const { ts } = context;
|
|
1621
|
+
const attrName = wxmlAttrName(key);
|
|
1622
|
+
const folded = foldExpression(ts, value, env.scope.consts);
|
|
1623
|
+
if (folded !== undefined) {
|
|
1624
|
+
if (folded === false || folded === null) {
|
|
1625
|
+
return "";
|
|
1626
|
+
}
|
|
1627
|
+
if (folded === true) {
|
|
1628
|
+
return attrName;
|
|
1629
|
+
}
|
|
1630
|
+
return `${attrName}="${escapeAttr(literalToString(folded))}"`;
|
|
1631
|
+
}
|
|
1632
|
+
const text = rawTemplateText(ts, value);
|
|
1633
|
+
if (text !== undefined) {
|
|
1634
|
+
return `${attrName}="${escapeAttr(text)}"`;
|
|
1635
|
+
}
|
|
1636
|
+
return `${attrName}="{{${toBinding(bindingContext(context, classSource, env), value)}}}"`;
|
|
1637
|
+
}
|
|
1638
|
+
var KEBAB_ATTRS = {
|
|
1639
|
+
scrollX: "scroll-x",
|
|
1640
|
+
scrollY: "scroll-y",
|
|
1641
|
+
scrollIntoView: "scroll-into-view",
|
|
1642
|
+
scrollWithAnimation: "scroll-with-animation",
|
|
1643
|
+
scrollAnchoring: "scroll-anchoring",
|
|
1644
|
+
enableFlex: "enable-flex",
|
|
1645
|
+
enableScroll: "enable-scroll",
|
|
1646
|
+
enableZoom: "enable-zoom",
|
|
1647
|
+
enablePassive: "enable-passive",
|
|
1648
|
+
autoFocus: "auto-focus",
|
|
1649
|
+
confirmType: "confirm-type",
|
|
1650
|
+
confirmHold: "confirm-hold",
|
|
1651
|
+
cursorSpacing: "cursor-spacing",
|
|
1652
|
+
selectionStart: "selection-start",
|
|
1653
|
+
selectionEnd: "selection-end",
|
|
1654
|
+
showConfirmBar: "show-confirm-bar",
|
|
1655
|
+
adjustPosition: "adjust-position",
|
|
1656
|
+
holdKeyboard: "hold-keyboard",
|
|
1657
|
+
disableDefaultPadding: "disable-default-padding",
|
|
1658
|
+
disableAutoPush: "disable-auto-push",
|
|
1659
|
+
disableBeforeInput: "disable-before-input",
|
|
1660
|
+
showMarker: "show-marker",
|
|
1661
|
+
enablePublish: "enable-publish",
|
|
1662
|
+
markerCluster: "marker-cluster",
|
|
1663
|
+
showLocation: "show-location",
|
|
1664
|
+
showCompass: "show-compass",
|
|
1665
|
+
enableSatellite: "enable-satellite",
|
|
1666
|
+
enableTraffic: "enable-traffic",
|
|
1667
|
+
enableBuilding: "enable-building",
|
|
1668
|
+
enableRotate: "enable-rotate",
|
|
1669
|
+
enableOverlooking: "enable-overlooking",
|
|
1670
|
+
subKey: "sub-key",
|
|
1671
|
+
enableLazy: "enable-lazy",
|
|
1672
|
+
showMenuByLongpress: "show-menu-by-longpress",
|
|
1673
|
+
openType: "open-type",
|
|
1674
|
+
formType: "form-type",
|
|
1675
|
+
unitId: "unit-id",
|
|
1676
|
+
hoverClass: "hover-class",
|
|
1677
|
+
hoverStartTime: "hover-start-time",
|
|
1678
|
+
hoverStayTime: "hover-stay-time",
|
|
1679
|
+
hoverStopPropagation: "hover-stop-propagation",
|
|
1680
|
+
plain: "plain",
|
|
1681
|
+
loading: "loading",
|
|
1682
|
+
disabled: "disabled",
|
|
1683
|
+
size: "size"
|
|
1684
|
+
};
|
|
1685
|
+
function wxmlAttrName(key) {
|
|
1686
|
+
if (key === "href") {
|
|
1687
|
+
return "url";
|
|
1688
|
+
}
|
|
1689
|
+
if (key.startsWith("data") && key.length > 4) {
|
|
1690
|
+
return `data${key.slice(4).replace(/([A-Z])/g, "-$1").toLowerCase()}`;
|
|
1691
|
+
}
|
|
1692
|
+
return KEBAB_ATTRS[key] ?? key;
|
|
1693
|
+
}
|
|
1694
|
+
function compileLiteralString(context, classSource, value, what) {
|
|
1695
|
+
const { ts } = context;
|
|
1696
|
+
const folded = foldExpression(ts, value, new Map);
|
|
1697
|
+
if (typeof folded !== "string") {
|
|
1698
|
+
throw mpError(classSource.filePath, `${what}\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u5B57\u9762\u91CF`);
|
|
1699
|
+
}
|
|
1700
|
+
return folded;
|
|
1701
|
+
}
|
|
1702
|
+
function textContent(context, classSource, node, env) {
|
|
1703
|
+
const { ts } = context;
|
|
1704
|
+
node = unwrapParentheses(ts, node);
|
|
1705
|
+
if (ts.isStringLiteral(node)) {
|
|
1706
|
+
return escapeXml(node.text);
|
|
1707
|
+
}
|
|
1708
|
+
if (ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
1709
|
+
return node.text.includes("{{") ? node.text : escapeXml(node.text);
|
|
1710
|
+
}
|
|
1711
|
+
if (ts.isTemplateExpression(node)) {
|
|
1712
|
+
return `{{${toBinding(bindingContext(context, classSource, env), node)}}}`;
|
|
1713
|
+
}
|
|
1714
|
+
if (ts.isIdentifier(node)) {
|
|
1715
|
+
if (env.scope.params.has(node.text)) {
|
|
1716
|
+
return `{{${node.text}}}`;
|
|
1717
|
+
}
|
|
1718
|
+
const replacement = resolveIdentifierExpression(context, classSource, node, env);
|
|
1719
|
+
if (replacement) {
|
|
1720
|
+
return textContent(context, classSource, replacement, env);
|
|
1721
|
+
}
|
|
1722
|
+
throw mpError(classSource.filePath, `\u65E0\u6CD5\u89E3\u6790\u6A21\u677F\u6807\u8BC6\u7B26 "${node.text}"`);
|
|
1723
|
+
}
|
|
1724
|
+
if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {
|
|
1725
|
+
return `{{${toBinding(bindingContext(context, classSource, env), node)}}}`;
|
|
1726
|
+
}
|
|
1727
|
+
throw mpError(classSource.filePath, `\u4E0D\u652F\u6301\u7684\u6587\u672C\u8282\u70B9: ${node.getText().slice(0, 60)}`);
|
|
1728
|
+
}
|
|
1729
|
+
function isTextNode(ts, node) {
|
|
1730
|
+
return ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node) || ts.isTemplateExpression(node);
|
|
1731
|
+
}
|
|
1732
|
+
function resolveIdentifierExpression(_context, _classSource, node, env) {
|
|
1733
|
+
if (env.scope.locals.has(node.text)) {
|
|
1734
|
+
return env.scope.locals.get(node.text);
|
|
1735
|
+
}
|
|
1736
|
+
if (env.scope.consts.has(node.text)) {
|
|
1737
|
+
return env.scope.consts.get(node.text);
|
|
1738
|
+
}
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
function bindingContext(context, classSource, env) {
|
|
1742
|
+
return {
|
|
1743
|
+
ts: context.ts,
|
|
1744
|
+
scope: env.scope,
|
|
1745
|
+
filePath: classSource.filePath,
|
|
1746
|
+
onProp: (name) => env.builder.propsReferenced.add(name)
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
function callName2(ts, expression) {
|
|
1750
|
+
expression = unwrapParentheses(ts, expression);
|
|
1751
|
+
if (ts.isIdentifier(expression)) {
|
|
1752
|
+
return expression.text;
|
|
1753
|
+
}
|
|
1754
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
1755
|
+
return expression.name.text;
|
|
1756
|
+
}
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1759
|
+
function objectProperty(ts, object, key) {
|
|
1760
|
+
for (const property of object.properties) {
|
|
1761
|
+
if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.text === key) {
|
|
1762
|
+
return property.initializer;
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1767
|
+
function collectModuleConsts(context, classSource) {
|
|
1768
|
+
const consts = new Map;
|
|
1769
|
+
for (const statement of classSource.source.statements) {
|
|
1770
|
+
if (!context.ts.isVariableStatement(statement)) {
|
|
1771
|
+
continue;
|
|
1772
|
+
}
|
|
1773
|
+
const isConst = statement.declarationList.flags & context.ts.NodeFlags.Const;
|
|
1774
|
+
if (!isConst) {
|
|
1775
|
+
continue;
|
|
1776
|
+
}
|
|
1777
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
1778
|
+
if (context.ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
1779
|
+
consts.set(declaration.name.text, declaration.initializer);
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
return consts;
|
|
1784
|
+
}
|
|
1785
|
+
function collectFactoryOrigins(ts, source) {
|
|
1786
|
+
const origins = new Map;
|
|
1787
|
+
for (const statement of source.statements) {
|
|
1788
|
+
if (!ts.isImportDeclaration(statement)) {
|
|
1789
|
+
continue;
|
|
1790
|
+
}
|
|
1791
|
+
const specifier = statement.moduleSpecifier.getText().replace(/['"]/g, "");
|
|
1792
|
+
if (!specifier.includes("transone")) {
|
|
1793
|
+
continue;
|
|
1794
|
+
}
|
|
1795
|
+
const bindings = statement.importClause?.namedBindings;
|
|
1796
|
+
if (!bindings || !ts.isNamedImports(bindings)) {
|
|
1797
|
+
continue;
|
|
1798
|
+
}
|
|
1799
|
+
for (const element of bindings.elements) {
|
|
1800
|
+
const local = element.name.text;
|
|
1801
|
+
const original = element.propertyName?.text ?? local;
|
|
1802
|
+
if (ELEMENT_FACTORIES.has(original) || SPECIAL_CALLS.has(original)) {
|
|
1803
|
+
origins.set(local, original);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
return origins;
|
|
1808
|
+
}
|
|
1809
|
+
function inferPropType(context, _classSource, value, env) {
|
|
1810
|
+
const { ts } = context;
|
|
1811
|
+
const folded = foldExpression(ts, value, env.scope.consts);
|
|
1812
|
+
if (typeof folded === "string") {
|
|
1813
|
+
return "String";
|
|
1814
|
+
}
|
|
1815
|
+
if (typeof folded === "number") {
|
|
1816
|
+
return "Number";
|
|
1817
|
+
}
|
|
1818
|
+
if (typeof folded === "boolean") {
|
|
1819
|
+
return "Boolean";
|
|
1820
|
+
}
|
|
1821
|
+
if (Array.isArray(folded)) {
|
|
1822
|
+
return "Array";
|
|
1823
|
+
}
|
|
1824
|
+
if (folded !== undefined && typeof folded === "object") {
|
|
1825
|
+
return "Object";
|
|
1826
|
+
}
|
|
1827
|
+
return "null";
|
|
1828
|
+
}
|
|
1829
|
+
function rawTemplateText(ts, node) {
|
|
1830
|
+
node = unwrapParentheses(ts, node);
|
|
1831
|
+
if (ts.isNoSubstitutionTemplateLiteral(node) && node.text.includes("{{")) {
|
|
1832
|
+
return node.text;
|
|
1833
|
+
}
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
function literalToString(value) {
|
|
1837
|
+
return typeof value === "string" ? value : String(value);
|
|
1838
|
+
}
|
|
1839
|
+
function kebabCase(name) {
|
|
1840
|
+
const kebab = name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^A-Za-z0-9-]/g, "").toLowerCase();
|
|
1841
|
+
if (!kebab) {
|
|
1842
|
+
throw new Error(`\u65E0\u6CD5\u4ECE\u7C7B\u540D "${name}" \u751F\u6210\u7EC4\u4EF6\u6807\u7B7E\u540D`);
|
|
1843
|
+
}
|
|
1844
|
+
return kebab;
|
|
1845
|
+
}
|
|
1846
|
+
function escapeXml(value) {
|
|
1847
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1848
|
+
}
|
|
1849
|
+
function escapeAttr(value) {
|
|
1850
|
+
return escapeXml(value).replace(/"/g, """);
|
|
1851
|
+
}
|
|
1852
|
+
function indent(level) {
|
|
1853
|
+
return " ".repeat(level);
|
|
1854
|
+
}
|
|
1855
|
+
function findMethod(context, classSource, name) {
|
|
1856
|
+
const { ts } = context;
|
|
1857
|
+
return classSource.declaration.members.find((member) => ts.isMethodDeclaration(member) && member.name.getText() === name);
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
// src/mp/styles.ts
|
|
1861
|
+
var UNITLESS_PROPERTIES = new Set([
|
|
1862
|
+
"opacity",
|
|
1863
|
+
"zIndex",
|
|
1864
|
+
"fontWeight",
|
|
1865
|
+
"lineHeight",
|
|
1866
|
+
"flex",
|
|
1867
|
+
"flexGrow",
|
|
1868
|
+
"flexShrink",
|
|
1869
|
+
"order",
|
|
1870
|
+
"zoom",
|
|
1871
|
+
"scale",
|
|
1872
|
+
"transform",
|
|
1873
|
+
"animationIterationCount",
|
|
1874
|
+
"columnCount",
|
|
1875
|
+
"fontSizeAdjust"
|
|
1876
|
+
]);
|
|
1877
|
+
function compileStyles(context, classSource) {
|
|
1878
|
+
const { ts } = context;
|
|
1879
|
+
const method = findMethod(context, classSource, "initStyles");
|
|
1880
|
+
if (!method?.body) {
|
|
1881
|
+
return { style: "", global: "", hoverSelectors: new Set };
|
|
1882
|
+
}
|
|
1883
|
+
const consts = collectModuleConsts2(context, classSource);
|
|
1884
|
+
const entries = [];
|
|
1885
|
+
for (const statement of method.body.statements) {
|
|
1886
|
+
if (ts.isEmptyStatement(statement)) {
|
|
1887
|
+
continue;
|
|
1888
|
+
}
|
|
1889
|
+
if (!ts.isExpressionStatement(statement)) {
|
|
1890
|
+
throw mpError(classSource.filePath, "initStyles() \u53EA\u652F\u6301 this.styleManager.addStyle(...) \u8C03\u7528");
|
|
1891
|
+
}
|
|
1892
|
+
const expression = statement.expression;
|
|
1893
|
+
const entry = addStyleEntry(context, classSource, expression, consts);
|
|
1894
|
+
if (entry) {
|
|
1895
|
+
entries.push(entry);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
const local = [];
|
|
1899
|
+
const global = [];
|
|
1900
|
+
const hoverSelectors = new Set;
|
|
1901
|
+
for (const entry of entries) {
|
|
1902
|
+
const target = entry.selector === "body" ? global : local;
|
|
1903
|
+
target.push(renderStyle(entry, context.lengthUnit));
|
|
1904
|
+
if (entry.hover && entry.selector !== "body") {
|
|
1905
|
+
hoverSelectors.add(entry.selector);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
return { style: local.join(`
|
|
1909
|
+
`), global: global.join(`
|
|
1910
|
+
`), hoverSelectors };
|
|
1911
|
+
}
|
|
1912
|
+
function addStyleEntry(context, classSource, expression, consts) {
|
|
1913
|
+
const { ts } = context;
|
|
1914
|
+
if (!ts.isCallExpression(expression)) {
|
|
1915
|
+
throw mpError(classSource.filePath, "initStyles() \u53EA\u652F\u6301 this.styleManager.addStyle(...) \u8C03\u7528");
|
|
1916
|
+
}
|
|
1917
|
+
const callee = expression.expression;
|
|
1918
|
+
const manager = ts.isPropertyAccessExpression(callee) ? callee.expression : undefined;
|
|
1919
|
+
if (!ts.isPropertyAccessExpression(callee) || callee.name.text !== "addStyle" || !manager || !ts.isPropertyAccessExpression(manager) || !isThisExpression(ts, manager.expression) || manager.name.text !== "styleManager") {
|
|
1920
|
+
throw mpError(classSource.filePath, "initStyles() \u53EA\u652F\u6301 this.styleManager.addStyle(...) \u8C03\u7528");
|
|
1921
|
+
}
|
|
1922
|
+
const optionsExpr = expression.arguments[1];
|
|
1923
|
+
if (!optionsExpr || !ts.isObjectLiteralExpression(optionsExpr)) {
|
|
1924
|
+
throw mpError(classSource.filePath, "addStyle \u7684\u7B2C\u4E8C\u4E2A\u53C2\u6570\u5FC5\u987B\u662F\u5BF9\u8C61\u5B57\u9762\u91CF");
|
|
1925
|
+
}
|
|
1926
|
+
const selector = foldObjectString(ts, optionsExpr, "selector", consts);
|
|
1927
|
+
const properties = foldObjectRecord(ts, optionsExpr, "properties", consts);
|
|
1928
|
+
const hover = foldObjectRecord(ts, optionsExpr, "hover", consts);
|
|
1929
|
+
const media = foldMedia(ts, optionsExpr, consts);
|
|
1930
|
+
if (selector === undefined || properties === undefined) {
|
|
1931
|
+
throw mpError(classSource.filePath, "addStyle \u9700\u8981 selector \u4E0E properties \u5B57\u9762\u91CF");
|
|
1932
|
+
}
|
|
1933
|
+
return {
|
|
1934
|
+
selector,
|
|
1935
|
+
properties,
|
|
1936
|
+
...hover ? { hover } : {},
|
|
1937
|
+
...media ? { media } : {}
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
function foldObjectString(ts, object, key, consts) {
|
|
1941
|
+
const value = objectProperty2(ts, object, key);
|
|
1942
|
+
if (!value) {
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
const folded = foldExpression(ts, value, consts);
|
|
1946
|
+
return typeof folded === "string" ? folded : undefined;
|
|
1947
|
+
}
|
|
1948
|
+
function foldObjectRecord(ts, object, key, consts) {
|
|
1949
|
+
const value = objectProperty2(ts, object, key);
|
|
1950
|
+
if (!value) {
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
if (!ts.isObjectLiteralExpression(value)) {
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
const result = {};
|
|
1957
|
+
for (const property of value.properties) {
|
|
1958
|
+
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) {
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
const folded = foldExpression(ts, property.initializer, consts);
|
|
1962
|
+
if (typeof folded !== "string" && typeof folded !== "number") {
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
result[property.name.text] = folded;
|
|
1966
|
+
}
|
|
1967
|
+
return result;
|
|
1968
|
+
}
|
|
1969
|
+
function foldMedia(ts, object, consts) {
|
|
1970
|
+
const value = objectProperty2(ts, object, "media");
|
|
1971
|
+
if (!value) {
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1974
|
+
if (!ts.isObjectLiteralExpression(value)) {
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
const result = {};
|
|
1978
|
+
for (const property of value.properties) {
|
|
1979
|
+
if (!ts.isPropertyAssignment(property) || !ts.isStringLiteral(property.name) || !ts.isObjectLiteralExpression(property.initializer)) {
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
const props = {};
|
|
1983
|
+
for (const item of property.initializer.properties) {
|
|
1984
|
+
if (!ts.isPropertyAssignment(item) || !ts.isIdentifier(item.name)) {
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
const folded = foldExpression(ts, item.initializer, consts);
|
|
1988
|
+
if (typeof folded !== "string" && typeof folded !== "number") {
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
props[item.name.text] = folded;
|
|
1992
|
+
}
|
|
1993
|
+
result[property.name.text] = props;
|
|
1994
|
+
}
|
|
1995
|
+
return result;
|
|
1996
|
+
}
|
|
1997
|
+
function renderStyle(entry, lengthUnit) {
|
|
1998
|
+
const selector = entry.selector === "body" ? "page" : entry.selector;
|
|
1999
|
+
const parts = [];
|
|
2000
|
+
parts.push(`${selector} {
|
|
2001
|
+
${convertToCss(entry.properties, lengthUnit)}
|
|
2002
|
+
}`);
|
|
2003
|
+
if (entry.hover) {
|
|
2004
|
+
parts.push(`${selector}-hover {
|
|
2005
|
+
${convertToCss(entry.hover, lengthUnit)}
|
|
2006
|
+
}`);
|
|
2007
|
+
}
|
|
2008
|
+
for (const [query, properties] of Object.entries(entry.media ?? {})) {
|
|
2009
|
+
parts.push(`@media ${query} {
|
|
2010
|
+
${selector} {
|
|
2011
|
+
${convertToCss(properties, lengthUnit)}
|
|
2012
|
+
}
|
|
2013
|
+
}`);
|
|
2014
|
+
}
|
|
2015
|
+
return parts.join(`
|
|
2016
|
+
`);
|
|
2017
|
+
}
|
|
2018
|
+
function convertToCss(properties, lengthUnit) {
|
|
2019
|
+
return Object.entries(properties).map(([key, value]) => {
|
|
2020
|
+
const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
2021
|
+
return ` ${cssKey}: ${formatValue(key, value, lengthUnit)};`;
|
|
2022
|
+
}).join(`
|
|
2023
|
+
`);
|
|
2024
|
+
}
|
|
2025
|
+
function formatValue(key, value, lengthUnit) {
|
|
2026
|
+
if (typeof value !== "number") {
|
|
2027
|
+
return value;
|
|
2028
|
+
}
|
|
2029
|
+
if (value === 0 || UNITLESS_PROPERTIES.has(key)) {
|
|
2030
|
+
return String(value);
|
|
2031
|
+
}
|
|
2032
|
+
return lengthUnit === "rpx" ? `${value * 2}rpx` : `${value}px`;
|
|
2033
|
+
}
|
|
2034
|
+
function objectProperty2(ts, object, key) {
|
|
2035
|
+
for (const property of object.properties) {
|
|
2036
|
+
if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.text === key) {
|
|
2037
|
+
return property.initializer;
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
return;
|
|
2041
|
+
}
|
|
2042
|
+
function collectModuleConsts2(context, classSource) {
|
|
2043
|
+
const consts = new Map;
|
|
2044
|
+
for (const statement of classSource.source.statements) {
|
|
2045
|
+
if (!context.ts.isVariableStatement(statement)) {
|
|
2046
|
+
continue;
|
|
2047
|
+
}
|
|
2048
|
+
const isConst = statement.declarationList.flags & context.ts.NodeFlags.Const;
|
|
2049
|
+
if (!isConst) {
|
|
2050
|
+
continue;
|
|
2051
|
+
}
|
|
2052
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
2053
|
+
if (context.ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
2054
|
+
consts.set(declaration.name.text, declaration.initializer);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
return consts;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
// src/mp/state.ts
|
|
2062
|
+
function compileState(context, classSource) {
|
|
2063
|
+
const { ts } = context;
|
|
2064
|
+
const method = findMethod(context, classSource, "initState");
|
|
2065
|
+
if (!method?.body) {
|
|
2066
|
+
return "{}";
|
|
2067
|
+
}
|
|
2068
|
+
const consts = collectModuleConsts3(context, classSource);
|
|
2069
|
+
const locals = new Map;
|
|
2070
|
+
let returnStatement;
|
|
2071
|
+
for (const statement of method.body.statements) {
|
|
2072
|
+
if (ts.isVariableStatement(statement)) {
|
|
2073
|
+
const isConst = statement.declarationList.flags & ts.NodeFlags.Const;
|
|
2074
|
+
if (!isConst) {
|
|
2075
|
+
throw mpError(classSource.filePath, "initState() \u5185\u53EA\u652F\u6301 const \u58F0\u660E\uFF08data \u9700\u9759\u6001\u6C42\u503C\uFF09");
|
|
2076
|
+
}
|
|
2077
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
2078
|
+
if (ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
2079
|
+
locals.set(declaration.name.text, declaration.initializer);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
continue;
|
|
2083
|
+
}
|
|
2084
|
+
if (ts.isReturnStatement(statement)) {
|
|
2085
|
+
returnStatement = statement;
|
|
2086
|
+
continue;
|
|
2087
|
+
}
|
|
2088
|
+
throw mpError(classSource.filePath, `initState() \u5185\u4E0D\u652F\u6301\u7684\u8BED\u53E5\uFF08\u53EA\u652F\u6301 const \u58F0\u660E\u4E0E return\uFF09: ${statement.getText().slice(0, 60)}`);
|
|
2089
|
+
}
|
|
2090
|
+
if (!returnStatement?.expression) {
|
|
2091
|
+
throw mpError(classSource.filePath, "initState() \u5FC5\u987B\u4EE5 return \u8868\u8FBE\u5F0F\u7ED3\u675F");
|
|
2092
|
+
}
|
|
2093
|
+
const allConsts = new Map([...consts, ...locals]);
|
|
2094
|
+
const value = foldExpression(ts, returnStatement.expression, allConsts);
|
|
2095
|
+
if (value === undefined) {
|
|
2096
|
+
throw mpError(classSource.filePath, "initState() \u7684\u7ED3\u679C\u5FC5\u987B\u80FD\u9759\u6001\u6C42\u503C\uFF08\u53EA\u652F\u6301\u5B57\u9762\u91CF\u3001\u6A21\u5757/\u5C40\u90E8\u5E38\u91CF\u4E0E\u7B80\u5355\u8868\u8FBE\u5F0F\uFF09");
|
|
2097
|
+
}
|
|
2098
|
+
return JSON.stringify(value, null, 2);
|
|
2099
|
+
}
|
|
2100
|
+
function collectModuleConsts3(context, classSource) {
|
|
2101
|
+
const consts = new Map;
|
|
2102
|
+
for (const statement of classSource.source.statements) {
|
|
2103
|
+
if (!context.ts.isVariableStatement(statement)) {
|
|
2104
|
+
continue;
|
|
2105
|
+
}
|
|
2106
|
+
const isConst = statement.declarationList.flags & context.ts.NodeFlags.Const;
|
|
2107
|
+
if (!isConst) {
|
|
2108
|
+
continue;
|
|
2109
|
+
}
|
|
2110
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
2111
|
+
if (context.ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
2112
|
+
consts.set(declaration.name.text, declaration.initializer);
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return consts;
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
// src/mp/methods.ts
|
|
2120
|
+
var PAGE_LIFECYCLE = {
|
|
2121
|
+
beforeMount: "onLoad",
|
|
2122
|
+
onMounted: "onReady",
|
|
2123
|
+
onUnmounted: "onUnload",
|
|
2124
|
+
onShow: "onShow",
|
|
2125
|
+
onHide: "onHide",
|
|
2126
|
+
onPullDownRefresh: "onPullDownRefresh",
|
|
2127
|
+
onReachBottom: "onReachBottom",
|
|
2128
|
+
onShareAppMessage: "onShareAppMessage",
|
|
2129
|
+
onPageScroll: "onPageScroll",
|
|
2130
|
+
onResize: "onResize"
|
|
2131
|
+
};
|
|
2132
|
+
var COMPONENT_LIFECYCLE = {
|
|
2133
|
+
beforeMount: "created",
|
|
2134
|
+
onMounted: "attached",
|
|
2135
|
+
onUnmounted: "detached"
|
|
2136
|
+
};
|
|
2137
|
+
function compileMethods(context, classSource, usedNames, kind, customEvents) {
|
|
2138
|
+
const { ts } = context;
|
|
2139
|
+
const methods = new Map;
|
|
2140
|
+
for (const member of classSource.declaration.members) {
|
|
2141
|
+
if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name) && !isStatic(ts, member)) {
|
|
2142
|
+
methods.set(member.name.text, member);
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
const lifecycleMap = kind === "page" ? PAGE_LIFECYCLE : COMPONENT_LIFECYCLE;
|
|
2146
|
+
const seed = new Set(usedNames);
|
|
2147
|
+
for (const hook of Object.keys(lifecycleMap)) {
|
|
2148
|
+
if (methods.has(hook)) {
|
|
2149
|
+
seed.add(hook);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
const queue = [...seed];
|
|
2153
|
+
const visited = new Set;
|
|
2154
|
+
const entries = [];
|
|
2155
|
+
const lifecycleEntries = [];
|
|
2156
|
+
const emittedKeys = new Set;
|
|
2157
|
+
while (queue.length > 0) {
|
|
2158
|
+
const name = queue.shift();
|
|
2159
|
+
if (visited.has(name)) {
|
|
2160
|
+
continue;
|
|
2161
|
+
}
|
|
2162
|
+
visited.add(name);
|
|
2163
|
+
const declaration = methods.get(name);
|
|
2164
|
+
if (!declaration) {
|
|
2165
|
+
throw mpError(classSource.filePath, `\u672A\u627E\u5230\u4E8B\u4EF6\u5904\u7406\u65B9\u6CD5 "${name}"`);
|
|
2166
|
+
}
|
|
2167
|
+
const lifecycleKey = lifecycleMap[name];
|
|
2168
|
+
const key = lifecycleKey ?? name;
|
|
2169
|
+
if (emittedKeys.has(key)) {
|
|
2170
|
+
throw mpError(classSource.filePath, `\u65B9\u6CD5\u540D "${key}" \u4E0E\u5C0F\u7A0B\u5E8F\u751F\u547D\u5468\u671F\u94A9\u5B50\u51B2\u7A81`);
|
|
2171
|
+
}
|
|
2172
|
+
emittedKeys.add(key);
|
|
2173
|
+
const fn = compileMethod(context, classSource, declaration, kind, customEvents, queue);
|
|
2174
|
+
if (lifecycleKey) {
|
|
2175
|
+
lifecycleEntries.push({ key, fn });
|
|
2176
|
+
} else {
|
|
2177
|
+
entries.push({ key, fn });
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
return { methods: entries, lifecycle: lifecycleEntries };
|
|
2181
|
+
}
|
|
2182
|
+
function compileMethod(context, classSource, declaration, kind, customEvents, referencedMethods) {
|
|
2183
|
+
const { ts } = context;
|
|
2184
|
+
if (!declaration.body) {
|
|
2185
|
+
throw mpError(classSource.filePath, `\u65B9\u6CD5 ${declaration.name.getText()} \u7F3A\u5C11\u65B9\u6CD5\u4F53`);
|
|
2186
|
+
}
|
|
2187
|
+
const params = declaration.parameters.map((parameter) => ts.factory.createParameterDeclaration(undefined, parameter.dotDotDotToken, parameter.name, undefined, undefined, parameter.initializer));
|
|
2188
|
+
const modifiers = isAsync(ts, declaration) ? [ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword)] : undefined;
|
|
2189
|
+
const functionExpression = ts.factory.createFunctionExpression(modifiers, undefined, undefined, undefined, params, undefined, declaration.body);
|
|
2190
|
+
const consts = collectModuleConsts4(context, classSource);
|
|
2191
|
+
const locals = new Set;
|
|
2192
|
+
const transformerFactory = (transformContext) => {
|
|
2193
|
+
return (root) => visit(context, classSource, root, {
|
|
2194
|
+
transformContext,
|
|
2195
|
+
kind,
|
|
2196
|
+
customEvents,
|
|
2197
|
+
consts,
|
|
2198
|
+
locals,
|
|
2199
|
+
referencedMethods
|
|
2200
|
+
});
|
|
2201
|
+
};
|
|
2202
|
+
const result = ts.transform(functionExpression, [transformerFactory]);
|
|
2203
|
+
const transformed = result.transformed[0];
|
|
2204
|
+
result.dispose();
|
|
2205
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
2206
|
+
const printed = printer.printNode(ts.EmitHint.Expression, transformed, classSource.source);
|
|
2207
|
+
const transpiled = ts.transpileModule(printed, {
|
|
2208
|
+
compilerOptions: { target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.None },
|
|
2209
|
+
reportDiagnostics: false
|
|
2210
|
+
});
|
|
2211
|
+
return transpiled.outputText.trim();
|
|
2212
|
+
}
|
|
2213
|
+
function visit(context, classSource, node, state) {
|
|
2214
|
+
const { ts } = context;
|
|
2215
|
+
if (ts.isFunctionLike(node)) {
|
|
2216
|
+
for (const parameter of node.parameters) {
|
|
2217
|
+
if (ts.isIdentifier(parameter.name)) {
|
|
2218
|
+
state.locals.add(parameter.name.text);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
2223
|
+
state.locals.add(node.name.text);
|
|
2224
|
+
}
|
|
2225
|
+
if (ts.isBinaryExpression(node) && isAssignmentOperator(ts, node.operatorToken.kind)) {
|
|
2226
|
+
if (isWholeStateAssignment(ts, node.left)) {
|
|
2227
|
+
throw mpError(classSource.filePath, "\u4E0D\u652F\u6301\u66FF\u6362\u6574\u4E2A this.state\uFF0C\u8BF7\u6539\u7528 this.setState({ ... })");
|
|
2228
|
+
}
|
|
2229
|
+
const path = statePath(ts, node.left);
|
|
2230
|
+
if (path !== undefined) {
|
|
2231
|
+
const assignment = buildStateAssignment(ts, node, classSource.filePath);
|
|
2232
|
+
return ts.visitEachChild(assignment, (child) => visit(context, classSource, child, state), state.transformContext);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
if (ts.isCallExpression(node) && isThisMemberCall(ts, node, "setState")) {
|
|
2236
|
+
const call = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createThis(), "setData"), undefined, node.arguments);
|
|
2237
|
+
return ts.visitEachChild(call, (child) => visit(context, classSource, child, state), state.transformContext);
|
|
2238
|
+
}
|
|
2239
|
+
if (ts.isCallExpression(node) && isThisMemberCall(ts, node, "emit")) {
|
|
2240
|
+
if (state.kind !== "component") {
|
|
2241
|
+
throw mpError(classSource.filePath, "\u9875\u9762\u7EC4\u4EF6\u4E0D\u80FD\u4F7F\u7528 this.emit\uFF08\u7EC4\u4EF6\u95F4\u4E8B\u4EF6\u4EC5\u81EA\u5B9A\u4E49\u7EC4\u4EF6\u652F\u6301\uFF09");
|
|
2242
|
+
}
|
|
2243
|
+
const eventName = node.arguments[0];
|
|
2244
|
+
if (!ts.isStringLiteral(eventName)) {
|
|
2245
|
+
throw mpError(classSource.filePath, "this.emit \u7684\u4E8B\u4EF6\u540D\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u5B57\u9762\u91CF");
|
|
2246
|
+
}
|
|
2247
|
+
state.customEvents.add(eventName.text);
|
|
2248
|
+
const args = ts.factory.createArrayLiteralExpression(node.arguments.slice(1));
|
|
2249
|
+
const payload = ts.factory.createObjectLiteralExpression([
|
|
2250
|
+
ts.factory.createPropertyAssignment("args", args)
|
|
2251
|
+
]);
|
|
2252
|
+
const call = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createThis(), "triggerEvent"), undefined, [eventName, payload]);
|
|
2253
|
+
return ts.visitEachChild(call, (child) => visit(context, classSource, child, state), state.transformContext);
|
|
2254
|
+
}
|
|
2255
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && isThisExpression(ts, node.expression.expression)) {
|
|
2256
|
+
const methodName = node.expression.name.text;
|
|
2257
|
+
if (!BRIDGE_METHODS.has(methodName)) {
|
|
2258
|
+
state.referencedMethods.push(methodName);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
if (ts.isPropertyAccessExpression(node) && isThisExpression(ts, node.expression)) {
|
|
2262
|
+
if (node.name.text === "state") {
|
|
2263
|
+
return ts.factory.createPropertyAccessExpression(ts.factory.createThis(), "data");
|
|
2264
|
+
}
|
|
2265
|
+
if (node.name.text === "props") {
|
|
2266
|
+
if (state.kind !== "component") {
|
|
2267
|
+
throw mpError(classSource.filePath, "\u9875\u9762\u7EC4\u4EF6\u4E0D\u80FD\u8BBF\u95EE this.props");
|
|
2268
|
+
}
|
|
2269
|
+
return ts.factory.createPropertyAccessExpression(ts.factory.createThis(), "properties");
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
if (ts.isIdentifier(node) && !state.locals.has(node.text) && state.consts.has(node.text)) {
|
|
2273
|
+
const folded = foldExpression(ts, state.consts.get(node.text), state.consts);
|
|
2274
|
+
if (folded === undefined) {
|
|
2275
|
+
throw mpError(classSource.filePath, `\u65B9\u6CD5\u4E2D\u5F15\u7528\u4E86\u65E0\u6CD5\u9759\u6001\u6C42\u503C\u7684\u6A21\u5757\u5E38\u91CF "${node.text}"`);
|
|
2276
|
+
}
|
|
2277
|
+
return valueToNode(ts, folded);
|
|
2278
|
+
}
|
|
2279
|
+
return ts.visitEachChild(node, (child) => visit(context, classSource, child, state), state.transformContext);
|
|
2280
|
+
}
|
|
2281
|
+
var BRIDGE_METHODS = new Set(["emit", "setState", "setData", "triggerEvent"]);
|
|
2282
|
+
function buildStateAssignment(ts, node, filePath) {
|
|
2283
|
+
const path = statePath(ts, node.left);
|
|
2284
|
+
if (path === undefined) {
|
|
2285
|
+
throw new Error("internal: state assignment without state path");
|
|
2286
|
+
}
|
|
2287
|
+
const operator = node.operatorToken.kind;
|
|
2288
|
+
const isCompound = operator !== ts.SyntaxKind.EqualsToken;
|
|
2289
|
+
let value;
|
|
2290
|
+
if (isCompound) {
|
|
2291
|
+
const operatorText = compoundOperatorText(ts, operator);
|
|
2292
|
+
if (!operatorText) {
|
|
2293
|
+
throw new Error(`\u4E0D\u652F\u6301\u7684\u590D\u5408\u8D4B\u503C: ${node.operatorToken.getText()} (${filePath})`);
|
|
2294
|
+
}
|
|
2295
|
+
value = ts.factory.createBinaryExpression(node.left, operatorText, node.right);
|
|
2296
|
+
} else {
|
|
2297
|
+
value = node.right;
|
|
2298
|
+
}
|
|
2299
|
+
const key = ts.factory.createStringLiteral(path);
|
|
2300
|
+
const object = ts.factory.createObjectLiteralExpression([
|
|
2301
|
+
ts.factory.createPropertyAssignment(key, value)
|
|
2302
|
+
]);
|
|
2303
|
+
return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createThis(), "setData"), undefined, [object]);
|
|
2304
|
+
}
|
|
2305
|
+
function statePath(ts, left) {
|
|
2306
|
+
const tokens = [];
|
|
2307
|
+
let current = left;
|
|
2308
|
+
for (;; ) {
|
|
2309
|
+
if (ts.isPropertyAccessExpression(current)) {
|
|
2310
|
+
if (isThisExpression(ts, current.expression) && current.name.text === "state") {
|
|
2311
|
+
if (tokens.length === 0) {
|
|
2312
|
+
return;
|
|
2313
|
+
}
|
|
2314
|
+
return tokens.reverse().map((token) => token.startsWith("[") ? token : `.${token}`).join("").slice(1);
|
|
2315
|
+
}
|
|
2316
|
+
tokens.push(current.name.text);
|
|
2317
|
+
current = current.expression;
|
|
2318
|
+
continue;
|
|
2319
|
+
}
|
|
2320
|
+
if (ts.isElementAccessExpression(current)) {
|
|
2321
|
+
const argument = current.argumentExpression;
|
|
2322
|
+
if (!ts.isStringLiteral(argument) && !ts.isNumericLiteral(argument)) {
|
|
2323
|
+
return;
|
|
2324
|
+
}
|
|
2325
|
+
tokens.push(`[${argument.text}]`);
|
|
2326
|
+
current = current.expression;
|
|
2327
|
+
continue;
|
|
2328
|
+
}
|
|
2329
|
+
return;
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
function isAssignmentOperator(ts, kind) {
|
|
2333
|
+
return kind === ts.SyntaxKind.EqualsToken || kind === ts.SyntaxKind.PlusEqualsToken || kind === ts.SyntaxKind.MinusEqualsToken || kind === ts.SyntaxKind.AsteriskEqualsToken || kind === ts.SyntaxKind.SlashEqualsToken || kind === ts.SyntaxKind.PercentEqualsToken || kind === ts.SyntaxKind.LessThanLessThanEqualsToken || kind === ts.SyntaxKind.GreaterThanGreaterThanEqualsToken || kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken || kind === ts.SyntaxKind.AmpersandEqualsToken || kind === ts.SyntaxKind.BarEqualsToken || kind === ts.SyntaxKind.CaretEqualsToken || kind === ts.SyntaxKind.AsteriskAsteriskEqualsToken || kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken || kind === ts.SyntaxKind.BarBarEqualsToken || kind === ts.SyntaxKind.QuestionQuestionEqualsToken;
|
|
2334
|
+
}
|
|
2335
|
+
function isWholeStateAssignment(ts, left) {
|
|
2336
|
+
return ts.isPropertyAccessExpression(left) && isThisExpression(ts, left.expression) && left.name.text === "state";
|
|
2337
|
+
}
|
|
2338
|
+
function compoundOperatorText(ts, kind) {
|
|
2339
|
+
switch (kind) {
|
|
2340
|
+
case ts.SyntaxKind.PlusEqualsToken:
|
|
2341
|
+
return ts.SyntaxKind.PlusToken;
|
|
2342
|
+
case ts.SyntaxKind.MinusEqualsToken:
|
|
2343
|
+
return ts.SyntaxKind.MinusToken;
|
|
2344
|
+
case ts.SyntaxKind.AsteriskEqualsToken:
|
|
2345
|
+
return ts.SyntaxKind.AsteriskToken;
|
|
2346
|
+
case ts.SyntaxKind.SlashEqualsToken:
|
|
2347
|
+
return ts.SyntaxKind.SlashToken;
|
|
2348
|
+
case ts.SyntaxKind.PercentEqualsToken:
|
|
2349
|
+
return ts.SyntaxKind.PercentToken;
|
|
2350
|
+
default:
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
function isThisMemberCall(ts, node, name) {
|
|
2355
|
+
return ts.isPropertyAccessExpression(node.expression) && isThisExpression(ts, node.expression.expression) && node.expression.name.text === name;
|
|
2356
|
+
}
|
|
2357
|
+
function isStatic(ts, declaration) {
|
|
2358
|
+
return (declaration.modifiers ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword);
|
|
2359
|
+
}
|
|
2360
|
+
function isAsync(ts, declaration) {
|
|
2361
|
+
return (declaration.modifiers ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword);
|
|
2362
|
+
}
|
|
2363
|
+
function valueToNode(ts, value) {
|
|
2364
|
+
if (typeof value === "string") {
|
|
2365
|
+
return ts.factory.createStringLiteral(value);
|
|
2366
|
+
}
|
|
2367
|
+
if (typeof value === "number") {
|
|
2368
|
+
return ts.factory.createNumericLiteral(String(value));
|
|
2369
|
+
}
|
|
2370
|
+
if (typeof value === "boolean") {
|
|
2371
|
+
return value ? ts.factory.createTrue() : ts.factory.createFalse();
|
|
2372
|
+
}
|
|
2373
|
+
if (value === null) {
|
|
2374
|
+
return ts.factory.createNull();
|
|
2375
|
+
}
|
|
2376
|
+
if (Array.isArray(value)) {
|
|
2377
|
+
return ts.factory.createArrayLiteralExpression(value.map((item) => valueToNode(ts, item)));
|
|
2378
|
+
}
|
|
2379
|
+
return ts.factory.createObjectLiteralExpression(Object.entries(value).map(([key, item]) => ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(key), valueToNode(ts, item))));
|
|
2380
|
+
}
|
|
2381
|
+
function collectModuleConsts4(context, classSource) {
|
|
2382
|
+
const consts = new Map;
|
|
2383
|
+
for (const statement of classSource.source.statements) {
|
|
2384
|
+
if (!context.ts.isVariableStatement(statement)) {
|
|
2385
|
+
continue;
|
|
2386
|
+
}
|
|
2387
|
+
const isConst = statement.declarationList.flags & context.ts.NodeFlags.Const;
|
|
2388
|
+
if (!isConst) {
|
|
2389
|
+
continue;
|
|
2390
|
+
}
|
|
2391
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
2392
|
+
if (context.ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
2393
|
+
consts.set(declaration.name.text, declaration.initializer);
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
return consts;
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
// src/mp/inline.ts
|
|
2401
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
2402
|
+
function collectInlineModules(context, classSource) {
|
|
2403
|
+
const { ts } = context;
|
|
2404
|
+
const output = [];
|
|
2405
|
+
const seen = new Set;
|
|
2406
|
+
const stack = new Set;
|
|
2407
|
+
const walk = (source) => {
|
|
2408
|
+
const filePath = source.fileName;
|
|
2409
|
+
if (seen.has(filePath)) {
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
for (const statement of source.statements) {
|
|
2413
|
+
if (!ts.isImportDeclaration(statement)) {
|
|
2414
|
+
continue;
|
|
2415
|
+
}
|
|
2416
|
+
const specifier = statement.moduleSpecifier;
|
|
2417
|
+
if (!ts.isStringLiteral(specifier)) {
|
|
2418
|
+
continue;
|
|
2419
|
+
}
|
|
2420
|
+
const target = resolveRelativeModule(context, filePath, specifier.text);
|
|
2421
|
+
if (!target) {
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
if (stack.has(target)) {
|
|
2425
|
+
warn(context, `\u6A21\u5757\u5FAA\u73AF\u5F15\u7528\u5DF2\u8DF3\u8FC7: ${target}`);
|
|
2426
|
+
continue;
|
|
2427
|
+
}
|
|
2428
|
+
stack.add(target);
|
|
2429
|
+
walk(readSource(context, target));
|
|
2430
|
+
stack.delete(target);
|
|
2431
|
+
}
|
|
2432
|
+
seen.add(filePath);
|
|
2433
|
+
output.push(compileInlineModule(context, source));
|
|
2434
|
+
};
|
|
2435
|
+
walk(classSource.source);
|
|
2436
|
+
return output;
|
|
2437
|
+
}
|
|
2438
|
+
function resolveRelativeModule(context, fromFile, specifier) {
|
|
2439
|
+
if (!specifier.startsWith("./") && !specifier.startsWith("../")) {
|
|
2440
|
+
return null;
|
|
2441
|
+
}
|
|
2442
|
+
const base = specifier.endsWith(".ts") ? specifier : `${specifier}.ts`;
|
|
2443
|
+
const resolved = join2(dirname2(fromFile), base);
|
|
2444
|
+
if (isComponentFile(context, resolved)) {
|
|
2445
|
+
return null;
|
|
2446
|
+
}
|
|
2447
|
+
return resolved;
|
|
2448
|
+
}
|
|
2449
|
+
function isComponentFile(context, filePath) {
|
|
2450
|
+
const { ts } = context;
|
|
2451
|
+
const source = readSource(context, filePath);
|
|
2452
|
+
for (const statement of source.statements) {
|
|
2453
|
+
if (!ts.isClassDeclaration(statement)) {
|
|
2454
|
+
continue;
|
|
2455
|
+
}
|
|
2456
|
+
const name = statement.name?.text;
|
|
2457
|
+
if (!name) {
|
|
2458
|
+
continue;
|
|
2459
|
+
}
|
|
2460
|
+
const isExported2 = statement.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
|
|
2461
|
+
if (!isExported2) {
|
|
2462
|
+
continue;
|
|
2463
|
+
}
|
|
2464
|
+
const heritage = statement.heritageClauses?.some((clause) => clause.types.some((type) => {
|
|
2465
|
+
const expr = type.expression;
|
|
2466
|
+
if (!ts.isIdentifier(expr)) {
|
|
2467
|
+
return false;
|
|
2468
|
+
}
|
|
2469
|
+
return expr.text === "Component" || expr.text.endsWith("Component");
|
|
2470
|
+
}));
|
|
2471
|
+
if (heritage) {
|
|
2472
|
+
return true;
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
return false;
|
|
2476
|
+
}
|
|
2477
|
+
function compileInlineModule(context, source) {
|
|
2478
|
+
const { ts } = context;
|
|
2479
|
+
const kept = [];
|
|
2480
|
+
for (const statement of source.statements) {
|
|
2481
|
+
if (ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement) || ts.isExportAssignment(statement) || ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement)) {
|
|
2482
|
+
continue;
|
|
2483
|
+
}
|
|
2484
|
+
kept.push(statement);
|
|
2485
|
+
}
|
|
2486
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
2487
|
+
const printed = printer.printList(ts.ListFormat.MultiLine, ts.factory.createNodeArray(kept), source);
|
|
2488
|
+
const transpiled = ts.transpileModule(printed, {
|
|
2489
|
+
compilerOptions: {
|
|
2490
|
+
target: ts.ScriptTarget.ESNext,
|
|
2491
|
+
module: ts.ModuleKind.ES2015
|
|
2492
|
+
},
|
|
2493
|
+
reportDiagnostics: false
|
|
2494
|
+
});
|
|
2495
|
+
return transpiled.outputText.replace(/^export\s+/gm, "").trim();
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// src/mp/compile.ts
|
|
2499
|
+
function compileUnit(context, classSource, options) {
|
|
2500
|
+
const { kind, name } = options;
|
|
2501
|
+
if (kind === "component") {
|
|
2502
|
+
const cached = context.components.get(name);
|
|
2503
|
+
if (cached) {
|
|
2504
|
+
return cached;
|
|
2505
|
+
}
|
|
2506
|
+
if (context.compiling.has(name)) {
|
|
2507
|
+
throw mpError(classSource.filePath, `\u7EC4\u4EF6\u5FAA\u73AF\u5F15\u7528: ${name}`);
|
|
2508
|
+
}
|
|
2509
|
+
context.compiling.add(name);
|
|
2510
|
+
}
|
|
2511
|
+
try {
|
|
2512
|
+
const styles = compileStyles(context, classSource);
|
|
2513
|
+
const { template, builder } = compileTemplate(context, classSource, kind, styles.hoverSelectors);
|
|
2514
|
+
const data = compileState(context, classSource);
|
|
2515
|
+
const usedNames = new Set(builder.handlers);
|
|
2516
|
+
for (const emitter of builder.emitters) {
|
|
2517
|
+
usedNames.add(emitter.method);
|
|
2518
|
+
}
|
|
2519
|
+
const customEvents = new Set;
|
|
2520
|
+
const inlineModules = collectInlineModules(context, classSource);
|
|
2521
|
+
const compiledMethods = compileMethods(context, classSource, usedNames, kind, customEvents);
|
|
2522
|
+
const methods = [...compiledMethods.methods];
|
|
2523
|
+
for (const emitter of builder.emitters) {
|
|
2524
|
+
const key = emitter.key ?? `__transone_emitter_${emitter.event}`;
|
|
2525
|
+
const fn = emitter.passArgs ? `function(e) { this.${emitter.method}(...e.detail.args); }` : `function() { this.${emitter.method}(); }`;
|
|
2526
|
+
methods.push({ key, fn });
|
|
2527
|
+
}
|
|
2528
|
+
const usingComponents = {};
|
|
2529
|
+
for (const [tag, source] of builder.usedComponents) {
|
|
2530
|
+
compileUnit(context, source, { kind: "component", name: tag });
|
|
2531
|
+
usingComponents[tag] = `/components/${tag}/${tag}`;
|
|
2532
|
+
}
|
|
2533
|
+
const unit = {
|
|
2534
|
+
kind,
|
|
2535
|
+
name,
|
|
2536
|
+
template,
|
|
2537
|
+
style: styles.style,
|
|
2538
|
+
globalStyle: styles.global,
|
|
2539
|
+
data,
|
|
2540
|
+
properties: {},
|
|
2541
|
+
propsReferenced: builder.propsReferenced,
|
|
2542
|
+
methods,
|
|
2543
|
+
lifecycle: compiledMethods.lifecycle,
|
|
2544
|
+
customEvents: [...customEvents],
|
|
2545
|
+
usingComponents,
|
|
2546
|
+
inlineModules
|
|
2547
|
+
};
|
|
2548
|
+
if (kind === "component") {
|
|
2549
|
+
context.components.set(name, unit);
|
|
2550
|
+
}
|
|
2551
|
+
return unit;
|
|
2552
|
+
} finally {
|
|
2553
|
+
if (kind === "component") {
|
|
2554
|
+
context.compiling.delete(name);
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
function finalizeComponentProperties(context) {
|
|
2559
|
+
for (const [tag, unit] of context.components) {
|
|
2560
|
+
const properties = new Map;
|
|
2561
|
+
for (const callSite of context.callSites.get(tag) ?? []) {
|
|
2562
|
+
for (const [name, type] of Object.entries(callSite)) {
|
|
2563
|
+
if (!properties.has(name) || properties.get(name) === "null") {
|
|
2564
|
+
properties.set(name, type);
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
for (const name of unit.propsReferenced) {
|
|
2569
|
+
if (!properties.has(name)) {
|
|
2570
|
+
properties.set(name, "null");
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
unit.properties = Object.fromEntries(properties);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2577
|
+
// src/mp/jsgen.ts
|
|
2578
|
+
var GENERATED_HEADER = (dialectId) => `// \u7531 transone build --target ${dialectId} \u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u7F16\u8F91`;
|
|
2579
|
+
function inlinePreamble(unit) {
|
|
2580
|
+
if (unit.inlineModules.length === 0) {
|
|
2581
|
+
return "";
|
|
2582
|
+
}
|
|
2583
|
+
return unit.inlineModules.join(`
|
|
2584
|
+
|
|
2585
|
+
`) + `
|
|
2586
|
+
|
|
2587
|
+
`;
|
|
2588
|
+
}
|
|
2589
|
+
function generatePageJs(unit, dialect) {
|
|
2590
|
+
const parts = [
|
|
2591
|
+
GENERATED_HEADER(dialect.id),
|
|
2592
|
+
inlinePreamble(unit),
|
|
2593
|
+
"Page({",
|
|
2594
|
+
` data: ${embedData(unit.data)},`
|
|
2595
|
+
];
|
|
2596
|
+
for (const entry of [...unit.methods, ...unit.lifecycle]) {
|
|
2597
|
+
parts.push(` ${JSON.stringify(entry.key)}: ${entry.fn},`);
|
|
2598
|
+
}
|
|
2599
|
+
parts.push("});");
|
|
2600
|
+
return parts.join(`
|
|
2601
|
+
`) + `
|
|
2602
|
+
`;
|
|
2603
|
+
}
|
|
2604
|
+
function generateComponentJs(unit, dialect) {
|
|
2605
|
+
const parts = [
|
|
2606
|
+
GENERATED_HEADER(dialect.id),
|
|
2607
|
+
inlinePreamble(unit),
|
|
2608
|
+
"Component({"
|
|
2609
|
+
];
|
|
2610
|
+
parts.push(` properties: ${generatePropertiesSource(unit.properties)},`);
|
|
2611
|
+
parts.push(` data: ${embedData(unit.data)},`);
|
|
2612
|
+
parts.push(" methods: {");
|
|
2613
|
+
for (const entry of unit.methods) {
|
|
2614
|
+
parts.push(` ${JSON.stringify(entry.key)}: ${entry.fn},`);
|
|
2615
|
+
}
|
|
2616
|
+
parts.push(" },");
|
|
2617
|
+
if (unit.lifecycle.length > 0) {
|
|
2618
|
+
parts.push(" lifetimes: {");
|
|
2619
|
+
for (const entry of unit.lifecycle) {
|
|
2620
|
+
parts.push(` ${JSON.stringify(entry.key)}: ${entry.fn},`);
|
|
2621
|
+
}
|
|
2622
|
+
parts.push(" },");
|
|
2623
|
+
}
|
|
2624
|
+
parts.push("});");
|
|
2625
|
+
return parts.join(`
|
|
2626
|
+
`) + `
|
|
2627
|
+
`;
|
|
2628
|
+
}
|
|
2629
|
+
function embedData(data) {
|
|
2630
|
+
const body = data.trim().replace(/^\{/, "").replace(/\}$/, "").trim();
|
|
2631
|
+
return `{
|
|
2632
|
+
${body.replace(/\n/g, `
|
|
2633
|
+
`)}
|
|
2634
|
+
}`;
|
|
2635
|
+
}
|
|
2636
|
+
function generatePropertiesSource(properties) {
|
|
2637
|
+
const entries = Object.entries(properties);
|
|
2638
|
+
if (entries.length === 0) {
|
|
2639
|
+
return "{}";
|
|
2640
|
+
}
|
|
2641
|
+
const lines = entries.map(([name, type]) => ` ${JSON.stringify(name)}: { type: ${type === "null" ? "null" : type}, value: '' },`);
|
|
2642
|
+
return `{
|
|
2643
|
+
${lines.join(`
|
|
2644
|
+
`)}
|
|
2645
|
+
}`;
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
// src/mp/build-mp.ts
|
|
2649
|
+
var GENERATED_COMMENT = (dialectId) => `\u7531 transone build --target ${dialectId} \u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u7F16\u8F91`;
|
|
2650
|
+
async function buildMiniProgram(config, dialect) {
|
|
2651
|
+
const mp = config.mp;
|
|
2652
|
+
if (!mp) {
|
|
2653
|
+
throw new Error("Mini program build requires config.mp");
|
|
2654
|
+
}
|
|
2655
|
+
const ts = await loadTypescript();
|
|
2656
|
+
const context = {
|
|
2657
|
+
ts,
|
|
2658
|
+
root: config.root,
|
|
2659
|
+
files: new Map,
|
|
2660
|
+
components: new Map,
|
|
2661
|
+
compiling: new Set,
|
|
2662
|
+
callSites: new Map,
|
|
2663
|
+
lengthUnit: mp.lengthUnit,
|
|
2664
|
+
dialect,
|
|
2665
|
+
warnings: []
|
|
2666
|
+
};
|
|
2667
|
+
const pages = [];
|
|
2668
|
+
for (const [route, entry] of Object.entries(mp.pages)) {
|
|
2669
|
+
const rootClass = findRootClass(context, entry);
|
|
2670
|
+
const location = pageLocation(route);
|
|
2671
|
+
const unit = compileUnit(context, rootClass, {
|
|
2672
|
+
kind: "page",
|
|
2673
|
+
name: location.name
|
|
2674
|
+
});
|
|
2675
|
+
pages.push({ route, unit });
|
|
2676
|
+
}
|
|
2677
|
+
finalizeComponentProperties(context);
|
|
2678
|
+
for (const warning of context.warnings) {
|
|
2679
|
+
console.warn(`[transone mp] ${warning}`);
|
|
2680
|
+
}
|
|
2681
|
+
const outDir = mp.outDir;
|
|
2682
|
+
await rm(outDir, { recursive: true, force: true });
|
|
2683
|
+
await mkdir(outDir, { recursive: true });
|
|
2684
|
+
const assetsBuilt = [];
|
|
2685
|
+
const write = async (path, content) => {
|
|
2686
|
+
const target = join3(outDir, path);
|
|
2687
|
+
await mkdir(dirname3(target), { recursive: true });
|
|
2688
|
+
await writeFile(target, content, "utf8");
|
|
2689
|
+
assetsBuilt.push(target);
|
|
2690
|
+
};
|
|
2691
|
+
await write(dialect.projectConfigFile, `${JSON.stringify(dialect.buildProjectConfig(mp, basename(config.root)), null, 2)}
|
|
2692
|
+
`);
|
|
2693
|
+
await write("app.json", `${JSON.stringify({
|
|
2694
|
+
pages: pages.map(({ route }) => appPagePath(route)),
|
|
2695
|
+
window: {
|
|
2696
|
+
...dialect.windowDefaults(mp.navigationBarTitleText),
|
|
2697
|
+
...mp.window
|
|
2698
|
+
},
|
|
2699
|
+
...mp.tabBar !== undefined ? { tabBar: mp.tabBar } : {},
|
|
2700
|
+
...mp.appExtra,
|
|
2701
|
+
...dialect.appJsonExtras()
|
|
2702
|
+
}, null, 2)}
|
|
2703
|
+
`);
|
|
2704
|
+
await write("app.js", `App(${JSON.stringify(mp.globalData !== undefined ? { globalData: mp.globalData } : {})});
|
|
2705
|
+
`);
|
|
2706
|
+
if (dialect.sitemap) {
|
|
2707
|
+
await write("sitemap.json", `${JSON.stringify({
|
|
2708
|
+
desc: GENERATED_COMMENT(dialect.id),
|
|
2709
|
+
rules: [{ action: "allow", page: "*" }]
|
|
2710
|
+
}, null, 2)}
|
|
2711
|
+
`);
|
|
2712
|
+
}
|
|
2713
|
+
const globalStyles = new Set;
|
|
2714
|
+
for (const { unit } of pages) {
|
|
2715
|
+
if (unit.globalStyle) {
|
|
2716
|
+
globalStyles.add(unit.globalStyle);
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
await write(dialect.appStyleFile, `${[...globalStyles].join(`
|
|
2720
|
+
`)}
|
|
2721
|
+
`);
|
|
2722
|
+
for (const { route, unit } of pages) {
|
|
2723
|
+
const base = pageFileBase(route);
|
|
2724
|
+
await write(`pages/${base}.${dialect.templateExt}`, unit.template);
|
|
2725
|
+
await write(`pages/${base}.${dialect.styleExt}`, `${unit.style}
|
|
2726
|
+
`);
|
|
2727
|
+
await write(`pages/${base}.js`, generatePageJs(unit, dialect));
|
|
2728
|
+
await write(`pages/${base}.json`, `${JSON.stringify({
|
|
2729
|
+
usingComponents: unit.usingComponents,
|
|
2730
|
+
...mp.pageExtra?.[route]
|
|
2731
|
+
}, null, 2)}
|
|
2732
|
+
`);
|
|
2733
|
+
}
|
|
2734
|
+
for (const [tag, unit] of context.components) {
|
|
2735
|
+
await write(`components/${tag}/${tag}.${dialect.templateExt}`, unit.template);
|
|
2736
|
+
await write(`components/${tag}/${tag}.${dialect.styleExt}`, `${unit.style}
|
|
2737
|
+
`);
|
|
2738
|
+
await write(`components/${tag}/${tag}.js`, generateComponentJs(unit, dialect));
|
|
2739
|
+
await write(`components/${tag}/${tag}.json`, `${JSON.stringify(dialect.componentJson(unit.usingComponents), null, 2)}
|
|
2740
|
+
`);
|
|
2741
|
+
}
|
|
2742
|
+
if (existsSync2(mp.publicDir)) {
|
|
2743
|
+
for (const file of await listFiles(mp.publicDir)) {
|
|
2744
|
+
const target = join3(outDir, file);
|
|
2745
|
+
if (!existsSync2(target)) {
|
|
2746
|
+
await cp(join3(mp.publicDir, file), target, {
|
|
2747
|
+
recursive: true,
|
|
2748
|
+
force: true,
|
|
2749
|
+
errorOnExist: false
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
return {
|
|
2755
|
+
root: config.root,
|
|
2756
|
+
outDir: resolve2(outDir),
|
|
2757
|
+
assetsBuilt
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
function pageLocation(route) {
|
|
2761
|
+
const segments = route.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
2762
|
+
if (segments.length === 0) {
|
|
2763
|
+
return { directory: "", name: "index" };
|
|
2764
|
+
}
|
|
2765
|
+
const name = segments[segments.length - 1];
|
|
2766
|
+
const directory = segments.slice(0, -1).join("/");
|
|
2767
|
+
return { directory, name };
|
|
2768
|
+
}
|
|
2769
|
+
function pageFileBase(route) {
|
|
2770
|
+
const location = pageLocation(route);
|
|
2771
|
+
const directory = location.directory === "" ? location.name : `${location.directory}/${location.name}`;
|
|
2772
|
+
return `${directory}/${location.name}`;
|
|
2773
|
+
}
|
|
2774
|
+
function appPagePath(route) {
|
|
2775
|
+
return `pages/${pageFileBase(route)}`;
|
|
2776
|
+
}
|
|
2777
|
+
async function listFiles(root, dir = root) {
|
|
2778
|
+
const out = [];
|
|
2779
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
2780
|
+
for (const entry of entries) {
|
|
2781
|
+
const abs = join3(dir, entry.name);
|
|
2782
|
+
if (entry.isDirectory()) {
|
|
2783
|
+
out.push(...await listFiles(root, abs));
|
|
2784
|
+
} else {
|
|
2785
|
+
out.push(relative(root, abs));
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
return out;
|
|
2789
|
+
}
|
|
2790
|
+
export {
|
|
2791
|
+
buildMiniProgram
|
|
2792
|
+
};
|
|
2793
|
+
|
|
2794
|
+
//# debugId=1B46276CC3CBABAA64756E2164756E21
|
|
2795
|
+
//# sourceMappingURL=build-mp-kcnx989m.js.map
|