Skip to content

Commit 47ae752

Browse files
authored
refactor: improve string export name completions (#58818)
1 parent e7410ce commit 47ae752

File tree

2 files changed

+38
-15
lines changed

2 files changed

+38
-15
lines changed

src/services/completions.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ import {
336336
rangeContainsPosition,
337337
rangeContainsPositionExclusive,
338338
rangeIsOnSingleLine,
339+
scanner,
339340
ScriptElementKind,
340341
ScriptElementKindModifier,
341342
ScriptTarget,
@@ -1889,9 +1890,16 @@ function createCompletionEntry(
18891890
if (parentNamedImportOrExport) {
18901891
const languageVersion = getEmitScriptTarget(host.getCompilationSettings());
18911892
if (!isIdentifierText(name, languageVersion)) {
1892-
insertText = JSON.stringify(name);
1893+
insertText = quotePropertyName(sourceFile, preferences, name);
1894+
18931895
if (parentNamedImportOrExport.kind === SyntaxKind.NamedImports) {
1894-
insertText += " as " + generateIdentifierForArbitraryString(name, languageVersion);
1896+
// check if it is import { ^here as name } from '...'
1897+
// we have to access the scanner here to check if it is { ^here as name } or { ^here, as, name }.
1898+
scanner.setText(sourceFile.text);
1899+
scanner.resetTokenState(position);
1900+
if (!(scanner.scan() === SyntaxKind.AsKeyword && scanner.scan() === SyntaxKind.Identifier)) {
1901+
insertText += " as " + generateIdentifierForArbitraryString(name, languageVersion);
1902+
}
18951903
}
18961904
}
18971905
else if (parentNamedImportOrExport.kind === SyntaxKind.NamedImports) {
@@ -4948,7 +4956,10 @@ function getCompletionData(
49484956
return !isFromObjectTypeDeclaration(contextToken);
49494957

49504958
case SyntaxKind.Identifier: {
4951-
if (containingNodeKind === SyntaxKind.ImportSpecifier &&
4959+
if ((
4960+
containingNodeKind === SyntaxKind.ImportSpecifier ||
4961+
containingNodeKind === SyntaxKind.ExportSpecifier
4962+
) &&
49524963
contextToken === (parent as ImportSpecifier).name &&
49534964
(contextToken as Identifier).text === "type"
49544965
) {

tests/cases/fourslash/completionsImportOrExportSpecifier.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@
44
//// export let foo = 1;
55
//// let someValue = 2;
66
//// let someType = 3;
7+
//// type someType2 = 4;
78
//// export {
89
//// someValue as "__some value",
910
//// someType as "__some type",
11+
//// type someType2 as "__some type2",
1012
//// };
1113

1214
// @Filename: values.ts
1315
//// import { /*valueImport0*/ } from "./exports";
1416
//// import { /*valueImport1*/ as valueImport1 } from "./exports";
1517
//// import { foo as /*valueImport2*/ } from "./exports";
1618
//// import { foo, /*valueImport3*/ as valueImport3 } from "./exports";
19+
//// import * as _a from "./exports";
20+
//// _a./*namespaceImport1*/;
1721
////
1822
//// export { /*valueExport0*/ } from "./exports";
1923
//// export { /*valueExport1*/ as valueExport1 } from "./exports";
@@ -25,34 +29,42 @@
2529
//// import { type /*typeImport1*/ as typeImport1 } from "./exports";
2630
//// import { type foo as /*typeImport2*/ } from "./exports";
2731
//// import { type foo, type /*typeImport3*/ as typeImport3 } from "./exports";
32+
//// import * as _a from "./exports";
2833
////
2934
//// export { type /*typeExport0*/ } from "./exports";
3035
//// export { type /*typeExport1*/ as typeExport1 } from "./exports";
3136
//// export { type foo as /*typeExport2*/ } from "./exports";
3237
//// export { type foo, type /*typeExport3*/ } from "./exports";
3338

3439
const __some_type = { name: "__some type", insertText: '"__some type"' }
40+
const __some_type2 = { name: "__some type2", insertText: '"__some type2"' }
3541
const __some_value = { name: "__some value", insertText: '"__some value"' }
3642
const __some_type_as = { name: "__some type", insertText: '"__some type" as __some_type' }
43+
const __some_type_squared = { name: "__some type", insertText: '["__some type"]' }
44+
const __some_type2_as = { name: "__some type2", insertText: '"__some type2" as __some_type2' }
45+
const __some_type2_squared = { name: "__some type2", insertText: '["__some type2"]' }
3746
const __some_value_as = { name: "__some value", insertText: '"__some value" as __some_value' }
47+
const __some_value_squared = { name: "__some value", insertText: '["__some value"]' }
3848
const typeKeyword = { name: "type", sortText: completion.SortText.GlobalsOrKeywords }
3949

40-
verify.completions({ marker: "valueImport0", exact: [__some_type_as, __some_value_as, "foo", typeKeyword] });
41-
verify.completions({ marker: "valueImport1", exact: [__some_type_as, __some_value_as, "foo", typeKeyword] });
50+
verify.completions({ marker: "valueImport0", exact: [__some_type_as, __some_type2_as, __some_value_as, "foo", typeKeyword] });
51+
verify.completions({ marker: "valueImport1", exact: [__some_type, __some_type2, __some_value, "foo", typeKeyword] });
4252
verify.completions({ marker: "valueImport2", exact: [] });
43-
verify.completions({ marker: "valueImport3", exact: [__some_type_as, __some_value_as, typeKeyword] });
53+
verify.completions({ marker: "valueImport3", exact: [__some_type, __some_type2, __some_value, typeKeyword] });
54+
// see https://github.com/microsoft/TypeScript/issues/58815
55+
verify.completions({ marker: 'namespaceImport1', exact: [/* __some_type_squared, __some_value_squared, */ 'foo'] })
4456

45-
verify.completions({ marker: "valueExport0", exact: [__some_type, __some_value, "foo", typeKeyword] });
46-
verify.completions({ marker: "valueExport1", exact: [__some_type, __some_value, "foo", typeKeyword] });
57+
verify.completions({ marker: "valueExport0", exact: [__some_type, __some_type2, __some_value, "foo", typeKeyword] });
58+
verify.completions({ marker: "valueExport1", exact: [__some_type, __some_type2, __some_value, "foo", typeKeyword] });
4759
verify.completions({ marker: "valueExport2", exact: [] });
48-
verify.completions({ marker: "valueExport3", exact: [__some_type, __some_value, typeKeyword] });
60+
verify.completions({ marker: "valueExport3", exact: [__some_type, __some_type2, __some_value, typeKeyword] });
4961

50-
verify.completions({ marker: "typeImport0", exact: [__some_type_as, __some_value_as, "foo"] });
51-
verify.completions({ marker: "typeImport1", exact: [__some_type_as, __some_value_as, "foo"] });
62+
verify.completions({ marker: "typeImport0", exact: [__some_type_as, __some_type2_as, __some_value_as, "foo"] });
63+
verify.completions({ marker: "typeImport1", exact: [__some_type, __some_type2, __some_value, "foo"] });
5264
verify.completions({ marker: "typeImport2", exact: [] });
53-
verify.completions({ marker: "typeImport3", exact: [__some_type_as, __some_value_as] });
65+
verify.completions({ marker: "typeImport3", exact: [__some_type, __some_type2, __some_value] });
5466

55-
verify.completions({ marker: "typeExport0", exact: [] });
56-
verify.completions({ marker: "typeExport1", exact: [__some_type, __some_value, "foo"] });
67+
verify.completions({ marker: "typeExport0", exact: [__some_type, __some_type2, __some_value, "foo"] });
68+
verify.completions({ marker: "typeExport1", exact: [__some_type, __some_type2, __some_value, "foo"] });
5769
verify.completions({ marker: "typeExport2", exact: [] });
58-
verify.completions({ marker: "typeExport3", exact: [] });
70+
verify.completions({ marker: "typeExport3", exact: [__some_type, __some_type2, __some_value] });

0 commit comments

Comments
 (0)