Skip to content

Commit

Permalink
feat: add option to simplify script setup virtual code for js
Browse files Browse the repository at this point in the history
close #1192
  • Loading branch information
johnsoncodehk committed May 15, 2022
1 parent 7d257ed commit a78acac
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 46 deletions.
Expand Up @@ -24,6 +24,14 @@
],
"markdownDescription": "Implicit wrap object literal component options export with `defineComponent()`."
},
"experimentalDowngradePropsAndEmitsToSetupReturnOnScriptSetup": {
"enum": [
true,
false,
"onlyJs"
],
"markdownDescription": "https://github.com/johnsoncodehk/volar/issues/1192"
},
"experimentalTemplateCompilerOptions": {
"type": "object",
"markdownDescription": "https://github.com/johnsoncodehk/volar/issues/576"
Expand Down
138 changes: 95 additions & 43 deletions packages/vue-code-gen/src/generators/script.ts
Expand Up @@ -23,6 +23,7 @@ export function generate(
getStyleBindTexts: () => string[],
vueLibName: string,
shimComponentOptions: boolean,
downgradePropsAndEmitsToSetupReturnOnScriptSetup: boolean,
) {

const codeGen = new CodeGen<EmbeddedFileMappingData>();
Expand Down Expand Up @@ -268,7 +269,7 @@ export function generate(
},
);

if (scriptSetupRanges?.withDefaultsArg) {
if (scriptSetupRanges.propsTypeArg && scriptSetupRanges?.withDefaultsArg) {
// fix https://github.com/johnsoncodehk/volar/issues/1187
codeGen.addText(`const __VLS_withDefaultsArg = (<T>(t: T) => t)(`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.withDefaultsArg.start, scriptSetupRanges.withDefaultsArg.end);
Expand All @@ -285,42 +286,44 @@ export function generate(
codeGen.addText(`),\n`);
}
if (scriptSetup && scriptSetupRanges) {
if (scriptSetupRanges.propsRuntimeArg || scriptSetupRanges.propsTypeArg) {
codeGen.addText(`props: (`);
if (scriptSetupRanges.propsTypeArg) {
if (!downgradePropsAndEmitsToSetupReturnOnScriptSetup) {
if (scriptSetupRanges.propsRuntimeArg || scriptSetupRanges.propsTypeArg) {
codeGen.addText(`props: (`);
if (scriptSetupRanges.propsTypeArg) {

usedTypes.DefinePropsToOptions = true;
codeGen.addText(`{} as `);
usedTypes.DefinePropsToOptions = true;
codeGen.addText(`{} as `);

if (scriptSetupRanges.withDefaultsArg) {
usedTypes.mergePropDefaults = true;
codeGen.addText(`__VLS_WithDefaults<`);
}
if (scriptSetupRanges.withDefaultsArg) {
usedTypes.mergePropDefaults = true;
codeGen.addText(`__VLS_WithDefaults<`);
}

codeGen.addText(`__VLS_TypePropsToRuntimeProps<`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsTypeArg.start, scriptSetupRanges.propsTypeArg.end);
codeGen.addText(`>`);

if (scriptSetupRanges.withDefaultsArg) {
codeGen.addText(`, typeof __VLS_withDefaultsArg`);
codeGen.addText(`__VLS_TypePropsToRuntimeProps<`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsTypeArg.start, scriptSetupRanges.propsTypeArg.end);
codeGen.addText(`>`);

if (scriptSetupRanges.withDefaultsArg) {
codeGen.addText(`, typeof __VLS_withDefaultsArg`);
codeGen.addText(`>`);
}
}
else if (scriptSetupRanges.propsRuntimeArg) {
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsRuntimeArg.start, scriptSetupRanges.propsRuntimeArg.end);
}
codeGen.addText(`),\n`);
}
else if (scriptSetupRanges.propsRuntimeArg) {
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsRuntimeArg.start, scriptSetupRanges.propsRuntimeArg.end);
if (scriptSetupRanges.emitsTypeArg) {
usedTypes.ConstructorOverloads = true;
codeGen.addText(`emits: ({} as __VLS_UnionToIntersection<__VLS_ConstructorOverloads<`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.emitsTypeArg.start, scriptSetupRanges.emitsTypeArg.end);
codeGen.addText(`>>),\n`);
}
else if (scriptSetupRanges.emitsRuntimeArg) {
codeGen.addText(`emits: (`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.emitsRuntimeArg.start, scriptSetupRanges.emitsRuntimeArg.end);
codeGen.addText(`),\n`);
}
codeGen.addText(`),\n`);
}
if (scriptSetupRanges.emitsTypeArg) {
usedTypes.ConstructorOverloads = true;
codeGen.addText(`emits: ({} as __VLS_UnionToIntersection<__VLS_ConstructorOverloads<`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.emitsTypeArg.start, scriptSetupRanges.emitsTypeArg.end);
codeGen.addText(`>>),\n`);
}
else if (scriptSetupRanges.emitsRuntimeArg) {
codeGen.addText(`emits: (`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.emitsRuntimeArg.start, scriptSetupRanges.emitsRuntimeArg.end);
codeGen.addText(`),\n`);
}
const bindingsArr: {
bindings: { start: number, end: number; }[],
Expand Down Expand Up @@ -352,24 +355,72 @@ export function generate(
}
writeTemplate();
codeGen.addText(`};\n`);
}

if (scriptSetupRanges.exposeTypeArg) {
codeGen.addText(`return { } as `);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.exposeTypeArg.start, scriptSetupRanges.exposeTypeArg.end);
codeGen.addText(`;\n`);
codeGen.addText(`return {\n`);

if (downgradePropsAndEmitsToSetupReturnOnScriptSetup) {
// fill $props
if (scriptSetupRanges.propsTypeArg) {
// NOTE: defineProps is inaccurate for $props
codeGen.addText(`$props: defineProps<`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsTypeArg.start, scriptSetupRanges.propsTypeArg.end);
codeGen.addText(`>(),\n`);
}
else if (scriptSetupRanges.exposeRuntimeArg) {
codeGen.addText(`return `);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.exposeRuntimeArg.start, scriptSetupRanges.exposeRuntimeArg.end);
codeGen.addText(`;\n`);
else if (scriptSetupRanges.propsRuntimeArg) {
// NOTE: defineProps is inaccurate for $props
codeGen.addText(`$props: defineProps(`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsRuntimeArg.start, scriptSetupRanges.propsRuntimeArg.end);
codeGen.addText(`),\n`);
}
// fill $emit
if (scriptSetupRanges.emitsAssignName) {
codeGen.addText(`$emit: ${scriptSetupRanges.emitsAssignName},\n`);
}
else if (scriptSetupRanges.emitsTypeArg) {
codeGen.addText(`$emit: defineEmits<`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.emitsTypeArg.start, scriptSetupRanges.emitsTypeArg.end);
codeGen.addText(`>(),\n`);
}
else if (scriptSetupRanges.emitsRuntimeArg) {
codeGen.addText(`$emit: defineEmits(`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.emitsRuntimeArg.start, scriptSetupRanges.emitsRuntimeArg.end);
codeGen.addText(`),\n`);
}
else {
codeGen.addText(`return { };\n`);
};
}

if (lsType === 'script') {
if (scriptSetupRanges.exposeRuntimeArg) {
codeGen.addText(`...(`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.exposeRuntimeArg.start, scriptSetupRanges.exposeRuntimeArg.end);
codeGen.addText(`),\n`);
}
if (scriptSetupRanges.exposeTypeArg) {
codeGen.addText(`...({} as `);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.exposeTypeArg.start, scriptSetupRanges.exposeTypeArg.end);
codeGen.addText(`),\n`);
}
}
if (lsType === 'template') {
codeGen.addText(`return {\n`);
// fill ctx from props
if (downgradePropsAndEmitsToSetupReturnOnScriptSetup) {
if (scriptSetupRanges.propsAssignName) {
codeGen.addText(`...${scriptSetupRanges.propsAssignName},\n`);
}
else if (scriptSetupRanges.withDefaultsArg && scriptSetupRanges.propsTypeArg) {
codeGen.addText(`...withDefaults(defineProps<`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsTypeArg.start, scriptSetupRanges.propsTypeArg.end);
codeGen.addText(`>(), `);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.withDefaultsArg.start, scriptSetupRanges.withDefaultsArg.end);
codeGen.addText(`),\n`);
}
else if (scriptSetupRanges.propsRuntimeArg) {
codeGen.addText(`...defineProps(`);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsRuntimeArg.start, scriptSetupRanges.propsRuntimeArg.end);
codeGen.addText(`),\n`);
}
}
// bindings
for (const { bindings, content } of bindingsArr) {
for (const expose of bindings) {
const varName = content.substring(expose.start, expose.end);
Expand Down Expand Up @@ -401,8 +452,9 @@ export function generate(
});
}
}
codeGen.addText(`};\n`);
}
codeGen.addText(`};\n`);

codeGen.addText(`},\n`);
}

Expand Down
2 changes: 2 additions & 0 deletions packages/vue-code-gen/src/index.ts
Expand Up @@ -19,6 +19,7 @@ export function generateSFCScriptTypeCheckCode(
scriptCode: string | undefined,
scriptSetupCode: string | undefined,
shimComponentOptions: boolean,
downgradePropsAndEmitsToSetupReturnOnScriptSetup: boolean,
templateAst?: CompilerDOM.RootNode,
cssVars?: string[],
vueLibName = 'vue',
Expand All @@ -45,6 +46,7 @@ export function generateSFCScriptTypeCheckCode(
() => cssVars ?? [],
vueLibName,
shimComponentOptions,
downgradePropsAndEmitsToSetupReturnOnScriptSetup,
);

return {
Expand Down
25 changes: 22 additions & 3 deletions packages/vue-code-gen/src/parsers/scriptSetupRanges.ts
Expand Up @@ -9,8 +9,10 @@ export function parseScriptSetupRanges(ts: typeof import('typescript/lib/tsserve
let notOnTopTypeExports: TextRange[] = [];
let importSectionEndOffset = 0;
let withDefaultsArg: TextRange | undefined;
let propsAssignName: string | undefined;
let propsRuntimeArg: TextRange | undefined;
let propsTypeArg: TextRange | undefined;
let emitsAssignName: string | undefined;
let emitsRuntimeArg: TextRange | undefined;
let emitsTypeArg: TextRange | undefined;
let exposeRuntimeArg: TextRange | undefined;
Expand All @@ -37,16 +39,18 @@ export function parseScriptSetupRanges(ts: typeof import('typescript/lib/tsserve
notOnTopTypeExports.push(_getStartEnd(node));
}
});
ast.forEachChild(visitNode);
ast.forEachChild(child => visitNode(child, ast));

return {
importSectionEndOffset,
notOnTopTypeExports,
bindings,
typeBindings,
withDefaultsArg,
propsAssignName,
propsRuntimeArg,
propsTypeArg,
emitsAssignName,
emitsRuntimeArg,
emitsTypeArg,
emitsTypeNums,
Expand All @@ -57,7 +61,7 @@ export function parseScriptSetupRanges(ts: typeof import('typescript/lib/tsserve
function _getStartEnd(node: ts.Node) {
return getStartEnd(node, ast);
}
function visitNode(node: ts.Node) {
function visitNode(node: ts.Node, parent: ts.Node) {
if (
ts.isCallExpression(node)
&& ts.isIdentifier(node.expression)
Expand All @@ -68,9 +72,15 @@ export function parseScriptSetupRanges(ts: typeof import('typescript/lib/tsserve
const runtimeArg = node.arguments[0];
if (callText === 'defineProps') {
propsRuntimeArg = _getStartEnd(runtimeArg);
if (ts.isVariableDeclaration(parent)) {
propsAssignName = parent.name.getText(ast);
}
}
else if (callText === 'defineEmits') {
emitsRuntimeArg = _getStartEnd(runtimeArg);
if (ts.isVariableDeclaration(parent)) {
emitsAssignName = parent.name.getText(ast);
}
}
else if (callText === 'defineExpose') {
exposeRuntimeArg = _getStartEnd(runtimeArg);
Expand All @@ -80,12 +90,18 @@ export function parseScriptSetupRanges(ts: typeof import('typescript/lib/tsserve
const typeArg = node.typeArguments[0];
if (callText === 'defineProps') {
propsTypeArg = _getStartEnd(typeArg);
if (ts.isVariableDeclaration(parent)) {
propsAssignName = parent.name.getText(ast);
}
}
else if (callText === 'defineEmits') {
emitsTypeArg = _getStartEnd(typeArg);
if (ts.isTypeLiteralNode(typeArg)) {
emitsTypeNums = typeArg.members.length;
}
if (ts.isVariableDeclaration(parent)) {
emitsAssignName = parent.name.getText(ast);
}
}
else if (callText === 'defineExpose') {
exposeTypeArg = _getStartEnd(typeArg);
Expand All @@ -97,9 +113,12 @@ export function parseScriptSetupRanges(ts: typeof import('typescript/lib/tsserve
const arg = node.arguments[1];
withDefaultsArg = _getStartEnd(arg);
}
if (ts.isVariableDeclaration(parent)) {
propsAssignName = parent.name.getText(ast);
}
}
}
node.forEachChild(child => visitNode(child));
node.forEachChild(child => visitNode(child, node));
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/vue-typescript/src/types.ts
Expand Up @@ -13,6 +13,7 @@ export interface ITemplateScriptData {
export interface VueCompilerOptions {
experimentalCompatMode?: 2 | 3;
experimentalImplicitWrapComponentOptionsWithDefineComponent?: boolean | 'onlyJs';
experimentalDowngradePropsAndEmitsToSetupReturnOnScriptSetup?: boolean | 'onlyJs';
experimentalTemplateCompilerOptions?: any;
experimentalTemplateCompilerOptionsRequirePath?: string;
experimentalDisableTemplateSupport?: boolean;
Expand Down
3 changes: 3 additions & 0 deletions packages/vue-typescript/src/use/useSfcScriptGen.ts
Expand Up @@ -49,6 +49,9 @@ export function useSfcScriptGen<T extends 'template' | 'script'>(
(compilerOptions.experimentalImplicitWrapComponentOptionsWithDefineComponent ?? 'onlyJs') === 'onlyJs'
? lang.value === 'js' || lang.value === 'jsx'
: !!compilerOptions.experimentalImplicitWrapComponentOptionsWithDefineComponent,
(compilerOptions.experimentalDowngradePropsAndEmitsToSetupReturnOnScriptSetup ?? 'onlyJs') === 'onlyJs'
? lang.value === 'js' || lang.value === 'jsx'
: !!compilerOptions.experimentalDowngradePropsAndEmitsToSetupReturnOnScriptSetup,
)
);
const file = computed(() => {
Expand Down

0 comments on commit a78acac

Please sign in to comment.