@vue/language-core 3.3.5 → 3.3.7

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.
Files changed (72) hide show
  1. package/index.d.ts +1 -0
  2. package/index.js +1 -0
  3. package/lib/codegen/codeFeatures.d.ts +24 -84
  4. package/lib/codegen/codeFeatures.js +46 -4
  5. package/lib/codegen/names.d.ts +3 -4
  6. package/lib/codegen/names.js +3 -4
  7. package/lib/codegen/script/index.js +5 -5
  8. package/lib/codegen/script/scriptSetup.js +4 -4
  9. package/lib/codegen/style/common.js +7 -11
  10. package/lib/codegen/style/index.d.ts +55 -27
  11. package/lib/codegen/style/index.js +4 -4
  12. package/lib/codegen/style/modules.d.ts +1 -1
  13. package/lib/codegen/style/modules.js +1 -1
  14. package/lib/codegen/style/scopedClasses.d.ts +2 -1
  15. package/lib/codegen/style/scopedClasses.js +5 -4
  16. package/lib/codegen/template/context.d.ts +55 -124
  17. package/lib/codegen/template/context.js +187 -269
  18. package/lib/codegen/template/element.js +18 -103
  19. package/lib/codegen/template/elementDirectives.js +11 -11
  20. package/lib/codegen/template/elementEvents.js +50 -45
  21. package/lib/codegen/template/elementProps.js +12 -12
  22. package/lib/codegen/template/index.d.ts +55 -27
  23. package/lib/codegen/template/index.js +7 -7
  24. package/lib/codegen/template/interpolation.js +28 -28
  25. package/lib/codegen/template/objectProperty.js +5 -5
  26. package/lib/codegen/template/propertyAccess.js +1 -1
  27. package/lib/codegen/template/slotOutlet.js +8 -10
  28. package/lib/codegen/template/styleScopedClasses.d.ts +3 -0
  29. package/lib/codegen/template/styleScopedClasses.js +126 -4
  30. package/lib/codegen/template/vFor.js +3 -3
  31. package/lib/codegen/template/vIf.js +4 -4
  32. package/lib/codegen/template/vSlot.js +9 -9
  33. package/lib/codegen/utils/boundary.d.ts +7 -2
  34. package/lib/codegen/utils/boundary.js +15 -9
  35. package/lib/codegen/utils/camelized.js +5 -13
  36. package/lib/codegen/utils/escaped.js +4 -9
  37. package/lib/codegen/utils/index.d.ts +1 -1
  38. package/lib/codegen/utils/index.js +3 -3
  39. package/lib/codegen/utils/stringLiteralKey.js +3 -3
  40. package/lib/codegen/utils/unicode.d.ts +1 -1
  41. package/lib/codegen/utils/unicode.js +4 -4
  42. package/lib/languagePlugin.js +2 -1
  43. package/lib/parsers/scriptRanges.d.ts +2 -2
  44. package/lib/parsers/scriptRanges.js +3 -10
  45. package/lib/parsers/scriptSetupRanges.d.ts +2 -2
  46. package/lib/parsers/scriptSetupRanges.js +3 -10
  47. package/lib/parsers/utils.d.ts +1 -0
  48. package/lib/parsers/utils.js +10 -0
  49. package/lib/parsers/vueCompilerOptions.js +2 -2
  50. package/lib/plugins/file-html.js +4 -4
  51. package/lib/plugins/file-md.js +15 -15
  52. package/lib/plugins/file-vue.js +2 -2
  53. package/lib/plugins/vue-root-tags.js +3 -3
  54. package/lib/plugins/vue-sfc-customblocks.js +2 -2
  55. package/lib/plugins/vue-sfc-scripts.js +2 -4
  56. package/lib/plugins/vue-sfc-styles.js +3 -3
  57. package/lib/plugins/vue-sfc-template.js +2 -2
  58. package/lib/plugins/vue-style-css.js +86 -33
  59. package/lib/plugins/vue-template-html.js +3 -3
  60. package/lib/plugins/vue-template-inline-css.js +2 -7
  61. package/lib/plugins/vue-template-inline-ts.js +4 -5
  62. package/lib/plugins/vue-tsx.d.ts +61 -31
  63. package/lib/plugins/vue-tsx.js +26 -23
  64. package/lib/plugins.d.ts +0 -1
  65. package/lib/plugins.js +0 -15
  66. package/lib/types.d.ts +1 -1
  67. package/lib/utils/forEachTemplateNode.js +36 -43
  68. package/lib/virtualCode/index.js +2 -2
  69. package/package.json +4 -4
  70. package/types/template-helpers.d.ts +14 -24
  71. package/lib/plugins/shared.d.ts +0 -2
  72. package/lib/plugins/shared.js +0 -12
