mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
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
This commit is contained in:
parent
a24201c8ef
commit
2bcfed01f3
@ -7235,16 +7235,6 @@ namespace ts {
|
||||
return statements;
|
||||
}
|
||||
|
||||
function canHaveExportModifier(node: Statement): node is Extract<HasModifiers, Statement> {
|
||||
return isEnumDeclaration(node) ||
|
||||
isVariableStatement(node) ||
|
||||
isFunctionDeclaration(node) ||
|
||||
isClassDeclaration(node) ||
|
||||
(isModuleDeclaration(node) && !isExternalModuleAugmentation(node) && !isGlobalScopeAugmentation(node)) ||
|
||||
isInterfaceDeclaration(node) ||
|
||||
isTypeDeclaration(node);
|
||||
}
|
||||
|
||||
function addExportModifier(node: Extract<HasModifiers, Statement>) {
|
||||
const flags = (getEffectiveModifierFlags(node) | ModifierFlags.Export) & ~ModifierFlags.Ambient;
|
||||
return factory.updateModifiers(node, flags);
|
||||
@ -42691,27 +42681,6 @@ namespace ts {
|
||||
getNameOfDeclaration(name.parent) === name;
|
||||
}
|
||||
|
||||
function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | EnumDeclaration | ImportClause | ImportSpecifier | ExportSpecifier {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
case SyntaxKind.JSDocEnumTag:
|
||||
return true;
|
||||
case SyntaxKind.ImportClause:
|
||||
return (node as ImportClause).isTypeOnly;
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
return (node as ImportSpecifier | ExportSpecifier).parent.parent.isTypeOnly;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// True if the given identifier is part of a type reference
|
||||
function isTypeReferenceIdentifier(node: EntityName): boolean {
|
||||
while (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
|
||||
@ -6687,6 +6687,14 @@
|
||||
"category": "Message",
|
||||
"code": 90058
|
||||
},
|
||||
"Export '{0}' from module '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 90059
|
||||
},
|
||||
"Export all referenced locals": {
|
||||
"category": "Message",
|
||||
"code": 90060
|
||||
},
|
||||
|
||||
"Convert function to an ES2015 class": {
|
||||
"category": "Message",
|
||||
|
||||
@ -7752,4 +7752,30 @@ namespace ts {
|
||||
export function getParameterTypeNode(parameter: ParameterDeclaration | JSDocParameterTag) {
|
||||
return parameter.kind === SyntaxKind.JSDocParameterTag ? parameter.typeExpression?.type : parameter.type;
|
||||
}
|
||||
|
||||
export function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | EnumDeclaration | ImportClause | ImportSpecifier | ExportSpecifier {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
case SyntaxKind.JSDocEnumTag:
|
||||
return true;
|
||||
case SyntaxKind.ImportClause:
|
||||
return (node as ImportClause).isTypeOnly;
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
return (node as ImportSpecifier | ExportSpecifier).parent.parent.isTypeOnly;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function canHaveExportModifier(node: Node): node is Extract<HasModifiers, Statement> {
|
||||
return isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node)
|
||||
|| isInterfaceDeclaration(node) || isTypeDeclaration(node) || (isModuleDeclaration(node) && !isExternalModuleAugmentation(node) && !isGlobalScopeAugmentation(node));
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,10 +264,6 @@ namespace ts.codefix {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isSourceFileFromLibrary(program: Program, node: SourceFile) {
|
||||
return program.isSourceFileFromExternalLibrary(node) || program.isSourceFileDefaultLibrary(node);
|
||||
}
|
||||
|
||||
function getActionsForMissingMemberDeclaration(context: CodeFixContext, info: TypeLikeDeclarationInfo): CodeFixAction[] | undefined {
|
||||
return info.isJSFile ? singleElementArray(createActionForAddMissingMemberInJavascriptFile(context, info)) :
|
||||
createActionsForAddMissingMemberInTypeScriptFile(context, info);
|
||||
|
||||
163
src/services/codefixes/fixImportNonExportedMember.ts
Normal file
163
src/services/codefixes/fixImportNonExportedMember.ts
Normal file
@ -0,0 +1,163 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
const fixId = "fixImportNonExportedMember";
|
||||
const errorCodes = [
|
||||
Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported.code,
|
||||
];
|
||||
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
fixIds: [fixId],
|
||||
getCodeActions(context) {
|
||||
const { sourceFile, span, program } = context;
|
||||
const info = getInfo(sourceFile, span.start, program);
|
||||
if (info === undefined) return undefined;
|
||||
|
||||
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, program, info));
|
||||
return [createCodeFixAction(fixId, changes, [Diagnostics.Export_0_from_module_1, info.exportName.node.text, info.moduleSpecifier], fixId, Diagnostics.Export_all_referenced_locals)];
|
||||
},
|
||||
getAllCodeActions(context) {
|
||||
const { program } = context;
|
||||
return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => {
|
||||
const exports = new Map<SourceFile, ModuleExports>();
|
||||
|
||||
eachDiagnostic(context, errorCodes, diag => {
|
||||
const info = getInfo(diag.file, diag.start, program);
|
||||
if (info === undefined) return undefined;
|
||||
|
||||
const { exportName, node, moduleSourceFile } = info;
|
||||
if (tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly) === undefined && canHaveExportModifier(node)) {
|
||||
changes.insertExportModifier(moduleSourceFile, node);
|
||||
}
|
||||
else {
|
||||
const moduleExports = exports.get(moduleSourceFile) || { typeOnlyExports: [], exports: [] };
|
||||
if (exportName.isTypeOnly) {
|
||||
moduleExports.typeOnlyExports.push(exportName);
|
||||
}
|
||||
else {
|
||||
moduleExports.exports.push(exportName);
|
||||
}
|
||||
exports.set(moduleSourceFile, moduleExports);
|
||||
}
|
||||
});
|
||||
|
||||
exports.forEach((moduleExports, moduleSourceFile) => {
|
||||
const exportDeclaration = tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ true);
|
||||
if (exportDeclaration && exportDeclaration.isTypeOnly) {
|
||||
doChanges(changes, program, moduleSourceFile, moduleExports.typeOnlyExports, exportDeclaration);
|
||||
doChanges(changes, program, moduleSourceFile, moduleExports.exports, tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ false));
|
||||
}
|
||||
else {
|
||||
doChanges(changes, program, moduleSourceFile, [...moduleExports.exports, ...moduleExports.typeOnlyExports], exportDeclaration);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
interface ModuleExports {
|
||||
typeOnlyExports: ExportName[];
|
||||
exports: ExportName[];
|
||||
}
|
||||
|
||||
interface ExportName {
|
||||
node: Identifier;
|
||||
isTypeOnly: boolean;
|
||||
}
|
||||
|
||||
interface Info {
|
||||
exportName: ExportName;
|
||||
node: Declaration | VariableStatement;
|
||||
moduleSourceFile: SourceFile;
|
||||
moduleSpecifier: string;
|
||||
}
|
||||
|
||||
function getInfo(sourceFile: SourceFile, pos: number, program: Program): Info | undefined {
|
||||
const token = getTokenAtPosition(sourceFile, pos);
|
||||
if (isIdentifier(token)) {
|
||||
const importDeclaration = findAncestor(token, isImportDeclaration);
|
||||
if (importDeclaration === undefined) return undefined;
|
||||
|
||||
const moduleSpecifier = isStringLiteral(importDeclaration.moduleSpecifier) ? importDeclaration.moduleSpecifier.text : undefined;
|
||||
if (moduleSpecifier === undefined) return undefined;
|
||||
|
||||
const resolvedModule = getResolvedModule(sourceFile, moduleSpecifier, /*mode*/ undefined);
|
||||
if (resolvedModule === undefined) return undefined;
|
||||
|
||||
const moduleSourceFile = program.getSourceFile(resolvedModule.resolvedFileName);
|
||||
if (moduleSourceFile === undefined || isSourceFileFromLibrary(program, moduleSourceFile)) return undefined;
|
||||
|
||||
const moduleSymbol = moduleSourceFile.symbol;
|
||||
const locals = moduleSymbol.valueDeclaration?.locals;
|
||||
if (locals === undefined) return undefined;
|
||||
|
||||
const localSymbol = locals.get(token.escapedText);
|
||||
if (localSymbol === undefined) return undefined;
|
||||
|
||||
const node = getNodeOfSymbol(localSymbol);
|
||||
if (node === undefined) return undefined;
|
||||
|
||||
const exportName = { node: token, isTypeOnly: isTypeDeclaration(node) };
|
||||
return { exportName, node, moduleSourceFile, moduleSpecifier };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function doChange(changes: textChanges.ChangeTracker, program: Program, { exportName, node, moduleSourceFile }: Info) {
|
||||
const exportDeclaration = tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly);
|
||||
if (exportDeclaration) {
|
||||
updateExport(changes, program, moduleSourceFile, exportDeclaration, [exportName]);
|
||||
}
|
||||
else if (canHaveExportModifier(node)) {
|
||||
changes.insertExportModifier(moduleSourceFile, node);
|
||||
}
|
||||
else {
|
||||
createExport(changes, program, moduleSourceFile, [exportName]);
|
||||
}
|
||||
}
|
||||
|
||||
function doChanges(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, moduleExports: ExportName[], node: ExportDeclaration | undefined) {
|
||||
if (length(moduleExports)) {
|
||||
if (node) {
|
||||
updateExport(changes, program, sourceFile, node, moduleExports);
|
||||
}
|
||||
else {
|
||||
createExport(changes, program, sourceFile, moduleExports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetExportDeclaration(sourceFile: SourceFile, isTypeOnly: boolean) {
|
||||
const predicate = (node: Node): node is ExportDeclaration =>
|
||||
isExportDeclaration(node) && (isTypeOnly && node.isTypeOnly || !node.isTypeOnly);
|
||||
return findLast(sourceFile.statements, predicate);
|
||||
}
|
||||
|
||||
function updateExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, node: ExportDeclaration, names: ExportName[]) {
|
||||
const namedExports = node.exportClause && isNamedExports(node.exportClause) ? node.exportClause.elements : factory.createNodeArray([]);
|
||||
const allowTypeModifier = !node.isTypeOnly && !!(program.getCompilerOptions().isolatedModules || find(namedExports, e => e.isTypeOnly));
|
||||
changes.replaceNode(sourceFile, node,
|
||||
factory.updateExportDeclaration(node, node.modifiers, node.isTypeOnly,
|
||||
factory.createNamedExports(
|
||||
factory.createNodeArray([...namedExports, ...createExportSpecifiers(names, allowTypeModifier)], /*hasTrailingComma*/ namedExports.hasTrailingComma)), node.moduleSpecifier, node.assertClause));
|
||||
}
|
||||
|
||||
function createExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, names: ExportName[]) {
|
||||
changes.insertNodeAtEndOfScope(sourceFile, sourceFile,
|
||||
factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false,
|
||||
factory.createNamedExports(createExportSpecifiers(names, /*allowTypeModifier*/ !!program.getCompilerOptions().isolatedModules)), /*moduleSpecifier*/ undefined, /*assertClause*/ undefined));
|
||||
}
|
||||
|
||||
function createExportSpecifiers(names: ExportName[], allowTypeModifier: boolean) {
|
||||
return factory.createNodeArray(map(names, n => factory.createExportSpecifier(allowTypeModifier && n.isTypeOnly, /*propertyName*/ undefined, n.node)));
|
||||
}
|
||||
|
||||
function getNodeOfSymbol(symbol: Symbol) {
|
||||
if (symbol.valueDeclaration === undefined) {
|
||||
return firstOrUndefined(symbol.declarations);
|
||||
}
|
||||
const declaration = symbol.valueDeclaration;
|
||||
const variableStatement = isVariableDeclaration(declaration) ? tryCast(declaration.parent.parent, isVariableStatement) : undefined;
|
||||
return variableStatement && length(variableStatement.declarationList.declarations) === 1 ? variableStatement : declaration;
|
||||
}
|
||||
}
|
||||
@ -71,6 +71,7 @@
|
||||
"codefixes/fixOverrideModifier.ts",
|
||||
"codefixes/fixNoPropertyAccessFromIndexSignature.ts",
|
||||
"codefixes/fixImplicitThis.ts",
|
||||
"codefixes/fixImportNonExportedMember.ts",
|
||||
"codefixes/fixIncorrectNamedTupleSyntax.ts",
|
||||
"codefixes/fixSpelling.ts",
|
||||
"codefixes/returnValueCorrect.ts",
|
||||
|
||||
@ -3423,5 +3423,9 @@ namespace ts {
|
||||
return jsx === JsxEmit.React || jsx === JsxEmit.ReactNative;
|
||||
}
|
||||
|
||||
export function isSourceFileFromLibrary(program: Program, node: SourceFile) {
|
||||
return program.isSourceFileFromExternalLibrary(node) || program.isSourceFileDefaultLibrary(node);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
|
||||
22
tests/cases/fourslash/codeFixImportNonExportedMember1.ts
Normal file
22
tests/cases/fourslash/codeFixImportNonExportedMember1.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////declare function foo(): any
|
||||
////declare function bar(): any;
|
||||
////export { foo };
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { bar } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "bar", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`declare function foo(): any
|
||||
declare function bar(): any;
|
||||
export { foo, bar };`,
|
||||
}
|
||||
});
|
||||
26
tests/cases/fourslash/codeFixImportNonExportedMember10.ts
Normal file
26
tests/cases/fourslash/codeFixImportNonExportedMember10.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
/////**
|
||||
//// * foo
|
||||
//// */
|
||||
////function foo() {}
|
||||
////export const bar = 1;
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { foo } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "foo", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`/**
|
||||
* foo
|
||||
*/
|
||||
export function foo() {}
|
||||
export const bar = 1;`,
|
||||
}
|
||||
});
|
||||
21
tests/cases/fourslash/codeFixImportNonExportedMember11.ts
Normal file
21
tests/cases/fourslash/codeFixImportNonExportedMember11.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @isolatedModules: true
|
||||
// @filename: /a.ts
|
||||
////type T = {};
|
||||
////export {};
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { T } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "T", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`type T = {};
|
||||
export { type T };`,
|
||||
}
|
||||
});
|
||||
22
tests/cases/fourslash/codeFixImportNonExportedMember12.ts
Normal file
22
tests/cases/fourslash/codeFixImportNonExportedMember12.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////type T1 = {};
|
||||
////type T2 = {};
|
||||
////export { type T1 };
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { T2 } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "T2", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`type T1 = {};
|
||||
type T2 = {};
|
||||
export { type T1, type T2 };`,
|
||||
}
|
||||
});
|
||||
23
tests/cases/fourslash/codeFixImportNonExportedMember13.ts
Normal file
23
tests/cases/fourslash/codeFixImportNonExportedMember13.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @isolatedModules: true
|
||||
// @filename: /a.ts
|
||||
////type T1 = {};
|
||||
////type T2 = {};
|
||||
////export type { T1 };
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { T2 } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "T2", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`type T1 = {};
|
||||
type T2 = {};
|
||||
export type { T1, T2 };`,
|
||||
}
|
||||
});
|
||||
20
tests/cases/fourslash/codeFixImportNonExportedMember2.ts
Normal file
20
tests/cases/fourslash/codeFixImportNonExportedMember2.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////export declare function foo(): any;
|
||||
////declare function bar(): any;
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { bar } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "bar", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`export declare function foo(): any;
|
||||
export declare function bar(): any;`,
|
||||
}
|
||||
});
|
||||
23
tests/cases/fourslash/codeFixImportNonExportedMember3.ts
Normal file
23
tests/cases/fourslash/codeFixImportNonExportedMember3.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////let foo = 1, bar = 1;
|
||||
////export const baz = 1;
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { bar } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "bar", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`let foo = 1, bar = 1;
|
||||
export const baz = 1;
|
||||
|
||||
export { bar };
|
||||
`,
|
||||
}
|
||||
});
|
||||
12
tests/cases/fourslash/codeFixImportNonExportedMember4.ts
Normal file
12
tests/cases/fourslash/codeFixImportNonExportedMember4.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.d.ts
|
||||
////declare function foo(): any;
|
||||
////declare function bar(): any;
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { bar } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.not.codeFixAvailable("fixImportNonExportedMember");
|
||||
12
tests/cases/fourslash/codeFixImportNonExportedMember5.ts
Normal file
12
tests/cases/fourslash/codeFixImportNonExportedMember5.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @moduleResolution: node
|
||||
// @module: esnext
|
||||
// @filename: /node_modules/foo/index.js
|
||||
////function bar() {}
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { bar } from "./foo";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.not.codeFixAvailable("fixImportNonExportedMember");
|
||||
25
tests/cases/fourslash/codeFixImportNonExportedMember6.ts
Normal file
25
tests/cases/fourslash/codeFixImportNonExportedMember6.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////let a = 1, b = 1;
|
||||
////type T = number;
|
||||
////export type { T };
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { b } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "b", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`let a = 1, b = 1;
|
||||
type T = number;
|
||||
export type { T };
|
||||
|
||||
export { b };
|
||||
`,
|
||||
}
|
||||
});
|
||||
30
tests/cases/fourslash/codeFixImportNonExportedMember7.ts
Normal file
30
tests/cases/fourslash/codeFixImportNonExportedMember7.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////const a = 1
|
||||
////const b = 1;
|
||||
////export { a, b };
|
||||
////
|
||||
////type T2 = number;
|
||||
////type T1 = number;
|
||||
////export type { T1 };
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { T2 } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "T2", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`const a = 1
|
||||
const b = 1;
|
||||
export { a, b };
|
||||
|
||||
type T2 = number;
|
||||
type T1 = number;
|
||||
export type { T1, T2 };`,
|
||||
}
|
||||
});
|
||||
22
tests/cases/fourslash/codeFixImportNonExportedMember8.ts
Normal file
22
tests/cases/fourslash/codeFixImportNonExportedMember8.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////const a = 1;
|
||||
////type T = number;
|
||||
////export { a };
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { T } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "T", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`const a = 1;
|
||||
type T = number;
|
||||
export { a, T };`,
|
||||
}
|
||||
});
|
||||
26
tests/cases/fourslash/codeFixImportNonExportedMember9.ts
Normal file
26
tests/cases/fourslash/codeFixImportNonExportedMember9.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
/////**
|
||||
//// * foo
|
||||
//// */
|
||||
////function foo() {}
|
||||
////export {};
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { foo } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Export_0_from_module_1.message, "foo", "./a"],
|
||||
index: 0,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`/**
|
||||
* foo
|
||||
*/
|
||||
function foo() {}
|
||||
export { foo };`,
|
||||
}
|
||||
});
|
||||
22
tests/cases/fourslash/codeFixImportNonExportedMember_all1.ts
Normal file
22
tests/cases/fourslash/codeFixImportNonExportedMember_all1.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////declare function foo(): any;
|
||||
////declare function bar(): any;
|
||||
////export declare function baz(): any;
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { foo, bar } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "fixImportNonExportedMember",
|
||||
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`export declare function foo(): any;
|
||||
export declare function bar(): any;
|
||||
export declare function baz(): any;`
|
||||
},
|
||||
});
|
||||
24
tests/cases/fourslash/codeFixImportNonExportedMember_all2.ts
Normal file
24
tests/cases/fourslash/codeFixImportNonExportedMember_all2.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////declare function foo(): any;
|
||||
////declare function bar(): any;
|
||||
////declare function baz(): any;
|
||||
////export { baz };
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { foo, bar } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "fixImportNonExportedMember",
|
||||
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`declare function foo(): any;
|
||||
declare function bar(): any;
|
||||
declare function baz(): any;
|
||||
export { baz, foo, bar };`
|
||||
},
|
||||
});
|
||||
25
tests/cases/fourslash/codeFixImportNonExportedMember_all3.ts
Normal file
25
tests/cases/fourslash/codeFixImportNonExportedMember_all3.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////let a = 1, b = 1;
|
||||
////let c = 1, d = 1;
|
||||
////export const e = 1;
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { b, d } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "fixImportNonExportedMember",
|
||||
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`let a = 1, b = 1;
|
||||
let c = 1, d = 1;
|
||||
export const e = 1;
|
||||
|
||||
export { b, d };
|
||||
`
|
||||
},
|
||||
});
|
||||
28
tests/cases/fourslash/codeFixImportNonExportedMember_all4.ts
Normal file
28
tests/cases/fourslash/codeFixImportNonExportedMember_all4.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////const a = 1;
|
||||
////export const foo = 1;
|
||||
|
||||
// @filename: /b.ts
|
||||
////const b = 1;
|
||||
////export const bar = 1;
|
||||
|
||||
// @filename: /c.ts
|
||||
////import { a } from "./a";
|
||||
////import { b } from "./b";
|
||||
|
||||
goTo.file("/c.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "fixImportNonExportedMember",
|
||||
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`export const a = 1;
|
||||
export const foo = 1;`,
|
||||
"/b.ts":
|
||||
`export const b = 1;
|
||||
export const bar = 1;`
|
||||
},
|
||||
});
|
||||
79
tests/cases/fourslash/codeFixImportNonExportedMember_all5.ts
Normal file
79
tests/cases/fourslash/codeFixImportNonExportedMember_all5.ts
Normal file
@ -0,0 +1,79 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////let a = 1, b = 1, c = 1;
|
||||
////export { b };
|
||||
////
|
||||
////type T2 = number;
|
||||
////type T1 = number;
|
||||
////export type { T2 };
|
||||
|
||||
// @filename: /b.ts
|
||||
////let a = 1, b = 1, c = 1;
|
||||
////
|
||||
////type T3 = number;
|
||||
////type T4 = number;
|
||||
////export type { T4 };
|
||||
|
||||
// @filename: /c.ts
|
||||
////let a = 1, b = 1, c = 1;
|
||||
////
|
||||
////type T5 = number;
|
||||
////type T6 = number;
|
||||
////export { a };
|
||||
|
||||
// @filename: /d.ts
|
||||
////export const a = 1;
|
||||
////let b = 1, c = 1, d = 1;
|
||||
////
|
||||
////type T7 = number;
|
||||
////type T8 = number;
|
||||
|
||||
// @filename: /e.ts
|
||||
////import { T1, a } from "./a";
|
||||
////import { T3, b } from "./b";
|
||||
////import { T5, c } from "./c";
|
||||
////import { T7, d } from "./d";
|
||||
|
||||
goTo.file("/e.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "fixImportNonExportedMember",
|
||||
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`let a = 1, b = 1, c = 1;
|
||||
export { b, a };
|
||||
|
||||
type T2 = number;
|
||||
type T1 = number;
|
||||
export type { T2, T1 };`,
|
||||
|
||||
"/b.ts":
|
||||
`let a = 1, b = 1, c = 1;
|
||||
|
||||
type T3 = number;
|
||||
type T4 = number;
|
||||
export type { T4, T3 };
|
||||
|
||||
export { b };
|
||||
`,
|
||||
|
||||
"/c.ts":
|
||||
`let a = 1, b = 1, c = 1;
|
||||
|
||||
type T5 = number;
|
||||
type T6 = number;
|
||||
export { a, c, T5 };`,
|
||||
|
||||
"/d.ts":
|
||||
`export const a = 1;
|
||||
let b = 1, c = 1, d = 1;
|
||||
|
||||
export type T7 = number;
|
||||
type T8 = number;
|
||||
|
||||
export { d };
|
||||
`,
|
||||
},
|
||||
});
|
||||
35
tests/cases/fourslash/codeFixImportNonExportedMember_all6.ts
Normal file
35
tests/cases/fourslash/codeFixImportNonExportedMember_all6.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @isolatedModules: true
|
||||
// @filename: /a.ts
|
||||
////type T1 = {};
|
||||
////const a = 1;
|
||||
////const b = 1;
|
||||
////export { a };
|
||||
|
||||
// @filename: /b.ts
|
||||
////type T2 = {};
|
||||
////type T3 = {};
|
||||
////export type { T2 };
|
||||
|
||||
// @filename: /c.ts
|
||||
////import { b, T1 } from "./a";
|
||||
////import { T3 } from "./b";
|
||||
|
||||
goTo.file("/c.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "fixImportNonExportedMember",
|
||||
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`type T1 = {};
|
||||
const a = 1;
|
||||
const b = 1;
|
||||
export { a, b, type T1 };`,
|
||||
"/b.ts":
|
||||
`type T2 = {};
|
||||
type T3 = {};
|
||||
export type { T2, T3 };`,
|
||||
},
|
||||
});
|
||||
26
tests/cases/fourslash/codeFixImportNonExportedMember_all7.ts
Normal file
26
tests/cases/fourslash/codeFixImportNonExportedMember_all7.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: esnext
|
||||
// @filename: /a.ts
|
||||
////type T1 = {};
|
||||
////type T2 = {};
|
||||
////type T3 = {};
|
||||
////const a = 1;
|
||||
////export { a, type T1 };
|
||||
|
||||
// @filename: /b.ts
|
||||
////import { T2, T3 } from "./a";
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "fixImportNonExportedMember",
|
||||
fixAllDescription: ts.Diagnostics.Export_all_referenced_locals.message,
|
||||
newFileContent: {
|
||||
"/a.ts":
|
||||
`type T1 = {};
|
||||
type T2 = {};
|
||||
type T3 = {};
|
||||
const a = 1;
|
||||
export { a, type T1, type T2, type T3 };`,
|
||||
},
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user