Skip to content

Commit

Permalink
refactor(language-core): generate global types for the first parsed V…
Browse files Browse the repository at this point in the history
…ue component
  • Loading branch information
johnsoncodehk committed Sep 4, 2024
1 parent e3f8b91 commit b14b8a9
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 151 deletions.
2 changes: 1 addition & 1 deletion packages/component-meta/lib/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export function baseCreate(
const fileExists = languageServiceHost.fileExists.bind(languageServiceHost);
const getScriptSnapshot = languageServiceHost.getScriptSnapshot.bind(languageServiceHost);
const globalTypesName = `${commandLine.vueOptions.lib}_${commandLine.vueOptions.target}_${commandLine.vueOptions.strictTemplates}.d.ts`;
const globalTypesContents = vue.generateGlobalTypes('global', commandLine.vueOptions.lib, commandLine.vueOptions.target, commandLine.vueOptions.strictTemplates);
const globalTypesContents = `// @ts-nocheck\nexport {};\n` + vue.generateGlobalTypes(commandLine.vueOptions.lib, commandLine.vueOptions.target, commandLine.vueOptions.strictTemplates);
const globalTypesSnapshot: ts.IScriptSnapshot = {
getText: (start, end) => globalTypesContents.substring(start, end),
getLength: () => globalTypesContents.length,
Expand Down
254 changes: 116 additions & 138 deletions packages/language-core/lib/codegen/globalTypes.ts
Original file line number Diff line number Diff line change
@@ -1,156 +1,134 @@
import { getSlotsPropertyName } from '../utils/shared';
import { endOfLine, newLine } from './common';

export function generateGlobalTypes(mode: 'global' | 'local', lib: string, target: number, strictTemplates: boolean) {
export function generateGlobalTypes(lib: string, target: number, strictTemplates: boolean) {
const fnPropsType = `(K extends { $props: infer Props } ? Props : any)${strictTemplates ? '' : ' & Record<string, unknown>'}`;
return `
; declare module '${lib}' {
export interface GlobalComponents { }
}
declare global {
const __VLS_intrinsicElements: __VLS_IntrinsicElements;
const __VLS_directiveBindingRestFields: { instance: null, oldValue: null, modifiers: any, dir: any };
const __VLS_unref: typeof import('${lib}').unref;
let decl = '';
let str = '';
let globalComponentsType: string;
const __VLS_nativeElements = {
...{} as SVGElementTagNameMap,
...{} as HTMLElementTagNameMap,
};
if (mode === 'global') {
str += `// @ts-nocheck${newLine}`;
str += `export {}${endOfLine}`;
str += `declare module '${lib}' {${newLine}`;
str += ` export interface GlobalComponents { }${newLine}`;
str += `}${newLine}`;
str += `declare global {${newLine}`;
globalComponentsType = `import('${lib}').GlobalComponents`;
}
else {
decl = 'declare ';
str += `// @ts-ignore${newLine}`;
str += `const __VLS_globalComponents = { ...{} as import('${lib}').GlobalComponents }${endOfLine}`;
globalComponentsType = `void extends typeof __VLS_globalComponents ? {} : typeof __VLS_globalComponents`;
}

str += `
${decl}const __VLS_intrinsicElements: __VLS_IntrinsicElements;
${decl}const __VLS_directiveBindingRestFields: { instance: null, oldValue: null, modifiers: any, dir: any };
${decl}const __VLS_unref: typeof import('${lib}').unref;
const __VLS_nativeElements = {
...{} as SVGElementTagNameMap,
...{} as HTMLElementTagNameMap,
};
type __VLS_IntrinsicElements = ${(
type __VLS_IntrinsicElements = ${(
target >= 3.3
? `import('${lib}/jsx-runtime').JSX.IntrinsicElements;`
: `globalThis.JSX.IntrinsicElements;`
)}
type __VLS_Element = ${(
type __VLS_Element = ${(
target >= 3.3
? `import('${lib}/jsx-runtime').JSX.Element;`
: `globalThis.JSX.Element;`
)}
type __VLS_GlobalComponents = ${(
type __VLS_GlobalComponents = ${(
target >= 3.5
? globalComponentsType
: `(${globalComponentsType}) & Pick<typeof import('${lib}'), 'Transition' | 'TransitionGroup' | 'KeepAlive' | 'Suspense' | 'Teleport'>;`
? `import('${lib}').GlobalComponents`
: `import('${lib}').GlobalComponents & Pick<typeof import('${lib}'), 'Transition' | 'TransitionGroup' | 'KeepAlive' | 'Suspense' | 'Teleport'>;`
)}
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
type __VLS_unknownDirective = (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
type __VLS_WithComponent<N0 extends string, LocalComponents, N1 extends string, N2 extends string, N3 extends string> =
N1 extends keyof LocalComponents ? N1 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N1] } :
N2 extends keyof LocalComponents ? N2 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N2] } :
N3 extends keyof LocalComponents ? N3 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N3] } :
N1 extends keyof __VLS_GlobalComponents ? N1 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N1] } :
N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N2] } :
N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N3] } :
${strictTemplates ? '{}' : '{ [K in N0]: unknown }'}
type __VLS_FunctionalComponentProps<T, K> =
'__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: { props?: infer P } } ? NonNullable<P> : never
: T extends (props: infer P, ...args: any) => any ? P :
{};
type __VLS_IsFunction<T, K> = K extends keyof T
? __VLS_IsAny<T[K]> extends false
? unknown extends T[K]
? false
: true
: false
: false;
// fix https://github.com/vuejs/language-tools/issues/926
type __VLS_UnionToIntersection<U> = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never;
type __VLS_OverloadUnionInner<T, U = unknown> = U & T extends (...args: infer A) => infer R
? U extends T
? never
: __VLS_OverloadUnionInner<T, Pick<T, keyof T> & U & ((...args: A) => R)> | ((...args: A) => R)
: never;
type __VLS_OverloadUnion<T> = Exclude<
__VLS_OverloadUnionInner<(() => never) & T>,
T extends () => never ? never : () => never
>;
type __VLS_ConstructorOverloads<T> = __VLS_OverloadUnion<T> extends infer F
? F extends (event: infer E, ...args: infer A) => any
? { [K in E & string]: (...args: A) => void; }
: never
: never;
type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
__VLS_UnionToIntersection<
__VLS_ConstructorOverloads<T> & {
[K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never
}
>
>;
type __VLS_PrettifyGlobal<T> = { [K in keyof T]: T[K]; } & {};
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
type __VLS_unknownDirective = (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
type __VLS_WithComponent<N0 extends string, LocalComponents, N1 extends string, N2 extends string, N3 extends string> =
N1 extends keyof LocalComponents ? N1 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N1] } :
N2 extends keyof LocalComponents ? N2 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N2] } :
N3 extends keyof LocalComponents ? N3 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N3] } :
N1 extends keyof __VLS_GlobalComponents ? N1 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N1] } :
N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N2] } :
N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N3] } :
${strictTemplates ? '{}' : '{ [K in N0]: unknown }'}
type __VLS_FunctionalComponentProps<T, K> =
'__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: { props?: infer P } } ? NonNullable<P> : never
: T extends (props: infer P, ...args: any) => any ? P :
{};
type __VLS_IsFunction<T, K> = K extends keyof T
? __VLS_IsAny<T[K]> extends false
? unknown extends T[K]
? false
: true
: false
: false;
// fix https://github.com/vuejs/language-tools/issues/926
type __VLS_UnionToIntersection<U> = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never;
type __VLS_OverloadUnionInner<T, U = unknown> = U & T extends (...args: infer A) => infer R
? U extends T
? never
: __VLS_OverloadUnionInner<T, Pick<T, keyof T> & U & ((...args: A) => R)> | ((...args: A) => R)
: never;
type __VLS_OverloadUnion<T> = Exclude<
__VLS_OverloadUnionInner<(() => never) & T>,
T extends () => never ? never : () => never
>;
type __VLS_ConstructorOverloads<T> = __VLS_OverloadUnion<T> extends infer F
? F extends (event: infer E, ...args: infer A) => any
? { [K in E & string]: (...args: A) => void; }
: never
: never;
type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
__VLS_UnionToIntersection<
__VLS_ConstructorOverloads<T> & {
[K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never
}
>
>;
type __VLS_PrettifyGlobal<T> = { [K in keyof T]: T[K]; } & {};
${decl}function __VLS_getVForSourceType(source: number): [number, number, number][];
${decl}function __VLS_getVForSourceType(source: string): [string, number, number][];
${decl}function __VLS_getVForSourceType<T extends any[]>(source: T): [
item: T[number],
key: number,
index: number,
][];
${decl}function __VLS_getVForSourceType<T extends { [Symbol.iterator](): Iterator<any> }>(source: T): [
item: T extends { [Symbol.iterator](): Iterator<infer T1> } ? T1 : never,
key: number,
index: undefined,
][];
// #3845
${decl}function __VLS_getVForSourceType<T extends number | { [Symbol.iterator](): Iterator<any> }>(source: T): [
item: number | (Exclude<T, number> extends { [Symbol.iterator](): Iterator<infer T1> } ? T1 : never),
key: number,
index: undefined,
][];
${decl}function __VLS_getVForSourceType<T>(source: T): [
item: T[keyof T],
key: keyof T,
index: number,
][];
// @ts-ignore
${decl}function __VLS_getSlotParams<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>;
// @ts-ignore
${decl}function __VLS_getSlotParam<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>[0];
${decl}function __VLS_directiveAsFunction<T extends import('${lib}').Directive>(dir: T): T extends (...args: any) => any
? T | __VLS_unknownDirective
: NonNullable<(T & Record<string, __VLS_unknownDirective>)['created' | 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted']>;
${decl}function __VLS_withScope<T, K>(ctx: T, scope: K): ctx is T & K;
${decl}function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] };
${decl}function __VLS_nonNullable<T>(t: T): T extends null | undefined ? never : T;
${decl}function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
T extends new (...args: any) => any
? (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { __ctx?: {
attrs?: any,
slots?: K extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : any,
emit?: K extends { $emit: infer Emit } ? Emit : any
} & { props?: ${fnPropsType}; expose?(exposed: K): void; } }
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
: T extends (...args: any) => any ? T
: (_: {}${strictTemplates ? '' : ' & Record<string, unknown>'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${strictTemplates ? '' : ' & Record<string, unknown>'} } };
${decl}function __VLS_elementAsFunction<T>(tag: T, endTag?: T): (_: T${strictTemplates ? '' : ' & Record<string, unknown>'}) => void;
${decl}function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
${decl}function __VLS_pickFunctionalComponentCtx<T, K>(comp: T, compInstance: K): NonNullable<__VLS_PickNotAny<
'__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: infer Ctx } ? Ctx : never : any
, T extends (props: any, ctx: infer Ctx) => any ? Ctx : any
>>;
${decl}function __VLS_normalizeSlot<S>(s: S): S extends () => infer R ? (props: {}) => R : S;
${decl}function __VLS_tryAsConstant<const T>(t: T): T;
function __VLS_getVForSourceType(source: number): [number, number, number][];
function __VLS_getVForSourceType(source: string): [string, number, number][];
function __VLS_getVForSourceType<T extends any[]>(source: T): [
item: T[number],
key: number,
index: number,
][];
function __VLS_getVForSourceType<T extends { [Symbol.iterator](): Iterator<any> }>(source: T): [
item: T extends { [Symbol.iterator](): Iterator<infer T1> } ? T1 : never,
key: number,
index: undefined,
][];
// #3845
function __VLS_getVForSourceType<T extends number | { [Symbol.iterator](): Iterator<any> }>(source: T): [
item: number | (Exclude<T, number> extends { [Symbol.iterator](): Iterator<infer T1> } ? T1 : never),
key: number,
index: undefined,
][];
function __VLS_getVForSourceType<T>(source: T): [
item: T[keyof T],
key: keyof T,
index: number,
][];
// @ts-ignore
function __VLS_getSlotParams<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>;
// @ts-ignore
function __VLS_getSlotParam<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>[0];
function __VLS_directiveAsFunction<T extends import('${lib}').Directive>(dir: T): T extends (...args: any) => any
? T | __VLS_unknownDirective
: NonNullable<(T & Record<string, __VLS_unknownDirective>)['created' | 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted']>;
function __VLS_withScope<T, K>(ctx: T, scope: K): ctx is T & K;
function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] };
function __VLS_nonNullable<T>(t: T): T extends null | undefined ? never : T;
function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
T extends new (...args: any) => any
? (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { __ctx?: {
attrs?: any,
slots?: K extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : any,
emit?: K extends { $emit: infer Emit } ? Emit : any
} & { props?: ${fnPropsType}; expose?(exposed: K): void; } }
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
: T extends (...args: any) => any ? T
: (_: {}${strictTemplates ? '' : ' & Record<string, unknown>'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${strictTemplates ? '' : ' & Record<string, unknown>'} } };
function __VLS_elementAsFunction<T>(tag: T, endTag?: T): (_: T${strictTemplates ? '' : ' & Record<string, unknown>'}) => void;
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
function __VLS_pickFunctionalComponentCtx<T, K>(comp: T, compInstance: K): NonNullable<__VLS_PickNotAny<
'__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: infer Ctx } ? Ctx : never : any
, T extends (props: any, ctx: infer Ctx) => any ? Ctx : any
>>;
function __VLS_normalizeSlot<S>(s: S): S extends () => infer R ? (props: {}) => R : S;
function __VLS_tryAsConstant<const T>(t: T): T;
}
`;

if (mode === 'global') {
str += `}${newLine}`;
}
return str;
};
5 changes: 3 additions & 2 deletions packages/language-core/lib/codegen/script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface ScriptCodegenOptions {
scriptSetupRanges: ScriptSetupRanges | undefined;
templateCodegen: TemplateCodegenContext & { codes: Code[]; } | undefined;
edited: boolean;
appendGlobalTypes: boolean;
getGeneratedLength: () => number;
linkedCodeMappings: Mapping[];
}
Expand Down Expand Up @@ -151,8 +152,8 @@ export function* generateScript(options: ScriptCodegenOptions): Generator<Code,
yield `type __VLS_IntrinsicElementsCompletion = __VLS_IntrinsicElements${endOfLine}`;
}
yield* ctx.localTypes.generate([...ctx.localTypes.getUsedNames()]);
if (!options.vueCompilerOptions.__setupedGlobalTypes) {
yield generateGlobalTypes('local', options.vueCompilerOptions.lib, options.vueCompilerOptions.target, options.vueCompilerOptions.strictTemplates);
if (options.appendGlobalTypes) {
yield generateGlobalTypes(options.vueCompilerOptions.lib, options.vueCompilerOptions.target, options.vueCompilerOptions.strictTemplates);
}

if (options.sfc.scriptSetup) {
Expand Down
14 changes: 11 additions & 3 deletions packages/language-core/lib/plugins/vue-tsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const fileEditTimes = new Map<string, number>();

const plugin: VueLanguagePlugin = ctx => {

let appendedGlobalTypes = false;

return {

version: 2.1,
Expand Down Expand Up @@ -51,7 +53,12 @@ const plugin: VueLanguagePlugin = ctx => {

function useTsx(fileName: string, sfc: Sfc) {
if (!tsCodegen.has(sfc)) {
tsCodegen.set(sfc, createTsx(fileName, sfc, ctx));
let appendGlobalTypes = false;
if (!ctx.vueCompilerOptions.__setupedGlobalTypes && !appendedGlobalTypes) {
appendGlobalTypes = true;
appendedGlobalTypes = true;
}
tsCodegen.set(sfc, createTsx(fileName, sfc, ctx, appendGlobalTypes));
}
return tsCodegen.get(sfc)!;
}
Expand All @@ -62,9 +69,9 @@ export default plugin;
function createTsx(
fileName: string,
_sfc: Sfc,
ctx: Parameters<VueLanguagePlugin>[0]
ctx: Parameters<VueLanguagePlugin>[0],
appendGlobalTypes: boolean
) {

const ts = ctx.modules.typescript;
const lang = computed(() => {
return !_sfc.script && !_sfc.scriptSetup ? 'ts'
Expand Down Expand Up @@ -172,6 +179,7 @@ function createTsx(
edited: ctx.vueCompilerOptions.__test || (fileEditTimes.get(fileName) ?? 0) >= 2,
getGeneratedLength: () => generatedLength,
linkedCodeMappings,
appendGlobalTypes,
});
fileEditTimes.set(fileName, (fileEditTimes.get(fileName) ?? 0) + 1);

Expand Down
2 changes: 1 addition & 1 deletion packages/language-core/lib/utils/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ export function setupGlobalTypes(rootDir: string, vueOptions: VueCompilerOptions
dir = parentDir;
}
const globalTypesPath = path.resolve(dir, `node_modules/.vue-global-types/${vueOptions.lib}_${vueOptions.target}_${vueOptions.strictTemplates}.d.ts`);
const globalTypesContents = generateGlobalTypes('global', vueOptions.lib, vueOptions.target, vueOptions.strictTemplates);
const globalTypesContents = `// @ts-nocheck\nexport {};\n` + generateGlobalTypes(vueOptions.lib, vueOptions.target, vueOptions.strictTemplates);
host.writeFile(globalTypesPath, globalTypesContents);
return true;
} catch {
Expand Down
2 changes: 1 addition & 1 deletion packages/language-server/lib/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function initialize(
const fileExists = project.typescript.languageServiceHost.fileExists.bind(project.typescript.languageServiceHost);
const getScriptSnapshot = project.typescript.languageServiceHost.getScriptSnapshot.bind(project.typescript.languageServiceHost);
const globalTypesName = `${vueCompilerOptions.lib}_${vueCompilerOptions.target}_${vueCompilerOptions.strictTemplates}.d.ts`;
const globalTypesContents = generateGlobalTypes('global', vueCompilerOptions.lib, vueCompilerOptions.target, vueCompilerOptions.strictTemplates);
const globalTypesContents = `// @ts-nocheck\nexport {};\n` + generateGlobalTypes(vueCompilerOptions.lib, vueCompilerOptions.target, vueCompilerOptions.strictTemplates);
const globalTypesSnapshot: ts.IScriptSnapshot = {
getText: (start, end) => globalTypesContents.substring(start, end),
getLength: () => globalTypesContents.length,
Expand Down
Loading

0 comments on commit b14b8a9

Please sign in to comment.