Skip to content

Commit 2ebed24

Browse files
committed
add support for optional chaining (estools#412)
Co-authored-by: sanex3339 <yarabotayuvyandex3339>
1 parent 54c331e commit 2ebed24

6 files changed

+143
-23
lines changed

escodegen.js

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,12 @@
9999
Await: 14,
100100
Unary: 14,
101101
Postfix: 15,
102-
Call: 16,
103-
New: 17,
104-
TaggedTemplate: 18,
105-
Member: 19,
106-
Primary: 20
102+
OptionalChaining: 16,
103+
Call: 17,
104+
New: 18,
105+
TaggedTemplate: 19,
106+
Member: 20,
107+
Primary: 21
107108
};
108109

109110
BinaryPrecedence = {
@@ -1880,8 +1881,14 @@
18801881

18811882
CallExpression: function (expr, precedence, flags) {
18821883
var result, i, iz;
1884+
18831885
// F_ALLOW_UNPARATH_NEW becomes false.
18841886
result = [this.generateExpression(expr.callee, Precedence.Call, E_TTF)];
1887+
1888+
if (expr.optional) {
1889+
result.push('?.');
1890+
}
1891+
18851892
result.push('(');
18861893
for (i = 0, iz = expr['arguments'].length; i < iz; ++i) {
18871894
result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT));
@@ -1894,9 +1901,20 @@
18941901
if (!(flags & F_ALLOW_CALL)) {
18951902
return ['(', result, ')'];
18961903
}
1904+
18971905
return parenthesize(result, Precedence.Call, precedence);
18981906
},
18991907

1908+
ChainExpression: function (expr, precedence, flags) {
1909+
if (Precedence.OptionalChaining < precedence) {
1910+
flags |= F_ALLOW_CALL;
1911+
}
1912+
1913+
var result = this.generateExpression(expr.expression, Precedence.OptionalChaining, flags);
1914+
1915+
return parenthesize(result, Precedence.OptionalChaining, precedence);
1916+
},
1917+
19001918
NewExpression: function (expr, precedence, flags) {
19011919
var result, length, i, iz, itemFlags;
19021920
length = expr['arguments'].length;
@@ -1931,11 +1949,15 @@
19311949
result = [this.generateExpression(expr.object, Precedence.Call, (flags & F_ALLOW_CALL) ? E_TTF : E_TFF)];
19321950

19331951
if (expr.computed) {
1952+
if (expr.optional) {
1953+
result.push('?.');
1954+
}
1955+
19341956
result.push('[');
19351957
result.push(this.generateExpression(expr.property, Precedence.Sequence, flags & F_ALLOW_CALL ? E_TTT : E_TFT));
19361958
result.push(']');
19371959
} else {
1938-
if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
1960+
if (!expr.optional && expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
19391961
fragment = toSourceNodeWhenNeeded(result).toString();
19401962
// When the following conditions are all true,
19411963
// 1. No floating point
@@ -1952,7 +1974,7 @@
19521974
result.push(' ');
19531975
}
19541976
}
1955-
result.push('.');
1977+
result.push(expr.optional ? '?.' : '.');
19561978
result.push(generateIdentifier(expr.property));
19571979
}
19581980

@@ -2466,8 +2488,7 @@
24662488
this.generateExpression(expr.source, Precedence.Assignment, E_TTT),
24672489
')'
24682490
], Precedence.Call, precedence);
2469-
},
2470-
2491+
}
24712492
};
24722493

