Skip to content

Commit 5080fd9

Browse files
authored
fix(language-core): tolerate non-literal export default (#5675)
1 parent 1308528 commit 5080fd9

File tree

8 files changed

+82
-57
lines changed

8 files changed

+82
-57
lines changed

packages/language-core/lib/codegen/script/component.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ export function* generateComponent(
1313
scriptSetupRanges: ScriptSetupRanges,
1414
): Generator<Code> {
1515
if (
16-
options.sfc.script && options.scriptRanges?.exportDefault
17-
&& options.scriptRanges.exportDefault.expression.start !== options.scriptRanges.exportDefault.args.start
16+
options.sfc.script
17+
&& options.scriptRanges?.componentOptions
18+
&& options.scriptRanges.componentOptions.expression.start !== options.scriptRanges.componentOptions.args.start
1819
) {
1920
// use defineComponent() from user space code if it exist
2021
yield generateSfcBlockSection(
2122
options.sfc.script,
22-
options.scriptRanges.exportDefault.expression.start,
23-
options.scriptRanges.exportDefault.args.start,
23+
options.scriptRanges.componentOptions.expression.start,
24+
options.scriptRanges.componentOptions.args.start,
2425
codeFeatures.all,
2526
);
2627
yield `{${newLine}`;
@@ -70,8 +71,8 @@ export function* generateComponent(
7071
) {
7172
yield `__typeEl: {} as __VLS_RootEl,${newLine}`;
7273
}
73-
if (options.sfc.script && options.scriptRanges?.exportDefault?.args) {
74-
const { args } = options.scriptRanges.exportDefault;
74+
if (options.sfc.script && options.scriptRanges?.componentOptions?.args) {
75+
const { args } = options.scriptRanges.componentOptions;
7576
yield generateSfcBlockSection(options.sfc.script, args.start + 1, args.end - 1, codeFeatures.all);
7677
}
7778
yield `})`;

packages/language-core/lib/codegen/script/index.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function* generateScript(
4848
yield* generateScriptSetupImports(options.sfc.scriptSetup, options.scriptSetupRanges);
4949
}
5050
if (options.sfc.script && options.scriptRanges) {
51-
const { exportDefault } = options.scriptRanges;
51+
const exportDefault = options.scriptRanges.componentOptions ?? options.scriptRanges.exportDefault;
5252
if (options.sfc.scriptSetup && options.scriptSetupRanges) {
5353
if (exportDefault) {
5454
yield generateSfcBlockSection(options.sfc.script, 0, exportDefault.start, codeFeatures.all);
@@ -149,9 +149,7 @@ export function* generateConstExport(
149149
if (options.sfc.script) {
150150
yield* generatePartiallyEnding(
151151
options.sfc.script.name,
152-
options.scriptRanges?.exportDefault
153-
? options.scriptRanges.exportDefault.start
154-
: options.sfc.script.content.length,
152+
options.scriptRanges?.componentOptions?.start ?? options.sfc.script.content.length,
155153
'#3632/script.vue',
156154
);
157155
}
@@ -175,16 +173,16 @@ function* generateExportDefault(options: ScriptCodegenOptions): Generator<Code>
175173
let prefix: Code;
176174
let suffix: Code;
177175
if (options.sfc.script && options.scriptRanges?.exportDefault) {
178-
const { exportDefault } = options.scriptRanges;
176+
const { exportDefault, componentOptions } = options.scriptRanges;
179177
prefix = generateSfcBlockSection(
180178
options.sfc.script,
181179
exportDefault.start,
182-
exportDefault.expression.start,
180+
(componentOptions ?? exportDefault).expression.start,
183181
codeFeatures.all,
184182
);
185183
suffix = generateSfcBlockSection(
186184
options.sfc.script,
187-
exportDefault.expression.end,
185+
(componentOptions ?? exportDefault).expression.end,
188186
options.sfc.script.content.length,
189187
codeFeatures.all,
190188
);

packages/language-core/lib/codegen/script/template.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,18 @@ export function* generateTemplate(
2727
}
2828

2929
function* generateSelf(options: ScriptCodegenOptions): Generator<Code> {
30-
if (options.sfc.script && options.scriptRanges?.exportDefault) {
30+
if (options.sfc.script && options.scriptRanges?.componentOptions) {
3131
yield `const __VLS_self = (await import('${options.vueCompilerOptions.lib}')).defineComponent(`;
32-
const { args } = options.scriptRanges.exportDefault;
32+
const { args } = options.scriptRanges.componentOptions;
3333
yield generateSfcBlockSection(options.sfc.script, args.start, args.end, codeFeatures.all);
3434
yield `)${endOfLine}`;
3535
}
36+
else if (options.sfc.script && options.scriptRanges?.exportDefault) {
37+
yield `const __VLS_self = `;
38+
const { expression } = options.scriptRanges.exportDefault;
39+
yield generateSfcBlockSection(options.sfc.script, expression.start, expression.end, codeFeatures.all);
40+
yield endOfLine;
41+
}
3642
else if (options.sfc.script?.src) {
3743
yield `let __VLS_self!: typeof import('./${path.basename(options.fileName)}').default${endOfLine}`;
3844
}
@@ -110,13 +116,13 @@ function* generateTemplateElements(): Generator<Code> {
110116
function* generateTemplateComponents(options: ScriptCodegenOptions): Generator<Code> {
111117
const types: string[] = [`typeof __VLS_ctx`];
112118

113-
if (options.sfc.script && options.scriptRanges?.exportDefault?.componentsOption) {
114-
const { componentsOption } = options.scriptRanges.exportDefault;
119+
if (options.sfc.script && options.scriptRanges?.componentOptions?.components) {
120+
const { components } = options.scriptRanges.componentOptions;
115121
yield `const __VLS_componentsOption = `;
116122
yield generateSfcBlockSection(
117123
options.sfc.script,
118-
componentsOption.start,
119-
componentsOption.end,
124+
components.start,
125+
components.end,
120126
codeFeatures.navigation,
121127
);
122128
yield endOfLine;
@@ -130,13 +136,13 @@ function* generateTemplateComponents(options: ScriptCodegenOptions): Generator<C
130136
function* generateTemplateDirectives(options: ScriptCodegenOptions): Generator<Code> {
131137
const types: string[] = [`typeof __VLS_ctx`];
132138

133-
if (options.sfc.script && options.scriptRanges?.exportDefault?.directivesOption) {
134-
const { directivesOption } = options.scriptRanges.exportDefault;
139+
if (options.sfc.script && options.scriptRanges?.componentOptions?.directives) {
140+
const { directives } = options.scriptRanges.componentOptions;
135141
yield `const __VLS_directivesOption = `;
136142
yield generateSfcBlockSection(
137143
options.sfc.script,
138-
directivesOption.start,
139-
directivesOption.end,
144+
directives.start,
145+
directives.end,
140146
codeFeatures.navigation,
141147
);
142148
yield endOfLine;

packages/language-core/lib/parsers/scriptRanges.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,32 @@ export interface ScriptRanges extends ReturnType<typeof parseScriptRanges> {}
77

88
export function parseScriptRanges(ts: typeof import('typescript'), ast: ts.SourceFile, hasScriptSetup: boolean) {
99
let exportDefault:
10-
| (TextRange & {
10+
| TextRange & {
11+
expression: TextRange;
12+
}
13+
| undefined;
14+
let componentOptions:
15+
| TextRange & {
1116
expression: TextRange;
1217
args: TextRange;
1318
argsNode: ts.ObjectLiteralExpression;
14-
componentsOption: TextRange | undefined;
15-
componentsOptionNode: ts.ObjectLiteralExpression | undefined;
16-
directivesOption: TextRange | undefined;
17-
nameOption: TextRange | undefined;
18-
inheritAttrsOption: string | undefined;
19-
})
19+
components: TextRange | undefined;
20+
componentsNode: ts.ObjectLiteralExpression | undefined;
21+
directives: TextRange | undefined;
22+
name: TextRange | undefined;
23+
inheritAttrs: string | undefined;
24+
}
2025
| undefined;
2126

2227
const bindings = hasScriptSetup ? parseBindingRanges(ts, ast) : [];
2328

2429
ts.forEachChild(ast, raw => {
2530
if (ts.isExportAssignment(raw)) {
31+
exportDefault = {
32+
..._getStartEnd(raw),
33+
expression: _getStartEnd(raw.expression),
34+
};
35+
2636
let node: ts.AsExpression | ts.ExportAssignment | ts.ParenthesizedExpression = raw;
2737
while (isAsExpression(node.expression) || ts.isParenthesizedExpression(node.expression)) { // fix https://github.com/vuejs/language-tools/issues/1882
2838
node = node.expression;
@@ -60,27 +70,28 @@ export function parseScriptRanges(ts: typeof import('typescript'), ast: ts.Sourc
6070
}
6171
}
6272
});
63-
exportDefault = {
73+
componentOptions = {
6474
..._getStartEnd(raw),
6575
expression: _getStartEnd(node.expression),
6676
args: _getStartEnd(obj),
6777
argsNode: obj,
68-
componentsOption: componentsOptionNode ? _getStartEnd(componentsOptionNode) : undefined,
69-
componentsOptionNode,
70-
directivesOption: directivesOptionNode ? _getStartEnd(directivesOptionNode) : undefined,
71-
nameOption: nameOptionNode ? _getStartEnd(nameOptionNode) : undefined,
72-
inheritAttrsOption,
78+
components: componentsOptionNode ? _getStartEnd(componentsOptionNode) : undefined,
79+
componentsNode: componentsOptionNode,
80+
directives: directivesOptionNode ? _getStartEnd(directivesOptionNode) : undefined,
81+
name: nameOptionNode ? _getStartEnd(nameOptionNode) : undefined,
82+
inheritAttrs: inheritAttrsOption,
7383
};
7484
const comment = getClosestMultiLineCommentRange(ts, raw, [], ast);
7585
if (comment) {
76-
exportDefault.start = comment.start;
86+
componentOptions.start = comment.start;
7787
}
7888
}
7989
}
8090
});
8191

8292
return {
8393
exportDefault,
94+
componentOptions,
8495
bindings,
8596
};
8697

packages/language-core/lib/plugins/vue-tsx.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,17 +154,17 @@ function createTsx(
154154

155155
const getSetupInheritAttrs = computed(() => {
156156
const value = getScriptSetupRanges()?.defineOptions?.inheritAttrs
157-
?? getScriptRanges()?.exportDefault?.inheritAttrsOption;
157+
?? getScriptRanges()?.componentOptions?.inheritAttrs;
158158
return value !== 'false';
159159
});
160160

161161
const getComponentSelfName = computed(() => {
162162
let name: string;
163-
const { exportDefault } = getScriptRanges() ?? {};
164-
if (sfc.script && exportDefault?.nameOption) {
163+
const { componentOptions } = getScriptRanges() ?? {};
164+
if (sfc.script && componentOptions?.name) {
165165
name = sfc.script.content.slice(
166-
exportDefault.nameOption.start + 1,
167-
exportDefault.nameOption.end - 1,
166+
componentOptions.name.start + 1,
167+
componentOptions.name.end - 1,
168168
);
169169
}
170170
else {

packages/language-server/tests/definitions.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,13 @@ test('#2600', async () => {
105105
[
106106
{
107107
"end": {
108-
"line": 1,
109-
"offset": 1,
108+
"line": 8,
109+
"offset": 3,
110110
},
111111
"file": "\${testWorkspacePath}/tsconfigProject/foo.vue",
112112
"start": {
113-
"line": 1,
114-
"offset": 1,
113+
"line": 7,
114+
"offset": 3,
115115
},
116116
},
117117
]

packages/language-service/lib/plugins/vue-extract-file.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -300,38 +300,38 @@ export function createAddComponentToOptionEdit(
300300
componentName: string,
301301
) {
302302
const scriptRanges = tsCodegen.get(sfc)?.getScriptRanges();
303-
if (!scriptRanges?.exportDefault) {
303+
if (!scriptRanges?.componentOptions) {
304304
return;
305305
}
306-
const { exportDefault } = scriptRanges;
306+
const { componentOptions } = scriptRanges;
307307

308308
// https://github.com/microsoft/TypeScript/issues/36174
309309
const printer = ts.createPrinter();
310-
if (exportDefault.componentsOption && exportDefault.componentsOptionNode) {
311-
const newNode: typeof exportDefault.componentsOptionNode = {
312-
...exportDefault.componentsOptionNode,
310+
if (componentOptions.components && componentOptions.componentsNode) {
311+
const newNode: typeof componentOptions.componentsNode = {
312+
...componentOptions.componentsNode,
313313
properties: [
314-
...exportDefault.componentsOptionNode.properties,
314+
...componentOptions.componentsNode.properties,
315315
ts.factory.createShorthandPropertyAssignment(componentName),
316316
] as any as ts.NodeArray<ts.ObjectLiteralElementLike>,
317317
};
318318
const printText = printer.printNode(ts.EmitHint.Expression, newNode, ast);
319319
return {
320-
range: exportDefault.componentsOption,
320+
range: componentOptions.components,
321321
newText: unescape(printText.replace(unicodeReg, '%u')),
322322
};
323323
}
324324
else {
325-
const newNode: typeof exportDefault.argsNode = {
326-
...exportDefault.argsNode,
325+
const newNode: typeof componentOptions.argsNode = {
326+
...componentOptions.argsNode,
327327
properties: [
328-
...exportDefault.argsNode.properties,
328+
...componentOptions.argsNode.properties,
329329
ts.factory.createShorthandPropertyAssignment(`components: { ${componentName} }`),
330330
] as any as ts.NodeArray<ts.ObjectLiteralElementLike>,
331331
};
332332
const printText = printer.printNode(ts.EmitHint.Expression, newNode, ast);
333333
return {
334-
range: exportDefault.args,
334+
range: componentOptions.args,
335335
newText: unescape(printText.replace(unicodeReg, '%u')),
336336
};
337337
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script lang="ts">
2+
import { defineComponent } from 'vue';
3+
4+
const component = defineComponent({});
5+
6+
export default component;
7+
</script>
8+
9+
<script setup lang="ts"></script>

0 commit comments

Comments
 (0)