diff --git a/packages/vue-language-core/src/generators/script.ts b/packages/vue-language-core/src/generators/script.ts index 9604d998aa..823550bc5e 100644 --- a/packages/vue-language-core/src/generators/script.ts +++ b/packages/vue-language-core/src/generators/script.ts @@ -10,6 +10,7 @@ import type { ScriptSetupRanges } from '../parsers/scriptSetupRanges'; import type { TextRange, VueCompilerOptions } from '../types'; import { Sfc } from '../types'; import * as sharedTypes from '../utils/globalTypes'; +import { geneateGlobalTypes } from '../utils/globalTypes'; import { getSlotsPropertyName, hyphenateTag } from '../utils/shared'; import { walkInterpolationFragment } from '../utils/transform'; @@ -24,6 +25,7 @@ export function generate( compilerOptions: ts.CompilerOptions, vueCompilerOptions: VueCompilerOptions, codegenStack: boolean, + withGlobalTypes: boolean, ) { const [codes, codeStacks] = codegenStack ? muggle.track([] as Segment[]) : [[], []]; @@ -108,6 +110,11 @@ export function generate( }; function generateHelperTypes() { + // global types + if (withGlobalTypes) { + codes.push(geneateGlobalTypes(vueCompilerOptions)); + } + // local types let usedPrettify = false; if (usedHelperTypes.DefinePropsToOptions) { if (compilerOptions.exactOptionalPropertyTypes) { @@ -132,10 +139,10 @@ export function generate( codes.push('type __VLS_UnionToIntersection = __VLS_Prettify<(U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never>;\n'); usedPrettify = true; if (scriptSetupRanges && scriptSetupRanges.emitsTypeNums !== -1) { - codes.push(sharedTypes.genConstructorOverloads('__VLS_ConstructorOverloads', scriptSetupRanges.emitsTypeNums)); + codes.push(sharedTypes.generateConstructorOverloads('__VLS_ConstructorOverloads', scriptSetupRanges.emitsTypeNums)); } else { - codes.push(sharedTypes.genConstructorOverloads('__VLS_ConstructorOverloads')); + codes.push(sharedTypes.generateConstructorOverloads('__VLS_ConstructorOverloads')); } codes.push(`type __VLS_NormalizeEmits = __VLS_ConstructorOverloads & { [K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never diff --git a/packages/vue-language-core/src/languageModule.ts b/packages/vue-language-core/src/languageModule.ts index be17351bef..ce4a2221c1 100644 --- a/packages/vue-language-core/src/languageModule.ts +++ b/packages/vue-language-core/src/languageModule.ts @@ -1,9 +1,7 @@ import type { Language } from '@volar/language-core'; -import { posix as path } from 'path'; import { getDefaultVueLanguagePlugins } from './plugins'; import { VueFile } from './sourceFile'; import { VueCompilerOptions, VueLanguagePlugin } from './types'; -import * as sharedTypes from './utils/globalTypes'; import type * as ts from 'typescript/lib/tsserverlibrary'; import { resolveVueCompilerOptions } from './utils/ts'; @@ -33,12 +31,16 @@ function getVueFileRegistry(key: string, plugins: VueLanguagePlugin[]) { return fileRegistry; } +export type VueLanguage = ReturnType; + export function createVueLanguage( ts: typeof import('typescript/lib/tsserverlibrary'), compilerOptions: ts.CompilerOptions = {}, _vueCompilerOptions: Partial = {}, codegenStack: boolean = false, -): Language { +): Language & { + getGlobalTypesFile(): VueFile | undefined; +} { const vueCompilerOptions = resolveVueCompilerOptions(_vueCompilerOptions); const plugins = getDefaultVueLanguagePlugins( @@ -57,7 +59,6 @@ export function createVueLanguage( .map(key => [key, compilerOptions[key as keyof ts.CompilerOptions]]), ]; const fileRegistry = getVueFileRegistry(JSON.stringify(keys), _vueCompilerOptions.plugins ?? []); - const allowLanguageIds = new Set(['vue']); if (vueCompilerOptions.extensions.includes('.md')) { @@ -67,7 +68,12 @@ export function createVueLanguage( allowLanguageIds.add('html'); } + let globalTypesFile: VueFile | undefined; + return { + getGlobalTypesFile() { + return globalTypesFile; + }, createVirtualFile(fileName, snapshot, languageId) { if ( (languageId && allowLanguageIds.has(languageId)) @@ -78,8 +84,12 @@ export function createVueLanguage( reusedVueFile.update(snapshot); return reusedVueFile; } - const vueFile = new VueFile(fileName, snapshot, vueCompilerOptions, plugins, ts, codegenStack); + + const vueFile = new VueFile(fileName, snapshot, vueCompilerOptions, plugins, ts, codegenStack, !globalTypesFile); fileRegistry.set(fileName, vueFile); + + globalTypesFile ??= vueFile; + return vueFile; } }, @@ -87,8 +97,6 @@ export function createVueLanguage( sourceFile.update(snapshot); }, resolveHost(host) { - const sharedTypesSnapshot = ts.ScriptSnapshot.fromString(sharedTypes.getTypesCode(vueCompilerOptions)); - const sharedTypesFileName = path.join(host.rootPath, sharedTypes.baseName); return { ...host, resolveModuleName(moduleName, impliedNodeFormat) { @@ -97,18 +105,6 @@ export function createVueLanguage( } return host.resolveModuleName?.(moduleName, impliedNodeFormat) ?? moduleName; }, - getScriptFileNames() { - return [ - sharedTypesFileName, - ...host.getScriptFileNames(), - ]; - }, - getScriptSnapshot(fileName) { - if (fileName === sharedTypesFileName) { - return sharedTypesSnapshot; - } - return host.getScriptSnapshot(fileName); - }, }; }, }; diff --git a/packages/vue-language-core/src/plugins/vue-tsx.ts b/packages/vue-language-core/src/plugins/vue-tsx.ts index 3f791abdb3..05acd7c122 100644 --- a/packages/vue-language-core/src/plugins/vue-tsx.ts +++ b/packages/vue-language-core/src/plugins/vue-tsx.ts @@ -23,9 +23,9 @@ const plugin: VueLanguagePlugin = (ctx) => { 'exactOptionalPropertyTypes', ], - getEmbeddedFileNames(fileName, sfc) { + getEmbeddedFileNames(fileName, sfc, vueFile) { - const tsx = useTsx(fileName, sfc); + const tsx = useTsx(fileName, sfc, vueFile.withGlobalTypes); const fileNames: string[] = []; if (['js', 'ts', 'jsx', 'tsx'].includes(tsx.lang.value)) { @@ -40,9 +40,9 @@ const plugin: VueLanguagePlugin = (ctx) => { return fileNames; }, - resolveEmbeddedFile(fileName, sfc, embeddedFile) { + resolveEmbeddedFile(fileName, sfc, embeddedFile, vueFile) { - const _tsx = useTsx(fileName, sfc); + const _tsx = useTsx(fileName, sfc, vueFile.withGlobalTypes); const suffix = embeddedFile.fileName.replace(fileName, ''); if (suffix === '.' + _tsx.lang.value) { @@ -109,9 +109,9 @@ const plugin: VueLanguagePlugin = (ctx) => { }, }; - function useTsx(fileName: string, sfc: Sfc) { + function useTsx(fileName: string, sfc: Sfc, withGlobalTypes: boolean) { if (!tsCodegen.has(sfc)) { - tsCodegen.set(sfc, createTsx(fileName, sfc, ctx)); + tsCodegen.set(sfc, createTsx(fileName, sfc, ctx, withGlobalTypes)); } return tsCodegen.get(sfc)!; } @@ -119,7 +119,12 @@ const plugin: VueLanguagePlugin = (ctx) => { export default plugin; -function createTsx(fileName: string, _sfc: Sfc, { vueCompilerOptions, compilerOptions, codegenStack, modules }: Parameters[0]) { +function createTsx( + fileName: string, + _sfc: Sfc, + { vueCompilerOptions, compilerOptions, codegenStack, modules }: Parameters[0], + withGlobalTypes: boolean +) { const ts = modules.typescript; const lang = computed(() => { @@ -168,6 +173,7 @@ function createTsx(fileName: string, _sfc: Sfc, { vueCompilerOptions, compilerOp compilerOptions, vueCompilerOptions, codegenStack, + withGlobalTypes, ); }); diff --git a/packages/vue-language-core/src/sourceFile.ts b/packages/vue-language-core/src/sourceFile.ts index 779b5a6f01..92bf6ad6f0 100644 --- a/packages/vue-language-core/src/sourceFile.ts +++ b/packages/vue-language-core/src/sourceFile.ts @@ -201,7 +201,7 @@ export class VueFile implements VirtualFile { const files = computed(() => { try { if (plugin.getEmbeddedFileNames) { - const embeddedFileNames = plugin.getEmbeddedFileNames(this.fileName, this.sfc); + const embeddedFileNames = plugin.getEmbeddedFileNames(this.fileName, this.sfc, this); for (const oldFileName of Object.keys(embeddedFiles)) { if (!embeddedFileNames.includes(oldFileName)) { delete embeddedFiles[oldFileName]; @@ -215,7 +215,7 @@ export class VueFile implements VirtualFile { for (const plugin of this.plugins) { if (plugin.resolveEmbeddedFile) { try { - plugin.resolveEmbeddedFile(this.fileName, this.sfc, file); + plugin.resolveEmbeddedFile(this.fileName, this.sfc, file, this); } catch (e) { console.error(e); @@ -394,6 +394,7 @@ export class VueFile implements VirtualFile { public plugins: ReturnType[], public ts: typeof import('typescript/lib/tsserverlibrary'), public codegenStack: boolean, + public withGlobalTypes: boolean, ) { this.onUpdate(); } diff --git a/packages/vue-language-core/src/types.ts b/packages/vue-language-core/src/types.ts index 23b58c49e3..55f618d180 100644 --- a/packages/vue-language-core/src/types.ts +++ b/packages/vue-language-core/src/types.ts @@ -1,7 +1,7 @@ import type * as CompilerDOM from '@vue/compiler-dom'; import type { SFCParseResult } from '@vue/compiler-sfc'; import type * as ts from 'typescript/lib/tsserverlibrary'; -import type { VueEmbeddedFile } from './sourceFile'; +import { VueEmbeddedFile, VueFile } from './sourceFile'; export type { SFCParseResult } from '@vue/compiler-sfc'; @@ -59,8 +59,8 @@ export type VueLanguagePlugin = (ctx: { resolveTemplateCompilerOptions?(options: CompilerDOM.CompilerOptions): CompilerDOM.CompilerOptions; compileSFCTemplate?(lang: string, template: string, options: CompilerDOM.CompilerOptions): CompilerDOM.CodegenResult | undefined; updateSFCTemplate?(oldResult: CompilerDOM.CodegenResult, textChange: { start: number, end: number, newText: string; }): CompilerDOM.CodegenResult | undefined; - getEmbeddedFileNames?(fileName: string, sfc: Sfc): string[]; - resolveEmbeddedFile?(fileName: string, sfc: Sfc, embeddedFile: VueEmbeddedFile): void; + getEmbeddedFileNames?(fileName: string, sfc: Sfc, vueFile: VueFile): string[]; + resolveEmbeddedFile?(fileName: string, sfc: Sfc, embeddedFile: VueEmbeddedFile, vueFile: VueFile): void; }; export interface SfcBlock { diff --git a/packages/vue-language-core/src/utils/globalTypes.ts b/packages/vue-language-core/src/utils/globalTypes.ts index 1dd59eeae9..5e94ea57f9 100644 --- a/packages/vue-language-core/src/utils/globalTypes.ts +++ b/packages/vue-language-core/src/utils/globalTypes.ts @@ -1,127 +1,125 @@ import { VueCompilerOptions } from '../types'; import { getSlotsPropertyName } from './shared'; -export const baseName = '__VLS_types.d.ts'; - -export function getTypesCode(vueCompilerOptions: VueCompilerOptions) { +export function geneateGlobalTypes(vueCompilerOptions: VueCompilerOptions) { return ` -// @ts-nocheck - -type __VLS_IntrinsicElements = __VLS_PickNotAny>>; -type __VLS_Element = __VLS_PickNotAny; +declare global { + type __VLS_IntrinsicElements = __VLS_PickNotAny>>; + type __VLS_Element = __VLS_PickNotAny; -type __VLS_IsAny = 0 extends 1 & T ? true : false; -type __VLS_PickNotAny = __VLS_IsAny extends true ? B : A; + type __VLS_IsAny = 0 extends 1 & T ? true : false; + type __VLS_PickNotAny = __VLS_IsAny extends true ? B : A; -type __VLS_Prettify = { - [K in keyof T]: T[K]; -} & {}; + type __VLS_Prettify = { + [K in keyof T]: T[K]; + } & {}; -type __VLS_GlobalComponents = - __VLS_PickNotAny - & __VLS_PickNotAny - & __VLS_PickNotAny - & Pick; + type __VLS_GlobalComponents = + __VLS_PickNotAny + & __VLS_PickNotAny + & __VLS_PickNotAny + & Pick; -// v-for -declare function __VLS_getVForSourceType(source: number): [number, number, number][]; -declare function __VLS_getVForSourceType(source: string): [string, number, number][]; -declare function __VLS_getVForSourceType(source: T): [ - T[number], // item - number, // key - number, // index -][]; -declare function __VLS_getVForSourceType }>(source: T): [ - T extends { [Symbol.iterator](): Iterator } ? T1 : never, // item - number, // key - undefined, // index -][]; -declare function __VLS_getVForSourceType(source: T): [ - T[keyof T], // item - keyof T, // key - number, // index -][]; + // v-for + function __VLS_getVForSourceType(source: number): [number, number, number][]; + function __VLS_getVForSourceType(source: string): [string, number, number][]; + function __VLS_getVForSourceType(source: T): [ + T[number], // item + number, // key + number, // index + ][]; + function __VLS_getVForSourceType }>(source: T): [ + T extends { [Symbol.iterator](): Iterator } ? T1 : never, // item + number, // key + undefined, // index + ][]; + function __VLS_getVForSourceType(source: T): [ + T[keyof T], // item + keyof T, // key + number, // index + ][]; -declare function __VLS_getSlotParams(slot: T): Parameters<__VLS_PickNotAny, (...args: any[]) => any>>; -declare function __VLS_getSlotParam(slot: T): Parameters<__VLS_PickNotAny, (...args: any[]) => any>>[0]; -declare function __VLS_directiveFunction(dir: T): - T extends import('${vueCompilerOptions.lib}').ObjectDirective | import('${vueCompilerOptions.lib}').FunctionDirective ? (value: V) => void - : T; -declare function __VLS_withScope(ctx: T, scope: K): ctx is T & K; -declare function __VLS_makeOptional(t: T): { [K in keyof T]?: T[K] }; + function __VLS_getSlotParams(slot: T): Parameters<__VLS_PickNotAny, (...args: any[]) => any>>; + function __VLS_getSlotParam(slot: T): Parameters<__VLS_PickNotAny, (...args: any[]) => any>>[0]; + function __VLS_directiveFunction(dir: T): + T extends import('${vueCompilerOptions.lib}').ObjectDirective | import('${vueCompilerOptions.lib}').FunctionDirective ? (value: V) => void + : T; + function __VLS_withScope(ctx: T, scope: K): ctx is T & K; + function __VLS_makeOptional(t: T): { [K in keyof T]?: T[K] }; -type __VLS_SelfComponent = string extends N ? {} : N extends string ? { [P in N]: C } : {}; -type __VLS_WithComponent = - N1 extends keyof LocalComponents ? N1 extends N0 ? Pick : { [K in N0]: LocalComponents[N1] } : - N2 extends keyof LocalComponents ? N2 extends N0 ? Pick : { [K in N0]: LocalComponents[N2] } : - N3 extends keyof LocalComponents ? N3 extends N0 ? Pick : { [K in N0]: LocalComponents[N3] } : - N1 extends keyof __VLS_GlobalComponents ? N1 extends N0 ? Pick<__VLS_GlobalComponents, N0> : { [K in N0]: __VLS_GlobalComponents[N1] } : - N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0> : { [K in N0]: __VLS_GlobalComponents[N2] } : - N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0> : { [K in N0]: __VLS_GlobalComponents[N3] } : - ${vueCompilerOptions.strictTemplates ? '{}' : '{ [K in N0]: unknown }'} + type __VLS_SelfComponent = string extends N ? {} : N extends string ? { [P in N]: C } : {}; + type __VLS_WithComponent = + N1 extends keyof LocalComponents ? N1 extends N0 ? Pick : { [K in N0]: LocalComponents[N1] } : + N2 extends keyof LocalComponents ? N2 extends N0 ? Pick : { [K in N0]: LocalComponents[N2] } : + N3 extends keyof LocalComponents ? N3 extends N0 ? Pick : { [K in N0]: LocalComponents[N3] } : + N1 extends keyof __VLS_GlobalComponents ? N1 extends N0 ? Pick<__VLS_GlobalComponents, N0> : { [K in N0]: __VLS_GlobalComponents[N1] } : + N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0> : { [K in N0]: __VLS_GlobalComponents[N2] } : + N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0> : { [K in N0]: __VLS_GlobalComponents[N3] } : + ${vueCompilerOptions.strictTemplates ? '{}' : '{ [K in N0]: unknown }'} -type __VLS_FillingEventArg_ParametersLength any> = __VLS_IsAny> extends true ? -1 : Parameters['length']; -type __VLS_FillingEventArg = E extends (...args: any) => any ? __VLS_FillingEventArg_ParametersLength extends 0 ? ($event?: undefined) => ReturnType : E : E; -type __VLS_EmitEvent = - F extends { - (event: E, ...payload: infer P): any - } ? (...payload: P) => void - : F extends { - (event: E, ...payload: infer P): any - (...args: any): any - } ? (...payload: P) => void - : F extends { - (event: E, ...payload: infer P): any - (...args: any): any - (...args: any): any - } ? (...payload: P) => void - : F extends { - (event: E, ...payload: infer P): any - (...args: any): any - (...args: any): any - (...args: any): any - } ? (...payload: P) => void - : unknown | '[Type Warning] Volar could not infer $emit event more than 4 overloads without DefineComponent. see https://github.com/vuejs/language-tools/issues/60'; -declare function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): - T extends new (...args: any) => any - ? (props: (K extends { $props: infer Props } ? Props : any)${vueCompilerOptions.strictTemplates ? '' : ' & Record'}, ctx?: { - attrs?: any, - slots?: K extends { ${getSlotsPropertyName(vueCompilerOptions.target)}: infer Slots } ? Slots : any, - emit?: K extends { $emit: infer Emit } ? Emit : any - }) => JSX.Element & { __ctx?: typeof ctx & { props?: typeof props; expose?(exposed: K): void; } } - : T extends () => any ? (props: {}, ctx?: any) => ReturnType - : T extends (...args: any) => any ? T - : (_: T extends import('${vueCompilerOptions.lib}').VNode | import('${vueCompilerOptions.lib}').VNode[] | string ? {}: T${vueCompilerOptions.strictTemplates ? '' : ' & Record'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: T${vueCompilerOptions.strictTemplates ? '' : ' & Record'} } }; // IntrinsicElement -declare function __VLS_functionalComponentArgsRest any>(t: T): Parameters['length'] extends 2 ? [any] : []; -declare function __VLS_pickEvent(emit: Emit, emitKey: K, event: E): __VLS_FillingEventArg< - __VLS_PickNotAny< - __VLS_AsFunctionOrAny, - __VLS_AsFunctionOrAny<__VLS_EmitEvent> - > -> | undefined; -declare function __VLS_pickFunctionalComponentCtx(comp: T, compInstance: K): __VLS_PickNotAny< - K extends { __ctx?: infer Ctx } ? Ctx : any, - T extends (props: any, ctx: infer Ctx) => any ? Ctx : any ->; -type __VLS_AsFunctionOrAny = unknown extends F ? any : ((...args: any) => any) extends F ? F : any; + type __VLS_FillingEventArg_ParametersLength any> = __VLS_IsAny> extends true ? -1 : Parameters['length']; + type __VLS_FillingEventArg = E extends (...args: any) => any ? __VLS_FillingEventArg_ParametersLength extends 0 ? ($event?: undefined) => ReturnType : E : E; + type __VLS_EmitEvent = + F extends { + (event: E, ...payload: infer P): any + } ? (...payload: P) => void + : F extends { + (event: E, ...payload: infer P): any + (...args: any): any + } ? (...payload: P) => void + : F extends { + (event: E, ...payload: infer P): any + (...args: any): any + (...args: any): any + } ? (...payload: P) => void + : F extends { + (event: E, ...payload: infer P): any + (...args: any): any + (...args: any): any + (...args: any): any + } ? (...payload: P) => void + : unknown | '[Type Warning] Volar could not infer $emit event more than 4 overloads without DefineComponent. see https://github.com/vuejs/language-tools/issues/60'; + function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): + T extends new (...args: any) => any + ? (props: (K extends { $props: infer Props } ? Props : any)${vueCompilerOptions.strictTemplates ? '' : ' & Record'}, ctx?: { + attrs?: any, + slots?: K extends { ${getSlotsPropertyName(vueCompilerOptions.target)}: infer Slots } ? Slots : any, + emit?: K extends { $emit: infer Emit } ? Emit : any + }) => JSX.Element & { __ctx?: typeof ctx & { props?: typeof props; expose?(exposed: K): void; } } + : T extends () => any ? (props: {}, ctx?: any) => ReturnType + : T extends (...args: any) => any ? T + : (_: T extends import('${vueCompilerOptions.lib}').VNode | import('${vueCompilerOptions.lib}').VNode[] | string ? {}: T${vueCompilerOptions.strictTemplates ? '' : ' & Record'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: T${vueCompilerOptions.strictTemplates ? '' : ' & Record'} } }; // IntrinsicElement + function __VLS_functionalComponentArgsRest any>(t: T): Parameters['length'] extends 2 ? [any] : []; + function __VLS_pickEvent(emit: Emit, emitKey: K, event: E): __VLS_FillingEventArg< + __VLS_PickNotAny< + __VLS_AsFunctionOrAny, + __VLS_AsFunctionOrAny<__VLS_EmitEvent> + > + > | undefined; + function __VLS_pickFunctionalComponentCtx(comp: T, compInstance: K): __VLS_PickNotAny< + K extends { __ctx?: infer Ctx } ? Ctx : any, + T extends (props: any, ctx: infer Ctx) => any ? Ctx : any + >; + type __VLS_AsFunctionOrAny = unknown extends F ? any : ((...args: any) => any) extends F ? F : any; -declare function __VLS_normalizeSlot(s: S): S extends () => infer R ? (props: {}) => R : S; -declare function __VLS_componentProps(comp: T, fnReturn: K): - __VLS_PickNotAny extends { __ctx: { props: infer P } } ? NonNullable

- : T extends (props: infer P, ...args: any) => any ? NonNullable

: - {}; + function __VLS_normalizeSlot(s: S): S extends () => infer R ? (props: {}) => R : S; + function __VLS_componentProps(comp: T, fnReturn: K): + __VLS_PickNotAny extends { __ctx: { props: infer P } } ? NonNullable

+ : T extends (props: infer P, ...args: any) => any ? NonNullable

: + {}; +} `.trim(); } // TODO: not working for overloads > n (n = 8) // see: https://github.com/vuejs/language-tools/issues/60 -export function genConstructorOverloads(name = 'ConstructorOverloads', nums?: number) { +export function generateConstructorOverloads(name = 'ConstructorOverloads', nums?: number) { let code = ''; code += `type ${name} =\n`; if (nums === undefined) { diff --git a/packages/vue-language-service/src/helpers.ts b/packages/vue-language-service/src/helpers.ts index 21909849de..d2623a3e53 100644 --- a/packages/vue-language-service/src/helpers.ts +++ b/packages/vue-language-service/src/helpers.ts @@ -2,7 +2,6 @@ import * as vue from '@vue/language-core'; import type { CompilerDOM } from '@vue/language-core'; import * as embedded from '@volar/language-core'; import { computed, ComputedRef } from '@vue/reactivity'; -import { sharedTypes } from '@vue/language-core'; import { camelize, capitalize } from '@vue/shared'; import type * as ts from 'typescript/lib/tsserverlibrary'; @@ -175,15 +174,18 @@ export function getComponentNames( export function getElementAttrs( ts: typeof import('typescript/lib/tsserverlibrary'), tsLs: ts.LanguageService, - tsLsHost: ts.LanguageServiceHost, + vueLanguage: vue.VueLanguage, tagName: string, ) { - const sharedTypesFileName = tsLsHost.getCurrentDirectory() + '/' + sharedTypes.baseName; + const globalTypesFile = vueLanguage.getGlobalTypesFile(); + if (!globalTypesFile) { + return []; + } let tsSourceFile: ts.SourceFile | undefined; - if (tsSourceFile = tsLs.getProgram()?.getSourceFile(sharedTypesFileName)) { + if (tsSourceFile = tsLs.getProgram()?.getSourceFile(globalTypesFile.mainScriptName)) { const typeNode = tsSourceFile.statements.find((node): node is ts.TypeAliasDeclaration => ts.isTypeAliasDeclaration(node) && node.name.getText() === '__VLS_IntrinsicElements'); const checker = tsLs.getProgram()?.getTypeChecker(); diff --git a/packages/vue-language-service/src/languageService.ts b/packages/vue-language-service/src/languageService.ts index 20fdc4eef7..64e710480a 100644 --- a/packages/vue-language-service/src/languageService.ts +++ b/packages/vue-language-service/src/languageService.ts @@ -1,5 +1,5 @@ import { Config, Service, ServiceContext } from '@volar/language-service'; -import { VueFile, createLanguages, hyphenateTag, resolveVueCompilerOptions, scriptRanges } from '@vue/language-core'; +import { VueFile, VueLanguage, createLanguages, hyphenateTag, resolveVueCompilerOptions, scriptRanges } from '@vue/language-core'; import { capitalize } from '@vue/shared'; import type * as ts from 'typescript/lib/tsserverlibrary'; import type { Data } from 'volar-service-typescript/out/features/completions/basic'; @@ -47,7 +47,7 @@ export function resolveConfig( const vueLanguageModules = createLanguages(compilerOptions, resolvedVueCompilerOptions, ts, codegenStack); config.languages = Object.assign({}, vueLanguageModules, config.languages); - config.services = resolvePlugins(config.services, resolvedVueCompilerOptions); + config.services = resolvePlugins(config.services, resolvedVueCompilerOptions, vueLanguageModules[0] as VueLanguage); return config; } @@ -55,6 +55,7 @@ export function resolveConfig( function resolvePlugins( services: Config['services'], vueCompilerOptions: VueCompilerOptions, + vueLanguage: VueLanguage, ) { const originalTsPlugin: Service = services?.typescript ?? TsService.create(); @@ -239,6 +240,7 @@ function resolvePlugins( }, isSupportedDocument: (document) => document.languageId === 'html', vueCompilerOptions, + vueLanguage, }); services.pug ??= VueTemplateLanguageService.create({ baseService: PugService.create(), @@ -253,6 +255,7 @@ function resolvePlugins( }, isSupportedDocument: (document) => document.languageId === 'jade', vueCompilerOptions, + vueLanguage, }); services.vue ??= VueService.create(); services.css ??= CssService.create(); diff --git a/packages/vue-language-service/src/plugins/vue-template.ts b/packages/vue-language-service/src/plugins/vue-template.ts index 17a098b1aa..13e0da368f 100644 --- a/packages/vue-language-service/src/plugins/vue-template.ts +++ b/packages/vue-language-service/src/plugins/vue-template.ts @@ -1,5 +1,5 @@ import { FileRangeCapabilities, Service, ServiceContext, SourceMapWithDocuments } from '@volar/language-service'; -import { VueFile, hyphenateAttr, hyphenateTag, parseScriptSetupRanges, tsCodegen } from '@vue/language-core'; +import { VueFile, VueLanguage, hyphenateAttr, hyphenateTag, parseScriptSetupRanges, tsCodegen } from '@vue/language-core'; import { camelize, capitalize } from '@vue/shared'; import * as html from 'vscode-html-languageservice'; import type * as vscode from 'vscode-languageserver-protocol'; @@ -18,6 +18,7 @@ export const create = (options: { baseService: S, isSupportedDocument: (document: TextDocument) => boolean, vueCompilerOptions: VueCompilerOptions, + vueLanguage: VueLanguage, }): Service => (_context: ServiceContext | undefined, modules): ReturnType => { const htmlOrPugService = options.baseService(_context, modules) as ReturnType; @@ -340,7 +341,6 @@ export const create = (options: { async function provideHtmlData(map: SourceMapWithDocuments, vueSourceFile: VueFile) { const languageService = _context!.inject('typescript/languageService'); - const languageServiceHost = _context!.inject('typescript/languageServiceHost'); const casing = await getNameCasing(ts, _context!, map.sourceFileDocument.uri, options.vueCompilerOptions); if (builtInData.tags) { @@ -409,7 +409,7 @@ export const create = (options: { }, provideAttributes: (tag) => { - const attrs = getElementAttrs(ts, languageService, languageServiceHost, tag); + const attrs = getElementAttrs(ts, languageService, options.vueLanguage, tag); const props = new Set(getPropsByTag(ts, languageService, vueSourceFile, tag, options.vueCompilerOptions)); const events = getEventsOfTag(ts, languageService, vueSourceFile, tag, options.vueCompilerOptions); const attributes: html.IAttributeData[] = []; diff --git a/packages/vue-tsc/bin/vue-tsc.js b/packages/vue-tsc/bin/vue-tsc.js index 6b7193cf43..39f1cbebb6 100755 --- a/packages/vue-tsc/bin/vue-tsc.js +++ b/packages/vue-tsc/bin/vue-tsc.js @@ -24,7 +24,6 @@ fs.readFileSync = (...args) => { tryReplace( `for (const existingRoot of buildInfoVersionMap.roots) {`, `for (const existingRoot of buildInfoVersionMap.roots - .filter(file => !file.toLowerCase().includes('__vls_')) .map(file => file.replace(/\.vue\.(j|t)sx?$/i, '.vue')) ) {` ); @@ -37,7 +36,6 @@ fs.readFileSync = (...args) => { tryReplace( `return createBuilderProgramUsingProgramBuildInfo(buildInfo, buildInfoPath, host);`, s => `buildInfo.program.fileNames = buildInfo.program.fileNames - .filter(file => !file.toLowerCase().includes('__vls_')) .map(file => file.replace(/\.vue\.(j|t)sx?$/i, '.vue'));\n` + s ); }