Skip to content

Commit

Permalink
Update: ecmaVersion defaults to 5, and allows "latest" (#14622)
Browse files Browse the repository at this point in the history
* Update: set default ecmaVersion => 5 and allows "latest"

* chore: add more tests
  • Loading branch information
aladdin-add committed Jun 12, 2021
1 parent c93a222 commit 831f6b3
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 14 deletions.
4 changes: 2 additions & 2 deletions docs/user-guide/configuring/language-options.md
Expand Up @@ -187,7 +187,7 @@ For ES6 syntax, use `{ "parserOptions": { "ecmaVersion": 6 } }`; for new ES6 glo

Parser options are set in your `.eslintrc.*` file by using the `parserOptions` property. The available options are:

* `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, 9, 10, 11, or 12 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), 2018 (same as 9), 2019 (same as 10), 2020 (same as 11), or 2021 (same as 12) to use the year-based naming.
* `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, 9, 10, 11, or 12 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), 2018 (same as 9), 2019 (same as 10), 2020 (same as 11), or 2021 (same as 12) to use the year-based naming. You can also set "latest" to use the most recently supported version.
* `sourceType` - set to `"script"` (default) or `"module"` if your code is in ECMAScript modules.
* `ecmaFeatures` - an object indicating which additional language features you'd like to use:
* `globalReturn` - allow `return` statements in the global scope
Expand All @@ -199,7 +199,7 @@ Here's an example `.eslintrc.json` file:
```json
{
"parserOptions": {
"ecmaVersion": 6,
"ecmaVersion": "latest",
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
Expand Down
31 changes: 19 additions & 12 deletions lib/linter/linter.js
Expand Up @@ -37,6 +37,7 @@ const
const debug = require("debug")("eslint:linter");
const MAX_AUTOFIX_PASSES = 10;
const DEFAULT_PARSER_NAME = "espree";
const DEFAULT_ECMA_VERSION = 5;
const commentParser = new ConfigCommentParser();
const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, column: 1 } };

Expand Down Expand Up @@ -432,10 +433,20 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) {

/**
* Normalize ECMAScript version from the initial config
* @param {number} ecmaVersion ECMAScript version from the initial config
* @param {Parser} parser The parser which uses this options.
* @param {number} ecmaVersion ECMAScript version from the initial config
* @returns {number} normalized ECMAScript version
*/
function normalizeEcmaVersion(ecmaVersion) {
function normalizeEcmaVersion(parser, ecmaVersion) {
if (parser === espree) {
if (ecmaVersion === void 0) {
return DEFAULT_ECMA_VERSION;
}

if (ecmaVersion === "latest") {
return espree.latestEcmaVersion;
}
}

/*
* Calculate ECMAScript edition number from official year version starting with
Expand Down Expand Up @@ -521,12 +532,13 @@ function normalizeVerifyOptions(providedOptions, config) {

/**
* Combines the provided parserOptions with the options from environments
* @param {string} parserName The parser name which uses this options.
* @param {Parser} parser The parser which uses this options.
* @param {ParserOptions} providedOptions The provided 'parserOptions' key in a config
* @param {Environment[]} enabledEnvironments The environments enabled in configuration and with inline comments
* @returns {ParserOptions} Resulting parser options after merge
*/
function resolveParserOptions(parserName, providedOptions, enabledEnvironments) {
function resolveParserOptions(parser, providedOptions, enabledEnvironments) {

const parserOptionsFromEnv = enabledEnvironments
.filter(env => env.parserOptions)
.reduce((parserOptions, env) => merge(parserOptions, env.parserOptions), {});
Expand All @@ -542,12 +554,7 @@ function resolveParserOptions(parserName, providedOptions, enabledEnvironments)
mergedParserOptions.ecmaFeatures = Object.assign({}, mergedParserOptions.ecmaFeatures, { globalReturn: false });
}

/*
* TODO: @aladdin-add
* 1. for a 3rd-party parser, do not normalize parserOptions
* 2. for espree, no need to do this (espree will do it)
*/
mergedParserOptions.ecmaVersion = normalizeEcmaVersion(mergedParserOptions.ecmaVersion);
mergedParserOptions.ecmaVersion = normalizeEcmaVersion(parser, mergedParserOptions.ecmaVersion);

return mergedParserOptions;
}
Expand Down Expand Up @@ -606,7 +613,7 @@ function getRuleOptions(ruleConfig) {
*/
function analyzeScope(ast, parserOptions, visitorKeys) {
const ecmaFeatures = parserOptions.ecmaFeatures || {};
const ecmaVersion = parserOptions.ecmaVersion || 5;
const ecmaVersion = parserOptions.ecmaVersion || DEFAULT_ECMA_VERSION;

return eslintScope.analyze(ast, {
ignoreEval: true,
Expand Down Expand Up @@ -1123,7 +1130,7 @@ class Linter {
.map(envName => getEnv(slots, envName))
.filter(env => env);

const parserOptions = resolveParserOptions(parserName, config.parserOptions || {}, enabledEnvs);
const parserOptions = resolveParserOptions(parser, config.parserOptions || {}, enabledEnvs);
const configuredGlobals = resolveGlobals(config.globals || {}, enabledEnvs);
const settings = config.settings || {};

Expand Down
65 changes: 65 additions & 0 deletions tests/lib/linter/linter.js
Expand Up @@ -11,6 +11,7 @@

const assert = require("chai").assert,
sinon = require("sinon"),
espree = require("espree"),
esprima = require("esprima"),
testParsers = require("../../fixtures/parsers/linter-test-parsers");

Expand Down Expand Up @@ -3493,6 +3494,70 @@ var a = "test2";
});

describe("ecmaVersion", () => {

it("should not support ES6 when no ecmaVersion provided", () => {
const messages = linter.verify("let x = 0;");

assert.strictEqual(messages.length, 1);
});

it("the default ECMAScript version is 5", () => {
let ecmaVersion = null;
const config = { rules: { "ecma-version": 2 } };

linter.defineRule("ecma-version", context => ({
Program() {
ecmaVersion = context.parserOptions.ecmaVersion;
}
}));
linter.verify("", config);
assert.strictEqual(ecmaVersion, 5);
});

it("supports ECMAScript version 'latest'", () => {
const messages = linter.verify("let x = 5 ** 7;", {
parserOptions: { ecmaVersion: "latest" }
});

assert.strictEqual(messages.length, 0);
});

it("the 'latest' is equal to espree.lastEcmaVersion", () => {
let ecmaVersion = null;
const config = { rules: { "ecma-version": 2 }, parserOptions: { ecmaVersion: "latest" } };

linter.defineRule("ecma-version", context => ({
Program() {
ecmaVersion = context.parserOptions.ecmaVersion;
}
}));
linter.verify("", config);
assert.strictEqual(ecmaVersion, espree.latestEcmaVersion);
});

it("should pass normalized ecmaVersion to eslint-scope", () => {
let blockScope = null;

linter.defineRule("block-scope", context => ({
BlockStatement() {
blockScope = context.getScope();
}
}));

linter.verify("{}", {
rules: { "block-scope": 2 },
parserOptions: { ecmaVersion: "latest" }
});

assert.strictEqual(blockScope.type, "block");

linter.verify("{}", {
rules: { "block-scope": 2 },
parserOptions: {} // ecmaVersion defaults to 5
});
assert.strictEqual(blockScope.type, "global");
});

describe("it should properly parse let declaration when", () => {
it("the ECMAScript version number is 6", () => {
const messages = linter.verify("let x = 5;", {
Expand Down

0 comments on commit 831f6b3

Please sign in to comment.