Skip to content

Commit

Permalink
Alias for module.exports.x = x (microsoft#40228)
Browse files Browse the repository at this point in the history
* Alias for `module.exports.x = x`

This fixes microsoft#40155 in a surprisingly small amount of code.

* Treat any aliasable expression as an alias

* test internal references to exported class
  • Loading branch information
sandersn authored Sep 10, 2020
1 parent 0636b9b commit e350c35
Show file tree
Hide file tree
Showing 47 changed files with 588 additions and 190 deletions.
8 changes: 4 additions & 4 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2806,10 +2806,10 @@ namespace ts {
return symbol;
});
if (symbol) {
const flags = isClassExpression(node.right) ?
SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.Class :
SymbolFlags.Property | SymbolFlags.ExportValue;
declareSymbol(symbol.exports!, symbol, node.left, flags, SymbolFlags.None);
const isAlias = isAliasableExpression(node.right) && (isExportsIdentifier(node.left.expression) || isModuleExportsAccessExpression(node.left.expression));
const flags = isAlias ? SymbolFlags.Alias : SymbolFlags.Property | SymbolFlags.ExportValue;
const excludeFlags = isAlias ? SymbolFlags.AliasExcludes : SymbolFlags.None;
declareSymbol(symbol.exports!, symbol, node.left, flags, excludeFlags);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5562,6 +5562,7 @@ namespace ts {
export const enum AssignmentDeclarationKind {
None,
/// exports.name = expr
/// module.exports.name = expr
ExportsProperty,
/// module.exports = expr
ModuleExports,
Expand Down
40 changes: 40 additions & 0 deletions tests/baselines/reference/commonJSImportClassExpression.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//// [tests/cases/conformance/salsa/commonJSImportClassExpression.ts] ////

//// [main.js]
const { K } = require("./mod1");
/** @param {K} k */
function f(k) {
k.values()
}

//// [mod1.js]
exports.K = class K {
values() {
}
};


//// [mod1.js]
"use strict";
exports.K = /** @class */ (function () {
function K() {
}
K.prototype.values = function () {
};
return K;
}());
//// [main.js]
"use strict";
var K = require("./mod1").K;
/** @param {K} k */
function f(k) {
k.values();
}


//// [mod1.d.ts]
export class K {
values(): void;
}
//// [main.d.ts]
export {};
29 changes: 29 additions & 0 deletions tests/baselines/reference/commonJSImportClassExpression.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
=== tests/cases/conformance/salsa/main.js ===
const { K } = require("./mod1");
>K : Symbol(K, Decl(main.js, 0, 7))
>require : Symbol(require)
>"./mod1" : Symbol("tests/cases/conformance/salsa/mod1", Decl(mod1.js, 0, 0))

/** @param {K} k */
function f(k) {
>f : Symbol(f, Decl(main.js, 0, 32))
>k : Symbol(k, Decl(main.js, 2, 11))

k.values()
>k.values : Symbol(K.values, Decl(mod1.js, 0, 21))
>k : Symbol(k, Decl(main.js, 2, 11))
>values : Symbol(K.values, Decl(mod1.js, 0, 21))
}

=== tests/cases/conformance/salsa/mod1.js ===
exports.K = class K {
>exports.K : Symbol(K, Decl(mod1.js, 0, 0))
>exports : Symbol(K, Decl(mod1.js, 0, 0))
>K : Symbol(K, Decl(mod1.js, 0, 0))
>K : Symbol(K, Decl(mod1.js, 0, 11))

values() {
>values : Symbol(K.values, Decl(mod1.js, 0, 21))
}
};

33 changes: 33 additions & 0 deletions tests/baselines/reference/commonJSImportClassExpression.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
=== tests/cases/conformance/salsa/main.js ===
const { K } = require("./mod1");
>K : typeof K
>require("./mod1") : typeof import("tests/cases/conformance/salsa/mod1")
>require : any
>"./mod1" : "./mod1"

/** @param {K} k */
function f(k) {
>f : (k: K) => void
>k : K

k.values()
>k.values() : void
>k.values : () => void
>k : K
>values : () => void
}

=== tests/cases/conformance/salsa/mod1.js ===
exports.K = class K {
>exports.K = class K { values() { }} : typeof K
>exports.K : typeof K
>exports : typeof import("tests/cases/conformance/salsa/mod1")
>K : typeof K
>class K { values() { }} : typeof K
>K : typeof K

values() {
>values : () => void
}
};

44 changes: 44 additions & 0 deletions tests/baselines/reference/commonJSImportClassTypeReference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//// [tests/cases/conformance/salsa/commonJSImportClassTypeReference.ts] ////

//// [main.js]
const { K } = require("./mod1");
/** @param {K} k */
function f(k) {
k.values()
}

//// [mod1.js]
class K {
values() {
return new K()
}
}
exports.K = K;


//// [mod1.js]
"use strict";
var K = /** @class */ (function () {
function K() {
}
K.prototype.values = function () {
return new K();
};
return K;
}());
exports.K = K;
//// [main.js]
"use strict";
var K = require("./mod1").K;
/** @param {K} k */
function f(k) {
k.values();
}


//// [mod1.d.ts]
export class K {
values(): K;
}
//// [main.d.ts]
export {};
34 changes: 34 additions & 0 deletions tests/baselines/reference/commonJSImportClassTypeReference.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
=== tests/cases/conformance/salsa/main.js ===
const { K } = require("./mod1");
>K : Symbol(K, Decl(main.js, 0, 7))
>require : Symbol(require)
>"./mod1" : Symbol("tests/cases/conformance/salsa/mod1", Decl(mod1.js, 0, 0))

/** @param {K} k */
function f(k) {
>f : Symbol(f, Decl(main.js, 0, 32))
>k : Symbol(k, Decl(main.js, 2, 11))

k.values()
>k.values : Symbol(K.values, Decl(mod1.js, 0, 9))
>k : Symbol(k, Decl(main.js, 2, 11))
>values : Symbol(K.values, Decl(mod1.js, 0, 9))
}

=== tests/cases/conformance/salsa/mod1.js ===
class K {
>K : Symbol(K, Decl(mod1.js, 0, 0))

values() {
>values : Symbol(K.values, Decl(mod1.js, 0, 9))

return new K()
>K : Symbol(K, Decl(mod1.js, 0, 0))
}
}
exports.K = K;
>exports.K : Symbol(K, Decl(mod1.js, 4, 1))
>exports : Symbol(K, Decl(mod1.js, 4, 1))
>K : Symbol(K, Decl(mod1.js, 4, 1))
>K : Symbol(K, Decl(mod1.js, 0, 0))

38 changes: 38 additions & 0 deletions tests/baselines/reference/commonJSImportClassTypeReference.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
=== tests/cases/conformance/salsa/main.js ===
const { K } = require("./mod1");
>K : typeof K
>require("./mod1") : typeof import("tests/cases/conformance/salsa/mod1")
>require : any
>"./mod1" : "./mod1"

/** @param {K} k */
function f(k) {
>f : (k: K) => void
>k : K

k.values()
>k.values() : K
>k.values : () => K
>k : K
>values : () => K
}

=== tests/cases/conformance/salsa/mod1.js ===
class K {
>K : K

values() {
>values : () => K

return new K()
>new K() : K
>K : typeof K
}
}
exports.K = K;
>exports.K = K : typeof K
>exports.K : typeof K
>exports : typeof import("tests/cases/conformance/salsa/mod1")
>K : typeof K
>K : typeof K

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//// [tests/cases/conformance/salsa/commonJSImportNestedClassTypeReference.ts] ////

//// [main.js]
const { K } = require("./mod1");
/** @param {K} k */
function f(k) {
k.values()
}

//// [mod1.js]
var NS = {}
NS.K =class {
values() {
return new NS.K()
}
}
exports.K = NS.K;


//// [mod1.js]
"use strict";
var NS = {};
NS.K = /** @class */ (function () {
function K() {
}
K.prototype.values = function () {
return new NS.K();
};
return K;
}());
exports.K = NS.K;
//// [main.js]
"use strict";
var K = require("./mod1").K;
/** @param {K} k */
function f(k) {
k.values();
}


//// [mod1.d.ts]
export var K: {
new (): {
values(): any;
};
};
//// [main.d.ts]
export {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
=== tests/cases/conformance/salsa/main.js ===
const { K } = require("./mod1");
>K : Symbol(K, Decl(main.js, 0, 7))
>require : Symbol(require)
>"./mod1" : Symbol("tests/cases/conformance/salsa/mod1", Decl(mod1.js, 0, 0))

/** @param {K} k */
function f(k) {
>f : Symbol(f, Decl(main.js, 0, 32))
>k : Symbol(k, Decl(main.js, 2, 11))

k.values()
>k.values : Symbol(K.values, Decl(mod1.js, 1, 13))
>k : Symbol(k, Decl(main.js, 2, 11))
>values : Symbol(K.values, Decl(mod1.js, 1, 13))
}

=== tests/cases/conformance/salsa/mod1.js ===
var NS = {}
>NS : Symbol(NS, Decl(mod1.js, 0, 3), Decl(mod1.js, 0, 11))

NS.K =class {
>NS.K : Symbol(K, Decl(mod1.js, 0, 11))
>NS : Symbol(NS, Decl(mod1.js, 0, 3), Decl(mod1.js, 0, 11))
>K : Symbol(K, Decl(mod1.js, 0, 11))

values() {
>values : Symbol(K.values, Decl(mod1.js, 1, 13))

return new NS.K()
>NS.K : Symbol(K, Decl(mod1.js, 0, 11))
>NS : Symbol(NS, Decl(mod1.js, 0, 3), Decl(mod1.js, 0, 11))
>K : Symbol(K, Decl(mod1.js, 0, 11))
}
}
exports.K = NS.K;
>exports.K : Symbol(K, Decl(mod1.js, 5, 1))
>exports : Symbol(K, Decl(mod1.js, 5, 1))
>K : Symbol(K, Decl(mod1.js, 5, 1))
>NS.K : Symbol(K, Decl(mod1.js, 0, 11))
>NS : Symbol(NS, Decl(mod1.js, 0, 3), Decl(mod1.js, 0, 11))
>K : Symbol(K, Decl(mod1.js, 0, 11))

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
=== tests/cases/conformance/salsa/main.js ===
const { K } = require("./mod1");
>K : typeof K
>require("./mod1") : typeof import("tests/cases/conformance/salsa/mod1")
>require : any
>"./mod1" : "./mod1"

/** @param {K} k */
function f(k) {
>f : (k: K) => void
>k : K

k.values()
>k.values() : K
>k.values : () => K
>k : K
>values : () => K
}

=== tests/cases/conformance/salsa/mod1.js ===
var NS = {}
>NS : typeof NS
>{} : {}

NS.K =class {
>NS.K =class { values() { return new NS.K() }} : typeof K
>NS.K : typeof K
>NS : typeof NS
>K : typeof K
>class { values() { return new NS.K() }} : typeof K

values() {
>values : () => K

return new NS.K()
>new NS.K() : K
>NS.K : typeof K
>NS : typeof NS
>K : typeof K
}
}
exports.K = NS.K;
>exports.K = NS.K : typeof K
>exports.K : typeof K
>exports : typeof import("tests/cases/conformance/salsa/mod1")
>K : typeof K
>NS.K : typeof K
>NS : typeof NS
>K : typeof K

Loading

0 comments on commit e350c35

Please sign in to comment.