@weapp-vite/volar 2.0.7 → 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/dist/index.cjs CHANGED
@@ -29,33 +29,13 @@ let _weapp_core_schematics = require("@weapp-core/schematics");
29
29
  //#region package.json
30
30
  var name = "@weapp-vite/volar";
31
31
  //#endregion
32
- //#region src/schema.ts
33
- /**
34
- * 为小程序配置生成 JSON Schema
35
- * 为支持 JSON Schema 的编辑器提供验证和自动补全
36
- *
37
- * 注意:JSON Schema 定义由 @weapp-core/schematics 统一维护
38
- * 使用 Zod 定义并自动生成,确保单一数据源
39
- */
40
- /**
41
- * 根据文件类型获取对应的 JSON Schema
42
- * Schema 定义来自 @weapp-core/schematics,使用 Zod 维护单一数据源
43
- */
44
- function getSchemaForType(type) {
45
- const definition = _weapp_core_schematics.JSON_SCHEMA_DEFINITIONS.find((d) => d.typeName === type);
46
- if (!definition) return null;
47
- return definition.schema;
48
- }
49
- //#endregion
50
- //#region src/index.ts
32
+ //#region src/constants.ts
51
33
  const BLOCK_TYPE = "json";
52
- const JS_LANG = "js";
53
34
  const JSONC_LANG = "jsonc";
54
35
  const JSON_LANG = "json";
55
- const JSON5_LANG = "json5";
56
36
  const PLUGIN_VERSION = 2.2;
57
- const TS_LANG = "ts";
58
37
  const BACKSLASH_RE = /\\/g;
38
+ const IDENTIFIER_NAME_RE = /^[$_\p{ID_Start}][$\u200C\u200D\p{ID_Continue}]*$/u;
59
39
  const NON_SPACE_RE = /\S/;
60
40
  const WXS_MODULE_RE = /<wxs[\s\S]*?module\s*=\s*(?:"([^"]+)"|'([^']+)')[\s\S]*?\/?>/gi;
