Skip to content

Commit

Permalink
Fake up a namespace enclosing declaration when generating expando nam…
Browse files Browse the repository at this point in the history
…espace members (#31971)

* Fake up a namespace enclosing declaration when generating expando namespace members

* Fix #31676
  • Loading branch information
weswigham committed Jun 20, 2019
1 parent c39a877 commit f2735b5
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 3 deletions.
12 changes: 9 additions & 3 deletions src/compiler/transformers/declarations.ts
Expand Up @@ -1036,19 +1036,25 @@ namespace ts {
/*body*/ undefined
));
if (clean && resolver.isExpandoFunctionDeclaration(input)) {
const declarations = mapDefined(resolver.getPropertiesOfContainerFunction(input), p => {
const props = resolver.getPropertiesOfContainerFunction(input);
const fakespace = createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, clean.name || createIdentifier("_default"), createModuleBlock([]), NodeFlags.Namespace);
fakespace.flags ^= NodeFlags.Synthesized; // unset synthesized so it is usable as an enclosing declaration
fakespace.parent = enclosingDeclaration as SourceFile | NamespaceDeclaration;
fakespace.locals = createSymbolTable(props);
fakespace.symbol = props[0].parent!;
const declarations = mapDefined(props, p => {
if (!isPropertyAccessExpression(p.valueDeclaration)) {
return undefined;
}
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration);
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker);
getSymbolAccessibilityDiagnostic = oldDiag;
const varDecl = createVariableDeclaration(unescapeLeadingUnderscores(p.escapedName), type, /*initializer*/ undefined);
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([varDecl]));
});
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input, isPrivate), input.name!, createModuleBlock(declarations), NodeFlags.Namespace);

