@vue/language-core 2.2.2 → 2.2.6

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 (90) hide show
  1. package/lib/codegen/globalTypes.js +21 -34
  2. package/lib/codegen/script/component.js +11 -9
  3. package/lib/codegen/script/componentSelf.js +4 -11
  4. package/lib/codegen/script/context.d.ts +0 -1
  5. package/lib/codegen/script/context.js +0 -1
  6. package/lib/codegen/script/index.d.ts +1 -4
  7. package/lib/codegen/script/index.js +8 -12
  8. package/lib/codegen/script/scriptSetup.js +90 -70
  9. package/lib/codegen/script/src.d.ts +2 -2
  10. package/lib/codegen/script/src.js +36 -37
  11. package/lib/codegen/script/styleModulesType.d.ts +1 -1
  12. package/lib/codegen/script/styleModulesType.js +2 -2
  13. package/lib/codegen/script/template.d.ts +1 -2
  14. package/lib/codegen/script/template.js +5 -53
  15. package/lib/codegen/style/classProperty.d.ts +2 -0
  16. package/lib/codegen/style/classProperty.js +18 -0
  17. package/lib/codegen/style/modules.d.ts +3 -0
  18. package/lib/codegen/style/modules.js +34 -0
  19. package/lib/codegen/style/scopedClasses.d.ts +4 -0
  20. package/lib/codegen/style/scopedClasses.js +32 -0
  21. package/lib/codegen/template/context.d.ts +106 -5
  22. package/lib/codegen/template/context.js +131 -6
  23. package/lib/codegen/template/element.d.ts +1 -1
  24. package/lib/codegen/template/element.js +74 -97
  25. package/lib/codegen/template/elementChildren.d.ts +1 -1
  26. package/lib/codegen/template/elementChildren.js +1 -13
  27. package/lib/codegen/template/elementDirectives.js +8 -6
  28. package/lib/codegen/template/elementEvents.d.ts +2 -1
  29. package/lib/codegen/template/elementEvents.js +52 -28
  30. package/lib/codegen/template/elementProps.d.ts +1 -1
  31. package/lib/codegen/template/elementProps.js +23 -20
  32. package/lib/codegen/template/index.js +29 -14
  33. package/lib/codegen/template/interpolation.js +5 -5
  34. package/lib/codegen/template/objectProperty.js +5 -4
  35. package/lib/codegen/template/propertyAccess.js +1 -1
  36. package/lib/codegen/template/slotOutlet.js +13 -11
  37. package/lib/codegen/template/styleScopedClasses.js +8 -58
  38. package/lib/codegen/template/templateChild.js +60 -28
  39. package/lib/codegen/template/vFor.js +2 -2
  40. package/lib/codegen/template/vIf.js +4 -8
  41. package/lib/codegen/template/vSlot.d.ts +1 -0
  42. package/lib/codegen/template/vSlot.js +14 -1
  43. package/lib/codegen/utils/camelized.d.ts +1 -1
  44. package/lib/codegen/utils/camelized.js +6 -6
  45. package/lib/codegen/utils/escaped.d.ts +2 -0
  46. package/lib/codegen/utils/escaped.js +23 -0
  47. package/lib/codegen/utils/index.d.ts +3 -3
  48. package/lib/codegen/utils/index.js +19 -15
  49. package/lib/codegen/utils/objectProperty.d.ts +3 -0
  50. package/lib/codegen/utils/objectProperty.js +41 -0
  51. package/lib/codegen/utils/stringLiteralKey.js +2 -1
  52. package/lib/codegen/utils/unicode.js +2 -2
  53. package/lib/codegen/utils/wrapWith.d.ts +3 -0
  54. package/lib/codegen/utils/wrapWith.js +24 -0
  55. package/lib/parsers/scriptSetupRanges.d.ts +2 -0
  56. package/lib/parsers/scriptSetupRanges.js +84 -106
  57. package/lib/plugins/file-md.js +3 -0
  58. package/lib/plugins/vue-template-inline-ts.js +3 -3
  59. package/lib/plugins/vue-tsx.d.ts +11 -8
  60. package/lib/plugins/vue-tsx.js +19 -28
  61. package/lib/types.d.ts +24 -14
  62. package/lib/utils/parseSfc.js +40 -16
  63. package/lib/utils/ts.js +17 -0
  64. package/lib/virtualFile/computedEmbeddedCodes.js +18 -11
  65. package/lib/virtualFile/computedSfc.js +21 -28
  66. package/lib/virtualFile/vueFile.d.ts +7 -10
  67. package/lib/virtualFile/vueFile.js +10 -4
  68. package/package.json +2 -2
  69. package/lib/codeFeatures.d.ts +0 -1
  70. package/lib/codeFeatures.js +0 -3
  71. package/lib/codegen/common.d.ts +0 -12
  72. package/lib/codegen/common.js +0 -79
  73. package/lib/codegen/script/binding.d.ts +0 -4
  74. package/lib/codegen/script/binding.js +0 -41
  75. package/lib/codegen/template/camelized.d.ts +0 -2
  76. package/lib/codegen/template/camelized.js +0 -31
  77. package/lib/codegen/utils/src.d.ts +0 -2
  78. package/lib/codegen/utils/src.js +0 -19
  79. package/lib/plugins/vue-style-class-names.d.ts +0 -5
  80. package/lib/plugins/vue-style-class-names.js +0 -32
  81. package/lib/plugins/vue-style-reference-link.d.ts +0 -1
  82. package/lib/plugins/vue-style-reference-link.js +0 -3
  83. package/lib/plugins/vue-style-reference-links.d.ts +0 -3
  84. package/lib/plugins/vue-style-reference-links.js +0 -26
  85. package/lib/plugins/vue-vine.d.ts +0 -3
  86. package/lib/plugins/vue-vine.js +0 -35
  87. package/lib/utils/findDestructuredProps.d.ts +0 -1
  88. package/lib/utils/findDestructuredProps.js +0 -3
  89. package/lib/utils/parseCssImports.d.ts +0 -4
  90. package/lib/utils/parseCssImports.js +0 -19
