Skip to content

Commit 493d464

Browse files
aladdin-addnot-an-aardvark
authored andcommitted
Breaking: validate parser options (fixes #384) (#412)
* Breaking: validate parser options (fixes #384) it will throw an error if any of the conditions is true: + ecmaVersion is invalid + sourceType is invalid + ecmaVersion < 6 & sourceType: "module" * fix failing tests * Update lib/espree.js Co-Authored-By: aladdin-add <[email protected]> * Update tests/lib/ecma-version.js Co-Authored-By: aladdin-add <[email protected]> * chore: update test * Chore: move some assginment to func normalizeOptions * Update lib/espree.js Co-Authored-By: aladdin-add <[email protected]> * Update lib/espree.js Co-Authored-By: aladdin-add <[email protected]> * Update ecma-version.js
1 parent a7895ea commit 493d464

File tree

3 files changed

+72
-15
lines changed

3 files changed

+72
-15
lines changed

lib/espree.js

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ const STATE = Symbol("espree's internal state");
1010
const ESPRIMA_FINISH_NODE = Symbol("espree's esprimaFinishNode");
1111
const tokTypes = Object.assign({}, acorn.tokTypes, jsx.tokTypes);
1212

13+
1314
/**
1415
* Normalize ECMAScript version from the initial config
1516
* @param {number} ecmaVersion ECMAScript version from the initial config
17+
* @throws {Error} throws an error if the ecmaVersion is invalid.
1618
* @returns {number} normalized ECMAScript version
1719
*/
18-
function normalizeEcmaVersion(ecmaVersion) {
20+
function normalizeEcmaVersion(ecmaVersion = DEFAULT_ECMA_VERSION) {
1921
if (typeof ecmaVersion === "number") {
2022
let version = ecmaVersion;
2123

@@ -35,12 +37,42 @@ function normalizeEcmaVersion(ecmaVersion) {
3537
case 10:
3638
return version;
3739

38-
default:
39-
throw new Error("Invalid ecmaVersion.");
40+
// no default
4041
}
41-
} else {
42-
return DEFAULT_ECMA_VERSION;
4342
}
43+
44+
throw new Error("Invalid ecmaVersion.");
45+
}
46+
47+
/**
48+
* Normalize sourceType from the initial config
49+
* @param {string} sourceType to normalize
50+
* @throws {Error} throw an error if sourceType is invalid
51+
* @returns {string} normalized sourceType
52+
*/
53+
function normalizeSourceType(sourceType = "script") {
54+
if (sourceType === "script" || sourceType === "module") {
55+
return sourceType;
56+
}
57+
throw new Error("Invalid sourceType.");
58+
}
59+
60+
/**
61+
* Normalize parserOptions
62+
* @param {Object} options the parser options to normalize
63+
* @throws {Error} throw an error if found invalid option.
64+
* @returns {Object} normalized options
65+
*/
66+
function normalizeOptions(options) {
67+
const ecmaVersion = normalizeEcmaVersion(options.ecmaVersion);
68+
const sourceType = normalizeSourceType(options.sourceType);
69+
const ranges = options.range === true;
70+
const locations = options.loc === true;
71+
72+
if (sourceType === "module" && ecmaVersion < 6) {
73+
throw new Error("sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.");
74+
}
75+
return Object.assign({}, options, { ecmaVersion, sourceType, ranges, locations });
4476
}
4577

4678
/**
@@ -77,28 +109,29 @@ function convertAcornCommentToEsprimaComment(block, text, start, end, startLoc,
77109
}
78110

79111
module.exports = () => Parser => class Espree extends Parser {
80-
constructor(options, code) {
81-
if (typeof options !== "object" || options === null) {
82-
options = {};
112+
constructor(opts, code) {
113+
if (typeof opts !== "object" || opts === null) {
114+
opts = {};
83115
}
84116
if (typeof code !== "string" && !(code instanceof String)) {
85117
code = String(code);
86118
}
87119

120+
const options = normalizeOptions(opts);
88121
const ecmaFeatures = options.ecmaFeatures || {};
89-
const ecmaVersion = normalizeEcmaVersion(options.ecmaVersion);
90-
const isModule = options.sourceType === "module";
91122
const tokenTranslator =
92123
options.tokens === true
93124
? new TokenTranslator(tokTypes, code)
94125
: null;
95126

96127
// Initialize acorn parser.
97128
super({
98-
ecmaVersion: isModule ? Math.max(6, ecmaVersion) : ecmaVersion,
99-
sourceType: isModule ? "module" : "script",
100-
ranges: options.range === true,
101-
locations: options.loc === true,
129+
130+
// TODO: use {...options} when spread is supported(Node.js >= 8.3.0).
131+
ecmaVersion: options.ecmaVersion,
132+
sourceType: options.sourceType,
133+
ranges: options.ranges,
134+
locations: options.locations,
102135

103136
// Truthy value is true for backward compatibility.
104137
allowReturnOutsideFunction: Boolean(ecmaFeatures.globalReturn),

tests/lib/ecma-version.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,30 @@ describe("ecmaVersion", () => {
141141
}, /Invalid ecmaVersion/);
142142
});
143143

144+
it("Should throw error when non-numeric year is provided", () => {
145+
assert.throws(() => {
146+
espree.parse(
147+
"let foo = bar;", {
148+
ecmaVersion: "2015",
149+
comment: true,
150+
tokens: true,
151+
range: true,
152+
loc: true
153+
}
154+
);
155+
}, /Invalid ecmaVersion/);
156+
});
157+
158+
it("Should throw error when using module in pre-ES6", () => {
159+
assert.throws(() => {
160+
espree.parse(
161+
"let foo = bar;", {
162+
ecmaVersion: 5,
163+
sourceType: "module"
164+
}
165+
);
166+
}, /sourceType 'module' is not supported when ecmaVersion < 2015/);
167+
});
144168
});
145169

146170
});

tests/lib/parse.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe("parse()", () => {
2424
it("should have correct column number when strict mode error occurs", () => {
2525

2626
try {
27-
espree.parse("function fn(a, a) {\n}", { sourceType: "module" });
27+
espree.parse("function fn(a, a) {\n}", { ecmaVersion: 6, sourceType: "module" });
2828
} catch (err) {
2929
assert.strictEqual(err.column, 16);
3030
}

0 commit comments

Comments
 (0)