if (!hasModifier(clean, ModifierFlags.ExportDefault)) {
if (!hasModifier(clean, ModifierFlags.Default)) {
return [clean, namespaceDecl];
}

Expand Down
@@ -0,0 +1,114 @@
//// [tests/cases/compiler/declarationEmitDefaultExportWithStaticAssignment.ts] ////

//// [foo.ts]
export class Foo {}

//// [index1.ts]
import {Foo} from './foo';
export default function Example() {}
Example.Foo = Foo

//// [index2.ts]
import {Foo} from './foo';
export {Foo};
export default function Example() {}
Example.Foo = Foo

//// [index3.ts]
export class Bar {}
export default function Example() {}

Example.Bar = Bar

//// [index4.ts]
function A() { }

function B() { }

export function C() {
return null;
}

C.A = A;
C.B = B;

//// [foo.js]
"use strict";
exports.__esModule = true;
var Foo = /** @class */ (function () {
function Foo() {
}
return Foo;
}());
exports.Foo = Foo;
//// [index1.js]
"use strict";
exports.__esModule = true;
var foo_1 = require("./foo");
function Example() { }
exports["default"] = Example;
Example.Foo = foo_1.Foo;
//// [index2.js]
"use strict";
exports.__esModule = true;
var foo_1 = require("./foo");
exports.Foo = foo_1.Foo;
function Example() { }
exports["default"] = Example;
Example.Foo = foo_1.Foo;
//// [index3.js]
"use strict";
exports.__esModule = true;
var Bar = /** @class */ (function () {
function Bar() {
}
return Bar;
}());
exports.Bar = Bar;
function Example() { }
exports["default"] = Example;
Example.Bar = Bar;
//// [index4.js]
"use strict";
exports.__esModule = true;
function A() { }
function B() { }
function C() {
return null;
}
exports.C = C;
C.A = A;
C.B = B;


//// [foo.d.ts]
export declare class Foo {
}
//// [index1.d.ts]
declare function Example(): void;
declare namespace Example {
var Foo: typeof import("./foo").Foo;
}
export default Example;
//// [index2.d.ts]
import { Foo } from './foo';
export { Foo };
declare function Example(): void;
declare namespace Example {
var Foo: typeof import("./foo").Foo;
}
export default Example;
//// [index3.d.ts]
export declare class Bar {
}
declare function Example(): void;
declare namespace Example {
var Bar: typeof import("./index3").Bar;
}
export default Example;
//// [index4.d.ts]
export declare function C(): any;
export declare namespace C {
var A: () => void;
var B: () => void;
}
@@ -0,0 +1,71 @@
=== tests/cases/compiler/foo.ts ===
export class Foo {}
>Foo : Symbol(Foo, Decl(foo.ts, 0, 0))

=== tests/cases/compiler/index1.ts ===
import {Foo} from './foo';
>Foo : Symbol(Foo, Decl(index1.ts, 0, 8))

export default function Example() {}
>Example : Symbol(Example, Decl(index1.ts, 0, 26), Decl(index1.ts, 1, 36))

Example.Foo = Foo
>Example.Foo : Symbol(Example.Foo, Decl(index1.ts, 1, 36))
>Example : Symbol(Example, Decl(index1.ts, 0, 26), Decl(index1.ts, 1, 36))
>Foo : Symbol(Example.Foo, Decl(index1.ts, 1, 36))
>Foo : Symbol(Foo, Decl(index1.ts, 0, 8))

=== tests/cases/compiler/index2.ts ===
import {Foo} from './foo';
>Foo : Symbol(Foo, Decl(index2.ts, 0, 8))

export {Foo};
>Foo : Symbol(Foo, Decl(index2.ts, 1, 8))

export default function Example() {}
>Example : Symbol(Example, Decl(index2.ts, 1, 13), Decl(index2.ts, 2, 36))

Example.Foo = Foo
>Example.Foo : Symbol(Example.Foo, Decl(index2.ts, 2, 36))
>Example : Symbol(Example, Decl(index2.ts, 1, 13), Decl(index2.ts, 2, 36))
>Foo : Symbol(Example.Foo, Decl(index2.ts, 2, 36))
>Foo : Symbol(Foo, Decl(index2.ts, 0, 8))

=== tests/cases/compiler/index3.ts ===
export class Bar {}
>Bar : Symbol(Bar, Decl(index3.ts, 0, 0))

export default function Example() {}
>Example : Symbol(Example, Decl(index3.ts, 0, 19), Decl(index3.ts, 1, 36))

Example.Bar = Bar
>Example.Bar : Symbol(Example.Bar, Decl(index3.ts, 1, 36))
>Example : Symbol(Example, Decl(index3.ts, 0, 19), Decl(index3.ts, 1, 36))
>Bar : Symbol(Example.Bar, Decl(index3.ts, 1, 36))
>Bar : Symbol(Bar, Decl(index3.ts, 0, 0))

=== tests/cases/compiler/index4.ts ===
function A() { }
>A : Symbol(A, Decl(index4.ts, 0, 0))

function B() { }
>B : Symbol(B, Decl(index4.ts, 0, 17))

export function C() {
>C : Symbol(C, Decl(index4.ts, 2, 16), Decl(index4.ts, 6, 1))

return null;
}

C.A = A;
>C.A : Symbol(C.A, Decl(index4.ts, 6, 1))
>C : Symbol(C, Decl(index4.ts, 2, 16), Decl(index4.ts, 6, 1))
>A : Symbol(C.A, Decl(index4.ts, 6, 1))
>A : Symbol(A, Decl(index4.ts, 0, 0))

C.B = B;
>C.B : Symbol(C.B, Decl(index4.ts, 8, 8))
>C : Symbol(C, Decl(index4.ts, 2, 16), Decl(index4.ts, 6, 1))
>B : Symbol(C.B, Decl(index4.ts, 8, 8))
>B : Symbol(B, Decl(index4.ts, 0, 17))

@@ -0,0 +1,77 @@
=== tests/cases/compiler/foo.ts ===
export class Foo {}
>Foo : Foo

=== tests/cases/compiler/index1.ts ===
import {Foo} from './foo';
>Foo : typeof Foo

export default function Example() {}
>Example : typeof Example

Example.Foo = Foo
>Example.Foo = Foo : typeof Foo
>Example.Foo : typeof Foo
>Example : typeof Example
>Foo : typeof Foo
>Foo : typeof Foo

=== tests/cases/compiler/index2.ts ===
import {Foo} from './foo';
>Foo : typeof Foo

export {Foo};
>Foo : typeof Foo

export default function Example() {}
>Example : typeof Example

Example.Foo = Foo
>Example.Foo = Foo : typeof Foo
>Example.Foo : typeof Foo
>Example : typeof Example
>Foo : typeof Foo
>Foo : typeof Foo

=== tests/cases/compiler/index3.ts ===
export class Bar {}
>Bar : Bar

export default function Example() {}
>Example : typeof Example

Example.Bar = Bar
>Example.Bar = Bar : typeof Bar
>Example.Bar : typeof Bar
>Example : typeof Example
>Bar : typeof Bar
>Bar : typeof Bar

=== tests/cases/compiler/index4.ts ===
function A() { }
>A : () => void

function B() { }
>B : () => void

export function C() {
>C : typeof C

return null;
>null : null
}

C.A = A;
>C.A = A : () => void
>C.A : () => void
>C : typeof C
>A : () => void
>A : () => void

C.B = B;
>C.B = B : () => void
>C.B : () => void
>C : typeof C
>B : () => void
>B : () => void

@@ -0,0 +1,32 @@
// @declaration: true
// @filename: foo.ts
export class Foo {}

// @filename: index1.ts
import {Foo} from './foo';
export default function Example() {}
Example.Foo = Foo

// @filename: index2.ts
import {Foo} from './foo';
export {Foo};
export default function Example() {}
Example.Foo = Foo

// @filename: index3.ts
export class Bar {}
export default function Example() {}

Example.Bar = Bar

// @filename: index4.ts
function A() { }

function B() { }

export function C() {
return null;
}

C.A = A;
C.B = B;

0 comments on commit f2735b5

Please sign in to comment.