Skip to content

Commit 2bcfed0

Browse files
authoredOct 13, 2022
feat(37440): Provide a quick-fix for non-exported types (#51038)
* feat(37440): add QF to handle missing exports * change diagnostic message * add type modifier only if isolatedModules is set or if the export declaration already uses type modifiers
1 parent a24201c commit 2bcfed0

27 files changed

+725
-35
lines changed
 

‎src/compiler/checker.ts

-31
Original file line numberDiff line numberDiff line change
@@ -7235,16 +7235,6 @@ namespace ts {
72357235
return statements;
72367236
}
72377237

7238-
function canHaveExportModifier(node: Statement): node is Extract<HasModifiers, Statement> {
7239-
return isEnumDeclaration(node) ||
7240-
isVariableStatement(node) ||
7241-
isFunctionDeclaration(node) ||
7242-
isClassDeclaration(node) ||
7243-
(isModuleDeclaration(node) && !isExternalModuleAugmentation(node) && !isGlobalScopeAugmentation(node)) ||
7244-
isInterfaceDeclaration(node) ||
7245-
isTypeDeclaration(node);
7246-
}
7247-
72487238
function addExportModifier(node: Extract<HasModifiers, Statement>) {
72497239
const flags = (getEffectiveModifierFlags(node) | ModifierFlags.Export) & ~ModifierFlags.Ambient;
72507240
return factory.updateModifiers(node, flags);
@@ -42691,27 +42681,6 @@ namespace ts {
4269142681
getNameOfDeclaration(name.parent) === name;
4269242682
}
4269342683

42694-
function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | EnumDeclaration | ImportClause | ImportSpecifier | ExportSpecifier {
42695-
switch (node.kind) {
42696-
case SyntaxKind.TypeParameter:
42697-
case SyntaxKind.ClassDeclaration:
42698-
case SyntaxKind.InterfaceDeclaration:
42699-
case SyntaxKind.TypeAliasDeclaration:
42700-
case SyntaxKind.EnumDeclaration:
42701-
case SyntaxKind.JSDocTypedefTag:
42702-
case SyntaxKind.JSDocCallbackTag:
42703-
case SyntaxKind.JSDocEnumTag:
42704-
return true;
42705-
case SyntaxKind.ImportClause:
42706-
return (node as ImportClause).isTypeOnly;
42707-
case SyntaxKind.ImportSpecifier:
42708-
case SyntaxKind.ExportSpecifier:
42709-
return (node as ImportSpecifier | ExportSpecifier).parent.parent.isTypeOnly;
42710-
default:
42711-
return false;
42712-
}
42713-
}
42714-
4271542684
// True if the given identifier is part of a type reference
4271642685
function isTypeReferenceIdentifier(node: EntityName): boolean {
4271742686
while (node.parent.kind === SyntaxKind.QualifiedName) {

‎src/compiler/diagnosticMessages.json

+8
Original file line numberDiff line numberDiff line change
@@ -6687,6 +6687,14 @@
66876687
"category": "Message",
66886688
"code": 90058
66896689
},
6690+
"Export '{0}' from module '{1}'": {
6691+
"category": "Message",
6692+
"code": 90059
6693+
},
6694+
"Export all referenced locals": {
6695+
"category": "Message",
6696+
"code": 90060
6697+
},
66906698

66916699
"Convert function to an ES2015 class": {
66926700
"category": "Message",

‎src/compiler/utilities.ts

+26
Original file line numberDiff line numberDiff line change
@@ -7752,4 +7752,30 @@ namespace ts {
77527752
export function getParameterTypeNode(parameter: ParameterDeclaration | JSDocParameterTag) {
77537753
return parameter.kind === SyntaxKind.JSDocParameterTag ? parameter.typeExpression?.type : parameter.type;
77547754
}
7755+
7756+
export function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | EnumDeclaration | ImportClause | ImportSpecifier | ExportSpecifier {
7757+
switch (node.kind) {
7758+
case SyntaxKind.TypeParameter:
7759+
case SyntaxKind.ClassDeclaration:
7760+
case SyntaxKind.InterfaceDeclaration:
7761+
case SyntaxKind.TypeAliasDeclaration:
7762+
case SyntaxKind.EnumDeclaration:
7763+
case SyntaxKind.JSDocTypedefTag:
7764+
case SyntaxKind.JSDocCallbackTag:
7765+
case SyntaxKind.JSDocEnumTag:
7766+
return true;
7767+
case SyntaxKind.ImportClause:
7768+
return (node as ImportClause).isTypeOnly;
7769+
case SyntaxKind.ImportSpecifier:
7770+
case SyntaxKind.ExportSpecifier:
7771+
return (node as ImportSpecifier | ExportSpecifier).parent.parent.isTypeOnly;
7772+
default:
7773+
return false;
7774+
}
7775+
}
7776+
7777+
export function canHaveExportModifier(node: Node): node is Extract<HasModifiers, Statement> {
7778+
return isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node)
7779+
|| isInterfaceDeclaration(node) || isTypeDeclaration(node) || (isModuleDeclaration(node) && !isExternalModuleAugmentation(node) && !isGlobalScopeAugmentation(node));
7780+
}
77557781
}

‎src/services/codefixes/fixAddMissingMember.ts

-4
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,6 @@ namespace ts.codefix {
264264
return undefined;
265265
}
266266

267-
function isSourceFileFromLibrary(program: Program, node: SourceFile) {
268-
return program.isSourceFileFromExternalLibrary(node) || program.isSourceFileDefaultLibrary(node);
269-
}
270-
271267
function getActionsForMissingMemberDeclaration(context: CodeFixContext, info: TypeLikeDeclarationInfo): CodeFixAction[] | undefined {
272268
return info.isJSFile ? singleElementArray(createActionForAddMissingMemberInJavascriptFile(context, info)) :
273269
createActionsForAddMissingMemberInTypeScriptFile(context, info);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/* @internal */
2+
namespace ts.codefix {
3+
const fixId = "fixImportNonExportedMember";
4+
const errorCodes = [
5+
Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported.code,
6+
];
7+
8+
registerCodeFix({
9+
errorCodes,
10+
fixIds: [fixId],
11+
getCodeActions(context) {
12+
const { sourceFile, span, program } = context;
13+
const info = getInfo(sourceFile, span.start, program);
14+
if (info === undefined) return undefined;
15+
16+
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, program, info));
17+
return [createCodeFixAction(fixId, changes, [Diagnostics.Export_0_from_module_1, info.exportName.node.text, info.moduleSpecifier], fixId, Diagnostics.Export_all_referenced_locals)];
18+
},
19+
getAllCodeActions(context) {
20+
const { program } = context;
21+
return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => {
22+
const exports = new Map<SourceFile, ModuleExports>();
23+
24+
eachDiagnostic(context, errorCodes, diag => {
25+
const info = getInfo(diag.file, diag.start, program);
26+
if (info === undefined) return undefined;
27+
28+
const { exportName, node, moduleSourceFile } = info;
29+
if (tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly) === undefined && canHaveExportModifier(node)) {
30+
changes.insertExportModifier(moduleSourceFile, node);
31+
}
32+
else {
33+
const moduleExports = exports.get(moduleSourceFile) || { typeOnlyExports: [], exports: [] };
34+
if (exportName.isTypeOnly) {
35+
moduleExports.typeOnlyExports.push(exportName);
36+
}
37+
else {
38+
moduleExports.exports.push(exportName);
39+
}
40+
exports.set(moduleSourceFile, moduleExports);
41+
}
42+
});
43+
44+
exports.forEach((moduleExports, moduleSourceFile) => {
45+
const exportDeclaration = tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ true);
46+
if (exportDeclaration && exportDeclaration.isTypeOnly) {
47+
doChanges(changes, program, moduleSourceFile, moduleExports.typeOnlyExports, exportDeclaration);
48+
doChanges(changes, program, moduleSourceFile, moduleExports.exports, tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ false));
49+
}
50+
else {
51+
doChanges(changes, program, moduleSourceFile, [...moduleExports.exports, ...moduleExports.typeOnlyExports], exportDeclaration);
52+
}
53+
});
54+
}));
55+
}
56+
});
57+
58+
interface ModuleExports {
59+
typeOnlyExports: ExportName[];
60+
exports: ExportName[];
61+
}
62+
63+
interface ExportName {
64+
node: Identifier;
65+
isTypeOnly: boolean;
66+
}
67+
68+
interface Info {
69+
exportName: ExportName;
70+
node: Declaration | VariableStatement;
71+
moduleSourceFile: SourceFile;
72+
moduleSpecifier: string;
73+
}
74+
75+
function getInfo(sourceFile: SourceFile, pos: number, program: Program): Info | undefined {
76+
const token = getTokenAtPosition(sourceFile, pos);
77+
if (isIdentifier(token)) {
78+
const importDeclaration = findAncestor(token, isImportDeclaration);
79+
if (importDeclaration === undefined) return undefined;
80+
81+
const moduleSpecifier = isStringLiteral(importDeclaration.moduleSpecifier) ? importDeclaration.moduleSpecifier.text : undefined;
82+
if (moduleSpecifier === undefined) return undefined;
83+
84+
const resolvedModule = getResolvedModule(sourceFile, moduleSpecifier, /*mode*/ undefined);
85+
if (resolvedModule === undefined) return undefined;
86+
87+
const moduleSourceFile = program.getSourceFile(resolvedModule.resolvedFileName);
88+
if (moduleSourceFile === undefined || isSourceFileFromLibrary(program, moduleSourceFile)) return undefined;
89+
90+
const moduleSymbol = moduleSourceFile.symbol;
91+
const locals = moduleSymbol.valueDeclaration?.locals;
92+
if (locals === undefined) return undefined;
93+
94+
const localSymbol = locals.get(token.escapedText);
95+
if (localSymbol === undefined) return undefined;
96+
97+
const node = getNodeOfSymbol(localSymbol);
98+
if (node === undefined) return undefined;
99+
100+
const exportName = { node: token, isTypeOnly: isTypeDeclaration(node) };
101+
return { exportName, node, moduleSourceFile, moduleSpecifier };
102+
}
103+
return undefined;
104+
}
105+
106+
function doChange(changes: textChanges.ChangeTracker, program: Program, { exportName, node, moduleSourceFile }: Info) {
107+
const exportDeclaration = tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly);
108+
if (exportDeclaration) {
109+
updateExport(changes, program, moduleSourceFile, exportDeclaration, [exportName]);
110+
}
111+
else if (canHaveExportModifier(node)) {
112+
changes.insertExportModifier(moduleSourceFile, node);
113+
}
114+
else {
115+
createExport(changes, program, moduleSourceFile, [exportName]);
116+
}
117+
}
118+
119+
function doChanges(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, moduleExports: ExportName[], node: ExportDeclaration | undefined) {
120+
if (length(moduleExports)) {
121+
if (node) {
122+
updateExport(changes, program, sourceFile, node, moduleExports);
123+
}
124+
else {
125+
createExport(changes, program, sourceFile, moduleExports);
126+
}
127+
}
128+
}
129+
130+
function tryGetExportDeclaration(sourceFile: SourceFile, isTypeOnly: boolean) {
131+
const predicate = (node: Node): node is ExportDeclaration =>
132+
isExportDeclaration(node) && (isTypeOnly && node.isTypeOnly || !node.isTypeOnly);
133+
return findLast(sourceFile.statements, predicate);
134+
}
135+
136+
function updateExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, node: ExportDeclaration, names: ExportName[]) {
137+
const namedExports = node.exportClause && isNamedExports(node.exportClause) ? node.exportClause.elements : factory.createNodeArray([]);
138+
const allowTypeModifier = !node.isTypeOnly && !!(program.getCompilerOptions().isolatedModules || find(namedExports, e => e.isTypeOnly));
139+
changes.replaceNode(sourceFile, node,
140+
factory.updateExportDeclaration(node, node.modifiers, node.isTypeOnly,
141+
factory.createNamedExports(
142+
factory.createNodeArray([...namedExports, ...createExportSpecifiers(names, allowTypeModifier)], /*hasTrailingComma*/ namedExports.hasTrailingComma)), node.moduleSpecifier, node.assertClause));
143+
}
144+
145+
function createExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, names: ExportName[]) {
146+
changes.insertNodeAtEndOfScope(sourceFile, sourceFile,
147+
factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false,
148+
factory.createNamedExports(createExportSpecifiers(names, /*allowTypeModifier*/ !!program.getCompilerOptions().isolatedModules)), /*moduleSpecifier*/ undefined, /*assertClause*/ undefined));
149+
}
150+
151+
function createExportSpecifiers(names: ExportName[], allowTypeModifier: boolean) {
152+
return factory.createNodeArray(map(names, n => factory.createExportSpecifier(allowTypeModifier && n.isTypeOnly, /*propertyName*/ undefined, n.node)));
153+
}
154+
155+
function getNodeOfSymbol(symbol: Symbol) {
156+
if (symbol.valueDeclaration === undefined) {
157+
return firstOrUndefined(symbol.declarations);
158+
}
159+
const declaration = symbol.valueDeclaration;
160+
const variableStatement = isVariableDeclaration(declaration) ? tryCast(declaration.parent.parent, isVariableStatement) : undefined;
161+
return variableStatement && length(variableStatement.declarationList.declarations) === 1 ? variableStatement : declaration;
162+
}
163+
}

