@weapp-vite/volar 2.0.8 → 2.1.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 +45 -38
- package/dist/index.cjs +117 -20
- package/dist/index.mjs +117 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,58 +1,65 @@
|
|
|
1
1
|
# @weapp-vite/volar
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 1. 简介
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`@weapp-vite/volar` 是 `weapp-vite` 的 Volar 语言服务插件,用来给小程序 Vue SFC 中的自定义块和相关宏提供更准确的类型、补全和诊断能力。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
它主要覆盖:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- `<json>` 自定义块的 schema 与类型提示
|
|
10
|
+
- `definePageJson` / `defineComponentJson` 等配置宏配套体验
|
|
11
|
+
- `wxs` 模块声明补全
|
|
12
|
+
- `script setup` 中为 weapp-vite / wevu 注入的额外声明
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
pnpm add -D @weapp-vite/volar
|
|
15
|
-
# or
|
|
16
|
-
yarn add -D @weapp-vite/volar
|
|
17
|
-
```
|
|
14
|
+
## 2. 安装方式
|
|
15
|
+
|
|
16
|
+
大多数情况下不需要单独安装。
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
`weapp-vite` 已经依赖并自动启用这个插件,项目里通常只需要按文档配置 `tsconfig.json` / `jsconfig.json` 即可。
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
如果你要在非标准工程里单独集成,可以安装:
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add -D @weapp-vite/volar @weapp-core/schematics
|
|
24
|
+
```
|
|
24
25
|
|
|
25
|
-
##
|
|
26
|
+
## 3. 常见配置
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"vueCompilerOptions": {
|
|
31
|
+
"plugins": ["weapp-vite/volar"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
> **注意**:更完整的编辑器接入方式,请优先参考 `weapp-vite` 主包文档中的 Volar 章节。
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
# 安装依赖
|
|
37
|
-
pnpm install
|
|
38
|
+
## 4. 提供的能力
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
| 能力 | 说明 |
|
|
41
|
+
| ----------------------- | ------------------------------------------------------ |
|
|
42
|
+
| `<json>` 块诊断 | 根据 App / Page / Component 语义提供 schema 与类型校验 |
|
|
43
|
+
| `script setup` 声明增强 | 自动补齐 weapp 相关额外声明 |
|
|
44
|
+
| `wxs` 模块名收集 | 让模板与脚本中的 `wxs` 使用获得更稳定的类型体验 |
|
|
45
|
+
| 自定义块嵌入代码 | 让 Volar 能识别并处理额外代码片段 |
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
pnpm build
|
|
47
|
+
## 5. 适用场景
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
- 在 `.vue` 文件里直接编写小程序页面 / 组件配置
|
|
50
|
+
- 使用 `definePageJson`、`defineComponentJson` 等宏
|
|
51
|
+
- 需要让 VS Code / Volar 正确理解 weapp-vite 的自定义块与扩展语义
|
|
48
52
|
|
|
49
|
-
##
|
|
53
|
+
## 6. 本地开发
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
+
```bash
|
|
56
|
+
pnpm --filter @weapp-vite/volar build
|
|
57
|
+
pnpm --filter @weapp-vite/volar test
|
|
58
|
+
pnpm --filter @weapp-vite/volar typecheck
|
|
59
|
+
```
|
|
55
60
|
|
|
56
|
-
##
|
|
61
|
+
## 7. 相关链接
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
- 详细用法:[./USAGE.md](./USAGE.md)
|
|
64
|
+
- 主包文档:[../weapp-vite/docs/volar.md](../weapp-vite/docs/volar.md)
|
|
65
|
+
- `weapp-vite`:[../weapp-vite/README.md](../weapp-vite/README.md)
|
package/dist/index.cjs
CHANGED
|
@@ -329,15 +329,18 @@ function unwrapParenthesizedExpression(node, tsModule) {
|
|
|
329
329
|
while (tsModule.isParenthesizedExpression(current)) current = current.expression;
|
|
330
330
|
return current;
|
|
331
331
|
}
|
|
332
|
-
function
|
|
332
|
+
function findReturnedExpression(node, tsModule) {
|
|
333
333
|
if (tsModule.isObjectLiteralExpression(node)) return node;
|
|
334
|
-
if (!tsModule.isBlock(node)) return;
|
|
334
|
+
if (!tsModule.isBlock(node)) return node;
|
|
335
335
|
for (const statement of node.statements) {
|
|
336
336
|
if (!tsModule.isReturnStatement(statement) || !statement.expression) continue;
|
|
337
|
-
|
|
338
|
-
if (tsModule.isObjectLiteralExpression(expression)) return expression;
|
|
337
|
+
return unwrapParenthesizedExpression(statement.expression, tsModule);
|
|
339
338
|
}
|
|
340
339
|
}
|
|
340
|
+
function findReturnedObjectLiteral(node, tsModule) {
|
|
341
|
+
const expression = findReturnedExpression(node, tsModule);
|
|
342
|
+
return expression && tsModule.isObjectLiteralExpression(expression) ? expression : void 0;
|
|
343
|
+
}
|
|
341
344
|
function extractDefineOptionsObjectLiteral(node, tsModule) {
|
|
342
345
|
if (!tsModule.isIdentifier(node.expression) || node.expression.text !== "defineOptions") return;
|
|
343
346
|
const [firstArg] = node.arguments;
|
|
@@ -346,20 +349,90 @@ function extractDefineOptionsObjectLiteral(node, tsModule) {
|
|
|
346
349
|
if (tsModule.isObjectLiteralExpression(arg)) return arg;
|
|
347
350
|
if (tsModule.isArrowFunction(arg) || tsModule.isFunctionExpression(arg)) return findReturnedObjectLiteral(arg.body, tsModule);
|
|
348
351
|
}
|
|
349
|
-
function
|
|
350
|
-
|
|
352
|
+
function setBindingType(map, name, typeText) {
|
|
353
|
+
if (!map.has(name)) map.set(name, typeText);
|
|
354
|
+
}
|
|
355
|
+
function getRuntimeConstructorType(node, tsModule) {
|
|
356
|
+
if (tsModule.isIdentifier(node)) {
|
|
357
|
+
if (node.text === "String") return "string";
|
|
358
|
+
if (node.text === "Number") return "number";
|
|
359
|
+
if (node.text === "Boolean") return "boolean";
|
|
360
|
+
if (node.text === "Array") return "any[]";
|
|
361
|
+
if (node.text === "Object") return "Record<string, any>";
|
|
362
|
+
}
|
|
363
|
+
if (tsModule.isArrayLiteralExpression(node)) {
|
|
364
|
+
const types = [...new Set(node.elements.map((element) => {
|
|
365
|
+
if (tsModule.isSpreadElement(element)) return null;
|
|
366
|
+
return getRuntimeConstructorType(element, tsModule);
|
|
367
|
+
}).filter((typeText) => Boolean(typeText)))];
|
|
368
|
+
return types.length > 0 ? types.join(" | ") : null;
|
|
369
|
+
}
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
function getFunctionSignatureTypeText(node, sourceFile) {
|
|
373
|
+
if (!(node.parameters.some((parameter) => Boolean(parameter.type)) || Boolean(node.type))) return "(...args: any[]) => any";
|
|
374
|
+
return `(${node.parameters.map((parameter) => parameter.getText(sourceFile)).join(", ")}) => ${node.type?.getText(sourceFile) ?? "any"}`;
|
|
375
|
+
}
|
|
376
|
+
function getMiniProgramPropertyType(node, tsModule) {
|
|
377
|
+
const runtimeType = getRuntimeConstructorType(node, tsModule);
|
|
378
|
+
if (runtimeType) return runtimeType;
|
|
379
|
+
if (!tsModule.isObjectLiteralExpression(node)) return "any";
|
|
351
380
|
for (const property of node.properties) {
|
|
352
|
-
if (!tsModule.isPropertyAssignment(property)
|
|
353
|
-
|
|
354
|
-
|
|
381
|
+
if (!tsModule.isPropertyAssignment(property)) continue;
|
|
382
|
+
if (getPropertyNameText(property.name, tsModule) !== "type") continue;
|
|
383
|
+
return getRuntimeConstructorType(unwrapParenthesizedExpression(property.initializer, tsModule), tsModule) ?? "any";
|
|
384
|
+
}
|
|
385
|
+
return "any";
|
|
386
|
+
}
|
|
387
|
+
function getExpressionTypeText(node, tsModule, sourceFile) {
|
|
388
|
+
const expression = unwrapParenthesizedExpression(node, tsModule);
|
|
389
|
+
if (tsModule.isAsExpression(expression) || tsModule.isTypeAssertionExpression(expression)) return expression.type.getText(sourceFile);
|
|
390
|
+
if (tsModule.isStringLiteral(expression) || tsModule.isNoSubstitutionTemplateLiteral(expression)) return "string";
|
|
391
|
+
if (tsModule.isNumericLiteral(expression)) return "number";
|
|
392
|
+
if (expression.kind === tsModule.SyntaxKind.TrueKeyword || expression.kind === tsModule.SyntaxKind.FalseKeyword) return "boolean";
|
|
393
|
+
if (tsModule.isPrefixUnaryExpression(expression) && tsModule.isNumericLiteral(expression.operand)) return "number";
|
|
394
|
+
if (tsModule.isArrayLiteralExpression(expression)) {
|
|
395
|
+
const itemTypes = [...new Set(expression.elements.map((element) => {
|
|
396
|
+
if (tsModule.isSpreadElement(element)) return null;
|
|
397
|
+
return getExpressionTypeText(element, tsModule, sourceFile);
|
|
398
|
+
}).filter((typeText) => Boolean(typeText) && typeText !== "undefined"))];
|
|
399
|
+
if (itemTypes.length === 0) return "any[]";
|
|
400
|
+
return itemTypes.length === 1 ? `${itemTypes[0]}[]` : `(${itemTypes.join(" | ")})[]`;
|
|
355
401
|
}
|
|
356
|
-
|
|
402
|
+
if (tsModule.isObjectLiteralExpression(expression)) {
|
|
403
|
+
const fields = [];
|
|
404
|
+
for (const property of expression.properties) {
|
|
405
|
+
if (tsModule.isPropertyAssignment(property)) {
|
|
406
|
+
const name = getPropertyNameText(property.name, tsModule);
|
|
407
|
+
if (name) fields.push(`${name}: ${getExpressionTypeText(property.initializer, tsModule, sourceFile)}`);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
if (tsModule.isShorthandPropertyAssignment(property)) {
|
|
411
|
+
fields.push(`${property.name.text}: any`);
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (tsModule.isMethodDeclaration(property) || tsModule.isGetAccessorDeclaration(property)) {
|
|
415
|
+
const name = getPropertyNameText(property.name, tsModule);
|
|
416
|
+
if (name) fields.push(`${name}: (...args: any[]) => any`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return fields.length > 0 ? `{ ${fields.join("; ")} }` : "Record<string, any>";
|
|
420
|
+
}
|
|
421
|
+
if (tsModule.isArrowFunction(expression) || tsModule.isFunctionExpression(expression)) return "(...args: any[]) => any";
|
|
422
|
+
if (tsModule.isIdentifier(expression) && expression.text === "undefined") return "undefined";
|
|
423
|
+
return "any";
|
|
424
|
+
}
|
|
425
|
+
function getFunctionLikeReturnTypeText(node, tsModule, sourceFile) {
|
|
426
|
+
if (node.type) return node.type.getText(sourceFile);
|
|
427
|
+
if (!node.body) return "any";
|
|
428
|
+
const returnedExpression = tsModule.isBlock(node.body) ? findReturnedExpression(node.body, tsModule) : findReturnedExpression(node.body, tsModule);
|
|
429
|
+
return returnedExpression ? getExpressionTypeText(returnedExpression, tsModule, sourceFile) : "any";
|
|
357
430
|
}
|
|
358
431
|
function collectDefineOptionsTemplateBindings(code, tsModule, lang) {
|
|
359
432
|
const scriptKind = lang === "ts" ? 3 : 1;
|
|
360
433
|
const sourceFile = tsModule.createSourceFile(`script-setup.${lang}`, code, 99, true, scriptKind);
|
|
361
|
-
const valueBindings = /* @__PURE__ */ new
|
|
362
|
-
const functionBindings = /* @__PURE__ */ new
|
|
434
|
+
const valueBindings = /* @__PURE__ */ new Map();
|
|
435
|
+
const functionBindings = /* @__PURE__ */ new Map();
|
|
363
436
|
const visit = (node) => {
|
|
364
437
|
if (tsModule.isCallExpression(node)) {
|
|
365
438
|
const optionsObject = extractDefineOptionsObjectLiteral(node, tsModule);
|
|
@@ -368,12 +441,30 @@ function collectDefineOptionsTemplateBindings(code, tsModule, lang) {
|
|
|
368
441
|
if (!sectionName) continue;
|
|
369
442
|
if (sectionName === "methods") {
|
|
370
443
|
const methodsObject = tsModule.isPropertyAssignment(property) ? unwrapParenthesizedExpression(property.initializer, tsModule) : void 0;
|
|
371
|
-
if (methodsObject && tsModule.isObjectLiteralExpression(methodsObject)) for (const
|
|
444
|
+
if (methodsObject && tsModule.isObjectLiteralExpression(methodsObject)) for (const entry of methodsObject.properties) {
|
|
445
|
+
if (!tsModule.isPropertyAssignment(entry) && !tsModule.isMethodDeclaration(entry) && !tsModule.isShorthandPropertyAssignment(entry)) continue;
|
|
446
|
+
const name = getPropertyNameText(entry.name, tsModule);
|
|
447
|
+
if (!name || !isIdentifierName(name)) continue;
|
|
448
|
+
setBindingType(functionBindings, name, tsModule.isPropertyAssignment(entry) && (tsModule.isArrowFunction(entry.initializer) || tsModule.isFunctionExpression(entry.initializer)) ? getFunctionSignatureTypeText(entry.initializer, sourceFile) : tsModule.isMethodDeclaration(entry) ? getFunctionSignatureTypeText(entry, sourceFile) : "(...args: any[]) => any");
|
|
449
|
+
}
|
|
372
450
|
continue;
|
|
373
451
|
}
|
|
374
452
|
if (sectionName === "properties" || sectionName === "computed") {
|
|
375
453
|
const objectValue = tsModule.isPropertyAssignment(property) ? unwrapParenthesizedExpression(property.initializer, tsModule) : void 0;
|
|
376
|
-
if (objectValue && tsModule.isObjectLiteralExpression(objectValue)) for (const
|
|
454
|
+
if (objectValue && tsModule.isObjectLiteralExpression(objectValue)) for (const entry of objectValue.properties) {
|
|
455
|
+
if (!tsModule.isPropertyAssignment(entry) && !tsModule.isMethodDeclaration(entry) && !tsModule.isShorthandPropertyAssignment(entry) && !tsModule.isGetAccessorDeclaration(entry)) continue;
|
|
456
|
+
const name = getPropertyNameText(entry.name, tsModule);
|
|
457
|
+
if (!name || !isIdentifierName(name)) continue;
|
|
458
|
+
let typeText = "any";
|
|
459
|
+
if (sectionName === "properties" && tsModule.isPropertyAssignment(entry)) typeText = getMiniProgramPropertyType(unwrapParenthesizedExpression(entry.initializer, tsModule), tsModule);
|
|
460
|
+
else if (sectionName === "computed") {
|
|
461
|
+
if (tsModule.isPropertyAssignment(entry)) {
|
|
462
|
+
const initializer = unwrapParenthesizedExpression(entry.initializer, tsModule);
|
|
463
|
+
if (tsModule.isArrowFunction(initializer) || tsModule.isFunctionExpression(initializer)) typeText = getFunctionLikeReturnTypeText(initializer, tsModule, sourceFile);
|
|
464
|
+
} else if (tsModule.isMethodDeclaration(entry) || tsModule.isGetAccessorDeclaration(entry)) typeText = getFunctionLikeReturnTypeText(entry, tsModule, sourceFile);
|
|
465
|
+
}
|
|
466
|
+
setBindingType(valueBindings, name, typeText);
|
|
467
|
+
}
|
|
377
468
|
continue;
|
|
378
469
|
}
|
|
379
470
|
if (sectionName === "data") {
|
|
@@ -381,9 +472,15 @@ function collectDefineOptionsTemplateBindings(code, tsModule, lang) {
|
|
|
381
472
|
if (tsModule.isMethodDeclaration(property)) dataObject = findReturnedObjectLiteral(property.body ?? tsModule.factory.createBlock([], false), tsModule);
|
|
382
473
|
else if (tsModule.isPropertyAssignment(property)) {
|
|
383
474
|
const initializer = unwrapParenthesizedExpression(property.initializer, tsModule);
|
|
384
|
-
if (tsModule.
|
|
475
|
+
if (tsModule.isObjectLiteralExpression(initializer)) dataObject = initializer;
|
|
476
|
+
else if (tsModule.isArrowFunction(initializer) || tsModule.isFunctionExpression(initializer)) dataObject = findReturnedObjectLiteral(initializer.body, tsModule);
|
|
477
|
+
}
|
|
478
|
+
if (dataObject) for (const property of dataObject.properties) {
|
|
479
|
+
if (!tsModule.isPropertyAssignment(property) && !tsModule.isMethodDeclaration(property) && !tsModule.isShorthandPropertyAssignment(property) && !tsModule.isGetAccessorDeclaration(property)) continue;
|
|
480
|
+
const name = getPropertyNameText(property.name, tsModule);
|
|
481
|
+
if (!name || !isIdentifierName(name)) continue;
|
|
482
|
+
setBindingType(valueBindings, name, tsModule.isPropertyAssignment(property) ? getExpressionTypeText(property.initializer, tsModule, sourceFile) : "(...args: any[]) => any");
|
|
385
483
|
}
|
|
386
|
-
if (dataObject) for (const name of collectObjectLiteralKeys(dataObject, tsModule)) valueBindings.add(name);
|
|
387
484
|
}
|
|
388
485
|
}
|
|
389
486
|
}
|
|
@@ -399,13 +496,13 @@ function createDefineOptionsTemplateDeclarations(code, tsModule, lang) {
|
|
|
399
496
|
const topLevelBindings = collectTopLevelBindingNames(code, tsModule, lang);
|
|
400
497
|
const bindings = collectDefineOptionsTemplateBindings(code, tsModule, lang);
|
|
401
498
|
const declarations = [];
|
|
402
|
-
for (const name of bindings.values) {
|
|
499
|
+
for (const [name, typeText] of bindings.values) {
|
|
403
500
|
if (topLevelBindings.has(name)) continue;
|
|
404
|
-
declarations.push(`const ${name}:
|
|
501
|
+
declarations.push(`const ${name}: ${typeText} = null as any`);
|
|
405
502
|
}
|
|
406
|
-
for (const name of bindings.functions) {
|
|
503
|
+
for (const [name, typeText] of bindings.functions) {
|
|
407
504
|
if (topLevelBindings.has(name)) continue;
|
|
408
|
-
declarations.push(`const ${name}:
|
|
505
|
+
declarations.push(`const ${name}: ${typeText} = null as any`);
|
|
409
506
|
}
|
|
410
507
|
return declarations.join("\n");
|
|
411
508
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -305,15 +305,18 @@ function unwrapParenthesizedExpression(node, tsModule) {
|
|
|
305
305
|
while (tsModule.isParenthesizedExpression(current)) current = current.expression;
|
|
306
306
|
return current;
|
|
307
307
|
}
|
|
308
|
-
function
|
|
308
|
+
function findReturnedExpression(node, tsModule) {
|
|
309
309
|
if (tsModule.isObjectLiteralExpression(node)) return node;
|
|
310
|
-
if (!tsModule.isBlock(node)) return;
|
|
310
|
+
if (!tsModule.isBlock(node)) return node;
|
|
311
311
|
for (const statement of node.statements) {
|
|
312
312
|
if (!tsModule.isReturnStatement(statement) || !statement.expression) continue;
|
|
313
|
-
|
|
314
|
-
if (tsModule.isObjectLiteralExpression(expression)) return expression;
|
|
313
|
+
return unwrapParenthesizedExpression(statement.expression, tsModule);
|
|
315
314
|
}
|
|
316
315
|
}
|
|
316
|
+
function findReturnedObjectLiteral(node, tsModule) {
|
|
317
|
+
const expression = findReturnedExpression(node, tsModule);
|
|
318
|
+
return expression && tsModule.isObjectLiteralExpression(expression) ? expression : void 0;
|
|
319
|
+
}
|
|
317
320
|
function extractDefineOptionsObjectLiteral(node, tsModule) {
|
|
318
321
|
if (!tsModule.isIdentifier(node.expression) || node.expression.text !== "defineOptions") return;
|
|
319
322
|
const [firstArg] = node.arguments;
|
|
@@ -322,20 +325,90 @@ function extractDefineOptionsObjectLiteral(node, tsModule) {
|
|
|
322
325
|
if (tsModule.isObjectLiteralExpression(arg)) return arg;
|
|
323
326
|
if (tsModule.isArrowFunction(arg) || tsModule.isFunctionExpression(arg)) return findReturnedObjectLiteral(arg.body, tsModule);
|
|
324
327
|
}
|
|
325
|
-
function
|
|
326
|
-
|
|
328
|
+
function setBindingType(map, name, typeText) {
|
|
329
|
+
if (!map.has(name)) map.set(name, typeText);
|
|
330
|
+
}
|
|
331
|
+
function getRuntimeConstructorType(node, tsModule) {
|
|
332
|
+
if (tsModule.isIdentifier(node)) {
|
|
333
|
+
if (node.text === "String") return "string";
|
|
334
|
+
if (node.text === "Number") return "number";
|
|
335
|
+
if (node.text === "Boolean") return "boolean";
|
|
336
|
+
if (node.text === "Array") return "any[]";
|
|
337
|
+
if (node.text === "Object") return "Record<string, any>";
|
|
338
|
+
}
|
|
339
|
+
if (tsModule.isArrayLiteralExpression(node)) {
|
|
340
|
+
const types = [...new Set(node.elements.map((element) => {
|
|
341
|
+
if (tsModule.isSpreadElement(element)) return null;
|
|
342
|
+
return getRuntimeConstructorType(element, tsModule);
|
|
343
|
+
}).filter((typeText) => Boolean(typeText)))];
|
|
344
|
+
return types.length > 0 ? types.join(" | ") : null;
|
|
345
|
+
}
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
function getFunctionSignatureTypeText(node, sourceFile) {
|
|
349
|
+
if (!(node.parameters.some((parameter) => Boolean(parameter.type)) || Boolean(node.type))) return "(...args: any[]) => any";
|
|
350
|
+
return `(${node.parameters.map((parameter) => parameter.getText(sourceFile)).join(", ")}) => ${node.type?.getText(sourceFile) ?? "any"}`;
|
|
351
|
+
}
|
|
352
|
+
function getMiniProgramPropertyType(node, tsModule) {
|
|
353
|
+
const runtimeType = getRuntimeConstructorType(node, tsModule);
|
|
354
|
+
if (runtimeType) return runtimeType;
|
|
355
|
+
if (!tsModule.isObjectLiteralExpression(node)) return "any";
|
|
327
356
|
for (const property of node.properties) {
|
|
328
|
-
if (!tsModule.isPropertyAssignment(property)
|
|
329
|
-
|
|
330
|
-
|
|
357
|
+
if (!tsModule.isPropertyAssignment(property)) continue;
|
|
358
|
+
if (getPropertyNameText(property.name, tsModule) !== "type") continue;
|
|
359
|
+
return getRuntimeConstructorType(unwrapParenthesizedExpression(property.initializer, tsModule), tsModule) ?? "any";
|
|
360
|
+
}
|
|
361
|
+
return "any";
|
|
362
|
+
}
|
|
363
|
+
function getExpressionTypeText(node, tsModule, sourceFile) {
|
|
364
|
+
const expression = unwrapParenthesizedExpression(node, tsModule);
|
|
365
|
+
if (tsModule.isAsExpression(expression) || tsModule.isTypeAssertionExpression(expression)) return expression.type.getText(sourceFile);
|
|
366
|
+
if (tsModule.isStringLiteral(expression) || tsModule.isNoSubstitutionTemplateLiteral(expression)) return "string";
|
|
367
|
+
if (tsModule.isNumericLiteral(expression)) return "number";
|
|
368
|
+
if (expression.kind === tsModule.SyntaxKind.TrueKeyword || expression.kind === tsModule.SyntaxKind.FalseKeyword) return "boolean";
|
|
369
|
+
if (tsModule.isPrefixUnaryExpression(expression) && tsModule.isNumericLiteral(expression.operand)) return "number";
|
|
370
|
+
if (tsModule.isArrayLiteralExpression(expression)) {
|
|
371
|
+
const itemTypes = [...new Set(expression.elements.map((element) => {
|
|
372
|
+
if (tsModule.isSpreadElement(element)) return null;
|
|
373
|
+
return getExpressionTypeText(element, tsModule, sourceFile);
|
|
374
|
+
}).filter((typeText) => Boolean(typeText) && typeText !== "undefined"))];
|
|
375
|
+
if (itemTypes.length === 0) return "any[]";
|
|
376
|
+
return itemTypes.length === 1 ? `${itemTypes[0]}[]` : `(${itemTypes.join(" | ")})[]`;
|
|
331
377
|
}
|
|
332
|
-
|
|
378
|
+
if (tsModule.isObjectLiteralExpression(expression)) {
|
|
379
|
+
const fields = [];
|
|
380
|
+
for (const property of expression.properties) {
|
|
381
|
+
if (tsModule.isPropertyAssignment(property)) {
|
|
382
|
+
const name = getPropertyNameText(property.name, tsModule);
|
|
383
|
+
if (name) fields.push(`${name}: ${getExpressionTypeText(property.initializer, tsModule, sourceFile)}`);
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (tsModule.isShorthandPropertyAssignment(property)) {
|
|
387
|
+
fields.push(`${property.name.text}: any`);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
if (tsModule.isMethodDeclaration(property) || tsModule.isGetAccessorDeclaration(property)) {
|
|
391
|
+
const name = getPropertyNameText(property.name, tsModule);
|
|
392
|
+
if (name) fields.push(`${name}: (...args: any[]) => any`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return fields.length > 0 ? `{ ${fields.join("; ")} }` : "Record<string, any>";
|
|
396
|
+
}
|
|
397
|
+
if (tsModule.isArrowFunction(expression) || tsModule.isFunctionExpression(expression)) return "(...args: any[]) => any";
|
|
398
|
+
if (tsModule.isIdentifier(expression) && expression.text === "undefined") return "undefined";
|
|
399
|
+
return "any";
|
|
400
|
+
}
|
|
401
|
+
function getFunctionLikeReturnTypeText(node, tsModule, sourceFile) {
|
|
402
|
+
if (node.type) return node.type.getText(sourceFile);
|
|
403
|
+
if (!node.body) return "any";
|
|
404
|
+
const returnedExpression = tsModule.isBlock(node.body) ? findReturnedExpression(node.body, tsModule) : findReturnedExpression(node.body, tsModule);
|
|
405
|
+
return returnedExpression ? getExpressionTypeText(returnedExpression, tsModule, sourceFile) : "any";
|
|
333
406
|
}
|
|
334
407
|
function collectDefineOptionsTemplateBindings(code, tsModule, lang) {
|
|
335
408
|
const scriptKind = lang === "ts" ? 3 : 1;
|
|
336
409
|
const sourceFile = tsModule.createSourceFile(`script-setup.${lang}`, code, 99, true, scriptKind);
|
|
337
|
-
const valueBindings = /* @__PURE__ */ new
|
|
338
|
-
const functionBindings = /* @__PURE__ */ new
|
|
410
|
+
const valueBindings = /* @__PURE__ */ new Map();
|
|
411
|
+
const functionBindings = /* @__PURE__ */ new Map();
|
|
339
412
|
const visit = (node) => {
|
|
340
413
|
if (tsModule.isCallExpression(node)) {
|
|
341
414
|
const optionsObject = extractDefineOptionsObjectLiteral(node, tsModule);
|
|
@@ -344,12 +417,30 @@ function collectDefineOptionsTemplateBindings(code, tsModule, lang) {
|
|
|
344
417
|
if (!sectionName) continue;
|
|
345
418
|
if (sectionName === "methods") {
|
|
346
419
|
const methodsObject = tsModule.isPropertyAssignment(property) ? unwrapParenthesizedExpression(property.initializer, tsModule) : void 0;
|
|
347
|
-
if (methodsObject && tsModule.isObjectLiteralExpression(methodsObject)) for (const
|
|
420
|
+
if (methodsObject && tsModule.isObjectLiteralExpression(methodsObject)) for (const entry of methodsObject.properties) {
|
|
421
|
+
if (!tsModule.isPropertyAssignment(entry) && !tsModule.isMethodDeclaration(entry) && !tsModule.isShorthandPropertyAssignment(entry)) continue;
|
|
422
|
+
const name = getPropertyNameText(entry.name, tsModule);
|
|
423
|
+
if (!name || !isIdentifierName(name)) continue;
|
|
424
|
+
setBindingType(functionBindings, name, tsModule.isPropertyAssignment(entry) && (tsModule.isArrowFunction(entry.initializer) || tsModule.isFunctionExpression(entry.initializer)) ? getFunctionSignatureTypeText(entry.initializer, sourceFile) : tsModule.isMethodDeclaration(entry) ? getFunctionSignatureTypeText(entry, sourceFile) : "(...args: any[]) => any");
|
|
425
|
+
}
|
|
348
426
|
continue;
|
|
349
427
|
}
|
|
350
428
|
if (sectionName === "properties" || sectionName === "computed") {
|
|
351
429
|
const objectValue = tsModule.isPropertyAssignment(property) ? unwrapParenthesizedExpression(property.initializer, tsModule) : void 0;
|
|
352
|
-
if (objectValue && tsModule.isObjectLiteralExpression(objectValue)) for (const
|
|
430
|
+
if (objectValue && tsModule.isObjectLiteralExpression(objectValue)) for (const entry of objectValue.properties) {
|
|
431
|
+
if (!tsModule.isPropertyAssignment(entry) && !tsModule.isMethodDeclaration(entry) && !tsModule.isShorthandPropertyAssignment(entry) && !tsModule.isGetAccessorDeclaration(entry)) continue;
|
|
432
|
+
const name = getPropertyNameText(entry.name, tsModule);
|
|
433
|
+
if (!name || !isIdentifierName(name)) continue;
|
|
434
|
+
let typeText = "any";
|
|
435
|
+
if (sectionName === "properties" && tsModule.isPropertyAssignment(entry)) typeText = getMiniProgramPropertyType(unwrapParenthesizedExpression(entry.initializer, tsModule), tsModule);
|
|
436
|
+
else if (sectionName === "computed") {
|
|
437
|
+
if (tsModule.isPropertyAssignment(entry)) {
|
|
438
|
+
const initializer = unwrapParenthesizedExpression(entry.initializer, tsModule);
|
|
439
|
+
if (tsModule.isArrowFunction(initializer) || tsModule.isFunctionExpression(initializer)) typeText = getFunctionLikeReturnTypeText(initializer, tsModule, sourceFile);
|
|
440
|
+
} else if (tsModule.isMethodDeclaration(entry) || tsModule.isGetAccessorDeclaration(entry)) typeText = getFunctionLikeReturnTypeText(entry, tsModule, sourceFile);
|
|
441
|
+
}
|
|
442
|
+
setBindingType(valueBindings, name, typeText);
|
|
443
|
+
}
|
|
353
444
|
continue;
|
|
354
445
|
}
|
|
355
446
|
if (sectionName === "data") {
|
|
@@ -357,9 +448,15 @@ function collectDefineOptionsTemplateBindings(code, tsModule, lang) {
|
|
|
357
448
|
if (tsModule.isMethodDeclaration(property)) dataObject = findReturnedObjectLiteral(property.body ?? tsModule.factory.createBlock([], false), tsModule);
|
|
358
449
|
else if (tsModule.isPropertyAssignment(property)) {
|
|
359
450
|
const initializer = unwrapParenthesizedExpression(property.initializer, tsModule);
|
|
360
|
-
if (tsModule.
|
|
451
|
+
if (tsModule.isObjectLiteralExpression(initializer)) dataObject = initializer;
|
|
452
|
+
else if (tsModule.isArrowFunction(initializer) || tsModule.isFunctionExpression(initializer)) dataObject = findReturnedObjectLiteral(initializer.body, tsModule);
|
|
453
|
+
}
|
|
454
|
+
if (dataObject) for (const property of dataObject.properties) {
|
|
455
|
+
if (!tsModule.isPropertyAssignment(property) && !tsModule.isMethodDeclaration(property) && !tsModule.isShorthandPropertyAssignment(property) && !tsModule.isGetAccessorDeclaration(property)) continue;
|
|
456
|
+
const name = getPropertyNameText(property.name, tsModule);
|
|
457
|
+
if (!name || !isIdentifierName(name)) continue;
|
|
458
|
+
setBindingType(valueBindings, name, tsModule.isPropertyAssignment(property) ? getExpressionTypeText(property.initializer, tsModule, sourceFile) : "(...args: any[]) => any");
|
|
361
459
|
}
|
|
362
|
-
if (dataObject) for (const name of collectObjectLiteralKeys(dataObject, tsModule)) valueBindings.add(name);
|
|
363
460
|
}
|
|
364
461
|
}
|
|
365
462
|
}
|
|
@@ -375,13 +472,13 @@ function createDefineOptionsTemplateDeclarations(code, tsModule, lang) {
|
|
|
375
472
|
const topLevelBindings = collectTopLevelBindingNames(code, tsModule, lang);
|
|
376
473
|
const bindings = collectDefineOptionsTemplateBindings(code, tsModule, lang);
|
|
377
474
|
const declarations = [];
|
|
378
|
-
for (const name of bindings.values) {
|
|
475
|
+
for (const [name, typeText] of bindings.values) {
|
|
379
476
|
if (topLevelBindings.has(name)) continue;
|
|
380
|
-
declarations.push(`const ${name}:
|
|
477
|
+
declarations.push(`const ${name}: ${typeText} = null as any`);
|
|
381
478
|
}
|
|
382
|
-
for (const name of bindings.functions) {
|
|
479
|
+
for (const [name, typeText] of bindings.functions) {
|
|
383
480
|
if (topLevelBindings.has(name)) continue;
|
|
384
|
-
declarations.push(`const ${name}:
|
|
481
|
+
declarations.push(`const ${name}: ${typeText} = null as any`);
|
|
385
482
|
}
|
|
386
483
|
return declarations.join("\n");
|
|
387
484
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weapp-vite/volar",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Volar plugin for weapp-vite - Provides IntelliSense and type checking for WeChat mini-program config blocks",
|
|
5
5
|
"author": "ice breaker <1324318532@qq.com>",
|
|
6
6
|
"license": "MIT",
|