Skip to content

Commit

Permalink
feat(language-core): support Vue 3.5 (#4474)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiyuanzmj authored Jul 4, 2024
1 parent 6f4aa71 commit 8d28afc
Show file tree
Hide file tree
Showing 20 changed files with 497 additions and 61 deletions.
109 changes: 67 additions & 42 deletions packages/language-core/lib/codegen/script/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,60 +67,85 @@ export function* generateScriptSetupOptions(
scriptSetup: NonNullable<Sfc['scriptSetup']>,
scriptSetupRanges: ScriptSetupRanges
): Generator<Code> {
const propsCodegens: (() => Generator<Code>)[] = [];
yield* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges);
yield* generateEmitsOption(options, scriptSetup, scriptSetupRanges);
}

if (ctx.generatedPropsType) {
propsCodegens.push(function* () {
yield `{} as `;
if (scriptSetupRanges.props.withDefaults?.arg) {
yield `${ctx.helperTypes.WithDefaults.name}<`;
}
yield `${ctx.helperTypes.TypePropsToOption.name}<`;
yield `__VLS_PublicProps>`;
if (scriptSetupRanges.props.withDefaults?.arg) {
yield `, typeof __VLS_withDefaultsArg>`;
}
});
}
if (scriptSetupRanges.props.define?.arg) {
const { arg } = scriptSetupRanges.props.define;
propsCodegens.push(function* () {
yield generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.navigation);
});
export function* generatePropsOption(
options: ScriptCodegenOptions,
ctx: ScriptCodegenContext,
scriptSetup: NonNullable<Sfc['scriptSetup']>,
scriptSetupRanges: ScriptSetupRanges
) {
if (options.vueCompilerOptions.target >= 3.5 && ctx.generatedPropsType) {
yield `__typeProps: {} as __VLS_PublicProps,${newLine}`;
}
else {
const codegens: (() => Generator<Code>)[] = [];

if (propsCodegens.length === 1) {
yield `props: `;
for (const generate of propsCodegens) {
yield* generate();
if (ctx.generatedPropsType) {
codegens.push(function* () {
yield `{} as `;
if (scriptSetupRanges.props.withDefaults?.arg) {
yield `${ctx.helperTypes.WithDefaults.name}<`;
}
yield `${ctx.helperTypes.TypePropsToOption.name}<`;
yield `__VLS_PublicProps>`;
if (scriptSetupRanges.props.withDefaults?.arg) {
yield `, typeof __VLS_withDefaultsArg>`;
}
});
}
yield `,${newLine}`;
}
else if (propsCodegens.length >= 2) {
yield `props: {${newLine}`;
for (const generate of propsCodegens) {
yield `...`;
yield* generate();
if (scriptSetupRanges.props.define?.arg) {
const { arg } = scriptSetupRanges.props.define;
codegens.push(function* () {
yield generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.navigation);
});
}

if (codegens.length === 1) {
yield `props: `;
for (const generate of codegens) {
yield* generate();
}
yield `,${newLine}`;
}
yield `},${newLine}`;
else if (codegens.length >= 2) {
yield `props: {${newLine}`;
for (const generate of codegens) {
yield `...`;
yield* generate();
yield `,${newLine}`;
}
yield `},${newLine}`;
}
}
}

export function* generateEmitsOption(
options: ScriptCodegenOptions,
scriptSetup: NonNullable<Sfc['scriptSetup']>,
scriptSetupRanges: ScriptSetupRanges
): Generator<Code> {
if (!scriptSetupRanges.emits.define && !scriptSetupRanges.defineProp.some(p => p.isModel)) {
return;
}
if (scriptSetupRanges.defineProp.filter(p => p.isModel).length || scriptSetupRanges.emits.define) {
yield `emits: ({} as __VLS_NormalizeEmits<typeof __VLS_modelEmitsType`;
if (scriptSetupRanges.emits.define) {

if (options.vueCompilerOptions.target < 3.5 || scriptSetupRanges.emits.define?.arg || scriptSetupRanges.emits.define?.hasUnionTypeArg) {
yield `emits: ({} as __VLS_NormalizeEmits<__VLS_ModelEmitsType`;
if (scriptSetupRanges?.emits.define) {
yield ` & typeof `;
yield scriptSetupRanges.emits.name ?? '__VLS_emit';
}
yield `>),${newLine}`;
}

if (options.vueCompilerOptions.target >= 3.5) {
// https://github.com/vuejs/core/pull/10801
if (scriptSetupRanges.props.define?.typeArg) {
yield `__typeProps: __VLS_typeProps,${newLine}`;
}
if (scriptSetupRanges.emits.define?.typeArg) {
yield `__typeEmits: ${scriptSetupRanges.emits.name ?? '__VLS_emit'},${newLine}`;
else {
yield `__typeEmits: {} as __VLS_ModelEmitsType`;
const typeArg = scriptSetupRanges.emits.define?.typeArg;
if (typeArg) {
yield ` & `;
yield scriptSetup.content.slice(typeArg.start, typeArg.end);
}
yield `,${newLine}`;
}
}
6 changes: 4 additions & 2 deletions packages/language-core/lib/codegen/script/globalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ declare global {
? `import('${vueCompilerOptions.lib}/jsx-runtime').JSX.Element;`
: `globalThis.JSX.Element;`
}
type __VLS_GlobalComponents = import('${vueCompilerOptions.lib}').GlobalComponents
& Pick<typeof import('${vueCompilerOptions.lib}'), 'Transition' | 'TransitionGroup' | 'KeepAlive' | 'Suspense' | 'Teleport'>;
type __VLS_GlobalComponents = ${vueCompilerOptions.target >= 3.5
? `import('${vueCompilerOptions.lib}').GlobalComponents`
: `import('${vueCompilerOptions.lib}').GlobalComponents & Pick<typeof import('${vueCompilerOptions.lib}'), 'Transition' | 'TransitionGroup' | 'KeepAlive' | 'Suspense' | 'Teleport'>;`
}
type __VLS_BuiltInPublicProps = ${vueCompilerOptions.target >= 3.4
? `import('${vueCompilerOptions.lib}').PublicProps;`
: vueCompilerOptions.target >= 3.0
Expand Down
27 changes: 13 additions & 14 deletions packages/language-core/lib/codegen/script/scriptSetup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges';
import type { Code, Sfc } from '../../types';
import { endOfLine, generateSfcBlockSection, newLine } from '../common';
import { generateComponent } from './component';
import { generateComponent, generateEmitsOption } from './component';
import type { ScriptCodegenContext } from './context';
import { ScriptCodegenOptions, codeFeatures } from './index';
import { generateTemplate } from './template';
Expand Down Expand Up @@ -48,7 +48,7 @@ export function* generateScriptSetup(
+ ` __VLS_setup = (async () => {${newLine}`;
yield* generateSetupFunction(options, ctx, scriptSetup, scriptSetupRanges, undefined, definePropMirrors);

const emitTypes = ['typeof __VLS_modelEmitsType'];
const emitTypes = ['__VLS_ModelEmitsType'];

if (scriptSetupRanges.emits.define) {
emitTypes.unshift(`typeof ${scriptSetupRanges.emits.name ?? '__VLS_emit'}`);
Expand Down Expand Up @@ -265,14 +265,7 @@ function* generateComponentProps(
yield generateSfcBlockSection(scriptSetup, scriptSetupRanges.props.define.arg.start, scriptSetupRanges.props.define.arg.end, codeFeatures.navigation);
yield `,${newLine}`;
}
if (scriptSetupRanges.emits.define || scriptSetupRanges.defineProp.some(p => p.isModel)) {
yield ` emits: ({} as __VLS_NormalizeEmits<typeof __VLS_modelEmitsType`;
if (scriptSetupRanges.emits.define) {
yield ` & typeof `;
yield scriptSetupRanges.emits.name ?? '__VLS_emit';
}
yield `>),${newLine}`;
}
yield* generateEmitsOption(options, scriptSetup, scriptSetupRanges);
yield `})${endOfLine}`;
yield `let __VLS_functionalComponentProps!: `;
yield `${ctx.helperTypes.OmitKeepDiscriminatedUnion.name}<InstanceType<typeof __VLS_fnComponent>['$props'], keyof __VLS_BuiltInPublicProps>`;
Expand Down Expand Up @@ -371,10 +364,13 @@ function* generateModelEmits(
scriptSetup: NonNullable<Sfc['scriptSetup']>,
scriptSetupRanges: ScriptSetupRanges
): Generator<Code> {
yield `const __VLS_modelEmitsType = `;

yield `type __VLS_ModelEmitsType = `;
if (scriptSetupRanges.defineProp.filter(p => p.isModel).length) {
yield `(await import('${options.vueCompilerOptions.lib}')).defineEmits<{${newLine}`;
if (options.vueCompilerOptions.target < 3.5) {
yield `typeof __VLS_modelEmitsType${endOfLine}`;
yield `const __VLS_modelEmitsType = (await import('${options.vueCompilerOptions.lib}')).defineEmits<`;
}
yield `{${newLine}`;
for (const defineProp of scriptSetupRanges.defineProp) {
if (!defineProp.isModel) {
continue;
Expand All @@ -394,7 +390,10 @@ function* generateModelEmits(
}
yield `]${endOfLine}`;
}
yield `}>()`;
yield `}`;
if (options.vueCompilerOptions.target < 3.5) {
yield `>()`;
}
} else {
yield `{}`;
}
Expand Down
12 changes: 11 additions & 1 deletion packages/language-core/lib/parsers/scriptSetupRanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export function parseScriptSetupRanges(
} = {};
const emits: {
name?: string;
define?: ReturnType<typeof parseDefineFunction>;
define?: ReturnType<typeof parseDefineFunction> & {
hasUnionTypeArg?: boolean;
};
} = {};
const expose: {
name?: string;
Expand Down Expand Up @@ -216,6 +218,14 @@ export function parseScriptSetupRanges(
if (ts.isVariableDeclaration(parent)) {
emits.name = getNodeText(ts, parent.name, ast);
}
if (node.typeArguments?.length && ts.isTypeLiteralNode(node.typeArguments[0]) && node.typeArguments[0].members.at(0)) {
for (const member of node.typeArguments[0].members) {
if (ts.isCallSignatureDeclaration(member) && member.parameters[0].type && ts.isUnionTypeNode(member.parameters[0].type)) {
emits.define.hasUnionTypeArg = true;
return;
}
}
}
}
else if (vueCompilerOptions.macros.defineExpose.includes(callText)) {
expose.define = parseDefineFunction(node);
Expand Down
Loading

0 comments on commit 8d28afc

Please sign in to comment.