Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions internal/transformers/tstransforms/runtimesyntax.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package tstransforms

// !!! Unqualified enum member references across merged enum declarations are not currently supported (e.g `enum E {A}; enum E {B=A}`)
// !!! Unqualified namespace member references across merged namespace declarations are not currently supported (e.g `namespace N { export var x = 1; }; namespace N { x; }`).
// !!! SourceMaps and Comments need to be validated

import (
Expand Down Expand Up @@ -1048,7 +1046,18 @@ func (tx *RuntimeSyntaxTransformer) visitExpressionIdentifier(node *ast.Identifi
tx.resolver = binder.NewReferenceResolver(tx.compilerOptions, binder.ReferenceResolverHooks{})
}
container := tx.resolver.GetReferencedExportContainer(location, false /*prefixLocals*/)
if container != nil && (ast.IsEnumDeclaration(container) || ast.IsModuleDeclaration(container)) && container.Contains(location) {
// Get symbols from the original nodes (before transformation) since transformed nodes may not have symbols
var currentNamespaceSymbol *ast.Symbol
var currentEnumSymbol *ast.Symbol
if tx.currentNamespace != nil {
currentNamespaceSymbol = tx.EmitContext().MostOriginal(tx.currentNamespace).Symbol()
}
if tx.currentEnum != nil {
currentEnumSymbol = tx.EmitContext().MostOriginal(tx.currentEnum).Symbol()
}
if container != nil &&
((ast.IsModuleDeclaration(container) && currentNamespaceSymbol != nil && container.Symbol() == currentNamespaceSymbol) ||
(ast.IsEnumDeclaration(container) && currentEnumSymbol != nil && container.Symbol() == currentEnumSymbol)) {
containerName := tx.getNamespaceContainerName(container)

memberName := node.Clone(tx.Factory())
Expand Down
41 changes: 39 additions & 2 deletions internal/transformers/tstransforms/runtimesyntax_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ var E;
E[E["A"] = 0] = "A";
})(E || (E = {}));
(function (E) {
E["B"] = A;
E["B"] = E.A;
if (typeof E.B !== "string") E[E.B] = "B";
})(E || (E = {}));`},

Expand Down Expand Up @@ -268,7 +268,7 @@ func TestNamespaceTransformer(t *testing.T) {
N.x = 1;
})(N || (N = {}));
(function (N) {
x;
N.x;
})(N || (N = {}));`},

{title: "exported array binding pattern", input: "namespace N { export var [x] = [1]; }", output: `var N;
Expand Down Expand Up @@ -342,13 +342,50 @@ func TestNamespaceTransformer(t *testing.T) {
N.f = f;
})(N || (N = {}));`},

{title: "exported function call across namespaces", input: "namespace N { export function Foo() {} } namespace N { Foo(); }", output: `var N;
(function (N) {
function Foo() { }
N.Foo = Foo;
})(N || (N = {}));
(function (N) {
N.Foo();
})(N || (N = {}));`},

{title: "export class", input: "namespace N { export class C {} }", output: `var N;
(function (N) {
class C {
}
N.C = C;
})(N || (N = {}));`},

{title: "class extends across namespaces", input: "namespace A { export class TypeA {} } namespace A { export class TypeB extends TypeA {} }", output: `var A;
(function (A) {
class TypeA {
}
A.TypeA = TypeA;
})(A || (A = {}));
(function (A) {
class TypeB extends A.TypeA {
}
A.TypeB = TypeB;
})(A || (A = {}));`},

{title: "three namespace blocks with class inheritance", input: "namespace N { export class A {} } namespace N { export class B extends A {} } namespace N { class C extends B {} }", output: `var N;
(function (N) {
class A {
}
N.A = A;
})(N || (N = {}));
(function (N) {
class B extends N.A {
}
N.B = B;
})(N || (N = {}));
(function (N) {
class C extends N.B {
}
})(N || (N = {}));`},

{title: "export enum", input: "namespace N { export enum E {A} }", output: `var N;
(function (N) {
let E;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//// [tests/cases/compiler/mergedNamespaceExportReference.ts] ////

//// [mergedNamespaceExportReference.ts]
// Test that references to exported namespace members across merged namespace
// declarations are correctly qualified in the emitted JavaScript.

namespace N {
export function foo() { return 1; }
export var x = 1;
export class C {}
}

namespace N {
// These should emit as N.foo(), N.x, and N.C
foo();
x;
class D extends C {}
}


//// [mergedNamespaceExportReference.js]
// Test that references to exported namespace members across merged namespace
// declarations are correctly qualified in the emitted JavaScript.
var N;
(function (N) {
function foo() { return 1; }
N.foo = foo;
N.x = 1;
class C {
}
N.C = C;
})(N || (N = {}));
(function (N) {
// These should emit as N.foo(), N.x, and N.C
N.foo();
N.x;
class D extends N.C {
}
})(N || (N = {}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [tests/cases/compiler/mergedNamespaceExportReference.ts] ////

=== mergedNamespaceExportReference.ts ===
// Test that references to exported namespace members across merged namespace
// declarations are correctly qualified in the emitted JavaScript.

namespace N {
>N : Symbol(N, Decl(mergedNamespaceExportReference.ts, 0, 0), Decl(mergedNamespaceExportReference.ts, 7, 1))

export function foo() { return 1; }
>foo : Symbol(foo, Decl(mergedNamespaceExportReference.ts, 3, 13))

export var x = 1;
>x : Symbol(x, Decl(mergedNamespaceExportReference.ts, 5, 14))

export class C {}
>C : Symbol(C, Decl(mergedNamespaceExportReference.ts, 5, 21))
}

namespace N {
>N : Symbol(N, Decl(mergedNamespaceExportReference.ts, 0, 0), Decl(mergedNamespaceExportReference.ts, 7, 1))

// These should emit as N.foo(), N.x, and N.C
foo();
>foo : Symbol(foo, Decl(mergedNamespaceExportReference.ts, 3, 13))

x;
>x : Symbol(x, Decl(mergedNamespaceExportReference.ts, 5, 14))

class D extends C {}
>D : Symbol(D, Decl(mergedNamespaceExportReference.ts, 12, 6))
>C : Symbol(C, Decl(mergedNamespaceExportReference.ts, 5, 21))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//// [tests/cases/compiler/mergedNamespaceExportReference.ts] ////

=== mergedNamespaceExportReference.ts ===
// Test that references to exported namespace members across merged namespace
// declarations are correctly qualified in the emitted JavaScript.

namespace N {
>N : typeof N

export function foo() { return 1; }
>foo : () => number
>1 : 1

export var x = 1;
>x : number
>1 : 1

export class C {}
>C : C
}

namespace N {
>N : typeof N

// These should emit as N.foo(), N.x, and N.C
foo();
>foo() : number
>foo : () => number

x;
>x : number

class D extends C {}
>D : D
>C : C
}

17 changes: 17 additions & 0 deletions testdata/tests/cases/compiler/mergedNamespaceExportReference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @target: esnext

// Test that references to exported namespace members across merged namespace
// declarations are correctly qualified in the emitted JavaScript.

namespace N {
export function foo() { return 1; }
export var x = 1;
export class C {}
}

namespace N {
// These should emit as N.foo(), N.x, and N.C
foo();
x;
class D extends C {}
}
Loading