@@ -3,49 +3,48 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateSrc = generateSrc;
4
4
  const codeFeatures_1 = require("../codeFeatures");
5
5
  const utils_1 = require("../utils");
6
- function* generateSrc(script, src) {
7
- if (src.endsWith('.d.ts')) {
8
- src = src.slice(0, -'.d.ts'.length);
6
+ function* generateSrc(src) {
7
+ if (src === true) {
8
+ return;
9
9
  }
10
- else if (src.endsWith('.ts')) {
11
- src = src.slice(0, -'.ts'.length);
10
+ let { text } = src;
11
+ if (text.endsWith('.d.ts')) {
12
+ text = text.slice(0, -'.d.ts'.length);
12
13
  }
13
- else if (src.endsWith('.tsx')) {
14
- src = src.slice(0, -'.tsx'.length) + '.jsx';
14
+ else if (text.endsWith('.ts')) {
15
+ text = text.slice(0, -'.ts'.length);
15
16
  }
16
- if (!src.endsWith('.js') && !src.endsWith('.jsx')) {
17
- src = src + '.js';
17
+ else if (text.endsWith('.tsx')) {
18
+ text = text.slice(0, -'.tsx'.length) + '.jsx';
19
+ }
20
+ if (!text.endsWith('.js') && !text.endsWith('.jsx')) {
21
+ text = text + '.js';
18
22
  }
19
23
  yield `export * from `;
20
- yield [
21
- `'${src}'`,
22
- 'script',
23
- script.srcOffset - 1,
24
- {
25
- ...codeFeatures_1.codeFeatures.all,
26
- navigation: src === script.src
27
- ? true
28
- : {
29
- shouldRename: () => false,
30
- resolveRenameEditText(newName) {
31
- if (newName.endsWith('.jsx') || newName.endsWith('.js')) {
32
- newName = newName.split('.').slice(0, -1).join('.');
33
- }
34
- if (script?.src?.endsWith('.d.ts')) {
35
- newName = newName + '.d.ts';
36
- }
37
- else if (script?.src?.endsWith('.ts')) {
38
- newName = newName + '.ts';
39
- }
40
- else if (script?.src?.endsWith('.tsx')) {
41
- newName = newName + '.tsx';
42
- }
43
- return newName;
44
- },
24
+ yield* (0, utils_1.generateSfcBlockAttrValue)(src, text, {
25
+ ...codeFeatures_1.codeFeatures.all,
26
+ navigation: text === src.text
27
+ ? true
28
+ : {
29
+ shouldRename: () => false,
30
+ resolveRenameEditText(newName) {
31
+ if (newName.endsWith('.jsx') || newName.endsWith('.js')) {
32
+ newName = newName.split('.').slice(0, -1).join('.');
33
+ }
34
+ if (src?.text.endsWith('.d.ts')) {
35
+ newName = newName + '.d.ts';
36
+ }
37
+ else if (src?.text.endsWith('.ts')) {
38
+ newName = newName + '.ts';
39
+ }
40
+ else if (src?.text.endsWith('.tsx')) {
41
+ newName = newName + '.tsx';
42
+ }
43
+ return newName;
45
44
  },
46
- },
47
- ];
45
+ },
46
+ });
48
47
  yield utils_1.endOfLine;
49
- yield `export { default } from '${src}'${utils_1.endOfLine}`;
48
+ yield `export { default } from '${text}'${utils_1.endOfLine}`;
50
49
  }
51
50
  //# sourceMappingURL=src.js.map
@@ -1,4 +1,4 @@
1
1
  import type { Code } from '../../types';
2
2
  import type { ScriptCodegenContext } from './context';
3
- import type { ScriptCodegenOptions } from './index';
3
+ import { ScriptCodegenOptions } from './index';
4
4
  export declare function generateStyleModulesType(options: ScriptCodegenOptions, ctx: ScriptCodegenContext): Generator<Code>;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateStyleModulesType = generateStyleModulesType;
4
- const codeFeatures_1 = require("../codeFeatures");
5
4
  const utils_1 = require("../utils");
5
+ const index_1 = require("./index");
6
6
  const template_1 = require("./template");
7
7
  function* generateStyleModulesType(options, ctx) {
8
8
  const styles = options.sfc.styles.map((style, i) => [style, i]).filter(([style]) => style.module);
@@ -17,7 +17,7 @@ function* generateStyleModulesType(options, ctx) {
17
17
  name,
18
18
  'main',
19
19
  offset + 1,
20
- codeFeatures_1.codeFeatures.all
20
+ index_1.codeFeatures.all
21
21
  ];
22
22
  }
23
23
  else {
@@ -1,8 +1,7 @@
1
1
  import type { Code } from '../../types';
2
- import { TemplateCodegenContext } from '../template/context';
2
+ import { type TemplateCodegenContext } from '../template/context';
3
3
  import type { ScriptCodegenContext } from './context';
4
4
  import type { ScriptCodegenOptions } from './index';
5
5
  export declare function generateTemplate(options: ScriptCodegenOptions, ctx: ScriptCodegenContext): Generator<Code, TemplateCodegenContext>;
6
6
  export declare function generateTemplateDirectives(options: ScriptCodegenOptions): Generator<Code>;
7
- export declare function generateCssClassProperty(styleIndex: number, classNameWithDot: string, offset: number, propertyType: string, optional: boolean): Generator<Code>;
8
7
  export declare function getTemplateUsageVars(options: ScriptCodegenOptions, ctx: ScriptCodegenContext): Set<string>;
@@ -2,10 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateTemplate = generateTemplate;
4
4
  exports.generateTemplateDirectives = generateTemplateDirectives;
5
- exports.generateCssClassProperty = generateCssClassProperty;
6
5
  exports.getTemplateUsageVars = getTemplateUsageVars;
7
6
  const shared_1 = require("../../utils/shared");
8
7
  const codeFeatures_1 = require("../codeFeatures");
8
+ const modules_1 = require("../style/modules");
9
+ const scopedClasses_1 = require("../style/scopedClasses");
9
10
  const context_1 = require("../template/context");
10
11
  const interpolation_1 = require("../template/interpolation");
11
12
  const styleScopedClasses_1 = require("../template/styleScopedClasses");
@@ -93,13 +94,12 @@ function* generateTemplateDirectives(options) {
93
94
  yield `let __VLS_directives!: __VLS_LocalDirectives & __VLS_GlobalDirectives${utils_1.endOfLine}`;
94
95
  }
95
96
  function* generateTemplateBody(options, templateCodegenCtx) {
96
- yield* generateStyleScopedClasses(options, templateCodegenCtx);
97
+ yield* (0, scopedClasses_1.generateStyleScopedClasses)(options, templateCodegenCtx);
97
98
  yield* (0, styleScopedClasses_1.generateStyleScopedClassReferences)(templateCodegenCtx, true);
99
+ yield* (0, modules_1.generateStyleModules)(options);
98
100
  yield* generateCssVars(options, templateCodegenCtx);
99
101
  if (options.templateCodegen) {
100
- for (const code of options.templateCodegen.codes) {
101
- yield code;
102
- }
102
+ yield* options.templateCodegen.codes;
103
103
  }
104
104
  else {
105
105
  yield `// no template${utils_1.newLine}`;
@@ -111,54 +111,6 @@ function* generateTemplateBody(options, templateCodegenCtx) {
111
111
  yield `type __VLS_RootEl = any${utils_1.endOfLine}`;
112
112
  }
113
113
  }
114
- function* generateStyleScopedClasses(options, ctx) {
115
- const firstClasses = new Set();
116
- yield `type __VLS_StyleScopedClasses = {}`;
117
- for (let i = 0; i < options.sfc.styles.length; i++) {
118
- const style = options.sfc.styles[i];
119
- const option = options.vueCompilerOptions.experimentalResolveStyleCssClasses;
120
- if (option === 'always' || (option === 'scoped' && style.scoped)) {
121
- for (const className of style.classNames) {
122
- if (firstClasses.has(className.text)) {
123
- ctx.scopedClasses.push({
124
- source: 'style_' + i,
125
- className: className.text.slice(1),
126
- offset: className.offset + 1
127
- });
128
- continue;
129
- }
130
- firstClasses.add(className.text);
131
- yield* generateCssClassProperty(i, className.text, className.offset, 'boolean', true);
132
- }
133
- }
134
- }
135
- yield utils_1.endOfLine;
136
- }
137
- function* generateCssClassProperty(styleIndex, classNameWithDot, offset, propertyType, optional) {
138
- yield `${utils_1.newLine} & { `;
139
- yield [
140
- '',
141
- 'style_' + styleIndex,
142
- offset,
143
- codeFeatures_1.codeFeatures.navigation,
144
- ];
145
- yield `'`;
146
- yield [
147
- classNameWithDot.slice(1),
148
- 'style_' + styleIndex,
149
- offset + 1,
150
- codeFeatures_1.codeFeatures.navigation,
151
- ];
152
- yield `'`;
153
- yield [
154
- '',
155
- 'style_' + styleIndex,
156
- offset + classNameWithDot.length,
157
- codeFeatures_1.codeFeatures.navigationWithoutRename,
158
- ];
159
- yield `${optional ? '?' : ''}: ${propertyType}`;
160
- yield ` }`;
161
- }
162
114
  function* generateCssVars(options, ctx) {
163
115
  if (!options.sfc.styles.length) {
164
116
  return;
@@ -0,0 +1,2 @@
1
+ import type { Code } from '../../types';
2
+ export declare function generateClassProperty(styleIndex: number, classNameWithDot: string, offset: number, propertyType: string): Generator<Code>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateClassProperty = generateClassProperty;
4
+ const codeFeatures_1 = require("../codeFeatures");
5
+ const utils_1 = require("../utils");
6
+ const wrapWith_1 = require("../utils/wrapWith");
7
+ function* generateClassProperty(styleIndex, classNameWithDot, offset, propertyType) {
8
+ yield `${utils_1.newLine} & { `;
9
+ yield* (0, wrapWith_1.wrapWith)(offset, offset + classNameWithDot.length, 'style_' + styleIndex, codeFeatures_1.codeFeatures.navigation, `'`, [
10
+ classNameWithDot.slice(1),
11
+ 'style_' + styleIndex,
12
+ offset + 1,
13
+ utils_1.combineLastMapping
14
+ ], `'`);
15
+ yield `: ${propertyType}`;
16
+ yield ` }`;
17
+ }
18
+ //# sourceMappingURL=classProperty.js.map
@@ -0,0 +1,3 @@
1
+ import type { Code } from '../../types';
2
+ import type { ScriptCodegenOptions } from '../script';
3
+ export declare function generateStyleModules(options: ScriptCodegenOptions): Generator<Code>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateStyleModules = generateStyleModules;
4
+ const codeFeatures_1 = require("../codeFeatures");
5
+ const utils_1 = require("../utils");
6
+ const classProperty_1 = require("./classProperty");
7
+ function* generateStyleModules(options) {
8
+ const styles = options.sfc.styles.map((style, i) => [style, i]).filter(([style]) => style.module);
9
+ if (!styles.length && !options.scriptSetupRanges?.useCssModule.length) {
10
+ return;
11
+ }
12
+ yield `type __VLS_StyleModules = {${utils_1.newLine}`;
13
+ for (const [style, i] of styles) {
14
+ if (style.module === true) {
15
+ yield `$style`;
16
+ }
17
+ else {
18
+ const { text, offset } = style.module;
19
+ yield [
20
+ text,
21
+ 'main',
22
+ offset,
23
+ codeFeatures_1.codeFeatures.withoutHighlight
24
+ ];
25
+ }
26
+ yield `: Record<string, string> & __VLS_PrettifyGlobal<{}`;
27
+ for (const className of style.classNames) {
28
+ yield* (0, classProperty_1.generateClassProperty)(i, className.text, className.offset, 'string');
29
+ }
30
+ yield `>${utils_1.endOfLine}`;
31
+ }
32
+ yield `}${utils_1.endOfLine}`;
33
+ }
34
+ //# sourceMappingURL=modules.js.map
@@ -0,0 +1,4 @@
1
+ import type { Code } from '../../types';
2
+ import type { ScriptCodegenOptions } from '../script';
3
+ import type { TemplateCodegenContext } from '../template/context';
4
+ export declare function generateStyleScopedClasses(options: ScriptCodegenOptions, ctx: TemplateCodegenContext): Generator<Code>;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateStyleScopedClasses = generateStyleScopedClasses;
4
+ const utils_1 = require("../utils");
5
+ const classProperty_1 = require("./classProperty");
6
+ function* generateStyleScopedClasses(options, ctx) {
7
+ const option = options.vueCompilerOptions.experimentalResolveStyleCssClasses;
8
+ const styles = options.sfc.styles
9
+ .map((style, i) => [style, i])
10
+ .filter(([style]) => option === 'always' || (option === 'scoped' && style.scoped));
11
+ if (!styles.length) {
12
+ return;
13
+ }
14
+ const firstClasses = new Set();
15
+ yield `type __VLS_StyleScopedClasses = {}`;
16
+ for (const [style, i] of styles) {
17
+ for (const className of style.classNames) {
18
+ if (firstClasses.has(className.text)) {
19
+ ctx.scopedClasses.push({
20
+ source: 'style_' + i,
21
+ className: className.text.slice(1),
22
+ offset: className.offset + 1
23
+ });
24
+ continue;
25
+ }
26
+ firstClasses.add(className.text);
27
+ yield* (0, classProperty_1.generateClassProperty)(i, className.text, className.offset, 'boolean');
28
+ }
29
+ }
30
+ yield utils_1.endOfLine;
31
+ }
32
+ //# sourceMappingURL=scopedClasses.js.map
@@ -3,6 +3,103 @@ import type { Code, VueCodeInformation } from '../../types';
3
3
  import { InlayHintInfo } from '../inlayHints';
4
4
  import type { TemplateCodegenOptions } from './index';
5
5
  export type TemplateCodegenContext = ReturnType<typeof createTemplateCodegenContext>;
6
+ /**
7
+ * Creates and returns a Context object used for generating type-checkable TS code
8
+ * from the template section of a .vue file.
9
+ *
10
+ * ## Implementation Notes for supporting `@vue-ignore`, `@vue-expect-error`, and `@vue-skip` directives.
11
+ *
12
+ * Vue language tooling supports a number of directives for suppressing diagnostics within
13
+ * Vue templates (https://github.com/vuejs/language-tools/pull/3215)
14
+ *
15
+ * Here is an overview for how support for how @vue-expect-error is implemented within this file
16
+ * (@vue-expect-error is the most complicated directive to support due to its behavior of raising
17
+ * a diagnostic when it is annotating a piece of code that doesn't actually have any errors/warning/diagnostics).
18
+ *
19
+ * Given .vue code:
20
+ *
21
+ * ```vue
22
+ * <script setup lang="ts">
23
+ * defineProps<{
24
+ * knownProp1: string;
25
+ * knownProp2: string;
26
+ * knownProp3: string;
27
+ * knownProp4_will_trigger_unused_expect_error: string;
28
+ * }>();
29
+ * </script>
30
+ *
31
+ * <template>
32
+ * {{ knownProp1 }}
33
+ * {{ error_unknownProp }} <!-- ERROR: Property 'error_unknownProp' does not exist on type [...] -->
34
+ * {{ knownProp2 }}
35
+ * <!-- @vue-expect-error This suppresses an Unknown Property Error -->
36
+ * {{ suppressed_error_unknownProp }}
37
+ * {{ knownProp3 }}
38
+ * <!-- @vue-expect-error This will trigger Unused '@ts-expect-error' directive.ts(2578) -->
39
+ * {{ knownProp4_will_trigger_unused_expect_error }}
40
+ * </template>
41
+ * ```
42
+ *
43
+ * The above code should raise two diagnostics:
44
+ *
45
+ * 1. Property 'error_unknownProp' does not exist on type [...]
46
+ * 2. Unused '@ts-expect-error' directive.ts(2578) -- this is the bottom `@vue-expect-error` directive
47
+ * that covers code that doesn't actually raise an error -- note that all `@vue-...` directives
48
+ * will ultimately translate into `@ts-...` diagnostics.
49
+ *
50
+ * The above code will produce the following type-checkable TS code (note: omitting asterisks
51
+ * to prevent VSCode syntax double-greying out double-commented code).
52
+ *
53
+ * ```ts
54
+ * ( __VLS_ctx.knownProp1 );
55
+ * ( __VLS_ctx.error_unknownProp ); // ERROR: Property 'error_unknownProp' does not exist on type [...]
56
+ * ( __VLS_ctx.knownProp2 );
57
+ * // @vue-expect-error start
58
+ * ( __VLS_ctx.suppressed_error_unknownProp );
59
+ * // @ts-expect-error __VLS_TS_EXPECT_ERROR
60
+ * ;
61
+ * // @vue-expect-error end of INTERPOLATION
62
+ * ( __VLS_ctx.knownProp3 );
63
+ * // @vue-expect-error start
64
+ * ( __VLS_ctx.knownProp4_will_trigger_unused_expect_error );
65
+ * // @ts-expect-error __VLS_TS_EXPECT_ERROR
66
+ * ;
67
+ * // @vue-expect-error end of INTERPOLATION
68
+ * ```
69
+ *
70
+ * In the generated code, there are actually 3 diagnostic errors that'll be raised in the first
71
+ * pass on this generated code (but through cleverness described below, not all of them will be
72
+ * propagated back to the original .vue file):
73
+ *
74
+ * 1. Property 'error_unknownProp' does not exist on type [...]
75
+ * 2. Unused '@ts-expect-error' directive.ts(2578) from the 1st `@ts-expect-error __VLS_TS_EXPECT_ERROR`
76
+ * 3. Unused '@ts-expect-error' directive.ts(2578) from the 2nd `@ts-expect-error __VLS_TS_EXPECT_ERROR`
77
+ *
78
+ * Be sure to pay careful attention to the mixture of `@vue-expect-error` and `@ts-expect-error`;
79
+ * Within the TS file, the only "real" directives recognized by TS are going to be prefixed with `@ts-`;
80
+ * any `@vue-` prefixed directives in the comments are only for debugging purposes.
81
+ *
82
+ * As mentioned above, there are 3 diagnostics errors that'll be generated for the above code, but
83
+ * only 2 should be propagated back to the original .vue file.
84
+ *
85
+ * (The reason we structure things this way is somewhat complicated, but in short it allows us
86
+ * to lean on TS as much as possible to generate actual `unused @ts-expect-error directive` errors
87
+ * while covering a number of edge cases.)
88
+ *
89
+ * So, we need a way to dynamically decide whether each of the `@ts-expect-error __VLS_TS_EXPECT_ERROR`
90
+ * directives should be reported as an unused directive or not.
91
+ *
92
+ * To do this, we'll make use of the `shouldReport` callback that'll optionally be provided to the
93
+ * `verification` property of the `CodeInformation` object attached to the mapping between source .vue
94
+ * and generated .ts code. The `verification` property determines whether "verification" (which includes
95
+ * semantic diagnostics) should be performed on the generated .ts code, and `shouldReport`, if provided,
96
+ * can be used to determine whether a given diagnostic should be reported back "upwards" to the original
97
+ * .vue file or not.
98
+ *
99
+ * See the comments in the code below for how and where we use this hook to keep track of whether
100
+ * an error/diagnostic was encountered for a region of code covered by a `@vue-expect-error` directive,
101
+ * and additionally how we use that to determine whether to propagate diagnostics back upward.
102
+ */
6
103
  export declare function createTemplateCodegenContext(options: Pick<TemplateCodegenOptions, 'scriptSetupBindingNames' | 'edited'>): {
7
104
  codeFeatures: {
8
105
  all: VueCodeInformation;
@@ -34,7 +131,7 @@ export declare function createTemplateCodegenContext(options: Pick<TemplateCodeg
34
131
  expVar: string;
35
132
  propsVar: string;
36
133
  }[];
37
- specialVars: Set<string>;
134
+ dollarVars: Set<string>;
38
135
  accessExternalVariables: Map<string, Set<number>>;
39
136
  lastGenericComment: {
40
137
  content: string;
@@ -48,21 +145,25 @@ export declare function createTemplateCodegenContext(options: Pick<TemplateCodeg
48
145
  }[];
49
146
  emptyClassOffsets: number[];
50
147
  inlayHints: InlayHintInfo[];
51
- hasSlot: boolean;
52
148
  bindingAttrLocs: CompilerDOM.SourceLocation[];
53
149
  inheritedAttrVars: Set<string>;
54
- templateRefs: Map<string, [varName: string, offset: number]>;
150
+ templateRefs: Map<string, {
151
+ typeExp: string;
152
+ offset: number;
153
+ }>;
55
154
  currentComponent: {
56
155
  ctxVar: string;
57
156
  used: boolean;
58
157
  } | undefined;
59
- singleRootElType: string | undefined;
60
- singleRootNode: CompilerDOM.ElementNode | undefined;
158
+ singleRootElTypes: string[];
159
+ singleRootNodes: Set<CompilerDOM.ElementNode | null>;
61
160
  accessExternalVariable(name: string, offset?: number): void;
62
161
  hasLocalVariable: (name: string) => boolean;
63
162
  addLocalVariable: (name: string) => void;
64
163
  removeLocalVariable: (name: string) => void;
65
164
  getInternalVariable: () => string;
165
+ getHoistVariable: (originalVar: string) => string;
166
+ generateHoistVariables: () => Generator<string, void, unknown>;
66
167
  ignoreError: () => Generator<Code>;
67
168
  expectError: (prevNode: CompilerDOM.CommentNode) => Generator<Code>;
68
169
  resetDirectiveComments: (endStr: string) => Generator<Code>;
@@ -3,6 +3,104 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createTemplateCodegenContext = createTemplateCodegenContext;
4
4
  const codeFeatures_1 = require("../codeFeatures");
5
5
  const utils_1 = require("../utils");
6
+ const wrapWith_1 = require("../utils/wrapWith");
7
+ /**
8
+ * Creates and returns a Context object used for generating type-checkable TS code
9
+ * from the template section of a .vue file.
10
+ *
11
+ * ## Implementation Notes for supporting `@vue-ignore`, `@vue-expect-error`, and `@vue-skip` directives.
12
+ *
13
+ * Vue language tooling supports a number of directives for suppressing diagnostics within
14
+ * Vue templates (https://github.com/vuejs/language-tools/pull/3215)
15
+ *
16
+ * Here is an overview for how support for how @vue-expect-error is implemented within this file
17
+ * (@vue-expect-error is the most complicated directive to support due to its behavior of raising
18
+ * a diagnostic when it is annotating a piece of code that doesn't actually have any errors/warning/diagnostics).
19
+ *
20
+ * Given .vue code:
21
+ *
22
+ * ```vue
23
+ * <script setup lang="ts">
24
+ * defineProps<{
25
+ * knownProp1: string;
26
+ * knownProp2: string;
27
+ * knownProp3: string;
28
+ * knownProp4_will_trigger_unused_expect_error: string;
29
+ * }>();
30
+ * </script>
31
+ *
32
+ * <template>
33
+ * {{ knownProp1 }}
34
+ * {{ error_unknownProp }} <!-- ERROR: Property 'error_unknownProp' does not exist on type [...] -->
35
+ * {{ knownProp2 }}
36
+ * <!-- @vue-expect-error This suppresses an Unknown Property Error -->
37
+ * {{ suppressed_error_unknownProp }}
38
+ * {{ knownProp3 }}
39
+ * <!-- @vue-expect-error This will trigger Unused '@ts-expect-error' directive.ts(2578) -->
40
+ * {{ knownProp4_will_trigger_unused_expect_error }}
41
+ * </template>
42
+ * ```
43
+ *
44
+ * The above code should raise two diagnostics:
45
+ *
46
+ * 1. Property 'error_unknownProp' does not exist on type [...]
47
+ * 2. Unused '@ts-expect-error' directive.ts(2578) -- this is the bottom `@vue-expect-error` directive
48
+ * that covers code that doesn't actually raise an error -- note that all `@vue-...` directives
49
+ * will ultimately translate into `@ts-...` diagnostics.
50
+ *
51
+ * The above code will produce the following type-checkable TS code (note: omitting asterisks
52
+ * to prevent VSCode syntax double-greying out double-commented code).
53
+ *
54
+ * ```ts
55
+ * ( __VLS_ctx.knownProp1 );
56
+ * ( __VLS_ctx.error_unknownProp ); // ERROR: Property 'error_unknownProp' does not exist on type [...]
57
+ * ( __VLS_ctx.knownProp2 );
58
+ * // @vue-expect-error start
59
+ * ( __VLS_ctx.suppressed_error_unknownProp );
60
+ * // @ts-expect-error __VLS_TS_EXPECT_ERROR
61
+ * ;
62
+ * // @vue-expect-error end of INTERPOLATION
63
+ * ( __VLS_ctx.knownProp3 );
64
+ * // @vue-expect-error start
65
+ * ( __VLS_ctx.knownProp4_will_trigger_unused_expect_error );
66
+ * // @ts-expect-error __VLS_TS_EXPECT_ERROR
67
+ * ;
68
+ * // @vue-expect-error end of INTERPOLATION
69
+ * ```
70
+ *
71
+ * In the generated code, there are actually 3 diagnostic errors that'll be raised in the first
72
+ * pass on this generated code (but through cleverness described below, not all of them will be
73
+ * propagated back to the original .vue file):
74
+ *
75
+ * 1. Property 'error_unknownProp' does not exist on type [...]
76
+ * 2. Unused '@ts-expect-error' directive.ts(2578) from the 1st `@ts-expect-error __VLS_TS_EXPECT_ERROR`
77
+ * 3. Unused '@ts-expect-error' directive.ts(2578) from the 2nd `@ts-expect-error __VLS_TS_EXPECT_ERROR`
78
+ *
79
+ * Be sure to pay careful attention to the mixture of `@vue-expect-error` and `@ts-expect-error`;
80
+ * Within the TS file, the only "real" directives recognized by TS are going to be prefixed with `@ts-`;
81
+ * any `@vue-` prefixed directives in the comments are only for debugging purposes.
82
+ *
83
+ * As mentioned above, there are 3 diagnostics errors that'll be generated for the above code, but
84
+ * only 2 should be propagated back to the original .vue file.
85
+ *
86
+ * (The reason we structure things this way is somewhat complicated, but in short it allows us
87
+ * to lean on TS as much as possible to generate actual `unused @ts-expect-error directive` errors
88
+ * while covering a number of edge cases.)
89
+ *
90
+ * So, we need a way to dynamically decide whether each of the `@ts-expect-error __VLS_TS_EXPECT_ERROR`
91
+ * directives should be reported as an unused directive or not.
92
+ *
93
+ * To do this, we'll make use of the `shouldReport` callback that'll optionally be provided to the
94
+ * `verification` property of the `CodeInformation` object attached to the mapping between source .vue
95
+ * and generated .ts code. The `verification` property determines whether "verification" (which includes
96
+ * semantic diagnostics) should be performed on the generated .ts code, and `shouldReport`, if provided,
97
+ * can be used to determine whether a given diagnostic should be reported back "upwards" to the original
98
+ * .vue file or not.
99
+ *
100
+ * See the comments in the code below for how and where we use this hook to keep track of whether
101
+ * an error/diagnostic was encountered for a region of code covered by a `@vue-expect-error` directive,
102
+ * and additionally how we use that to determine whether to propagate diagnostics back upward.
103
+ */
6
104
  function createTemplateCodegenContext(options) {
7
105
  let ignoredError = false;
8
106
  let expectErrorToken;
@@ -11,12 +109,18 @@ function createTemplateCodegenContext(options) {
11
109
  function resolveCodeFeatures(features) {
12
110
  if (features.verification) {
13
111
  if (ignoredError) {
112
+ // We are currently in a region of code covered by a @vue-ignore directive, so don't
113
+ // even bother performing any type-checking: set verification to false.
14
114
  return {
15
115
  ...features,
16
116
  verification: false,
17
117
  };
18
118
  }
19
119
  if (expectErrorToken) {
120
+ // We are currently in a region of code covered by a @vue-expect-error directive. We need to
121
+ // keep track of the number of errors encountered within this region so that we can know whether
122
+ // we will need to propagate an "unused ts-expect-error" diagnostic back to the original
123
+ // .vue file or not.
20
124
  const token = expectErrorToken;
21
125
  return {
22
126
  ...features,
@@ -31,8 +135,9 @@ function createTemplateCodegenContext(options) {
31
135
  }
32
136
  return features;
33
137
  }
138
+ const hoistVars = new Map();
34
139
  const localVars = new Map();
35
- const specialVars = new Set();
140
+ const dollarVars = new Set();
36
141
  const accessExternalVariables = new Map();
37
142
  const slots = [];
38
143
  const dynamicSlots = [];
@@ -53,20 +158,19 @@ function createTemplateCodegenContext(options) {
53
158
  resolveCodeFeatures,
54
159
  slots,
55
160
  dynamicSlots,
56
- specialVars,
161
+ dollarVars,
57
162
  accessExternalVariables,
58
163
  lastGenericComment,
59
164
  blockConditions,
60
165
  scopedClasses,
61
166
  emptyClassOffsets,
62
167
  inlayHints,
63
- hasSlot: false,
64
168
  bindingAttrLocs,
65
169
  inheritedAttrVars,
66
170
  templateRefs,
67
171
  currentComponent: undefined,
68
- singleRootElType: undefined,
69
- singleRootNode: undefined,
172
+ singleRootElTypes: [],
173
+ singleRootNodes: new Set(),
70
174
  accessExternalVariable(name, offset) {
71
175
  let arr = accessExternalVariables.get(name);
72
176
  if (!arr) {
@@ -88,6 +192,24 @@ function createTemplateCodegenContext(options) {
88
192
  getInternalVariable: () => {
89
193
  return `__VLS_${variableId++}`;
90
194
  },
195
+ getHoistVariable: (originalVar) => {
196
+ let name = hoistVars.get(originalVar);
197
+ if (name === undefined) {
198
+ hoistVars.set(originalVar, name = `__VLS_${variableId++}`);
199
+ }
200
+ return name;
201
+ },
202
+ generateHoistVariables: function* () {
203
+ // trick to avoid TS 4081 (#5186)
204
+ if (hoistVars.size) {
205
+ yield `// @ts-ignore${utils_1.newLine}`;
206
+ yield `var `;
207
+ for (const [originalVar, hoistVar] of hoistVars) {
208
+ yield `${hoistVar} = ${originalVar}, `;
209
+ }
210
+ yield utils_1.endOfLine;
211
+ }
212
+ },
91
213
  ignoreError: function* () {
92
214
  if (!ignoredError) {
93
215
  ignoredError = true;
@@ -106,8 +228,11 @@ function createTemplateCodegenContext(options) {
106
228
  resetDirectiveComments: function* (endStr) {
107
229
  if (expectErrorToken) {
108
230
  const token = expectErrorToken;
109
- yield* (0, utils_1.wrapWith)(expectErrorToken.node.loc.start.offset, expectErrorToken.node.loc.end.offset, {
231
+ yield* (0, wrapWith_1.wrapWith)(expectErrorToken.node.loc.start.offset, expectErrorToken.node.loc.end.offset, {
110
232
  verification: {
233
+ // If no errors/warnings/diagnostics were reported within the region of code covered
234
+ // by the @vue-expect-error directive, then we should allow any `unused @ts-expect-error`
235
+ // diagnostics to be reported upward.
111
236
  shouldReport: () => token.errors === 0,
112
237
  },
113
238
  }, `// @ts-expect-error __VLS_TS_EXPECT_ERROR`);
@@ -2,5 +2,5 @@ import * as CompilerDOM from '@vue/compiler-dom';
2
2
  import type { Code } from '../../types';
3
3
  import type { TemplateCodegenContext } from './context';
4
4
  import type { TemplateCodegenOptions } from './index';
5
- export declare function generateComponent(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode): Generator<Code>;
5
+ export declare function generateComponent(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, isVForChild: boolean): Generator<Code>;
6
6
  export declare function generateElement(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, isVForChild: boolean): Generator<Code>;