@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 CHANGED
@@ -1,58 +1,65 @@
1
1
  # @weapp-vite/volar
2
2
 
3
- > 为 weapp-vite 提供 VSCode 智能提示和类型检查的 Volar 插件
3
+ ## 1. 简介
4
4
 
5
- ## 安装
5
+ `@weapp-vite/volar` 是 `weapp-vite` 的 Volar 语言服务插件,用来给小程序 Vue SFC 中的自定义块和相关宏提供更准确的类型、补全和诊断能力。
6
6
 
7
- 此包已作为 `weapp-vite` 的依赖自动安装,**无需单独安装**。
7
+ 它主要覆盖:
8
8
 
9
- 如果你确实需要单独安装:
9
+ - `<json>` 自定义块的 schema 与类型提示
10
+ - `definePageJson` / `defineComponentJson` 等配置宏配套体验
11
+ - `wxs` 模块声明补全
12
+ - `script setup` 中为 weapp-vite / wevu 注入的额外声明
10
13
 
11
- ```bash
12
- npm install -D @weapp-vite/volar
13
- # or
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
- **推荐方式:** 通过 weapp-vite 使用,插件会自动启用。
20
+ 如果你要在非标准工程里单独集成,可以安装:
22
21
 
23
- 详细使用文档请参考:[weapp-vite Volar 文档](../weapp-vite/docs/volar.md)
22
+ ```bash
23
+ pnpm add -D @weapp-vite/volar @weapp-core/schematics
24
+ ```
24
25
 
25
- ## 功能特性
26
+ ## 3. 常见配置
26
27
 
27
- - ✅ **配置文件智能提示** - 为 `<json>` 代码块提供完整的类型检查和自动补全
28
- - ✅ **JSON Schema 支持** - 支持 JSON Schema 验证和自动补全
29
- - ✅ **TypeScript 类型检查** - 利用 TypeScript 类型系统确保配置正确性
30
- - ✅ **自动推断配置类型** - 根据文件路径自动推断是 App/Page/Component 配置
31
- - ✅ **多模式支持** - 支持 JSON 模式和 TypeScript 模式
28
+ ```json
29
+ {
30
+ "vueCompilerOptions": {
31
+ "plugins": ["weapp-vite/volar"]
32
+ }
33
+ }
34
+ ```
32
35
 
33
- ## 开发
36
+ > **注意**:更完整的编辑器接入方式,请优先参考 `weapp-vite` 主包文档中的 Volar 章节。
34
37
 
35
- ```bash
36
- # 安装依赖
37
- pnpm install
38
+ ## 4. 提供的能力
38
39
 
39
- # 开发模式
40
- pnpm dev
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
- pnpm test
47
- ```
49
+ - 在 `.vue` 文件里直接编写小程序页面 / 组件配置
50
+ - 使用 `definePageJson`、`defineComponentJson` 等宏
51
+ - 需要让 VS Code / Volar 正确理解 weapp-vite 的自定义块与扩展语义
48
52
 
49
- ## 相关文档
53
+ ## 6. 本地开发
50
54
 
51
- - [weapp-vite 文档](../weapp-vite)
52
- - [weapp-vite Volar 使用指南](../weapp-vite/docs/volar.md)
53
- - [Vue 3 文档](https://vuejs.org/)
54
- - [微信小程序官方文档](https://developers.weixin.qq.com/miniprogram/dev/framework/)
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
- ## License
61
+ ## 7. 相关链接
57
62
 
58
- MIT
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 findReturnedObjectLiteral(node, tsModule) {
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
- const expression = unwrapParenthesizedExpression(statement.expression, tsModule);
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 collectObjectLiteralKeys(node, tsModule) {
350
- const keys = [];
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) && !tsModule.isMethodDeclaration(property) && !tsModule.isShorthandPropertyAssignment(property) && !tsModule.isGetAccessorDeclaration(property)) continue;
353
- const key = getPropertyNameText(property.name, tsModule);
354
- if (key && isIdentifierName(key)) keys.push(key);
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
- return keys;
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 Set();
362
- const functionBindings = /* @__PURE__ */ new Set();
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 name of collectObjectLiteralKeys(methodsObject, tsModule)) functionBindings.add(name);
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 name of collectObjectLiteralKeys(objectValue, tsModule)) valueBindings.add(name);
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.isArrowFunction(initializer) || tsModule.isFunctionExpression(initializer)) dataObject = findReturnedObjectLiteral(initializer.body, 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}: any = null as any`);
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}: (...args: any[]) => any = null as any`);
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 findReturnedObjectLiteral(node, tsModule) {
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
- const expression = unwrapParenthesizedExpression(statement.expression, tsModule);
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 collectObjectLiteralKeys(node, tsModule) {
326
- const keys = [];
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) && !tsModule.isMethodDeclaration(property) && !tsModule.isShorthandPropertyAssignment(property) && !tsModule.isGetAccessorDeclaration(property)) continue;
329
- const key = getPropertyNameText(property.name, tsModule);
330
- if (key && isIdentifierName(key)) keys.push(key);
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
- return keys;
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 Set();
338
- const functionBindings = /* @__PURE__ */ new Set();
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 name of collectObjectLiteralKeys(methodsObject, tsModule)) functionBindings.add(name);
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 name of collectObjectLiteralKeys(objectValue, tsModule)) valueBindings.add(name);
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.isArrowFunction(initializer) || tsModule.isFunctionExpression(initializer)) dataObject = findReturnedObjectLiteral(initializer.body, 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}: any = null as any`);
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}: (...args: any[]) => any = null as any`);
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.8",
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",