Skip to content

Commit 38c1e48

Browse files
refactor: write real files to FS for shared global types (#4736)
1 parent a162f04 commit 38c1e48

File tree

29 files changed

+608
-648
lines changed

29 files changed

+608
-648
lines changed

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@
3232
},
3333
"pnpm": {
3434
"overrides": {
35-
"@volar/kit": "https://pkg.pr.new/volarjs/volar.js/@volar/kit@28cbdee",
36-
"@volar/language-core": "https://pkg.pr.new/volarjs/volar.js/@volar/language-core@28cbdee",
37-
"@volar/language-server": "https://pkg.pr.new/volarjs/volar.js/@volar/language-server@28cbdee",
38-
"@volar/language-service": "https://pkg.pr.new/volarjs/volar.js/@volar/language-service@28cbdee",
39-
"@volar/source-map": "https://pkg.pr.new/volarjs/volar.js/@volar/source-map@28cbdee",
40-
"@volar/test-utils": "https://pkg.pr.new/volarjs/volar.js/@volar/test-utils@28cbdee",
41-
"@volar/typescript": "https://pkg.pr.new/volarjs/volar.js/@volar/typescript@28cbdee",
42-
"@volar/vscode": "https://pkg.pr.new/volarjs/volar.js/@volar/vscode@28cbdee",
35+
"@volar/kit": "https://pkg.pr.new/volarjs/volar.js/@volar/kit@0e1be44",
36+
"@volar/language-core": "https://pkg.pr.new/volarjs/volar.js/@volar/language-core@0e1be44",
37+
"@volar/language-server": "https://pkg.pr.new/volarjs/volar.js/@volar/language-server@0e1be44",
38+
"@volar/language-service": "https://pkg.pr.new/volarjs/volar.js/@volar/language-service@0e1be44",
39+
"@volar/source-map": "https://pkg.pr.new/volarjs/volar.js/@volar/source-map@0e1be44",
40+
"@volar/test-utils": "https://pkg.pr.new/volarjs/volar.js/@volar/test-utils@0e1be44",
41+
"@volar/typescript": "https://pkg.pr.new/volarjs/volar.js/@volar/typescript@0e1be44",
42+
"@volar/vscode": "https://pkg.pr.new/volarjs/volar.js/@volar/vscode@0e1be44",
4343
"volar-service-typescript": "https://pkg.pr.new/volarjs/services/volar-service-typescript@177b9ed",
4444
"inquirer": "9.2.23"
4545
}

packages/component-meta/lib/base.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1+
import { TypeScriptProjectHost, createLanguageServiceHost, resolveFileLanguageId } from '@volar/typescript';
12
import * as vue from '@vue/language-core';
2-
import type * as ts from 'typescript';
33
import * as path from 'path-browserify';
4+
import type * as ts from 'typescript';
45
import { code as typeHelpersCode } from 'vue-component-type-helpers';
56
import { code as vue2TypeHelpersCode } from 'vue-component-type-helpers/vue2';
6-
import { TypeScriptProjectHost, createLanguageServiceHost, resolveFileLanguageId } from '@volar/typescript';
77

88
import type {
9-
MetaCheckerOptions,
109
ComponentMeta,
10+
Declaration,
1111
EventMeta,
1212
ExposeMeta,
13+
MetaCheckerOptions,
1314
PropertyMeta,
1415
PropertyMetaSchema,
15-
SlotMeta,
16-
Declaration
16+
SlotMeta
1717
} from './types';
1818

1919
export * from './types';
@@ -83,16 +83,11 @@ export function baseCreate(
8383
];
8484
};
8585

