Skip to content

Commit 4277ab6

Browse files
committed
feat(language-core): support <!-- @strictTemplates --> magic comment (#5845)
1 parent 4972119 commit 4277ab6

File tree

22 files changed

+74
-29
lines changed

22 files changed

+74
-29
lines changed

packages/language-core/lib/codegen/globalTypes.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ export function getGlobalTypesFileName(options: VueCompilerOptions) {
66
return [
77
options.lib,
88
options.target,
9-
options.checkUnknownProps,
10-
].map(v => (typeof v === 'boolean' ? Number(v) : v)).join('_') + '.d.ts';
9+
].join('_') + '.d.ts';
1110
}
1211

1312
export function generateGlobalTypes(options: VueCompilerOptions) {
14-
const { lib, target, checkUnknownProps } = options;
13+
const { lib, target } = options;
1514

1615
let text = `// @ts-nocheck${newLine}`;
1716
text += `export {}${endOfLine}`;
@@ -24,7 +23,7 @@ export function generateGlobalTypes(options: VueCompilerOptions) {
2423
}
2524

2625
text += `declare global {
27-
${checkUnknownProps ? '' : `var ${names.PROPS_FALLBACK}: Record<string, unknown>;`}
26+
var ${names.PROPS_FALLBACK}: Record<string, unknown>;
2827
2928
const __VLS_directiveBindingRestFields: { instance: null, oldValue: null, modifiers: any, dir: any };
3029
const ${names.placeholder}: any;
@@ -61,9 +60,20 @@ export function generateGlobalTypes(options: VueCompilerOptions) {
6160
? K extends { __ctx?: { props?: infer P } } ? NonNullable<P> : never
6261
: T extends (props: infer P, ...args: any) => any ? P
6362
: {};
64-
type __VLS_FunctionalComponent<T> = (props: (T extends { $props: infer Props } ? Props : {})${
65-
checkUnknownProps ? '' : ' & Record<string, unknown>'
66-
}, ctx?: any) => ${
63+
type __VLS_FunctionalComponent0<T> = (props: (T extends { $props: infer Props } ? Props : {}), ctx?: any) => ${
64+
target >= 3.3
65+
? `import('${lib}/jsx-runtime').JSX.Element`
66+
: `globalThis.JSX.Element`
67+
} & {
68+
__ctx?: {
69+
attrs?: any;
70+
slots?: T extends { $slots: infer Slots } ? Slots : Record<string, any>;
71+
emit?: T extends { $emit: infer Emit } ? Emit : {};
72+
props?: typeof props;
73+
expose?: (exposed: T) => void;
74+
};
75+
};
76+
type __VLS_FunctionalComponent1<T> = (props: (T extends { $props: infer Props } ? Props : {}) & Record<string, unknown>, ctx?: any) => ${
6777
target >= 3.3
6878
? `import('${lib}/jsx-runtime').JSX.Element`
6979
: `globalThis.JSX.Element`
@@ -153,15 +163,19 @@ export function generateGlobalTypes(options: VueCompilerOptions) {
153163
: T extends (...args: any) => any
154164
? T
155165
: (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
156-
function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
157-
T extends new (...args: any) => any ? __VLS_FunctionalComponent<K>
166+
function __VLS_asFunctionalComponent0<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
167+
T extends new (...args: any) => any ? __VLS_FunctionalComponent0<K>
168+
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
169+
: T extends (...args: any) => any ? T
170+
: __VLS_FunctionalComponent0<{}>;
171+
function __VLS_asFunctionalComponent1<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
172+
T extends new (...args: any) => any ? __VLS_FunctionalComponent1<K>
158173
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
159174
: T extends (...args: any) => any ? T
160-
: __VLS_FunctionalComponent<{}>;
175+
: __VLS_FunctionalComponent1<{}>;
161176
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
162-
function __VLS_asFunctionalElement<T>(tag: T, endTag?: T): (attrs: T${
163-
checkUnknownProps ? '' : ' & Record<string, unknown>'
164-
}) => void;
177+
function __VLS_asFunctionalElement0<T>(tag: T, endTag?: T): (attrs: T) => void;
178+
function __VLS_asFunctionalElement1<T>(tag: T, endTag?: T): (attrs: T & Record<string, unknown>) => void;
165179
function __VLS_asFunctionalSlot<S>(slot: S): S extends () => infer R ? (props: {}) => R : NonNullable<S>;
166180
function __VLS_tryAsConstant<const T>(t: T): T;
167181
}${newLine}`;

packages/language-core/lib/codegen/script/scriptSetup.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,11 @@ export function* generateGeneric(
9696
+ ` & import('${vueCompilerOptions.lib}').AllowedComponentProps`
9797
+ ` & import('${vueCompilerOptions.lib}').ComponentCustomProps`
9898
: `globalThis.JSX.IntrinsicAttributes`
99-
} & (typeof globalThis extends { ${names.PROPS_FALLBACK}: infer P } ? P : {})${endOfLine}`;
99+
}`;
100+
if (!vueCompilerOptions.checkUnknownProps) {
101+
yield ` & (typeof globalThis extends { ${names.PROPS_FALLBACK}: infer P } ? P : {})`;
102+
}
103+
yield endOfLine;
100104
yield ` expose: (exposed: `;
101105
yield scriptSetupRanges.defineExpose
102106
? `import('${vueCompilerOptions.lib}').ShallowUnwrapRef<typeof ${names.exposed}>`

packages/language-core/lib/codegen/template/element.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ function* generateComponentBody(
185185
const propsVar = ctx.getInternalVariable();
186186

187187
yield `// @ts-ignore${newLine}`;
188-
yield `const ${functionalVar} = __VLS_asFunctionalComponent(${componentVar}, new ${componentVar}({${newLine}`;
188+
yield `const ${functionalVar} = ${
189+
options.vueCompilerOptions.checkUnknownProps ? '__VLS_asFunctionalComponent0' : '__VLS_asFunctionalComponent1'
190+
}(${componentVar}, new ${componentVar}({${newLine}`;
189191
yield* toString(propCodes);
190192
yield `}))${endOfLine}`;
191193

@@ -274,7 +276,9 @@ export function* generateElement(
274276
const [startTagOffset, endTagOffset] = getElementTagOffsets(node, options.template);
275277
const failedPropExps: FailGeneratedExpression[] = [];
276278

277-
yield `__VLS_asFunctionalElement(${names.intrinsics}`;
279+
yield `${
280+
options.vueCompilerOptions.checkUnknownProps ? `__VLS_asFunctionalElement0` : `__VLS_asFunctionalElement1`
281+
}(${names.intrinsics}`;
278282
yield* generatePropertyAccess(
279283
options,
280284
ctx,

packages/language-core/lib/compilerOptions.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export function createParsedCommandLine(
113113
}
114114

115115
export class CompilerOptionsResolver {
116-
options: Omit<RawVueCompilerOptions, 'target' | 'globalTypesPath' | 'plugins'> = {};
116+
options: Omit<RawVueCompilerOptions, 'target' | 'strictTemplates' | 'globalTypesPath' | 'plugins'> = {};
117117
target: number | undefined;
118118
globalTypesPath: string | undefined;
119119
plugins: VueLanguagePlugin[] = [];
@@ -133,6 +133,14 @@ export class CompilerOptionsResolver {
133133
this.target = options[key];
134134
}
135135
break;
136+
case 'strictTemplates':
137+
const strict = !!options.strictTemplates;
138+
this.options.strictVModel ??= strict;
139+
this.options.checkUnknownProps ??= strict;
140+
this.options.checkUnknownEvents ??= strict;
141+
this.options.checkUnknownDirectives ??= strict;
142+
this.options.checkUnknownComponents ??= strict;
143+
break;
136144
case 'globalTypesPath':
137145
if (options[key] !== undefined) {
138146
this.globalTypesPath = path.join(rootDir, options[key]);
@@ -169,12 +177,11 @@ export class CompilerOptionsResolver {
169177
}
170178
}
171179

172-
build(defaults?: VueCompilerOptions) {
173-
defaults ??= getDefaultCompilerOptions(this.target, this.options.lib, this.options.strictTemplates);
174-
180+
build(defaults = getDefaultCompilerOptions()) {
175181
const resolvedOptions: VueCompilerOptions = {
176182
...defaults,
177183
...this.options,
184+
target: this.target ?? defaults.target,
178185
plugins: this.plugins,
179186
macros: {
180187
...defaults.macros,
@@ -275,8 +282,8 @@ export function getDefaultCompilerOptions(target = 99, lib = 'vue', strictTempla
275282
vitePressExtensions: [],
276283
petiteVueExtensions: [],
277284
jsxSlots: false,
278-
strictVModel: strictTemplates,
279285
strictCssModules: false,
286+
strictVModel: strictTemplates,
280287
checkUnknownProps: strictTemplates,
281288
checkUnknownEvents: strictTemplates,
282289
checkUnknownDirectives: strictTemplates,

test-workspace/tsc/passedFixtures/vue3_strictTemplate/#2726/main.vue renamed to test-workspace/tsc/passedFixtures/vue3/#2726/main.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<!-- @strictTemplates true -->
2+
13
<script lang="ts" setup>
24
import { ref } from 'vue';
35

test-workspace/tsc/passedFixtures/vue3_strictTemplate/#3140/Focus.ts renamed to test-workspace/tsc/passedFixtures/vue3/#3140/Focus.ts

File renamed without changes.

test-workspace/tsc/passedFixtures/vue3_strictTemplate/#3140/main.vue renamed to test-workspace/tsc/passedFixtures/vue3/#3140/main.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<!-- @strictTemplates true -->
2+
13
<script setup lang="ts">
24
import { vFocus } from './Focus';
35
</script>

test-workspace/tsc/passedFixtures/vue3_strictTemplate/#3152/MyInput.vue renamed to test-workspace/tsc/passedFixtures/vue3/#3152/MyInput.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<!-- @strictTemplates true -->
2+
13
<script setup>
24
</script>
35

test-workspace/tsc/passedFixtures/vue3_strictTemplate/#3152/main.vue renamed to test-workspace/tsc/passedFixtures/vue3/#3152/main.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<!-- @strictTemplates true -->
2+
13
<script setup>
24
import { ref } from 'vue'
35
import MyInput from './MyInput.vue';

test-workspace/tsc/passedFixtures/vue3_strictTemplate/#3539/main.vue renamed to test-workspace/tsc/passedFixtures/vue3/#3539/main.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<!-- @strictTemplates true -->
2+
13
<script setup lang="ts">
24
import { ref } from 'vue';
35

0 commit comments

Comments
 (0)