From 368cdfd29ace559e257a3c92b12212c626a5a692 Mon Sep 17 00:00:00 2001 From: Chris West Date: Wed, 13 Jan 2021 23:51:08 +0000 Subject: [PATCH] fix: const enums + isolatedModules emit invalid code (#41933) * chore: failing test for const enums and isolatedModules * fix: const enums + isolatedModules emit invalid code In `isolatedModules` mode, the compiler does not inline const enums, but also decides not to `import` them, leaving invalid code that throws a `ReferenceError` at runtime. This code: ``` import { SomeEnum } from './bar'; sink(SomeEnum.VALUE); ``` ..should compile to either: ``` var { SomeEnum } = require('./bar'); sink(SomeEnum.VALUE); ``` ..or (with const enum inlining): ``` sink(1 /* VALUE */); ``` ..but actually compiles to: ``` sink(SomeEnum.VALUE); ``` ..with no imports, which throws a ReferenceError at runtime. --- The compiler has already realised that the symbol is a referenced const enum, it just doesn't use this information when it comes to deciding whether to emit an import. This commit additionally checks that information, if we are compiling in isolatedModules mode. --- In my opinion, this is not the correct fix, but it is the simplest. In `isolatedModules` mode, `const enum` should probably be a compile error (because there are no benefits and the complexity is high, and, apparently, buggy). If not, the compiler should not be checking whether something is a const enum, and should just be treating it as a regular enum, and checking as if it was? Fixes #40499. * chore: extra test for type-only * feat: explicitly ban --isolatedModules --preserveConstEnums false * feat: isolatedModules implies preserveConstEnum * Update src/compiler/diagnosticMessages.json Co-authored-by: Andrew Branch * chore: compiler test for argument incompatibility * Add and fix test for namespace import of const enum * Fix additional bug with reexport of const-enum-only module Co-authored-by: Andrew Branch Co-authored-by: Andrew Branch --- src/compiler/binder.ts | 2 +- src/compiler/checker.ts | 25 +++++++--- src/compiler/diagnosticMessages.json | 4 ++ src/compiler/program.ts | 4 ++ src/compiler/transformers/ts.ts | 5 +- src/compiler/utilities.ts | 4 ++ ...ceCausesNoImport(isolatedmodules=false).js | 35 +++++++++++++ ...sesNoImport(isolatedmodules=false).symbols | 40 +++++++++++++++ ...ausesNoImport(isolatedmodules=false).types | 39 +++++++++++++++ ...nceCausesNoImport(isolatedmodules=true).js | 42 ++++++++++++++++ ...usesNoImport(isolatedmodules=true).symbols | 40 +++++++++++++++ ...CausesNoImport(isolatedmodules=true).types | 39 +++++++++++++++ ...stEnumNamespaceReferenceCausesNoImport2.js | 50 +++++++++++++++++++ .../isolatedModulesImportConstEnum.js | 25 ++++++++++ .../isolatedModulesImportConstEnum.symbols | 20 ++++++++ .../isolatedModulesImportConstEnum.types | 21 ++++++++ .../isolatedModulesImportConstEnumTypeOnly.js | 22 ++++++++ ...atedModulesImportConstEnumTypeOnly.symbols | 14 ++++++ ...olatedModulesImportConstEnumTypeOnly.types | 13 +++++ ...odulesRequiresPreserveConstEnum.errors.txt | 8 +++ ...solatedModulesRequiresPreserveConstEnum.js | 8 +++ ...edModulesRequiresPreserveConstEnum.symbols | 5 ++ ...atedModulesRequiresPreserveConstEnum.types | 5 ++ ...nstEnumNamespaceReferenceCausesNoImport.ts | 2 + ...stEnumNamespaceReferenceCausesNoImport2.ts | 24 +++++++++ .../isolatedModulesImportConstEnum.ts | 13 +++++ .../isolatedModulesImportConstEnumTypeOnly.ts | 8 +++ ...solatedModulesRequiresPreserveConstEnum.ts | 8 +++ 28 files changed, 514 insertions(+), 11 deletions(-) create mode 100644 tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).js create mode 100644 tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).symbols create mode 100644 tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).types create mode 100644 tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).js create mode 100644 tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).symbols create mode 100644 tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).types create mode 100644 tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport2.js create mode 100644 tests/baselines/reference/isolatedModulesImportConstEnum.js create mode 100644 tests/baselines/reference/isolatedModulesImportConstEnum.symbols create mode 100644 tests/baselines/reference/isolatedModulesImportConstEnum.types create mode 100644 tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.js create mode 100644 tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.symbols create mode 100644 tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.types create mode 100644 tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.errors.txt create mode 100644 tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.js create mode 100644 tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.symbols create mode 100644 tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.types create mode 100644 tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport2.ts create mode 100644 tests/cases/compiler/isolatedModulesImportConstEnum.ts create mode 100644 tests/cases/compiler/isolatedModulesImportConstEnumTypeOnly.ts create mode 100644 tests/cases/compiler/isolatedModulesRequiresPreserveConstEnum.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 11b1955869d..b397bbf28d5 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3435,7 +3435,7 @@ namespace ts { function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean { const instanceState = getModuleInstanceState(node); - return instanceState === ModuleInstanceState.Instantiated || (instanceState === ModuleInstanceState.ConstEnumOnly && !!options.preserveConstEnums); + return instanceState === ModuleInstanceState.Instantiated || (instanceState === ModuleInstanceState.ConstEnumOnly && shouldPreserveConstEnums(options)); } function checkUnreachable(node: Node): boolean { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index af8faea439c..70bd5d08ebf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2395,7 +2395,7 @@ namespace ts { } else { Debug.assert(!!(result.flags & SymbolFlags.ConstEnum)); - if (compilerOptions.preserveConstEnums) { + if (shouldPreserveConstEnums(compilerOptions)) { diagnosticMessage = error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationName); } } @@ -23215,7 +23215,13 @@ namespace ts { if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !getTypeOnlyAliasDeclaration(symbol)) { const target = resolveAlias(symbol); if (target.flags & SymbolFlags.Value) { - if (compilerOptions.preserveConstEnums && isExportOrExportExpression(location) || !isConstEnumOrConstEnumOnlyModule(target)) { + // An alias resolving to a const enum cannot be elided if (1) 'isolatedModules' is enabled + // (because the const enum value will not be inlined), or if (2) the alias is an export + // of a const enum declaration that will be preserved. + if (compilerOptions.isolatedModules || + shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location) || + !isConstEnumOrConstEnumOnlyModule(target) + ) { markAliasSymbolAsReferenced(symbol); } else { @@ -26271,7 +26277,11 @@ namespace ts { } prop = getPropertyOfType(apparentType, right.escapedText); } - if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) { + // In `Foo.Bar.Baz`, 'Foo' is not referenced if 'Bar' is a const enum or a module containing only const enums. + // The exceptions are: + // 1. if 'isolatedModules' is enabled, because the const enum value will not be inlined, and + // 2. if 'preserveConstEnums' is enabled and the expression is itself an export, e.g. `export = Foo.Bar.Baz`. + if (isIdentifier(left) && parentSymbol && (compilerOptions.isolatedModules || !(prop && isConstEnumOrConstEnumOnlyModule(prop)) || shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(node))) { markAliasReferenced(parentSymbol, node); } @@ -36648,7 +36658,7 @@ namespace ts { if (symbol.flags & SymbolFlags.ValueModule && !inAmbientContext && symbol.declarations.length > 1 - && isInstantiatedModule(node, !!compilerOptions.preserveConstEnums || !!compilerOptions.isolatedModules)) { + && isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions))) { const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); if (firstNonAmbientClassOrFunc) { if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { @@ -38571,7 +38581,7 @@ namespace ts { // const enums and modules that contain only const enums are not considered values from the emit perspective // unless 'preserveConstEnums' option is set to true return !!(target.flags & SymbolFlags.Value) && - (compilerOptions.preserveConstEnums || !isConstEnumOrConstEnumOnlyModule(target)); + (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)); } function isConstEnumOrConstEnumOnlyModule(s: Symbol): boolean { @@ -38581,13 +38591,14 @@ namespace ts { function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean { if (isAliasSymbolDeclaration(node)) { const symbol = getSymbolOfNode(node); - if (symbol && getSymbolLinks(symbol).referenced) { + const links = symbol && getSymbolLinks(symbol); + if (links?.referenced) { return true; } const target = getSymbolLinks(symbol!).target; // TODO: GH#18217 if (target && getEffectiveModifierFlags(node) & ModifierFlags.Export && target.flags & SymbolFlags.Value && - (compilerOptions.preserveConstEnums || !isConstEnumOrConstEnumOnlyModule(target))) { + (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target))) { // An `export import ... =` of a value symbol is always considered referenced return true; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 8162ea6b3ef..d96b2957da6 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3813,6 +3813,10 @@ "category": "Error", "code": 5090 }, + "Option 'preserveConstEnums' cannot be disabled when 'isolatedModules' is enabled.": { + "category": "Error", + "code": 5091 + }, "Generates a sourcemap for each corresponding '.d.ts' file.": { "category": "Message", diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 10ac23aa196..bc7e006801d 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -3157,6 +3157,10 @@ namespace ts { createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target"); } + if (options.preserveConstEnums === false) { + createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_isolatedModules_is_enabled, "preserveConstEnums", "isolatedModules"); + } + const firstNonExternalModuleSourceFile = find(files, f => !isExternalModule(f) && !isSourceFileJS(f) && !f.isDeclarationFile && f.scriptKind !== ScriptKind.JSON); if (firstNonExternalModuleSourceFile) { const span = getErrorSpanForNode(firstNonExternalModuleSourceFile, firstNonExternalModuleSourceFile); diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 9cc9c1c3fc9..0d24f332c15 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2316,8 +2316,7 @@ namespace ts { */ function shouldEmitEnumDeclaration(node: EnumDeclaration) { return !isEnumConst(node) - || compilerOptions.preserveConstEnums - || compilerOptions.isolatedModules; + || shouldPreserveConstEnums(compilerOptions); } /** @@ -2507,7 +2506,7 @@ namespace ts { // If we can't find a parse tree node, assume the node is instantiated. return true; } - return isInstantiatedModule(node, !!compilerOptions.preserveConstEnums || !!compilerOptions.isolatedModules); + return isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions)); } /** diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 85a19df7f06..8afa9482369 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6001,6 +6001,10 @@ namespace ts { return !!(compilerOptions.declaration || compilerOptions.composite); } + export function shouldPreserveConstEnums(compilerOptions: CompilerOptions): boolean { + return !!(compilerOptions.preserveConstEnums || compilerOptions.isolatedModules); + } + export function isIncrementalCompilation(options: CompilerOptions) { return !!(options.incremental || options.composite); } diff --git a/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).js b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).js new file mode 100644 index 00000000000..145cb9d37e8 --- /dev/null +++ b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).js @@ -0,0 +1,35 @@ +//// [tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport.ts] //// + +//// [foo.ts] +export const enum ConstFooEnum { + Some, + Values, + Here +}; +export function fooFunc(): void { /* removed */ } +//// [index.ts] +import * as Foo from "./foo"; + +function check(x: Foo.ConstFooEnum): void { + switch (x) { + case Foo.ConstFooEnum.Some: + break; + } +} + +//// [foo.js] +"use strict"; +exports.__esModule = true; +exports.fooFunc = void 0; +; +function fooFunc() { } +exports.fooFunc = fooFunc; +//// [index.js] +"use strict"; +exports.__esModule = true; +function check(x) { + switch (x) { + case 0 /* Some */: + break; + } +} diff --git a/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).symbols b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).symbols new file mode 100644 index 00000000000..92a85013834 --- /dev/null +++ b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).symbols @@ -0,0 +1,40 @@ +=== tests/cases/compiler/foo.ts === +export const enum ConstFooEnum { +>ConstFooEnum : Symbol(ConstFooEnum, Decl(foo.ts, 0, 0)) + + Some, +>Some : Symbol(ConstFooEnum.Some, Decl(foo.ts, 0, 32)) + + Values, +>Values : Symbol(ConstFooEnum.Values, Decl(foo.ts, 1, 9)) + + Here +>Here : Symbol(ConstFooEnum.Here, Decl(foo.ts, 2, 11)) + +}; +export function fooFunc(): void { /* removed */ } +>fooFunc : Symbol(fooFunc, Decl(foo.ts, 4, 2)) + +=== tests/cases/compiler/index.ts === +import * as Foo from "./foo"; +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) + +function check(x: Foo.ConstFooEnum): void { +>check : Symbol(check, Decl(index.ts, 0, 29)) +>x : Symbol(x, Decl(index.ts, 2, 15)) +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) +>ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0)) + + switch (x) { +>x : Symbol(x, Decl(index.ts, 2, 15)) + + case Foo.ConstFooEnum.Some: +>Foo.ConstFooEnum.Some : Symbol(Foo.ConstFooEnum.Some, Decl(foo.ts, 0, 32)) +>Foo.ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0)) +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) +>ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0)) +>Some : Symbol(Foo.ConstFooEnum.Some, Decl(foo.ts, 0, 32)) + + break; + } +} diff --git a/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).types b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).types new file mode 100644 index 00000000000..dc9c6ea705b --- /dev/null +++ b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=false).types @@ -0,0 +1,39 @@ +=== tests/cases/compiler/foo.ts === +export const enum ConstFooEnum { +>ConstFooEnum : ConstFooEnum + + Some, +>Some : ConstFooEnum.Some + + Values, +>Values : ConstFooEnum.Values + + Here +>Here : ConstFooEnum.Here + +}; +export function fooFunc(): void { /* removed */ } +>fooFunc : () => void + +=== tests/cases/compiler/index.ts === +import * as Foo from "./foo"; +>Foo : typeof Foo + +function check(x: Foo.ConstFooEnum): void { +>check : (x: Foo.ConstFooEnum) => void +>x : Foo.ConstFooEnum +>Foo : any + + switch (x) { +>x : Foo.ConstFooEnum + + case Foo.ConstFooEnum.Some: +>Foo.ConstFooEnum.Some : Foo.ConstFooEnum.Some +>Foo.ConstFooEnum : typeof Foo.ConstFooEnum +>Foo : typeof Foo +>ConstFooEnum : typeof Foo.ConstFooEnum +>Some : Foo.ConstFooEnum.Some + + break; + } +} diff --git a/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).js b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).js new file mode 100644 index 00000000000..4f282ee36fb --- /dev/null +++ b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).js @@ -0,0 +1,42 @@ +//// [tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport.ts] //// + +//// [foo.ts] +export const enum ConstFooEnum { + Some, + Values, + Here +}; +export function fooFunc(): void { /* removed */ } +//// [index.ts] +import * as Foo from "./foo"; + +function check(x: Foo.ConstFooEnum): void { + switch (x) { + case Foo.ConstFooEnum.Some: + break; + } +} + +//// [foo.js] +"use strict"; +exports.__esModule = true; +exports.fooFunc = exports.ConstFooEnum = void 0; +var ConstFooEnum; +(function (ConstFooEnum) { + ConstFooEnum[ConstFooEnum["Some"] = 0] = "Some"; + ConstFooEnum[ConstFooEnum["Values"] = 1] = "Values"; + ConstFooEnum[ConstFooEnum["Here"] = 2] = "Here"; +})(ConstFooEnum = exports.ConstFooEnum || (exports.ConstFooEnum = {})); +; +function fooFunc() { } +exports.fooFunc = fooFunc; +//// [index.js] +"use strict"; +exports.__esModule = true; +var Foo = require("./foo"); +function check(x) { + switch (x) { + case Foo.ConstFooEnum.Some: + break; + } +} diff --git a/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).symbols b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).symbols new file mode 100644 index 00000000000..92a85013834 --- /dev/null +++ b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).symbols @@ -0,0 +1,40 @@ +=== tests/cases/compiler/foo.ts === +export const enum ConstFooEnum { +>ConstFooEnum : Symbol(ConstFooEnum, Decl(foo.ts, 0, 0)) + + Some, +>Some : Symbol(ConstFooEnum.Some, Decl(foo.ts, 0, 32)) + + Values, +>Values : Symbol(ConstFooEnum.Values, Decl(foo.ts, 1, 9)) + + Here +>Here : Symbol(ConstFooEnum.Here, Decl(foo.ts, 2, 11)) + +}; +export function fooFunc(): void { /* removed */ } +>fooFunc : Symbol(fooFunc, Decl(foo.ts, 4, 2)) + +=== tests/cases/compiler/index.ts === +import * as Foo from "./foo"; +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) + +function check(x: Foo.ConstFooEnum): void { +>check : Symbol(check, Decl(index.ts, 0, 29)) +>x : Symbol(x, Decl(index.ts, 2, 15)) +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) +>ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0)) + + switch (x) { +>x : Symbol(x, Decl(index.ts, 2, 15)) + + case Foo.ConstFooEnum.Some: +>Foo.ConstFooEnum.Some : Symbol(Foo.ConstFooEnum.Some, Decl(foo.ts, 0, 32)) +>Foo.ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0)) +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) +>ConstFooEnum : Symbol(Foo.ConstFooEnum, Decl(foo.ts, 0, 0)) +>Some : Symbol(Foo.ConstFooEnum.Some, Decl(foo.ts, 0, 32)) + + break; + } +} diff --git a/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).types b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).types new file mode 100644 index 00000000000..dc9c6ea705b --- /dev/null +++ b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport(isolatedmodules=true).types @@ -0,0 +1,39 @@ +=== tests/cases/compiler/foo.ts === +export const enum ConstFooEnum { +>ConstFooEnum : ConstFooEnum + + Some, +>Some : ConstFooEnum.Some + + Values, +>Values : ConstFooEnum.Values + + Here +>Here : ConstFooEnum.Here + +}; +export function fooFunc(): void { /* removed */ } +>fooFunc : () => void + +=== tests/cases/compiler/index.ts === +import * as Foo from "./foo"; +>Foo : typeof Foo + +function check(x: Foo.ConstFooEnum): void { +>check : (x: Foo.ConstFooEnum) => void +>x : Foo.ConstFooEnum +>Foo : any + + switch (x) { +>x : Foo.ConstFooEnum + + case Foo.ConstFooEnum.Some: +>Foo.ConstFooEnum.Some : Foo.ConstFooEnum.Some +>Foo.ConstFooEnum : typeof Foo.ConstFooEnum +>Foo : typeof Foo +>ConstFooEnum : typeof Foo.ConstFooEnum +>Some : Foo.ConstFooEnum.Some + + break; + } +} diff --git a/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport2.js b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport2.js new file mode 100644 index 00000000000..02a802f20ea --- /dev/null +++ b/tests/baselines/reference/constEnumNamespaceReferenceCausesNoImport2.js @@ -0,0 +1,50 @@ +//// [tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport2.ts] //// + +//// [foo.ts] +export module ConstEnumOnlyModule { + export const enum ConstFooEnum { + Some, + Values, + Here + } +} + +//// [reexport.ts] +import * as Foo from "./foo"; +export = Foo.ConstEnumOnlyModule; + +//// [index.ts] +import Foo = require("./reexport"); +function check(x: Foo.ConstFooEnum): void { + switch (x) { + case Foo.ConstFooEnum.Some: + break; + } +} + +//// [foo.js] +"use strict"; +exports.__esModule = true; +exports.ConstEnumOnlyModule = void 0; +var ConstEnumOnlyModule; +(function (ConstEnumOnlyModule) { + var ConstFooEnum; + (function (ConstFooEnum) { + ConstFooEnum[ConstFooEnum["Some"] = 0] = "Some"; + ConstFooEnum[ConstFooEnum["Values"] = 1] = "Values"; + ConstFooEnum[ConstFooEnum["Here"] = 2] = "Here"; + })(ConstFooEnum = ConstEnumOnlyModule.ConstFooEnum || (ConstEnumOnlyModule.ConstFooEnum = {})); +})(ConstEnumOnlyModule = exports.ConstEnumOnlyModule || (exports.ConstEnumOnlyModule = {})); +//// [reexport.js] +"use strict"; +var Foo = require("./foo"); +module.exports = Foo.ConstEnumOnlyModule; +//// [index.js] +"use strict"; +exports.__esModule = true; +function check(x) { + switch (x) { + case 0 /* Some */: + break; + } +} diff --git a/tests/baselines/reference/isolatedModulesImportConstEnum.js b/tests/baselines/reference/isolatedModulesImportConstEnum.js new file mode 100644 index 00000000000..6af32fc5e90 --- /dev/null +++ b/tests/baselines/reference/isolatedModulesImportConstEnum.js @@ -0,0 +1,25 @@ +//// [tests/cases/compiler/isolatedModulesImportConstEnum.ts] //// + +//// [file1.ts] +import { Foo } from './file2'; +console.log(Foo.BAR); + +//// [file2.ts] +export const enum Foo { + BAR, +} + + +//// [file2.js] +"use strict"; +exports.__esModule = true; +exports.Foo = void 0; +var Foo; +(function (Foo) { + Foo[Foo["BAR"] = 0] = "BAR"; +})(Foo = exports.Foo || (exports.Foo = {})); +//// [file1.js] +"use strict"; +exports.__esModule = true; +var file2_1 = require("./file2"); +console.log(file2_1.Foo.BAR); diff --git a/tests/baselines/reference/isolatedModulesImportConstEnum.symbols b/tests/baselines/reference/isolatedModulesImportConstEnum.symbols new file mode 100644 index 00000000000..797b8825c7d --- /dev/null +++ b/tests/baselines/reference/isolatedModulesImportConstEnum.symbols @@ -0,0 +1,20 @@ +=== tests/cases/compiler/file1.ts === +import { Foo } from './file2'; +>Foo : Symbol(Foo, Decl(file1.ts, 0, 8)) + +console.log(Foo.BAR); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>Foo.BAR : Symbol(Foo.BAR, Decl(file2.ts, 0, 23)) +>Foo : Symbol(Foo, Decl(file1.ts, 0, 8)) +>BAR : Symbol(Foo.BAR, Decl(file2.ts, 0, 23)) + +=== tests/cases/compiler/file2.ts === +export const enum Foo { +>Foo : Symbol(Foo, Decl(file2.ts, 0, 0)) + + BAR, +>BAR : Symbol(Foo.BAR, Decl(file2.ts, 0, 23)) +} + diff --git a/tests/baselines/reference/isolatedModulesImportConstEnum.types b/tests/baselines/reference/isolatedModulesImportConstEnum.types new file mode 100644 index 00000000000..70f9856d663 --- /dev/null +++ b/tests/baselines/reference/isolatedModulesImportConstEnum.types @@ -0,0 +1,21 @@ +=== tests/cases/compiler/file1.ts === +import { Foo } from './file2'; +>Foo : typeof Foo + +console.log(Foo.BAR); +>console.log(Foo.BAR) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>Foo.BAR : Foo +>Foo : typeof Foo +>BAR : Foo + +=== tests/cases/compiler/file2.ts === +export const enum Foo { +>Foo : Foo + + BAR, +>BAR : Foo.BAR +} + diff --git a/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.js b/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.js new file mode 100644 index 00000000000..3781ecf9eed --- /dev/null +++ b/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.js @@ -0,0 +1,22 @@ +//// [tests/cases/compiler/isolatedModulesImportConstEnumTypeOnly.ts] //// + +//// [enum.ts] +export const enum Foo { Bar } + +//// [index.ts] +import { Foo } from "./enum"; +function f(foo: Foo) { return; } + + +//// [enum.js] +"use strict"; +exports.__esModule = true; +exports.Foo = void 0; +var Foo; +(function (Foo) { + Foo[Foo["Bar"] = 0] = "Bar"; +})(Foo = exports.Foo || (exports.Foo = {})); +//// [index.js] +"use strict"; +exports.__esModule = true; +function f(foo) { return; } diff --git a/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.symbols b/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.symbols new file mode 100644 index 00000000000..52fb92e2c71 --- /dev/null +++ b/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.symbols @@ -0,0 +1,14 @@ +=== tests/cases/compiler/enum.ts === +export const enum Foo { Bar } +>Foo : Symbol(Foo, Decl(enum.ts, 0, 0)) +>Bar : Symbol(Foo.Bar, Decl(enum.ts, 0, 23)) + +=== tests/cases/compiler/index.ts === +import { Foo } from "./enum"; +>Foo : Symbol(Foo, Decl(index.ts, 0, 8)) + +function f(foo: Foo) { return; } +>f : Symbol(f, Decl(index.ts, 0, 29)) +>foo : Symbol(foo, Decl(index.ts, 1, 11)) +>Foo : Symbol(Foo, Decl(index.ts, 0, 8)) + diff --git a/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.types b/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.types new file mode 100644 index 00000000000..fea6ef63fee --- /dev/null +++ b/tests/baselines/reference/isolatedModulesImportConstEnumTypeOnly.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/enum.ts === +export const enum Foo { Bar } +>Foo : Foo +>Bar : Foo.Bar + +=== tests/cases/compiler/index.ts === +import { Foo } from "./enum"; +>Foo : typeof Foo + +function f(foo: Foo) { return; } +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.errors.txt b/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.errors.txt new file mode 100644 index 00000000000..70ddd6b8b8b --- /dev/null +++ b/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.errors.txt @@ -0,0 +1,8 @@ +error TS5091: Option 'preserveConstEnums' cannot be disabled when 'isolatedModules' is enabled. + + +!!! error TS5091: Option 'preserveConstEnums' cannot be disabled when 'isolatedModules' is enabled. +==== tests/cases/compiler/file1.ts (0 errors) ==== + export {}; + + \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.js b/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.js new file mode 100644 index 00000000000..0691bf23e38 --- /dev/null +++ b/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.js @@ -0,0 +1,8 @@ +//// [file1.ts] +export {}; + + + +//// [file1.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.symbols b/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.symbols new file mode 100644 index 00000000000..39ef3fa478d --- /dev/null +++ b/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.symbols @@ -0,0 +1,5 @@ +=== tests/cases/compiler/file1.ts === +export {}; +No type information for this code. +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.types b/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.types new file mode 100644 index 00000000000..39ef3fa478d --- /dev/null +++ b/tests/baselines/reference/isolatedModulesRequiresPreserveConstEnum.types @@ -0,0 +1,5 @@ +=== tests/cases/compiler/file1.ts === +export {}; +No type information for this code. +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport.ts b/tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport.ts index 3df68067ef5..f43f740ba91 100644 --- a/tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport.ts +++ b/tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport.ts @@ -1,3 +1,5 @@ +// @isolatedModules: true, false + // @filename: foo.ts export const enum ConstFooEnum { Some, diff --git a/tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport2.ts b/tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport2.ts new file mode 100644 index 00000000000..06abeafd1fb --- /dev/null +++ b/tests/cases/compiler/constEnumNamespaceReferenceCausesNoImport2.ts @@ -0,0 +1,24 @@ +// @preserveConstEnums: true +// @noTypesAndSymbols: true + +// @filename: foo.ts +export module ConstEnumOnlyModule { + export const enum ConstFooEnum { + Some, + Values, + Here + } +} + +// @filename: reexport.ts +import * as Foo from "./foo"; +export = Foo.ConstEnumOnlyModule; + +// @filename: index.ts +import Foo = require("./reexport"); +function check(x: Foo.ConstFooEnum): void { + switch (x) { + case Foo.ConstFooEnum.Some: + break; + } +} \ No newline at end of file diff --git a/tests/cases/compiler/isolatedModulesImportConstEnum.ts b/tests/cases/compiler/isolatedModulesImportConstEnum.ts new file mode 100644 index 00000000000..46768cb75a1 --- /dev/null +++ b/tests/cases/compiler/isolatedModulesImportConstEnum.ts @@ -0,0 +1,13 @@ +// @isolatedModules: true +// @module: commonjs + +// @filename: file1.ts + +import { Foo } from './file2'; +console.log(Foo.BAR); + +// @filename: file2.ts + +export const enum Foo { + BAR, +} diff --git a/tests/cases/compiler/isolatedModulesImportConstEnumTypeOnly.ts b/tests/cases/compiler/isolatedModulesImportConstEnumTypeOnly.ts new file mode 100644 index 00000000000..85b89be6e75 --- /dev/null +++ b/tests/cases/compiler/isolatedModulesImportConstEnumTypeOnly.ts @@ -0,0 +1,8 @@ +// @isolatedModules: true + +// @filename: enum.ts +export const enum Foo { Bar } + +// @filename: index.ts +import { Foo } from "./enum"; +function f(foo: Foo) { return; } diff --git a/tests/cases/compiler/isolatedModulesRequiresPreserveConstEnum.ts b/tests/cases/compiler/isolatedModulesRequiresPreserveConstEnum.ts new file mode 100644 index 00000000000..34d601df00b --- /dev/null +++ b/tests/cases/compiler/isolatedModulesRequiresPreserveConstEnum.ts @@ -0,0 +1,8 @@ +// @isolatedModules: true +// @preserveConstEnums: false +// @module: commonjs + +// @filename: file1.ts + +export {}; +