From cacd6f709e17e6c25b54a0e63567b13dde1ace69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Fri, 18 Jun 2021 13:46:16 +0800 Subject: [PATCH 1/7] Revert "Revert "Update: ecmaVersion defaults to 5, and allows "latest" (#14622)" (#14711)" This reverts commit 97d9bd2a8061e61e98ebabb4c41231af1df7629f. --- .../configuring/language-options.md | 4 +- lib/linter/linter.js | 31 +++++---- tests/lib/linter/linter.js | 65 +++++++++++++++++++ 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/docs/user-guide/configuring/language-options.md b/docs/user-guide/configuring/language-options.md index eb3fe8a0afe..08b62aad571 100644 --- a/docs/user-guide/configuring/language-options.md +++ b/docs/user-guide/configuring/language-options.md @@ -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 @@ -199,7 +199,7 @@ Here's an example `.eslintrc.json` file: ```json { "parserOptions": { - "ecmaVersion": 6, + "ecmaVersion": "latest", "sourceType": "module", "ecmaFeatures": { "jsx": true diff --git a/lib/linter/linter.js b/lib/linter/linter.js index e94b507b5dd..77682ea9548 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -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 } }; @@ -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 @@ -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), {}); @@ -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; } @@ -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, @@ -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 || {}; diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index adce5a39d86..9865acd7c88 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -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"); @@ -3492,6 +3493,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;", { From dd0a08387dac44a8dcfea97c9a45232092b493e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Thu, 17 Jun 2021 10:57:19 +0800 Subject: [PATCH 2/7] chore: use parser.$parser to check if it's espree --- lib/linter/linter.js | 4 +++- lib/rule-tester/rule-tester.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/linter/linter.js b/lib/linter/linter.js index 77682ea9548..82df6a55a95 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -438,7 +438,9 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) { * @returns {number} normalized ECMAScript version */ function normalizeEcmaVersion(parser, ecmaVersion) { - if (parser === espree) { + + // RuleTester always wraps parser, parser.$parser is the original parser object + if ((parser.$parser || parser) === espree) { if (ecmaVersion === void 0) { return DEFAULT_ECMA_VERSION; } diff --git a/lib/rule-tester/rule-tester.js b/lib/rule-tester/rule-tester.js index cac81bc71d1..15c29bfde01 100644 --- a/lib/rule-tester/rule-tester.js +++ b/lib/rule-tester/rule-tester.js @@ -260,6 +260,7 @@ function defineStartEndAsErrorInTree(ast, visitorKeys) { function wrapParser(parser) { if (typeof parser.parseForESLint === "function") { return { + $parser: parser, parseForESLint(...args) { const ret = parser.parseForESLint(...args); @@ -269,6 +270,7 @@ function wrapParser(parser) { }; } return { + $parser: parser, parse(...args) { const ast = parser.parse(...args); From f743871e26f1af29e29a836b2fda014db7f4ae88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Fri, 18 Jun 2021 13:57:36 +0800 Subject: [PATCH 3/7] chore: add some tests --- .../fixtures/parsers/empty-program-parser.js | 27 +++ tests/lib/rule-tester/rule-tester.js | 200 +++++++++++++++++- 2 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/parsers/empty-program-parser.js diff --git a/tests/fixtures/parsers/empty-program-parser.js b/tests/fixtures/parsers/empty-program-parser.js new file mode 100644 index 00000000000..7f336cdbef1 --- /dev/null +++ b/tests/fixtures/parsers/empty-program-parser.js @@ -0,0 +1,27 @@ +"use strict"; + +exports.parse = function (text, parserOptions) { + return { + "type": "Program", + "start": 0, + "end": 0, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 0 + } + }, + "range": [ + 0, + 0 + ], + "body": [], + "sourceType": "script", + "comments": [], + "tokens": [] + }; +}; diff --git a/tests/lib/rule-tester/rule-tester.js b/tests/lib/rule-tester/rule-tester.js index 70647b18670..cf10097c7c5 100644 --- a/tests/lib/rule-tester/rule-tester.js +++ b/tests/lib/rule-tester/rule-tester.js @@ -11,7 +11,8 @@ const sinon = require("sinon"), EventEmitter = require("events"), { RuleTester } = require("../../../lib/rule-tester"), assert = require("chai").assert, - nodeAssert = require("assert"); + nodeAssert = require("assert"), + espree = require("espree"); const NODE_ASSERT_STRICT_EQUAL_OPERATOR = (() => { try { @@ -1041,6 +1042,203 @@ describe("RuleTester", () => { }); assert.strictEqual(spy.args[1][1].parser, require.resolve("esprima")); }); + it("should pass normalized ecmaVersion to the rule", () => { + const reportEcmaVersionRule = { + meta: { + messages: { + ecmaVersionMessage: "context.parserOptions.ecmaVersion is {{type}} {{ecmaVersion}}." + } + }, + create: context => ({ + Program(node) { + const { ecmaVersion } = context.parserOptions; + + context.report({ + node, + messageId: "ecmaVersionMessage", + data: { type: typeof ecmaVersion, ecmaVersion } + }); + } + }) + }; + + const notEspree = require.resolve("../../fixtures/parsers/empty-program-parser"); + + ruleTester.run("report-ecma-version", reportEcmaVersionRule, { + valid: [], + invalid: [ + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }] + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + parserOptions: {} + }, + { + code: "
", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + parser: require.resolve("espree") + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + env: { browser: true } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + env: { es6: false } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }], + env: { es6: true } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "8" } }], + env: { es6: false, es2017: true } + }, + { + code: "let x", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }], + env: { es6: "truthy" } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "8" } }], + env: { es2017: true } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "11" } }], + env: { es2020: true } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "12" } }], + env: { es2021: true } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: String(espree.latestEcmaVersion) } }], + parserOptions: { ecmaVersion: "latest" } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: String(espree.latestEcmaVersion) } }], + parser: require.resolve("espree"), + parserOptions: { ecmaVersion: "latest" } + }, + { + code: "
", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: String(espree.latestEcmaVersion) } }], + parserOptions: { ecmaVersion: "latest", ecmaFeatures: { jsx: true } } + }, + { + code: "import 'foo'", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: String(espree.latestEcmaVersion) } }], + parserOptions: { ecmaVersion: "latest", sourceType: "module" } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: String(espree.latestEcmaVersion) } }], + parserOptions: { ecmaVersion: "latest" }, + env: { es6: true } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: String(espree.latestEcmaVersion) } }], + parserOptions: { ecmaVersion: "latest" }, + env: { es2020: true } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }], + parser: notEspree + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }], + parser: notEspree, + parserOptions: {} + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + parser: notEspree, + parserOptions: { ecmaVersion: 5 } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }], + parser: notEspree, + parserOptions: { ecmaVersion: 6 } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }], + parser: notEspree, + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "string", ecmaVersion: "latest" } }], + parser: notEspree, + parserOptions: { ecmaVersion: "latest" } + } + ] + }); + + [{ parserOptions: { ecmaVersion: 6 } }, { env: { es6: true } }].forEach(options => { + new RuleTester(options).run("report-ecma-version", reportEcmaVersionRule, { + valid: [], + invalid: [ + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }] + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }], + parserOptions: {} + } + ] + }); + }); + + new RuleTester({ parser: notEspree }).run("report-ecma-version", reportEcmaVersionRule, { + valid: [], + invalid: [ + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }] + }, + { + code: "", + errors: [{ messageId: "ecmaVersionMessage", data: { type: "string", ecmaVersion: "latest" } }], + parserOptions: { ecmaVersion: "latest" } + } + ] + }); + }); it("should pass-through services from parseForESLint to the rule", () => { const enhancedParserPath = require.resolve("../../fixtures/parsers/enhanced-parser"); From 5b13582a23667c7e875c6a1efae93da3046dba28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Sun, 20 Jun 2021 09:19:39 +0800 Subject: [PATCH 4/7] chore: not set default 5 --- lib/linter/linter.js | 4 ---- tests/lib/linter/linter.js | 13 ------------- tests/lib/rule-tester/rule-tester.js | 12 ++++++------ 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/lib/linter/linter.js b/lib/linter/linter.js index 82df6a55a95..815ef9f2a16 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -441,10 +441,6 @@ function normalizeEcmaVersion(parser, ecmaVersion) { // RuleTester always wraps parser, parser.$parser is the original parser object if ((parser.$parser || parser) === espree) { - if (ecmaVersion === void 0) { - return DEFAULT_ECMA_VERSION; - } - if (ecmaVersion === "latest") { return espree.latestEcmaVersion; } diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index 9865acd7c88..522f9b19726 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -3500,19 +3500,6 @@ var a = "test2"; 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" } diff --git a/tests/lib/rule-tester/rule-tester.js b/tests/lib/rule-tester/rule-tester.js index cf10097c7c5..71225611dfe 100644 --- a/tests/lib/rule-tester/rule-tester.js +++ b/tests/lib/rule-tester/rule-tester.js @@ -1069,21 +1069,21 @@ describe("RuleTester", () => { invalid: [ { code: "", - errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }] + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }] }, { code: "", - errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }], parserOptions: {} }, { code: "
", - errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }], parserOptions: { ecmaFeatures: { jsx: true } } }, { code: "", - errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }], parser: require.resolve("espree") }, { @@ -1098,12 +1098,12 @@ describe("RuleTester", () => { }, { code: "", - errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }], env: { browser: true } }, { code: "", - errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "5" } }], + errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }], env: { es6: false } }, { From fee5375c11747679b8a9579d22b9be53c2081ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Thu, 24 Jun 2021 10:45:48 +0800 Subject: [PATCH 5/7] chore: make the $parser non-enumerable --- lib/rule-tester/rule-tester.js | 41 ++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/lib/rule-tester/rule-tester.js b/lib/rule-tester/rule-tester.js index 15c29bfde01..9eaae6c657e 100644 --- a/lib/rule-tester/rule-tester.js +++ b/lib/rule-tester/rule-tester.js @@ -239,6 +239,21 @@ function defineStartEndAsError(objName, node) { }); } +/** + * define a property "$parser" to be original parser + * use `Object.defineProperty` to make it non-enumerable + * @param {Parser} wrappedParser the wrapped parser + * @param {Parser} originalParser the original parser + * @returns {void} + */ +function defineOriginalParser(wrappedParser, originalParser) { + Object.defineProperty(wrappedParser, "$parser", { + value: originalParser, + writable: true, + enumerable: false + }); +} + /** * Define `start`/`end` properties of all nodes of the given AST as throwing error. * @param {ASTNode} ast The root node to errorize `start`/`end` properties. @@ -258,8 +273,10 @@ function defineStartEndAsErrorInTree(ast, visitorKeys) { * @returns {Parser} Wrapped parser object. */ function wrapParser(parser) { + let wrappedParser; + if (typeof parser.parseForESLint === "function") { - return { + wrappedParser = { $parser: parser, parseForESLint(...args) { const ret = parser.parseForESLint(...args); @@ -268,16 +285,22 @@ function wrapParser(parser) { return ret; } }; + } else { + wrappedParser = { + $parser: parser, + parse(...args) { + const ast = parser.parse(...args); + + defineStartEndAsErrorInTree(ast); + return ast; + } + }; } - return { - $parser: parser, - parse(...args) { - const ast = parser.parse(...args); - defineStartEndAsErrorInTree(ast); - return ast; - } - }; + defineOriginalParser(wrappedParser, parser); + + return wrappedParser; + } //------------------------------------------------------------------------------ From 849464ee81927c799bb895add4d53d496bd2da18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Fri, 25 Jun 2021 09:30:15 +0800 Subject: [PATCH 6/7] chore: use symbol --- lib/linter/linter.js | 5 ++--- lib/rule-tester/rule-tester.js | 19 ++----------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/lib/linter/linter.js b/lib/linter/linter.js index 815ef9f2a16..4e80926a895 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -40,6 +40,7 @@ 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 } }; +const parserSymbol = Symbol.for("eslint.RuleTester.parser"); //------------------------------------------------------------------------------ // Typedefs @@ -438,9 +439,7 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) { * @returns {number} normalized ECMAScript version */ function normalizeEcmaVersion(parser, ecmaVersion) { - - // RuleTester always wraps parser, parser.$parser is the original parser object - if ((parser.$parser || parser) === espree) { + if ((parser[parserSymbol] || parser) === espree) { if (ecmaVersion === "latest") { return espree.latestEcmaVersion; } diff --git a/lib/rule-tester/rule-tester.js b/lib/rule-tester/rule-tester.js index 9eaae6c657e..5fb14359b1b 100644 --- a/lib/rule-tester/rule-tester.js +++ b/lib/rule-tester/rule-tester.js @@ -53,6 +53,7 @@ const const ajv = require("../shared/ajv")({ strictDefaults: true }); const espreePath = require.resolve("espree"); +const parserSymbol = Symbol.for("eslint.RuleTester.parser"); //------------------------------------------------------------------------------ // Typedefs @@ -239,20 +240,6 @@ function defineStartEndAsError(objName, node) { }); } -/** - * define a property "$parser" to be original parser - * use `Object.defineProperty` to make it non-enumerable - * @param {Parser} wrappedParser the wrapped parser - * @param {Parser} originalParser the original parser - * @returns {void} - */ -function defineOriginalParser(wrappedParser, originalParser) { - Object.defineProperty(wrappedParser, "$parser", { - value: originalParser, - writable: true, - enumerable: false - }); -} /** * Define `start`/`end` properties of all nodes of the given AST as throwing error. @@ -277,7 +264,6 @@ function wrapParser(parser) { if (typeof parser.parseForESLint === "function") { wrappedParser = { - $parser: parser, parseForESLint(...args) { const ret = parser.parseForESLint(...args); @@ -287,7 +273,6 @@ function wrapParser(parser) { }; } else { wrappedParser = { - $parser: parser, parse(...args) { const ast = parser.parse(...args); @@ -297,7 +282,7 @@ function wrapParser(parser) { }; } - defineOriginalParser(wrappedParser, parser); + wrappedParser[parserSymbol] = parser; return wrappedParser; From 1f9469ec32a368d7e2a12d6a1a6823c7b5f30bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Fri, 25 Jun 2021 09:43:44 +0800 Subject: [PATCH 7/7] chore: a small refactor --- lib/rule-tester/rule-tester.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/rule-tester/rule-tester.js b/lib/rule-tester/rule-tester.js index 5fb14359b1b..2b5524923be 100644 --- a/lib/rule-tester/rule-tester.js +++ b/lib/rule-tester/rule-tester.js @@ -260,10 +260,10 @@ function defineStartEndAsErrorInTree(ast, visitorKeys) { * @returns {Parser} Wrapped parser object. */ function wrapParser(parser) { - let wrappedParser; if (typeof parser.parseForESLint === "function") { - wrappedParser = { + return { + [parserSymbol]: parser, parseForESLint(...args) { const ret = parser.parseForESLint(...args); @@ -271,21 +271,17 @@ function wrapParser(parser) { return ret; } }; - } else { - wrappedParser = { - parse(...args) { - const ast = parser.parse(...args); - - defineStartEndAsErrorInTree(ast); - return ast; - } - }; } - wrappedParser[parserSymbol] = parser; - - return wrappedParser; + return { + [parserSymbol]: parser, + parse(...args) { + const ast = parser.parse(...args); + defineStartEndAsErrorInTree(ast); + return ast; + } + }; } //------------------------------------------------------------------------------