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
Clean up, reword diagnostics
  • Loading branch information
andrewbranch committed Sep 8, 2021
commit 9e2e4dc39d67fcc9674001586c8af3f9ac0921f3
88 changes: 42 additions & 46 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38607,49 +38607,45 @@ namespace ts {
error(node, message, symbolToString(symbol));
}

// Type assertion to defeat the type predicate aliasing of `node` here because
// `isTypeOnlyImportOrExportDeclaration` is a one-sided type guard so `!isDeclaredTypeOnly`
// does not actually imply any narrowing effect on `node`.
const isDeclaredTypeOnly = isTypeOnlyImportOrExportDeclaration(node as never);
if (compilerOptions.isolatedModules
&& !isDeclaredTypeOnly
&& !(node.flags & NodeFlags.Ambient)
&& (!(target.flags & SymbolFlags.Value) || getTypeOnlyAliasDeclaration(symbol))) {
const isType = !(target.flags & SymbolFlags.Value);
&& !isTypeOnlyImportOrExportDeclaration(node)
&& !(node.flags & NodeFlags.Ambient)) {
const typeOnlyAlias = getTypeOnlyAliasDeclaration(symbol);
Comment thread
andrewbranch marked this conversation as resolved.
Outdated

switch (node.kind) {
case SyntaxKind.ImportClause:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration: {
if (compilerOptions.preserveValueImports) {
const message = isType
? Diagnostics._0_is_a_type_and_must_be_imported_with_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled
: Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_with_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled;
const name = idText(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name!);
addTypeOnlyDeclarationRelatedInfo(
error(node, message, name),
isType ? undefined : typeOnlyAlias,
name
);
const isType = !(target.flags & SymbolFlags.Value);
if (isType || typeOnlyAlias) {
switch (node.kind) {
case SyntaxKind.ImportClause:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration: {
if (compilerOptions.preserveValueImports) {
const message = isType
? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled
: Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled;
const name = idText(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name!);
addTypeOnlyDeclarationRelatedInfo(
error(node, message, name),
isType ? undefined : typeOnlyAlias,
name
);
Comment thread
andrewbranch marked this conversation as resolved.
Outdated
}
break;
}
break;
}
case SyntaxKind.ExportSpecifier: {
// 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;
case SyntaxKind.ExportSpecifier: {
// 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_using_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;
}
}
}
}
Expand Down Expand Up @@ -40433,13 +40429,13 @@ namespace ts {
function isValueAliasDeclaration(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
return isAliasResolvedToValue(getSymbolOfNode(node) || unknownSymbol);
return isAliasResolvedToValue(getSymbolOfNode(node));
case SyntaxKind.ImportClause:
case SyntaxKind.NamespaceImport:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ExportSpecifier:
const symbol = getSymbolOfNode(node) || unknownSymbol;
return isAliasResolvedToValue(symbol) && !getTypeOnlyAliasDeclaration(symbol);
const symbol = getSymbolOfNode(node);
return !!symbol && isAliasResolvedToValue(symbol) && !getTypeOnlyAliasDeclaration(symbol);
case SyntaxKind.ExportDeclaration:
const exportClause = (node as ExportDeclaration).exportClause;
return !!exportClause && (
Expand All @@ -40448,7 +40444,7 @@ namespace ts {
);
case SyntaxKind.ExportAssignment:
return (node as ExportAssignment).expression && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier ?
isAliasResolvedToValue(getSymbolOfNode(node) || unknownSymbol) :
isAliasResolvedToValue(getSymbolOfNode(node)) :
true;
}
return false;
Expand All @@ -40465,8 +40461,8 @@ namespace ts {
return isValue && node.moduleReference && !nodeIsMissing(node.moduleReference);
}

function isAliasResolvedToValue(symbol: Symbol): boolean {
if (symbol === unknownSymbol) {
function isAliasResolvedToValue(symbol: Symbol | undefined): boolean {
if (!symbol) {
return false;
}
const target = resolveAlias(symbol);
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1173,7 +1173,7 @@ namespace ts {
type: "boolean",
affectsEmit: true,
category: Diagnostics.Emit,
description: Diagnostics.Disable_the_removal_of_unused_imported_identifiers_from_the_JavaScript_output
description: Diagnostics.Preserve_unused_imported_values_in_the_JavaScript_output_that_would_otherwise_be_removed,
},

{
Expand Down
10 changes: 5 additions & 5 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1408,19 +1408,19 @@
"category": "Error",
"code": 1443
},
"'{0}' is a type and must be imported with a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.": {
"'{0}' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.": {
"category": "Error",
"code": 1444
},
"'{0}' resolves to a type-only declaration and must be imported with a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.": {
"'{0}' resolves to a type-only declaration and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.": {
"category": "Error",
"code": 1446
},
"'{0}' resolves to a type-only declaration and must be re-exported with a type-only re-export when 'isolatedModules' is enabled.": {
"'{0}' resolves to a type-only declaration and must be re-exported using a type-only re-export when 'isolatedModules' is enabled.": {
"category": "Error",
"code": 1448
},
"Disable the removal of unused imported identifiers from the JavaScript output.": {
"Preserve unused imported values in the JavaScript output that would otherwise be removed.": {
"category": "Message",
"code": 1449
},
Expand Down Expand Up @@ -4054,7 +4054,7 @@
"category": "Error",
"code": 5094
},
"Option 'preserveValueImports' may be enabled only when 'module' is set to 'es2015' or later.": {
"Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later.": {
"category": "Error",
"code": 5095
},
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3308,7 +3308,7 @@ namespace ts {
}

if (options.preserveValueImports && getEmitModuleKind(options) < ModuleKind.ES2015) {
createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_preserveValueImports_may_be_enabled_only_when_module_is_set_to_es2015_or_later);
createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_preserveValueImports_can_only_be_used_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
7 changes: 3 additions & 4 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ namespace ts {
const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks");
const languageVersion = getEmitScriptTarget(compilerOptions);
const moduleKind = getEmitModuleKind(compilerOptions);
const { importsNotUsedAsValues } = compilerOptions;

// Save the previous transformation hooks.
const previousOnEmitNode = context.onEmitNode;
Expand Down Expand Up @@ -2810,8 +2809,8 @@ namespace ts {
// Elide the declaration if the import clause was elided.
const importClause = visitNode(node.importClause, visitImportClause, isImportClause);
return importClause ||
importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve ||
importsNotUsedAsValues === ImportsNotUsedAsValues.Error
compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve ||
compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error
? factory.updateImportDeclaration(
node,
/*decorators*/ undefined,
Expand Down Expand Up @@ -2966,7 +2965,7 @@ namespace ts {
if (isExternalModuleImportEqualsDeclaration(node)) {
const isReferenced = shouldEmitAliasDeclaration(node);
// If the alias is unreferenced but we want to keep the import, replace with 'import "mod"'.
if (!isReferenced && importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve) {
if (!isReferenced && compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve) {
return setOriginalNode(
setTextRange(
factory.createImportDeclaration(
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3104,6 +3104,14 @@ namespace ts {
| ImportOrExportSpecifier
;

export type TypeOnlyAliasDeclaration =
| ImportClause & { readonly isTypeOnly: true, readonly name: Identifier }
| ImportEqualsDeclaration & { readonly isTypeOnly: true }
| NamespaceImport & { readonly parent: ImportClause & { readonly isTypeOnly: true } }
| ImportSpecifier & { readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true } } }
| ExportSpecifier & { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } }
;

/**
* This is either an `export =` or an `export default` declaration.
* Unless `isExportEquals` is set, this node was parsed as an `export default`.
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/utilitiesPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@ namespace ts {
return isImportSpecifier(node) || isExportSpecifier(node);
}

export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyCompatibleAliasDeclaration {
export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration {
switch (node.kind) {
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ExportSpecifier:
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/noErasingImportedNames.ts] ////
//// [tests/cases/conformance/externalModules/typeOnly/preserveValueImports.ts] ////

//// [a.ts]
export default {};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
tests/cases/conformance/externalModules/typeOnly/b.ts(1,19): error TS1444: 'D' is a type and must be imported with a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.
tests/cases/conformance/externalModules/typeOnly/b.ts(1,19): error TS1444: 'D' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.
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.
Expand All @@ -13,7 +13,7 @@ tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1202: Import
==== tests/cases/conformance/externalModules/typeOnly/b.ts (1 errors) ====
import a, { b, c, D } from "./a";
~
!!! error TS1444: 'D' is a type and must be imported with a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.
!!! error TS1444: 'D' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.

==== tests/cases/conformance/externalModules/typeOnly/c.ts (0 errors) ====
import * as a from "./a";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//// [tests/cases/conformance/externalModules/typeOnly/noErasingImportedNames.ts] ////
//// [tests/cases/conformance/externalModules/typeOnly/preserveValueImports.ts] ////

//// [a.ts]
export default {};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//// [tests/cases/conformance/externalModules/typeOnly/noErasingImportedNames_errors.ts] ////
//// [tests/cases/conformance/externalModules/typeOnly/preserveValueImports_errors.ts] ////

//// [a.ts]
export type A = {};
Expand Down
Loading