Skip to content

Commit

Permalink
add support for optional chaining (estools#412)
Browse files Browse the repository at this point in the history
Co-authored-by: sanex3339 <yarabotayuvyandex3339>
  • Loading branch information
sanex3339 committed Aug 14, 2020
1 parent 54c331e commit 2ebed24
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 23 deletions.
39 changes: 30 additions & 9 deletions escodegen.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,12 @@
Await: 14,
Unary: 14,
Postfix: 15,
Call: 16,
New: 17,
TaggedTemplate: 18,
Member: 19,
Primary: 20
OptionalChaining: 16,
Call: 17,
New: 18,
TaggedTemplate: 19,
Member: 20,
Primary: 21
};

BinaryPrecedence = {
Expand Down Expand Up @@ -1880,8 +1881,14 @@

CallExpression: function (expr, precedence, flags) {
var result, i, iz;

// F_ALLOW_UNPARATH_NEW becomes false.
result = [this.generateExpression(expr.callee, Precedence.Call, E_TTF)];

if (expr.optional) {
result.push('?.');
}

result.push('(');
for (i = 0, iz = expr['arguments'].length; i < iz; ++i) {
result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT));
Expand All @@ -1894,9 +1901,20 @@
if (!(flags & F_ALLOW_CALL)) {
return ['(', result, ')'];
}

return parenthesize(result, Precedence.Call, precedence);
},

ChainExpression: function (expr, precedence, flags) {
if (Precedence.OptionalChaining < precedence) {
flags |= F_ALLOW_CALL;
}

var result = this.generateExpression(expr.expression, Precedence.OptionalChaining, flags);

return parenthesize(result, Precedence.OptionalChaining, precedence);
},

NewExpression: function (expr, precedence, flags) {
var result, length, i, iz, itemFlags;
length = expr['arguments'].length;
Expand Down Expand Up @@ -1931,11 +1949,15 @@
result = [this.generateExpression(expr.object, Precedence.Call, (flags & F_ALLOW_CALL) ? E_TTF : E_TFF)];

if (expr.computed) {
if (expr.optional) {
result.push('?.');
}

result.push('[');
result.push(this.generateExpression(expr.property, Precedence.Sequence, flags & F_ALLOW_CALL ? E_TTT : E_TFT));
result.push(']');
} else {
if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
if (!expr.optional && expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
fragment = toSourceNodeWhenNeeded(result).toString();
// When the following conditions are all true,
// 1. No floating point
Expand All @@ -1952,7 +1974,7 @@
result.push(' ');
}
}
result.push('.');
result.push(expr.optional ? '?.' : '.');
result.push(generateIdentifier(expr.property));
}

Expand Down Expand Up @@ -2466,8 +2488,7 @@
this.generateExpression(expr.source, Precedence.Assignment, E_TTT),
')'
], Precedence.Call, precedence);
},

}
};