24732494
merge(CodeGenerator.prototype, CodeGenerator.Expression);

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"url": "http://github.com/estools/escodegen.git"
3131
},
3232
"dependencies": {
33-
"estraverse": "^4.2.0",
33+
"estraverse": "^5.2.0",
3434
"esutils": "^2.0.2",
3535
"esprima": "^4.0.1",
3636
"optionator": "^0.8.1"
@@ -42,7 +42,8 @@
4242
"acorn": "^8.0.1",
4343
"bluebird": "^3.4.7",
4444
"bower-registry-client": "^1.0.0",
45-
"chai": "^3.5.0",
45+
"chai": "^4.2.0",
46+
"chai-exclude": "^2.0.2",
4647
"commonjs-everywhere": "^0.9.7",
4748
"gulp": "^3.8.10",
4849
"gulp-eslint": "^3.0.1",

test/compare-acorn-es2020.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ var fs = require('fs'),
2828
acorn = require('acorn'),
2929
escodegen = require('./loader'),
3030
chai = require('chai'),
31+
chaiExclude = require('chai-exclude'),
3132
expect = chai.expect;
3233

33-
function test(code, expected) {
34-
var tree, actual, options, StringObject;
34+
chai.use(chaiExclude);
3535

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

3939
options = {
40-
ranges: true,
40+
ranges: false,
4141
locations: false,
4242
ecmaVersion: 11,
4343
sourceType: 'module'
@@ -46,18 +46,18 @@ function test(code, expected) {
4646
tree = acorn.parse(code, options);
4747

4848
// for UNIX text comment
49-
actual = escodegen.generate(tree).replace(/[\n\r]$/, '') + '\n';
49+
actual = escodegen.generate(tree);
50+
actualTree = acorn.parse(actual, options);
51+
5052
expect(actual).to.be.equal(expected);
53+
expect(tree).excludingEvery(['start', 'end']).to.deep.equal(actualTree);
5154
}
5255

5356
function testMin(code, expected) {
54-
var tree, actual, options, StringObject;
55-
56-
// alias, so that JSLint does not complain.
57-
StringObject = String;
57+
var tree, actual, actualTree, options;
5858

5959
options = {
60-
ranges: true,
60+
ranges: false,
6161
locations: false,
6262
ecmaVersion: 11,
6363
sourceType: 'module'
@@ -70,7 +70,10 @@ function testMin(code, expected) {
7070
format: escodegen.FORMAT_MINIFY,
7171
raw: false
7272
}).replace(/[\n\r]$/, '') + '\n';
73+
actualTree = acorn.parse(actual, options);
74+
7375
expect(actual).to.be.equal(expected);
76+
expect(tree).excludingEvery(['start', 'end']).to.deep.equal(actualTree);
7477
}
7578

7679
describe('compare acorn es2020 test', function () {
@@ -91,4 +94,4 @@ describe('compare acorn es2020 test', function () {
9194
}
9295
});
9396
});
94-
/* vim: set sw=4 ts=4 et tw=80 : */
97+
/* vim: set sw=4 ts=4 et tw=80 : */
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
obj.aaa.bbb;
2+
obj.aaa?.bbb;
3+
obj?.aaa.bbb;
4+
obj?.aaa?.bbb;
5+
obj.aaa.bbb;
6+
obj.aaa?.bbb;
7+
(obj?.aaa).bbb;
8+
(obj?.aaa)?.bbb;
9+
(obj?.aaa).bbb.ccc.ddd;
10+
((obj?.aaa).bbb?.ccc).ddd;
11+
(obj?.aaa)?.bbb;
12+
obj[aaa][bbb];
13+
obj[aaa]?.[bbb];
14+
obj?.[aaa][bbb];
15+
obj?.[aaa]?.[bbb];
16+
obj[aaa][bbb];
17+
obj[aaa]?.[bbb];
18+
(obj?.[aaa])[bbb];
19+
(obj?.[aaa])?.[bbb];
20+
obj[aaa][bbb][ccc][ddd];
21+
((obj?.[aaa])[bbb]?.[ccc])[ddd];
22+
1?.a;
23+
obj()();
24+
obj()?.();
25+
obj?.()();
26+
obj?.()?.();
27+
obj()();
28+
obj()?.();
29+
(obj?.())();
30+
(obj?.())?.();
31+
obj()()()();
32+
((obj?.())()?.())();
33+
(a?.b)();
34+
a?.b();
35+
a?.b?.();
36+
(a?.b)?.();
37+
a?.().b;
38+
(a?.()).b;
39+
a?.b.c();
40+
(a?.b.c)();
41+
a.b?.().c;
42+
(a.b?.()).c;
43+
(a.b?.())?.c;
44+
new (a?.b().c)();
45+
new (a?.b())();
46+
new (a?.b().c)();
47+
new (a?.b())();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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())
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
obj.aaa.bbb;
2+
obj.aaa?.bbb;
3+
obj?.aaa.bbb;
4+
obj?.aaa?.bbb;
5+
(obj.aaa).bbb;
6+
(obj.aaa)?.bbb;
7+
(obj?.aaa).bbb;
8+
(obj?.aaa)?.bbb;
9+
((obj?.aaa).bbb.ccc).ddd;
10+
((obj?.aaa).bbb?.ccc).ddd;
11+
(obj?.aaa)?.bbb;
12+
obj[aaa][bbb];
13+
obj[aaa]?.[bbb];
14+
obj?.[aaa][bbb];
15+
obj?.[aaa]?.[bbb];
16+
(obj[aaa])[bbb];
17+
(obj[aaa])?.[bbb];
18+
(obj?.[aaa])[bbb];
19+
(obj?.[aaa])?.[bbb];
20+
((obj[aaa])[bbb][ccc])[ddd];
21+
((obj?.[aaa])[bbb]?.[ccc])[ddd];
22+
1?.a;
23+
obj()();
24+
obj()?.();
25+
obj?.()();
26+
obj?.()?.();
27+
(obj())();
28+
(obj())?.();
29+
(obj?.())();
30+
(obj?.())?.();
31+
((obj())()())();
32+
((obj?.())()?.())();
33+
(a?.b)();
34+
a?.b();
35+
a?.b?.();
36+
(a?.b)?.();
37+
a?.().b;
38+
(a?.()).b;
39+
a?.b.c();
40+
(a?.b.c)();
41+
a.b?.().c;
42+
(a.b?.()).c;
43+
(a.b?.())?.c;
44+
new (a?.b().c);
45+
new (a?.b());
46+
new (a?.b().c)();
47+
new (a?.b())();

0 commit comments

Comments
 (0)