86-
const vueLanguagePlugin = vue.createVueLanguagePlugin2<string>(
86+
const vueLanguagePlugin = vue.createVueLanguagePlugin<string>(
8787
ts,
88-
id => id,
89-
vue.createRootFileChecker(
90-
projectHost.getProjectVersion ? () => projectHost.getProjectVersion!() : undefined,
91-
() => projectHost.getScriptFileNames(),
92-
ts.sys.useCaseSensitiveFileNames
93-
),
9488
projectHost.getCompilationSettings(),
95-
commandLine.vueOptions
89+
commandLine.vueOptions,
90+
id => id
9691
);
9792
const language = vue.createLanguage(
9893
[
@@ -140,6 +135,31 @@ export function baseCreate(
140135
const { languageServiceHost } = createLanguageServiceHost(ts, ts.sys, language, s => s, projectHost);
141136
const tsLs = ts.createLanguageService(languageServiceHost);
142137

138+
const fileExists = languageServiceHost.fileExists.bind(languageServiceHost);
139+
const getScriptSnapshot = languageServiceHost.getScriptSnapshot.bind(languageServiceHost);
140+
const globalTypesName = `__globalTypes_${commandLine.vueOptions.target}_${commandLine.vueOptions.strictTemplates}.d.ts`;
141+
const snapshots = new Map<string, ts.IScriptSnapshot>();
142+
languageServiceHost.fileExists = path => {
143+
if (path.endsWith(globalTypesName)) {
144+
return true;
145+
}
146+
return fileExists(path);
147+
};
148+
languageServiceHost.getScriptSnapshot = path => {
149+
if (path.endsWith(globalTypesName)) {
150+
if (!snapshots.has(path)) {
151+
const contents = vue.generateGlobalTypes(commandLine.vueOptions.lib, commandLine.vueOptions.target, commandLine.vueOptions.strictTemplates);
152+
snapshots.set(path, {
153+
getText: (start, end) => contents.substring(start, end),
154+
getLength: () => contents.length,
155+
getChangeRange: () => undefined,
156+
});
157+
}
158+
return snapshots.get(path)!;
159+
}
160+
return getScriptSnapshot(path);
161+
};
162+
143163
if (checkerOptions.forceUseTs) {
144164
const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
145165
languageServiceHost.getScriptKind = fileName => {

packages/language-core/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
export * from './lib/codegen/globalTypes';
12
export * from './lib/codegen/template';
23
export * from './lib/languagePlugin';
34
export * from './lib/parsers/scriptSetupRanges';
45
export * from './lib/plugins';
5-
export * from './lib/virtualFile/vueFile';
66
export * from './lib/types';
7-
export * from './lib/utils/ts';
87
export * from './lib/utils/parseSfc';
8+
export * from './lib/utils/ts';
9+
export * from './lib/virtualFile/vueFile';
910

1011
export * as scriptRanges from './lib/parsers/scriptRanges';
11-
export * from './lib/utils/shared';
1212
export { tsCodegen } from './lib/plugins/vue-tsx';
13+
export * from './lib/utils/shared';
1314

1415
export * from '@volar/language-core';
1516
export type * as CompilerDOM from '@vue/compiler-dom';
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { getSlotsPropertyName } from '../utils/shared';
2+
3+
export function generateGlobalTypes(lib: string, target: number, strictTemplates: boolean) {
4+
const fnPropsType = `(K extends { $props: infer Props } ? Props : any)${strictTemplates ? '' : ' & Record<string, unknown>'}`;
5+
return `
6+
const __VLS_globalComponents = { ...{} as import('${lib}').GlobalComponents };
7+
8+
declare const __VLS_intrinsicElements: __VLS_IntrinsicElements;
9+
declare const __VLS_directiveBindingRestFields = { instance: null, oldValue: null, modifiers: null as any, dir: null as any };
10+
11+
type __VLS_IntrinsicElements = ${(
12+
target >= 3.3
13+
? `import('${lib}/jsx-runtime').JSX.IntrinsicElements;`
14+
: `globalThis.JSX.IntrinsicElements;`
15+
)}
16+
type __VLS_Element = ${(
17+
target >= 3.3
18+
? `import('${lib}/jsx-runtime').JSX.Element;`
19+
: `globalThis.JSX.Element;`
20+
)}
21+
type __VLS_GlobalComponents = ${(
22+
target >= 3.5
23+
? `void extends typeof __VLS_globalComponents ? {} : typeof __VLS_globalComponents;`
24+
: `(void extends typeof __VLS_globalComponents ? {} : typeof __VLS_globalComponents) & Pick<typeof import('${lib}'), 'Transition' | 'TransitionGroup' | 'KeepAlive' | 'Suspense' | 'Teleport'>;`
25+
)}
26+
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
27+
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
28+
type __VLS_unknownDirective = (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
29+
type __VLS_WithComponent<N0 extends string, LocalComponents, N1 extends string, N2 extends string, N3 extends string> =
30+
N1 extends keyof LocalComponents ? N1 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N1] } :
31+
N2 extends keyof LocalComponents ? N2 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N2] } :
32+
N3 extends keyof LocalComponents ? N3 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N3] } :
33+
N1 extends keyof __VLS_GlobalComponents ? N1 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N1] } :
34+
N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N2] } :
35+
N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N3] } :
36+
${strictTemplates ? '{}' : '{ [K in N0]: unknown }'}
37+
type __VLS_FunctionalComponentProps<T, K> =
38+
'__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: { props?: infer P } } ? NonNullable<P> : never
39+
: T extends (props: infer P, ...args: any) => any ? P :
40+
{};
41+
type __VLS_IsFunction<T, K> = K extends keyof T
42+
? __VLS_IsAny<T[K]> extends false
43+
? unknown extends T[K]
44+
? false
45+
: true
46+
: false
47+
: false;
48+
// fix https://github.com/vuejs/language-tools/issues/926
49+
type __VLS_UnionToIntersection<U> = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never;
50+
type __VLS_OverloadUnionInner<T, U = unknown> = U & T extends (...args: infer A) => infer R
51+
? U extends T
52+
? never
53+
: __VLS_OverloadUnionInner<T, Pick<T, keyof T> & U & ((...args: A) => R)> | ((...args: A) => R)
54+
: never;
55+
type __VLS_OverloadUnion<T> = Exclude<
56+
__VLS_OverloadUnionInner<(() => never) & T>,
57+
T extends () => never ? never : () => never
58+
>;
59+
type __VLS_ConstructorOverloads<T> = __VLS_OverloadUnion<T> extends infer F
60+
? F extends (event: infer E, ...args: infer A) => any
61+
? { [K in E & string]: (...args: A) => void; }
62+
: never
63+
: never;
64+
type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
65+
__VLS_UnionToIntersection<
66+
__VLS_ConstructorOverloads<T> & {
67+
[K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never
68+
}
69+
>
70+
>;
71+
type __VLS_PrettifyGlobal<T> = { [K in keyof T]: T[K]; } & {};
72+
73+
declare function __VLS_getVForSourceType(source: number): [number, number, number][];
74+
declare function __VLS_getVForSourceType(source: string): [string, number, number][];
75+
declare function __VLS_getVForSourceType<T extends any[]>(source: T): [
76+
item: T[number],
77+
key: number,
78+
index: number,
79+
][];
80+
declare function __VLS_getVForSourceType<T extends { [Symbol.iterator](): Iterator<any> }>(source: T): [
81+
item: T extends { [Symbol.iterator](): Iterator<infer T1> } ? T1 : never,
82+
key: number,
83+
index: undefined,
84+
][];
85+
// #3845
86+
declare function __VLS_getVForSourceType<T extends number | { [Symbol.iterator](): Iterator<any> }>(source: T): [
87+
item: number | (Exclude<T, number> extends { [Symbol.iterator](): Iterator<infer T1> } ? T1 : never),
88+
key: number,
89+
index: undefined,
90+
][];
91+
declare function __VLS_getVForSourceType<T>(source: T): [
92+
item: T[keyof T],
93+
key: keyof T,
94+
index: number,
95+
][];
96+
// @ts-ignore
97+
declare function __VLS_getSlotParams<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>;
98+
// @ts-ignore
99+
declare function __VLS_getSlotParam<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>[0];
100+
declare function __VLS_directiveAsFunction<T extends import('${lib}').Directive>(dir: T): T extends (...args: any) => any
101+
? T | __VLS_unknownDirective
102+
: NonNullable<(T & Record<string, __VLS_unknownDirective>)['created' | 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted']>;
103+
declare function __VLS_withScope<T, K>(ctx: T, scope: K): ctx is T & K;
104+
declare function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] };
105+
declare function __VLS_nonNullable<T>(t: T): T extends null | undefined ? never : T;
106+
declare function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
107+
T extends new (...args: any) => any
108+
? (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { __ctx?: {
109+
attrs?: any,
110+
slots?: K extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : any,
111+
emit?: K extends { $emit: infer Emit } ? Emit : any
112+
} & { props?: ${fnPropsType}; expose?(exposed: K): void; } }
113+
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
114+
: T extends (...args: any) => any ? T
115+
: (_: {}${strictTemplates ? '' : ' & Record<string, unknown>'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${strictTemplates ? '' : ' & Record<string, unknown>'} } };
116+
declare function __VLS_elementAsFunction<T>(tag: T, endTag?: T): (_: T${strictTemplates ? '' : ' & Record<string, unknown>'}) => void;
117+
declare function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): Parameters<T>['length'] extends 2 ? [any] : [];
118+
declare function __VLS_pickFunctionalComponentCtx<T, K>(comp: T, compInstance: K): NonNullable<__VLS_PickNotAny<
119+
'__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: infer Ctx } ? Ctx : never : any
120+
, T extends (props: any, ctx: infer Ctx) => any ? Ctx : any
121+
>>;
122+
declare function __VLS_normalizeSlot<S>(s: S): S extends () => infer R ? (props: {}) => R : S;
123+
declare function __VLS_tryAsConstant<const T>(t: T): T;
124+
`;
125+
};
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import type * as ts from 'typescript';
2+
import { VueCompilerOptions } from '../types';
3+
import { getSlotsPropertyName } from '../utils/shared';
4+
import { endOfLine } from './common';
5+
6+
export function getLocalTypesGenerator(compilerOptions: ts.CompilerOptions, vueCompilerOptions: VueCompilerOptions) {
7+
const used = new Set<string>();
8+
9+
const OmitKeepDiscriminatedUnion = defineHelper(
10+
`__VLS_OmitKeepDiscriminatedUnion`,
11+
() => `
12+
type __VLS_OmitKeepDiscriminatedUnion<T, K extends keyof any> = T extends any
13+
? Pick<T, Exclude<keyof T, K>>
14+
: never;
15+
`.trimStart()
16+
);
17+
const WithDefaults = defineHelper(
18+
`__VLS_WithDefaults`,
19+
() => `
20+
type __VLS_WithDefaults<P, D> = {
21+
[K in keyof Pick<P, keyof P>]: K extends keyof D
22+
? ${PrettifyLocal.name}<P[K] & { default: D[K]}>
23+
: P[K]
24+
};
25+
`.trimStart()
26+
);
27+
const PrettifyLocal = defineHelper(
28+
`__VLS_PrettifyLocal`,
29+
() => `type __VLS_PrettifyLocal<T> = { [K in keyof T]: T[K]; } & {}${endOfLine}`
30+
);
31+
const WithTemplateSlots = defineHelper(
32+
`__VLS_WithTemplateSlots`,
33+
() => `
34+
type __VLS_WithTemplateSlots<T, S> = T & {
35+
new(): {
36+
${getSlotsPropertyName(vueCompilerOptions.target)}: S;
37+
${vueCompilerOptions.jsxSlots ? `$props: ${PropsChildren.name}<S>;` : ''}
38+
}
39+
};
40+
`.trimStart()
41+
);
42+
const PropsChildren = defineHelper(
43+
`__VLS_PropsChildren`,
44+
() => `
45+
type __VLS_PropsChildren<S> = {
46+
[K in keyof (
47+
boolean extends (
48+
// @ts-ignore
49+
JSX.ElementChildrenAttribute extends never
50+
? true
51+
: false
52+
)
53+
? never
54+
// @ts-ignore
55+
: JSX.ElementChildrenAttribute
56+
)]?: S;
57+
};
58+
`.trimStart()
59+
);
60+
const TypePropsToOption = defineHelper(
61+
`__VLS_TypePropsToOption`,
62+
() => compilerOptions.exactOptionalPropertyTypes ?
63+
`
64+
type __VLS_TypePropsToOption<T> = {
65+
[K in keyof T]-?: {} extends Pick<T, K>
66+
? { type: import('${vueCompilerOptions.lib}').PropType<T[K]> }
67+
: { type: import('${vueCompilerOptions.lib}').PropType<T[K]>, required: true }
68+
};
69+
`.trimStart() :
70+
`
71+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
72+
type __VLS_TypePropsToOption<T> = {
73+
[K in keyof T]-?: {} extends Pick<T, K>
74+
? { type: import('${vueCompilerOptions.lib}').PropType<__VLS_NonUndefinedable<T[K]>> }
75+
: { type: import('${vueCompilerOptions.lib}').PropType<T[K]>, required: true }
76+
};
77+
`.trimStart()
78+
);
79+
const OmitIndexSignature = defineHelper(
80+
`__VLS_OmitIndexSignature`,
81+
() => `type __VLS_OmitIndexSignature<T> = { [K in keyof T as {} extends Record<K, unknown> ? never : K]: T[K]; }${endOfLine}`
82+
);
83+
const PickRefsExpose = defineHelper(
84+
`__VLS_PickRefsExpose`,
85+
() => `
86+
type __VLS_PickRefsExpose<T> = T extends object
87+
? { [K in keyof T]: (T[K] extends any[]
88+
? Parameters<T[K][0]['expose']>[0][]
89+
: T[K] extends { expose?: (exposed: infer E) => void }
90+
? E
91+
: T[K]) | null }
92+
: never;
93+
`.trimStart()
94+
);
95+
96+
const helpers = {
97+
[PrettifyLocal.name]: PrettifyLocal,
98+
[OmitKeepDiscriminatedUnion.name]: OmitKeepDiscriminatedUnion,
99+
[WithDefaults.name]: WithDefaults,
100+
[WithTemplateSlots.name]: WithTemplateSlots,
101+
[PropsChildren.name]: PropsChildren,
102+
[TypePropsToOption.name]: TypePropsToOption,
103+
[OmitIndexSignature.name]: OmitIndexSignature,
104+
[PickRefsExpose.name]: PickRefsExpose,
105+
};
106+
used.clear();
107+
108+
return {
109+
generate,
110+
getUsedNames() {
111+
return used;
112+
},
113+
get PrettifyLocal() { return PrettifyLocal.name; },
114+
get OmitKeepDiscriminatedUnion() { return OmitKeepDiscriminatedUnion.name; },
115+
get WithDefaults() { return WithDefaults.name; },
116+
get WithTemplateSlots() { return WithTemplateSlots.name; },
117+
get PropsChildren() { return PropsChildren.name; },
118+
get TypePropsToOption() { return TypePropsToOption.name; },
119+
get OmitIndexSignature() { return OmitIndexSignature.name; },
120+
get PickRefsExpose() { return PickRefsExpose.name; },
121+
};
122+
123+
function* generate(names: string[]) {
124+
const generated = new Set<string>();
125+
while (names.length) {
126+
used.clear();
127+
for (const name of names) {
128+
if (generated.has(name)) {
129+
continue;
130+
}
131+
const helper = helpers[name as keyof typeof helpers];
132+
yield helper.generate();
133+
generated.add(name);
134+
}
135+
names = [...used].filter(name => !generated.has(name));
136+
}
137+
}
138+
139+
function defineHelper(name: string, generate: () => string) {
140+
return {
141+
get name() {
142+
used.add(name);
143+
return name;
144+
},
145+
generate,
146+
};
147+
}
148+
}

0 commit comments

Comments
 (0)