merge(CodeGenerator.prototype, CodeGenerator.Expression);
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"url": "http://github.com/estools/escodegen.git"
},
"dependencies": {
"estraverse": "^4.2.0",
"estraverse": "^5.2.0",
"esutils": "^2.0.2",
"esprima": "^4.0.1",
"optionator": "^0.8.1"
Expand All @@ -42,7 +42,8 @@
"acorn": "^8.0.1",
"bluebird": "^3.4.7",
"bower-registry-client": "^1.0.0",
"chai": "^3.5.0",
"chai": "^4.2.0",
"chai-exclude": "^2.0.2",
"commonjs-everywhere": "^0.9.7",
"gulp": "^3.8.10",
"gulp-eslint": "^3.0.1",
Expand Down
27 changes: 15 additions & 12 deletions test/compare-acorn-es2020.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ var fs = require('fs'),
acorn = require('acorn'),
escodegen = require('./loader'),
chai = require('chai'),
chaiExclude = require('chai-exclude'),
expect = chai.expect;

function test(code, expected) {
var tree, actual, options, StringObject;
chai.use(chaiExclude);

// alias, so that JSLint does not complain.
StringObject = String;
function test(code, expected) {
var tree, actual, actualTree, options;

options = {
ranges: true,
ranges: false,
locations: false,
ecmaVersion: 11,
sourceType: 'module'
Expand All @@ -46,18 +46,18 @@ function test(code, expected) {
tree = acorn.parse(code, options);

// for UNIX text comment
actual = escodegen.generate(tree).replace(/[\n\r]$/, '') + '\n';
actual = escodegen.generate(tree);
actualTree = acorn.parse(actual, options);

expect(actual).to.be.equal(expected);
expect(tree).excludingEvery(['start', 'end']).to.deep.equal(actualTree);
}

function testMin(code, expected) {
var tree, actual, options, StringObject;

// alias, so that JSLint does not complain.
StringObject = String;
var tree, actual, actualTree, options;

options = {
ranges: true,
ranges: false,
locations: false,
ecmaVersion: 11,
sourceType: 'module'
Expand All @@ -70,7 +70,10 @@ function testMin(code, expected) {
format: escodegen.FORMAT_MINIFY,
raw: false
}).replace(/[\n\r]$/, '') + '\n';
actualTree = acorn.parse(actual, options);

expect(actual).to.be.equal(expected);
expect(tree).excludingEvery(['start', 'end']).to.deep.equal(actualTree);
}

describe('compare acorn es2020 test', function () {
Expand All @@ -91,4 +94,4 @@ describe('compare acorn es2020 test', function () {
}
});
});
/* vim: set sw=4 ts=4 et tw=80 : */
/* vim: set sw=4 ts=4 et tw=80 : */
47 changes: 47 additions & 0 deletions test/compare-acorn-es2020/optional-chaining.expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
obj.aaa.bbb;
obj.aaa?.bbb;
obj?.aaa.bbb;
obj?.aaa?.bbb;
obj.aaa.bbb;
obj.aaa?.bbb;
(obj?.aaa).bbb;
(obj?.aaa)?.bbb;
(obj?.aaa).bbb.ccc.ddd;
((obj?.aaa).bbb?.ccc).ddd;
(obj?.aaa)?.bbb;
obj[aaa][bbb];
obj[aaa]?.[bbb];
obj?.[aaa][bbb];
obj?.[aaa]?.[bbb];
obj[aaa][bbb];
obj[aaa]?.[bbb];
(obj?.[aaa])[bbb];
(obj?.[aaa])?.[bbb];
obj[aaa][bbb][ccc][ddd];
((obj?.[aaa])[bbb]?.[ccc])[ddd];
1?.a;
obj()();
obj()?.();
obj?.()();
obj?.()?.();
obj()();
obj()?.();
(obj?.())();
(obj?.())?.();
obj()()()();
((obj?.())()?.())();
(a?.b)();
a?.b();
a?.b?.();
(a?.b)?.();
a?.().b;
(a?.()).b;
a?.b.c();
(a?.b.c)();
a.b?.().c;
(a.b?.()).c;
(a.b?.())?.c;
new (a?.b().c)();
new (a?.b())();
new (a?.b().c)();
new (a?.b())();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
obj.aaa.bbb;obj.aaa?.bbb;obj?.aaa.bbb;obj?.aaa?.bbb;obj.aaa.bbb;obj.aaa?.bbb;(obj?.aaa).bbb;(obj?.aaa)?.bbb;(obj?.aaa).bbb.ccc.ddd;((obj?.aaa).bbb?.ccc).ddd;(obj?.aaa)?.bbb;obj[aaa][bbb];obj[aaa]?.[bbb];obj?.[aaa][bbb];obj?.[aaa]?.[bbb];obj[aaa][bbb];obj[aaa]?.[bbb];(obj?.[aaa])[bbb];(obj?.[aaa])?.[bbb];obj[aaa][bbb][ccc][ddd];((obj?.[aaa])[bbb]?.[ccc])[ddd];1?.a;obj()();obj()?.();obj?.()();obj?.()?.();obj()();obj()?.();(obj?.())();(obj?.())?.();obj()()()();((obj?.())()?.())();(a?.b)();a?.b();a?.b?.();(a?.b)?.();a?.().b;(a?.()).b;a?.b.c();(a?.b.c)();a.b?.().c;(a.b?.()).c;(a.b?.())?.c;new(a?.b().c);new(a?.b());new(a?.b().c);new(a?.b())
47 changes: 47 additions & 0 deletions test/compare-acorn-es2020/optional-chaining.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
obj.aaa.bbb;
obj.aaa?.bbb;
obj?.aaa.bbb;
obj?.aaa?.bbb;
(obj.aaa).bbb;
(obj.aaa)?.bbb;
(obj?.aaa).bbb;
(obj?.aaa)?.bbb;
((obj?.aaa).bbb.ccc).ddd;
((obj?.aaa).bbb?.ccc).ddd;
(obj?.aaa)?.bbb;
obj[aaa][bbb];
obj[aaa]?.[bbb];
obj?.[aaa][bbb];
obj?.[aaa]?.[bbb];
(obj[aaa])[bbb];
(obj[aaa])?.[bbb];
(obj?.[aaa])[bbb];
(obj?.[aaa])?.[bbb];
((obj[aaa])[bbb][ccc])[ddd];
((obj?.[aaa])[bbb]?.[ccc])[ddd];
1?.a;
obj()();
obj()?.();
obj?.()();
obj?.()?.();
(obj())();
(obj())?.();
(obj?.())();
(obj?.())?.();
((obj())()())();
((obj?.())()?.())();
(a?.b)();
a?.b();
a?.b?.();
(a?.b)?.();
a?.().b;
(a?.()).b;
a?.b.c();
(a?.b.c)();
a.b?.().c;
(a.b?.()).c;
(a.b?.())?.c;
new (a?.b().c);
new (a?.b());
new (a?.b().c)();
new (a?.b())();

0 comments on commit 2ebed24

Please sign in to comment.