@@ -34,304 +34,91 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.createTemplateCodegenContext = createTemplateCodegenContext;
37
+ const language_core_1 = require("@volar/language-core");
37
38
  const CompilerDOM = __importStar(require("@vue/compiler-dom"));
38
39
  const codeFeatures_1 = require("../codeFeatures");
39
40
  const utils_1 = require("../utils");
40
41
  const boundary_1 = require("../utils/boundary");
41
- const commentDirectiveRegex = /^<!--\s*@vue-(?<name>[-\w]+)\b(?<content>[\s\S]*)-->$/;
42
- /**
43
- * Creates and returns a Context object used for generating type-checkable TS code
44
- * from the template section of a .vue file.
45
- *
46
- * ## Implementation Notes for supporting `@vue-ignore`, `@vue-expect-error`, and `@vue-skip` directives.
47
- *
48
- * Vue language tooling supports a number of directives for suppressing diagnostics within
49
- * Vue templates (https://github.com/vuejs/language-tools/pull/3215)
50
- *
51
- * Here is an overview for how support for how @vue-expect-error is implemented within this file
52
- * (@vue-expect-error is the most complicated directive to support due to its behavior of raising
53
- * a diagnostic when it is annotating a piece of code that doesn't actually have any errors/warning/diagnostics).
54
- *
55
- * Given .vue code:
56
- *
57
- * ```vue
58
- * <script setup lang="ts">
59
- * defineProps<{
60
- * knownProp1: string;
61
- * knownProp2: string;
62
- * knownProp3: string;
63
- * knownProp4_will_trigger_unused_expect_error: string;
64
- * }>();
65
- * </script>
66
- *
67
- * <template>
68
- * {{ knownProp1 }}
69
- * {{ error_unknownProp }} <!-- ERROR: Property 'error_unknownProp' does not exist on type [...] -->
70
- * {{ knownProp2 }}
71
- * <!-- @vue-expect-error This suppresses an Unknown Property Error -->
72
- * {{ suppressed_error_unknownProp }}
73
- * {{ knownProp3 }}
74
- * <!-- @vue-expect-error This will trigger Unused '@ts-expect-error' directive.ts(2578) -->
75
- * {{ knownProp4_will_trigger_unused_expect_error }}
76
- * </template>
77
- * ```
78
- *
79
- * The above code should raise two diagnostics:
80
- *
81
- * 1. Property 'error_unknownProp' does not exist on type [...]
82
- * 2. Unused '@ts-expect-error' directive.ts(2578) -- this is the bottom `@vue-expect-error` directive
83
- * that covers code that doesn't actually raise an error -- note that all `@vue-...` directives
84
- * will ultimately translate into `@ts-...` diagnostics.
85
- *
86
- * The above code will produce the following type-checkable TS code (note: omitting asterisks
87
- * to prevent VSCode syntax double-greying out double-commented code).
88
- *
89
- * ```ts
90
- * ( __VLS_ctx.knownProp1 );
91
- * ( __VLS_ctx.error_unknownProp ); // ERROR: Property 'error_unknownProp' does not exist on type [...]
92
- * ( __VLS_ctx.knownProp2 );
93
- * // @vue-expect-error start
94
- * ( __VLS_ctx.suppressed_error_unknownProp );
95
- * // @ts-expect-error __VLS_TS_EXPECT_ERROR
96
- * ;
97
- * // @vue-expect-error end of INTERPOLATION
98
- * ( __VLS_ctx.knownProp3 );
99
- * // @vue-expect-error start
100
- * ( __VLS_ctx.knownProp4_will_trigger_unused_expect_error );
101
- * // @ts-expect-error __VLS_TS_EXPECT_ERROR
102
- * ;
103
- * // @vue-expect-error end of INTERPOLATION
104
- * ```
105
- *
106
- * In the generated code, there are actually 3 diagnostic errors that'll be raised in the first
107
- * pass on this generated code (but through cleverness described below, not all of them will be
108
- * propagated back to the original .vue file):
109
- *
110
- * 1. Property 'error_unknownProp' does not exist on type [...]
111
- * 2. Unused '@ts-expect-error' directive.ts(2578) from the 1st `@ts-expect-error __VLS_TS_EXPECT_ERROR`
112
- * 3. Unused '@ts-expect-error' directive.ts(2578) from the 2nd `@ts-expect-error __VLS_TS_EXPECT_ERROR`
113
- *
114
- * Be sure to pay careful attention to the mixture of `@vue-expect-error` and `@ts-expect-error`;
115
- * Within the TS file, the only "real" directives recognized by TS are going to be prefixed with `@ts-`;
116
- * any `@vue-` prefixed directives in the comments are only for debugging purposes.
117
- *
118
- * As mentioned above, there are 3 diagnostics errors that'll be generated for the above code, but
119
- * only 2 should be propagated back to the original .vue file.
120
- *
121
- * (The reason we structure things this way is somewhat complicated, but in short it allows us
122
- * to lean on TS as much as possible to generate actual `unused @ts-expect-error directive` errors
123
- * while covering a number of edge cases.)
124
- *
125
- * So, we need a way to dynamically decide whether each of the `@ts-expect-error __VLS_TS_EXPECT_ERROR`
126
- * directives should be reported as an unused directive or not.
127
- *
128
- * To do this, we'll make use of the `shouldReport` callback that'll optionally be provided to the
129
- * `verification` property of the `CodeInformation` object attached to the mapping between source .vue
130
- * and generated .ts code. The `verification` property determines whether "verification" (which includes
131
- * semantic diagnostics) should be performed on the generated .ts code, and `shouldReport`, if provided,
132
- * can be used to determine whether a given diagnostic should be reported back "upwards" to the original
133
- * .vue file or not.
134
- *
135
- * See the comments in the code below for how and where we use this hook to keep track of whether
136
- * an error/diagnostic was encountered for a region of code covered by a `@vue-expect-error` directive,
137
- * and additionally how we use that to determine whether to propagate diagnostics back upward.
138
- */
42
+ const directiveCommentRE = /^<!--\s*@vue-(?<name>[-\w]+)\b(?<content>[\s\S]*)-->$/;
139
43
  function createTemplateCodegenContext() {
140
- let variableId = 0;
141
- const scopes = [];
142
- const components = [];
143
- const hoistVars = new Map();
144
- const dollarVars = new Set();
145
- const componentAccessMap = new Map();
146
- const slots = [];
147
- const dynamicSlots = [];
148
- const blockConditions = [];
149
- const inlayHints = [];
150
- const inheritedAttrVars = new Set();
151
- const templateRefs = new Map();
44
+ // directive comments ---------------------------------------------------------
152
45
  const stack = [];
153
46
  const commentBuffer = [];
154
- return {
155
- generatedTypes: new Set(),
156
- get currentInfo() {
157
- return stack[stack.length - 1];
158
- },
159
- resolveCodeFeatures,
160
- inVFor: false,
161
- slots,
162
- dynamicSlots,
163
- dollarVars,
164
- componentAccessMap,
165
- blockConditions,
166
- inlayHints,
167
- inheritedAttrVars,
168
- templateRefs,
169
- singleRootElTypes: new Set(),
170
- singleRootNodes: new Set(),
171
- addTemplateRef(name, typeExp, offset) {
172
- let refs = templateRefs.get(name);
173
- if (!refs) {
174
- templateRefs.set(name, refs = []);
175
- }
176
- refs.push({ typeExp, offset });
177
- },
178
- recordComponentAccess(source, name, offset) {
179
- let map = componentAccessMap.get(name);
180
- if (!map) {
181
- componentAccessMap.set(name, map = new Map());
182
- }
183
- let arr = map.get(source);
184
- if (!arr) {
185
- map.set(source, arr = new Set());
186
- }
187
- if (offset !== undefined) {
188
- arr.add(offset);
189
- }
190
- },
191
- scopes,
192
- components,
193
- declare(...varNames) {
194
- const scope = scopes.at(-1);
195
- for (const varName of varNames) {
196
- scope.add(varName);
197
- }
198
- },
199
- startScope() {
200
- const scope = new Set();
201
- scopes.push(scope);
202
- return () => {
203
- scopes.pop();
204
- return generateAutoImport();
205
- };
206
- },
207
- getInternalVariable() {
208
- return `__VLS_${variableId++}`;
209
- },
210
- getHoistVariable(originalVar) {
211
- let name = hoistVars.get(originalVar);
212
- if (name === undefined) {
213
- hoistVars.set(originalVar, name = `__VLS_${variableId++}`);
214
- }
215
- return name;
216
- },
217
- *generateHoistVariables() {
218
- // trick to avoid TS 4081 (#5186)
219
- if (hoistVars.size) {
220
- yield `// @ts-ignore${utils_1.newLine}`;
221
- yield `var `;
222
- for (const [originalVar, hoistVar] of hoistVars) {
223
- yield `${hoistVar} = ${originalVar}, `;
224
- }
225
- yield utils_1.endOfLine;
226
- }
227
- },
228
- *generateConditionGuards() {
229
- for (const condition of blockConditions) {
230
- yield `if (!${condition}) return${utils_1.endOfLine}`;
231
- }
232
- },
233
- enter(node) {
234
- if (node.type === CompilerDOM.NodeTypes.COMMENT) {
235
- commentBuffer.push(node);
236
- return false;
237
- }
238
- const data = {};
239
- const comments = [...commentBuffer];
240
- commentBuffer.length = 0;
241
- for (const comment of comments) {
242
- const match = comment.loc.source.match(commentDirectiveRegex);
243
- if (match) {
244
- const { name, content } = match.groups;
245
- switch (name) {
246
- case 'skip': {
247
- return false;
248
- }
249
- case 'ignore': {
250
- data.ignoreError = true;
251
- break;
252
- }
253
- case 'expect-error': {
254
- data.expectError = {
255
- token: 0,
256
- node: comment,
47
+ function getCommentInfo() {
48
+ return stack[stack.length - 1];
49
+ }
50
+ function enter(node) {
51
+ if (node.type === CompilerDOM.NodeTypes.COMMENT) {
52
+ commentBuffer.push(node);
53
+ return false;
54
+ }
55
+ const info = {};
56
+ const comments = [...commentBuffer];
57
+ commentBuffer.length = 0;
58
+ for (const comment of comments) {
59
+ const match = comment.loc.source.match(directiveCommentRE);
60
+ if (match) {
61
+ const { name, content } = match.groups;
62
+ switch (name) {
63
+ case 'skip': {
64
+ return false;
65
+ }
66
+ case 'ignore': {
67
+ info.ignoreError = true;
68
+ break;
69
+ }
70
+ case 'expect-error': {
71
+ info.expectError = {
72
+ token: 0,
73
+ node: comment,
74
+ };
75
+ break;
76
+ }
77
+ case 'generic': {
78
+ const text = content.trim();
79
+ if (text.startsWith('{') && text.endsWith('}')) {
80
+ info.generic = {
81
+ content: text.slice(1, -1),
82
+ offset: comment.loc.start.offset + comment.loc.source.indexOf('{') + 1,
257
83
  };
258
- break;
259
- }
260
- case 'generic': {
261
- const text = content.trim();
262
- if (text.startsWith('{') && text.endsWith('}')) {
263
- data.generic = {
264
- content: text.slice(1, -1),
265
- offset: comment.loc.start.offset + comment.loc.source.indexOf('{') + 1,
266
- };
267
- }
268
- break;
269
84
  }
85
+ break;
270
86
  }
271
87
  }
272
88
  }
273
- stack.push(data);
274
- return true;
275
- },
276
- *exit() {
277
- const data = stack.pop();
278
- commentBuffer.length = 0;
279
- if (data.expectError !== undefined) {
280
- const token = yield* (0, boundary_1.startBoundary)('template', data.expectError.node.loc.start.offset, {
281
- verification: {
282
- // If no errors/warnings/diagnostics were reported within the region of code covered
283
- // by the @vue-expect-error directive, then we should allow any `unused @ts-expect-error`
284
- // diagnostics to be reported upward.
285
- shouldReport: () => data.expectError.token === 0,
286
- },
287
- });
288
- yield `// @ts-expect-error`;
289
- yield (0, boundary_1.endBoundary)(token, data.expectError.node.loc.end.offset);
290
- yield `${utils_1.newLine}${utils_1.endOfLine}`;
291
- }
292
- },
293
- };
294
- function* generateAutoImport() {
295
- const all = [...componentAccessMap.entries()];
296
- if (!all.some(([, offsets]) => offsets.size)) {
297
- return;
298
89
  }
299
- yield `// @ts-ignore${utils_1.newLine}`; // #2304
300
- yield `[`;
301
- for (const [varName, map] of all) {
302
- for (const [source, offsets] of map) {
303
- for (const offset of offsets) {
304
- yield [varName, source, offset, codeFeatures_1.codeFeatures.importCompletionOnly];
305
- yield `,`;
306
- }
307
- offsets.clear();
308
- }
90
+ stack.push(info);
91
+ return true;
92
+ }
93
+ function* exit() {
94
+ const info = stack.pop();
95
+ commentBuffer.length = 0;
96
+ if (info.expectError !== undefined) {
97
+ const boundary = yield* boundary_1.Boundary.start('template', info.expectError.node.loc.start.offset, {
98
+ verification: {
99
+ shouldReport: () => info.expectError.token === 0,
100
+ },
101
+ });
102
+ yield `// @ts-expect-error`;
103
+ yield boundary.end(info.expectError.node.loc.end.offset);
104
+ yield `${utils_1.newLine}${utils_1.endOfLine}`;
309
105
  }
310
- yield `]${utils_1.endOfLine}`;
311
106
  }
312
107
  function resolveCodeFeatures(features) {
313
108
  if (features.verification && stack.length) {
314
109
  const data = stack[stack.length - 1];
315
110
  if (data.ignoreError) {
316
- // We are currently in a region of code covered by a @vue-ignore directive, so don't
317
- // even bother performing any type-checking: set verification to false.
318
111
  return {
319
112
  ...features,
320
113
  verification: false,
321
114
  };
322
115
  }
323
116
  if (data.expectError !== undefined) {
324
- // We are currently in a region of code covered by a @vue-expect-error directive. We need to
325
- // keep track of the number of errors encountered within this region so that we can know whether
326
- // we will need to propagate an "unused ts-expect-error" diagnostic back to the original
327
- // .vue file or not.
328
117
  return {
329
118
  ...features,
330
119
  verification: {
331
120
  shouldReport: (source, code) => {
332
- if (typeof features.verification !== 'object'
333
- || !features.verification.shouldReport
334
- || features.verification.shouldReport(source, code) === true) {
121
+ if ((0, language_core_1.shouldReportDiagnostics)(features, source, code)) {
335
122
  data.expectError.token++;
336
123
  }
337
124
  return false;
@@ -342,5 +129,136 @@ function createTemplateCodegenContext() {
342
129
  }
343
130
  return features;
344
131
  }
132
+ // internal variables ---------------------------------------------------------
133
+ let variableId = 0;
134
+ function getInternalVariable() {
135
+ return `__VLS_${variableId++}`;
136
+ }
137
+ // scopes ---------------------------------------------------------------------
138
+ class Scope extends Set {
139
+ declare(...variables) {
140
+ for (const name of variables) {
141
+ this.add(name);
142
+ }
143
+ }
144
+ end() {
145
+ scopes.pop();
146
+ return generateAutoImport();
147
+ }
148
+ }
149
+ const scopes = [];
150
+ function scope() {
151
+ const scope = new Scope();
152
+ scopes.push(scope);
153
+ return scope;
154
+ }
155
+ // context accesses -----------------------------------------------------------
156
+ const contextAccesses = new Map();
157
+ function accessVariable(source, name, offset) {
158
+ let map = contextAccesses.get(name);
159
+ if (!map) {
160
+ contextAccesses.set(name, map = new Map());
161
+ }
162
+ let arr = map.get(source);
163
+ if (!arr) {
164
+ map.set(source, arr = new Set());
165
+ }
166
+ if (offset !== undefined) {
167
+ arr.add(offset);
168
+ }
169
+ }
170
+ function* generateAutoImport() {
171
+ const all = [...contextAccesses.entries()];
172
+ if (!all.some(([, offsets]) => offsets.size)) {
173
+ return;
174
+ }
175
+ yield `// @ts-ignore${utils_1.newLine}`; // #2304
176
+ yield `[`;
177
+ for (const [varName, map] of all) {
178
+ for (const [source, offsets] of map) {
179
+ for (const offset of offsets) {
180
+ yield [varName, source, offset, codeFeatures_1.codeFeatures.importCompletionOnly];
181
+ yield `,`;
182
+ }
183
+ offsets.clear();
184
+ }
185
+ }
186
+ yield `]${utils_1.endOfLine}`;
187
+ }
188
+ // conditions -----------------------------------------------------------------
189
+ const conditions = [];
190
+ function* generateConditionGuards() {
191
+ for (const condition of conditions) {
192
+ yield `if (!${condition}) throw 0${utils_1.endOfLine}`;
193
+ }
194
+ }
195
+ // hoist vars -----------------------------------------------------------------
196
+ const hoistVars = new Map();
197
+ function getHoistVariable(originalVar) {
198
+ let name = hoistVars.get(originalVar);
199
+ if (name === undefined) {
200
+ hoistVars.set(originalVar, name = `__VLS_${variableId++}`);
201
+ }
202
+ return name;
203
+ }
204
+ function* generateHoistVariables() {
205
+ // trick to avoid TS 4081 (#5186)
206
+ if (hoistVars.size) {
207
+ yield `// @ts-ignore${utils_1.newLine}`;
208
+ yield `var `;
209
+ for (const [originalVar, hoistVar] of hoistVars) {
210
+ yield `${hoistVar} = ${originalVar}, `;
211
+ }
212
+ yield utils_1.endOfLine;
213
+ }
214
+ }
215
+ // template refs --------------------------------------------------------------
216
+ const templateRefs = new Map();
217
+ function addTemplateRef(name, typeExp, offset) {
218
+ let refs = templateRefs.get(name);
219
+ if (!refs) {
220
+ templateRefs.set(name, refs = []);
221
+ }
222
+ refs.push({ typeExp, offset });
223
+ }
224
+ // others ---------------------------------------------------------------------
225
+ const components = [];
226
+ const dollarVars = new Set();
227
+ const inlayHints = [];
228
+ const generatedTypes = new Set();
229
+ const inheritedAttrVars = new Set();
230
+ const singleRootElTypes = new Set();
231
+ const singleRootNodes = new Set();
232
+ const slots = [];
233
+ const dynamicSlots = [];
234
+ return {
235
+ getCommentInfo,
236
+ enter,
237
+ exit,
238
+ resolveCodeFeatures,
239
+ getInternalVariable,
240
+ scopes,
241
+ scope,
242
+ contextAccesses,
243
+ accessVariable,
244
+ generateAutoImport,
245
+ conditions,
246
+ generateConditionGuards,
247
+ hoistVars,
248
+ getHoistVariable,
249
+ generateHoistVariables,
250
+ templateRefs,
251
+ addTemplateRef,
252
+ components,
253
+ dollarVars,
254
+ inlayHints,
255
+ generatedTypes,
256
+ inheritedAttrVars,
257
+ singleRootElTypes,
258
+ singleRootNodes,
259
+ slots,
260
+ dynamicSlots,
261
+ inVFor: false,
262
+ };
345
263
  }
346
264
  //# sourceMappingURL=context.js.map