Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@
},
"pnpm": {
"overrides": {
"@volar/kit": "https://pkg.pr.new/volarjs/volar.js/@volar/kit@28cbdee",
"@volar/language-core": "https://pkg.pr.new/volarjs/volar.js/@volar/language-core@28cbdee",
"@volar/language-server": "https://pkg.pr.new/volarjs/volar.js/@volar/language-server@28cbdee",
"@volar/language-service": "https://pkg.pr.new/volarjs/volar.js/@volar/language-service@28cbdee",
"@volar/source-map": "https://pkg.pr.new/volarjs/volar.js/@volar/source-map@28cbdee",
"@volar/test-utils": "https://pkg.pr.new/volarjs/volar.js/@volar/test-utils@28cbdee",
"@volar/typescript": "https://pkg.pr.new/volarjs/volar.js/@volar/typescript@28cbdee",
"@volar/vscode": "https://pkg.pr.new/volarjs/volar.js/@volar/vscode@28cbdee",
"@volar/kit": "https://pkg.pr.new/volarjs/volar.js/@volar/kit@0e1be44",
"@volar/language-core": "https://pkg.pr.new/volarjs/volar.js/@volar/language-core@0e1be44",
"@volar/language-server": "https://pkg.pr.new/volarjs/volar.js/@volar/language-server@0e1be44",
"@volar/language-service": "https://pkg.pr.new/volarjs/volar.js/@volar/language-service@0e1be44",
"@volar/source-map": "https://pkg.pr.new/volarjs/volar.js/@volar/source-map@0e1be44",
"@volar/test-utils": "https://pkg.pr.new/volarjs/volar.js/@volar/test-utils@0e1be44",
"@volar/typescript": "https://pkg.pr.new/volarjs/volar.js/@volar/typescript@0e1be44",
"@volar/vscode": "https://pkg.pr.new/volarjs/volar.js/@volar/vscode@0e1be44",
"volar-service-typescript": "https://pkg.pr.new/volarjs/services/volar-service-typescript@177b9ed",
"inquirer": "9.2.23"
}
Expand Down
46 changes: 33 additions & 13 deletions packages/component-meta/lib/base.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { TypeScriptProjectHost, createLanguageServiceHost, resolveFileLanguageId } from '@volar/typescript';
import * as vue from '@vue/language-core';
import type * as ts from 'typescript';
import * as path from 'path-browserify';
import type * as ts from 'typescript';
import { code as typeHelpersCode } from 'vue-component-type-helpers';
import { code as vue2TypeHelpersCode } from 'vue-component-type-helpers/vue2';
import { TypeScriptProjectHost, createLanguageServiceHost, resolveFileLanguageId } from '@volar/typescript';

import type {
MetaCheckerOptions,
ComponentMeta,
Declaration,
EventMeta,
ExposeMeta,
MetaCheckerOptions,
PropertyMeta,
PropertyMetaSchema,
SlotMeta,
Declaration
SlotMeta
} from './types';

export * from './types';
Expand Down Expand Up @@ -83,16 +83,11 @@ export function baseCreate(
];
};