‎src/services/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"codefixes/fixOverrideModifier.ts",
7272
"codefixes/fixNoPropertyAccessFromIndexSignature.ts",
7373
"codefixes/fixImplicitThis.ts",
74+
"codefixes/fixImportNonExportedMember.ts",
7475
"codefixes/fixIncorrectNamedTupleSyntax.ts",
7576
"codefixes/fixSpelling.ts",
7677
"codefixes/returnValueCorrect.ts",

‎src/services/utilities.ts

+4
Original file line numberDiff line numberDiff line change
@@ -3423,5 +3423,9 @@ namespace ts {
34233423
return jsx === JsxEmit.React || jsx === JsxEmit.ReactNative;
34243424
}
34253425

3426+
export function isSourceFileFromLibrary(program: Program, node: SourceFile) {
3427+
return program.isSourceFileFromExternalLibrary(node) || program.isSourceFileDefaultLibrary(node);
3428+
}
3429+
34263430
// #endregion
34273431
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////declare function foo(): any
6+
////declare function bar(): any;
7+
////export { foo };
8+
9+
// @filename: /b.ts
10+
////import { bar } from "./a";
11+
12+
goTo.file("/b.ts");
13+
verify.codeFix({
14+
description: [ts.Diagnostics.Export_0_from_module_1.message, "bar", "./a"],
15+
index: 0,
16+
newFileContent: {
17+
"/a.ts":
18+
`declare function foo(): any
19+
declare function bar(): any;
20+
export { foo, bar };`,
21+
}
22+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
/////**
6+
//// * foo
7+
//// */
8+
////function foo() {}
9+
////export const bar = 1;
10+
11+
// @filename: /b.ts
12+
////import { foo } from "./a";
13+
14+
goTo.file("/b.ts");
15+
verify.codeFix({
16+
description: [ts.Diagnostics.Export_0_from_module_1.message, "foo", "./a"],
17+
index: 0,
18+
newFileContent: {
19+
"/a.ts":
20+
`/**
21+
* foo
22+
*/
23+
export function foo() {}
24+
export const bar = 1;`,
25+
}
26+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @isolatedModules: true
5+
// @filename: /a.ts
6+
////type T = {};
7+
////export {};
8+
9+
// @filename: /b.ts
10+
////import { T } from "./a";
11+
12+
goTo.file("/b.ts");
13+
verify.codeFix({
14+
description: [ts.Diagnostics.Export_0_from_module_1.message, "T", "./a"],
15+
index: 0,
16+
newFileContent: {
17+
"/a.ts":
18+
`type T = {};
19+
export { type T };`,
20+
}
21+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////type T1 = {};
6+
////type T2 = {};
7+
////export { type T1 };
8+
9+
// @filename: /b.ts
10+
////import { T2 } from "./a";
11+
12+
goTo.file("/b.ts");
13+
verify.codeFix({
14+
description: [ts.Diagnostics.Export_0_from_module_1.message, "T2", "./a"],
15+
index: 0,
16+
newFileContent: {
17+
"/a.ts":
18+
`type T1 = {};
19+
type T2 = {};
20+
export { type T1, type T2 };`,
21+
}
22+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @isolatedModules: true
5+
// @filename: /a.ts
6+
////type T1 = {};
7+
////type T2 = {};
8+
////export type { T1 };
9+
10+
// @filename: /b.ts
11+
////import { T2 } from "./a";
12+
13+
goTo.file("/b.ts");
14+
verify.codeFix({
15+
description: [ts.Diagnostics.Export_0_from_module_1.message, "T2", "./a"],
16+
index: 0,
17+
newFileContent: {
18+
"/a.ts":
19+
`type T1 = {};
20+
type T2 = {};
21+
export type { T1, T2 };`,
22+
}
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////export declare function foo(): any;
6+
////declare function bar(): any;
7+
8+
// @filename: /b.ts
9+
////import { bar } from "./a";
10+
11+
goTo.file("/b.ts");
12+
verify.codeFix({
13+
description: [ts.Diagnostics.Export_0_from_module_1.message, "bar", "./a"],
14+
index: 0,
15+
newFileContent: {
16+
"/a.ts":
17+
`export declare function foo(): any;
18+
export declare function bar(): any;`,
19+
}
20+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////let foo = 1, bar = 1;
6+
////export const baz = 1;
7+
8+
// @filename: /b.ts
9+
////import { bar } from "./a";
10+
11+
goTo.file("/b.ts");
12+
verify.codeFix({
13+
description: [ts.Diagnostics.Export_0_from_module_1.message, "bar", "./a"],
14+
index: 0,
15+
newFileContent: {
16+
"/a.ts":
17+
`let foo = 1, bar = 1;
18+
export const baz = 1;
19+
20+
export { bar };
21+
`,
22+
}
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.d.ts
5+
////declare function foo(): any;
6+
////declare function bar(): any;
7+
8+
// @filename: /b.ts
9+
////import { bar } from "./a";
10+
11+
goTo.file("/b.ts");
12+
verify.not.codeFixAvailable("fixImportNonExportedMember");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @moduleResolution: node
4+
// @module: esnext
5+
// @filename: /node_modules/foo/index.js
6+
////function bar() {}
7+
8+
// @filename: /b.ts
9+
////import { bar } from "./foo";
10+
11+
goTo.file("/b.ts");
12+
verify.not.codeFixAvailable("fixImportNonExportedMember");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////let a = 1, b = 1;
6+
////type T = number;
7+
////export type { T };
8+
9+
// @filename: /b.ts
10+
////import { b } from "./a";
11+
12+
goTo.file("/b.ts");
13+
verify.codeFix({
14+
description: [ts.Diagnostics.Export_0_from_module_1.message, "b", "./a"],
15+
index: 0,
16+
newFileContent: {
17+
"/a.ts":
18+
`let a = 1, b = 1;
19+
type T = number;
20+
export type { T };
21+
22+
export { b };
23+
`,
24+
}
25+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////const a = 1
6+
////const b = 1;
7+
////export { a, b };
8+
////
9+
////type T2 = number;
10+
////type T1 = number;
11+
////export type { T1 };
12+
13+
// @filename: /b.ts
14+
////import { T2 } from "./a";
15+
16+
goTo.file("/b.ts");
17+
verify.codeFix({
18+
description: [ts.Diagnostics.Export_0_from_module_1.message, "T2", "./a"],
19+
index: 0,
20+
newFileContent: {
21+
"/a.ts":
22+
`const a = 1
23+
const b = 1;
24+
export { a, b };
25+
26+
type T2 = number;
27+
type T1 = number;
28+
export type { T1, T2 };`,
29+
}
30+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////const a = 1;
6+
////type T = number;
7+
////export { a };
8+
9+
// @filename: /b.ts
10+
////import { T } from "./a";
11+
12+
goTo.file("/b.ts");
13+
verify.codeFix({
14+
description: [ts.Diagnostics.Export_0_from_module_1.message, "T", "./a"],
15+
index: 0,
16+
newFileContent: {
17+
"/a.ts":
18+
`const a = 1;
19+
type T = number;
20+
export { a, T };`,
21+
}
22+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
/////**
6+
//// * foo
7+
//// */
8+
////function foo() {}
9+
////export {};
10+
11+
// @filename: /b.ts
12+
////import { foo } from "./a";
13+
14+
goTo.file("/b.ts");
15+
verify.codeFix({
16+
description: [ts.Diagnostics.Export_0_from_module_1.message, "foo", "./a"],
17+
index: 0,
18+
newFileContent: {
19+
"/a.ts":
20+
`/**
21+
* foo
22+
*/
23+
function foo() {}
24+
export { foo };`,
25+
}
26+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////declare function foo(): any;
6+
////declare function bar(): any;
7+
////export declare function baz(): any;
8+
9+
// @filename: /b.ts
10+
////import { foo, bar } from "./a";
11+
12+
goTo.file("/b.ts");
13+
verify.codeFixAll({
14+
fixId: "fixImportNonExportedMember",
15+
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
16+
newFileContent: {
17+
"/a.ts":
18+
`export declare function foo(): any;
19+
export declare function bar(): any;
20+
export declare function baz(): any;`
21+
},
22+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////declare function foo(): any;
6+
////declare function bar(): any;
7+
////declare function baz(): any;
8+
////export { baz };
9+
10+
// @filename: /b.ts
11+
////import { foo, bar } from "./a";
12+
13+
goTo.file("/b.ts");
14+
verify.codeFixAll({
15+
fixId: "fixImportNonExportedMember",
16+
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
17+
newFileContent: {
18+
"/a.ts":
19+
`declare function foo(): any;
20+
declare function bar(): any;
21+
declare function baz(): any;
22+
export { baz, foo, bar };`
23+
},
24+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////let a = 1, b = 1;
6+
////let c = 1, d = 1;
7+
////export const e = 1;
8+
9+
// @filename: /b.ts
10+
////import { b, d } from "./a";
11+
12+
goTo.file("/b.ts");
13+
verify.codeFixAll({
14+
fixId: "fixImportNonExportedMember",
15+
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
16+
newFileContent: {
17+
"/a.ts":
18+
`let a = 1, b = 1;
19+
let c = 1, d = 1;
20+
export const e = 1;
21+
22+
export { b, d };
23+
`
24+
},
25+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////const a = 1;
6+
////export const foo = 1;
7+
8+
// @filename: /b.ts
9+
////const b = 1;
10+
////export const bar = 1;
11+
12+
// @filename: /c.ts
13+
////import { a } from "./a";
14+
////import { b } from "./b";
15+
16+
goTo.file("/c.ts");
17+
verify.codeFixAll({
18+
fixId: "fixImportNonExportedMember",
19+
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
20+
newFileContent: {
21+
"/a.ts":
22+
`export const a = 1;
23+
export const foo = 1;`,
24+
"/b.ts":
25+
`export const b = 1;
26+
export const bar = 1;`
27+
},
28+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////let a = 1, b = 1, c = 1;
6+
////export { b };
7+
////
8+
////type T2 = number;
9+
////type T1 = number;
10+
////export type { T2 };
11+
12+
// @filename: /b.ts
13+
////let a = 1, b = 1, c = 1;
14+
////
15+
////type T3 = number;
16+
////type T4 = number;
17+
////export type { T4 };
18+
19+
// @filename: /c.ts
20+
////let a = 1, b = 1, c = 1;
21+
////
22+
////type T5 = number;
23+
////type T6 = number;
24+
////export { a };
25+
26+
// @filename: /d.ts
27+
////export const a = 1;
28+
////let b = 1, c = 1, d = 1;
29+
////
30+
////type T7 = number;
31+
////type T8 = number;
32+
33+
// @filename: /e.ts
34+
////import { T1, a } from "./a";
35+
////import { T3, b } from "./b";
36+
////import { T5, c } from "./c";
37+
////import { T7, d } from "./d";
38+
39+
goTo.file("/e.ts");
40+
verify.codeFixAll({
41+
fixId: "fixImportNonExportedMember",
42+
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
43+
newFileContent: {
44+
"/a.ts":
45+
`let a = 1, b = 1, c = 1;
46+
export { b, a };
47+
48+
type T2 = number;
49+
type T1 = number;
50+
export type { T2, T1 };`,
51+
52+
"/b.ts":
53+
`let a = 1, b = 1, c = 1;
54+
55+
type T3 = number;
56+
type T4 = number;
57+
export type { T4, T3 };
58+
59+
export { b };
60+
`,
61+
62+
"/c.ts":
63+
`let a = 1, b = 1, c = 1;
64+
65+
type T5 = number;
66+
type T6 = number;
67+
export { a, c, T5 };`,
68+
69+
"/d.ts":
70+
`export const a = 1;
71+
let b = 1, c = 1, d = 1;
72+
73+
export type T7 = number;
74+
type T8 = number;
75+
76+
export { d };
77+
`,
78+
},
79+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @isolatedModules: true
5+
// @filename: /a.ts
6+
////type T1 = {};
7+
////const a = 1;
8+
////const b = 1;
9+
////export { a };
10+
11+
// @filename: /b.ts
12+
////type T2 = {};
13+
////type T3 = {};
14+
////export type { T2 };
15+
16+
// @filename: /c.ts
17+
////import { b, T1 } from "./a";
18+
////import { T3 } from "./b";
19+
20+
goTo.file("/c.ts");
21+
verify.codeFixAll({
22+
fixId: "fixImportNonExportedMember",
23+
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
24+
newFileContent: {
25+
"/a.ts":
26+
`type T1 = {};
27+
const a = 1;
28+
const b = 1;
29+
export { a, b, type T1 };`,
30+
"/b.ts":
31+
`type T2 = {};
32+
type T3 = {};
33+
export type { T2, T3 };`,
34+
},
35+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @module: esnext
4+
// @filename: /a.ts
5+
////type T1 = {};
6+
////type T2 = {};
7+
////type T3 = {};
8+
////const a = 1;
9+
////export { a, type T1 };
10+
11+
// @filename: /b.ts
12+
////import { T2, T3 } from "./a";
13+
14+
goTo.file("/b.ts");
15+
verify.codeFixAll({
16+
fixId: "fixImportNonExportedMember",
17+
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
18+
newFileContent: {
19+
"/a.ts":
20+
`type T1 = {};
21+
type T2 = {};
22+
type T3 = {};
23+
const a = 1;
24+
export { a, type T1, type T2, type T3 };`,
25+
},
26+
});

0 commit comments

Comments
 (0)
Please sign in to comment.