Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -5185,6 +5185,14 @@
"category": "Message",
"code": 90053
},
"Export '{0}' from module '{1}'": {
"category": "Message",
"code": 90054
},
"Export all non-exported member": {
Comment thread
Qiyu8 marked this conversation as resolved.
Outdated
"category": "Message",
"code": 90055
},
"Convert function to an ES2015 class": {
"category": "Message",
"code": 95001
Expand Down
62 changes: 62 additions & 0 deletions src/services/codefixes/fixImportNonExportedMember.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* @internal */
namespace ts.codefix {
const fixId = "importNonExportedMember";
const errorCodes = [
Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported.code
];
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { sourceFile } = context;
const info = getInfo(sourceFile, context, context.span.start);
if (!info) {
return undefined;
}
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, info.originSourceFile, info.node));
return [createCodeFixAction(fixId, changes, [Diagnostics.Export_0_from_module_1, info.node.text, showModuleSpecifier(info.importDecl)], fixId, Diagnostics.Export_all_non_exported_member)];
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const info = getInfo(diag.file, context, diag.start);
if (info) doChange(changes, info.originSourceFile, info.node);
}),
});

interface Info {
readonly node: Identifier;
readonly importDecl: ImportDeclaration;
readonly originSourceFile: SourceFile
}

function getInfo(sourceFile: SourceFile, context: CodeFixContext | CodeFixAllContext, pos: number): Info | undefined {
const node = getTokenAtPosition(sourceFile, pos);
if (node && isIdentifier(node)) {
const importStart = getLineStartPositionForPosition(pos, sourceFile);
const importDecl = tryGetImportFrom(getTokenAtPosition(sourceFile, importStart));
Comment thread
Qiyu8 marked this conversation as resolved.
Outdated
if (!importDecl || !isStringLiteralLike(importDecl.moduleSpecifier)) {
return undefined;
}
const resolvedModule = getResolvedModule(sourceFile, importDecl.moduleSpecifier.text);
const originSourceFile = resolvedModule && context.program.getSourceFile(resolvedModule.resolvedFileName);
if (!originSourceFile) {
return undefined;
}
return { node, importDecl, originSourceFile };
}
}

function tryGetImportFrom(token: Node): ImportDeclaration | undefined {
return token.kind === SyntaxKind.ImportKeyword ? tryCast(token.parent, isImportDeclaration) : undefined;
}

function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: Identifier): void {
const exportSpecifier = createExportSpecifier(/*propertyName*/ undefined, node);
const exportDeclaration = createExportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createNamedExports([exportSpecifier]),
/*moduleSpecifier*/ undefined,
/*isTypeOnly*/ false);
changes.insertNodeAtEndOfScope(sourceFile, sourceFile, exportDeclaration);
}
}
1 change: 1 addition & 0 deletions src/services/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"codefixes/fixModuleAndTargetOptions.ts",
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
"codefixes/fixForgottenThisPropertyAccess.ts",
"codefixes/fixImportNonExportedMember.ts",
"codefixes/fixInvalidJsxCharacters.ts",
"codefixes/fixUnusedIdentifier.ts",
"codefixes/fixUnreachableCode.ts",
Expand Down
32 changes: 32 additions & 0 deletions tests/cases/fourslash/codeFixImportNonExportedMember.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/// <reference path='fourslash.ts' />
// @Filename: /a.ts
////declare function zoo(): any;
////export { zoo };

// @Filename: /b.ts
////declare function foo(): any;
////declare function bar(): any;
////export { foo };

// @Filename: /c.ts
////import { zoo } from "./a";
////import { bar } from "./b";

goTo.file("/c.ts");
verify.codeFixAvailable([
{ description: `Export 'bar' from module './b'` },
{ description: `Remove import from './a'` },
{ description: `Remove import from './b'` },
]);
verify.codeFix({
index: 0,
description: `Export 'bar' from module './b'`,
newFileContent: {
'/b.ts': `declare function foo(): any;
declare function bar(): any;
export { foo };

export { bar };
Comment thread
Qiyu8 marked this conversation as resolved.
Outdated
`
}
});
28 changes: 28 additions & 0 deletions tests/cases/fourslash/codeFixImportNonExportedMember_all.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/// <reference path='fourslash.ts' />

// @Filename: /a.ts
////declare function foo(): any;
////declare function bar(): any;
////declare function zoo(): any;
////export { zoo }

// @Filename: /b.ts
////import { foo, bar } from "./a";

goTo.file("/b.ts");
verify.codeFixAll({
fixId: "importNonExportedMember",
fixAllDescription: "Export all non-exported member",
newFileContent: {
'/a.ts': `declare function foo(): any;
declare function bar(): any;
declare function zoo(): any;
export { zoo }

export { foo };


export { bar };
`
}
});