Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Redo as noEraslingImportedNames
  • Loading branch information
andrewbranch committed Jun 16, 2021
commit 30636381e2259f1213e021ee75ec5f166ccecdc8
42 changes: 17 additions & 25 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38081,7 +38081,7 @@ namespace ts {
}

const isDeclaredTypeOnly = isTypeOnlyImportOrExportDeclaration(node);
if ((compilerOptions.isolatedModules || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.PreserveExact)
if (compilerOptions.isolatedModules
&& !isDeclaredTypeOnly
&& !(node.flags & NodeFlags.Ambient)
&& (!(target.flags & SymbolFlags.Value) || getTypeOnlyAliasDeclaration(symbol))) {
Expand All @@ -38092,10 +38092,10 @@ namespace ts {
case SyntaxKind.ImportClause:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration: {
if (compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.PreserveExact) {
if (compilerOptions.noErasingImportedNames) {
const message = isType
? Diagnostics._0_is_a_type_and_must_be_imported_with_a_type_only_import_when_importsNotUsedAsValues_is_set_to_preserve_exact
: Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_with_a_type_only_import_when_importsNotUsedAsValues_is_set_to_preserve_exact;
? Diagnostics._0_is_a_type_and_must_be_imported_with_a_type_only_import_when_noErasingImportedNames_and_isolatedModules_are_both_enabled
: Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_with_a_type_only_import_when_noErasingImportedNames_and_isolatedModules_are_both_enabled;
const name = idText(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name!);
addTypeOnlyDeclarationRelatedInfo(
error(node, message, name),
Expand All @@ -38106,29 +38106,21 @@ namespace ts {
break;
}
case SyntaxKind.ExportSpecifier: {
// Don't allow re-exporting an export that will be elided when `--isolatedModules` is set
// or when `--importsNotUsedAsValues` is `preserve-exact`.
if (compilerOptions.isolatedModules &&
compilerOptions.importsNotUsedAsValues !== ImportsNotUsedAsValues.PreserveExact &&
typeOnlyAlias && getSourceFileOfNode(typeOnlyAlias) === getSourceFileOfNode(node)) {
// In `isolatedModules` alone, `import type { A } from './a'; export { A }` is allowed
// because single-file analysis can determine that the export should be dropped.
// `--importsNotUsedAsValues=preserv-exact` is stricter; it refuses to touch non-type-only
// imports and exports, so `export { A }` is not allowed if 'A' is not emitted.
// Don't allow re-exporting an export that will be elided when `--isolatedModules` is set.
// The exception is that `import type { A } from './a'; export { A }` is allowed
// because single-file analysis can determine that the export should be dropped.
if (getSourceFileOfNode(typeOnlyAlias) !== getSourceFileOfNode(node)) {
const message = isType
? Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type
: Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_with_a_type_only_re_export_when_isolatedModules_is_enabled;
const name = idText(node.propertyName || node.name);
addTypeOnlyDeclarationRelatedInfo(
error(node, message, name),
isType ? undefined : typeOnlyAlias,
name
);
return;
}
const message =
compilerOptions.isolatedModules && isType ? Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type :
compilerOptions.isolatedModules && !isType ? Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_with_a_type_only_re_export_when_isolatedModules_is_enabled :
isType ? Diagnostics._0_is_a_type_and_must_be_re_exported_with_a_type_only_re_export_when_importsNotUsedAsValues_is_set_to_preserve_exact :
Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_with_a_type_only_re_export_when_importsNotUsedAsValues_is_set_to_preserve_exact;
const name = idText(node.propertyName || node.name);
addTypeOnlyDeclarationRelatedInfo(
error(node, message, name),
isType ? undefined : typeOnlyAlias,
name
);
return;
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,6 @@ namespace ts {
"remove": ImportsNotUsedAsValues.Remove,
"preserve": ImportsNotUsedAsValues.Preserve,
"error": ImportsNotUsedAsValues.Error,
"preserve-exact": ImportsNotUsedAsValues.PreserveExact,
})),
affectsEmit: true,
affectsSemanticDiagnostics: true,
Expand Down Expand Up @@ -1085,6 +1084,13 @@ namespace ts {
category: Diagnostics.Advanced_Options,
description: Diagnostics.Emit_class_fields_with_Define_instead_of_Set,
},
{
name: "noErasingImportedNames",
type: "boolean",
affectsEmit: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Disable_the_removal_of_unused_imported_identifiers_from_the_JavaScript_output
Comment thread
andrewbranch marked this conversation as resolved.
Outdated
},

{
name: "keyofStringsOnly",
Expand Down
18 changes: 7 additions & 11 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1364,26 +1364,22 @@
"category": "Error",
"code": 1433
},
"'{0}' is a type and must be imported with a type-only import when 'importsNotUsedAsValues' is set to 'preserve-exact'.": {
"'{0}' is a type and must be imported with a type-only import when 'noErasingImportedNames' and 'isolatedModules' are both enabled.": {
"category": "Error",
"code": 1434
},
"'{0}' is a type and must be re-exported with a type-only re-export when 'importsNotUsedAsValues' is set to 'preserve-exact'.": {
"category": "Error",
"code": 1435
},
"'{0}' resolves to a type-only declaration and must be imported with a type-only import when 'importsNotUsedAsValues' is set to 'preserve-exact'.": {
"'{0}' resolves to a type-only declaration and must be imported with a type-only import when 'noErasingImportedNames' and 'isolatedModules' are both enabled.": {
"category": "Error",
"code": 1436
},
"'{0}' resolves to a type-only declaration and must be re-exported with a type-only re-export when 'importsNotUsedAsValues' is set to 'preserve-exact'.": {
"category": "Error",
"code": 1437
},
"'{0}' resolves to a type-only declaration and must be re-exported with a type-only re-export when 'isolatedModules' is enabled.": {
"category": "Error",
"code": 1438
},
"Disable the removal of unused imported identifiers from the JavaScript output.": {
"category": "Message",
"code": 1439
},

"The types of '{0}' are incompatible between these types.": {
"category": "Error",
Expand Down Expand Up @@ -3962,7 +3958,7 @@
"category": "Error",
"code": 5094
},
"Option 'importsNotUsedAsValues' may be set to 'preserve-exact' only when 'module' is set to 'es2015' or later.": {
"Option 'noErasingImportedNames' may be enabled only when 'module' is set to 'es2015' or later.": {
"category": "Error",
"code": 5095
},
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3295,8 +3295,8 @@ namespace ts {
}
}

if (options.importsNotUsedAsValues === ImportsNotUsedAsValues.PreserveExact && getEmitModuleKind(options) < ModuleKind.ES2015) {
createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_importsNotUsedAsValues_may_be_set_to_preserve_exact_only_when_module_is_set_to_es2015_or_later);
if (options.noErasingImportedNames && getEmitModuleKind(options) < ModuleKind.ES2015) {
createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_noErasingImportedNames_may_be_enabled_only_when_module_is_set_to_es2015_or_later);
}

// If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
Expand Down
12 changes: 6 additions & 6 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2803,7 +2803,7 @@ namespace ts {
}

/**
* Visits an import declaration, eliding it if it is not referenced and `importsNotUsedAsValues` is not 'preserve' or 'preserve-exact'.
* Visits an import declaration, eliding it if it is not referenced and `importsNotUsedAsValues` is not 'preserve' and `noErasingImportedNames` is not set.
*
* @param node The import declaration node.
*/
Expand All @@ -2821,8 +2821,8 @@ namespace ts {
// Elide the declaration if the import clause was elided.
const importClause = visitNode(node.importClause, visitImportClause, isImportClause);
return importClause ||
compilerOptions.noErasingImportedNames ||
importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve ||
importsNotUsedAsValues === ImportsNotUsedAsValues.PreserveExact ||
importsNotUsedAsValues === ImportsNotUsedAsValues.Error
? factory.updateImportDeclaration(
node,
Expand All @@ -2834,13 +2834,13 @@ namespace ts {
}

/**
* Visits an import clause, eliding it if it is not referenced and `importsNotUsedAsValues` is not 'preserve-exact'.
* Visits an import clause, eliding it if it is not referenced and `noErasingImportedNames` is not set.
*
* @param node The import clause node.
*/
function visitImportClause(node: ImportClause): VisitResult<ImportClause> {
Debug.assert(!node.isTypeOnly);
if (importsNotUsedAsValues === ImportsNotUsedAsValues.PreserveExact) {
if (compilerOptions.noErasingImportedNames) {
return node;
}
// Elide the import clause if we elide both its name and its named bindings.
Expand Down Expand Up @@ -2891,7 +2891,7 @@ namespace ts {

/**
* Visits an export declaration, eliding it if it does not contain a clause that resolves
* to a value and if `importsNotUsedAsValues` is not 'preserve-exact'.
* to a value and if `noErasingImportedNames` is not set.
*
* @param node The export declaration node.
*/
Expand All @@ -2900,7 +2900,7 @@ namespace ts {
return undefined;
}

if (!node.exportClause || isNamespaceExport(node.exportClause) || importsNotUsedAsValues === ImportsNotUsedAsValues.PreserveExact) {
if (!node.exportClause || isNamespaceExport(node.exportClause) || compilerOptions.noErasingImportedNames) {
// never elide `export <whatever> from <whereever>` declarations -
// they should be kept for sideffects/untyped exports, even when the
// type checker doesn't know about any exports
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5954,6 +5954,7 @@ namespace ts {
/*@internal*/noEmitForJsFiles?: boolean;
noEmitHelpers?: boolean;
noEmitOnError?: boolean;
noErasingImportedNames?: boolean;
noErrorTruncation?: boolean;
noFallthroughCasesInSwitch?: boolean;
noImplicitAny?: boolean; // Always combine with strict property
Expand Down Expand Up @@ -6071,7 +6072,6 @@ namespace ts {
Remove,
Preserve,
Error,
PreserveExact,
}

export const enum NewLineKind {
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2850,6 +2850,7 @@ declare namespace ts {
noEmit?: boolean;
noEmitHelpers?: boolean;
noEmitOnError?: boolean;
noErasingImportedNames?: boolean;
noErrorTruncation?: boolean;
noFallthroughCasesInSwitch?: boolean;
noImplicitAny?: boolean;
Expand Down Expand Up @@ -2946,8 +2947,7 @@ declare namespace ts {
export enum ImportsNotUsedAsValues {
Remove = 0,
Preserve = 1,
Error = 2,
PreserveExact = 3
Error = 2
}
export enum NewLineKind {
CarriageReturnLineFeed = 0,
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2850,6 +2850,7 @@ declare namespace ts {
noEmit?: boolean;
noEmitHelpers?: boolean;
noEmitOnError?: boolean;
noErasingImportedNames?: boolean;
noErrorTruncation?: boolean;
noFallthroughCasesInSwitch?: boolean;
noImplicitAny?: boolean;
Expand Down Expand Up @@ -2946,8 +2947,7 @@ declare namespace ts {
export enum ImportsNotUsedAsValues {
Remove = 0,
Preserve = 1,
Error = 2,
PreserveExact = 3
Error = 2
}
export enum NewLineKind {
CarriageReturnLineFeed = 0,
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//// [tests/cases/conformance/externalModules/typeOnly/importsNotUsedAsValues_preserve-exact.ts] ////
//// [tests/cases/conformance/externalModules/typeOnly/noErasingImportedNames.ts] ////

//// [a.ts]
export default {};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
tests/cases/conformance/externalModules/typeOnly/d.ts(1,1): error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.
tests/cases/conformance/externalModules/typeOnly/e.ts(1,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead.
tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead.


==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ====
export default {};
export const b = 0;
export const c = 1;

==== tests/cases/conformance/externalModules/typeOnly/b.ts (0 errors) ====
import a, { b, c } from "./a";

==== tests/cases/conformance/externalModules/typeOnly/c.ts (0 errors) ====
import * as a from "./a";

==== tests/cases/conformance/externalModules/typeOnly/d.ts (1 errors) ====
export = {};
~~~~~~~~~~~~
!!! error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.

==== tests/cases/conformance/externalModules/typeOnly/e.ts (2 errors) ====
import D = require("./d");
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead.
import DD = require("./d");
~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead.
DD;

==== tests/cases/conformance/externalModules/typeOnly/f.ts (0 errors) ====
import type a from "./a";
import { b, c } from "./a";
b;

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//// [tests/cases/conformance/externalModules/typeOnly/noErasingImportedNames.ts] ////

//// [a.ts]
export default {};
export const b = 0;
export const c = 1;

//// [b.ts]
import a, { b, c } from "./a";

//// [c.ts]
import * as a from "./a";

//// [d.ts]
export = {};

//// [e.ts]
import D = require("./d");
import DD = require("./d");
DD;

//// [f.ts]
import type a from "./a";
import { b, c } from "./a";
b;


//// [a.js]
export default {};
export var b = 0;
export var c = 1;
//// [b.js]
import a, { b, c } from "./a";
//// [c.js]
import * as a from "./a";
//// [d.js]
export {};
//// [e.js]
DD;
export {};
//// [f.js]
import { b, c } from "./a";
b;
Loading