= { [K in keyof T as K]: T[K]; } & {};
+ type __VLS_WithDefaultsGlobal = {
+ [K in keyof P as K extends keyof D ? K : never]-?: P[K];
+ } & {
+ [K in keyof P as K extends keyof D ? never : K]: P[K];
+ };
type __VLS_UseTemplateRef = Readonly>;
+ type __VLS_ProxyRefs = import('${lib}').ShallowUnwrapRef;
function __VLS_getVForSourceType>(source: T): [
item: T extends number ? number
@@ -154,7 +164,6 @@ export function generateGlobalTypes(options: VueCompilerOptions) {
: T extends (...args: any) => any
? T
: (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
- function __VLS_makeOptional(t: T): { [K in keyof T]?: T[K] };
function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K):
T extends new (...args: any) => any ? __VLS_FunctionalComponent
: T extends () => any ? (props: {}, ctx?: any) => ReturnType${
diff --git a/packages/language-core/lib/codegen/localTypes.ts b/packages/language-core/lib/codegen/localTypes.ts
index c41cd55cde..7be0e26c85 100644
--- a/packages/language-core/lib/codegen/localTypes.ts
+++ b/packages/language-core/lib/codegen/localTypes.ts
@@ -5,20 +5,11 @@ import { endOfLine } from './utils';
export function getLocalTypesGenerator(vueCompilerOptions: VueCompilerOptions) {
const used = new Set();
- const OmitKeepDiscriminatedUnion = defineHelper(
- `__VLS_OmitKeepDiscriminatedUnion`,
+ const WithDefaultsLocal = defineHelper(
+ `__VLS_WithDefaultsLocal`,
() =>
`
-type __VLS_OmitKeepDiscriminatedUnion = T extends any
- ? Pick>
- : never;
-`.trimStart(),
- );
- const WithDefaults = defineHelper(
- `__VLS_WithDefaults`,
- () =>
- `
-type __VLS_WithDefaults = {
+type __VLS_WithDefaultsLocal
= {
[K in keyof Pick
]: K extends keyof D
? ${PrettifyLocal.name}
: P[K]
@@ -36,7 +27,6 @@ type __VLS_WithDefaults
= {
type __VLS_WithSlots = T & {
new(): {
${getSlotsPropertyName(vueCompilerOptions.target)}: S;
- ${vueCompilerOptions.jsxSlots ? `$props: ${PropsChildren.name};` : ''}
}
};
`.trimStart(),
@@ -78,8 +68,7 @@ type __VLS_TypePropsToOption = {
);
const helpers = {
[PrettifyLocal.name]: PrettifyLocal,
- [OmitKeepDiscriminatedUnion.name]: OmitKeepDiscriminatedUnion,
- [WithDefaults.name]: WithDefaults,
+ [WithDefaultsLocal.name]: WithDefaultsLocal,
[WithSlots.name]: WithSlots,
[PropsChildren.name]: PropsChildren,
[TypePropsToOption.name]: TypePropsToOption,
@@ -89,17 +78,11 @@ type __VLS_TypePropsToOption = {
return {
generate,
- getUsedNames() {
- return used;
- },
get PrettifyLocal() {
return PrettifyLocal.name;
},
- get OmitKeepDiscriminatedUnion() {
- return OmitKeepDiscriminatedUnion.name;
- },
- get WithDefaults() {
- return WithDefaults.name;
+ get WithDefaultsLocal() {
+ return WithDefaultsLocal.name;
},
get WithSlots() {
return WithSlots.name;
@@ -115,20 +98,11 @@ type __VLS_TypePropsToOption = {
},
};
- function* generate(names: string[]) {
- const generated = new Set();
- while (names.length) {
- used.clear();
- for (const name of names) {
- if (generated.has(name)) {
- continue;
- }
- const helper = helpers[name as keyof typeof helpers];
- yield helper.generate();
- generated.add(name);
- }
- names = [...used].filter(name => !generated.has(name));
+ function* generate() {
+ for (const name of used) {
+ yield helpers[name].generate();
}
+ used.clear();
}
function defineHelper(name: string, generate: () => string) {
diff --git a/packages/language-core/lib/codegen/script/component.ts b/packages/language-core/lib/codegen/script/component.ts
index 4b1de2a15b..4a6457a589 100644
--- a/packages/language-core/lib/codegen/script/component.ts
+++ b/packages/language-core/lib/codegen/script/component.ts
@@ -29,9 +29,18 @@ export function* generateComponent(
yield `(await import('${options.vueCompilerOptions.lib}')).defineComponent({${newLine}`;
}
- const returns: Code[] = [];
+ const returns: string[] = [];
if (ctx.bypassDefineComponent) {
- returns.push(...generateComponentSetupReturns(scriptSetupRanges));
+ // fill $props
+ if (scriptSetupRanges.defineProps) {
+ const name = scriptSetupRanges.defineProps.name ?? `__VLS_props`;
+ // NOTE: defineProps is inaccurate for $props
+ returns.push(name, `{} as { $props: Partial }`);
+ }
+ // fill $emit
+ if (scriptSetupRanges.defineEmits) {
+ returns.push(`{} as { $emit: typeof ${scriptSetupRanges.defineEmits.name ?? `__VLS_emit`} }`);
+ }
}
if (scriptSetupRanges.defineExpose) {
returns.push(`__VLS_exposed`);
@@ -45,7 +54,7 @@ export function* generateComponent(
if (!ctx.bypassDefineComponent) {
const emitOptionCodes = [...generateEmitsOption(options, scriptSetupRanges)];
yield* emitOptionCodes;
- yield* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges, !!emitOptionCodes.length, true);
+ yield* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges, !!emitOptionCodes.length);
}
if (
options.vueCompilerOptions.target >= 3.5
@@ -68,21 +77,7 @@ export function* generateComponent(
yield `})`;
}
-export function* generateComponentSetupReturns(scriptSetupRanges: ScriptSetupRanges): Generator {
- // fill $props
- if (scriptSetupRanges.defineProps) {
- const name = scriptSetupRanges.defineProps.name ?? `__VLS_props`;
- // NOTE: defineProps is inaccurate for $props
- yield name;
- yield `{} as { $props: Partial }`;
- }
- // fill $emit
- if (scriptSetupRanges.defineEmits) {
- yield `{} as { $emit: typeof ${scriptSetupRanges.defineEmits.name ?? `__VLS_emit`} }`;
- }
-}
-
-export function* generateEmitsOption(
+function* generateEmitsOption(
options: ScriptCodegenOptions,
scriptSetupRanges: ScriptSetupRanges,
): Generator {
@@ -116,18 +111,17 @@ export function* generateEmitsOption(
}
}
-export function* generatePropsOption(
+function* generatePropsOption(
options: ScriptCodegenOptions,
ctx: ScriptCodegenContext,
scriptSetup: NonNullable,
scriptSetupRanges: ScriptSetupRanges,
hasEmitsOption: boolean,
- inheritAttrs: boolean,
): Generator {
const getOptionCodes: (() => Code)[] = [];
const typeOptionCodes: Code[] = [];
- if (inheritAttrs && options.templateCodegen?.inheritedAttrVars.size) {
+ if (options.templateCodegen?.inheritedAttrVars.size) {
let attrsType = `__VLS_InheritedAttrs`;
if (hasEmitsOption) {
attrsType = `Omit<${attrsType}, \`on\${string}\`>`;
@@ -145,7 +139,7 @@ export function* generatePropsOption(
const propsType = `${ctx.localTypes.TypePropsToOption}<__VLS_PublicProps>`;
return `{} as ` + (
scriptSetupRanges.withDefaults?.arg
- ? `${ctx.localTypes.WithDefaults}<${propsType}, typeof __VLS_withDefaultsArg>`
+ ? `${ctx.localTypes.WithDefaultsLocal}<${propsType}, typeof __VLS_defaults>`
: propsType
);
});
@@ -166,7 +160,7 @@ export function* generatePropsOption(
options.vueCompilerOptions.target >= 3.6
&& scriptSetupRanges.withDefaults?.arg
) {
- yield `__defaults: __VLS_withDefaultsArg,${newLine}`;
+ yield `__defaults: __VLS_defaults,${newLine}`;
}
yield `__typeProps: `;
yield* generateSpreadMerge(typeOptionCodes);
diff --git a/packages/language-core/lib/codegen/script/componentSelf.ts b/packages/language-core/lib/codegen/script/componentSelf.ts
deleted file mode 100644
index 1f8b6b8377..0000000000
--- a/packages/language-core/lib/codegen/script/componentSelf.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { camelize, capitalize } from '@vue/shared';
-import * as path from 'path-browserify';
-import type { Code } from '../../types';
-import { codeFeatures } from '../codeFeatures';
-import type { TemplateCodegenContext } from '../template/context';
-import { endOfLine, generateSfcBlockSection, newLine } from '../utils';
-import { generateComponentSetupReturns, generateEmitsOption, generatePropsOption } from './component';
-import type { ScriptCodegenContext } from './context';
-import type { ScriptCodegenOptions } from './index';
-
-export function* generateComponentSelf(
- options: ScriptCodegenOptions,
- ctx: ScriptCodegenContext,
- templateCodegenCtx: TemplateCodegenContext,
-): Generator {
- if (options.sfc.scriptSetup && options.scriptSetupRanges) {
- yield `const __VLS_self = (await import('${options.vueCompilerOptions.lib}')).defineComponent({${newLine}`;
- yield `setup: () => ({${newLine}`;
- if (ctx.bypassDefineComponent) {
- for (const code of generateComponentSetupReturns(options.scriptSetupRanges)) {
- yield `...${code},${newLine}`;
- }
- }
- // bindings
- const templateUsageVars = new Set([
- ...options.sfc.template?.ast?.components.flatMap(c => [camelize(c), capitalize(camelize(c))]) ?? [],
- ...options.templateCodegen?.accessExternalVariables.keys() ?? [],
- ...templateCodegenCtx.accessExternalVariables.keys(),
- ]);
- for (const varName of ctx.bindingNames) {
- if (!templateUsageVars.has(varName)) {
- continue;
- }
- const token = Symbol(varName.length);
- yield ['', undefined, 0, { __linkedToken: token }];
- yield `${varName}: ${varName} as typeof `;
- yield ['', undefined, 0, { __linkedToken: token }];
- yield `${varName},${newLine}`;
- }
- yield `}),${newLine}`;
- if (options.sfc.scriptSetup && options.scriptSetupRanges && !ctx.bypassDefineComponent) {
- const emitOptionCodes = [...generateEmitsOption(options, options.scriptSetupRanges)];
- yield* emitOptionCodes;
- yield* generatePropsOption(
- options,
- ctx,
- options.sfc.scriptSetup,
- options.scriptSetupRanges,
- !!emitOptionCodes.length,
- false,
- );
- }
- if (options.sfc.script && options.scriptRanges?.exportDefault?.args) {
- const { args } = options.scriptRanges.exportDefault;
- yield generateSfcBlockSection(options.sfc.script, args.start + 1, args.end - 1, codeFeatures.all);
- }
- yield `})${endOfLine}`; // defineComponent {
- }
- else if (options.sfc.script) {
- yield `let __VLS_self!: typeof import('./${path.basename(options.fileName)}').default${endOfLine}`;
- }
- else {
- yield `const __VLS_self = (await import('${options.vueCompilerOptions.lib}')).defineComponent({})${endOfLine}`;
- }
-}
diff --git a/packages/language-core/lib/codegen/script/index.ts b/packages/language-core/lib/codegen/script/index.ts
index 69cf33c303..fac9504143 100644
--- a/packages/language-core/lib/codegen/script/index.ts
+++ b/packages/language-core/lib/codegen/script/index.ts
@@ -2,12 +2,12 @@ import * as path from 'path-browserify';
import type * as ts from 'typescript';
import type { ScriptRanges } from '../../parsers/scriptRanges';
import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges';
-import type { Code, Sfc, VueCompilerOptions } from '../../types';
+import type { Code, Sfc, SfcBlock, VueCompilerOptions } from '../../types';
import { codeFeatures } from '../codeFeatures';
import type { TemplateCodegenContext } from '../template/context';
-import { endOfLine, generateSfcBlockSection, newLine } from '../utils';
-import { generateComponentSelf } from './componentSelf';
-import { type ScriptCodegenContext } from './context';
+import { endOfLine, generatePartiallyEnding, generateSfcBlockSection, newLine } from '../utils';
+import { wrapWith } from '../utils/wrapWith';
+import type { ScriptCodegenContext } from './context';
import { generateScriptSetup, generateScriptSetupImports } from './scriptSetup';
import { generateSrc } from './src';
import { generateTemplate } from './template';
@@ -32,74 +32,63 @@ export function* generateScript(
options: ScriptCodegenOptions,
ctx: ScriptCodegenContext,
): Generator {
- yield* generateGlobalTypesPath(options);
+ yield* generateGlobalTypesReference(options);
- if (options.sfc.script?.src) {
- yield* generateSrc(options.sfc.script.src);
- }
if (options.sfc.scriptSetup && options.scriptSetupRanges) {
yield* generateScriptSetupImports(options.sfc.scriptSetup, options.scriptSetupRanges);
}
if (options.sfc.script && options.scriptRanges) {
const { exportDefault, classBlockEnd } = options.scriptRanges;
- const isExportRawObject = exportDefault
- && options.sfc.script.content[exportDefault.expression.start] === '{';
if (options.sfc.scriptSetup && options.scriptSetupRanges) {
if (exportDefault) {
- yield generateSfcBlockSection(options.sfc.script, 0, exportDefault.expression.start, codeFeatures.all);
+ yield generateSfcBlockSection(options.sfc.script, 0, exportDefault.start, codeFeatures.all);
yield* generateScriptSetup(options, ctx, options.sfc.scriptSetup, options.scriptSetupRanges);
- yield generateSfcBlockSection(
- options.sfc.script,
- exportDefault.expression.end,
- options.sfc.script.content.length,
- codeFeatures.all,
- );
}
else {
yield generateSfcBlockSection(options.sfc.script, 0, options.sfc.script.content.length, codeFeatures.all);
- yield* generateScriptSectionPartiallyEnding(
- options.sfc.script.name,
- options.sfc.script.content.length,
- '#3632/both.vue',
- );
yield* generateScriptSetup(options, ctx, options.sfc.scriptSetup, options.scriptSetupRanges);
}
}
- else if (exportDefault && isExportRawObject && options.vueCompilerOptions.optionsWrapper.length) {
- ctx.inlayHints.push({
- blockName: options.sfc.script.name,
- offset: exportDefault.expression.start,
- setting: 'vue.inlayHints.optionsWrapper',
- label: options.vueCompilerOptions.optionsWrapper.length
- ? options.vueCompilerOptions.optionsWrapper[0]
- : '[Missing optionsWrapper[0]]',
- tooltip: [
- 'This is virtual code that is automatically wrapped for type support, it does not affect your runtime behavior, you can customize it via `vueCompilerOptions.optionsWrapper` option in tsconfig / jsconfig.',
- 'To hide it, you can set `"vue.inlayHints.optionsWrapper": false` in IDE settings.',
- ].join('\n\n'),
- }, {
- blockName: options.sfc.script.name,
- offset: exportDefault.expression.end,
- setting: 'vue.inlayHints.optionsWrapper',
- label: options.vueCompilerOptions.optionsWrapper.length >= 2
- ? options.vueCompilerOptions.optionsWrapper[1]
- : '[Missing optionsWrapper[1]]',
- });
- yield generateSfcBlockSection(options.sfc.script, 0, exportDefault.expression.start, codeFeatures.all);
- yield options.vueCompilerOptions.optionsWrapper[0];
+ else if (exportDefault) {
+ let wrapLeft: string | undefined;
+ let wrapRight: string | undefined;
+ if (
+ options.sfc.script.content[exportDefault.expression.start] === '{'
+ && options.vueCompilerOptions.optionsWrapper.length
+ ) {
+ [wrapLeft, wrapRight] = options.vueCompilerOptions.optionsWrapper;
+ ctx.inlayHints.push({
+ blockName: options.sfc.script.name,
+ offset: exportDefault.expression.start,
+ setting: 'vue.inlayHints.optionsWrapper',
+ label: wrapLeft || '[Missing optionsWrapper[0]]',
+ tooltip: [
+ 'This is virtual code that is automatically wrapped for type support, it does not affect your runtime behavior, you can customize it via `vueCompilerOptions.optionsWrapper` option in tsconfig / jsconfig.',
+ 'To hide it, you can set `"vue.inlayHints.optionsWrapper": false` in IDE settings.',
+ ].join('\n\n'),
+ }, {
+ blockName: options.sfc.script.name,
+ offset: exportDefault.expression.end,
+ setting: 'vue.inlayHints.optionsWrapper',
+ label: wrapRight || '[Missing optionsWrapper[1]]',
+ });
+ }
+
+ yield generateSfcBlockSection(options.sfc.script, 0, exportDefault.start, codeFeatures.all);
+ yield* generateConstExport(options, options.sfc.script);
+ if (wrapLeft) {
+ yield wrapLeft;
+ }
yield generateSfcBlockSection(
options.sfc.script,
exportDefault.expression.start,
exportDefault.expression.end,
codeFeatures.all,
);
- yield options.vueCompilerOptions.optionsWrapper[1];
- yield generateSfcBlockSection(
- options.sfc.script,
- exportDefault.expression.end,
- options.sfc.script.content.length,
- codeFeatures.all,
- );
+ if (wrapRight) {
+ yield wrapRight;
+ }
+ yield endOfLine;
}
else if (classBlockEnd !== undefined) {
if (options.vueCompilerOptions.skipTemplateCodegen) {
@@ -108,8 +97,7 @@ export function* generateScript(
else {
yield generateSfcBlockSection(options.sfc.script, 0, classBlockEnd, codeFeatures.all);
yield `__VLS_template = () => {${newLine}`;
- const templateCodegenCtx = yield* generateTemplate(options, ctx);
- yield* generateComponentSelf(options, ctx, templateCodegenCtx);
+ yield* generateTemplate(options, ctx);
yield `}${endOfLine}`;
yield generateSfcBlockSection(
options.sfc.script,
@@ -121,39 +109,26 @@ export function* generateScript(
}
else {
yield generateSfcBlockSection(options.sfc.script, 0, options.sfc.script.content.length, codeFeatures.all);
- yield* generateScriptSectionPartiallyEnding(
- options.sfc.script.name,
- options.sfc.script.content.length,
- '#3632/script.vue',
- );
+ yield* generateConstExport(options, options.sfc.script);
+ yield `(await import('${options.vueCompilerOptions.lib}')).defineComponent({})${endOfLine}`;
}
}
else if (options.sfc.scriptSetup && options.scriptSetupRanges) {
yield* generateScriptSetup(options, ctx, options.sfc.scriptSetup, options.scriptSetupRanges);
}
- if (options.sfc.scriptSetup) {
- yield* generateScriptSectionPartiallyEnding(
- options.sfc.scriptSetup.name,
- options.sfc.scriptSetup.content.length,
- '#4569/main.vue',
- ';',
- );
- }
-
if (!ctx.generatedTemplate) {
- const templateCodegenCtx = yield* generateTemplate(options, ctx);
- yield* generateComponentSelf(options, ctx, templateCodegenCtx);
+ yield* generateTemplate(options, ctx);
}
- yield* ctx.localTypes.generate([...ctx.localTypes.getUsedNames()]);
-
- if (options.sfc.scriptSetup) {
- yield ['', 'scriptSetup', options.sfc.scriptSetup.content.length, codeFeatures.verification];
+ if (!options.scriptRanges?.classBlockEnd) {
+ yield* generateExportDefault(options);
}
+
+ yield* ctx.localTypes.generate();
}
-function* generateGlobalTypesPath(
+function* generateGlobalTypesReference(
options: ScriptCodegenOptions,
): Generator {
const globalTypesPath = options.vueCompilerOptions.globalTypesPath(options.fileName);
@@ -177,13 +152,58 @@ function* generateGlobalTypesPath(
}
}
-export function* generateScriptSectionPartiallyEnding(
- source: string,
- end: number,
- mark: string,
- delimiter = 'debugger',
+export function* generateConstExport(
+ options: ScriptCodegenOptions,
+ block: SfcBlock,
): Generator {
- yield delimiter;
- yield ['', source, end, codeFeatures.verification];
- yield `/* PartiallyEnd: ${mark} */${newLine}`;
+ if (options.sfc.script) {
+ yield* generatePartiallyEnding(
+ options.sfc.script.name,
+ options.scriptRanges?.exportDefault
+ ? options.scriptRanges.exportDefault.start
+ : options.sfc.script.content.length,
+ '#3632/script.vue',
+ );
+ }
+ yield `const `;
+ yield* wrapWith(
+ 0,
+ block.content.length,
+ block.name,
+ codeFeatures.verification,
+ `__VLS_export`,
+ );
+ yield ` = `;
+}
+
+function* generateExportDefault(options: ScriptCodegenOptions): Generator {
+ if (options.sfc.script?.src) {
+ yield* generateSrc(options.sfc.script.src);
+ return;
+ }
+
+ let prefix: Code;
+ let suffix: Code;
+ if (options.sfc.script && options.scriptRanges?.exportDefault) {
+ const { exportDefault } = options.scriptRanges;
+ prefix = generateSfcBlockSection(
+ options.sfc.script,
+ exportDefault.start,
+ exportDefault.expression.start,
+ codeFeatures.all,
+ );
+ suffix = generateSfcBlockSection(
+ options.sfc.script,
+ exportDefault.expression.end,
+ options.sfc.script.content.length,
+ codeFeatures.all,
+ );
+ }
+ else {
+ prefix = `export default `;
+ suffix = endOfLine;
+ }
+ yield prefix;
+ yield `{} as typeof __VLS_export`;
+ yield suffix;
}
diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts
index 58397c4c2d..8bf9f895d6 100644
--- a/packages/language-core/lib/codegen/script/scriptSetup.ts
+++ b/packages/language-core/lib/codegen/script/scriptSetup.ts
@@ -2,13 +2,12 @@ import { camelize } from '@vue/shared';
import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges';
import type { Code, Sfc, TextRange } from '../../types';
import { codeFeatures } from '../codeFeatures';
-import { endOfLine, generateSfcBlockSection, newLine } from '../utils';
+import { endOfLine, generatePartiallyEnding, generateSfcBlockSection, identifierRegex, newLine } from '../utils';
import { generateCamelized } from '../utils/camelized';
import { wrapWith } from '../utils/wrapWith';
-import { generateComponent, generateEmitsOption } from './component';
-import { generateComponentSelf } from './componentSelf';
+import { generateComponent } from './component';
import type { ScriptCodegenContext } from './context';
-import { generateScriptSectionPartiallyEnding, type ScriptCodegenOptions } from './index';
+import { generateConstExport, type ScriptCodegenOptions } from './index';
import { generateTemplate } from './template';
export function* generateScriptSetupImports(
@@ -33,11 +32,7 @@ export function* generateScriptSetup(
scriptSetupRanges: ScriptSetupRanges,
): Generator {
if (scriptSetup.generic) {
- if (!options.scriptRanges?.exportDefault) {
- // #4569
- yield ['', 'scriptSetup', 0, codeFeatures.verification];
- yield `export default `;
- }
+ yield* generateConstExport(options, scriptSetup);
yield `(`;
if (typeof scriptSetup.generic === 'object') {
yield `<`;
@@ -59,8 +54,33 @@ export function* generateScriptSetup(
+ ` __VLS_setup = (async () => {${newLine}`;
yield* generateSetupFunction(options, ctx, scriptSetup, scriptSetupRanges, undefined);
- const emitTypes: string[] = [];
+ const propTypes: string[] = [];
+ if (ctx.generatedPropsType) {
+ propTypes.push(`__VLS_PublicProps`);
+ }
+ if (scriptSetupRanges.defineProps?.arg) {
+ yield `const __VLS_propsOption = `;
+ yield generateSfcBlockSection(
+ scriptSetup,
+ scriptSetupRanges.defineProps.arg.start,
+ scriptSetupRanges.defineProps.arg.end,
+ codeFeatures.navigation,
+ );
+ yield endOfLine;
+ propTypes.push(
+ `import('${options.vueCompilerOptions.lib}').${
+ options.vueCompilerOptions.target >= 3.3 ? `ExtractPublicPropTypes` : `ExtractPropTypes`
+ }`,
+ );
+ }
+ if (scriptSetupRanges.defineEmits || scriptSetupRanges.defineModel.length) {
+ propTypes.push(`__VLS_EmitProps`);
+ }
+ if (options.templateCodegen?.inheritedAttrVars.size) {
+ propTypes.push(`__VLS_InheritedAttrs`);
+ }
+ const emitTypes: string[] = [];
if (scriptSetupRanges.defineEmits) {
emitTypes.push(`typeof ${scriptSetupRanges.defineEmits.name ?? '__VLS_emit'}`);
}
@@ -69,28 +89,36 @@ export function* generateScriptSetup(
}
yield `return {} as {${newLine}`
- + ` props: ${ctx.localTypes.PrettifyLocal}<__VLS_OwnProps & __VLS_PublicProps & __VLS_InheritedAttrs> & __VLS_BuiltInPublicProps,${newLine}`
- + ` expose(exposed: import('${options.vueCompilerOptions.lib}').ShallowUnwrapRef<${
- scriptSetupRanges.defineExpose ? 'typeof __VLS_exposed' : '{}'
- }>): void,${newLine}`
- + ` attrs: any,${newLine}`
- + ` slots: __VLS_Slots,${newLine}`
- + ` emit: ${emitTypes.length ? emitTypes.join(' & ') : `{}`},${newLine}`
+ + ` props: ${ctx.localTypes.PrettifyLocal}<${propTypes.join(` & `)}> & ${
+ options.vueCompilerOptions.target >= 3.4
+ ? `import('${options.vueCompilerOptions.lib}').PublicProps`
+ : options.vueCompilerOptions.target >= 3
+ ? `import('${options.vueCompilerOptions.lib}').VNodeProps`
+ + ` & import('${options.vueCompilerOptions.lib}').AllowedComponentProps`
+ + ` & import('${options.vueCompilerOptions.lib}').ComponentCustomProps`
+ : `globalThis.JSX.IntrinsicAttributes`
+ }${endOfLine}`
+ + ` expose: (exposed: ${
+ scriptSetupRanges.defineExpose
+ ? `import('${options.vueCompilerOptions.lib}').ShallowUnwrapRef`
+ : `{}`
+ }) => void${endOfLine}`
+ + ` attrs: any${endOfLine}`
+ + ` slots: __VLS_Slots${endOfLine}`
+ + ` emit: ${emitTypes.length ? emitTypes.join(` & `) : `{}`}${endOfLine}`
+ `}${endOfLine}`;
yield `})(),${newLine}`; // __VLS_setup = (async () => {
- yield `) => ({} as import('${options.vueCompilerOptions.lib}').VNode & { __ctx?: Awaited }))`;
+ yield `) => ({} as import('${options.vueCompilerOptions.lib}').VNode & { __ctx?: Awaited }))${endOfLine}`;
}
else if (!options.sfc.script) {
// no script block, generate script setup code at root
yield* generateSetupFunction(options, ctx, scriptSetup, scriptSetupRanges, 'export default');
}
else {
- if (!options.scriptRanges?.exportDefault) {
- yield `export default `;
- }
+ yield* generateConstExport(options, scriptSetup);
yield `await (async () => {${newLine}`;
yield* generateSetupFunction(options, ctx, scriptSetup, scriptSetupRanges, 'return');
- yield `})()`;
+ yield `})()${endOfLine}`;
}
}
@@ -291,40 +319,32 @@ function* generateSetupFunction(
}
yield generateSfcBlockSection(scriptSetup, nextStart, scriptSetup.content.length, codeFeatures.all);
- yield* generateScriptSectionPartiallyEnding(scriptSetup.name, scriptSetup.content.length, '#3632/scriptSetup.vue');
+ yield* generatePartiallyEnding(scriptSetup.name, scriptSetup.content.length, '#3632/scriptSetup.vue');
yield* generateMacros(options, ctx);
- if (scriptSetupRanges.defineProps?.typeArg && scriptSetupRanges.withDefaults?.arg) {
- // fix https://github.com/vuejs/language-tools/issues/1187
- yield `const __VLS_withDefaultsArg = (function (t: T) { return t })(`;
- yield generateSfcBlockSection(
- scriptSetup,
- scriptSetupRanges.withDefaults.arg.start,
- scriptSetupRanges.withDefaults.arg.end,
- codeFeatures.navigation,
- );
- yield `)${endOfLine}`;
- }
+ const hasSlots = !!(
+ scriptSetupRanges.defineSlots
+ || options.templateCodegen?.slots.length
+ || options.templateCodegen?.dynamicSlots.length
+ );
- yield* generateComponentProps(options, ctx, scriptSetup, scriptSetupRanges);
- yield* generateModelEmit(scriptSetup, scriptSetupRanges);
- const templateCodegenCtx = yield* generateTemplate(options, ctx);
- yield* generateComponentSelf(options, ctx, templateCodegenCtx);
+ yield* generateModels(scriptSetup, scriptSetupRanges);
+ yield* generatePublicProps(options, ctx, scriptSetup, scriptSetupRanges, hasSlots);
+ yield* generateTemplate(options, ctx);
if (syntax) {
- if (
- scriptSetupRanges.defineSlots
- || options.templateCodegen?.slots.length
- || options.templateCodegen?.dynamicSlots.length
- ) {
- yield `const __VLS_component = `;
+ const prefix = syntax === 'return'
+ ? [`return `]
+ : generateConstExport(options, scriptSetup);
+ if (hasSlots) {
+ yield `const __VLS_base = `;
yield* generateComponent(options, ctx, scriptSetup, scriptSetupRanges);
yield endOfLine;
- yield `${syntax} `;
- yield `{} as ${ctx.localTypes.WithSlots}${endOfLine}`;
+ yield* prefix;
+ yield `{} as ${ctx.localTypes.WithSlots}${endOfLine}`;
}
else {
- yield `${syntax} `;
+ yield* prefix;
yield* generateComponent(options, ctx, scriptSetup, scriptSetupRanges);
yield endOfLine;
}
@@ -406,176 +426,163 @@ function* generateDefineWithType(
];
}
}
+ else if (!identifierRegex.test(name)) {
+ yield [[`const ${defaultName} = `], statement.start, callExp.start];
+ yield [
+ [
+ endOfLine,
+ generateSfcBlockSection(scriptSetup, statement.start, callExp.start, codeFeatures.all),
+ defaultName,
+ ],
+ statement.end,
+ statement.end,
+ ];
+ }
}
-function* generateComponentProps(
+function* generatePublicProps(
options: ScriptCodegenOptions,
ctx: ScriptCodegenContext,
scriptSetup: NonNullable,
scriptSetupRanges: ScriptSetupRanges,
+ hasSlots: boolean,
): Generator {
- if (scriptSetup.generic) {
- yield `const __VLS_fnComponent = (await import('${options.vueCompilerOptions.lib}')).defineComponent({${newLine}`;
-
- if (scriptSetupRanges.defineProps?.arg) {
- yield `props: `;
- yield generateSfcBlockSection(
- scriptSetup,
- scriptSetupRanges.defineProps.arg.start,
- scriptSetupRanges.defineProps.arg.end,
- codeFeatures.navigation,
- );
- yield `,${newLine}`;
- }
-
- yield* generateEmitsOption(options, scriptSetupRanges);
-
- yield `})${endOfLine}`;
-
- yield `type __VLS_BuiltInPublicProps = ${
- options.vueCompilerOptions.target >= 3.4
- ? `import('${options.vueCompilerOptions.lib}').PublicProps`
- : options.vueCompilerOptions.target >= 3
- ? `import('${options.vueCompilerOptions.lib}').VNodeProps`
- + ` & import('${options.vueCompilerOptions.lib}').AllowedComponentProps`
- + ` & import('${options.vueCompilerOptions.lib}').ComponentCustomProps`
- : `globalThis.JSX.IntrinsicAttributes`
- }`;
- yield endOfLine;
-
- yield `type __VLS_OwnProps = `;
- yield `${ctx.localTypes.OmitKeepDiscriminatedUnion}['$props'], keyof __VLS_BuiltInPublicProps>`;
+ if (scriptSetupRanges.defineProps?.typeArg && scriptSetupRanges.withDefaults?.arg) {
+ yield `const __VLS_defaults = `;
+ yield generateSfcBlockSection(
+ scriptSetup,
+ scriptSetupRanges.withDefaults.arg.start,
+ scriptSetupRanges.withDefaults.arg.end,
+ codeFeatures.navigation,
+ );
yield endOfLine;
}
- if (scriptSetupRanges.defineModel.length) {
- yield `const __VLS_defaults = {${newLine}`;
- for (const defineModel of scriptSetupRanges.defineModel) {
- if (!defineModel.defaultValue) {
- continue;
- }
- const [propName] = getPropAndLocalName(scriptSetup, defineModel);
-
- yield `'${propName}': `;
- yield getRangeText(scriptSetup, defineModel.defaultValue);
- yield `,${newLine}`;
- }
- yield `}${endOfLine}`;
- }
-
- yield `type __VLS_PublicProps = `;
- if (scriptSetupRanges.defineSlots && options.vueCompilerOptions.jsxSlots) {
- if (ctx.generatedPropsType) {
- yield ` & `;
- }
- ctx.generatedPropsType = true;
- yield `${ctx.localTypes.PropsChildren}<__VLS_Slots>`;
+ const propTypes: string[] = [];
+ if (options.vueCompilerOptions.jsxSlots && hasSlots) {
+ propTypes.push(`${ctx.localTypes.PropsChildren}<__VLS_Slots>`);
}
if (scriptSetupRanges.defineProps?.typeArg) {
- if (ctx.generatedPropsType) {
- yield ` & `;
- }
- ctx.generatedPropsType = true;
- yield `__VLS_Props`;
+ propTypes.push(`__VLS_Props`);
}
if (scriptSetupRanges.defineModel.length) {
- if (ctx.generatedPropsType) {
- yield ` & `;
- }
- ctx.generatedPropsType = true;
- yield `{${newLine}`;
- for (const defineModel of scriptSetupRanges.defineModel) {
- const [propName, localName] = getPropAndLocalName(scriptSetup, defineModel);
-
- if (defineModel.comments) {
- yield scriptSetup.content.slice(defineModel.comments.start, defineModel.comments.end);
- yield newLine;
- }
-
- if (defineModel.name) {
- yield* generateCamelized(
- getRangeText(scriptSetup, defineModel.name),
- scriptSetup.name,
- defineModel.name.start,
- codeFeatures.navigation,
- );
- }
- else {
- yield propName;
- }
-
- yield defineModel.required ? `: ` : `?: `;
- yield* generateDefineModelType(scriptSetup, propName, localName, defineModel);
- yield `,${newLine}`;
-
- if (defineModel.modifierType) {
- const modifierName = `${propName === 'modelValue' ? 'model' : propName}Modifiers`;
- const modifierType = getRangeText(scriptSetup, defineModel.modifierType);
- yield `'${modifierName}'?: Partial>,${newLine}`;
- }
- }
- yield `}`;
+ propTypes.push(`__VLS_ModelProps`);
}
- if (!ctx.generatedPropsType) {
- yield `{}`;
+ if (propTypes.length) {
+ ctx.generatedPropsType = true;
+ yield `type __VLS_PublicProps = ${propTypes.join(` & `)}${endOfLine}`;
}
- yield endOfLine;
}
-function* generateModelEmit(
+function* generateModels(
scriptSetup: NonNullable,
scriptSetupRanges: ScriptSetupRanges,
): Generator {
- if (scriptSetupRanges.defineModel.length) {
- yield `type __VLS_ModelEmit = {${newLine}`;
- for (const defineModel of scriptSetupRanges.defineModel) {
- const [propName, localName] = getPropAndLocalName(scriptSetup, defineModel);
- yield `'update:${propName}': [value: `;
- yield* generateDefineModelType(scriptSetup, propName, localName, defineModel);
- if (!defineModel.required && !defineModel.defaultValue) {
- yield ` | undefined`;
- }
- yield `]${endOfLine}`;
+ if (!scriptSetupRanges.defineModel.length) {
+ return;
+ }
+
+ const defaultCodes: string[] = [];
+ const propCodes: Generator[] = [];
+ const emitCodes: Generator[] = [];
+
+ for (const defineModel of scriptSetupRanges.defineModel) {
+ const propName = defineModel.name
+ ? camelize(getRangeText(scriptSetup, defineModel.name).slice(1, -1))
+ : 'modelValue';
+
+ let modelType: string;
+ if (defineModel.type) {
+ // Infer from defineModel
+ modelType = getRangeText(scriptSetup, defineModel.type);
+ }
+ else if (defineModel.runtimeType && defineModel.localName) {
+ // Infer from actual prop declaration code
+ modelType = `typeof ${getRangeText(scriptSetup, defineModel.localName)}['value']`;
+ }
+ else if (defineModel.defaultValue && propName) {
+ // Infer from defineModel({ default: T })
+ modelType = `typeof __VLS_defaultModels['${propName}']`;
}
+ else {
+ modelType = `any`;
+ }
+
+ if (defineModel.defaultValue) {
+ defaultCodes.push(
+ `'${propName}': ${getRangeText(scriptSetup, defineModel.defaultValue)},${newLine}`,
+ );
+ }
+
+ propCodes.push(generateModelProp(scriptSetup, defineModel, propName, modelType));
+ emitCodes.push(generateModelEmit(defineModel, propName, modelType));
+ }
+
+ if (defaultCodes.length) {
+ yield `const __VLS_defaultModels = {${newLine}`;
+ yield* defaultCodes;
yield `}${endOfLine}`;
- yield `const __VLS_modelEmit = defineEmits<__VLS_ModelEmit>()${endOfLine}`;
}
+
+ yield `type __VLS_ModelProps = {${newLine}`;
+ for (const codes of propCodes) {
+ yield* codes;
+ }
+ yield `}${endOfLine}`;
+
+ yield `type __VLS_ModelEmit = {${newLine}`;
+ for (const codes of emitCodes) {
+ yield* codes;
+ }
+ yield `}${endOfLine}`;
+ yield `const __VLS_modelEmit = defineEmits<__VLS_ModelEmit>()${endOfLine}`;
}
-function* generateDefineModelType(
+function* generateModelProp(
scriptSetup: NonNullable,
- propName: string | undefined,
- localName: string | undefined,
defineModel: ScriptSetupRanges['defineModel'][number],
-) {
- if (defineModel.type) {
- // Infer from defineModel
- yield getRangeText(scriptSetup, defineModel.type);
- }
- else if (defineModel.runtimeType && localName) {
- // Infer from actual prop declaration code
- yield `typeof ${localName}['value']`;
+ propName: string,
+ modelType: string,
+): Generator {
+ if (defineModel.comments) {
+ yield scriptSetup.content.slice(defineModel.comments.start, defineModel.comments.end);
+ yield newLine;
}
- else if (defineModel.defaultValue && propName) {
- // Infer from defineModel({default: T})
- yield `typeof __VLS_defaults['${propName}']`;
+
+ if (defineModel.name) {
+ yield* generateCamelized(
+ getRangeText(scriptSetup, defineModel.name),
+ scriptSetup.name,
+ defineModel.name.start,
+ codeFeatures.navigation,
+ );
}
else {
- yield `any`;
+ yield propName;
+ }
+
+ yield defineModel.required ? `: ` : `?: `;
+ yield modelType;
+ yield endOfLine;
+
+ if (defineModel.modifierType) {
+ const modifierName = `${propName === 'modelValue' ? 'model' : propName}Modifiers`;
+ const modifierType = getRangeText(scriptSetup, defineModel.modifierType);
+ yield `'${modifierName}'?: Partial>${endOfLine}`;
}
}
-function getPropAndLocalName(
- scriptSetup: NonNullable,
+function* generateModelEmit(
defineModel: ScriptSetupRanges['defineModel'][number],
-) {
- const localName = defineModel.localName
- ? getRangeText(scriptSetup, defineModel.localName)
- : undefined;
- const propName = defineModel.name
- ? camelize(getRangeText(scriptSetup, defineModel.name).slice(1, -1))
- : 'modelValue';
- return [propName, localName] as const;
+ propName: string,
+ modelType: string,
+): Generator {
+ yield `'update:${propName}': [value: `;
+ yield modelType;
+ if (!defineModel.required && !defineModel.defaultValue) {
+ yield ` | undefined`;
+ }
+ yield `]${endOfLine}`;
}
function getRangeText(
diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts
index 9963e7a38e..f3a5ba8a0f 100644
--- a/packages/language-core/lib/codegen/script/template.ts
+++ b/packages/language-core/lib/codegen/script/template.ts
@@ -1,3 +1,5 @@
+import { camelize, capitalize } from '@vue/shared';
+import * as path from 'path-browserify';
import type { Code } from '../../types';
import { codeFeatures } from '../codeFeatures';
import { generateStyleModules } from '../style/modules';
@@ -13,32 +15,89 @@ import type { ScriptCodegenOptions } from './index';
export function* generateTemplate(
options: ScriptCodegenOptions,
ctx: ScriptCodegenContext,
-): Generator {
+): Generator {
ctx.generatedTemplate = true;
- const templateCodegenCtx = createTemplateCodegenContext({
- scriptSetupBindingNames: new Set(),
- });
- yield* generateTemplateCtx(options);
+ yield* generateSelf(options);
+ yield* generateTemplateCtx(options, ctx);
yield* generateTemplateElements();
yield* generateTemplateComponents(options);
yield* generateTemplateDirectives(options);
- yield* generateTemplateBody(options, templateCodegenCtx);
- return templateCodegenCtx;
+ yield* generateTemplateBody(options, ctx);
}
-function* generateTemplateCtx(options: ScriptCodegenOptions): Generator {
- const exps = [];
+function* generateSelf(options: ScriptCodegenOptions): Generator {
+ if (options.sfc.script && options.scriptRanges?.exportDefault) {
+ yield `const __VLS_self = (await import('${options.vueCompilerOptions.lib}')).defineComponent(`;
+ const { args } = options.scriptRanges.exportDefault;
+ yield generateSfcBlockSection(options.sfc.script, args.start, args.end, codeFeatures.all);
+ yield `)${endOfLine}`;
+ }
+ else if (options.sfc.script?.src || options.scriptRanges?.classBlockEnd) {
+ yield `let __VLS_self!: typeof import('./${path.basename(options.fileName)}').default${endOfLine}`;
+ }
+}
- exps.push(`{} as InstanceType<__VLS_PickNotAny {}>>`);
+function* generateTemplateCtx(
+ options: ScriptCodegenOptions,
+ ctx: ScriptCodegenContext,
+): Generator {
+ const exps: Code[] = [];
if (options.vueCompilerOptions.petiteVueExtensions.some(ext => options.fileName.endsWith(ext))) {
exps.push(`globalThis`);
}
+ if (options.sfc.script?.src || options.scriptRanges?.exportDefault || options.scriptRanges?.classBlockEnd) {
+ exps.push(`{} as InstanceType<__VLS_PickNotAny {}>>`);
+ }
+ else {
+ exps.push(`{} as import('${options.vueCompilerOptions.lib}').ComponentPublicInstance`);
+ }
if (options.sfc.styles.some(style => style.module)) {
exps.push(`{} as __VLS_StyleModules`);
}
+ const emitTypes: string[] = [];
+ if (options.scriptSetupRanges?.defineEmits) {
+ const { defineEmits } = options.scriptSetupRanges;
+ emitTypes.push(`typeof ${defineEmits.name ?? `__VLS_emit`}`);
+ }
+ if (options.scriptSetupRanges?.defineModel.length) {
+ emitTypes.push(`typeof __VLS_modelEmit`);
+ }
+ if (emitTypes.length) {
+ yield `type __VLS_EmitProps = __VLS_EmitsToProps<__VLS_NormalizeEmits<${emitTypes.join(` & `)}>>${endOfLine}`;
+ exps.push(`{} as { $emit: ${emitTypes.join(` & `)} }`);
+ }
+
+ const propTypes: string[] = [];
+ const { defineProps, withDefaults } = options.scriptSetupRanges ?? {};
+ const props = defineProps?.arg
+ ? `typeof ${defineProps.name ?? `__VLS_props`}`
+ : defineProps?.typeArg
+ ? withDefaults?.arg
+ ? `__VLS_WithDefaultsGlobal<__VLS_Props, typeof __VLS_defaults>`
+ : `__VLS_Props`
+ : undefined;
+ if (props) {
+ propTypes.push(props);
+ }
+ if (options.scriptSetupRanges?.defineModel.length) {
+ propTypes.push(`__VLS_ModelProps`);
+ }
+ if (emitTypes.length) {
+ propTypes.push(`__VLS_EmitProps`);
+ }
+ if (propTypes.length) {
+ yield `type __VLS_InternalProps = ${propTypes.join(` & `)}${endOfLine}`;
+ exps.push(`{} as { $props: __VLS_InternalProps }`);
+ exps.push(`{} as __VLS_InternalProps`);
+ }
+
+ if (options.scriptSetupRanges && ctx.bindingNames.size) {
+ exps.push(`{} as __VLS_Bindings`);
+ }
+
yield `const __VLS_ctx = `;
yield* generateSpreadMerge(exps);
yield endOfLine;
@@ -68,7 +127,7 @@ function* generateTemplateComponents(options: ScriptCodegenOptions): Generator {
+function* generateTemplateDirectives(options: ScriptCodegenOptions): Generator {
const types: string[] = [`typeof __VLS_ctx`];
if (options.sfc.script && options.scriptRanges?.exportDefault?.directivesOption) {
@@ -90,12 +149,17 @@ export function* generateTemplateDirectives(options: ScriptCodegenOptions): Gene
function* generateTemplateBody(
options: ScriptCodegenOptions,
- templateCodegenCtx: TemplateCodegenContext,
+ ctx: ScriptCodegenContext,
): Generator {
+ const templateCodegenCtx = createTemplateCodegenContext({
+ scriptSetupBindingNames: new Set(),
+ });
+
yield* generateStyleScopedClasses(options, templateCodegenCtx);
yield* generateStyleScopedClassReferences(templateCodegenCtx, true);
yield* generateStyleModules(options);
yield* generateCssVars(options, templateCodegenCtx);
+ yield* generateBindings(options, ctx, templateCodegenCtx);
if (options.templateCodegen) {
yield* options.templateCodegen.codes;
@@ -110,11 +174,10 @@ function* generateTemplateBody(
}
}
-function* generateCssVars(options: ScriptCodegenOptions, ctx: TemplateCodegenContext): Generator {
- if (!options.sfc.styles.length) {
- return;
- }
- yield `// CSS variable injection ${newLine}`;
+function* generateCssVars(
+ options: ScriptCodegenOptions,
+ ctx: TemplateCodegenContext,
+): Generator {
for (const style of options.sfc.styles) {
for (const binding of style.bindings) {
yield* generateInterpolation(
@@ -124,9 +187,41 @@ function* generateCssVars(options: ScriptCodegenOptions, ctx: TemplateCodegenCon
codeFeatures.all,
binding.text,
binding.offset,
+ `(`,
+ `)`,
);
yield endOfLine;
}
}
- yield `// CSS variable injection end ${newLine}`;
+}
+
+function* generateBindings(
+ options: ScriptCodegenOptions,
+ ctx: ScriptCodegenContext,
+ templateCodegenCtx: TemplateCodegenContext,
+): Generator {
+ if (!options.sfc.scriptSetup || !ctx.bindingNames.size) {
+ return;
+ }
+
+ const usageVars = new Set([
+ ...options.sfc.template?.ast?.components.flatMap(c => [camelize(c), capitalize(camelize(c))]) ?? [],
+ ...options.templateCodegen?.accessExternalVariables.keys() ?? [],
+ ...templateCodegenCtx.accessExternalVariables.keys(),
+ ]);
+
+ yield `type __VLS_Bindings = __VLS_ProxyRefs<{${newLine}`;
+ for (const varName of ctx.bindingNames) {
+ if (!usageVars.has(varName)) {
+ continue;
+ }
+
+ const token = Symbol(varName.length);
+ yield ['', undefined, 0, { __linkedToken: token }];
+ yield `${varName}: typeof `;
+ yield ['', undefined, 0, { __linkedToken: token }];
+ yield varName;
+ yield endOfLine;
+ }
+ yield `}>${endOfLine}`;
}
diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts
index c5c7897e10..4f9f2958d0 100644
--- a/packages/language-core/lib/codegen/template/context.ts
+++ b/packages/language-core/lib/codegen/template/context.ts
@@ -264,7 +264,7 @@ export function createTemplateCodegenContext(
},
*generateAutoImportCompletion(): Generator {
const all = [...accessExternalVariables.entries()];
- if (!all.some(([_, offsets]) => offsets.size)) {
+ if (!all.some(([, offsets]) => offsets.size)) {
return;
}
yield `// @ts-ignore${newLine}`; // #2304
diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts
index 3348c945c2..3ecf690809 100644
--- a/packages/language-core/lib/codegen/template/element.ts
+++ b/packages/language-core/lib/codegen/template/element.ts
@@ -1,7 +1,7 @@
import * as CompilerDOM from '@vue/compiler-dom';
import { camelize, capitalize } from '@vue/shared';
import type { Code, VueCodeInformation } from '../../types';
-import { getSlotsPropertyName, hyphenateTag } from '../../utils/shared';
+import { hyphenateTag } from '../../utils/shared';
import { codeFeatures } from '../codeFeatures';
import { createVBindShorthandInlayHintInfo } from '../inlayHints';
import { endOfLine, identifierRegex, newLine, normalizeAttributeValue } from '../utils';
@@ -138,9 +138,7 @@ export function* generateComponent(
getCanonicalComponentName(node.tag)
}', __VLS_LocalComponents, `;
if (options.selfComponentName && possibleOriginalNames.includes(options.selfComponentName)) {
- yield `typeof __VLS_self & (new () => { `
- + getSlotsPropertyName(options.vueCompilerOptions.target)
- + `: __VLS_Slots }), `;
+ yield `typeof __VLS_export, `;
}
else {
yield `void, `;
diff --git a/packages/language-core/lib/codegen/template/elementProps.ts b/packages/language-core/lib/codegen/template/elementProps.ts
index 4aa75ecbe8..e303be1870 100644
--- a/packages/language-core/lib/codegen/template/elementProps.ts
+++ b/packages/language-core/lib/codegen/template/elementProps.ts
@@ -372,9 +372,7 @@ function getShouldCamelize(
&& !options.vueCompilerOptions.htmlAttributes.some(pattern => isMatch(propName, pattern));
}
-function getPropsCodeFeatures(
- strictPropsCheck: boolean,
-): VueCodeInformation {
+function getPropsCodeFeatures(strictPropsCheck: boolean): VueCodeInformation {
return {
...codeFeatures.withoutHighlightAndCompletion,
...strictPropsCheck
diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts
index f623349b67..fb80082f46 100644
--- a/packages/language-core/lib/codegen/template/index.ts
+++ b/packages/language-core/lib/codegen/template/index.ts
@@ -22,8 +22,8 @@ export interface TemplateCodegenOptions {
destructuredPropNames: Set;
templateRefNames: Set;
hasDefineSlots?: boolean;
- slotsAssignName?: string;
propsAssignName?: string;
+ slotsAssignName?: string;
inheritAttrs: boolean;
selfComponentName?: string;
}
@@ -60,24 +60,26 @@ export function* generateTemplate(
yield* generateStyleScopedClassReferences(ctx);
yield* ctx.generateHoistVariables();
- const speicalTypes = [
+ const dollarTypes = [
[slotsPropertyName, yield* generateSlots(options, ctx)],
['$attrs', yield* generateInheritedAttrs(options, ctx)],
['$refs', yield* generateTemplateRefs(options, ctx)],
['$el', yield* generateRootEl(ctx)],
- ];
+ ].filter(([name]) => ctx.dollarVars.has(name));
- yield `var __VLS_dollars!: {${newLine}`;
- for (const [name, type] of speicalTypes) {
- yield `${name}: ${type}${endOfLine}`;
+ if (dollarTypes.length) {
+ yield `var __VLS_dollars!: {${newLine}`;
+ for (const [name, type] of dollarTypes) {
+ yield `${name}: ${type}${endOfLine}`;
+ }
+ yield `} & { [K in keyof import('${options.vueCompilerOptions.lib}').ComponentPublicInstance]: unknown }${endOfLine}`;
}
- yield `} & { [K in keyof import('${options.vueCompilerOptions.lib}').ComponentPublicInstance]: unknown }${endOfLine}`;
}
function* generateSlots(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
-): Generator {
+): Generator {
if (!options.hasDefineSlots) {
yield `type __VLS_Slots = {}`;
for (const { expVar, propsVar } of ctx.dynamicSlots) {
@@ -112,7 +114,7 @@ function* generateSlots(
function* generateInheritedAttrs(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
-): Generator {
+): Generator {
yield `type __VLS_InheritedAttrs = ${
ctx.inheritedAttrVars.size
? `Partial<${[...ctx.inheritedAttrVars].map(name => `typeof ${name}`).join(` & `)}>`
@@ -140,7 +142,7 @@ function* generateInheritedAttrs(
function* generateTemplateRefs(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
-): Generator {
+): Generator {
yield `type __VLS_TemplateRefs = {}`;
for (const [name, refs] of ctx.templateRefs) {
yield `${newLine}& `;
@@ -172,7 +174,7 @@ function* generateTemplateRefs(
function* generateRootEl(
ctx: TemplateCodegenContext,
-): Generator {
+): Generator {
yield `type __VLS_RootEl = `;
if (ctx.singleRootElTypes.length && !ctx.singleRootNodes.has(null)) {
for (const type of ctx.singleRootElTypes) {
diff --git a/packages/language-core/lib/codegen/utils/index.ts b/packages/language-core/lib/codegen/utils/index.ts
index 6f7ab63253..61e9f5c85b 100644
--- a/packages/language-core/lib/codegen/utils/index.ts
+++ b/packages/language-core/lib/codegen/utils/index.ts
@@ -1,6 +1,7 @@
import type * as CompilerDOM from '@vue/compiler-dom';
import type * as ts from 'typescript';
import type { Code, SfcBlock, VueCodeInformation } from '../../types';
+import { codeFeatures } from '../codeFeatures';
export const newLine = `\n`;
export const endOfLine = `;${newLine}`;
@@ -47,3 +48,14 @@ export function generateSfcBlockSection(
features,
];
}
+
+export function* generatePartiallyEnding(
+ source: string,
+ end: number,
+ mark: string,
+ delimiter = 'debugger',
+): Generator {
+ yield delimiter;
+ yield [``, source, end, codeFeatures.verification];
+ yield `/* PartiallyEnd: ${mark} */${newLine}`;
+}
diff --git a/packages/language-core/lib/languagePlugin.ts b/packages/language-core/lib/languagePlugin.ts
index 9e9c21882d..fc9d186399 100644
--- a/packages/language-core/lib/languagePlugin.ts
+++ b/packages/language-core/lib/languagePlugin.ts
@@ -139,16 +139,11 @@ export function createVueLanguagePlugin(
}
export function getAllExtensions(options: VueCompilerOptions) {
- const result = new Set();
- for (const key in options) {
- if (key === 'extensions' || key.endsWith('Extensions')) {
- const value = options[key as keyof VueCompilerOptions];
- if (Array.isArray(value) && value.every(v => typeof v === 'string')) {
- for (const ext of value) {
- result.add(ext);
- }
- }
- }
- }
- return [...result];
+ return [
+ ...new Set(([
+ 'extensions',
+ 'vitePressExtensions',
+ 'petiteVueExtensions',
+ ] as const).flatMap(key => options[key])),
+ ];
}
diff --git a/packages/language-core/lib/parsers/scriptRanges.ts b/packages/language-core/lib/parsers/scriptRanges.ts
index 1aca002dc0..e2ae3d5cf8 100644
--- a/packages/language-core/lib/parsers/scriptRanges.ts
+++ b/packages/language-core/lib/parsers/scriptRanges.ts
@@ -1,7 +1,7 @@
import type * as ts from 'typescript';
import type { TextRange } from '../types';
import { getNodeText, getStartEnd } from '../utils/shared';
-import { parseBindingRanges } from './scriptSetupRanges';
+import { getClosestMultiLineCommentRange, parseBindingRanges } from './utils';
export interface ScriptRanges extends ReturnType {}
@@ -72,6 +72,10 @@ export function parseScriptRanges(ts: typeof import('typescript'), ast: ts.Sourc
nameOption: nameOptionNode ? _getStartEnd(nameOptionNode) : undefined,
inheritAttrsOption,
};
+ const comment = getClosestMultiLineCommentRange(ts, raw, [], ast);
+ if (comment) {
+ exportDefault.start = comment.start;
+ }
}
}
diff --git a/packages/language-core/lib/parsers/scriptSetupRanges.ts b/packages/language-core/lib/parsers/scriptSetupRanges.ts
index 886de3ff79..343e1bf72b 100644
--- a/packages/language-core/lib/parsers/scriptSetupRanges.ts
+++ b/packages/language-core/lib/parsers/scriptSetupRanges.ts
@@ -1,9 +1,10 @@
import type * as ts from 'typescript';
import type { TextRange, VueCompilerOptions } from '../types';
-import { collectBindingIdentifiers, collectBindingRanges } from '../utils/collectBindings';
+import { collectBindingIdentifiers } from '../utils/collectBindings';
import { getNodeText, getStartEnd } from '../utils/shared';
+import { getClosestMultiLineCommentRange, parseBindingRanges } from './utils';
-const tsCheckReg = /^\/\/\s*@ts-(?:no)?check($|\s)/;
+const tsCheckReg = /^\/\/\s*@ts-(?:no)?check(?:$|\s)/;
type CallExpressionRange = {
callExp: TextRange;
@@ -349,7 +350,9 @@ export function parseScriptSetupRanges(
function parseCallExpressionAssignment(node: ts.CallExpression, parent: ts.Node) {
return {
- name: ts.isVariableDeclaration(parent) ? _getNodeText(parent.name) : undefined,
+ name: ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)
+ ? _getNodeText(parent.name)
+ : undefined,
...parseCallExpression(node),
};
}
@@ -363,90 +366,6 @@ export function parseScriptSetupRanges(
}
}
-export function parseBindingRanges(ts: typeof import('typescript'), ast: ts.SourceFile) {
- const bindings: {
- range: TextRange;
- moduleName?: string;
- isDefaultImport?: boolean;
- isNamespace?: boolean;
- }[] = [];
-
- ts.forEachChild(ast, node => {
- if (ts.isVariableStatement(node)) {
- for (const decl of node.declarationList.declarations) {
- const ranges = collectBindingRanges(ts, decl.name, ast);
- bindings.push(...ranges.map(range => ({ range })));
- }
- }
- else if (ts.isFunctionDeclaration(node)) {
- if (node.name && ts.isIdentifier(node.name)) {
- bindings.push({
- range: _getStartEnd(node.name),
- });
- }
- }
- else if (ts.isClassDeclaration(node)) {
- if (node.name) {
- bindings.push({
- range: _getStartEnd(node.name),
- });
- }
- }
- else if (ts.isEnumDeclaration(node)) {
- bindings.push({
- range: _getStartEnd(node.name),
- });
- }
-
- if (ts.isImportDeclaration(node)) {
- const moduleName = _getNodeText(node.moduleSpecifier).slice(1, -1);
-
- if (node.importClause && !node.importClause.isTypeOnly) {
- const { name, namedBindings } = node.importClause;
-
- if (name) {
- bindings.push({
- range: _getStartEnd(name),
- moduleName,
- isDefaultImport: true,
- });
- }
- if (namedBindings) {
- if (ts.isNamedImports(namedBindings)) {
- for (const element of namedBindings.elements) {
- if (element.isTypeOnly) {
- continue;
- }
- bindings.push({
- range: _getStartEnd(element.name),
- moduleName,
- isDefaultImport: element.propertyName?.text === 'default',
- });
- }
- }
- else {
- bindings.push({
- range: _getStartEnd(namedBindings.name),
- moduleName,
- isNamespace: true,
- });
- }
- }
- }
- }
- });
-
- return bindings;
-
- function _getStartEnd(node: ts.Node) {
- return getStartEnd(ts, node, ast);
- }
-
- function _getNodeText(node: ts.Node) {
- return getNodeText(ts, node, ast);
- }
-}
-
function getStatementRange(
ts: typeof import('typescript'),
parents: ts.Node[],
@@ -470,27 +389,3 @@ function getStatementRange(
}
return statementRange;
}
-
-function getClosestMultiLineCommentRange(
- ts: typeof import('typescript'),
- node: ts.Node,
- parents: ts.Node[],
- ast: ts.SourceFile,
-) {
- for (let i = parents.length - 1; i >= 0; i--) {
- if (ts.isStatement(node)) {
- break;
- }
- node = parents[i];
- }
- const comment = ts.getLeadingCommentRanges(ast.text, node.pos)
- ?.reverse()
- .find(range => range.kind === 3 satisfies ts.SyntaxKind.MultiLineCommentTrivia);
-
- if (comment) {
- return {
- start: comment.pos,
- end: comment.end,
- };
- }
-}
diff --git a/packages/language-core/lib/parsers/utils.ts b/packages/language-core/lib/parsers/utils.ts
new file mode 100644
index 0000000000..f69c1f7709
--- /dev/null
+++ b/packages/language-core/lib/parsers/utils.ts
@@ -0,0 +1,112 @@
+import type * as ts from 'typescript';
+import type { TextRange } from '../types';
+import { collectBindingRanges } from '../utils/collectBindings';
+import { getNodeText, getStartEnd } from '../utils/shared';
+
+export function parseBindingRanges(ts: typeof import('typescript'), ast: ts.SourceFile) {
+ const bindings: {
+ range: TextRange;
+ moduleName?: string;
+ isDefaultImport?: boolean;
+ isNamespace?: boolean;
+ }[] = [];
+
+ ts.forEachChild(ast, node => {
+ if (ts.isVariableStatement(node)) {
+ for (const decl of node.declarationList.declarations) {
+ const ranges = collectBindingRanges(ts, decl.name, ast);
+ bindings.push(...ranges.map(range => ({ range })));
+ }
+ }
+ else if (ts.isFunctionDeclaration(node)) {
+ if (node.name && ts.isIdentifier(node.name)) {
+ bindings.push({
+ range: _getStartEnd(node.name),
+ });
+ }
+ }
+ else if (ts.isClassDeclaration(node)) {
+ if (node.name) {
+ bindings.push({
+ range: _getStartEnd(node.name),
+ });
+ }
+ }
+ else if (ts.isEnumDeclaration(node)) {
+ bindings.push({
+ range: _getStartEnd(node.name),
+ });
+ }
+
+ if (ts.isImportDeclaration(node)) {
+ const moduleName = _getNodeText(node.moduleSpecifier).slice(1, -1);
+
+ if (node.importClause && !node.importClause.isTypeOnly) {
+ const { name, namedBindings } = node.importClause;
+
+ if (name) {
+ bindings.push({
+ range: _getStartEnd(name),
+ moduleName,
+ isDefaultImport: true,
+ });
+ }
+ if (namedBindings) {
+ if (ts.isNamedImports(namedBindings)) {
+ for (const element of namedBindings.elements) {
+ if (element.isTypeOnly) {
+ continue;
+ }
+ bindings.push({
+ range: _getStartEnd(element.name),
+ moduleName,
+ isDefaultImport: element.propertyName?.text === 'default',
+ });
+ }
+ }
+ else {
+ bindings.push({
+ range: _getStartEnd(namedBindings.name),
+ moduleName,
+ isNamespace: true,
+ });
+ }
+ }
+ }
+ }
+ });
+
+ return bindings;
+
+ function _getStartEnd(node: ts.Node) {
+ return getStartEnd(ts, node, ast);
+ }
+
+ function _getNodeText(node: ts.Node) {
+ return getNodeText(ts, node, ast);
+ }
+}
+
+export function getClosestMultiLineCommentRange(
+ ts: typeof import('typescript'),
+ node: ts.Node,
+ parents: ts.Node[],
+ ast: ts.SourceFile,
+) {
+ for (let i = parents.length - 1; i >= 0; i--) {
+ if (ts.isStatement(node)) {
+ break;
+ }
+ node = parents[i];
+ }
+ const comment = ts.getLeadingCommentRanges(ast.text, node.pos)
+ ?.reverse()
+ .find(range => range.kind === 3 satisfies ts.SyntaxKind.MultiLineCommentTrivia);
+
+ if (comment) {
+ return {
+ start: comment.pos,
+ end: comment.end,
+ };
+ }
+}
diff --git a/packages/language-core/lib/plugins/vue-tsx.ts b/packages/language-core/lib/plugins/vue-tsx.ts
index 731f06ce97..1a92f5e681 100644
--- a/packages/language-core/lib/plugins/vue-tsx.ts
+++ b/packages/language-core/lib/plugins/vue-tsx.ts
@@ -150,10 +150,10 @@ function createTsx(
const setupHasDefineSlots = computed(() => !!getScriptSetupRanges()?.defineSlots);
- const getSetupSlotsAssignName = computed(() => getScriptSetupRanges()?.defineSlots?.name);
-
const getSetupPropsAssignName = computed(() => getScriptSetupRanges()?.defineProps?.name);
+ const getSetupSlotsAssignName = computed(() => getScriptSetupRanges()?.defineSlots?.name);
+
const getSetupInheritAttrs = computed(() => {
const value = getScriptSetupRanges()?.defineOptions?.inheritAttrs
?? getScriptRanges()?.exportDefault?.inheritAttrsOption;
@@ -161,17 +161,25 @@ function createTsx(
});
const getComponentSelfName = computed(() => {
+ let name: string;
const { exportDefault } = getScriptRanges() ?? {};
if (sfc.script && exportDefault?.nameOption) {
- const { nameOption } = exportDefault;
- return sfc.script.content.slice(nameOption.start + 1, nameOption.end - 1);
+ name = sfc.script.content.slice(
+ exportDefault.nameOption.start + 1,
+ exportDefault.nameOption.end - 1,
+ );
}
- const { defineOptions } = getScriptSetupRanges() ?? {};
- if (sfc.scriptSetup && defineOptions?.name) {
- return defineOptions.name;
+ else {
+ const { defineOptions } = getScriptSetupRanges() ?? {};
+ if (sfc.scriptSetup && defineOptions?.name) {
+ name = defineOptions.name;
+ }
+ else {
+ const baseName = path.basename(fileName);
+ name = baseName.slice(0, baseName.lastIndexOf('.'));
+ }
}
- const baseName = path.basename(fileName);
- return capitalize(camelize(baseName.slice(0, baseName.lastIndexOf('.'))));
+ return capitalize(camelize(name));
});
const getGeneratedTemplate = computed(() => {
@@ -189,8 +197,8 @@ function createTsx(
destructuredPropNames: getSetupDestructuredPropNames(),
templateRefNames: getSetupTemplateRefNames(),
hasDefineSlots: setupHasDefineSlots(),
- slotsAssignName: getSetupSlotsAssignName(),
propsAssignName: getSetupPropsAssignName(),
+ slotsAssignName: getSetupSlotsAssignName(),
inheritAttrs: getSetupInheritAttrs(),
selfComponentName: getComponentSelfName(),
};
@@ -216,7 +224,7 @@ function createTsx(
ts,
compilerOptions: ctx.compilerOptions,
vueCompilerOptions: getResolvedOptions(),
- sfc: sfc,
+ sfc,
fileName,
lang: getLang(),
scriptRanges: getScriptRanges(),
diff --git a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap
index 666ef55420..3061be7155 100644
--- a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap
+++ b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap
@@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`vue-tsc-dts > Input: empty-component/component.vue, Output: empty-component/component.vue.d.ts 1`] = `
-"declare const _default: import("vue").DefineComponent2<{
+"declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -22,12 +22,13 @@ exports[`vue-tsc-dts > Input: empty-component/component.vue, Output: empty-compo
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
exports[`vue-tsc-dts > Input: empty-component/custom-extension-component.cext, Output: empty-component/custom-extension-component.cext.d.ts 1`] = `
-"declare const _default: import("vue").DefineComponent2<{
+"declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -48,23 +49,24 @@ exports[`vue-tsc-dts > Input: empty-component/custom-extension-component.cext, O
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
exports[`vue-tsc-dts > Input: generic/component.vue, Output: generic/component.vue.d.ts 1`] = `
-"declare const _default: (__VLS_props: NonNullable>["props"], __VLS_ctx?: __VLS_PrettifyLocal>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable>["expose"], __VLS_setup?: Promise<{
- props: __VLS_PrettifyLocal & Omit<{
- readonly "onUpdate:title"?: (value: string) => any;
- readonly onBar?: (data: number) => any;
- } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onUpdate:title" | "onBar"> & ({
+"declare const __VLS_export: (__VLS_props: NonNullable>["props"], __VLS_ctx?: __VLS_PrettifyLocal>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable>["expose"], __VLS_setup?: Promise<{
+ props: __VLS_PrettifyLocal<({
foo: number;
} & {
title?: string;
- }) & {}> & import("vue").PublicProps;
- expose(exposed: import("vue").ShallowUnwrapRef<{
+ }) & {
+ "onUpdate:title"?: (value: string) => any;
+ onBar?: (data: number) => any;
+ }> & import("vue").PublicProps;
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
baz: number;
- }>): void;
+ }>) => void;
attrs: any;
slots: {
default?: (props: {
@@ -75,6 +77,7 @@ exports[`vue-tsc-dts > Input: generic/component.vue, Output: generic/component.v
}>) => import("vue").VNode & {
__ctx?: Awaited;
};
+declare const _default: typeof __VLS_export;
export default _default;
type __VLS_PrettifyLocal = {
[K in keyof T as K]: T[K];
@@ -83,18 +86,18 @@ type __VLS_PrettifyLocal = {
`;
exports[`vue-tsc-dts > Input: generic/custom-extension-component.cext, Output: generic/custom-extension-component.cext.d.ts 1`] = `
-"declare const _default: (__VLS_props: NonNullable>["props"], __VLS_ctx?: __VLS_PrettifyLocal>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable>["expose"], __VLS_setup?: Promise<{
- props: __VLS_PrettifyLocal & Omit<{
- readonly "onUpdate:title"?: (value: string) => any;
- readonly onBar?: (data: number) => any;
- } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onUpdate:title" | "onBar"> & ({
+"declare const __VLS_export: (__VLS_props: NonNullable>["props"], __VLS_ctx?: __VLS_PrettifyLocal>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable>["expose"], __VLS_setup?: Promise<{
+ props: __VLS_PrettifyLocal<({
foo: number;
} & {
title?: string;
- }) & {}> & import("vue").PublicProps;
- expose(exposed: import("vue").ShallowUnwrapRef<{
+ }) & {
+ "onUpdate:title"?: (value: string) => any;
+ onBar?: (data: number) => any;
+ }> & import("vue").PublicProps;
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
baz: number;
- }>): void;
+ }>) => void;
attrs: any;
slots: {
default?: (props: {
@@ -105,6 +108,7 @@ exports[`vue-tsc-dts > Input: generic/custom-extension-component.cext, Output: g
}>) => import("vue").VNode & {
__ctx?: Awaited;
};
+declare const _default: typeof __VLS_export;
export default _default;
type __VLS_PrettifyLocal = {
[K in keyof T as K]: T[K];
@@ -113,7 +117,7 @@ type __VLS_PrettifyLocal = {
`;
exports[`vue-tsc-dts > Input: generic/main.vue, Output: generic/main.vue.d.ts 1`] = `
-"declare const _default: import("vue").DefineComponent2<{
+"declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -134,6 +138,7 @@ exports[`vue-tsc-dts > Input: generic/main.vue, Output: generic/main.vue.d.ts 1`
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
@@ -215,7 +220,7 @@ export default _default;
exports[`vue-tsc-dts > Input: reference-type-events/component.vue, Output: reference-type-events/component.vue.d.ts 1`] = `
"import type { MyEvents } from './my-events';
-declare const _default: import("vue").DefineComponent2<{
+declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -236,6 +241,7 @@ declare const _default: import("vue").DefineComponent2<{
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
@@ -260,7 +266,7 @@ export {};
`;
exports[`vue-tsc-dts > Input: reference-type-exposed/component.vue, Output: reference-type-exposed/component.vue.d.ts 1`] = `
-"declare const _default: import("vue").DefineComponent2<{
+"declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {
/**
* a counter string
@@ -286,12 +292,13 @@ exports[`vue-tsc-dts > Input: reference-type-exposed/component.vue, Output: refe
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
exports[`vue-tsc-dts > Input: reference-type-model/component.vue, Output: reference-type-model/component.vue.d.ts 1`] = `
-"type __VLS_PublicProps = {
+"type __VLS_ModelProps = {
/**
* required number modelValue
*/
@@ -311,7 +318,7 @@ type __VLS_ModelEmit = {
'update:foo': [value: boolean];
'update:bar': [value: string | undefined];
};
-declare const _default: import("vue").DefineComponent2<{
+declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -326,19 +333,20 @@ declare const _default: import("vue").DefineComponent2<{
directives: {};
provide: {};
expose: string;
- __typeProps: __VLS_PublicProps;
+ __typeProps: __VLS_ModelProps;
__typeEmits: __VLS_ModelEmit;
__typeRefs: {};
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
exports[`vue-tsc-dts > Input: reference-type-props/component.vue, Output: reference-type-props/component.vue.d.ts 1`] = `
"import { MyProps } from './my-props';
-declare const _default: import("vue").DefineComponent2<{
+declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -362,6 +370,7 @@ declare const _default: import("vue").DefineComponent2<{
baz: () => string[];
};
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
@@ -370,7 +379,7 @@ exports[`vue-tsc-dts > Input: reference-type-props/component-destructure.vue, Ou
"type __VLS_Props = {
text: string;
};
-declare const _default: import("vue").DefineComponent2<{
+declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -391,12 +400,13 @@ declare const _default: import("vue").DefineComponent2<{
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
exports[`vue-tsc-dts > Input: reference-type-props/component-js.vue, Output: reference-type-props/component-js.vue.d.ts 1`] = `
-"declare const _default: import("vue").DefineComponent2<{
+"declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {
@@ -440,12 +450,13 @@ exports[`vue-tsc-dts > Input: reference-type-props/component-js.vue, Output: ref
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
exports[`vue-tsc-dts > Input: reference-type-props/component-js-setup.vue, Output: reference-type-props/component-js-setup.vue.d.ts 1`] = `
-"declare const _default: import("vue").DefineComponent2<{
+"declare const __VLS_export: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {
@@ -506,6 +517,7 @@ exports[`vue-tsc-dts > Input: reference-type-props/component-js-setup.vue, Outpu
__typeEl: any;
__defaults: unknown;
}>;
+declare const _default: typeof __VLS_export;
export default _default;
"
`;
@@ -639,7 +651,7 @@ type __VLS_Slots = {} & {
} & {
vbind?: (props: typeof __VLS_7) => any;
};
-declare const __VLS_component: import("vue").DefineComponent2<{
+declare const __VLS_base: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -660,7 +672,8 @@ declare const __VLS_component: import("vue").DefineComponent2<{
__typeEl: any;
__defaults: unknown;
}>;
-declare const _default: __VLS_WithSlots;
+declare const __VLS_export: __VLS_WithSlots;
+declare const _default: typeof __VLS_export;
export default _default;
type __VLS_WithSlots = T & {
new (): {
@@ -685,7 +698,7 @@ type __VLS_Slots = {
}) => VNode[];
'no-bind': () => VNode[];
};
-declare const __VLS_component: import("vue").DefineComponent2<{
+declare const __VLS_base: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -706,7 +719,8 @@ declare const __VLS_component: import("vue").DefineComponent2<{
__typeEl: any;
__defaults: unknown;
}>;
-declare const _default: __VLS_WithSlots;
+declare const __VLS_export: __VLS_WithSlots;
+declare const _default: typeof __VLS_export;
export default _default;
type __VLS_WithSlots = T & {
new (): {
@@ -734,7 +748,7 @@ type __VLS_Slots = {} & {
} & {
vbind?: (props: typeof __VLS_7) => any;
};
-declare const __VLS_component: import("vue").DefineComponent2<{
+declare const __VLS_base: import("vue").DefineComponent2<{
setup(): {};
data(): {};
props: {};
@@ -755,7 +769,8 @@ declare const __VLS_component: import("vue").DefineComponent2<{
__typeEl: any;
__defaults: unknown;
}>;
-declare const _default: __VLS_WithSlots;
+declare const __VLS_export: __VLS_WithSlots;
+declare const _default: typeof __VLS_export;
export default _default;
type __VLS_WithSlots = T & {
new (): {
diff --git a/packages/tsc/tests/typecheck.spec.ts b/packages/tsc/tests/typecheck.spec.ts
index aea249b044..198591bac1 100644
--- a/packages/tsc/tests/typecheck.spec.ts
+++ b/packages/tsc/tests/typecheck.spec.ts
@@ -12,11 +12,12 @@ describe(`vue-tsc`, () => {
"test-workspace/tsc/failureFixtures/#3632/both.vue(7,1): error TS1109: Expression expected.",
"test-workspace/tsc/failureFixtures/#3632/script.vue(3,1): error TS1109: Expression expected.",
"test-workspace/tsc/failureFixtures/#3632/scriptSetup.vue(3,1): error TS1109: Expression expected.",
+ "test-workspace/tsc/failureFixtures/#4569/main.vue(1,41): error TS4025: Exported variable '__VLS_export' has or is using private name 'Props'.",
"test-workspace/tsc/failureFixtures/#5071/withScript.vue(1,19): error TS1005: ';' expected.",
"test-workspace/tsc/failureFixtures/#5071/withoutScript.vue(2,26): error TS1005: ';' expected.",
"test-workspace/tsc/failureFixtures/directives/main.vue(12,2): error TS2578: Unused '@ts-expect-error' directive.",
- "test-workspace/tsc/failureFixtures/directives/main.vue(4,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: {}; }, {}, {}, {}, {}, {}, {}, PublicProps, {}, true, {}, {}, GlobalComponents, GlobalDirectives, ... 12 more ..., {}>'.",
- "test-workspace/tsc/failureFixtures/directives/main.vue(9,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: {}; }, {}, {}, {}, {}, {}, {}, PublicProps, {}, true, {}, {}, GlobalComponents, GlobalDirectives, ... 12 more ..., {}>'.",
+ "test-workspace/tsc/failureFixtures/directives/main.vue(4,6): error TS2339: Property 'notExist' does not exist on type '{ exist: {}; $: ComponentInternalInstance; $data: {}; $props: {}; $attrs: Data; $refs: Data; $slots: Readonly; ... 8 more ...; $watch any)>(source: T, cb: T extends (...args: any) => infer R ? (args_0: R, args_1: R, args_2: OnCleanup) => any : (args_0: any, args_1...'.",
+ "test-workspace/tsc/failureFixtures/directives/main.vue(9,6): error TS2339: Property 'notExist' does not exist on type '{ exist: {}; $: ComponentInternalInstance; $data: {}; $props: {}; $attrs: Data; $refs: Data; $slots: Readonly; ... 8 more ...; $watch any)>(source: T, cb: T extends (...args: any) => infer R ? (args_0: R, args_1: R, args_2: OnCleanup) => any : (args_0: any, args_1...'.",
]
`);
});
diff --git a/packages/typescript-plugin/lib/requests/getComponentEvents.ts b/packages/typescript-plugin/lib/requests/getComponentEvents.ts
index ceea3992f7..70d13fcf0f 100644
--- a/packages/typescript-plugin/lib/requests/getComponentEvents.ts
+++ b/packages/typescript-plugin/lib/requests/getComponentEvents.ts
@@ -22,7 +22,7 @@ export function getComponentEvents(
return [];
}
- const componentType = getComponentType(ts, languageService, root, components, fileName, tag);
+ const componentType = getComponentType(ts, languageService, root, components, tag);
if (!componentType) {
return [];
}
diff --git a/packages/typescript-plugin/lib/requests/getComponentProps.ts b/packages/typescript-plugin/lib/requests/getComponentProps.ts
index e30130a259..6b30932f03 100644
--- a/packages/typescript-plugin/lib/requests/getComponentProps.ts
+++ b/packages/typescript-plugin/lib/requests/getComponentProps.ts
@@ -30,7 +30,7 @@ export function getComponentProps(
return [];
}
- const componentType = getComponentType(ts, languageService, root, components, fileName, tag);
+ const componentType = getComponentType(ts, languageService, root, components, tag);
if (!componentType) {
return [];
}
diff --git a/packages/typescript-plugin/lib/requests/utils.ts b/packages/typescript-plugin/lib/requests/utils.ts
index bdabe5a0c4..4a486182af 100644
--- a/packages/typescript-plugin/lib/requests/utils.ts
+++ b/packages/typescript-plugin/lib/requests/utils.ts
@@ -8,7 +8,6 @@ export function getComponentType(
languageService: ts.LanguageService,
vueCode: VueVirtualCode,
components: NonNullable>,
- fileName: string,
tag: string,
) {
const program = languageService.getProgram()!;
@@ -21,9 +20,9 @@ export function getComponentType(
let componentType: ts.Type | undefined;
if (!componentSymbol) {
- const name = getSelfComponentName(fileName);
+ const name = getSelfComponentName(vueCode.fileName);
if (name === capitalize(camelize(tag))) {
- componentType = getVariableType(ts, languageService, vueCode, '__VLS_self')?.type;
+ componentType = getVariableType(ts, languageService, vueCode, '__VLS_export')?.type;
}
}
else {
diff --git a/test-workspace/tsc/passedFixtures/vue3/components/main.vue b/test-workspace/tsc/passedFixtures/vue3/components/main.vue
index 2dc0ba4dea..9da3e4898b 100644
--- a/test-workspace/tsc/passedFixtures/vue3/components/main.vue
+++ b/test-workspace/tsc/passedFixtures/vue3/components/main.vue
@@ -57,7 +57,7 @@ declare const ScriptSetupGenericExact: (
_expose?: NonNullable>['expose'],
_setup?: Promise<{
props: {
- readonly onBar?: ((data: T) => any) | undefined;
+ onBar?: ((data: T) => any) | undefined;
foo: T;
} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps,
attrs: any,
diff --git a/test-workspace/tsc/passedFixtures/vue3/withDefaults/main.vue b/test-workspace/tsc/passedFixtures/vue3/withDefaults/main.vue
index a46cf5f520..9cf95ec07e 100644
--- a/test-workspace/tsc/passedFixtures/vue3/withDefaults/main.vue
+++ b/test-workspace/tsc/passedFixtures/vue3/withDefaults/main.vue
@@ -13,6 +13,6 @@ withDefaults(defineProps(), {
{{ exactType(actionText, {} as string) }}
- {{ exactType($props.actionText, {} as string | undefined) }}
+ {{ exactType($props.actionText, {} as string) }}