Skip to content

Commit 165d11b

Browse files
committed
INCOMPLETE: failling single SequenceExpressionAsKey test
Merge branch 'eslint-npm' into eslint-npm-full; also adds linting to recent adds and fixes regression (line 959) introduced in cf9a7b8 * eslint-npm: - npm: update estraverse - npm: update devDeps. - npm: Update package-lock version - npm: update devDeps. - npm: Update package-lock version - Linting: Temporarily disable most linting, with a few fixes - Breaking change: Remove bower-registry-client build (bower deprecated) - Update: Use new SourceMapConsumer API in test - Build: Provide browserified builds with npm package - Travis: Drop 4, 6, 8; Add 10, 12, 14; check build - Maintenance: Add `.editorconfig` - Docs: Use fenced code blocks in README (for syntax highlighting) - npm: Add `bugs`, `keywords`, change from `maintainers` to `authors`/`contributors` - npm: Restore `optionator` to a regular dep. (used in published binary file) - npm: Drop unused semver, minimist - npm: Bump deps. (estraverse, optionator, optional source-map potentially breaking) and devDeps. - npm: Drop bluebird in favor of ES Promises - npm: Use more recently maintained browserify + uglifyify - npm: Replace linting and testing scripts in Gulpfile with npm scripts Add more optional-chaining tests Test logical assignments Implement coalescing code generation Support BigInt syntax Update gulpfile and dependencies Version 2.0.0 add support for optional chaining (estools#412) Update .gitattributes drop support for node <6 (estools#419) # Conflicts: # .eslintignore # .eslintrc.js # .gitignore # escodegen.js.map # package-lock.json # package.json # src/escodegen.js # test/source-map.js # tools/release.js
2 parents 8d538ba + 77da34c commit 165d11b

22 files changed

+11861
-2445
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
test/3rdparty/**/* -crlf -diff
2+
# don't collapse diffs of test expectations
3+
test/compare-*/*.expected.min.js -linguist-generated

escodegen.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 10985 additions & 2407 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
"escodegen.browser.js",
2222
"package.json"
2323
],
24-
"version": "1.14.3",
24+
"version": "2.0.0",
2525
"engines": {
26-
"node": ">=4.0"
26+
"node": ">=6.0"
2727
},
2828
"author": {
2929
"name": "Yusuke Suzuki",
@@ -37,7 +37,7 @@
3737
},
3838
"dependencies": {
3939
"esprima": "^4.0.1",
40-
"estraverse": "^5.1.0",
40+
"estraverse": "^5.2.0",
4141
"esutils": "^2.0.3",
4242
"optionator": "^0.9.1"
4343
},
@@ -47,14 +47,15 @@
4747
"devDependencies": {
4848
"@babel/cli": "^7.8.4",
4949
"@babel/preset-env": "^7.9.5",
50-
"acorn": "^7.3.1",
50+
"acorn": "^8.0.5",
5151
"babel-plugin-transform-es2017-object-entries": "0.0.5",
52-
"browserify": "^16.5.1",
53-
"chai": "^4.2.0",
54-
"eslint": "^7.3.1",
55-
"mocha": "^8.0.1",
52+
"browserify": "^17.0.0",
53+
"chai": "^4.3.0",
54+
"chai-exclude": "^2.0.2",
55+
"eslint": "^7.19.0",
56+
"mocha": "^8.2.1",
5657
"nyc": "^15.1.0",
57-
"semver": "^7.3.2",
58+
"source-map": "~0.7.3",
5859
"uglifyify": "^5.0.2"
5960
},
6061
"license": "BSD-2-Clause",
@@ -76,9 +77,9 @@
7677
"build": "babel src/escodegen.js --out-file escodegen.js --source-maps",
7778
"browser-build-min": "browserify -t uglifyify -e tools/entry-point.js -o escodegen.browser.min.js",
7879
"browser-build": "browserify -e tools/entry-point.js -o escodegen.browser.js",
79-
"test": "npm run unit-test && npm run lint",
80-
"unit-test": "nyc --require chai/register-expect mocha test/*.js --timeout 100000",
8180
"lint": "eslint --rulesdir tools/rules/ .",
81+
"unit-test": "nyc --require chai/register-expect mocha test/*.js --timeout 100000",
82+
"test": "npm run unit-test && npm run lint",
8283
"release": "node tools/release.js"
8384
}
8485
}

src/escodegen.js

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
1212
Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
1313
Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
14+
Copyright (C) 2020 Apple Inc. All rights reserved.
1415
1516
Redistribution and use in source and binary forms, with or without
1617
modification, are permitted provided that the following conditions are met:
@@ -77,28 +78,31 @@
7778
Assignment: 1,
7879
Conditional: 2,
7980
ArrowFunction: 2,
80-
LogicalOR: 3,
81-
LogicalAND: 4,
82-
BitwiseOR: 5,
83-
BitwiseXOR: 6,
84-
BitwiseAND: 7,
85-
Equality: 8,
86-
Relational: 9,
87-
BitwiseSHIFT: 10,
88-
Additive: 11,
89-
Multiplicative: 12,
90-
Exponentiation: 13,
91-
Await: 14,
92-
Unary: 14,
93-
Postfix: 15,
94-
Call: 16,
95-
New: 17,
96-
TaggedTemplate: 18,
97-
Member: 19,
98-
Primary: 20
81+
Coalesce: 3,
82+
LogicalOR: 4,
83+
LogicalAND: 5,
84+
BitwiseOR: 6,
85+
BitwiseXOR: 7,
86+
BitwiseAND: 8,
87+
Equality: 9,
88+
Relational: 10,
89+
BitwiseSHIFT: 11,
90+
Additive: 12,
91+
Multiplicative: 13,
92+
Exponentiation: 14,
93+
Await: 15,
94+
Unary: 15,
95+
Postfix: 16,
96+
OptionalChaining: 17,
97+
Call: 18,
98+
New: 19,
99+
TaggedTemplate: 20,
100+
Member: 21,
101+
Primary: 22
99102
};
100103

101104
const BinaryPrecedence = {
105+
'??': Precedence.Coalesce,
102106
'||': Precedence.LogicalOR,
103107
'&&': Precedence.LogicalAND,
104108
'|': Precedence.BitwiseOR,
@@ -133,7 +137,8 @@
133137
F_ALLOW_UNPARATH_NEW = 1 << 2,
134138
F_FUNC_BODY = 1 << 3,
135139
F_DIRECTIVE_CTX = 1 << 4,
136-
F_SEMICOLON_OPT = 1 << 5;
140+
F_SEMICOLON_OPT = 1 << 5,
141+
F_FOUND_COALESCE = 1 << 6;
137142

138143
//Expression flag sets
139144
//NOTE: Flag order:
@@ -951,7 +956,7 @@
951956
result.push('[');
952957
}
953958

954-
result.push(this.generateExpression(expr, Precedence.Sequence, E_TTT));
959+
result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT));
955960

956961
if (computed) {
957962
result.push(']');
@@ -1812,7 +1817,7 @@
18121817
}
18131818
return parenthesize(
18141819
[
1815-
this.generateExpression(expr.test, Precedence.LogicalOR, flags),
1820+
this.generateExpression(expr.test, Precedence.Coalesce, flags),
18161821
`${space}?${space}`,
18171822
this.generateExpression(expr.consequent, Precedence.Assignment, flags),
18181823
`${space}:${space}`,
@@ -1824,6 +1829,9 @@
18241829
},
18251830

18261831
LogicalExpression (expr, precedence, flags) {
1832+
if (expr.operator === '??') {
1833+
flags |= F_FOUND_COALESCE;
1834+
}
18271835
return this.BinaryExpression(expr, precedence, flags);
18281836
},
18291837

@@ -1861,12 +1869,20 @@
18611869
if (expr.operator === 'in' && !(flags & F_ALLOW_IN)) {
18621870
return ['(', result, ')'];
18631871
}
1872+
if ((expr.operator === '||' || expr.operator === '&&') && (flags & F_FOUND_COALESCE)) {
1873+
return ['(', result, ')'];
1874+
}
18641875
return parenthesize(result, currentPrecedence, precedence);
18651876
},
18661877

18671878
CallExpression (expr, precedence, flags) {
18681879
// F_ALLOW_UNPARATH_NEW becomes false.
18691880
const result = [this.generateExpression(expr.callee, Precedence.Call, E_TTF)];
1881+
1882+
if (expr.optional) {
1883+
result.push('?.');
1884+
}
1885+
18701886
result.push('(');
18711887
for (let i = 0, iz = expr['arguments'].length; i < iz; ++i) {
18721888
result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT));
@@ -1879,9 +1895,20 @@
18791895
if (!(flags & F_ALLOW_CALL)) {
18801896
return ['(', result, ')'];
18811897
}
1898+
18821899
return parenthesize(result, Precedence.Call, precedence);
18831900
},
18841901

1902+
ChainExpression (expr, precedence, flags) {
1903+
if (Precedence.OptionalChaining < precedence) {
1904+
flags |= F_ALLOW_CALL;
1905+
}
1906+
1907+
const result = this.generateExpression(expr.expression, Precedence.OptionalChaining, flags);
1908+
1909+
return parenthesize(result, Precedence.OptionalChaining, precedence);
1910+
},
1911+
18851912
NewExpression (expr, precedence, flags) {
18861913
const { length } = expr['arguments'];
18871914

@@ -1913,11 +1940,15 @@
19131940
const result = [this.generateExpression(expr.object, Precedence.Call, (flags & F_ALLOW_CALL) ? E_TTF : E_TFF)];
19141941

19151942
if (expr.computed) {
1943+
if (expr.optional) {
1944+
result.push('?.');
1945+
}
1946+
19161947
result.push('[');
19171948
result.push(this.generateExpression(expr.property, Precedence.Sequence, flags & F_ALLOW_CALL ? E_TTT : E_TFT));
19181949
result.push(']');
19191950
} else {
1920-
if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
1951+
if (!expr.optional && expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
19211952
const fragment = toSourceNodeWhenNeeded(result).toString();
19221953
// When the following conditions are all true,
19231954
// 1. No floating point
@@ -1934,7 +1965,7 @@
19341965
result.push(' ');
19351966
}
19361967
}
1937-
result.push('.');
1968+
result.push(expr.optional ? '?.' : '.');
19381969
result.push(generateIdentifier(expr.property));
19391970
}
19401971

@@ -2314,6 +2345,16 @@
23142345
return `/${expr.regex.pattern}/${expr.regex.flags}`;
23152346
}
23162347

2348+
if (typeof expr.value === 'bigint') {
2349+
return expr.value.toString() + 'n';
2350+
}
2351+
2352+
// `expr.value` can be null if `expr.bigint` exists. We need to check
2353+
// `expr.bigint` first.
2354+
if (expr.bigint) {
2355+
return expr.bigint + 'n';
2356+
}
2357+
23172358
if (expr.value === null) {
23182359
return 'null';
23192360
}
@@ -2445,8 +2486,7 @@
24452486
this.generateExpression(expr.source, Precedence.Assignment, E_TTT),
24462487
')'
24472488
], Precedence.Call, precedence);
2448-
},
2449-
2489+
}
24502490
};
24512491

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

test/compare-acorn-es2020.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above copyright
10+
notice, this list of conditions and the following disclaimer in the
11+
documentation and/or other materials provided with the distribution.
12+
13+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16+
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
17+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23+
*/
24+
25+
'use strict';
26+
27+
const fs = require('fs'),
28+
acorn = require('acorn'),
29+
escodegen = require('./loader'),
30+
chai = require('chai'),
31+
chaiExclude = require('chai-exclude');
32+
33+
chai.use(chaiExclude);
34+
35+
function test(code, expected) {
36+
const options = {
37+
ranges: false,
38+
locations: false,
39+
ecmaVersion: 11
40+
};
41+
42+
const tree = acorn.parse(code, options);
43+
44+
// for UNIX text comment
45+
const actual = escodegen.generate(tree);
46+
const actualTree = acorn.parse(actual, options);
47+
48+
expect(actual).to.be.equal(expected);
49+
expect(tree).excludingEvery(['start', 'end', 'raw']).to.deep.equal(actualTree);
50+
}
51+
52+
function testMin(code, expected) {
53+
const options = {
54+
ranges: false,
55+
locations: false,
56+
ecmaVersion: 11
57+
};
58+
59+
const tree = acorn.parse(code, options);
60+
61+
// for UNIX text comment
62+
const actual = `${escodegen.generate(tree, {
63+
format: escodegen.FORMAT_MINIFY,
64+
raw: false
65+
}).replace(/[\n\r]$/, '')}\n`;
66+
const actualTree = acorn.parse(actual, options);
67+
68+
expect(actual).to.be.equal(expected);
69+
expect(tree).excludingEvery(['start', 'end', 'raw']).to.deep.equal(actualTree);
70+
}
71+
72+
describe('compare acorn es2020 test', function () {
73+
fs.readdirSync(`${__dirname}/compare-acorn-es2020`).sort().forEach(function(file) {
74+
if (/\.js$/.test(file) && !/expected\.js$/.test(file) && !/expected\.min\.js$/.test(file)) {
75+
it(file, function () {
76+
const exp = file.replace(/\.js$/, '.expected.js');
77+
const min = file.replace(/\.js$/, '.expected.min.js');
78+
const code = fs.readFileSync(`${__dirname}/compare-acorn-es2020/${file}`, 'utf-8');
79+
let expected = fs.readFileSync(`${__dirname}/compare-acorn-es2020/${exp}`, 'utf-8');
80+
test(code, expected);
81+
if (fs.existsSync(`${__dirname}/compare-acorn-es2020/${min}`)) {
82+
expected = fs.readFileSync(`${__dirname}/compare-acorn-es2020/${min}`, 'utf-8');
83+
testMin(code, expected);
84+
}
85+
});
86+
}
87+
});
88+
});
89+
/* vim: set sw=4 ts=4 et tw=80 : */
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2000n + 30;
2+
20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n + 30;
3+
-20000000000000000000000000000n;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2000n+30;20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n+30;-20000000000000000000000000000n

test/compare-acorn-es2020/bigint.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (C) 2020 Apple Inc.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23+
* THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
2000n + 30;
27+
20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n + 30;
28+
-20000000000000000000000000000n;

0 commit comments

Comments
 (0)