61
41
  const FULL_CAPABILITIES = {
@@ -74,21 +54,185 @@ const VOID_CAPABILITIES = {
74
54
  structure: false,
75
55
  format: false
76
56
  };
77
- const require$1 = (0, node_module.createRequire)(typeof module !== "undefined" && module.filename ? module.filename : node_path.default.join(node_process.default.cwd(), "weapp-vite-volar.cjs"));
78
- let hasSchematicsTypes = false;
79
- try {
80
- require$1.resolve("@weapp-core/schematics");
81
- hasSchematicsTypes = true;
82
- } catch {
83
- hasSchematicsTypes = false;
57
+ //#endregion
58
+ //#region src/schema.ts
59
+ /**
60
+ * 为小程序配置生成 JSON Schema
61
+ * 为支持 JSON Schema 的编辑器提供验证和自动补全
62
+ *
63
+ * 注意:JSON Schema 定义由 @weapp-core/schematics 统一维护
64
+ * 使用 Zod 定义并自动生成,确保单一数据源
65
+ */
66
+ /**
67
+ * 根据文件类型获取对应的 JSON Schema
68
+ * Schema 定义来自 @weapp-core/schematics,使用 Zod 维护单一数据源
69
+ */
70
+ function getSchemaForType(type) {
71
+ const definition = _weapp_core_schematics.JSON_SCHEMA_DEFINITIONS.find((d) => d.typeName === type);
72
+ if (!definition) return null;
73
+ return definition.schema;
84
74
  }
85
- function parseVueSfc(content, filename = "component.vue") {
86
- try {
87
- return require$1("@vue/compiler-sfc").parse(content, { filename });
88
- } catch {
75
+ //#endregion
76
+ //#region src/jsonBlock.ts
77
+ function normalizeFilename(filename) {
78
+ if (!filename) return "";
79
+ return filename.replace(BACKSLASH_RE, "/");
80
+ }
81
+ function inferConfigType(filename) {
82
+ const normalized = normalizeFilename(filename);
83
+ if (normalized.endsWith("/app.vue")) return "App";
84
+ if (normalized.includes("/plugin/")) return "Plugin";
85
+ if (normalized.includes("/components/")) return "Component";
86
+ if (normalized.includes("/theme/")) return "Theme";
87
+ if (normalized.includes("/sitemap")) return "Sitemap";
88
+ return "Page";
89
+ }
90
+ function normalizeLang(lang) {
91
+ if (!lang) return JSON_LANG;
92
+ const lower = lang.toLowerCase();
93
+ if (lower === "txt") return JSON_LANG;
94
+ return lower;
95
+ }
96
+ function getEmbeddedCodesFromCustomBlocks(sfc) {
97
+ const names = [];
98
+ for (let i = 0; i < sfc.customBlocks.length; i++) {
99
+ const block = sfc.customBlocks[i];
100
+ if (block.type === "json") {
101
+ const normalizedLang = normalizeLang(block.lang);
102
+ if (normalizedLang === "js" || normalizedLang === "ts") {
103
+ names.push({
104
+ id: `${BLOCK_TYPE}_${i}`,
105
+ lang: "ts"
106
+ });
107
+ continue;
108
+ }
109
+ const embeddedLang = normalizedLang === "json" || normalizedLang === "jsonc" || normalizedLang === "json5" ? JSONC_LANG : JSON_LANG;
110
+ names.push({
111
+ id: `${BLOCK_TYPE}_${i}`,
112
+ lang: embeddedLang
113
+ });
114
+ }
115
+ }
116
+ return names;
117
+ }
118
+ function findExportDefaultExpression(code, tsModule, lang) {
119
+ const scriptKind = lang === "ts" ? 3 : 1;
120
+ const sourceFile = tsModule.createSourceFile(`config.${lang}`, code, 99, true, scriptKind);
121
+ for (const statement of sourceFile.statements) if (tsModule.isExportAssignment(statement)) {
122
+ const expressionStart = statement.expression.getStart(sourceFile);
123
+ const expressionEnd = statement.expression.getEnd();
124
+ const leading = code.slice(0, statement.getStart(sourceFile));
125
+ return {
126
+ expression: code.slice(expressionStart, expressionEnd),
127
+ expressionStart,
128
+ expressionEnd,
129
+ leading,
130
+ trailing: code.slice(statement.getEnd())
131
+ };
132
+ }
133
+ return null;
134
+ }
135
+ function injectSchemaIntoJsonObject(content, schemaId) {
136
+ const trimmed = content.trim();
137
+ if (!trimmed.startsWith("{")) return content;
138
+ const leftBraceIndex = content.indexOf("{");
139
+ if (leftBraceIndex < 0) return content;
140
+ const firstNonSpace = content.slice(leftBraceIndex + 1).match(NON_SPACE_RE);
141
+ const nextCharIndex = firstNonSpace ? leftBraceIndex + 1 + firstNonSpace.index : -1;
142
+ const isEmptyObject = nextCharIndex >= 0 && content[nextCharIndex] === "}";
143
+ const schemaLine = ` "$schema": "${schemaId}"`;
144
+ const injected = isEmptyObject ? `{\n${schemaLine}\n}` : `{\n${schemaLine},${content.slice(leftBraceIndex + 1)}`;
145
+ if (trimmed === content) return injected;
146
+ return `${content.slice(0, content.indexOf(trimmed))}${injected}${content.slice(content.indexOf(trimmed) + trimmed.length)}`;
147
+ }
148
+ function resolveEmbeddedJsonBlock(fileName, sfc, embeddedCode, tsModule, hasSchematicsTypes) {
149
+ const match = embeddedCode.id.match(new RegExp(`^${BLOCK_TYPE}_(\\d+)$`));
150
+ if (!match) return;
151
+ const index = Number.parseInt(match[1]);
152
+ const block = sfc.customBlocks[index];
153
+ if (!block) return;
154
+ const normalizedLang = normalizeLang(block.lang);
155
+ const configType = inferConfigType(fileName);
156
+ if (!hasSchematicsTypes) {
157
+ embeddedCode.content.push([
158
+ block.content,
159
+ block.name,
160
+ 0,
161
+ FULL_CAPABILITIES
162
+ ]);
89
163
  return;
90
164
  }
165
+ if (normalizedLang === "js" || normalizedLang === "ts") {
166
+ const parsed = tsModule && findExportDefaultExpression(block.content, tsModule, normalizedLang);
167
+ if (parsed) {
168
+ const typeImport = `import type { ${configType} as __WeappConfig } from '@weapp-core/schematics'\n`;
169
+ embeddedCode.content.push([
170
+ `${typeImport}const __weapp_defineConfig = <T extends __WeappConfig>(config: T) => config
171
+
172
+ `,
173
+ void 0,
174
+ 0,
175
+ VOID_CAPABILITIES
176
+ ]);
177
+ if (parsed.leading) embeddedCode.content.push([
178
+ parsed.leading,
179
+ block.name,
180
+ 0,
181
+ FULL_CAPABILITIES
182
+ ]);
183
+ embeddedCode.content.push([
184
+ "export default __weapp_defineConfig(",
185
+ void 0,
186
+ parsed.expressionStart,
187
+ VOID_CAPABILITIES
188
+ ]);
189
+ embeddedCode.content.push([
190
+ parsed.expression,
191
+ block.name,
192
+ parsed.expressionStart,
193
+ FULL_CAPABILITIES
194
+ ]);
195
+ embeddedCode.content.push([
196
+ ")",
197
+ void 0,
198
+ parsed.expressionEnd,
199
+ VOID_CAPABILITIES
200
+ ]);
201
+ if (parsed.trailing) embeddedCode.content.push([
202
+ parsed.trailing,
203
+ block.name,
204
+ parsed.expressionEnd,
205
+ FULL_CAPABILITIES
206
+ ]);
207
+ return;
208
+ }
209
+ embeddedCode.content.push([
210
+ block.content,
211
+ block.name,
212
+ 0,
213
+ FULL_CAPABILITIES
214
+ ]);
215
+ return;
216
+ }
217
+ const schema = getSchemaForType(configType);
218
+ if (schema && schema.$id && !block.content.includes("$schema")) {
219
+ embeddedCode.content.push([
220
+ injectSchemaIntoJsonObject(block.content, schema.$id),
221
+ block.name,
222
+ 0,
223
+ FULL_CAPABILITIES
224
+ ]);
225
+ return;
226
+ }
227
+ embeddedCode.content.push([
228
+ block.content,
229
+ block.name,
230
+ 0,
231
+ FULL_CAPABILITIES
232
+ ]);
91
233
  }
234
+ //#endregion
235
+ //#region src/scriptSetup.ts
92
236
  function collectWxsModuleNames(templateContent) {
93
237
  if (!templateContent) return [];
94
238
  const names = /* @__PURE__ */ new Set();
@@ -107,6 +251,10 @@ function appendWxsDeclarations(code, moduleNames) {
107
251
  if (!declarations) return code;
108
252
  return code ? `${code}\n\n${declarations}\n` : `${declarations}\n`;
109
253
  }
254
+ function appendScriptSetupDeclarations(code, declarations) {
255
+ if (!declarations) return code;
256
+ return code ? `${code}\n\n${declarations}\n` : `${declarations}\n`;
257
+ }
110
258
  function createSyntheticScriptSetup(moduleNames) {
111
259
  const content = createWxsModuleDeclarations(moduleNames);
112
260
  if (!content) return;
@@ -135,54 +283,248 @@ function createSyntheticScriptSetup(moduleNames) {
135
283
  name: "scriptSetup"
136
284
  };
137
285
  }
138
- function normalizeFilename(filename) {
139
- if (!filename) return "";
140
- return filename.replace(BACKSLASH_RE, "/");
286
+ function syncScriptBlockSource(block) {
287
+ if (!block) return;
288
+ const attrs = Object.entries(block.attrs ?? {}).filter(([, value]) => value != null).map(([key, value]) => value === true ? key : `${key}="${String(value)}"`).join(" ");
289
+ const openTag = attrs ? `<script ${attrs}>` : "<script>";
290
+ block.loc.source = `${openTag}\n${block.content}\n<\/script>`;
141
291
  }
142
- function inferConfigType(filename) {
143
- const normalized = normalizeFilename(filename);
144
- if (normalized.endsWith("/app.vue")) return "App";
145
- if (normalized.includes("/plugin/")) return "Plugin";
146
- if (normalized.includes("/components/")) return "Component";
147
- if (normalized.includes("/theme/")) return "Theme";
148
- if (normalized.includes("/sitemap")) return "Sitemap";
149
- return "Page";
292
+ function isIdentifierName(name) {
293
+ return IDENTIFIER_NAME_RE.test(name);
150
294
  }
151
- function normalizeLang(lang) {
152
- if (!lang) return JSON_LANG;
153
- const lower = lang.toLowerCase();
154
- if (lower === "txt") return JSON_LANG;
155
- return lower;
295
+ function getPropertyNameText(node, tsModule) {
296
+ if (tsModule.isIdentifier(node) || tsModule.isStringLiteral(node) || tsModule.isNumericLiteral(node)) return node.text;
156
297
  }
157
- function findExportDefaultExpression(code, tsModule, lang) {
158
- const scriptKind = lang === TS_LANG ? tsModule.ScriptKind.TS : tsModule.ScriptKind.JS;
159
- const sourceFile = tsModule.createSourceFile(`config.${lang}`, code, tsModule.ScriptTarget.Latest, true, scriptKind);
160
- for (const statement of sourceFile.statements) if (tsModule.isExportAssignment(statement)) {
161
- const expressionStart = statement.expression.getStart(sourceFile);
162
- const expressionEnd = statement.expression.getEnd();
163
- const leading = code.slice(0, statement.getStart(sourceFile));
164
- return {
165
- expression: code.slice(expressionStart, expressionEnd),
166
- expressionStart,
167
- expressionEnd,
168
- leading,
169
- trailing: code.slice(statement.getEnd())
170
- };
298
+ function collectBindingNames(name, tsModule, bindings) {
299
+ if (tsModule.isIdentifier(name)) {
300
+ bindings.add(name.text);
301
+ return;
302
+ }
303
+ for (const element of name.elements) if (tsModule.isBindingElement(element)) collectBindingNames(element.name, tsModule, bindings);
304
+ }
305
+ function collectTopLevelBindingNames(code, tsModule, lang) {
306
+ const scriptKind = lang === "ts" ? 3 : 1;
307
+ const sourceFile = tsModule.createSourceFile(`bindings.${lang}`, code, 99, true, scriptKind);
308
+ const bindings = /* @__PURE__ */ new Set();
309
+ for (const statement of sourceFile.statements) {
310
+ if (tsModule.isVariableStatement(statement)) {
311
+ for (const declaration of statement.declarationList.declarations) collectBindingNames(declaration.name, tsModule, bindings);
312
+ continue;
313
+ }
314
+ if ((tsModule.isFunctionDeclaration(statement) || tsModule.isClassDeclaration(statement) || tsModule.isEnumDeclaration(statement)) && statement.name) {
315
+ bindings.add(statement.name.text);
316
+ continue;
317
+ }
318
+ if (tsModule.isImportDeclaration(statement) && statement.importClause) {
319
+ const { importClause } = statement;
320
+ if (importClause.name) bindings.add(importClause.name.text);
321
+ if (importClause.namedBindings) if (tsModule.isNamespaceImport(importClause.namedBindings)) bindings.add(importClause.namedBindings.name.text);
322
+ else for (const element of importClause.namedBindings.elements) bindings.add(element.name.text);
323
+ }
324
+ }
325
+ return bindings;
326
+ }
327
+ function unwrapParenthesizedExpression(node, tsModule) {
328
+ let current = node;
329
+ while (tsModule.isParenthesizedExpression(current)) current = current.expression;
330
+ return current;
331
+ }
332
+ function findReturnedExpression(node, tsModule) {
333
+ if (tsModule.isObjectLiteralExpression(node)) return node;
334
+ if (!tsModule.isBlock(node)) return node;
335
+ for (const statement of node.statements) {
336
+ if (!tsModule.isReturnStatement(statement) || !statement.expression) continue;
337
+ return unwrapParenthesizedExpression(statement.expression, tsModule);
338
+ }
339
+ }
340
+ function findReturnedObjectLiteral(node, tsModule) {
341
+ const expression = findReturnedExpression(node, tsModule);
342
+ return expression && tsModule.isObjectLiteralExpression(expression) ? expression : void 0;
343
+ }
344
+ function extractDefineOptionsObjectLiteral(node, tsModule) {
345
+ if (!tsModule.isIdentifier(node.expression) || node.expression.text !== "defineOptions") return;
346
+ const [firstArg] = node.arguments;
347
+ if (!firstArg) return;
348
+ const arg = unwrapParenthesizedExpression(firstArg, tsModule);
349
+ if (tsModule.isObjectLiteralExpression(arg)) return arg;
350
+ if (tsModule.isArrowFunction(arg) || tsModule.isFunctionExpression(arg)) return findReturnedObjectLiteral(arg.body, tsModule);
351
+ }
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;
171
369
  }
172
370
  return null;
173
371
  }
174
- function injectSchemaIntoJsonObject(content, schemaId) {
175
- const trimmed = content.trim();
176
- if (!trimmed.startsWith("{")) return content;
177
- const leftBraceIndex = content.indexOf("{");
178
- if (leftBraceIndex < 0) return content;
179
- const firstNonSpace = content.slice(leftBraceIndex + 1).match(NON_SPACE_RE);
180
- const nextCharIndex = firstNonSpace ? leftBraceIndex + 1 + firstNonSpace.index : -1;
181
- const isEmptyObject = nextCharIndex >= 0 && content[nextCharIndex] === "}";
182
- const schemaLine = ` "$schema": "${schemaId}"`;
183
- const injected = isEmptyObject ? `{\n${schemaLine}\n}` : `{\n${schemaLine},${content.slice(leftBraceIndex + 1)}`;
184
- if (trimmed === content) return injected;
185
- return `${content.slice(0, content.indexOf(trimmed))}${injected}${content.slice(content.indexOf(trimmed) + trimmed.length)}`;
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";
380
+ for (const property of node.properties) {
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(" | ")})[]`;
401
+ }
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";
430
+ }
431
+ function collectDefineOptionsTemplateBindings(code, tsModule, lang) {
432
+ const scriptKind = lang === "ts" ? 3 : 1;
433
+ const sourceFile = tsModule.createSourceFile(`script-setup.${lang}`, code, 99, true, scriptKind);
434
+ const valueBindings = /* @__PURE__ */ new Map();
435
+ const functionBindings = /* @__PURE__ */ new Map();
436
+ const visit = (node) => {
437
+ if (tsModule.isCallExpression(node)) {
438
+ const optionsObject = extractDefineOptionsObjectLiteral(node, tsModule);
439
+ if (optionsObject) for (const property of optionsObject.properties) {
440
+ const sectionName = tsModule.isPropertyAssignment(property) || tsModule.isMethodDeclaration(property) ? getPropertyNameText(property.name, tsModule) : void 0;
441
+ if (!sectionName) continue;
442
+ if (sectionName === "methods") {
443
+ const methodsObject = tsModule.isPropertyAssignment(property) ? unwrapParenthesizedExpression(property.initializer, tsModule) : void 0;
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
+ }
450
+ continue;
451
+ }
452
+ if (sectionName === "properties" || sectionName === "computed") {
453
+ const objectValue = tsModule.isPropertyAssignment(property) ? unwrapParenthesizedExpression(property.initializer, tsModule) : void 0;
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
+ }
468
+ continue;
469
+ }
470
+ if (sectionName === "data") {
471
+ let dataObject;
472
+ if (tsModule.isMethodDeclaration(property)) dataObject = findReturnedObjectLiteral(property.body ?? tsModule.factory.createBlock([], false), tsModule);
473
+ else if (tsModule.isPropertyAssignment(property)) {
474
+ const initializer = unwrapParenthesizedExpression(property.initializer, 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");
483
+ }
484
+ }
485
+ }
486
+ }
487
+ tsModule.forEachChild(node, visit);
488
+ };
489
+ visit(sourceFile);
490
+ return {
491
+ values: [...valueBindings],
492
+ functions: [...functionBindings]
493
+ };
494
+ }
495
+ function createDefineOptionsTemplateDeclarations(code, tsModule, lang) {
496
+ const topLevelBindings = collectTopLevelBindingNames(code, tsModule, lang);
497
+ const bindings = collectDefineOptionsTemplateBindings(code, tsModule, lang);
498
+ const declarations = [];
499
+ for (const [name, typeText] of bindings.values) {
500
+ if (topLevelBindings.has(name)) continue;
501
+ declarations.push(`const ${name}: ${typeText} = null as any`);
502
+ }
503
+ for (const [name, typeText] of bindings.functions) {
504
+ if (topLevelBindings.has(name)) continue;
505
+ declarations.push(`const ${name}: ${typeText} = null as any`);
506
+ }
507
+ return declarations.join("\n");
508
+ }
509
+ function resolveScriptSetupLang(lang) {
510
+ return lang === "js" ? "js" : "ts";
511
+ }
512
+ //#endregion
513
+ //#region src/index.ts
514
+ const require$1 = (0, node_module.createRequire)(typeof module !== "undefined" && module.filename ? module.filename : node_path.default.join(node_process.default.cwd(), "weapp-vite-volar.cjs"));
515
+ let hasSchematicsTypes = false;
516
+ try {
517
+ require$1.resolve("@weapp-core/schematics");
518
+ hasSchematicsTypes = true;
519
+ } catch {
520
+ hasSchematicsTypes = false;
521
+ }
522
+ function parseVueSfc(content, filename = "component.vue") {
523
+ try {
524
+ return require$1("@vue/compiler-sfc").parse(content, { filename });
525
+ } catch {
526
+ return;
527
+ }
186
528
  }
187
529
  /**
188
530
  * Volar 语言插件:为 weapp 配置块提供类型与 schema 提示。
@@ -204,118 +546,21 @@ const plugin = (ctx) => {
204
546
  if (!parsed) return;
205
547
  const descriptor = parsed.descriptor;
206
548
  const wxsModuleNames = collectWxsModuleNames(descriptor.template?.content);
207
- if (!wxsModuleNames.length) return parsed;
208
- if (descriptor.scriptSetup) descriptor.scriptSetup.content = appendWxsDeclarations(descriptor.scriptSetup.content, wxsModuleNames);
209
- else descriptor.scriptSetup = createSyntheticScriptSetup(wxsModuleNames);
549
+ const scriptSetup = descriptor.scriptSetup;
550
+ const scriptSetupLang = resolveScriptSetupLang(scriptSetup?.lang);
551
+ const defineOptionsDeclarations = scriptSetup?.content && tsModule ? createDefineOptionsTemplateDeclarations(scriptSetup.content, tsModule, scriptSetupLang) : "";
552
+ if (!wxsModuleNames.length && !defineOptionsDeclarations) return parsed;
553
+ if (descriptor.scriptSetup) {
554
+ descriptor.scriptSetup.content = appendScriptSetupDeclarations(appendWxsDeclarations(descriptor.scriptSetup.content, wxsModuleNames), defineOptionsDeclarations);
555
+ syncScriptBlockSource(descriptor.scriptSetup);
556
+ } else descriptor.scriptSetup = createSyntheticScriptSetup(wxsModuleNames);
210
557
  return parsed;
211
558
  },
212
559
  getEmbeddedCodes(_, sfc) {
213
- const names = [];
214
- for (let i = 0; i < sfc.customBlocks.length; i++) {
215
- const block = sfc.customBlocks[i];
216
- if (block.type === BLOCK_TYPE) {
217
- const normalizedLang = normalizeLang(block.lang);
218
- if (normalizedLang === JS_LANG || normalizedLang === TS_LANG) {
219
- names.push({
220
- id: `${BLOCK_TYPE}_${i}`,
221
- lang: TS_LANG
222
- });
223
- continue;
224
- }
225
- const embeddedLang = normalizedLang === JSON_LANG || normalizedLang === JSONC_LANG || normalizedLang === JSON5_LANG ? JSONC_LANG : JSON_LANG;
226
- names.push({
227
- id: `${BLOCK_TYPE}_${i}`,
228
- lang: embeddedLang
229
- });
230
- }
231
- }
232
- return names;
560
+ return getEmbeddedCodesFromCustomBlocks(sfc);
233
561
  },
234
562
  resolveEmbeddedCode(fileName, sfc, embeddedCode) {
235
- const match = embeddedCode.id.match(new RegExp(`^${BLOCK_TYPE}_(\\d+)$`));
236
- if (!match) return;
237
- const index = Number.parseInt(match[1]);
238
- const block = sfc.customBlocks[index];
239
- if (!block) return;
240
- const normalizedLang = normalizeLang(block.lang);
241
- const configType = inferConfigType(fileName);
242
- if (!hasSchematicsTypes) {
243
- embeddedCode.content.push([
244
- block.content,
245
- block.name,
246
- 0,
247
- FULL_CAPABILITIES
248
- ]);
249
- return;
250
- }
251
- if (normalizedLang === JS_LANG || normalizedLang === TS_LANG) {
252
- const parsed = tsModule && findExportDefaultExpression(block.content, tsModule, normalizedLang);
253
- if (parsed && hasSchematicsTypes) {
254
- const typeImport = `import type { ${configType} as __WeappConfig } from '@weapp-core/schematics'\n`;
255
- embeddedCode.content.push([
256
- `${typeImport}const __weapp_defineConfig = <T extends __WeappConfig>(config: T) => config
257
-
258
- `,
259
- void 0,
260
- 0,
261
- VOID_CAPABILITIES
262
- ]);
263
- if (parsed.leading) embeddedCode.content.push([
264
- parsed.leading,
265
- block.name,
266
- 0,
267
- FULL_CAPABILITIES
268
- ]);
269
- embeddedCode.content.push([
270
- "export default __weapp_defineConfig(",
271
- void 0,
272
- parsed.expressionStart,
273
- VOID_CAPABILITIES
274
- ]);
275
- embeddedCode.content.push([
276
- parsed.expression,
277
- block.name,
278
- parsed.expressionStart,
279
- FULL_CAPABILITIES
280
- ]);
281
- embeddedCode.content.push([
282
- ")",
283
- void 0,
284
- parsed.expressionEnd,
285
- VOID_CAPABILITIES
286
- ]);
287
- if (parsed.trailing) embeddedCode.content.push([
288
- parsed.trailing,
289
- block.name,
290
- parsed.expressionEnd,
291
- FULL_CAPABILITIES
292
- ]);
293
- return;
294
- }
295
- embeddedCode.content.push([
296
- block.content,
297
- block.name,
298
- 0,
299
- FULL_CAPABILITIES
300
- ]);
301
- return;
302
- }
303
- const schema = getSchemaForType(configType);
304
- if (schema && schema.$id && !block.content.includes("$schema")) {
305
- embeddedCode.content.push([
306
- injectSchemaIntoJsonObject(block.content, schema.$id),
307
- block.name,
308
- 0,
309
- FULL_CAPABILITIES
310
- ]);
311
- return;
312
- }
313
- embeddedCode.content.push([
314
- block.content,
315
- block.name,
316
- 0,
317
- FULL_CAPABILITIES
318
- ]);
563
+ resolveEmbeddedJsonBlock(fileName, sfc, embeddedCode, tsModule, hasSchematicsTypes);
319
564
  }
320
565
  };
321
566
  };