const vueLanguagePlugin = vue.createVueLanguagePlugin2<string>(
const vueLanguagePlugin = vue.createVueLanguagePlugin<string>(
ts,
id => id,
vue.createRootFileChecker(
projectHost.getProjectVersion ? () => projectHost.getProjectVersion!() : undefined,
() => projectHost.getScriptFileNames(),
ts.sys.useCaseSensitiveFileNames
),
projectHost.getCompilationSettings(),
commandLine.vueOptions
commandLine.vueOptions,
id => id
);
const language = vue.createLanguage(
[
Expand Down Expand Up @@ -140,6 +135,31 @@ export function baseCreate(
const { languageServiceHost } = createLanguageServiceHost(ts, ts.sys, language, s => s, projectHost);
const tsLs = ts.createLanguageService(languageServiceHost);

const fileExists = languageServiceHost.fileExists.bind(languageServiceHost);
const getScriptSnapshot = languageServiceHost.getScriptSnapshot.bind(languageServiceHost);
const globalTypesName = `__globalTypes_${commandLine.vueOptions.target}_${commandLine.vueOptions.strictTemplates}.d.ts`;
const snapshots = new Map<string, ts.IScriptSnapshot>();
languageServiceHost.fileExists = path => {
if (path.endsWith(globalTypesName)) {
return true;
}
return fileExists(path);
};
languageServiceHost.getScriptSnapshot = path => {
if (path.endsWith(globalTypesName)) {
if (!snapshots.has(path)) {
const contents = vue.generateGlobalTypes(commandLine.vueOptions.lib, commandLine.vueOptions.target, commandLine.vueOptions.strictTemplates);
snapshots.set(path, {
getText: (start, end) => contents.substring(start, end),
getLength: () => contents.length,
getChangeRange: () => undefined,
});
}
return snapshots.get(path)!;
}
return getScriptSnapshot(path);
};

if (checkerOptions.forceUseTs) {
const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
languageServiceHost.getScriptKind = fileName => {
Expand Down
7 changes: 4 additions & 3 deletions packages/language-core/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
export * from './lib/codegen/globalTypes';
export * from './lib/codegen/template';
export * from './lib/languagePlugin';
export * from './lib/parsers/scriptSetupRanges';
export * from './lib/plugins';
export * from './lib/virtualFile/vueFile';
export * from './lib/types';
export * from './lib/utils/ts';
export * from './lib/utils/parseSfc';
export * from './lib/utils/ts';
export * from './lib/virtualFile/vueFile';

export * as scriptRanges from './lib/parsers/scriptRanges';
export * from './lib/utils/shared';
export { tsCodegen } from './lib/plugins/vue-tsx';
export * from './lib/utils/shared';

export * from '@volar/language-core';
export type * as CompilerDOM from '@vue/compiler-dom';
125 changes: 125 additions & 0 deletions packages/language-core/lib/codegen/globalTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { getSlotsPropertyName } from '../utils/shared';

export function generateGlobalTypes(lib: string, target: number, strictTemplates: boolean) {
const fnPropsType = `(K extends { $props: infer Props } ? Props : any)${strictTemplates ? '' : ' & Record<string, unknown>'}`;
return `
const __VLS_globalComponents = { ...{} as import('${lib}').GlobalComponents };

declare const __VLS_intrinsicElements: __VLS_IntrinsicElements;
declare const __VLS_directiveBindingRestFields = { instance: null, oldValue: null, modifiers: null as any, dir: null as any };

type __VLS_IntrinsicElements = ${(
target >= 3.3
? `import('${lib}/jsx-runtime').JSX.IntrinsicElements;`
: `globalThis.JSX.IntrinsicElements;`
)}
type __VLS_Element = ${(
target >= 3.3
? `import('${lib}/jsx-runtime').JSX.Element;`
: `globalThis.JSX.Element;`
)}
type __VLS_GlobalComponents = ${(
target >= 3.5
? `void extends typeof __VLS_globalComponents ? {} : typeof __VLS_globalComponents;`
: `(void extends typeof __VLS_globalComponents ? {} : typeof __VLS_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]; } & {};

declare function __VLS_getVForSourceType(source: number): [number, number, number][];
declare function __VLS_getVForSourceType(source: string): [string, number, number][];
declare function __VLS_getVForSourceType<T extends any[]>(source: T): [
item: T[number],
key: number,
index: number,
][];
declare 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
declare 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,
][];
declare function __VLS_getVForSourceType<T>(source: T): [
item: T[keyof T],
key: keyof T,
index: number,
][];
// @ts-ignore
declare function __VLS_getSlotParams<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>;
// @ts-ignore
declare function __VLS_getSlotParam<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>[0];
declare 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']>;
declare function __VLS_withScope<T, K>(ctx: T, scope: K): ctx is T & K;
declare function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] };
declare function __VLS_nonNullable<T>(t: T): T extends null | undefined ? never : T;
declare 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>'} } };
declare function __VLS_elementAsFunction<T>(tag: T, endTag?: T): (_: T${strictTemplates ? '' : ' & Record<string, unknown>'}) => void;
declare function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): Parameters<T>['length'] extends 2 ? [any] : [];
declare 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
>>;
declare function __VLS_normalizeSlot<S>(s: S): S extends () => infer R ? (props: {}) => R : S;
declare function __VLS_tryAsConstant<const T>(t: T): T;
`;
};
148 changes: 148 additions & 0 deletions packages/language-core/lib/codegen/localTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import type * as ts from 'typescript';
import { VueCompilerOptions } from '../types';
import { getSlotsPropertyName } from '../utils/shared';
import { endOfLine } from './common';

export function getLocalTypesGenerator(compilerOptions: ts.CompilerOptions, vueCompilerOptions: VueCompilerOptions) {
const used = new Set<string>();

const OmitKeepDiscriminatedUnion = defineHelper(
`__VLS_OmitKeepDiscriminatedUnion`,
() => `
type __VLS_OmitKeepDiscriminatedUnion<T, K extends keyof any> = T extends any
? Pick<T, Exclude<keyof T, K>>
: never;
`.trimStart()
);
const WithDefaults = defineHelper(
`__VLS_WithDefaults`,
() => `
type __VLS_WithDefaults<P, D> = {
[K in keyof Pick<P, keyof P>]: K extends keyof D
? ${PrettifyLocal.name}<P[K] & { default: D[K]}>
: P[K]
};
`.trimStart()
);
const PrettifyLocal = defineHelper(
`__VLS_PrettifyLocal`,
() => `type __VLS_PrettifyLocal<T> = { [K in keyof T]: T[K]; } & {}${endOfLine}`
);
const WithTemplateSlots = defineHelper(
`__VLS_WithTemplateSlots`,
() => `
type __VLS_WithTemplateSlots<T, S> = T & {
new(): {
${getSlotsPropertyName(vueCompilerOptions.target)}: S;
${vueCompilerOptions.jsxSlots ? `$props: ${PropsChildren.name}<S>;` : ''}
}
};
`.trimStart()
);
const PropsChildren = defineHelper(
`__VLS_PropsChildren`,
() => `
type __VLS_PropsChildren<S> = {
[K in keyof (
boolean extends (
// @ts-ignore
JSX.ElementChildrenAttribute extends never
? true
: false
)
? never
// @ts-ignore
: JSX.ElementChildrenAttribute
)]?: S;
};
`.trimStart()
);
const TypePropsToOption = defineHelper(
`__VLS_TypePropsToOption`,
() => compilerOptions.exactOptionalPropertyTypes ?
`
type __VLS_TypePropsToOption<T> = {
[K in keyof T]-?: {} extends Pick<T, K>
? { type: import('${vueCompilerOptions.lib}').PropType<T[K]> }
: { type: import('${vueCompilerOptions.lib}').PropType<T[K]>, required: true }
};
`.trimStart() :
`
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
type __VLS_TypePropsToOption<T> = {
[K in keyof T]-?: {} extends Pick<T, K>
? { type: import('${vueCompilerOptions.lib}').PropType<__VLS_NonUndefinedable<T[K]>> }
: { type: import('${vueCompilerOptions.lib}').PropType<T[K]>, required: true }
};
`.trimStart()
);
const OmitIndexSignature = defineHelper(
`__VLS_OmitIndexSignature`,
() => `type __VLS_OmitIndexSignature<T> = { [K in keyof T as {} extends Record<K, unknown> ? never : K]: T[K]; }${endOfLine}`
);
const PickRefsExpose = defineHelper(
`__VLS_PickRefsExpose`,
() => `
type __VLS_PickRefsExpose<T> = T extends object
? { [K in keyof T]: (T[K] extends any[]
? Parameters<T[K][0]['expose']>[0][]
: T[K] extends { expose?: (exposed: infer E) => void }
? E
: T[K]) | null }
: never;
`.trimStart()
);

const helpers = {
[PrettifyLocal.name]: PrettifyLocal,
[OmitKeepDiscriminatedUnion.name]: OmitKeepDiscriminatedUnion,
[WithDefaults.name]: WithDefaults,
[WithTemplateSlots.name]: WithTemplateSlots,
[PropsChildren.name]: PropsChildren,
[TypePropsToOption.name]: TypePropsToOption,
[OmitIndexSignature.name]: OmitIndexSignature,
[PickRefsExpose.name]: PickRefsExpose,
};
used.clear();

return {
generate,
getUsedNames() {
return used;
},
get PrettifyLocal() { return PrettifyLocal.name; },
get OmitKeepDiscriminatedUnion() { return OmitKeepDiscriminatedUnion.name; },
get WithDefaults() { return WithDefaults.name; },
get WithTemplateSlots() { return WithTemplateSlots.name; },
get PropsChildren() { return PropsChildren.name; },
get TypePropsToOption() { return TypePropsToOption.name; },
get OmitIndexSignature() { return OmitIndexSignature.name; },
get PickRefsExpose() { return PickRefsExpose.name; },
};

function* generate(names: string[]) {
const generated = new Set<string>();
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 defineHelper(name: string, generate: () => string) {
return {
get name() {
used.add(name);
return name;
},
generate,
};
}
}
Loading