Skip to content
Closed
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
27 changes: 24 additions & 3 deletions src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,11 @@ namespace ts {
return visitFunctionDeclaration(node as FunctionDeclaration);

case SyntaxKind.ArrowFunction:
return visitArrowFunction(node as ArrowFunction);
let name: string | undefined;
if (node.parent && isVariableDeclaration(node.parent) && isIdentifier(node.parent.name)) {
name = `${node.parent.name.escapedText}`;
}
return visitArrowFunction(node as ArrowFunction, name);

case SyntaxKind.FunctionExpression:
return visitFunctionExpression(node as FunctionExpression);
Expand Down Expand Up @@ -1771,7 +1775,7 @@ namespace ts {
*
* @param node An ArrowFunction node.
*/
function visitArrowFunction(node: ArrowFunction) {
function visitArrowFunction(node: ArrowFunction, name?: string) {
if (node.transformFlags & TransformFlags.ContainsLexicalThis && !(hierarchyFacts & HierarchyFacts.StaticInitializer)) {
hierarchyFacts |= HierarchyFacts.CapturedLexicalThis;
}
Expand All @@ -1782,7 +1786,7 @@ namespace ts {
const func = factory.createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*name*/ name ? createNonCollidingName(name, node) : undefined,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
Expand Down Expand Up @@ -4353,4 +4357,21 @@ namespace ts {
return isIdentifier(expression) && expression.escapedText === "arguments";
}
}

function createNonCollidingName(name: string, node: Node): string {
const identifiers = new Set<string>();
forEachFreeIdentifier(node, (identifier) => {
identifiers.add(`${identifier.escapedText}`);
});

return createUniqueName(name, 0, identifiers);
}

function createUniqueName(name: string, counter: number, existingNames: Set<string>): string {
const fullName = counter === 0 ? name : `${name}_${counter}`;
if (!existingNames.has(fullName)) {
return fullName;
}
return createUniqueName(name, counter + 1, existingNames);
}
}
23 changes: 23 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7414,4 +7414,27 @@ namespace ts {
export function escapeSnippetText(text: string): string {
return text.replace(/\$/gm, "\\$");
}

/**
* A free identifier is an identifier that can be accessed through name lookup as a local variable.
* In the expression `x.y`, `x` is a free identifier, but `y` is not.
*/
export function forEachFreeIdentifier(node: Node, cb: (id: Identifier) => void): void {
if (isIdentifier(node) && isFreeIdentifier(node)) cb(node);
forEachChild(node, child => forEachFreeIdentifier(child, cb));
}

export function isFreeIdentifier(node: Identifier): boolean {
const { parent } = node;
switch (parent.kind) {
case SyntaxKind.PropertyAccessExpression:
return (parent as PropertyAccessExpression).name !== node;
case SyntaxKind.BindingElement:
return (parent as BindingElement).propertyName !== node;
case SyntaxKind.ImportSpecifier:
return (parent as ImportSpecifier).propertyName !== node;
default:
return true;
}
}
}
23 changes: 0 additions & 23 deletions src/services/codefixes/convertToEsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -517,29 +517,6 @@ namespace ts.codefix {
return map;
}

/**
* A free identifier is an identifier that can be accessed through name lookup as a local variable.
* In the expression `x.y`, `x` is a free identifier, but `y` is not.
*/
function forEachFreeIdentifier(node: Node, cb: (id: Identifier) => void): void {
if (isIdentifier(node) && isFreeIdentifier(node)) cb(node);
node.forEachChild(child => forEachFreeIdentifier(child, cb));
}

function isFreeIdentifier(node: Identifier): boolean {
const { parent } = node;
switch (parent.kind) {
case SyntaxKind.PropertyAccessExpression:
return (parent as PropertyAccessExpression).name !== node;
case SyntaxKind.BindingElement:
return (parent as BindingElement).propertyName !== node;
case SyntaxKind.ImportSpecifier:
return (parent as ImportSpecifier).propertyName !== node;
default:
return true;
}
}

// Node helpers

function functionExpressionToDeclaration(name: string | undefined, additionalModifiers: readonly Modifier[], fn: FunctionExpression | ArrowFunction | MethodDeclaration, useSitesToUnqualify: ESMap<Node, Node> | undefined): FunctionDeclaration {
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/ArrowFunction4.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ var v = (a, b) => {
};

//// [ArrowFunction4.js]
var v = function (a, b) {
var v = function v(a, b) {
};
2 changes: 1 addition & 1 deletion tests/baselines/reference/abstractPropertyInConstructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ var AbstractClass = /** @class */ (function () {
}
this.cb(str);
// OK, reference is inside function
var innerFunction = function () {
var innerFunction = function innerFunction() {
return _this.prop;
};
// OK, references are to another instance
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/arrowFunctionContexts.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ var __extends = (this && this.__extends) || (function () {
var _this = this;
// Arrow function used in with statement
with (window) {
var p = function () { return _this; };
var p = function p() { return _this; };
}
// Arrow function as argument to super call
var Base = /** @class */ (function () {
Expand Down Expand Up @@ -147,16 +147,16 @@ var E;
// Arrow function as module variable initializer
var M;
(function (M) {
M.a = function (s) { return ''; };
var b = function (s) { return s; };
M.a = function a(s) { return ''; };
var b = function b(s) { return s; };
})(M || (M = {}));
// Repeat above for module members that are functions? (necessary to redo all of them?)
var M2;
(function (M2) {
var _this = this;
// Arrow function used in with statement
with (window) {
var p = function () { return _this; };
var p = function p() { return _this; };
}
// Arrow function as argument to super call
var Base = /** @class */ (function () {
Expand Down Expand Up @@ -189,8 +189,8 @@ var M2;
// Arrow function as module variable initializer
var M;
(function (M) {
M.a = function (s) { return ''; };
var b = function (s) { return s; };
M.a = function a(s) { return ''; };
var b = function b(s) { return s; };
})(M || (M = {}));
})(M2 || (M2 = {}));
// <Identifier>(ParamList) => { ... } is a generic arrow function
Expand Down
40 changes: 20 additions & 20 deletions tests/baselines/reference/arrowFunctionExpressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,42 +104,42 @@ function tryCatchFn() {
var a = function (p) { return p.length; };
var a = function (p) { return p.length; };
// Identifier => Block is equivalent to(Identifier) => Block
var b = function (j) { return 0; };
var b = function (j) { return 0; };
var b = function b(j) { return 0; };
var b = function b(j) { return 0; };
// Identifier => AssignmentExpression is equivalent to(Identifier) => AssignmentExpression
var c;
var d = function (n) { return c = n; };
var d = function (n) { return c = n; };
var d = function d(n) { return c = n; };
var d = function d(n) { return c = n; };
var d;
// Binding patterns in arrow functions
var p1 = function (_a) {
var p1 = function p1(_a) {
var a = _a[0];
};
var p2 = function (_a) {
var p2 = function p2(_a) {
var a = _a.slice(0);
};
var p3 = function (_a) {
var p3 = function p3(_a) {
var a = _a[1];
};
var p4 = function (_a) {
var p4 = function p4(_a) {
var a = _a.slice(1);
};
var p5 = function (_a) {
var p5 = function p5(_a) {
var _b = _a[0], a = _b === void 0 ? 1 : _b;
};
var p6 = function (_a) {
var p6 = function p6(_a) {
var a = _a.a;
};
var p7 = function (_a) {
var p7 = function p7(_a) {
var b = _a.a.b;
};
var p8 = function (_a) {
var p8 = function p8(_a) {
var _b = _a.a, a = _b === void 0 ? 1 : _b;
};
var p9 = function (_a) {
var p9 = function p9(_a) {
var _b = _a.a, _c = _b === void 0 ? { b: 1 } : _b, _d = _c.b, b = _d === void 0 ? 1 : _d;
};
var p10 = function (_a) {
var p10 = function p10(_a) {
var _b = _a[0], value = _b.value, done = _b.done;
};
// Arrow function used in class member initializer
Expand All @@ -152,8 +152,8 @@ var MyClass = /** @class */ (function () {
}
MyClass.prototype.fn = function () {
var _this = this;
var m = function (n) { return n + 1; };
var p = function (n) { return n && _this; };
var m = function m(n) { return n + 1; };
var p = function p(n) { return n && _this; };
};
return MyClass;
}());
Expand All @@ -174,7 +174,7 @@ function someOtherFn() {
// Arrow function used in nested function in function
function outerFn() {
function innerFn() {
var arrowFn = function () { };
var arrowFn = function arrowFn() { };
var p = arrowFn();
var p;
}
Expand Down Expand Up @@ -204,12 +204,12 @@ h.toExponential();
function tryCatchFn() {
var _this = this;
try {
var x = function () { return _this; };
var x = function x() { return _this; };
}
catch (e) {
var t = function () { return e + _this; };
var t = function t() { return e + _this; };
}
finally {
var m = function () { return _this + ''; };
var m = function m() { return _this + ''; };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ var square = (x: number) => x * x;

//// [arrowFunctionMissingCurlyWithSemicolon.js]
// Should error at semicolon.
var f = function () { return ; };
var f = function f() { return ; };
var b = 1 * 2 * 3 * 4;
var square = function (x) { return x * x; };
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ var d = () => ((<Error>({ name: "foo", message: "bar" })));
//// [arrowFunctionWithObjectLiteralBody5.js]
var a = function () { return ({ name: "foo", message: "bar" }); };
var b = function () { return ({ name: "foo", message: "bar" }); };
var c = function () { return ({ name: "foo", message: "bar" }); };
var c = function c() { return ({ name: "foo", message: "bar" }); };
var d = function () { return ({ name: "foo", message: "bar" }); };
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
const x = async => async;

//// [arrowFunctionWithParameterNameAsync_es2017.js]
var x = function (async) { return async; };
var x = function x(async) { return async; };
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
const x = async => async;

//// [arrowFunctionWithParameterNameAsync_es5.js]
var x = function (async) { return async; };
var x = function x(async) { return async; };
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
const x = async => async;

//// [arrowFunctionWithParameterNameAsync_es6.js]
var x = function (async) { return async; };
var x = function x(async) { return async; };
20 changes: 10 additions & 10 deletions tests/baselines/reference/arrowFunctionsMissingTokens.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,37 +68,37 @@ module okay {
//// [arrowFunctionsMissingTokens.js]
var missingArrowsWithCurly;
(function (missingArrowsWithCurly) {
var a = function () { };
var a = function a() { };
var b = function () { };
var c = function (x) { };
var c = function c(x) { };
var d = function (x, y) { };
var e = function (x, y) { };
})(missingArrowsWithCurly || (missingArrowsWithCurly = {}));
var missingCurliesWithArrow;
(function (missingCurliesWithArrow) {
var withStatement;
(function (withStatement) {
var a = function () { var k = 10; };
var a = function a() { var k = 10; };
var b = function () { var k = 10; };
var c = function (x) { var k = 10; };
var c = function c(x) { var k = 10; };
var d = function (x, y) { var k = 10; };
var e = function (x, y) { var k = 10; };
var f = function () { var k = 10; };
var f = function f() { var k = 10; };
})(withStatement || (withStatement = {}));
var withoutStatement;
(function (withoutStatement) {
var a = function () { return ; };
var a = function a() { return ; };
})(withoutStatement || (withoutStatement = {}));
;
var b = function () { return ; };
})(missingCurliesWithArrow || (missingCurliesWithArrow = {}));
var c = function (x) { return ; };
var c = function c(x) { return ; };
;
var d = function (x, y) { return ; };
;
var e = function (x, y) { return ; };
;
var f = function () { return ; };
var f = function f() { return ; };
var ce_nEst_pas_une_arrow_function;
(function (ce_nEst_pas_une_arrow_function) {
var a = ();
Expand All @@ -109,9 +109,9 @@ var ce_nEst_pas_une_arrow_function;
})(ce_nEst_pas_une_arrow_function || (ce_nEst_pas_une_arrow_function = {}));
var okay;
(function (okay) {
var a = function () { };
var a = function a() { };
var b = function () { };
var c = function (x) { };
var c = function c(x) { };
var d = function (x, y) { };
var e = function (x, y) { };
})(okay || (okay = {}));
2 changes: 1 addition & 1 deletion tests/baselines/reference/assertionTypePredicates1.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var assert = function (value) { };
var assert = function assert(value) { };
function f01(x) {
if (!!true) {
assert(typeof x === "string");
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/assertionTypePredicates2.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ exports.main = void 0;
* @param {A} a
* @returns { asserts a is B }
*/
var foo = function (a) {
var foo = function foo(a) {
if ( /** @type { B } */(a).y !== 0)
throw TypeError();
return undefined;
};
var main = function () {
var main = function main() {
/** @type { A } */
var a = { x: 1 };
foo(a);
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/asyncArrowFunction2_es5.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ var f = (await) => {
}

//// [asyncArrowFunction2_es5.js]
var f = function (await) {
var f = function f(await) {
};
2 changes: 1 addition & 1 deletion tests/baselines/reference/asyncArrowFunction4_es5.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ var await = () => {
}

//// [asyncArrowFunction4_es5.js]
var await = function () {
var await = function await() {
};
2 changes: 1 addition & 1 deletion tests/baselines/reference/asyncMethodWithSuper_es5.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ var B = /** @class */ (function (_super) {
return __awaiter(this, void 0, void 0, function () {
var f, a, b;
return __generator(this, function (_a) {
f = function () { };
f = function f() { };
// call with property access
_super.prototype.x.call(this);
// call with element access
Expand Down
Loading