From 460c5ad176eaf39ff579cd96b3bcbe0539093f8f Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Sun, 8 Sep 2019 11:11:29 -0400 Subject: [PATCH 01/26] Sponsors: Sync README with website --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 134c991d81d..4c02d619c2b 100644 --- a/README.md +++ b/README.md @@ -264,7 +264,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

Gold Sponsors

Shopify Salesforce Badoo Airbnb Facebook Open Source

Silver Sponsors

AMP Project

Bronze Sponsors

-

VPS Server Free Icons by Icons8 UI UX Design Agencies clay Discord ThemeIsle TekHattan Marfeel Fire Stick Tricks JSHeroes

+

Discord MONEYPUG Free Icons by Icons8 UI UX Design Agencies clay VPS Server ThemeIsle TekHattan Marfeel Fire Stick Tricks JSHeroes

## Technology Sponsors From acc5ec5082aed466a29899f651e6767b39155aec Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Thu, 12 Sep 2019 12:11:27 -0400 Subject: [PATCH 02/26] Sponsors: Sync README with website --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c02d619c2b..e51882e9c29 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

Gold Sponsors

-

Shopify Salesforce Badoo Airbnb Facebook Open Source

Silver Sponsors

+

Shopify Salesforce Badoo Airbnb Facebook Open Source

Silver Sponsors

AMP Project

Bronze Sponsors

Discord MONEYPUG Free Icons by Icons8 UI UX Design Agencies clay VPS Server ThemeIsle TekHattan Marfeel Fire Stick Tricks JSHeroes

From 9418fbe0eb31cace3debe27b620709628df2fad7 Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Thu, 12 Sep 2019 13:11:29 -0400 Subject: [PATCH 03/26] Sponsors: Sync README with website --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e51882e9c29..28f512920c2 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ The following companies, organizations, and individuals support ESLint's ongoing

Gold Sponsors

-

Shopify Salesforce Badoo Airbnb Facebook Open Source

Silver Sponsors

+

Shopify Salesforce Badoo Airbnb Facebook Open Source

Silver Sponsors

AMP Project

Bronze Sponsors

Discord MONEYPUG Free Icons by Icons8 UI UX Design Agencies clay VPS Server ThemeIsle TekHattan Marfeel Fire Stick Tricks JSHeroes

From e38f5fdfc786363a3eae642f1a69a8725600aa61 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 13 Sep 2019 04:25:01 +0200 Subject: [PATCH 04/26] Update: fix no-octal-escape false negatives after \0 (#12079) --- lib/rules/no-octal-escape.js | 22 +++++++++++++-------- tests/lib/rules/no-octal-escape.js | 31 +++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/lib/rules/no-octal-escape.js b/lib/rules/no-octal-escape.js index a2860ca5bf8..7f6845ec70f 100644 --- a/lib/rules/no-octal-escape.js +++ b/lib/rules/no-octal-escape.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-octal-escape" }, - schema: [] + schema: [], + + messages: { + octalEscapeSequence: "Don't use octal: '\\{{sequence}}'. Use '\\u....' instead." + } }, create(context) { @@ -32,15 +36,17 @@ module.exports = { return; } - const match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/u); + // \0 represents a valid NULL character if it isn't followed by a digit. + const match = node.raw.match( + /^(?:[^\\]|\\.)*?\\([0-3][0-7]{1,2}|[4-7][0-7]|[1-7])/u + ); if (match) { - const octalDigit = match[2]; - - // \0 is actually not considered an octal - if (match[2] !== "0" || typeof match[3] !== "undefined") { - context.report({ node, message: "Don't use octal: '\\{{octalDigit}}'. Use '\\u....' instead.", data: { octalDigit } }); - } + context.report({ + node, + messageId: "octalEscapeSequence", + data: { sequence: match[1] } + }); } } diff --git a/tests/lib/rules/no-octal-escape.js b/tests/lib/rules/no-octal-escape.js index b15416ebf95..cd555ab607e 100644 --- a/tests/lib/rules/no-octal-escape.js +++ b/tests/lib/rules/no-octal-escape.js @@ -24,13 +24,34 @@ ruleTester.run("no-octal-escape", rule, { "var foo = \"\\x51\";", "var foo = \"foo \\\\251 bar\";", "var foo = /([abc]) \\1/g;", - "var foo = '\\0';" + "var foo = '\\0';", + "'\\0 '", + "'\\0a'", + "'\\\\1'", + "'\\\\01'", + "'\\08'", + "'\\09'" ], invalid: [ + + // Test full message { code: "var foo = \"foo \\01 bar\";", errors: [{ message: "Don't use octal: '\\01'. Use '\\u....' instead.", type: "Literal" }] }, - { code: "var foo = \"foo \\251 bar\";", errors: [{ message: "Don't use octal: '\\251'. Use '\\u....' instead.", type: "Literal" }] }, - { code: "var foo = \"\\751\";", errors: [{ message: "Don't use octal: '\\75'. Use '\\u....' instead.", type: "Literal" }] }, - { code: "var foo = \"\\3s51\";", errors: [{ message: "Don't use octal: '\\3'. Use '\\u....' instead.", type: "Literal" }] }, - { code: "var foo = \"\\\\\\751\";", errors: [{ message: "Don't use octal: '\\75'. Use '\\u....' instead.", type: "Literal" }] } + + { code: "var foo = \"foo \\251 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "251" }, type: "Literal" }] }, + { code: "var foo = \"\\751\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "75" }, type: "Literal" }] }, + { code: "var foo = \"\\3s51\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "3" }, type: "Literal" }] }, + { code: "var foo = \"\\\\\\751\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "75" }, type: "Literal" }] }, + { code: "'\\0\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] }, + { code: "'\\0 \\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] }, + { code: "'\\0\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] }, + { code: "'\\0 \\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] }, + { code: "'\\08\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] }, + { code: "'\\08\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] }, + + // Only the first one is reported + { code: "'\\01\\02'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] }, + { code: "'\\02\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "02" }, type: "Literal" }] }, + { code: "'\\01\\2'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] }, + { code: "'\\2\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "2" }, type: "Literal" }] } ] }); From a41fdc07404a7675d14183fab245fb8f49dcb858 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 13 Sep 2019 04:28:35 +0200 Subject: [PATCH 05/26] Fix: Remove autofixer for no-unsafe-negation (#12157) --- lib/rules/no-unsafe-negation.js | 12 ++---------- tests/lib/rules/no-unsafe-negation.js | 6 ------ 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/lib/rules/no-unsafe-negation.js b/lib/rules/no-unsafe-negation.js index f394f674259..717e5f6be39 100644 --- a/lib/rules/no-unsafe-negation.js +++ b/lib/rules/no-unsafe-negation.js @@ -51,7 +51,7 @@ module.exports = { }, schema: [], - fixable: "code", + fixable: null, messages: { unexpected: "Unexpected negating the left operand of '{{operator}}' operator." } @@ -70,15 +70,7 @@ module.exports = { node, loc: node.left.loc, messageId: "unexpected", - data: { operator: node.operator }, - - fix(fixer) { - const negationToken = sourceCode.getFirstToken(node.left); - const fixRange = [negationToken.range[1], node.range[1]]; - const text = sourceCode.text.slice(fixRange[0], fixRange[1]); - - return fixer.replaceTextRange(fixRange, `(${text})`); - } + data: { operator: node.operator } }); } } diff --git a/tests/lib/rules/no-unsafe-negation.js b/tests/lib/rules/no-unsafe-negation.js index 8316aad0227..6ac24541248 100644 --- a/tests/lib/rules/no-unsafe-negation.js +++ b/tests/lib/rules/no-unsafe-negation.js @@ -34,32 +34,26 @@ ruleTester.run("no-unsafe-negation", rule, { invalid: [ { code: "!a in b", - output: "!(a in b)", errors: [unexpectedInError] }, { code: "(!a in b)", - output: "(!(a in b))", errors: [unexpectedInError] }, { code: "!(a) in b", - output: "!((a) in b)", errors: [unexpectedInError] }, { code: "!a instanceof b", - output: "!(a instanceof b)", errors: [unexpectedInstanceofError] }, { code: "(!a instanceof b)", - output: "(!(a instanceof b))", errors: [unexpectedInstanceofError] }, { code: "!(a) instanceof b", - output: "!((a) instanceof b)", errors: [unexpectedInstanceofError] } ] From d52328f012f3704c7d1ce39427e63f80531c7979 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 13 Sep 2019 07:11:21 +0200 Subject: [PATCH 06/26] Docs: fix no-sequences `with` examples (#12239) --- docs/rules/no-sequences.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/no-sequences.md b/docs/rules/no-sequences.md index f1f4afea0ac..602a412f16a 100644 --- a/docs/rules/no-sequences.md +++ b/docs/rules/no-sequences.md @@ -60,7 +60,7 @@ switch ((val = foo(), val)) {} while ((val = foo(), val < 42)); -// with ((doSomething(), val)) {} +with ((doSomething(), val)) {} ``` ## When Not To Use It From 319e4d8386ea846928f0f906c251b46043a53491 Mon Sep 17 00:00:00 2001 From: Jens Melgaard Date: Fri, 13 Sep 2019 15:40:53 +0200 Subject: [PATCH 07/26] Docs: adding finally example (#12256) --- docs/rules/no-useless-catch.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/rules/no-useless-catch.md b/docs/rules/no-useless-catch.md index d320e561d07..0562063f634 100644 --- a/docs/rules/no-useless-catch.md +++ b/docs/rules/no-useless-catch.md @@ -43,6 +43,12 @@ try { } catch (e) { handleError(e); } + +try { + doSomethingThatMightThrow(); +} finally { + cleanUp(); +} ``` ## When Not To Use It From 01da7d04c4e5a7376cf241ec02db7971726a1bf9 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 00:47:54 +0200 Subject: [PATCH 08/26] Fix: eqeqeq rule reports incorrect locations (#12265) --- lib/rules/eqeqeq.js | 26 ++++-------- tests/lib/cli-engine/cli-engine.js | 2 + tests/lib/rules/eqeqeq.js | 63 ++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 19 deletions(-) diff --git a/lib/rules/eqeqeq.js b/lib/rules/eqeqeq.js index 58ff9030dbb..57926dbed0e 100644 --- a/lib/rules/eqeqeq.js +++ b/lib/rules/eqeqeq.js @@ -116,18 +116,6 @@ module.exports = { return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left); } - /** - * Gets the location (line and column) of the binary expression's operator - * @param {ASTNode} node The binary expression node to check - * @returns {Object} { line, column } location of operator - * @private - */ - function getOperatorLocation(node) { - const opToken = sourceCode.getTokenAfter(node.left); - - return { line: opToken.loc.start.line, column: opToken.loc.start.column }; - } - /** * Reports a message for this rule. * @param {ASTNode} node The binary expression node that was checked @@ -136,21 +124,21 @@ module.exports = { * @private */ function report(node, expectedOperator) { + const operatorToken = sourceCode.getFirstTokenBetween( + node.left, + node.right, + token => token.value === node.operator + ); + context.report({ node, - loc: getOperatorLocation(node), + loc: operatorToken.loc, messageId: "unexpected", data: { expectedOperator, actualOperator: node.operator }, fix(fixer) { // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix. if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) { - const operatorToken = sourceCode.getFirstTokenBetween( - node.left, - node.right, - token => token.value === node.operator - ); - return fixer.replaceText(operatorToken, expectedOperator); } return null; diff --git a/tests/lib/cli-engine/cli-engine.js b/tests/lib/cli-engine/cli-engine.js index 0c6db3ff93b..b3039e74314 100644 --- a/tests/lib/cli-engine/cli-engine.js +++ b/tests/lib/cli-engine/cli-engine.js @@ -1641,6 +1641,8 @@ describe("CLIEngine", () => { { column: 9, line: 2, + endColumn: 11, + endLine: 2, message: "Expected '===' and instead saw '=='.", messageId: "unexpected", nodeType: "BinaryExpression", diff --git a/tests/lib/rules/eqeqeq.js b/tests/lib/rules/eqeqeq.js index b74e9bc2ca5..05e33bbcfa9 100644 --- a/tests/lib/rules/eqeqeq.js +++ b/tests/lib/rules/eqeqeq.js @@ -105,6 +105,69 @@ ruleTester.run("eqeqeq", rule, { { messageId: "unexpected", data: wantedNotEqEq, type: "BinaryExpression", line: 1 }, { messageId: "unexpected", data: wantedNotEqEq, type: "BinaryExpression", line: 1 } ] + }, + + // location tests + { + code: "a == b;", + errors: [ + { + messageId: "unexpected", + data: wantedEqEqEq, + type: "BinaryExpression", + column: 3, + endColumn: 5 + } + ] + }, + { + code: "a!=b;", + errors: [ + { + messageId: "unexpected", + data: wantedNotEqEq, + type: "BinaryExpression", + column: 2, + endColumn: 4 + } + ] + }, + { + code: "(a + b) == c;", + errors: [ + { + messageId: "unexpected", + data: wantedEqEqEq, + type: "BinaryExpression", + column: 9, + endColumn: 11 + } + ] + }, + { + code: "(a + b) != c;", + errors: [ + { + messageId: "unexpected", + data: wantedNotEqEq, + type: "BinaryExpression", + column: 10, + endColumn: 12 + } + ] + }, + { + code: "((1) ) == (2);", + output: "((1) ) === (2);", + errors: [ + { + messageId: "unexpected", + data: wantedEqEqEq, + type: "BinaryExpression", + column: 9, + endColumn: 11 + } + ] } // If no output is provided, assert that no output is produced. From 985c9e5eba351965a8a1491a41dbdcc78154b8f4 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 02:14:52 +0200 Subject: [PATCH 09/26] Fix: space-before-function-paren autofix removes comments (fixes #12259) (#12264) --- lib/rules/space-before-function-paren.js | 13 ++- .../lib/rules/space-before-function-paren.js | 86 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/lib/rules/space-before-function-paren.js b/lib/rules/space-before-function-paren.js index ca20dbc4abf..3a6d430f362 100644 --- a/lib/rules/space-before-function-paren.js +++ b/lib/rules/space-before-function-paren.js @@ -124,7 +124,18 @@ module.exports = { node, loc: leftToken.loc.end, message: "Unexpected space before function parentheses.", - fix: fixer => fixer.removeRange([leftToken.range[1], rightToken.range[0]]) + fix(fixer) { + const comments = sourceCode.getCommentsBefore(rightToken); + + // Don't fix anything if there's a single line comment between the left and the right token + if (comments.some(comment => comment.type === "Line")) { + return null; + } + return fixer.replaceTextRange( + [leftToken.range[1], rightToken.range[0]], + comments.reduce((text, comment) => text + sourceCode.getText(comment), "") + ); + } }); } else if (!hasSpacing && functionConfig === "always") { context.report({ diff --git a/tests/lib/rules/space-before-function-paren.js b/tests/lib/rules/space-before-function-paren.js index 5bcfd7be16c..961d6895adc 100644 --- a/tests/lib/rules/space-before-function-paren.js +++ b/tests/lib/rules/space-before-function-paren.js @@ -24,6 +24,11 @@ ruleTester.run("space-before-function-paren", rule, { "function foo () {}", "var foo = function () {}", "var bar = function foo () {}", + "var bar = function foo/**/ () {}", + "var bar = function foo /**/() {}", + "var bar = function foo/**/\n() {}", + "var bar = function foo\n/**/() {}", + "var bar = function foo//\n() {}", "var obj = { get foo () {}, set foo (val) {} };", { code: "var obj = { foo () {} };", @@ -34,6 +39,9 @@ ruleTester.run("space-before-function-paren", rule, { { code: "function foo() {}", options: ["never"] }, { code: "var foo = function() {}", options: ["never"] }, + { code: "var foo = function/**/() {}", options: ["never"] }, + { code: "var foo = function/* */() {}", options: ["never"] }, + { code: "var foo = function/* *//* */() {}", options: ["never"] }, { code: "var bar = function foo() {}", options: ["never"] }, { code: "var obj = { get foo() {}, set foo(val) {} };", options: ["never"] }, { @@ -226,6 +234,84 @@ ruleTester.run("space-before-function-paren", rule, { } ] }, + { + code: "function foo /* */ () {}", + output: "function foo/* */() {}", + options: ["never"], + errors: [ + { + type: "FunctionDeclaration", + message: "Unexpected space before function parentheses.", + line: 1, + column: 13 + } + ] + }, + { + code: "function foo/* block comment */ () {}", + output: "function foo/* block comment */() {}", + options: ["never"], + errors: [ + { + type: "FunctionDeclaration", + message: "Unexpected space before function parentheses.", + line: 1, + column: 13 + } + ] + }, + { + code: "function foo/* 1 */ /* 2 */ \n /* 3 */\n/* 4 */ () {}", + output: "function foo/* 1 *//* 2 *//* 3 *//* 4 */() {}", + options: ["never"], + errors: [ + { + type: "FunctionDeclaration", + message: "Unexpected space before function parentheses.", + line: 1, + column: 13 + } + ] + }, + { + code: "function foo//\n() {}", + output: null, + options: ["never"], + errors: [ + { + type: "FunctionDeclaration", + message: "Unexpected space before function parentheses.", + line: 1, + column: 13 + } + ] + }, + { + code: "function foo // line comment \n () {}", + output: null, + options: ["never"], + errors: [ + { + type: "FunctionDeclaration", + message: "Unexpected space before function parentheses.", + line: 1, + column: 13 + } + ] + }, + { + code: "function foo\n//\n() {}", + output: null, + options: ["never"], + errors: [ + { + type: "FunctionDeclaration", + message: "Unexpected space before function parentheses.", + line: 1, + column: 13 + } + ] + }, { code: "var foo = function () {}", output: "var foo = function() {}", From 37c0fdeb87b92a0b779b125adf45535b79b65757 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 02:25:07 +0200 Subject: [PATCH 10/26] Update: Report global Atomics calls in no-obj-calls (fixes #12234) (#12258) --- docs/rules/no-obj-calls.md | 10 ++- lib/rules/no-obj-calls.js | 38 ++++++++--- tests/lib/rules/no-obj-calls.js | 109 ++++++++++++++++++++++++++++++-- 3 files changed, 142 insertions(+), 15 deletions(-) diff --git a/docs/rules/no-obj-calls.md b/docs/rules/no-obj-calls.md index 9484eb73688..cfd5576eae5 100644 --- a/docs/rules/no-obj-calls.md +++ b/docs/rules/no-obj-calls.md @@ -6,13 +6,17 @@ The [ECMAScript 5 specification](https://es5.github.io/#x15.8) makes it clear th > The Math object does not have a `[[Call]]` internal property; it is not possible to invoke the Math object as a function. -And the [ECMAScript 2015 specification](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-reflect-object) makes it clear that `Reflect` cannot be invoked: +The [ECMAScript 2015 specification](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-reflect-object) makes it clear that `Reflect` cannot be invoked: > The Reflect object also does not have a `[[Call]]` internal method; it is not possible to invoke the Reflect object as a function. +And the [ECMAScript 2017 specification](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-atomics-object) makes it clear that `Atomics` cannot be invoked: + +> The Atomics object does not have a [[Call]] internal method; it is not possible to invoke the Atomics object as a function. + ## Rule Details -This rule disallows calling the `Math`, `JSON` and `Reflect` objects as functions. +This rule disallows calling the `Math`, `JSON`, `Reflect` and `Atomics` objects as functions. Examples of **incorrect** code for this rule: @@ -22,6 +26,7 @@ Examples of **incorrect** code for this rule: var math = Math(); var json = JSON(); var reflect = Reflect(); +var atomics = Atomics(); ``` Examples of **correct** code for this rule: @@ -34,6 +39,7 @@ function area(r) { } var object = JSON.parse("{}"); var value = Reflect.get({ x: 1, y: 2 }, "x"); +var first = Atomics.load(foo, 0); ``` ## Further Reading diff --git a/lib/rules/no-obj-calls.js b/lib/rules/no-obj-calls.js index 92492b7a26e..5102d559494 100644 --- a/lib/rules/no-obj-calls.js +++ b/lib/rules/no-obj-calls.js @@ -5,6 +5,18 @@ "use strict"; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const { CALL, ReferenceTracker } = require("eslint-utils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect"]; + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -20,23 +32,31 @@ module.exports = { url: "https://eslint.org/docs/rules/no-obj-calls" }, - schema: [] + schema: [], + + messages: { + unexpectedCall: "'{{name}}' is not a function." + } }, create(context) { return { - CallExpression(node) { - - if (node.callee.type === "Identifier") { - const name = node.callee.name; + Program() { + const scope = context.getScope(); + const tracker = new ReferenceTracker(scope); + const traceMap = {}; + + for (const global of nonCallableGlobals) { + traceMap[global] = { + [CALL]: true + }; + } - if (name === "Math" || name === "JSON" || name === "Reflect") { - context.report({ node, message: "'{{name}}' is not a function.", data: { name } }); - } + for (const { node } of tracker.iterateGlobalReferences(traceMap)) { + context.report({ node, messageId: "unexpectedCall", data: { name: node.callee.name } }); } } }; - } }; diff --git a/tests/lib/rules/no-obj-calls.js b/tests/lib/rules/no-obj-calls.js index 6f390ab4575..d5bcf063818 100644 --- a/tests/lib/rules/no-obj-calls.js +++ b/tests/lib/rules/no-obj-calls.js @@ -20,11 +20,112 @@ const ruleTester = new RuleTester(); ruleTester.run("no-obj-calls", rule, { valid: [ - "var x = Math.random();" + "var x = Math;", + "var x = Math.random();", + "var x = Math.PI;", + "var x = foo.Math();", + "JSON.parse(foo)", + "Reflect.get(foo, 'x')", + "Atomics.load(foo, 0)", + + // non-existing variables + "/*globals Math: off*/ Math();", + { + code: "JSON();", + globals: { JSON: "off" } + }, + "Reflect();", + "Atomics();", + { + code: "Atomics();", + env: { es6: true } + }, + + // shadowed variables + "var Math; Math();", + { + code: "let JSON; JSON();", + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (foo) { const Reflect = 1; Reflect(); }", + parserOptions: { ecmaVersion: 2015 }, + env: { es6: true } + }, + "function foo(Math) { Math(); }", + { + code: "function foo(Atomics) { Atomics(); }", + env: { es2017: true } + }, + "function foo() { var JSON; JSON(); }", + { + code: "function foo() { var Atomics = bar(); var baz = Atomics(5); }", + globals: { Atomics: false } + } ], invalid: [ - { code: "var x = Math();", errors: [{ message: "'Math' is not a function.", type: "CallExpression" }] }, - { code: "var x = JSON();", errors: [{ message: "'JSON' is not a function.", type: "CallExpression" }] }, - { code: "var x = Reflect();", errors: [{ message: "'Reflect' is not a function.", type: "CallExpression" }] } + + // test full message + { + code: "Math();", + errors: [{ message: "'Math' is not a function.", type: "CallExpression" }] + }, + + { + code: "var x = Math();", + errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression" }] + }, + { + code: "f(Math());", + errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression", column: 3, endColumn: 9 }] + }, + { + code: "Math().foo;", + errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression", column: 1, endColumn: 7 }] + }, + { + code: "var x = JSON();", + errors: [{ messageId: "unexpectedCall", data: { name: "JSON" }, type: "CallExpression" }] + }, + { + code: "x = JSON(str);", + errors: [{ messageId: "unexpectedCall", data: { name: "JSON" }, type: "CallExpression" }] + }, + { + code: "Math( JSON() );", + errors: [ + { messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression", column: 1, endColumn: 15 }, + { messageId: "unexpectedCall", data: { name: "JSON" }, type: "CallExpression", column: 7, endColumn: 13 } + ] + }, + { + code: "var x = Reflect();", + env: { es6: true }, + errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }] + }, + { + code: "var x = Reflect();", + env: { es2017: true }, + errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }] + }, + { + code: "/*globals Reflect: true*/ Reflect();", + errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }] + }, + { + code: "var x = Atomics();", + env: { es2017: true }, + errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }] + }, + { + code: "var x = Atomics();", + env: { es2020: true }, + errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }] + }, + { + code: "var x = Atomics();", + globals: { Atomics: false }, + errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }] + } ] }); From 3be04fd6a4e7b3f5a5ecb845a29cf29b71fe2dfb Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 02:29:15 +0200 Subject: [PATCH 11/26] New: Add prefer-regex-literals rule (fixes #12238) (#12254) * New: Add prefer-regex-literals rule (fixes #12238) * Update docs/rules/prefer-regex-literals.md Co-Authored-By: Kevin Partington * Update docs/rules/prefer-regex-literals.md Co-Authored-By: Kevin Partington * Pass ecmaVersion to RuleTester constructor * Check global String reference --- docs/rules/prefer-regex-literals.md | 90 +++++++++++ lib/rules/index.js | 1 + lib/rules/prefer-regex-literals.js | 125 ++++++++++++++++ tests/lib/rules/prefer-regex-literals.js | 182 +++++++++++++++++++++++ tools/rule-types.json | 1 + 5 files changed, 399 insertions(+) create mode 100644 docs/rules/prefer-regex-literals.md create mode 100644 lib/rules/prefer-regex-literals.js create mode 100644 tests/lib/rules/prefer-regex-literals.js diff --git a/docs/rules/prefer-regex-literals.md b/docs/rules/prefer-regex-literals.md new file mode 100644 index 00000000000..01d4149cf20 --- /dev/null +++ b/docs/rules/prefer-regex-literals.md @@ -0,0 +1,90 @@ +# Disallow use of the `RegExp` constructor in favor of regular expression literals (prefer-regex-literals) + +There are two ways to create a regular expression: + +* Regular expression literals, e.g., `/abc/u`. +* The `RegExp` constructor function, e.g., `new RegExp("abc", "u")` or `RegExp("abc", "u")`. + +The constructor function is particularly useful when you want to dynamically generate the pattern, +because it takes string arguments. + +When using the constructor function with string literals, don't forget that the string escaping rules still apply. +If you want to put a backslash in the pattern, you need to escape it in the string literal. +Thus, the following are equivalent: + +```js +new RegExp("^\\d\\.$"); + +/^\d\.$/; + +// matches "0.", "1.", "2." ... "9." +``` + +In the above example, the regular expression literal is easier to read and reason about. +Also, it's a common mistake to omit the extra `\` in the string literal, which would produce a completely different regular expression: + +```js +new RegExp("^\d\.$"); + +// equivalent to /^d.$/, matches "d1", "d2", "da", "db" ... +``` + +When a regular expression is known in advance, it is considered a best practice to avoid the string literal notation on top +of the regular expression notation, and use regular expression literals instead of the constructor function. + +## Rule Details + +This rule disallows the use of the `RegExp` constructor function with string literals as its arguments. + +This rule also disallows the use of the `RegExp` constructor function with template literals without expressions +and `String.raw` tagged template literals without expressions. + +The rule does not disallow all use of the `RegExp` constructor. It should be still used for +dynamically generated regular expressions. + +Examples of **incorrect** code for this rule: + +```js +new RegExp("abc"); + +new RegExp("abc", "u"); + +RegExp("abc"); + +RegExp("abc", "u"); + +new RegExp("\\d\\d\\.\\d\\d\\.\\d\\d\\d\\d"); + +RegExp(`^\\d\\.$`); + +new RegExp(String.raw`^\d\.$`); +``` + +Examples of **correct** code for this rule: + +```js +/abc/; + +/abc/u; + +/\d\d\.\d\d\.\d\d\d\d/; + +/^\d\.$/; + +// RegExp constructor is allowed for dynamically generated regular expressions + +new RegExp(pattern); + +RegExp("abc", flags); + +new RegExp(prefix + "abc"); + +RegExp(`${prefix}abc`); + +new RegExp(String.raw`^\d\. ${sufix}`); +``` + +## Further Reading + +* [MDN: Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) +* [MDN: RegExp Constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) diff --git a/lib/rules/index.js b/lib/rules/index.js index 51d224d219f..dcfe2e1c3c6 100644 --- a/lib/rules/index.js +++ b/lib/rules/index.js @@ -242,6 +242,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "prefer-object-spread": () => require("./prefer-object-spread"), "prefer-promise-reject-errors": () => require("./prefer-promise-reject-errors"), "prefer-reflect": () => require("./prefer-reflect"), + "prefer-regex-literals": () => require("./prefer-regex-literals"), "prefer-rest-params": () => require("./prefer-rest-params"), "prefer-spread": () => require("./prefer-spread"), "prefer-template": () => require("./prefer-template"), diff --git a/lib/rules/prefer-regex-literals.js b/lib/rules/prefer-regex-literals.js new file mode 100644 index 00000000000..47b2b090f82 --- /dev/null +++ b/lib/rules/prefer-regex-literals.js @@ -0,0 +1,125 @@ +/** + * @fileoverview Rule to disallow use of the `RegExp` constructor in favor of regular expression literals + * @author Milos Djermanovic + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const astUtils = require("./utils/ast-utils"); +const { CALL, CONSTRUCT, ReferenceTracker, findVariable } = require("eslint-utils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Determines whether the given node is a string literal. + * @param {ASTNode} node Node to check. + * @returns {boolean} True if the node is a string literal. + */ +function isStringLiteral(node) { + return node.type === "Literal" && typeof node.value === "string"; +} + +/** + * Determines whether the given node is a template literal without expressions. + * @param {ASTNode} node Node to check. + * @returns {boolean} True if the node is a template literal without expressions. + */ +function isStaticTemplateLiteral(node) { + return node.type === "TemplateLiteral" && node.expressions.length === 0; +} + + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "suggestion", + + docs: { + description: "disallow use of the `RegExp` constructor in favor of regular expression literals", + category: "Best Practices", + recommended: false, + url: "https://eslint.org/docs/rules/prefer-regex-literals" + }, + + schema: [], + + messages: { + unexpectedRegExp: "Use a regular expression literal instead of the 'RegExp' constructor." + } + }, + + create(context) { + + /** + * Determines whether the given identifier node is a reference to a global variable. + * @param {ASTNode} node `Identifier` node to check. + * @returns {boolean} True if the identifier is a reference to a global variable. + */ + function isGlobalReference(node) { + const scope = context.getScope(); + const variable = findVariable(scope, node); + + return variable !== null && variable.scope.type === "global" && variable.defs.length === 0; + } + + /** + * Determines whether the given node is a String.raw`` tagged template expression + * with a static template literal. + * @param {ASTNode} node Node to check. + * @returns {boolean} True if the node is String.raw`` with a static template. + */ + function isStringRawTaggedStaticTemplateLiteral(node) { + return node.type === "TaggedTemplateExpression" && + node.tag.type === "MemberExpression" && + node.tag.object.type === "Identifier" && + node.tag.object.name === "String" && + isGlobalReference(node.tag.object) && + astUtils.getStaticPropertyName(node.tag) === "raw" && + isStaticTemplateLiteral(node.quasi); + } + + /** + * Determines whether the given node is considered to be a static string by the logic of this rule. + * @param {ASTNode} node Node to check. + * @returns {boolean} True if the node is a static string. + */ + function isStaticString(node) { + return isStringLiteral(node) || + isStaticTemplateLiteral(node) || + isStringRawTaggedStaticTemplateLiteral(node); + } + + return { + Program() { + const scope = context.getScope(); + const tracker = new ReferenceTracker(scope); + const traceMap = { + RegExp: { + [CALL]: true, + [CONSTRUCT]: true + } + }; + + for (const { node } of tracker.iterateGlobalReferences(traceMap)) { + const args = node.arguments; + + if ( + (args.length === 1 || args.length === 2) && + args.every(isStaticString) + ) { + context.report({ node, messageId: "unexpectedRegExp" }); + } + } + } + }; + } +}; diff --git a/tests/lib/rules/prefer-regex-literals.js b/tests/lib/rules/prefer-regex-literals.js new file mode 100644 index 00000000000..e263ef03dc7 --- /dev/null +++ b/tests/lib/rules/prefer-regex-literals.js @@ -0,0 +1,182 @@ +/** + * @fileoverview Tests for the prefer-regex-literals rule + * @author Milos Djermanovic + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require("../../../lib/rules/prefer-regex-literals"); +const { RuleTester } = require("../../../lib/rule-tester"); + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } }); + +ruleTester.run("prefer-regex-literals", rule, { + valid: [ + "/abc/", + "/abc/g", + + // considered as dynamic + "new RegExp(pattern)", + "RegExp(pattern, 'g')", + "new RegExp(f('a'))", + "RegExp(prefix + 'a')", + "new RegExp('a' + sufix)", + "RegExp(`a` + sufix);", + "new RegExp(String.raw`a` + sufix);", + "RegExp('a', flags)", + "RegExp('a', 'g' + flags)", + "new RegExp(String.raw`a`, flags);", + "RegExp(`${prefix}abc`)", + "new RegExp(`a${b}c`);", + "new RegExp(`a${''}c`);", + "new RegExp(String.raw`a${b}c`);", + "new RegExp(String.raw`a${''}c`);", + "new RegExp('a' + 'b')", + "RegExp(1)", + + // invalid number of arguments + "new RegExp;", + "new RegExp();", + "RegExp();", + "new RegExp('a', 'g', 'b');", + "RegExp('a', 'g', 'b');", + "new RegExp(`a`, `g`, `b`);", + "RegExp(`a`, `g`, `b`);", + "new RegExp(String.raw`a`, String.raw`g`, String.raw`b`);", + "RegExp(String.raw`a`, String.raw`g`, String.raw`b`);", + + // not String.raw`` + "new RegExp(String`a`);", + "RegExp(raw`a`);", + "new RegExp(f(String.raw)`a`);", + "RegExp(string.raw`a`);", + "new RegExp(String.Raw`a`);", + "new RegExp(String[raw]`a`);", + "RegExp(String.raw.foo`a`);", + "new RegExp(String.foo.raw`a`);", + "RegExp(foo.String.raw`a`);", + "new RegExp(String.raw);", + + // not the global String in String.raw`` + "let String; new RegExp(String.raw`a`);", + "function foo() { var String; new RegExp(String.raw`a`); }", + "function foo(String) { RegExp(String.raw`a`); }", + "if (foo) { const String = bar; RegExp(String.raw`a`); }", + "/* globals String:off */ new RegExp(String.raw`a`);", + { + code: "RegExp('a', String.raw`g`);", + globals: { String: "off" } + }, + + // not RegExp + "new Regexp('abc');", + "Regexp(`a`);", + "new Regexp(String.raw`a`);", + + // not the global RegExp + "let RegExp; new RegExp('a');", + "function foo() { var RegExp; RegExp('a', 'g'); }", + "function foo(RegExp) { new RegExp(String.raw`a`); }", + "if (foo) { const RegExp = bar; RegExp('a'); }", + "/* globals RegExp:off */ new RegExp('a');", + { + code: "RegExp('a');", + globals: { RegExp: "off" } + } + ], + + invalid: [ + { + code: "new RegExp('abc');", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp('abc');", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "new RegExp('abc', 'g');", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp('abc', 'g');", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "new RegExp(`abc`);", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp(`abc`);", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "new RegExp(`abc`, `g`);", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp(`abc`, `g`);", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "new RegExp(String.raw`abc`);", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp(String.raw`abc`);", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "new RegExp(String.raw`abc`, String.raw`g`);", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp(String.raw`abc`, String.raw`g`);", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "new RegExp(String['raw']`a`);", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "new RegExp('');", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp('', '');", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "new RegExp(String.raw``);", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "new RegExp('a', `g`);", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp(`a`, 'g');", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "RegExp(String.raw`a`, 'g');", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + }, + { + code: "new RegExp(String.raw`\\d`, `g`);", + errors: [{ messageId: "unexpectedRegExp", type: "NewExpression" }] + }, + { + code: "RegExp('a', String.raw`g`);", + errors: [{ messageId: "unexpectedRegExp", type: "CallExpression" }] + } + ] +}); diff --git a/tools/rule-types.json b/tools/rule-types.json index 74cae9391cb..ea15a2cfd4c 100644 --- a/tools/rule-types.json +++ b/tools/rule-types.json @@ -229,6 +229,7 @@ "prefer-object-spread": "suggestion", "prefer-promise-reject-errors": "suggestion", "prefer-reflect": "suggestion", + "prefer-regex-literals": "suggestion", "prefer-rest-params": "suggestion", "prefer-spread": "suggestion", "prefer-template": "suggestion", From 1c921c6dfd7ddfb0308c8103e53d32c1241475f0 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Sat, 14 Sep 2019 09:30:53 +0900 Subject: [PATCH 12/26] New: add no-import-assign (fixes #12237) (#12252) * New: add no-import-assign (fixes #12237) * add destructuring and for-in/of syntax * add mutation functions * add a more test * allow seal and preventExtensions * add a test --- docs/rules/no-import-assign.md | 44 ++++ lib/rules/index.js | 1 + lib/rules/no-import-assign.js | 238 +++++++++++++++++++++ tests/lib/rules/no-import-assign.js | 315 ++++++++++++++++++++++++++++ tools/rule-types.json | 1 + 5 files changed, 599 insertions(+) create mode 100644 docs/rules/no-import-assign.md create mode 100644 lib/rules/no-import-assign.js create mode 100644 tests/lib/rules/no-import-assign.js diff --git a/docs/rules/no-import-assign.md b/docs/rules/no-import-assign.md new file mode 100644 index 00000000000..78b228dd828 --- /dev/null +++ b/docs/rules/no-import-assign.md @@ -0,0 +1,44 @@ +# disallow assigning to imported bindings (no-import-assign) + +The updates of imported bindings by ES Modules cause runtime errors. + +## Rule Details + +This rule warns the assignments, increments, and decrements of imported bindings. + +Examples of **incorrect** code for this rule: + +```js +/*eslint no-import-assign: "error"*/ + +import mod, { named } from "./mod.mjs" +import * as mod_ns from "./mod.mjs" + +mod = 1 // ERROR: 'mod' is readonly. +named = 2 // ERROR: 'named' is readonly. +mod_ns.named = 3 // ERROR: the members of 'mod_ns' is readonly. +mod_ns = {} // ERROR: 'mod_ns' is readonly. +``` + +Examples of **correct** code for this rule: + +```js +/*eslint no-import-assign: "error"*/ + +import mod, { named } from "./mod.mjs" +import * as mod_ns from "./mod.mjs" + +mod.prop = 1 +named.prop = 2 +mod_ns.named.prop = 3 + +// Known Limitation +function test(obj) { + obj.named = 4 // Not errored because 'obj' is not namespace objects. +} +test(mod_ns) // Not errored because it doesn't know that 'test' updates the member of the argument. +``` + +## When Not To Use It + +If you don't want to be notified about modifying imported bindings, you can disable this rule. diff --git a/lib/rules/index.js b/lib/rules/index.js index dcfe2e1c3c6..8b0abc4ee7a 100644 --- a/lib/rules/index.js +++ b/lib/rules/index.js @@ -132,6 +132,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "no-implicit-coercion": () => require("./no-implicit-coercion"), "no-implicit-globals": () => require("./no-implicit-globals"), "no-implied-eval": () => require("./no-implied-eval"), + "no-import-assign": () => require("./no-import-assign"), "no-inline-comments": () => require("./no-inline-comments"), "no-inner-declarations": () => require("./no-inner-declarations"), "no-invalid-regexp": () => require("./no-invalid-regexp"), diff --git a/lib/rules/no-import-assign.js b/lib/rules/no-import-assign.js new file mode 100644 index 00000000000..0865cf9a977 --- /dev/null +++ b/lib/rules/no-import-assign.js @@ -0,0 +1,238 @@ +/** + * @fileoverview Rule to flag updates of imported bindings. + * @author Toru Nagashima + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +const { findVariable, getPropertyName } = require("eslint-utils"); + +const MutationMethods = { + Object: new Set([ + "assign", "defineProperties", "defineProperty", "freeze", + "setPrototypeOf" + ]), + Reflect: new Set([ + "defineProperty", "deleteProperty", "set", "setPrototypeOf" + ]) +}; + +/** + * Check if a given node is LHS of an assignment node. + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if the node is LHS. + */ +function isAssignmentLeft(node) { + const { parent } = node; + + return ( + ( + parent.type === "AssignmentExpression" && + parent.left === node + ) || + + // Destructuring assignments + parent.type === "ArrayPattern" || + ( + parent.type === "Property" && + parent.value === node && + parent.parent.type === "ObjectPattern" + ) || + parent.type === "RestElement" || + ( + parent.type === "AssignmentPattern" && + parent.left === node + ) + ); +} + +/** + * Check if a given node is the operand of mutation unary operator. + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if the node is the operand of mutation unary operator. + */ +function isOperandOfMutationUnaryOperator(node) { + const { parent } = node; + + return ( + ( + parent.type === "UpdateExpression" && + parent.argument === node + ) || + ( + parent.type === "UnaryExpression" && + parent.operator === "delete" && + parent.argument === node + ) + ); +} + +/** + * Check if a given node is the iteration variable of `for-in`/`for-of` syntax. + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if the node is the iteration variable. + */ +function isIterationVariable(node) { + const { parent } = node; + + return ( + ( + parent.type === "ForInStatement" && + parent.left === node + ) || + ( + parent.type === "ForOfStatement" && + parent.left === node + ) + ); +} + +/** + * Check if a given node is the iteration variable of `for-in`/`for-of` syntax. + * @param {ASTNode} node The node to check. + * @param {Scope} scope A `escope.Scope` object to find variable (whichever). + * @returns {boolean} `true` if the node is the iteration variable. + */ +function isArgumentOfWellKnownMutationFunction(node, scope) { + const { parent } = node; + + if ( + parent.type === "CallExpression" && + parent.arguments[0] === node && + parent.callee.type === "MemberExpression" && + parent.callee.object.type === "Identifier" + ) { + const { callee } = parent; + const { object } = callee; + + if (Object.keys(MutationMethods).includes(object.name)) { + const variable = findVariable(scope, object); + + return ( + variable !== null && + variable.scope.type === "global" && + MutationMethods[object.name].has(getPropertyName(callee, scope)) + ); + } + } + + return false; +} + +/** + * Check if the identifier node is placed at to update members. + * @param {ASTNode} id The Identifier node to check. + * @param {Scope} scope A `escope.Scope` object to find variable (whichever). + * @returns {boolean} `true` if the member of `id` was updated. + */ +function isMemberWrite(id, scope) { + const { parent } = id; + + return ( + ( + parent.type === "MemberExpression" && + parent.object === id && + ( + isAssignmentLeft(parent) || + isOperandOfMutationUnaryOperator(parent) || + isIterationVariable(parent) + ) + ) || + isArgumentOfWellKnownMutationFunction(id, scope) + ); +} + +/** + * Get the mutation node. + * @param {ASTNode} id The Identifier node to get. + * @returns {ASTNode} The mutation node. + */ +function getWriteNode(id) { + let node = id.parent; + + while ( + node && + node.type !== "AssignmentExpression" && + node.type !== "UpdateExpression" && + node.type !== "UnaryExpression" && + node.type !== "CallExpression" && + node.type !== "ForInStatement" && + node.type !== "ForOfStatement" + ) { + node = node.parent; + } + + return node || id; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "problem", + + docs: { + description: "disallow assigning to imported bindings", + category: "Possible Errors", + recommended: false, + url: "https://eslint.org/docs/rules/no-import-assign" + }, + + schema: [], + + messages: { + readonly: "'{{name}}' is read-only.", + readonlyMember: "The members of '{{name}}' are read-only." + } + }, + + create(context) { + return { + ImportDeclaration(node) { + const scope = context.getScope(); + + for (const variable of context.getDeclaredVariables(node)) { + const shouldCheckMembers = variable.defs.some( + d => d.node.type === "ImportNamespaceSpecifier" + ); + let prevIdNode = null; + + for (const reference of variable.references) { + const idNode = reference.identifier; + + /* + * AssignmentPattern (e.g. `[a = 0] = b`) makes two write + * references for the same identifier. This should skip + * the one of the two in order to prevent redundant reports. + */ + if (idNode === prevIdNode) { + continue; + } + prevIdNode = idNode; + + if (reference.isWrite()) { + context.report({ + node: getWriteNode(idNode), + messageId: "readonly", + data: { name: idNode.name } + }); + } else if (shouldCheckMembers && isMemberWrite(idNode, scope)) { + context.report({ + node: getWriteNode(idNode), + messageId: "readonlyMember", + data: { name: idNode.name } + }); + } + } + } + } + }; + + } +}; diff --git a/tests/lib/rules/no-import-assign.js b/tests/lib/rules/no-import-assign.js new file mode 100644 index 00000000000..ab65451e33a --- /dev/null +++ b/tests/lib/rules/no-import-assign.js @@ -0,0 +1,315 @@ +/** + * @fileoverview Tests for no-import-assign rule. + * @author Toru Nagashima + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require("../../../lib/rules/no-import-assign"), + { RuleTester } = require("../../../lib/rule-tester"); + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + parserOptions: { + ecmaVersion: 2018, + sourceType: "module" + }, + globals: { + Reflect: "readonly" + } +}); + +ruleTester.run("no-import-assign", rule, { + valid: [ + "import mod from 'mod'; mod.prop = 0", + "import mod from 'mod'; mod.prop += 0", + "import mod from 'mod'; mod.prop++", + "import mod from 'mod'; delete mod.prop", + "import mod from 'mod'; for (mod.prop in foo);", + "import mod from 'mod'; for (mod.prop of foo);", + "import mod from 'mod'; [mod.prop] = foo;", + "import mod from 'mod'; [...mod.prop] = foo;", + "import mod from 'mod'; ({ bar: mod.prop } = foo);", + "import mod from 'mod'; ({ ...mod.prop } = foo);", + "import {named} from 'mod'; named.prop = 0", + "import {named} from 'mod'; named.prop += 0", + "import {named} from 'mod'; named.prop++", + "import {named} from 'mod'; delete named.prop", + "import {named} from 'mod'; for (named.prop in foo);", + "import {named} from 'mod'; for (named.prop of foo);", + "import {named} from 'mod'; [named.prop] = foo;", + "import {named} from 'mod'; [...named.prop] = foo;", + "import {named} from 'mod'; ({ bar: named.prop } = foo);", + "import {named} from 'mod'; ({ ...named.prop } = foo);", + "import * as mod from 'mod'; mod.named.prop = 0", + "import * as mod from 'mod'; mod.named.prop += 0", + "import * as mod from 'mod'; mod.named.prop++", + "import * as mod from 'mod'; delete mod.named.prop", + "import * as mod from 'mod'; for (mod.named.prop in foo);", + "import * as mod from 'mod'; for (mod.named.prop of foo);", + "import * as mod from 'mod'; [mod.named.prop] = foo;", + "import * as mod from 'mod'; [...mod.named.prop] = foo;", + "import * as mod from 'mod'; ({ bar: mod.named.prop } = foo);", + "import * as mod from 'mod'; ({ ...mod.named.prop } = foo);", + "import * as mod from 'mod'; obj[mod] = 0", + "import * as mod from 'mod'; obj[mod.named] = 0", + "import * as mod from 'mod'; for (var foo in mod.named);", + "import * as mod from 'mod'; for (var foo of mod.named);", + "import * as mod from 'mod'; [bar = mod.named] = foo;", + "import * as mod from 'mod'; ({ bar = mod.named } = foo);", + "import * as mod from 'mod'; ({ bar: baz = mod.named } = foo);", + "import * as mod from 'mod'; ({ [mod.named]: bar } = foo);", + "import * as mod from 'mod'; var obj = { ...mod.named };", + "import * as mod from 'mod'; var obj = { foo: mod.named };", + "import mod from 'mod'; { let mod = 0; mod = 1 }", + "import * as mod from 'mod'; { let mod = 0; mod = 1 }", + "import * as mod from 'mod'; { let mod = 0; mod.named = 1 }", + "import {} from 'mod'", + "import 'mod'", + "import mod from 'mod'; Object.assign(mod, obj);", + "import {named} from 'mod'; Object.assign(named, obj);", + "import * as mod from 'mod'; Object.assign(mod.prop, obj);", + "import * as mod from 'mod'; Object.assign(obj, mod, other);", + "import * as mod from 'mod'; Object[assign](mod, obj);", + "import * as mod from 'mod'; Object.getPrototypeOf(mod);", + "import * as mod from 'mod'; Reflect.set(obj, key, mod);", + "import * as mod from 'mod'; { var Object; Object.assign(mod, obj); }", + "import * as mod from 'mod'; var Object; Object.assign(mod, obj);", + "import * as mod from 'mod'; Object.seal(mod, obj)", + "import * as mod from 'mod'; Object.preventExtensions(mod)", + "import * as mod from 'mod'; Reflect.preventExtensions(mod)" + ], + invalid: [ + { + code: "import mod1 from 'mod'; mod1 = 0", + errors: [{ messageId: "readonly", data: { name: "mod1" }, column: 25 }] + }, + { + code: "import mod2 from 'mod'; mod2 += 0", + errors: [{ messageId: "readonly", data: { name: "mod2" }, column: 25 }] + }, + { + code: "import mod3 from 'mod'; mod3++", + errors: [{ messageId: "readonly", data: { name: "mod3" }, column: 25 }] + }, + { + code: "import mod4 from 'mod'; for (mod4 in foo);", + errors: [{ messageId: "readonly", data: { name: "mod4" }, column: 25 }] + }, + { + code: "import mod5 from 'mod'; for (mod5 of foo);", + errors: [{ messageId: "readonly", data: { name: "mod5" }, column: 25 }] + }, + { + code: "import mod6 from 'mod'; [mod6] = foo", + errors: [{ messageId: "readonly", data: { name: "mod6" }, column: 25 }] + }, + { + code: "import mod7 from 'mod'; [mod7 = 0] = foo", + errors: [{ messageId: "readonly", data: { name: "mod7" }, column: 25 }] + }, + { + code: "import mod8 from 'mod'; [...mod8] = foo", + errors: [{ messageId: "readonly", data: { name: "mod8" }, column: 25 }] + }, + { + code: "import mod9 from 'mod'; ({ bar: mod9 } = foo)", + errors: [{ messageId: "readonly", data: { name: "mod9" }, column: 26 }] + }, + { + code: "import mod10 from 'mod'; ({ bar: mod10 = 0 } = foo)", + errors: [{ messageId: "readonly", data: { name: "mod10" }, column: 27 }] + }, + { + code: "import mod11 from 'mod'; ({ ...mod11 } = foo)", + errors: [{ messageId: "readonly", data: { name: "mod11" }, column: 27 }] + }, + { + code: "import {named1} from 'mod'; named1 = 0", + errors: [{ messageId: "readonly", data: { name: "named1" }, column: 29 }] + }, + { + code: "import {named2} from 'mod'; named2 += 0", + errors: [{ messageId: "readonly", data: { name: "named2" }, column: 29 }] + }, + { + code: "import {named3} from 'mod'; named3++", + errors: [{ messageId: "readonly", data: { name: "named3" }, column: 29 }] + }, + { + code: "import {named4} from 'mod'; for (named4 in foo);", + errors: [{ messageId: "readonly", data: { name: "named4" }, column: 29 }] + }, + { + code: "import {named5} from 'mod'; for (named5 of foo);", + errors: [{ messageId: "readonly", data: { name: "named5" }, column: 29 }] + }, + { + code: "import {named6} from 'mod'; [named6] = foo", + errors: [{ messageId: "readonly", data: { name: "named6" }, column: 29 }] + }, + { + code: "import {named7} from 'mod'; [named7 = 0] = foo", + errors: [{ messageId: "readonly", data: { name: "named7" }, column: 29 }] + }, + { + code: "import {named8} from 'mod'; [...named8] = foo", + errors: [{ messageId: "readonly", data: { name: "named8" }, column: 29 }] + }, + { + code: "import {named9} from 'mod'; ({ bar: named9 } = foo)", + errors: [{ messageId: "readonly", data: { name: "named9" }, column: 30 }] + }, + { + code: "import {named10} from 'mod'; ({ bar: named10 = 0 } = foo)", + errors: [{ messageId: "readonly", data: { name: "named10" }, column: 31 }] + }, + { + code: "import {named11} from 'mod'; ({ ...named11 } = foo)", + errors: [{ messageId: "readonly", data: { name: "named11" }, column: 31 }] + }, + { + code: "import {named12 as foo} from 'mod'; foo = 0; named12 = 0", + errors: [{ messageId: "readonly", data: { name: "foo" }, column: 37 }] + }, + { + code: "import * as mod1 from 'mod'; mod1 = 0", + errors: [{ messageId: "readonly", data: { name: "mod1" }, column: 30 }] + }, + { + code: "import * as mod2 from 'mod'; mod2 += 0", + errors: [{ messageId: "readonly", data: { name: "mod2" }, column: 30 }] + }, + { + code: "import * as mod3 from 'mod'; mod3++", + errors: [{ messageId: "readonly", data: { name: "mod3" }, column: 30 }] + }, + { + code: "import * as mod4 from 'mod'; for (mod4 in foo);", + errors: [{ messageId: "readonly", data: { name: "mod4" }, column: 30 }] + }, + { + code: "import * as mod5 from 'mod'; for (mod5 of foo);", + errors: [{ messageId: "readonly", data: { name: "mod5" }, column: 30 }] + }, + { + code: "import * as mod6 from 'mod'; [mod6] = foo", + errors: [{ messageId: "readonly", data: { name: "mod6" }, column: 30 }] + }, + { + code: "import * as mod7 from 'mod'; [mod7 = 0] = foo", + errors: [{ messageId: "readonly", data: { name: "mod7" }, column: 30 }] + }, + { + code: "import * as mod8 from 'mod'; [...mod8] = foo", + errors: [{ messageId: "readonly", data: { name: "mod8" }, column: 30 }] + }, + { + code: "import * as mod9 from 'mod'; ({ bar: mod9 } = foo)", + errors: [{ messageId: "readonly", data: { name: "mod9" }, column: 31 }] + }, + { + code: "import * as mod10 from 'mod'; ({ bar: mod10 = 0 } = foo)", + errors: [{ messageId: "readonly", data: { name: "mod10" }, column: 32 }] + }, + { + code: "import * as mod11 from 'mod'; ({ ...mod11 } = foo)", + errors: [{ messageId: "readonly", data: { name: "mod11" }, column: 32 }] + }, + { + code: "import * as mod1 from 'mod'; mod1.named = 0", + errors: [{ messageId: "readonlyMember", data: { name: "mod1" }, column: 30 }] + }, + { + code: "import * as mod2 from 'mod'; mod2.named += 0", + errors: [{ messageId: "readonlyMember", data: { name: "mod2" }, column: 30 }] + }, + { + code: "import * as mod3 from 'mod'; mod3.named++", + errors: [{ messageId: "readonlyMember", data: { name: "mod3" }, column: 30 }] + }, + { + code: "import * as mod4 from 'mod'; for (mod4.named in foo);", + errors: [{ messageId: "readonlyMember", data: { name: "mod4" }, column: 30 }] + }, + { + code: "import * as mod5 from 'mod'; for (mod5.named of foo);", + errors: [{ messageId: "readonlyMember", data: { name: "mod5" }, column: 30 }] + }, + { + code: "import * as mod6 from 'mod'; [mod6.named] = foo", + errors: [{ messageId: "readonlyMember", data: { name: "mod6" }, column: 30 }] + }, + { + code: "import * as mod7 from 'mod'; [mod7.named = 0] = foo", + errors: [{ messageId: "readonlyMember", data: { name: "mod7" }, column: 30 }] + }, + { + code: "import * as mod8 from 'mod'; [...mod8.named] = foo", + errors: [{ messageId: "readonlyMember", data: { name: "mod8" }, column: 30 }] + }, + { + code: "import * as mod9 from 'mod'; ({ bar: mod9.named } = foo)", + errors: [{ messageId: "readonlyMember", data: { name: "mod9" }, column: 31 }] + }, + { + code: "import * as mod10 from 'mod'; ({ bar: mod10.named = 0 } = foo)", + errors: [{ messageId: "readonlyMember", data: { name: "mod10" }, column: 32 }] + }, + { + code: "import * as mod11 from 'mod'; ({ ...mod11.named } = foo)", + errors: [{ messageId: "readonlyMember", data: { name: "mod11" }, column: 32 }] + }, + { + code: "import * as mod12 from 'mod'; delete mod12.named", + errors: [{ messageId: "readonlyMember", data: { name: "mod12" }, column: 31 }] + }, + { + code: "import * as mod from 'mod'; Object.assign(mod, obj)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import * as mod from 'mod'; Object.defineProperty(mod, key, d)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import * as mod from 'mod'; Object.defineProperties(mod, d)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import * as mod from 'mod'; Object.setPrototypeOf(mod, proto)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import * as mod from 'mod'; Object.freeze(mod)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import * as mod from 'mod'; Reflect.defineProperty(mod, key, d)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import * as mod from 'mod'; Reflect.deleteProperty(mod, key)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import * as mod from 'mod'; Reflect.set(mod, key, value)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import * as mod from 'mod'; Reflect.setPrototypeOf(mod, proto)", + errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }] + }, + { + code: "import mod, * as mod_ns from 'mod'; mod.prop = 0; mod_ns.prop = 0", + errors: [{ messageId: "readonlyMember", data: { name: "mod_ns" }, column: 51 }] + } + ] +}); diff --git a/tools/rule-types.json b/tools/rule-types.json index ea15a2cfd4c..6c72abb6cb2 100644 --- a/tools/rule-types.json +++ b/tools/rule-types.json @@ -119,6 +119,7 @@ "no-implicit-coercion": "suggestion", "no-implicit-globals": "suggestion", "no-implied-eval": "suggestion", + "no-import-assign": "problem", "no-inline-comments": "suggestion", "no-inner-declarations": "problem", "no-invalid-regexp": "problem", From 365331a42e22af5a77ac9cfa9673d6a8f653eb5a Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 13 Sep 2019 17:31:41 -0700 Subject: [PATCH 13/26] Fix: object-shorthand providing invalid fixes for typescript (#12260) * Fix: object-shorthand providing invalid fixes for typescript * Chore: refactor to not rely on async modifier check * Chore: ensure return type isn't wiped for no arguments * Chore: add ts code test to prevent regressions --- lib/rules/object-shorthand.js | 44 +- .../object-with-arrow-fn-props.js | 8935 +++++++++++++++++ tests/lib/rules/object-shorthand.js | 92 + 3 files changed, 9062 insertions(+), 9 deletions(-) create mode 100644 tests/fixtures/parsers/typescript-parsers/object-with-arrow-fn-props.js diff --git a/lib/rules/object-shorthand.js b/lib/rules/object-shorthand.js index bff7c717a0d..df302b5e872 100644 --- a/lib/rules/object-shorthand.js +++ b/lib/rules/object-shorthand.js @@ -244,6 +244,7 @@ module.exports = { const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]); let keyPrefix = ""; + // key: /* */ () => {} if (sourceCode.commentsExistBetween(lastKeyToken, node.value)) { return null; } @@ -255,24 +256,49 @@ module.exports = { keyPrefix += "*"; } + const fixRange = [firstKeyToken.range[0], node.range[1]]; + const methodPrefix = keyPrefix + keyText; + if (node.value.type === "FunctionExpression") { const functionToken = sourceCode.getTokens(node.value).find(token => token.type === "Keyword" && token.value === "function"); const tokenBeforeParams = node.value.generator ? sourceCode.getTokenAfter(functionToken) : functionToken; return fixer.replaceTextRange( - [firstKeyToken.range[0], node.range[1]], - keyPrefix + keyText + sourceCode.text.slice(tokenBeforeParams.range[1], node.value.range[1]) + fixRange, + methodPrefix + sourceCode.text.slice(tokenBeforeParams.range[1], node.value.range[1]) ); } - const arrowToken = sourceCode.getTokenBefore(node.value.body, { filter: token => token.value === "=>" }); - const tokenBeforeArrow = sourceCode.getTokenBefore(arrowToken); - const hasParensAroundParameters = tokenBeforeArrow.type === "Punctuator" && tokenBeforeArrow.value === ")"; - const oldParamText = sourceCode.text.slice(sourceCode.getFirstToken(node.value, node.value.async ? 1 : 0).range[0], tokenBeforeArrow.range[1]); - const newParamText = hasParensAroundParameters ? oldParamText : `(${oldParamText})`; + + const arrowToken = sourceCode.getTokenBefore(node.value.body, astUtils.isArrowToken); + const fnBody = sourceCode.text.slice(arrowToken.range[1], node.value.range[1]); + + let shouldAddParensAroundParameters = false; + let tokenBeforeParams; + + if (node.value.params.length === 0) { + tokenBeforeParams = sourceCode.getFirstToken(node.value, astUtils.isOpeningParenToken); + } else { + tokenBeforeParams = sourceCode.getTokenBefore(node.value.params[0]); + } + + if (node.value.params.length === 1) { + const hasParen = astUtils.isOpeningParenToken(tokenBeforeParams); + const isTokenOutsideNode = tokenBeforeParams.range[0] < node.range[0]; + + shouldAddParensAroundParameters = !hasParen || isTokenOutsideNode; + } + + const sliceStart = shouldAddParensAroundParameters + ? node.value.params[0].range[0] + : tokenBeforeParams.range[0]; + const sliceEnd = sourceCode.getTokenBefore(arrowToken).range[1]; + + const oldParamText = sourceCode.text.slice(sliceStart, sliceEnd); + const newParamText = shouldAddParensAroundParameters ? `(${oldParamText})` : oldParamText; return fixer.replaceTextRange( - [firstKeyToken.range[0], node.range[1]], - keyPrefix + keyText + newParamText + sourceCode.text.slice(arrowToken.range[1], node.value.range[1]) + fixRange, + methodPrefix + newParamText + fnBody ); } diff --git a/tests/fixtures/parsers/typescript-parsers/object-with-arrow-fn-props.js b/tests/fixtures/parsers/typescript-parsers/object-with-arrow-fn-props.js new file mode 100644 index 00000000000..9177aa46717 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/object-with-arrow-fn-props.js @@ -0,0 +1,8935 @@ +'use strict'; + +/* + * Parsed on astexplorer.net using @typescript-eslint/parser@1.13.0 + * + * Source: +const test = { + key: (): void => {x()}, + key: ( (): void => {x()} ), + key: ( (): (void) => {x()} ), + + key: (arg: t): void => {x()}, + key: ( (arg: t): void => {x()} ), + key: ( (arg: t): (void) => {x()} ), + + key: (arg: t, arg2: t): void => {x()}, + key: ( (arg: t, arg2: t): void => {x()} ), + key: ( (arg: t, arg2: t): (void) => {x()} ), + + key: async (): void => {x()}, + key: ( async (): void => {x()} ), + key: ( async (): (void) => {x()} ), + + key: async (arg: t): void => {x()}, + key: ( async (arg: t): void => {x()} ), + key: ( async (arg: t): (void) => {x()} ), + + key: async (arg: t, arg2: t): void => {x()}, + key: ( async (arg: t, arg2: t): void => {x()} ), + key: ( async (arg: t, arg2: t): (void) => {x()} ), +} + */ + +exports.parse = () => ({ + type: 'Program', + body: [ + { + type: 'VariableDeclaration', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'test', + range: [6, 10], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + init: { + type: 'ObjectExpression', + properties: [ + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [19, 22], + loc: { + start: { + line: 2, + column: 4, + }, + end: { + line: 2, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [37, 38], + loc: { + start: { + line: 2, + column: 22, + }, + end: { + line: 2, + column: 23, + }, + }, + }, + arguments: [], + range: [37, 40], + loc: { + start: { + line: 2, + column: 22, + }, + end: { + line: 2, + column: 25, + }, + }, + }, + range: [37, 40], + loc: { + start: { + line: 2, + column: 22, + }, + end: { + line: 2, + column: 25, + }, + }, + }, + ], + range: [36, 41], + loc: { + start: { + line: 2, + column: 21, + }, + end: { + line: 2, + column: 26, + }, + }, + }, + async: false, + expression: false, + range: [24, 41], + loc: { + start: { + line: 2, + column: 9, + }, + end: { + line: 2, + column: 26, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 2, + column: 11, + }, + end: { + line: 2, + column: 17, + }, + }, + range: [26, 32], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [28, 32], + loc: { + start: { + line: 2, + column: 13, + }, + end: { + line: 2, + column: 17, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [19, 41], + loc: { + start: { + line: 2, + column: 4, + }, + end: { + line: 2, + column: 26, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [47, 50], + loc: { + start: { + line: 3, + column: 4, + }, + end: { + line: 3, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [67, 68], + loc: { + start: { + line: 3, + column: 24, + }, + end: { + line: 3, + column: 25, + }, + }, + }, + arguments: [], + range: [67, 70], + loc: { + start: { + line: 3, + column: 24, + }, + end: { + line: 3, + column: 27, + }, + }, + }, + range: [67, 70], + loc: { + start: { + line: 3, + column: 24, + }, + end: { + line: 3, + column: 27, + }, + }, + }, + ], + range: [66, 71], + loc: { + start: { + line: 3, + column: 23, + }, + end: { + line: 3, + column: 28, + }, + }, + }, + async: false, + expression: false, + range: [54, 71], + loc: { + start: { + line: 3, + column: 11, + }, + end: { + line: 3, + column: 28, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 3, + column: 13, + }, + end: { + line: 3, + column: 19, + }, + }, + range: [56, 62], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [58, 62], + loc: { + start: { + line: 3, + column: 15, + }, + end: { + line: 3, + column: 19, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [47, 73], + loc: { + start: { + line: 3, + column: 4, + }, + end: { + line: 3, + column: 30, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [79, 82], + loc: { + start: { + line: 4, + column: 4, + }, + end: { + line: 4, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [101, 102], + loc: { + start: { + line: 4, + column: 26, + }, + end: { + line: 4, + column: 27, + }, + }, + }, + arguments: [], + range: [101, 104], + loc: { + start: { + line: 4, + column: 26, + }, + end: { + line: 4, + column: 29, + }, + }, + }, + range: [101, 104], + loc: { + start: { + line: 4, + column: 26, + }, + end: { + line: 4, + column: 29, + }, + }, + }, + ], + range: [100, 105], + loc: { + start: { + line: 4, + column: 25, + }, + end: { + line: 4, + column: 30, + }, + }, + }, + async: false, + expression: false, + range: [86, 105], + loc: { + start: { + line: 4, + column: 11, + }, + end: { + line: 4, + column: 30, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 4, + column: 13, + }, + end: { + line: 4, + column: 21, + }, + }, + range: [88, 96], + typeAnnotation: { + type: 'TSParenthesizedType', + typeAnnotation: { + type: 'TSVoidKeyword', + range: [91, 95], + loc: { + start: { + line: 4, + column: 16, + }, + end: { + line: 4, + column: 20, + }, + }, + }, + range: [90, 96], + loc: { + start: { + line: 4, + column: 15, + }, + end: { + line: 4, + column: 21, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [79, 107], + loc: { + start: { + line: 4, + column: 4, + }, + end: { + line: 4, + column: 32, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [114, 117], + loc: { + start: { + line: 6, + column: 4, + }, + end: { + line: 6, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [120, 126], + loc: { + start: { + line: 6, + column: 10, + }, + end: { + line: 6, + column: 16, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 6, + column: 13, + }, + end: { + line: 6, + column: 16, + }, + }, + range: [123, 126], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [125, 126], + loc: { + start: { + line: 6, + column: 15, + }, + end: { + line: 6, + column: 16, + }, + }, + }, + range: [125, 126], + loc: { + start: { + line: 6, + column: 15, + }, + end: { + line: 6, + column: 16, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [138, 139], + loc: { + start: { + line: 6, + column: 28, + }, + end: { + line: 6, + column: 29, + }, + }, + }, + arguments: [], + range: [138, 141], + loc: { + start: { + line: 6, + column: 28, + }, + end: { + line: 6, + column: 31, + }, + }, + }, + range: [138, 141], + loc: { + start: { + line: 6, + column: 28, + }, + end: { + line: 6, + column: 31, + }, + }, + }, + ], + range: [137, 142], + loc: { + start: { + line: 6, + column: 27, + }, + end: { + line: 6, + column: 32, + }, + }, + }, + async: false, + expression: false, + range: [119, 142], + loc: { + start: { + line: 6, + column: 9, + }, + end: { + line: 6, + column: 32, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 6, + column: 17, + }, + end: { + line: 6, + column: 23, + }, + }, + range: [127, 133], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [129, 133], + loc: { + start: { + line: 6, + column: 19, + }, + end: { + line: 6, + column: 23, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [114, 142], + loc: { + start: { + line: 6, + column: 4, + }, + end: { + line: 6, + column: 32, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [148, 151], + loc: { + start: { + line: 7, + column: 4, + }, + end: { + line: 7, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [156, 162], + loc: { + start: { + line: 7, + column: 12, + }, + end: { + line: 7, + column: 18, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 7, + column: 15, + }, + end: { + line: 7, + column: 18, + }, + }, + range: [159, 162], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [161, 162], + loc: { + start: { + line: 7, + column: 17, + }, + end: { + line: 7, + column: 18, + }, + }, + }, + range: [161, 162], + loc: { + start: { + line: 7, + column: 17, + }, + end: { + line: 7, + column: 18, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [174, 175], + loc: { + start: { + line: 7, + column: 30, + }, + end: { + line: 7, + column: 31, + }, + }, + }, + arguments: [], + range: [174, 177], + loc: { + start: { + line: 7, + column: 30, + }, + end: { + line: 7, + column: 33, + }, + }, + }, + range: [174, 177], + loc: { + start: { + line: 7, + column: 30, + }, + end: { + line: 7, + column: 33, + }, + }, + }, + ], + range: [173, 178], + loc: { + start: { + line: 7, + column: 29, + }, + end: { + line: 7, + column: 34, + }, + }, + }, + async: false, + expression: false, + range: [155, 178], + loc: { + start: { + line: 7, + column: 11, + }, + end: { + line: 7, + column: 34, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 7, + column: 19, + }, + end: { + line: 7, + column: 25, + }, + }, + range: [163, 169], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [165, 169], + loc: { + start: { + line: 7, + column: 21, + }, + end: { + line: 7, + column: 25, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [148, 180], + loc: { + start: { + line: 7, + column: 4, + }, + end: { + line: 7, + column: 36, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [186, 189], + loc: { + start: { + line: 8, + column: 4, + }, + end: { + line: 8, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [194, 200], + loc: { + start: { + line: 8, + column: 12, + }, + end: { + line: 8, + column: 18, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 8, + column: 15, + }, + end: { + line: 8, + column: 18, + }, + }, + range: [197, 200], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [199, 200], + loc: { + start: { + line: 8, + column: 17, + }, + end: { + line: 8, + column: 18, + }, + }, + }, + range: [199, 200], + loc: { + start: { + line: 8, + column: 17, + }, + end: { + line: 8, + column: 18, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [214, 215], + loc: { + start: { + line: 8, + column: 32, + }, + end: { + line: 8, + column: 33, + }, + }, + }, + arguments: [], + range: [214, 217], + loc: { + start: { + line: 8, + column: 32, + }, + end: { + line: 8, + column: 35, + }, + }, + }, + range: [214, 217], + loc: { + start: { + line: 8, + column: 32, + }, + end: { + line: 8, + column: 35, + }, + }, + }, + ], + range: [213, 218], + loc: { + start: { + line: 8, + column: 31, + }, + end: { + line: 8, + column: 36, + }, + }, + }, + async: false, + expression: false, + range: [193, 218], + loc: { + start: { + line: 8, + column: 11, + }, + end: { + line: 8, + column: 36, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 8, + column: 19, + }, + end: { + line: 8, + column: 27, + }, + }, + range: [201, 209], + typeAnnotation: { + type: 'TSParenthesizedType', + typeAnnotation: { + type: 'TSVoidKeyword', + range: [204, 208], + loc: { + start: { + line: 8, + column: 22, + }, + end: { + line: 8, + column: 26, + }, + }, + }, + range: [203, 209], + loc: { + start: { + line: 8, + column: 21, + }, + end: { + line: 8, + column: 27, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [186, 220], + loc: { + start: { + line: 8, + column: 4, + }, + end: { + line: 8, + column: 38, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [227, 230], + loc: { + start: { + line: 10, + column: 4, + }, + end: { + line: 10, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [233, 239], + loc: { + start: { + line: 10, + column: 10, + }, + end: { + line: 10, + column: 16, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 10, + column: 13, + }, + end: { + line: 10, + column: 16, + }, + }, + range: [236, 239], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [238, 239], + loc: { + start: { + line: 10, + column: 15, + }, + end: { + line: 10, + column: 16, + }, + }, + }, + range: [238, 239], + loc: { + start: { + line: 10, + column: 15, + }, + end: { + line: 10, + column: 16, + }, + }, + }, + }, + }, + { + type: 'Identifier', + name: 'arg2', + range: [241, 248], + loc: { + start: { + line: 10, + column: 18, + }, + end: { + line: 10, + column: 25, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 10, + column: 22, + }, + end: { + line: 10, + column: 25, + }, + }, + range: [245, 248], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [247, 248], + loc: { + start: { + line: 10, + column: 24, + }, + end: { + line: 10, + column: 25, + }, + }, + }, + range: [247, 248], + loc: { + start: { + line: 10, + column: 24, + }, + end: { + line: 10, + column: 25, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [260, 261], + loc: { + start: { + line: 10, + column: 37, + }, + end: { + line: 10, + column: 38, + }, + }, + }, + arguments: [], + range: [260, 263], + loc: { + start: { + line: 10, + column: 37, + }, + end: { + line: 10, + column: 40, + }, + }, + }, + range: [260, 263], + loc: { + start: { + line: 10, + column: 37, + }, + end: { + line: 10, + column: 40, + }, + }, + }, + ], + range: [259, 264], + loc: { + start: { + line: 10, + column: 36, + }, + end: { + line: 10, + column: 41, + }, + }, + }, + async: false, + expression: false, + range: [232, 264], + loc: { + start: { + line: 10, + column: 9, + }, + end: { + line: 10, + column: 41, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 10, + column: 26, + }, + end: { + line: 10, + column: 32, + }, + }, + range: [249, 255], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [251, 255], + loc: { + start: { + line: 10, + column: 28, + }, + end: { + line: 10, + column: 32, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [227, 264], + loc: { + start: { + line: 10, + column: 4, + }, + end: { + line: 10, + column: 41, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [270, 273], + loc: { + start: { + line: 11, + column: 4, + }, + end: { + line: 11, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [278, 284], + loc: { + start: { + line: 11, + column: 12, + }, + end: { + line: 11, + column: 18, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 11, + column: 15, + }, + end: { + line: 11, + column: 18, + }, + }, + range: [281, 284], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [283, 284], + loc: { + start: { + line: 11, + column: 17, + }, + end: { + line: 11, + column: 18, + }, + }, + }, + range: [283, 284], + loc: { + start: { + line: 11, + column: 17, + }, + end: { + line: 11, + column: 18, + }, + }, + }, + }, + }, + { + type: 'Identifier', + name: 'arg2', + range: [286, 293], + loc: { + start: { + line: 11, + column: 20, + }, + end: { + line: 11, + column: 27, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 11, + column: 24, + }, + end: { + line: 11, + column: 27, + }, + }, + range: [290, 293], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [292, 293], + loc: { + start: { + line: 11, + column: 26, + }, + end: { + line: 11, + column: 27, + }, + }, + }, + range: [292, 293], + loc: { + start: { + line: 11, + column: 26, + }, + end: { + line: 11, + column: 27, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [305, 306], + loc: { + start: { + line: 11, + column: 39, + }, + end: { + line: 11, + column: 40, + }, + }, + }, + arguments: [], + range: [305, 308], + loc: { + start: { + line: 11, + column: 39, + }, + end: { + line: 11, + column: 42, + }, + }, + }, + range: [305, 308], + loc: { + start: { + line: 11, + column: 39, + }, + end: { + line: 11, + column: 42, + }, + }, + }, + ], + range: [304, 309], + loc: { + start: { + line: 11, + column: 38, + }, + end: { + line: 11, + column: 43, + }, + }, + }, + async: false, + expression: false, + range: [277, 309], + loc: { + start: { + line: 11, + column: 11, + }, + end: { + line: 11, + column: 43, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 11, + column: 28, + }, + end: { + line: 11, + column: 34, + }, + }, + range: [294, 300], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [296, 300], + loc: { + start: { + line: 11, + column: 30, + }, + end: { + line: 11, + column: 34, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [270, 311], + loc: { + start: { + line: 11, + column: 4, + }, + end: { + line: 11, + column: 45, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [317, 320], + loc: { + start: { + line: 12, + column: 4, + }, + end: { + line: 12, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [325, 331], + loc: { + start: { + line: 12, + column: 12, + }, + end: { + line: 12, + column: 18, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 12, + column: 15, + }, + end: { + line: 12, + column: 18, + }, + }, + range: [328, 331], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [330, 331], + loc: { + start: { + line: 12, + column: 17, + }, + end: { + line: 12, + column: 18, + }, + }, + }, + range: [330, 331], + loc: { + start: { + line: 12, + column: 17, + }, + end: { + line: 12, + column: 18, + }, + }, + }, + }, + }, + { + type: 'Identifier', + name: 'arg2', + range: [333, 340], + loc: { + start: { + line: 12, + column: 20, + }, + end: { + line: 12, + column: 27, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 12, + column: 24, + }, + end: { + line: 12, + column: 27, + }, + }, + range: [337, 340], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [339, 340], + loc: { + start: { + line: 12, + column: 26, + }, + end: { + line: 12, + column: 27, + }, + }, + }, + range: [339, 340], + loc: { + start: { + line: 12, + column: 26, + }, + end: { + line: 12, + column: 27, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [354, 355], + loc: { + start: { + line: 12, + column: 41, + }, + end: { + line: 12, + column: 42, + }, + }, + }, + arguments: [], + range: [354, 357], + loc: { + start: { + line: 12, + column: 41, + }, + end: { + line: 12, + column: 44, + }, + }, + }, + range: [354, 357], + loc: { + start: { + line: 12, + column: 41, + }, + end: { + line: 12, + column: 44, + }, + }, + }, + ], + range: [353, 358], + loc: { + start: { + line: 12, + column: 40, + }, + end: { + line: 12, + column: 45, + }, + }, + }, + async: false, + expression: false, + range: [324, 358], + loc: { + start: { + line: 12, + column: 11, + }, + end: { + line: 12, + column: 45, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 12, + column: 28, + }, + end: { + line: 12, + column: 36, + }, + }, + range: [341, 349], + typeAnnotation: { + type: 'TSParenthesizedType', + typeAnnotation: { + type: 'TSVoidKeyword', + range: [344, 348], + loc: { + start: { + line: 12, + column: 31, + }, + end: { + line: 12, + column: 35, + }, + }, + }, + range: [343, 349], + loc: { + start: { + line: 12, + column: 30, + }, + end: { + line: 12, + column: 36, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [317, 360], + loc: { + start: { + line: 12, + column: 4, + }, + end: { + line: 12, + column: 47, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [367, 370], + loc: { + start: { + line: 14, + column: 4, + }, + end: { + line: 14, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [391, 392], + loc: { + start: { + line: 14, + column: 28, + }, + end: { + line: 14, + column: 29, + }, + }, + }, + arguments: [], + range: [391, 394], + loc: { + start: { + line: 14, + column: 28, + }, + end: { + line: 14, + column: 31, + }, + }, + }, + range: [391, 394], + loc: { + start: { + line: 14, + column: 28, + }, + end: { + line: 14, + column: 31, + }, + }, + }, + ], + range: [390, 395], + loc: { + start: { + line: 14, + column: 27, + }, + end: { + line: 14, + column: 32, + }, + }, + }, + async: true, + expression: false, + range: [372, 395], + loc: { + start: { + line: 14, + column: 9, + }, + end: { + line: 14, + column: 32, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 14, + column: 17, + }, + end: { + line: 14, + column: 23, + }, + }, + range: [380, 386], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [382, 386], + loc: { + start: { + line: 14, + column: 19, + }, + end: { + line: 14, + column: 23, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [367, 395], + loc: { + start: { + line: 14, + column: 4, + }, + end: { + line: 14, + column: 32, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [401, 404], + loc: { + start: { + line: 15, + column: 4, + }, + end: { + line: 15, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [427, 428], + loc: { + start: { + line: 15, + column: 30, + }, + end: { + line: 15, + column: 31, + }, + }, + }, + arguments: [], + range: [427, 430], + loc: { + start: { + line: 15, + column: 30, + }, + end: { + line: 15, + column: 33, + }, + }, + }, + range: [427, 430], + loc: { + start: { + line: 15, + column: 30, + }, + end: { + line: 15, + column: 33, + }, + }, + }, + ], + range: [426, 431], + loc: { + start: { + line: 15, + column: 29, + }, + end: { + line: 15, + column: 34, + }, + }, + }, + async: true, + expression: false, + range: [408, 431], + loc: { + start: { + line: 15, + column: 11, + }, + end: { + line: 15, + column: 34, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 15, + column: 19, + }, + end: { + line: 15, + column: 25, + }, + }, + range: [416, 422], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [418, 422], + loc: { + start: { + line: 15, + column: 21, + }, + end: { + line: 15, + column: 25, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [401, 433], + loc: { + start: { + line: 15, + column: 4, + }, + end: { + line: 15, + column: 36, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [439, 442], + loc: { + start: { + line: 16, + column: 4, + }, + end: { + line: 16, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [467, 468], + loc: { + start: { + line: 16, + column: 32, + }, + end: { + line: 16, + column: 33, + }, + }, + }, + arguments: [], + range: [467, 470], + loc: { + start: { + line: 16, + column: 32, + }, + end: { + line: 16, + column: 35, + }, + }, + }, + range: [467, 470], + loc: { + start: { + line: 16, + column: 32, + }, + end: { + line: 16, + column: 35, + }, + }, + }, + ], + range: [466, 471], + loc: { + start: { + line: 16, + column: 31, + }, + end: { + line: 16, + column: 36, + }, + }, + }, + async: true, + expression: false, + range: [446, 471], + loc: { + start: { + line: 16, + column: 11, + }, + end: { + line: 16, + column: 36, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 16, + column: 19, + }, + end: { + line: 16, + column: 27, + }, + }, + range: [454, 462], + typeAnnotation: { + type: 'TSParenthesizedType', + typeAnnotation: { + type: 'TSVoidKeyword', + range: [457, 461], + loc: { + start: { + line: 16, + column: 22, + }, + end: { + line: 16, + column: 26, + }, + }, + }, + range: [456, 462], + loc: { + start: { + line: 16, + column: 21, + }, + end: { + line: 16, + column: 27, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [439, 473], + loc: { + start: { + line: 16, + column: 4, + }, + end: { + line: 16, + column: 38, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [480, 483], + loc: { + start: { + line: 18, + column: 4, + }, + end: { + line: 18, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [492, 498], + loc: { + start: { + line: 18, + column: 16, + }, + end: { + line: 18, + column: 22, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 18, + column: 19, + }, + end: { + line: 18, + column: 22, + }, + }, + range: [495, 498], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [497, 498], + loc: { + start: { + line: 18, + column: 21, + }, + end: { + line: 18, + column: 22, + }, + }, + }, + range: [497, 498], + loc: { + start: { + line: 18, + column: 21, + }, + end: { + line: 18, + column: 22, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [510, 511], + loc: { + start: { + line: 18, + column: 34, + }, + end: { + line: 18, + column: 35, + }, + }, + }, + arguments: [], + range: [510, 513], + loc: { + start: { + line: 18, + column: 34, + }, + end: { + line: 18, + column: 37, + }, + }, + }, + range: [510, 513], + loc: { + start: { + line: 18, + column: 34, + }, + end: { + line: 18, + column: 37, + }, + }, + }, + ], + range: [509, 514], + loc: { + start: { + line: 18, + column: 33, + }, + end: { + line: 18, + column: 38, + }, + }, + }, + async: true, + expression: false, + range: [485, 514], + loc: { + start: { + line: 18, + column: 9, + }, + end: { + line: 18, + column: 38, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 18, + column: 23, + }, + end: { + line: 18, + column: 29, + }, + }, + range: [499, 505], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [501, 505], + loc: { + start: { + line: 18, + column: 25, + }, + end: { + line: 18, + column: 29, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [480, 514], + loc: { + start: { + line: 18, + column: 4, + }, + end: { + line: 18, + column: 38, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [520, 523], + loc: { + start: { + line: 19, + column: 4, + }, + end: { + line: 19, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [534, 540], + loc: { + start: { + line: 19, + column: 18, + }, + end: { + line: 19, + column: 24, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 19, + column: 21, + }, + end: { + line: 19, + column: 24, + }, + }, + range: [537, 540], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [539, 540], + loc: { + start: { + line: 19, + column: 23, + }, + end: { + line: 19, + column: 24, + }, + }, + }, + range: [539, 540], + loc: { + start: { + line: 19, + column: 23, + }, + end: { + line: 19, + column: 24, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [552, 553], + loc: { + start: { + line: 19, + column: 36, + }, + end: { + line: 19, + column: 37, + }, + }, + }, + arguments: [], + range: [552, 555], + loc: { + start: { + line: 19, + column: 36, + }, + end: { + line: 19, + column: 39, + }, + }, + }, + range: [552, 555], + loc: { + start: { + line: 19, + column: 36, + }, + end: { + line: 19, + column: 39, + }, + }, + }, + ], + range: [551, 556], + loc: { + start: { + line: 19, + column: 35, + }, + end: { + line: 19, + column: 40, + }, + }, + }, + async: true, + expression: false, + range: [527, 556], + loc: { + start: { + line: 19, + column: 11, + }, + end: { + line: 19, + column: 40, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 19, + column: 25, + }, + end: { + line: 19, + column: 31, + }, + }, + range: [541, 547], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [543, 547], + loc: { + start: { + line: 19, + column: 27, + }, + end: { + line: 19, + column: 31, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [520, 558], + loc: { + start: { + line: 19, + column: 4, + }, + end: { + line: 19, + column: 42, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [564, 567], + loc: { + start: { + line: 20, + column: 4, + }, + end: { + line: 20, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [578, 584], + loc: { + start: { + line: 20, + column: 18, + }, + end: { + line: 20, + column: 24, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 20, + column: 21, + }, + end: { + line: 20, + column: 24, + }, + }, + range: [581, 584], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [583, 584], + loc: { + start: { + line: 20, + column: 23, + }, + end: { + line: 20, + column: 24, + }, + }, + }, + range: [583, 584], + loc: { + start: { + line: 20, + column: 23, + }, + end: { + line: 20, + column: 24, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [598, 599], + loc: { + start: { + line: 20, + column: 38, + }, + end: { + line: 20, + column: 39, + }, + }, + }, + arguments: [], + range: [598, 601], + loc: { + start: { + line: 20, + column: 38, + }, + end: { + line: 20, + column: 41, + }, + }, + }, + range: [598, 601], + loc: { + start: { + line: 20, + column: 38, + }, + end: { + line: 20, + column: 41, + }, + }, + }, + ], + range: [597, 602], + loc: { + start: { + line: 20, + column: 37, + }, + end: { + line: 20, + column: 42, + }, + }, + }, + async: true, + expression: false, + range: [571, 602], + loc: { + start: { + line: 20, + column: 11, + }, + end: { + line: 20, + column: 42, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 20, + column: 25, + }, + end: { + line: 20, + column: 33, + }, + }, + range: [585, 593], + typeAnnotation: { + type: 'TSParenthesizedType', + typeAnnotation: { + type: 'TSVoidKeyword', + range: [588, 592], + loc: { + start: { + line: 20, + column: 28, + }, + end: { + line: 20, + column: 32, + }, + }, + }, + range: [587, 593], + loc: { + start: { + line: 20, + column: 27, + }, + end: { + line: 20, + column: 33, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [564, 604], + loc: { + start: { + line: 20, + column: 4, + }, + end: { + line: 20, + column: 44, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [611, 614], + loc: { + start: { + line: 22, + column: 4, + }, + end: { + line: 22, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [623, 629], + loc: { + start: { + line: 22, + column: 16, + }, + end: { + line: 22, + column: 22, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 22, + column: 19, + }, + end: { + line: 22, + column: 22, + }, + }, + range: [626, 629], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [628, 629], + loc: { + start: { + line: 22, + column: 21, + }, + end: { + line: 22, + column: 22, + }, + }, + }, + range: [628, 629], + loc: { + start: { + line: 22, + column: 21, + }, + end: { + line: 22, + column: 22, + }, + }, + }, + }, + }, + { + type: 'Identifier', + name: 'arg2', + range: [631, 638], + loc: { + start: { + line: 22, + column: 24, + }, + end: { + line: 22, + column: 31, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 22, + column: 28, + }, + end: { + line: 22, + column: 31, + }, + }, + range: [635, 638], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [637, 638], + loc: { + start: { + line: 22, + column: 30, + }, + end: { + line: 22, + column: 31, + }, + }, + }, + range: [637, 638], + loc: { + start: { + line: 22, + column: 30, + }, + end: { + line: 22, + column: 31, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [650, 651], + loc: { + start: { + line: 22, + column: 43, + }, + end: { + line: 22, + column: 44, + }, + }, + }, + arguments: [], + range: [650, 653], + loc: { + start: { + line: 22, + column: 43, + }, + end: { + line: 22, + column: 46, + }, + }, + }, + range: [650, 653], + loc: { + start: { + line: 22, + column: 43, + }, + end: { + line: 22, + column: 46, + }, + }, + }, + ], + range: [649, 654], + loc: { + start: { + line: 22, + column: 42, + }, + end: { + line: 22, + column: 47, + }, + }, + }, + async: true, + expression: false, + range: [616, 654], + loc: { + start: { + line: 22, + column: 9, + }, + end: { + line: 22, + column: 47, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 22, + column: 32, + }, + end: { + line: 22, + column: 38, + }, + }, + range: [639, 645], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [641, 645], + loc: { + start: { + line: 22, + column: 34, + }, + end: { + line: 22, + column: 38, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [611, 654], + loc: { + start: { + line: 22, + column: 4, + }, + end: { + line: 22, + column: 47, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [660, 663], + loc: { + start: { + line: 23, + column: 4, + }, + end: { + line: 23, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [674, 680], + loc: { + start: { + line: 23, + column: 18, + }, + end: { + line: 23, + column: 24, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 23, + column: 21, + }, + end: { + line: 23, + column: 24, + }, + }, + range: [677, 680], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [679, 680], + loc: { + start: { + line: 23, + column: 23, + }, + end: { + line: 23, + column: 24, + }, + }, + }, + range: [679, 680], + loc: { + start: { + line: 23, + column: 23, + }, + end: { + line: 23, + column: 24, + }, + }, + }, + }, + }, + { + type: 'Identifier', + name: 'arg2', + range: [682, 689], + loc: { + start: { + line: 23, + column: 26, + }, + end: { + line: 23, + column: 33, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 23, + column: 30, + }, + end: { + line: 23, + column: 33, + }, + }, + range: [686, 689], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [688, 689], + loc: { + start: { + line: 23, + column: 32, + }, + end: { + line: 23, + column: 33, + }, + }, + }, + range: [688, 689], + loc: { + start: { + line: 23, + column: 32, + }, + end: { + line: 23, + column: 33, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [701, 702], + loc: { + start: { + line: 23, + column: 45, + }, + end: { + line: 23, + column: 46, + }, + }, + }, + arguments: [], + range: [701, 704], + loc: { + start: { + line: 23, + column: 45, + }, + end: { + line: 23, + column: 48, + }, + }, + }, + range: [701, 704], + loc: { + start: { + line: 23, + column: 45, + }, + end: { + line: 23, + column: 48, + }, + }, + }, + ], + range: [700, 705], + loc: { + start: { + line: 23, + column: 44, + }, + end: { + line: 23, + column: 49, + }, + }, + }, + async: true, + expression: false, + range: [667, 705], + loc: { + start: { + line: 23, + column: 11, + }, + end: { + line: 23, + column: 49, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 23, + column: 34, + }, + end: { + line: 23, + column: 40, + }, + }, + range: [690, 696], + typeAnnotation: { + type: 'TSVoidKeyword', + range: [692, 696], + loc: { + start: { + line: 23, + column: 36, + }, + end: { + line: 23, + column: 40, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [660, 707], + loc: { + start: { + line: 23, + column: 4, + }, + end: { + line: 23, + column: 51, + }, + }, + }, + { + type: 'Property', + key: { + type: 'Identifier', + name: 'key', + range: [713, 716], + loc: { + start: { + line: 24, + column: 4, + }, + end: { + line: 24, + column: 7, + }, + }, + }, + value: { + type: 'ArrowFunctionExpression', + generator: false, + id: null, + params: [ + { + type: 'Identifier', + name: 'arg', + range: [727, 733], + loc: { + start: { + line: 24, + column: 18, + }, + end: { + line: 24, + column: 24, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 24, + column: 21, + }, + end: { + line: 24, + column: 24, + }, + }, + range: [730, 733], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [732, 733], + loc: { + start: { + line: 24, + column: 23, + }, + end: { + line: 24, + column: 24, + }, + }, + }, + range: [732, 733], + loc: { + start: { + line: 24, + column: 23, + }, + end: { + line: 24, + column: 24, + }, + }, + }, + }, + }, + { + type: 'Identifier', + name: 'arg2', + range: [735, 742], + loc: { + start: { + line: 24, + column: 26, + }, + end: { + line: 24, + column: 33, + }, + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 24, + column: 30, + }, + end: { + line: 24, + column: 33, + }, + }, + range: [739, 742], + typeAnnotation: { + type: 'TSTypeReference', + typeName: { + type: 'Identifier', + name: 't', + range: [741, 742], + loc: { + start: { + line: 24, + column: 32, + }, + end: { + line: 24, + column: 33, + }, + }, + }, + range: [741, 742], + loc: { + start: { + line: 24, + column: 32, + }, + end: { + line: 24, + column: 33, + }, + }, + }, + }, + }, + ], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'x', + range: [756, 757], + loc: { + start: { + line: 24, + column: 47, + }, + end: { + line: 24, + column: 48, + }, + }, + }, + arguments: [], + range: [756, 759], + loc: { + start: { + line: 24, + column: 47, + }, + end: { + line: 24, + column: 50, + }, + }, + }, + range: [756, 759], + loc: { + start: { + line: 24, + column: 47, + }, + end: { + line: 24, + column: 50, + }, + }, + }, + ], + range: [755, 760], + loc: { + start: { + line: 24, + column: 46, + }, + end: { + line: 24, + column: 51, + }, + }, + }, + async: true, + expression: false, + range: [720, 760], + loc: { + start: { + line: 24, + column: 11, + }, + end: { + line: 24, + column: 51, + }, + }, + returnType: { + type: 'TSTypeAnnotation', + loc: { + start: { + line: 24, + column: 34, + }, + end: { + line: 24, + column: 42, + }, + }, + range: [743, 751], + typeAnnotation: { + type: 'TSParenthesizedType', + typeAnnotation: { + type: 'TSVoidKeyword', + range: [746, 750], + loc: { + start: { + line: 24, + column: 37, + }, + end: { + line: 24, + column: 41, + }, + }, + }, + range: [745, 751], + loc: { + start: { + line: 24, + column: 36, + }, + end: { + line: 24, + column: 42, + }, + }, + }, + }, + }, + computed: false, + method: false, + shorthand: false, + kind: 'init', + range: [713, 762], + loc: { + start: { + line: 24, + column: 4, + }, + end: { + line: 24, + column: 53, + }, + }, + }, + ], + range: [13, 765], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 25, + column: 1, + }, + }, + }, + range: [6, 765], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 25, + column: 1, + }, + }, + }, + ], + kind: 'const', + range: [0, 765], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 25, + column: 1, + }, + }, + }, + ], + sourceType: 'module', + range: [0, 765], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 25, + column: 1, + }, + }, + tokens: [ + { + type: 'Keyword', + value: 'const', + range: [0, 5], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: 'Identifier', + value: 'test', + range: [6, 10], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: 'Punctuator', + value: '=', + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [13, 14], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [19, 22], + loc: { + start: { + line: 2, + column: 4, + }, + end: { + line: 2, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [22, 23], + loc: { + start: { + line: 2, + column: 7, + }, + end: { + line: 2, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [24, 25], + loc: { + start: { + line: 2, + column: 9, + }, + end: { + line: 2, + column: 10, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [25, 26], + loc: { + start: { + line: 2, + column: 10, + }, + end: { + line: 2, + column: 11, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [26, 27], + loc: { + start: { + line: 2, + column: 11, + }, + end: { + line: 2, + column: 12, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [28, 32], + loc: { + start: { + line: 2, + column: 13, + }, + end: { + line: 2, + column: 17, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [33, 35], + loc: { + start: { + line: 2, + column: 18, + }, + end: { + line: 2, + column: 20, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [36, 37], + loc: { + start: { + line: 2, + column: 21, + }, + end: { + line: 2, + column: 22, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [37, 38], + loc: { + start: { + line: 2, + column: 22, + }, + end: { + line: 2, + column: 23, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [38, 39], + loc: { + start: { + line: 2, + column: 23, + }, + end: { + line: 2, + column: 24, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [39, 40], + loc: { + start: { + line: 2, + column: 24, + }, + end: { + line: 2, + column: 25, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [40, 41], + loc: { + start: { + line: 2, + column: 25, + }, + end: { + line: 2, + column: 26, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [41, 42], + loc: { + start: { + line: 2, + column: 26, + }, + end: { + line: 2, + column: 27, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [47, 50], + loc: { + start: { + line: 3, + column: 4, + }, + end: { + line: 3, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [50, 51], + loc: { + start: { + line: 3, + column: 7, + }, + end: { + line: 3, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [52, 53], + loc: { + start: { + line: 3, + column: 9, + }, + end: { + line: 3, + column: 10, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [54, 55], + loc: { + start: { + line: 3, + column: 11, + }, + end: { + line: 3, + column: 12, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [55, 56], + loc: { + start: { + line: 3, + column: 12, + }, + end: { + line: 3, + column: 13, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [56, 57], + loc: { + start: { + line: 3, + column: 13, + }, + end: { + line: 3, + column: 14, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [58, 62], + loc: { + start: { + line: 3, + column: 15, + }, + end: { + line: 3, + column: 19, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [63, 65], + loc: { + start: { + line: 3, + column: 20, + }, + end: { + line: 3, + column: 22, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [66, 67], + loc: { + start: { + line: 3, + column: 23, + }, + end: { + line: 3, + column: 24, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [67, 68], + loc: { + start: { + line: 3, + column: 24, + }, + end: { + line: 3, + column: 25, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [68, 69], + loc: { + start: { + line: 3, + column: 25, + }, + end: { + line: 3, + column: 26, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [69, 70], + loc: { + start: { + line: 3, + column: 26, + }, + end: { + line: 3, + column: 27, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [70, 71], + loc: { + start: { + line: 3, + column: 27, + }, + end: { + line: 3, + column: 28, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [72, 73], + loc: { + start: { + line: 3, + column: 29, + }, + end: { + line: 3, + column: 30, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [73, 74], + loc: { + start: { + line: 3, + column: 30, + }, + end: { + line: 3, + column: 31, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [79, 82], + loc: { + start: { + line: 4, + column: 4, + }, + end: { + line: 4, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [82, 83], + loc: { + start: { + line: 4, + column: 7, + }, + end: { + line: 4, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [84, 85], + loc: { + start: { + line: 4, + column: 9, + }, + end: { + line: 4, + column: 10, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [86, 87], + loc: { + start: { + line: 4, + column: 11, + }, + end: { + line: 4, + column: 12, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [87, 88], + loc: { + start: { + line: 4, + column: 12, + }, + end: { + line: 4, + column: 13, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [88, 89], + loc: { + start: { + line: 4, + column: 13, + }, + end: { + line: 4, + column: 14, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [90, 91], + loc: { + start: { + line: 4, + column: 15, + }, + end: { + line: 4, + column: 16, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [91, 95], + loc: { + start: { + line: 4, + column: 16, + }, + end: { + line: 4, + column: 20, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [95, 96], + loc: { + start: { + line: 4, + column: 20, + }, + end: { + line: 4, + column: 21, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [97, 99], + loc: { + start: { + line: 4, + column: 22, + }, + end: { + line: 4, + column: 24, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [100, 101], + loc: { + start: { + line: 4, + column: 25, + }, + end: { + line: 4, + column: 26, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [101, 102], + loc: { + start: { + line: 4, + column: 26, + }, + end: { + line: 4, + column: 27, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [102, 103], + loc: { + start: { + line: 4, + column: 27, + }, + end: { + line: 4, + column: 28, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [103, 104], + loc: { + start: { + line: 4, + column: 28, + }, + end: { + line: 4, + column: 29, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [104, 105], + loc: { + start: { + line: 4, + column: 29, + }, + end: { + line: 4, + column: 30, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [106, 107], + loc: { + start: { + line: 4, + column: 31, + }, + end: { + line: 4, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [107, 108], + loc: { + start: { + line: 4, + column: 32, + }, + end: { + line: 4, + column: 33, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [114, 117], + loc: { + start: { + line: 6, + column: 4, + }, + end: { + line: 6, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [117, 118], + loc: { + start: { + line: 6, + column: 7, + }, + end: { + line: 6, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [119, 120], + loc: { + start: { + line: 6, + column: 9, + }, + end: { + line: 6, + column: 10, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [120, 123], + loc: { + start: { + line: 6, + column: 10, + }, + end: { + line: 6, + column: 13, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [123, 124], + loc: { + start: { + line: 6, + column: 13, + }, + end: { + line: 6, + column: 14, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [125, 126], + loc: { + start: { + line: 6, + column: 15, + }, + end: { + line: 6, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [126, 127], + loc: { + start: { + line: 6, + column: 16, + }, + end: { + line: 6, + column: 17, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [127, 128], + loc: { + start: { + line: 6, + column: 17, + }, + end: { + line: 6, + column: 18, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [129, 133], + loc: { + start: { + line: 6, + column: 19, + }, + end: { + line: 6, + column: 23, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [134, 136], + loc: { + start: { + line: 6, + column: 24, + }, + end: { + line: 6, + column: 26, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [137, 138], + loc: { + start: { + line: 6, + column: 27, + }, + end: { + line: 6, + column: 28, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [138, 139], + loc: { + start: { + line: 6, + column: 28, + }, + end: { + line: 6, + column: 29, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [139, 140], + loc: { + start: { + line: 6, + column: 29, + }, + end: { + line: 6, + column: 30, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [140, 141], + loc: { + start: { + line: 6, + column: 30, + }, + end: { + line: 6, + column: 31, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [141, 142], + loc: { + start: { + line: 6, + column: 31, + }, + end: { + line: 6, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [142, 143], + loc: { + start: { + line: 6, + column: 32, + }, + end: { + line: 6, + column: 33, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [148, 151], + loc: { + start: { + line: 7, + column: 4, + }, + end: { + line: 7, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [151, 152], + loc: { + start: { + line: 7, + column: 7, + }, + end: { + line: 7, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [153, 154], + loc: { + start: { + line: 7, + column: 9, + }, + end: { + line: 7, + column: 10, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [155, 156], + loc: { + start: { + line: 7, + column: 11, + }, + end: { + line: 7, + column: 12, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [156, 159], + loc: { + start: { + line: 7, + column: 12, + }, + end: { + line: 7, + column: 15, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [159, 160], + loc: { + start: { + line: 7, + column: 15, + }, + end: { + line: 7, + column: 16, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [161, 162], + loc: { + start: { + line: 7, + column: 17, + }, + end: { + line: 7, + column: 18, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [162, 163], + loc: { + start: { + line: 7, + column: 18, + }, + end: { + line: 7, + column: 19, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [163, 164], + loc: { + start: { + line: 7, + column: 19, + }, + end: { + line: 7, + column: 20, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [165, 169], + loc: { + start: { + line: 7, + column: 21, + }, + end: { + line: 7, + column: 25, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [170, 172], + loc: { + start: { + line: 7, + column: 26, + }, + end: { + line: 7, + column: 28, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [173, 174], + loc: { + start: { + line: 7, + column: 29, + }, + end: { + line: 7, + column: 30, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [174, 175], + loc: { + start: { + line: 7, + column: 30, + }, + end: { + line: 7, + column: 31, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [175, 176], + loc: { + start: { + line: 7, + column: 31, + }, + end: { + line: 7, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [176, 177], + loc: { + start: { + line: 7, + column: 32, + }, + end: { + line: 7, + column: 33, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [177, 178], + loc: { + start: { + line: 7, + column: 33, + }, + end: { + line: 7, + column: 34, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [179, 180], + loc: { + start: { + line: 7, + column: 35, + }, + end: { + line: 7, + column: 36, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [180, 181], + loc: { + start: { + line: 7, + column: 36, + }, + end: { + line: 7, + column: 37, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [186, 189], + loc: { + start: { + line: 8, + column: 4, + }, + end: { + line: 8, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [189, 190], + loc: { + start: { + line: 8, + column: 7, + }, + end: { + line: 8, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [191, 192], + loc: { + start: { + line: 8, + column: 9, + }, + end: { + line: 8, + column: 10, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [193, 194], + loc: { + start: { + line: 8, + column: 11, + }, + end: { + line: 8, + column: 12, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [194, 197], + loc: { + start: { + line: 8, + column: 12, + }, + end: { + line: 8, + column: 15, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [197, 198], + loc: { + start: { + line: 8, + column: 15, + }, + end: { + line: 8, + column: 16, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [199, 200], + loc: { + start: { + line: 8, + column: 17, + }, + end: { + line: 8, + column: 18, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [200, 201], + loc: { + start: { + line: 8, + column: 18, + }, + end: { + line: 8, + column: 19, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [201, 202], + loc: { + start: { + line: 8, + column: 19, + }, + end: { + line: 8, + column: 20, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [203, 204], + loc: { + start: { + line: 8, + column: 21, + }, + end: { + line: 8, + column: 22, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [204, 208], + loc: { + start: { + line: 8, + column: 22, + }, + end: { + line: 8, + column: 26, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [208, 209], + loc: { + start: { + line: 8, + column: 26, + }, + end: { + line: 8, + column: 27, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [210, 212], + loc: { + start: { + line: 8, + column: 28, + }, + end: { + line: 8, + column: 30, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [213, 214], + loc: { + start: { + line: 8, + column: 31, + }, + end: { + line: 8, + column: 32, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [214, 215], + loc: { + start: { + line: 8, + column: 32, + }, + end: { + line: 8, + column: 33, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [215, 216], + loc: { + start: { + line: 8, + column: 33, + }, + end: { + line: 8, + column: 34, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [216, 217], + loc: { + start: { + line: 8, + column: 34, + }, + end: { + line: 8, + column: 35, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [217, 218], + loc: { + start: { + line: 8, + column: 35, + }, + end: { + line: 8, + column: 36, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [219, 220], + loc: { + start: { + line: 8, + column: 37, + }, + end: { + line: 8, + column: 38, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [220, 221], + loc: { + start: { + line: 8, + column: 38, + }, + end: { + line: 8, + column: 39, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [227, 230], + loc: { + start: { + line: 10, + column: 4, + }, + end: { + line: 10, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [230, 231], + loc: { + start: { + line: 10, + column: 7, + }, + end: { + line: 10, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [232, 233], + loc: { + start: { + line: 10, + column: 9, + }, + end: { + line: 10, + column: 10, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [233, 236], + loc: { + start: { + line: 10, + column: 10, + }, + end: { + line: 10, + column: 13, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [236, 237], + loc: { + start: { + line: 10, + column: 13, + }, + end: { + line: 10, + column: 14, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [238, 239], + loc: { + start: { + line: 10, + column: 15, + }, + end: { + line: 10, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [239, 240], + loc: { + start: { + line: 10, + column: 16, + }, + end: { + line: 10, + column: 17, + }, + }, + }, + { + type: 'Identifier', + value: 'arg2', + range: [241, 245], + loc: { + start: { + line: 10, + column: 18, + }, + end: { + line: 10, + column: 22, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [245, 246], + loc: { + start: { + line: 10, + column: 22, + }, + end: { + line: 10, + column: 23, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [247, 248], + loc: { + start: { + line: 10, + column: 24, + }, + end: { + line: 10, + column: 25, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [248, 249], + loc: { + start: { + line: 10, + column: 25, + }, + end: { + line: 10, + column: 26, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [249, 250], + loc: { + start: { + line: 10, + column: 26, + }, + end: { + line: 10, + column: 27, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [251, 255], + loc: { + start: { + line: 10, + column: 28, + }, + end: { + line: 10, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [256, 258], + loc: { + start: { + line: 10, + column: 33, + }, + end: { + line: 10, + column: 35, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [259, 260], + loc: { + start: { + line: 10, + column: 36, + }, + end: { + line: 10, + column: 37, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [260, 261], + loc: { + start: { + line: 10, + column: 37, + }, + end: { + line: 10, + column: 38, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [261, 262], + loc: { + start: { + line: 10, + column: 38, + }, + end: { + line: 10, + column: 39, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [262, 263], + loc: { + start: { + line: 10, + column: 39, + }, + end: { + line: 10, + column: 40, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [263, 264], + loc: { + start: { + line: 10, + column: 40, + }, + end: { + line: 10, + column: 41, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [264, 265], + loc: { + start: { + line: 10, + column: 41, + }, + end: { + line: 10, + column: 42, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [270, 273], + loc: { + start: { + line: 11, + column: 4, + }, + end: { + line: 11, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [273, 274], + loc: { + start: { + line: 11, + column: 7, + }, + end: { + line: 11, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [275, 276], + loc: { + start: { + line: 11, + column: 9, + }, + end: { + line: 11, + column: 10, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [277, 278], + loc: { + start: { + line: 11, + column: 11, + }, + end: { + line: 11, + column: 12, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [278, 281], + loc: { + start: { + line: 11, + column: 12, + }, + end: { + line: 11, + column: 15, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [281, 282], + loc: { + start: { + line: 11, + column: 15, + }, + end: { + line: 11, + column: 16, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [283, 284], + loc: { + start: { + line: 11, + column: 17, + }, + end: { + line: 11, + column: 18, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [284, 285], + loc: { + start: { + line: 11, + column: 18, + }, + end: { + line: 11, + column: 19, + }, + }, + }, + { + type: 'Identifier', + value: 'arg2', + range: [286, 290], + loc: { + start: { + line: 11, + column: 20, + }, + end: { + line: 11, + column: 24, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [290, 291], + loc: { + start: { + line: 11, + column: 24, + }, + end: { + line: 11, + column: 25, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [292, 293], + loc: { + start: { + line: 11, + column: 26, + }, + end: { + line: 11, + column: 27, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [293, 294], + loc: { + start: { + line: 11, + column: 27, + }, + end: { + line: 11, + column: 28, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [294, 295], + loc: { + start: { + line: 11, + column: 28, + }, + end: { + line: 11, + column: 29, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [296, 300], + loc: { + start: { + line: 11, + column: 30, + }, + end: { + line: 11, + column: 34, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [301, 303], + loc: { + start: { + line: 11, + column: 35, + }, + end: { + line: 11, + column: 37, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [304, 305], + loc: { + start: { + line: 11, + column: 38, + }, + end: { + line: 11, + column: 39, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [305, 306], + loc: { + start: { + line: 11, + column: 39, + }, + end: { + line: 11, + column: 40, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [306, 307], + loc: { + start: { + line: 11, + column: 40, + }, + end: { + line: 11, + column: 41, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [307, 308], + loc: { + start: { + line: 11, + column: 41, + }, + end: { + line: 11, + column: 42, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [308, 309], + loc: { + start: { + line: 11, + column: 42, + }, + end: { + line: 11, + column: 43, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [310, 311], + loc: { + start: { + line: 11, + column: 44, + }, + end: { + line: 11, + column: 45, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [311, 312], + loc: { + start: { + line: 11, + column: 45, + }, + end: { + line: 11, + column: 46, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [317, 320], + loc: { + start: { + line: 12, + column: 4, + }, + end: { + line: 12, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [320, 321], + loc: { + start: { + line: 12, + column: 7, + }, + end: { + line: 12, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [322, 323], + loc: { + start: { + line: 12, + column: 9, + }, + end: { + line: 12, + column: 10, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [324, 325], + loc: { + start: { + line: 12, + column: 11, + }, + end: { + line: 12, + column: 12, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [325, 328], + loc: { + start: { + line: 12, + column: 12, + }, + end: { + line: 12, + column: 15, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [328, 329], + loc: { + start: { + line: 12, + column: 15, + }, + end: { + line: 12, + column: 16, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [330, 331], + loc: { + start: { + line: 12, + column: 17, + }, + end: { + line: 12, + column: 18, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [331, 332], + loc: { + start: { + line: 12, + column: 18, + }, + end: { + line: 12, + column: 19, + }, + }, + }, + { + type: 'Identifier', + value: 'arg2', + range: [333, 337], + loc: { + start: { + line: 12, + column: 20, + }, + end: { + line: 12, + column: 24, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [337, 338], + loc: { + start: { + line: 12, + column: 24, + }, + end: { + line: 12, + column: 25, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [339, 340], + loc: { + start: { + line: 12, + column: 26, + }, + end: { + line: 12, + column: 27, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [340, 341], + loc: { + start: { + line: 12, + column: 27, + }, + end: { + line: 12, + column: 28, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [341, 342], + loc: { + start: { + line: 12, + column: 28, + }, + end: { + line: 12, + column: 29, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [343, 344], + loc: { + start: { + line: 12, + column: 30, + }, + end: { + line: 12, + column: 31, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [344, 348], + loc: { + start: { + line: 12, + column: 31, + }, + end: { + line: 12, + column: 35, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [348, 349], + loc: { + start: { + line: 12, + column: 35, + }, + end: { + line: 12, + column: 36, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [350, 352], + loc: { + start: { + line: 12, + column: 37, + }, + end: { + line: 12, + column: 39, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [353, 354], + loc: { + start: { + line: 12, + column: 40, + }, + end: { + line: 12, + column: 41, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [354, 355], + loc: { + start: { + line: 12, + column: 41, + }, + end: { + line: 12, + column: 42, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [355, 356], + loc: { + start: { + line: 12, + column: 42, + }, + end: { + line: 12, + column: 43, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [356, 357], + loc: { + start: { + line: 12, + column: 43, + }, + end: { + line: 12, + column: 44, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [357, 358], + loc: { + start: { + line: 12, + column: 44, + }, + end: { + line: 12, + column: 45, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [359, 360], + loc: { + start: { + line: 12, + column: 46, + }, + end: { + line: 12, + column: 47, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [360, 361], + loc: { + start: { + line: 12, + column: 47, + }, + end: { + line: 12, + column: 48, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [367, 370], + loc: { + start: { + line: 14, + column: 4, + }, + end: { + line: 14, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [370, 371], + loc: { + start: { + line: 14, + column: 7, + }, + end: { + line: 14, + column: 8, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [372, 377], + loc: { + start: { + line: 14, + column: 9, + }, + end: { + line: 14, + column: 14, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [378, 379], + loc: { + start: { + line: 14, + column: 15, + }, + end: { + line: 14, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [379, 380], + loc: { + start: { + line: 14, + column: 16, + }, + end: { + line: 14, + column: 17, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [380, 381], + loc: { + start: { + line: 14, + column: 17, + }, + end: { + line: 14, + column: 18, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [382, 386], + loc: { + start: { + line: 14, + column: 19, + }, + end: { + line: 14, + column: 23, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [387, 389], + loc: { + start: { + line: 14, + column: 24, + }, + end: { + line: 14, + column: 26, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [390, 391], + loc: { + start: { + line: 14, + column: 27, + }, + end: { + line: 14, + column: 28, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [391, 392], + loc: { + start: { + line: 14, + column: 28, + }, + end: { + line: 14, + column: 29, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [392, 393], + loc: { + start: { + line: 14, + column: 29, + }, + end: { + line: 14, + column: 30, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [393, 394], + loc: { + start: { + line: 14, + column: 30, + }, + end: { + line: 14, + column: 31, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [394, 395], + loc: { + start: { + line: 14, + column: 31, + }, + end: { + line: 14, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [395, 396], + loc: { + start: { + line: 14, + column: 32, + }, + end: { + line: 14, + column: 33, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [401, 404], + loc: { + start: { + line: 15, + column: 4, + }, + end: { + line: 15, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [404, 405], + loc: { + start: { + line: 15, + column: 7, + }, + end: { + line: 15, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [406, 407], + loc: { + start: { + line: 15, + column: 9, + }, + end: { + line: 15, + column: 10, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [408, 413], + loc: { + start: { + line: 15, + column: 11, + }, + end: { + line: 15, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [414, 415], + loc: { + start: { + line: 15, + column: 17, + }, + end: { + line: 15, + column: 18, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [415, 416], + loc: { + start: { + line: 15, + column: 18, + }, + end: { + line: 15, + column: 19, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [416, 417], + loc: { + start: { + line: 15, + column: 19, + }, + end: { + line: 15, + column: 20, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [418, 422], + loc: { + start: { + line: 15, + column: 21, + }, + end: { + line: 15, + column: 25, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [423, 425], + loc: { + start: { + line: 15, + column: 26, + }, + end: { + line: 15, + column: 28, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [426, 427], + loc: { + start: { + line: 15, + column: 29, + }, + end: { + line: 15, + column: 30, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [427, 428], + loc: { + start: { + line: 15, + column: 30, + }, + end: { + line: 15, + column: 31, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [428, 429], + loc: { + start: { + line: 15, + column: 31, + }, + end: { + line: 15, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [429, 430], + loc: { + start: { + line: 15, + column: 32, + }, + end: { + line: 15, + column: 33, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [430, 431], + loc: { + start: { + line: 15, + column: 33, + }, + end: { + line: 15, + column: 34, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [432, 433], + loc: { + start: { + line: 15, + column: 35, + }, + end: { + line: 15, + column: 36, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [433, 434], + loc: { + start: { + line: 15, + column: 36, + }, + end: { + line: 15, + column: 37, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [439, 442], + loc: { + start: { + line: 16, + column: 4, + }, + end: { + line: 16, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [442, 443], + loc: { + start: { + line: 16, + column: 7, + }, + end: { + line: 16, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [444, 445], + loc: { + start: { + line: 16, + column: 9, + }, + end: { + line: 16, + column: 10, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [446, 451], + loc: { + start: { + line: 16, + column: 11, + }, + end: { + line: 16, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [452, 453], + loc: { + start: { + line: 16, + column: 17, + }, + end: { + line: 16, + column: 18, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [453, 454], + loc: { + start: { + line: 16, + column: 18, + }, + end: { + line: 16, + column: 19, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [454, 455], + loc: { + start: { + line: 16, + column: 19, + }, + end: { + line: 16, + column: 20, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [456, 457], + loc: { + start: { + line: 16, + column: 21, + }, + end: { + line: 16, + column: 22, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [457, 461], + loc: { + start: { + line: 16, + column: 22, + }, + end: { + line: 16, + column: 26, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [461, 462], + loc: { + start: { + line: 16, + column: 26, + }, + end: { + line: 16, + column: 27, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [463, 465], + loc: { + start: { + line: 16, + column: 28, + }, + end: { + line: 16, + column: 30, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [466, 467], + loc: { + start: { + line: 16, + column: 31, + }, + end: { + line: 16, + column: 32, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [467, 468], + loc: { + start: { + line: 16, + column: 32, + }, + end: { + line: 16, + column: 33, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [468, 469], + loc: { + start: { + line: 16, + column: 33, + }, + end: { + line: 16, + column: 34, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [469, 470], + loc: { + start: { + line: 16, + column: 34, + }, + end: { + line: 16, + column: 35, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [470, 471], + loc: { + start: { + line: 16, + column: 35, + }, + end: { + line: 16, + column: 36, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [472, 473], + loc: { + start: { + line: 16, + column: 37, + }, + end: { + line: 16, + column: 38, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [473, 474], + loc: { + start: { + line: 16, + column: 38, + }, + end: { + line: 16, + column: 39, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [480, 483], + loc: { + start: { + line: 18, + column: 4, + }, + end: { + line: 18, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [483, 484], + loc: { + start: { + line: 18, + column: 7, + }, + end: { + line: 18, + column: 8, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [485, 490], + loc: { + start: { + line: 18, + column: 9, + }, + end: { + line: 18, + column: 14, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [491, 492], + loc: { + start: { + line: 18, + column: 15, + }, + end: { + line: 18, + column: 16, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [492, 495], + loc: { + start: { + line: 18, + column: 16, + }, + end: { + line: 18, + column: 19, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [495, 496], + loc: { + start: { + line: 18, + column: 19, + }, + end: { + line: 18, + column: 20, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [497, 498], + loc: { + start: { + line: 18, + column: 21, + }, + end: { + line: 18, + column: 22, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [498, 499], + loc: { + start: { + line: 18, + column: 22, + }, + end: { + line: 18, + column: 23, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [499, 500], + loc: { + start: { + line: 18, + column: 23, + }, + end: { + line: 18, + column: 24, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [501, 505], + loc: { + start: { + line: 18, + column: 25, + }, + end: { + line: 18, + column: 29, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [506, 508], + loc: { + start: { + line: 18, + column: 30, + }, + end: { + line: 18, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [509, 510], + loc: { + start: { + line: 18, + column: 33, + }, + end: { + line: 18, + column: 34, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [510, 511], + loc: { + start: { + line: 18, + column: 34, + }, + end: { + line: 18, + column: 35, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [511, 512], + loc: { + start: { + line: 18, + column: 35, + }, + end: { + line: 18, + column: 36, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [512, 513], + loc: { + start: { + line: 18, + column: 36, + }, + end: { + line: 18, + column: 37, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [513, 514], + loc: { + start: { + line: 18, + column: 37, + }, + end: { + line: 18, + column: 38, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [514, 515], + loc: { + start: { + line: 18, + column: 38, + }, + end: { + line: 18, + column: 39, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [520, 523], + loc: { + start: { + line: 19, + column: 4, + }, + end: { + line: 19, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [523, 524], + loc: { + start: { + line: 19, + column: 7, + }, + end: { + line: 19, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [525, 526], + loc: { + start: { + line: 19, + column: 9, + }, + end: { + line: 19, + column: 10, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [527, 532], + loc: { + start: { + line: 19, + column: 11, + }, + end: { + line: 19, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [533, 534], + loc: { + start: { + line: 19, + column: 17, + }, + end: { + line: 19, + column: 18, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [534, 537], + loc: { + start: { + line: 19, + column: 18, + }, + end: { + line: 19, + column: 21, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [537, 538], + loc: { + start: { + line: 19, + column: 21, + }, + end: { + line: 19, + column: 22, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [539, 540], + loc: { + start: { + line: 19, + column: 23, + }, + end: { + line: 19, + column: 24, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [540, 541], + loc: { + start: { + line: 19, + column: 24, + }, + end: { + line: 19, + column: 25, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [541, 542], + loc: { + start: { + line: 19, + column: 25, + }, + end: { + line: 19, + column: 26, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [543, 547], + loc: { + start: { + line: 19, + column: 27, + }, + end: { + line: 19, + column: 31, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [548, 550], + loc: { + start: { + line: 19, + column: 32, + }, + end: { + line: 19, + column: 34, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [551, 552], + loc: { + start: { + line: 19, + column: 35, + }, + end: { + line: 19, + column: 36, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [552, 553], + loc: { + start: { + line: 19, + column: 36, + }, + end: { + line: 19, + column: 37, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [553, 554], + loc: { + start: { + line: 19, + column: 37, + }, + end: { + line: 19, + column: 38, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [554, 555], + loc: { + start: { + line: 19, + column: 38, + }, + end: { + line: 19, + column: 39, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [555, 556], + loc: { + start: { + line: 19, + column: 39, + }, + end: { + line: 19, + column: 40, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [557, 558], + loc: { + start: { + line: 19, + column: 41, + }, + end: { + line: 19, + column: 42, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [558, 559], + loc: { + start: { + line: 19, + column: 42, + }, + end: { + line: 19, + column: 43, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [564, 567], + loc: { + start: { + line: 20, + column: 4, + }, + end: { + line: 20, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [567, 568], + loc: { + start: { + line: 20, + column: 7, + }, + end: { + line: 20, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [569, 570], + loc: { + start: { + line: 20, + column: 9, + }, + end: { + line: 20, + column: 10, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [571, 576], + loc: { + start: { + line: 20, + column: 11, + }, + end: { + line: 20, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [577, 578], + loc: { + start: { + line: 20, + column: 17, + }, + end: { + line: 20, + column: 18, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [578, 581], + loc: { + start: { + line: 20, + column: 18, + }, + end: { + line: 20, + column: 21, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [581, 582], + loc: { + start: { + line: 20, + column: 21, + }, + end: { + line: 20, + column: 22, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [583, 584], + loc: { + start: { + line: 20, + column: 23, + }, + end: { + line: 20, + column: 24, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [584, 585], + loc: { + start: { + line: 20, + column: 24, + }, + end: { + line: 20, + column: 25, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [585, 586], + loc: { + start: { + line: 20, + column: 25, + }, + end: { + line: 20, + column: 26, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [587, 588], + loc: { + start: { + line: 20, + column: 27, + }, + end: { + line: 20, + column: 28, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [588, 592], + loc: { + start: { + line: 20, + column: 28, + }, + end: { + line: 20, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [592, 593], + loc: { + start: { + line: 20, + column: 32, + }, + end: { + line: 20, + column: 33, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [594, 596], + loc: { + start: { + line: 20, + column: 34, + }, + end: { + line: 20, + column: 36, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [597, 598], + loc: { + start: { + line: 20, + column: 37, + }, + end: { + line: 20, + column: 38, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [598, 599], + loc: { + start: { + line: 20, + column: 38, + }, + end: { + line: 20, + column: 39, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [599, 600], + loc: { + start: { + line: 20, + column: 39, + }, + end: { + line: 20, + column: 40, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [600, 601], + loc: { + start: { + line: 20, + column: 40, + }, + end: { + line: 20, + column: 41, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [601, 602], + loc: { + start: { + line: 20, + column: 41, + }, + end: { + line: 20, + column: 42, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [603, 604], + loc: { + start: { + line: 20, + column: 43, + }, + end: { + line: 20, + column: 44, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [604, 605], + loc: { + start: { + line: 20, + column: 44, + }, + end: { + line: 20, + column: 45, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [611, 614], + loc: { + start: { + line: 22, + column: 4, + }, + end: { + line: 22, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [614, 615], + loc: { + start: { + line: 22, + column: 7, + }, + end: { + line: 22, + column: 8, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [616, 621], + loc: { + start: { + line: 22, + column: 9, + }, + end: { + line: 22, + column: 14, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [622, 623], + loc: { + start: { + line: 22, + column: 15, + }, + end: { + line: 22, + column: 16, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [623, 626], + loc: { + start: { + line: 22, + column: 16, + }, + end: { + line: 22, + column: 19, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [626, 627], + loc: { + start: { + line: 22, + column: 19, + }, + end: { + line: 22, + column: 20, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [628, 629], + loc: { + start: { + line: 22, + column: 21, + }, + end: { + line: 22, + column: 22, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [629, 630], + loc: { + start: { + line: 22, + column: 22, + }, + end: { + line: 22, + column: 23, + }, + }, + }, + { + type: 'Identifier', + value: 'arg2', + range: [631, 635], + loc: { + start: { + line: 22, + column: 24, + }, + end: { + line: 22, + column: 28, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [635, 636], + loc: { + start: { + line: 22, + column: 28, + }, + end: { + line: 22, + column: 29, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [637, 638], + loc: { + start: { + line: 22, + column: 30, + }, + end: { + line: 22, + column: 31, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [638, 639], + loc: { + start: { + line: 22, + column: 31, + }, + end: { + line: 22, + column: 32, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [639, 640], + loc: { + start: { + line: 22, + column: 32, + }, + end: { + line: 22, + column: 33, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [641, 645], + loc: { + start: { + line: 22, + column: 34, + }, + end: { + line: 22, + column: 38, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [646, 648], + loc: { + start: { + line: 22, + column: 39, + }, + end: { + line: 22, + column: 41, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [649, 650], + loc: { + start: { + line: 22, + column: 42, + }, + end: { + line: 22, + column: 43, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [650, 651], + loc: { + start: { + line: 22, + column: 43, + }, + end: { + line: 22, + column: 44, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [651, 652], + loc: { + start: { + line: 22, + column: 44, + }, + end: { + line: 22, + column: 45, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [652, 653], + loc: { + start: { + line: 22, + column: 45, + }, + end: { + line: 22, + column: 46, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [653, 654], + loc: { + start: { + line: 22, + column: 46, + }, + end: { + line: 22, + column: 47, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [654, 655], + loc: { + start: { + line: 22, + column: 47, + }, + end: { + line: 22, + column: 48, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [660, 663], + loc: { + start: { + line: 23, + column: 4, + }, + end: { + line: 23, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [663, 664], + loc: { + start: { + line: 23, + column: 7, + }, + end: { + line: 23, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [665, 666], + loc: { + start: { + line: 23, + column: 9, + }, + end: { + line: 23, + column: 10, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [667, 672], + loc: { + start: { + line: 23, + column: 11, + }, + end: { + line: 23, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [673, 674], + loc: { + start: { + line: 23, + column: 17, + }, + end: { + line: 23, + column: 18, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [674, 677], + loc: { + start: { + line: 23, + column: 18, + }, + end: { + line: 23, + column: 21, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [677, 678], + loc: { + start: { + line: 23, + column: 21, + }, + end: { + line: 23, + column: 22, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [679, 680], + loc: { + start: { + line: 23, + column: 23, + }, + end: { + line: 23, + column: 24, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [680, 681], + loc: { + start: { + line: 23, + column: 24, + }, + end: { + line: 23, + column: 25, + }, + }, + }, + { + type: 'Identifier', + value: 'arg2', + range: [682, 686], + loc: { + start: { + line: 23, + column: 26, + }, + end: { + line: 23, + column: 30, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [686, 687], + loc: { + start: { + line: 23, + column: 30, + }, + end: { + line: 23, + column: 31, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [688, 689], + loc: { + start: { + line: 23, + column: 32, + }, + end: { + line: 23, + column: 33, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [689, 690], + loc: { + start: { + line: 23, + column: 33, + }, + end: { + line: 23, + column: 34, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [690, 691], + loc: { + start: { + line: 23, + column: 34, + }, + end: { + line: 23, + column: 35, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [692, 696], + loc: { + start: { + line: 23, + column: 36, + }, + end: { + line: 23, + column: 40, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [697, 699], + loc: { + start: { + line: 23, + column: 41, + }, + end: { + line: 23, + column: 43, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [700, 701], + loc: { + start: { + line: 23, + column: 44, + }, + end: { + line: 23, + column: 45, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [701, 702], + loc: { + start: { + line: 23, + column: 45, + }, + end: { + line: 23, + column: 46, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [702, 703], + loc: { + start: { + line: 23, + column: 46, + }, + end: { + line: 23, + column: 47, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [703, 704], + loc: { + start: { + line: 23, + column: 47, + }, + end: { + line: 23, + column: 48, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [704, 705], + loc: { + start: { + line: 23, + column: 48, + }, + end: { + line: 23, + column: 49, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [706, 707], + loc: { + start: { + line: 23, + column: 50, + }, + end: { + line: 23, + column: 51, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [707, 708], + loc: { + start: { + line: 23, + column: 51, + }, + end: { + line: 23, + column: 52, + }, + }, + }, + { + type: 'Identifier', + value: 'key', + range: [713, 716], + loc: { + start: { + line: 24, + column: 4, + }, + end: { + line: 24, + column: 7, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [716, 717], + loc: { + start: { + line: 24, + column: 7, + }, + end: { + line: 24, + column: 8, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [718, 719], + loc: { + start: { + line: 24, + column: 9, + }, + end: { + line: 24, + column: 10, + }, + }, + }, + { + type: 'Identifier', + value: 'async', + range: [720, 725], + loc: { + start: { + line: 24, + column: 11, + }, + end: { + line: 24, + column: 16, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [726, 727], + loc: { + start: { + line: 24, + column: 17, + }, + end: { + line: 24, + column: 18, + }, + }, + }, + { + type: 'Identifier', + value: 'arg', + range: [727, 730], + loc: { + start: { + line: 24, + column: 18, + }, + end: { + line: 24, + column: 21, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [730, 731], + loc: { + start: { + line: 24, + column: 21, + }, + end: { + line: 24, + column: 22, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [732, 733], + loc: { + start: { + line: 24, + column: 23, + }, + end: { + line: 24, + column: 24, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [733, 734], + loc: { + start: { + line: 24, + column: 24, + }, + end: { + line: 24, + column: 25, + }, + }, + }, + { + type: 'Identifier', + value: 'arg2', + range: [735, 739], + loc: { + start: { + line: 24, + column: 26, + }, + end: { + line: 24, + column: 30, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [739, 740], + loc: { + start: { + line: 24, + column: 30, + }, + end: { + line: 24, + column: 31, + }, + }, + }, + { + type: 'Identifier', + value: 't', + range: [741, 742], + loc: { + start: { + line: 24, + column: 32, + }, + end: { + line: 24, + column: 33, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [742, 743], + loc: { + start: { + line: 24, + column: 33, + }, + end: { + line: 24, + column: 34, + }, + }, + }, + { + type: 'Punctuator', + value: ':', + range: [743, 744], + loc: { + start: { + line: 24, + column: 34, + }, + end: { + line: 24, + column: 35, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [745, 746], + loc: { + start: { + line: 24, + column: 36, + }, + end: { + line: 24, + column: 37, + }, + }, + }, + { + type: 'Keyword', + value: 'void', + range: [746, 750], + loc: { + start: { + line: 24, + column: 37, + }, + end: { + line: 24, + column: 41, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [750, 751], + loc: { + start: { + line: 24, + column: 41, + }, + end: { + line: 24, + column: 42, + }, + }, + }, + { + type: 'Punctuator', + value: '=>', + range: [752, 754], + loc: { + start: { + line: 24, + column: 43, + }, + end: { + line: 24, + column: 45, + }, + }, + }, + { + type: 'Punctuator', + value: '{', + range: [755, 756], + loc: { + start: { + line: 24, + column: 46, + }, + end: { + line: 24, + column: 47, + }, + }, + }, + { + type: 'Identifier', + value: 'x', + range: [756, 757], + loc: { + start: { + line: 24, + column: 47, + }, + end: { + line: 24, + column: 48, + }, + }, + }, + { + type: 'Punctuator', + value: '(', + range: [757, 758], + loc: { + start: { + line: 24, + column: 48, + }, + end: { + line: 24, + column: 49, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [758, 759], + loc: { + start: { + line: 24, + column: 49, + }, + end: { + line: 24, + column: 50, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [759, 760], + loc: { + start: { + line: 24, + column: 50, + }, + end: { + line: 24, + column: 51, + }, + }, + }, + { + type: 'Punctuator', + value: ')', + range: [761, 762], + loc: { + start: { + line: 24, + column: 52, + }, + end: { + line: 24, + column: 53, + }, + }, + }, + { + type: 'Punctuator', + value: ',', + range: [762, 763], + loc: { + start: { + line: 24, + column: 53, + }, + end: { + line: 24, + column: 54, + }, + }, + }, + { + type: 'Punctuator', + value: '}', + range: [764, 765], + loc: { + start: { + line: 25, + column: 0, + }, + end: { + line: 25, + column: 1, + }, + }, + }, + ], + comments: [], +}); diff --git a/tests/lib/rules/object-shorthand.js b/tests/lib/rules/object-shorthand.js index 04d702535ba..911df1e3a41 100644 --- a/tests/lib/rules/object-shorthand.js +++ b/tests/lib/rules/object-shorthand.js @@ -11,6 +11,7 @@ const rule = require("../../../lib/rules/object-shorthand"), { RuleTester } = require("../../../lib/rule-tester"); +const { unIndent } = require("../_utils"); //------------------------------------------------------------------------------ // Tests @@ -1070,6 +1071,36 @@ ruleTester.run("object-shorthand", rule, { options: ["always", { avoidExplicitReturnArrows: true }], errors: [METHOD_ERROR] }, + { + code: "({ a: ((arg) => { return foo; }) })", + output: "({ a(arg) { return foo; } })", + options: ["always", { avoidExplicitReturnArrows: true }], + errors: [METHOD_ERROR] + }, + { + code: "({ a: ((arg, arg2) => { return foo; }) })", + output: "({ a(arg, arg2) { return foo; } })", + options: ["always", { avoidExplicitReturnArrows: true }], + errors: [METHOD_ERROR] + }, + { + code: "({ a: (async () => { return foo; }) })", + output: "({ async a() { return foo; } })", + options: ["always", { avoidExplicitReturnArrows: true }], + errors: [METHOD_ERROR] + }, + { + code: "({ a: (async (arg) => { return foo; }) })", + output: "({ async a(arg) { return foo; } })", + options: ["always", { avoidExplicitReturnArrows: true }], + errors: [METHOD_ERROR] + }, + { + code: "({ a: (async (arg, arg2) => { return foo; }) })", + output: "({ async a(arg, arg2) { return foo; } })", + options: ["always", { avoidExplicitReturnArrows: true }], + errors: [METHOD_ERROR] + }, // async generators { @@ -1083,6 +1114,67 @@ ruleTester.run("object-shorthand", rule, { output: "({ a: async function*() {} })", options: ["never"], errors: [LONGFORM_METHOD_ERROR] + }, + + // typescript: arrow function should preserve the return value + { + code: unIndent` + const test = { + key: (): void => {x()}, + key: ( (): void => {x()} ), + key: ( (): (void) => {x()} ), + + key: (arg: t): void => {x()}, + key: ( (arg: t): void => {x()} ), + key: ( (arg: t): (void) => {x()} ), + + key: (arg: t, arg2: t): void => {x()}, + key: ( (arg: t, arg2: t): void => {x()} ), + key: ( (arg: t, arg2: t): (void) => {x()} ), + + key: async (): void => {x()}, + key: ( async (): void => {x()} ), + key: ( async (): (void) => {x()} ), + + key: async (arg: t): void => {x()}, + key: ( async (arg: t): void => {x()} ), + key: ( async (arg: t): (void) => {x()} ), + + key: async (arg: t, arg2: t): void => {x()}, + key: ( async (arg: t, arg2: t): void => {x()} ), + key: ( async (arg: t, arg2: t): (void) => {x()} ), + } + `, + output: unIndent` + const test = { + key(): void {x()}, + key(): void {x()}, + key(): (void) {x()}, + + key(arg: t): void {x()}, + key(arg: t): void {x()}, + key(arg: t): (void) {x()}, + + key(arg: t, arg2: t): void {x()}, + key(arg: t, arg2: t): void {x()}, + key(arg: t, arg2: t): (void) {x()}, + + async key(): void {x()}, + async key(): void {x()}, + async key(): (void) {x()}, + + async key(arg: t): void {x()}, + async key(arg: t): void {x()}, + async key(arg: t): (void) {x()}, + + async key(arg: t, arg2: t): void {x()}, + async key(arg: t, arg2: t): void {x()}, + async key(arg: t, arg2: t): (void) {x()}, + } + `, + options: ["always", { avoidExplicitReturnArrows: true }], + parser: require.resolve("../../fixtures/parsers/typescript-parsers/object-with-arrow-fn-props"), + errors: Array(18).fill(METHOD_ERROR) } ] }); From ae17d1ca59dd466aa64da0680ec2453c2dc3b80d Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 02:37:37 +0200 Subject: [PATCH 14/26] Fix: no-sequences is reporting incorrect locations (#12241) * Fix: no-sequences is reporting incorrect locations * Report full location --- lib/rules/no-sequences.js | 4 ++-- tests/lib/rules/no-sequences.js | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/rules/no-sequences.js b/lib/rules/no-sequences.js index 71317c2f792..39d147b69be 100644 --- a/lib/rules/no-sequences.js +++ b/lib/rules/no-sequences.js @@ -105,9 +105,9 @@ module.exports = { } } - const child = sourceCode.getTokenAfter(node.expressions[0]); + const firstCommaToken = sourceCode.getTokenAfter(node.expressions[0], astUtils.isCommaToken); - context.report({ node, loc: child.loc.start, message: "Unexpected use of comma operator." }); + context.report({ node, loc: firstCommaToken.loc, message: "Unexpected use of comma operator." }); } }; diff --git a/tests/lib/rules/no-sequences.js b/tests/lib/rules/no-sequences.js index 55721de3e9d..7fcba267b7e 100644 --- a/tests/lib/rules/no-sequences.js +++ b/tests/lib/rules/no-sequences.js @@ -54,6 +54,17 @@ ruleTester.run("no-sequences", rule, { // Examples of code that should trigger the rule invalid: [ + { + code: "1, 2;", + errors: [{ + message: "Unexpected use of comma operator.", + type: "SequenceExpression", + line: 1, + column: 2, + endLine: 1, + endColumn: 3 + }] + }, { code: "a = 1, 2", errors: errors(6) }, { code: "do {} while (doSomething(), !!test);", errors: errors(27) }, { code: "for (; doSomething(), !!test; );", errors: errors(21) }, @@ -61,6 +72,9 @@ ruleTester.run("no-sequences", rule, { { code: "switch (doSomething(), val) {}", errors: errors(22) }, { code: "while (doSomething(), !!test);", errors: errors(21) }, { code: "with (doSomething(), val) {}", errors: errors(20) }, - { code: "a => (doSomething(), a)", env: { es6: true }, errors: errors(20) } + { code: "a => (doSomething(), a)", env: { es6: true }, errors: errors(20) }, + { code: "(1), 2", errors: errors(4) }, + { code: "((1)) , (2)", errors: errors(7) }, + { code: "while((1) , 2);", errors: errors(11) } ] }); From db2a29beb0fa28183f65bf9e659c66c03a8918b5 Mon Sep 17 00:00:00 2001 From: Kai Cataldo <7041728+kaicataldo@users.noreply.github.com> Date: Fri, 13 Sep 2019 20:38:04 -0400 Subject: [PATCH 15/26] Update: indentation of comment followed by semicolon (fixes #12232) (#12243) --- lib/rules/indent.js | 22 +- tests/lib/rules/indent.js | 490 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 506 insertions(+), 6 deletions(-) diff --git a/lib/rules/indent.js b/lib/rules/indent.js index 79b1063137e..f44eafa715c 100644 --- a/lib/rules/indent.js +++ b/lib/rules/indent.js @@ -1588,18 +1588,23 @@ module.exports = { return; } - // If the token matches the expected expected indentation, don't report it. - if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) { - return; - } - if (astUtils.isCommentToken(firstTokenOfLine)) { const tokenBefore = precedingTokens.get(firstTokenOfLine); const tokenAfter = tokenBefore ? sourceCode.getTokenAfter(tokenBefore) : sourceCode.ast.tokens[0]; - const mayAlignWithBefore = tokenBefore && !hasBlankLinesBetween(tokenBefore, firstTokenOfLine); const mayAlignWithAfter = tokenAfter && !hasBlankLinesBetween(firstTokenOfLine, tokenAfter); + /* + * If a comment precedes a line that begins with a semicolon token, align to that token, i.e. + * + * let foo + * // comment + * ;(async () => {})() + */ + if (tokenAfter && astUtils.isSemicolonToken(tokenAfter) && !astUtils.isTokenOnSameLine(firstTokenOfLine, tokenAfter)) { + offsets.setDesiredOffset(firstTokenOfLine, tokenAfter, 0); + } + // If a comment matches the expected indentation of the token immediately before or after, don't report it. if ( mayAlignWithBefore && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenBefore)) || @@ -1609,6 +1614,11 @@ module.exports = { } } + // If the token matches the expected indentation, don't report it. + if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) { + return; + } + // Otherwise, report the token/comment. report(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine)); }); diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js index b38c97e960b..e2d6202a998 100644 --- a/tests/lib/rules/indent.js +++ b/tests/lib/rules/indent.js @@ -4950,6 +4950,212 @@ ruleTester.run("indent", rule, { bar }]; `, + unIndent` + let foo + + // comment + + ;(async () => {})() + `, + unIndent` + let foo + // comment + + ;(async () => {})() + `, + unIndent` + let foo + + // comment + ;(async () => {})() + `, + unIndent` + let foo + // comment + ;(async () => {})() + `, + unIndent` + let foo + + /* comment */; + + (async () => {})() + `, + unIndent` + let foo + /* comment */; + + (async () => {})() + `, + unIndent` + let foo + + /* comment */; + (async () => {})() + `, + unIndent` + let foo + /* comment */; + (async () => {})() + `, + unIndent` + let foo + /* comment */; + + (async () => {})() + `, + unIndent` + let foo + /* comment */; + (async () => {})() + `, + unIndent` + // comment + + ;(async () => {})() + `, + unIndent` + // comment + ;(async () => {})() + `, + unIndent` + { + let foo + + // comment + + ;(async () => {})() + } + `, + unIndent` + { + let foo + // comment + ;(async () => {})() + } + `, + unIndent` + { + // comment + + ;(async () => {})() + } + `, + unIndent` + { + // comment + ;(async () => {})() + } + `, + unIndent` + const foo = 1 + const bar = foo + + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + + /* comment */ + ;[1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + /* comment */ + ;[1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + + /* comment */; + + [1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + /* comment */; + + [1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + + /* comment */; + [1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + /* comment */; + [1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + /* comment */; + + [1, 2, 3].forEach(() => {}) + `, + unIndent` + const foo = 1 + const bar = foo + /* comment */; + [1, 2, 3].forEach(() => {}) + `, + unIndent` + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + `, + unIndent` + /* comment */ + ;[1, 2, 3].forEach(() => {}) + `, + unIndent` + { + const foo = 1 + const bar = foo + + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + } + `, + unIndent` + { + const foo = 1 + const bar = foo + /* comment */ + ;[1, 2, 3].forEach(() => {}) + } + `, + unIndent` + { + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + } + `, + unIndent` + { + /* comment */ + ;[1, 2, 3].forEach(() => {}) + } + `, // import expressions { @@ -9606,6 +9812,290 @@ ruleTester.run("indent", rule, { `, errors: expectedErrors([5, 0, 4, "Line"]) }, + { + code: unIndent` + let foo + + // comment + + ;(async () => {})() + `, + output: unIndent` + let foo + + // comment + + ;(async () => {})() + `, + errors: expectedErrors([3, 0, 4, "Line"]) + }, + { + code: unIndent` + let foo + // comment + ;(async () => {})() + `, + output: unIndent` + let foo + // comment + ;(async () => {})() + `, + errors: expectedErrors([2, 0, 4, "Line"]) + }, + { + code: unIndent` + let foo + + /* comment */; + + (async () => {})() + `, + output: unIndent` + let foo + + /* comment */; + + (async () => {})() + `, + errors: expectedErrors([3, 4, 0, "Block"]) + }, + { + code: unIndent` + // comment + + ;(async () => {})() + `, + output: unIndent` + // comment + + ;(async () => {})() + `, + errors: expectedErrors([1, 0, 4, "Line"]) + }, + { + code: unIndent` + // comment + ;(async () => {})() + `, + output: unIndent` + // comment + ;(async () => {})() + `, + errors: expectedErrors([1, 0, 4, "Line"]) + }, + { + code: unIndent` + { + let foo + + // comment + + ;(async () => {})() + + } + `, + output: unIndent` + { + let foo + + // comment + + ;(async () => {})() + + } + `, + errors: expectedErrors([4, 4, 8, "Line"]) + }, + { + code: unIndent` + { + let foo + // comment + ;(async () => {})() + + } + `, + output: unIndent` + { + let foo + // comment + ;(async () => {})() + + } + `, + errors: expectedErrors([3, 4, 8, "Line"]) + }, + { + code: unIndent` + { + let foo + + /* comment */; + + (async () => {})() + + } + `, + output: unIndent` + { + let foo + + /* comment */; + + (async () => {})() + + } + `, + errors: expectedErrors([4, 8, 4, "Block"]) + }, + { + code: unIndent` + const foo = 1 + const bar = foo + + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + `, + output: unIndent` + const foo = 1 + const bar = foo + + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + `, + errors: expectedErrors([4, 0, 4, "Block"]) + }, + { + code: unIndent` + const foo = 1 + const bar = foo + /* comment */ + ;[1, 2, 3].forEach(() => {}) + `, + output: unIndent` + const foo = 1 + const bar = foo + /* comment */ + ;[1, 2, 3].forEach(() => {}) + `, + errors: expectedErrors([3, 0, 4, "Block"]) + }, + { + code: unIndent` + const foo = 1 + const bar = foo + + /* comment */; + + [1, 2, 3].forEach(() => {}) + `, + output: unIndent` + const foo = 1 + const bar = foo + + /* comment */; + + [1, 2, 3].forEach(() => {}) + `, + errors: expectedErrors([4, 4, 0, "Block"]) + }, + { + code: unIndent` + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + `, + output: unIndent` + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + `, + errors: expectedErrors([1, 0, 4, "Block"]) + }, + { + code: unIndent` + /* comment */ + ;[1, 2, 3].forEach(() => {}) + `, + output: unIndent` + /* comment */ + ;[1, 2, 3].forEach(() => {}) + `, + errors: expectedErrors([1, 0, 4, "Block"]) + }, + { + code: unIndent` + { + const foo = 1 + const bar = foo + + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + + } + `, + output: unIndent` + { + const foo = 1 + const bar = foo + + /* comment */ + + ;[1, 2, 3].forEach(() => {}) + + } + `, + errors: expectedErrors([5, 4, 8, "Block"]) + }, + { + code: unIndent` + { + const foo = 1 + const bar = foo + /* comment */ + ;[1, 2, 3].forEach(() => {}) + + } + `, + output: unIndent` + { + const foo = 1 + const bar = foo + /* comment */ + ;[1, 2, 3].forEach(() => {}) + + } + `, + errors: expectedErrors([4, 4, 8, "Block"]) + }, + { + code: unIndent` + { + const foo = 1 + const bar = foo + + /* comment */; + + [1, 2, 3].forEach(() => {}) + + } + `, + output: unIndent` + { + const foo = 1 + const bar = foo + + /* comment */; + + [1, 2, 3].forEach(() => {}) + + } + `, + errors: expectedErrors([5, 8, 4, "Block"]) + }, // import expressions { From f826eabbeecddb047f58f4e7308a14c18148d369 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 02:46:16 +0200 Subject: [PATCH 16/26] Fix: Allow line comment exception in object-curly-spacing (fixes #11902) (#12216) --- lib/rules/object-curly-spacing.js | 2 +- tests/lib/rules/object-curly-spacing.js | 108 ++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/lib/rules/object-curly-spacing.js b/lib/rules/object-curly-spacing.js index 079cf5707db..48a7dd953b7 100644 --- a/lib/rules/object-curly-spacing.js +++ b/lib/rules/object-curly-spacing.js @@ -167,7 +167,7 @@ module.exports = { if (options.spaced && !firstSpaced) { reportRequiredBeginningSpace(node, first); } - if (!options.spaced && firstSpaced) { + if (!options.spaced && firstSpaced && second.type !== "Line") { reportNoBeginningSpace(node, first); } } diff --git a/tests/lib/rules/object-curly-spacing.js b/tests/lib/rules/object-curly-spacing.js index 156bdb363b2..305ae28314e 100644 --- a/tests/lib/rules/object-curly-spacing.js +++ b/tests/lib/rules/object-curly-spacing.js @@ -26,6 +26,8 @@ ruleTester.run("object-curly-spacing", rule, { { code: "var obj = { foo: bar, baz: qux };", options: ["always"] }, { code: "var obj = { foo: { bar: quxx }, baz: qux };", options: ["always"] }, { code: "var obj = {\nfoo: bar,\nbaz: qux\n};", options: ["always"] }, + { code: "var obj = { /**/foo:bar/**/ };", options: ["always"] }, + { code: "var obj = { //\nfoo:bar };", options: ["always"] }, // always - destructuring { code: "var { x } = y", options: ["always"], parserOptions: { ecmaVersion: 6 } }, @@ -33,6 +35,8 @@ ruleTester.run("object-curly-spacing", rule, { { code: "var { x,y } = y", options: ["always"], parserOptions: { ecmaVersion: 6 } }, { code: "var {\nx,y } = y", options: ["always"], parserOptions: { ecmaVersion: 6 } }, { code: "var {\nx,y\n} = z", options: ["always"], parserOptions: { ecmaVersion: 6 } }, + { code: "var { /**/x/**/ } = y", options: ["always"], parserOptions: { ecmaVersion: 6 } }, + { code: "var { //\nx } = y", options: ["always"], parserOptions: { ecmaVersion: 6 } }, { code: "var { x = 10, y } = y", options: ["always"], parserOptions: { ecmaVersion: 6 } }, { code: "var { x: { z }, y } = y", options: ["always"], parserOptions: { ecmaVersion: 6 } }, { code: "var {\ny,\n} = x", options: ["always"], parserOptions: { ecmaVersion: 6 } }, @@ -44,6 +48,8 @@ ruleTester.run("object-curly-spacing", rule, { { code: "import * as door from 'room'", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "import { door } from 'room'", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "import {\ndoor } from 'room'", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "import { /**/door/**/ } from 'room'", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "import { //\ndoor } from 'room'", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "export { door } from 'room'", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "import { house, mouse } from 'caravan'", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "import house, { mouse } from 'caravan'", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, @@ -55,6 +61,10 @@ ruleTester.run("object-curly-spacing", rule, { { code: "import {\nx,\n} from 'foo';", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "export { x, } from 'foo';", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "export {\nx,\n} from 'foo';", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "export { /**/x/**/ } from 'foo';", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "export { //\nx } from 'foo';", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "var x = 1;\nexport { /**/x/**/ };", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "var x = 1;\nexport { //\nx };", options: ["always"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, // always - empty object { code: "var foo = {};", options: ["always"] }, @@ -86,6 +96,8 @@ ruleTester.run("object-curly-spacing", rule, { { code: "var obj = {\nfoo: bar,\nbaz: qux\n};", options: ["never"] }, { code: "var obj = {foo: bar, baz: qux /* */};", options: ["never"] }, { code: "var obj = {/* */ foo: bar, baz: qux};", options: ["never"] }, + { code: "var obj = {//\n foo: bar};", options: ["never"] }, + { code: "var obj = { // line comment exception\n foo: bar};", options: ["never"] }, // never - destructuring { code: "var {x} = y", options: ["never"], parserOptions: { ecmaVersion: 6 } }, @@ -101,6 +113,8 @@ ruleTester.run("object-curly-spacing", rule, { { code: "var {y:x} = x", options: ["never"], parserOptions: { ecmaVersion: 6 } }, { code: "var {/* */ y} = x", options: ["never"], parserOptions: { ecmaVersion: 6 } }, { code: "var {y /* */} = x", options: ["never"], parserOptions: { ecmaVersion: 6 } }, + { code: "var {//\n y} = x", options: ["never"], parserOptions: { ecmaVersion: 6 } }, + { code: "var { // line comment exception\n y} = x", options: ["never"], parserOptions: { ecmaVersion: 6 } }, // never - import / export { code: "import door from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, @@ -111,6 +125,12 @@ ruleTester.run("object-curly-spacing", rule, { { code: "export {/* */ door} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "import {door /* */} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "export {door /* */} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "import {//\n door} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "export {//\n door} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "var door = foo;\nexport {//\n door}", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "import { // line comment exception\n door} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "export { // line comment exception\n door} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, + { code: "var door = foo; export { // line comment exception\n door}", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "import {\ndoor} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "export {\ndoor\n} from 'room'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, { code: "import {house,mouse} from 'caravan'", options: ["never"], parserOptions: { ecmaVersion: 6, sourceType: "module" } }, @@ -271,6 +291,20 @@ ruleTester.run("object-curly-spacing", rule, { } ] }, + { + code: "import x, {//\n bar } from 'foo';", + output: "import x, { //\n bar } from 'foo';", + options: ["always"], + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "A space is required after '{'.", + type: "ImportDeclaration", + line: 1, + column: 11 + } + ] + }, { code: "import x, { bar, baz} from 'foo';", output: "import x, { bar, baz } from 'foo';", @@ -408,6 +442,40 @@ ruleTester.run("object-curly-spacing", rule, { } ] }, + { + code: "var bar = 0;\nexport {/* */ bar /* */};", + output: "var bar = 0;\nexport { /* */ bar /* */ };", + options: ["always"], + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "A space is required after '{'.", + type: "ExportNamedDeclaration", + line: 2, + column: 8 + }, + { + message: "A space is required before '}'.", + type: "ExportNamedDeclaration", + line: 2, + column: 24 + } + ] + }, + { + code: "var bar = 0;\nexport {//\n bar };", + output: "var bar = 0;\nexport { //\n bar };", + options: ["always"], + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + errors: [ + { + message: "A space is required after '{'.", + type: "ExportNamedDeclaration", + line: 2, + column: 8 + } + ] + }, { code: "var bar = 0;\nexport { /* */ bar /* */ };", output: "var bar = 0;\nexport {/* */ bar /* */};", @@ -619,6 +687,19 @@ ruleTester.run("object-curly-spacing", rule, { } ] }, + { + code: "var obj = {//\n foo: bar };", + output: "var obj = { //\n foo: bar };", + options: ["always"], + errors: [ + { + message: "A space is required after '{'.", + type: "ObjectExpression", + line: 1, + column: 11 + } + ] + }, { code: "var obj = { foo: bar, baz: qux};", output: "var obj = { foo: bar, baz: qux };", @@ -716,6 +797,19 @@ ruleTester.run("object-curly-spacing", rule, { } ] }, + { + code: "var obj = { // line comment exception\n foo: bar };", + output: "var obj = { // line comment exception\n foo: bar};", + options: ["never"], + errors: [ + { + message: "There should be no space before '}'.", + type: "ObjectExpression", + line: 2, + column: 11 + } + ] + }, { code: "var obj = { foo: { bar: quxx}, baz: qux};", output: "var obj = {foo: {bar: quxx}, baz: qux};", @@ -832,6 +926,20 @@ ruleTester.run("object-curly-spacing", rule, { } ] }, + { + code: "var {//\n x } = y", + output: "var { //\n x } = y", + options: ["always"], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + message: "A space is required after '{'.", + type: "ObjectPattern", + line: 1, + column: 5 + } + ] + }, { code: "var { x, y } = y", output: "var {x, y} = y", From 520c92270eed6e90c1a796e8af275980f01705e0 Mon Sep 17 00:00:00 2001 From: Henrique Barcelos Date: Fri, 13 Sep 2019 21:49:55 -0300 Subject: [PATCH 17/26] Docs: Added naming convention details to plugin usage (#12202) * Docs: Added naming convention details user guide Added clarification about the answer regarding #12190. * Docs: reverted markdown list style to the original --- docs/developer-guide/working-with-plugins.md | 2 +- docs/user-guide/configuring.md | 65 ++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/docs/developer-guide/working-with-plugins.md b/docs/developer-guide/working-with-plugins.md index 5a8fd764b38..a2b238cc936 100644 --- a/docs/developer-guide/working-with-plugins.md +++ b/docs/developer-guide/working-with-plugins.md @@ -1,6 +1,6 @@ # Working with Plugins -Each plugin is an npm module with a name in the format of `eslint-plugin-`, such as `eslint-plugin-jquery`. You can also use scoped packages in the format of `@/eslint-plugin-` such as `@jquery/eslint-plugin-jquery`. +Each plugin is an npm module with a name in the format of `eslint-plugin-`, such as `eslint-plugin-jquery`. You can also use scoped packages in the format of `@/eslint-plugin-` such as `@jquery/eslint-plugin-jquery` or even `@/eslint-plugin` such as `@jquery/eslint-plugin`. ## Create a Plugin diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md index 0818f85e2a5..8f5fd286d3a 100644 --- a/docs/user-guide/configuring.md +++ b/docs/user-guide/configuring.md @@ -323,6 +323,71 @@ And in YAML: **Note:** Plugins are resolved relative to the current working directory of the ESLint process. In other words, ESLint will load the same plugin as a user would obtain by running `require('eslint-plugin-pluginname')` in a Node REPL from their project root. +### Naming Convention + +#### Include a Plugin + +The `eslint-plugin-` prefix can be omitted for non-scoped packages + +```js +{ + // ... + "plugins": [ + "jquery", // means eslint-plugin-jquery + ] + // ... +} +``` + +The same rule does apply to scoped packages: + +```js +{ + // ... + "plugins": [ + "@jquery/jquery", // means @jquery/eslint-plugin-jquery + "@foobar" // means @foobar/eslint-plugin + ] + // ... +} +``` + +#### Use a Plugin + +When using rules, environments or configs defined by plugins, they must be referenced following the convention: + +* `eslint-plugin-foo` → `foo/a-rule` +* `@foo/eslint-plugin` → `@foo/a-config` +* `@foo/eslint-plugin-bar` → `@foo/bar/a-environment` + +For example: + +```js +{ + // ... + "plugins": [ + "jquery", // eslint-plugin-jquery + "@foo/foo", // @foo/eslint-plugin-foo + "@bar" // @bar/eslint-plugin + ], + "extends": [ + "plugin:@foo/foo/recommended", + "plugin:@bar/recommended" + ], + "rules": [ + "jquery/a-rule": "error", + "@foo/foo/some-rule": "error", + "@bar/another-rule": "error" + ], + "env": { + "jquery/jquery": true, + "@foo/foo/env-foo": true, + "@bar/env-bar": true, + } + // ... +} +``` + ## Configuring Rules ESLint comes with a large number of rules. You can modify which rules your project uses either using configuration comments or configuration files. To change a rule setting, you must set the rule ID equal to one of these values: From 1ee61b06715fcc750be2c923034a1e59ba663287 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 02:52:55 +0200 Subject: [PATCH 18/26] Update: enforceForClassMembers computed-property-spacing (fixes #12049) (#12214) --- docs/rules/computed-property-spacing.md | 55 ++- lib/rules/computed-property-spacing.js | 19 +- tests/lib/rules/computed-property-spacing.js | 438 ++++++++++++++++++- 3 files changed, 508 insertions(+), 4 deletions(-) diff --git a/docs/rules/computed-property-spacing.md b/docs/rules/computed-property-spacing.md index 89b1c775e06..9641ee089e5 100644 --- a/docs/rules/computed-property-spacing.md +++ b/docs/rules/computed-property-spacing.md @@ -25,11 +25,17 @@ This rule does not apply to brackets that are separated from the adjacent value ## Options -This rule has a string option: +This rule has two options, a string option and an object option. + +String option: * `"never"` (default) disallows spaces inside computed property brackets * `"always"` requires one or more spaces inside computed property brackets +Object option: + +* `"enforceForClassMembers": true` additionally applies this rule to class members (default is `false`) + ### never Examples of **incorrect** code for this rule with the default `"never"` option: @@ -84,6 +90,53 @@ var x = {[ b ]: a} obj[ foo[ bar ] ] ``` +#### enforceForClassMembers + +By default, this rule does not check class declarations and class expressions, +as the default value for `enforceForClassMembers` is `false`. + +When `enforceForClassMembers` is set to `true`, the rule will also disallow/enforce spaces inside of +computed keys of class methods, getters and setters. + +Examples of **incorrect** code for this rule with `"never"` and `{ "enforceForClassMembers": true }`: + +```js +/*eslint computed-property-spacing: ["error", "never", { "enforceForClassMembers": true }]*/ +/*eslint-env es6*/ + +class Foo { + [a ]() {} + get [b ]() {} + set [b ](value) {} +} + +const Bar = class { + [ a](){} + static [ b]() {} + static get [ c ]() {} + static set [ c ](value) {} +} +``` + +Examples of **correct** code for this rule with `"never"` and `{ "enforceForClassMembers": true }`: + +```js +/*eslint computed-property-spacing: ["error", "never", { "enforceForClassMembers": true }]*/ +/*eslint-env es6*/ + +class Foo { + [a]() {} + get [b]() {} + set [b](value) {} +} + +const Bar = class { + [a](){} + static [b]() {} + static get [c]() {} + static set [c](value) {} +} +``` ## When Not To Use It diff --git a/lib/rules/computed-property-spacing.js b/lib/rules/computed-property-spacing.js index 91b7d28963f..33f7c9401a9 100644 --- a/lib/rules/computed-property-spacing.js +++ b/lib/rules/computed-property-spacing.js @@ -26,6 +26,16 @@ module.exports = { schema: [ { enum: ["always", "never"] + }, + { + type: "object", + properties: { + enforceForClassMembers: { + type: "boolean", + default: false + } + }, + additionalProperties: false } ], @@ -41,6 +51,7 @@ module.exports = { create(context) { const sourceCode = context.getSourceCode(); const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" + const enforceForClassMembers = context.options[1] && context.options[1].enforceForClassMembers; //-------------------------------------------------------------------------- // Helpers @@ -178,10 +189,16 @@ module.exports = { // Public //-------------------------------------------------------------------------- - return { + const listeners = { Property: checkSpacing("key"), MemberExpression: checkSpacing("property") }; + if (enforceForClassMembers) { + listeners.MethodDefinition = checkSpacing("key"); + } + + return listeners; + } }; diff --git a/tests/lib/rules/computed-property-spacing.js b/tests/lib/rules/computed-property-spacing.js index fa1ca38f48a..3901d8c3fb3 100644 --- a/tests/lib/rules/computed-property-spacing.js +++ b/tests/lib/rules/computed-property-spacing.js @@ -72,7 +72,118 @@ ruleTester.run("computed-property-spacing", rule, { // never - unrelated cases { code: "var foo = {};", options: ["never"] }, - { code: "var foo = [];", options: ["never"] } + { code: "var foo = [];", options: ["never"] }, + + //------------------------------------------------------------------------------ + // Classes + //------------------------------------------------------------------------------ + + // test default settings + { + code: "class A { [ a ](){} }", + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["never"], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["never", {}], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [a](){} }", + options: ["always"], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [a](){} get [b](){} set [c](foo){} static [d](){} static get [e](){} static set [f](bar){} }", + options: ["always"], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a](){} get [b](){} set [c](foo){} static [d](){} static get [e](){} static set [f](bar){} }", + options: ["always", {}], + parserOptions: { ecmaVersion: 6 } + }, + + // explicitly disabled option + { + code: "class A { [ a ](){} }", + options: ["never", { enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["never", { enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [a](){} }", + options: ["always", { enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a](){} get [b](){} set [b](foo){} static [c](){} static get [d](){} static set [d](bar){} }", + options: ["always", { enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + + // valid spacing + { + code: "A = class { [a](){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a] ( ) { } }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [ \n a \n ](){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a](){} get [b](){} set [b](foo){} static [c](){} static get [d](){} static set [d](bar){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [ a ](){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [ a ](){}[ b ](){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [\na\n](){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // non-computed + { + code: "class A { a ( ) { } get b(){} set b ( foo ){} static c (){} static get d() {} static set d( bar ) {} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class {a(){}get b(){}set b(foo){}static c(){}static get d(){}static set d(bar){}}", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + } ], invalid: [ @@ -322,7 +433,330 @@ ruleTester.run("computed-property-spacing", rule, { line: 1 } ] - } + }, + + //------------------------------------------------------------------------------ + // Classes + //------------------------------------------------------------------------------ + + // never + { + code: "class A { [ a](){} }", + output: "class A { [a](){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 11, + line: 1 + } + ] + }, + { + code: "A = class { [a](){} b(){} static [c ](){} static [d](){}}", + output: "A = class { [a](){} b(){} static [c](){} static [d](){}}", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 37, + line: 1 + } + ] + }, + { + code: "class A { get [a ](){} set [ a](foo){} get b(){} static set b(bar){} static get [ a](){} static set [a ](baz){} }", + output: "class A { get [a](){} set [a](foo){} get b(){} static set b(bar){} static get [a](){} static set [a](baz){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 18, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 28, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 81, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 104, + line: 1 + } + ] + }, + { + code: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + output: "A = class { [a](){} get [b](){} set [c](foo){} static [d](){} static get [e](){} static set [f](bar){} }", + options: ["never", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 13, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 17, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 27, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 31, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 41, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 45, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 61, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 65, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 82, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 86, + line: 1 + }, + { + messageId: "unexpectedSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 103, + line: 1 + }, + { + messageId: "unexpectedSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 107, + line: 1 + } + ] + }, + // always + { + code: "class A { [ a](){} }", + output: "class A { [ a ](){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 14, + line: 1 + } + ] + }, + { + code: "A = class { [ a ](){} b(){} static [c ](){} static [ d ](){}}", + output: "A = class { [ a ](){} b(){} static [ c ](){} static [ d ](){}}", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 36, + line: 1 + } + ] + }, + { + code: "class A { get [a ](){} set [ a](foo){} get b(){} static set b(bar){} static get [ a](){} static set [a ](baz){} }", + output: "class A { get [ a ](){} set [ a ](foo){} get b(){} static set b(bar){} static get [ a ](){} static set [ a ](baz){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 15, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 31, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 84, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 101, + line: 1 + } + ] + }, + { + code: "A = class { [a](){} get [b](){} set [c](foo){} static [d](){} static get [e](){} static set [f](bar){} }", + output: "A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }", + options: ["always", { enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 13, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 15, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 25, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 27, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 37, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 39, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 55, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 57, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 74, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 76, + line: 1 + }, + { + messageId: "missingSpaceAfter", + data: { tokenValue: "[" }, + type: "MethodDefinition", + column: 93, + line: 1 + }, + { + messageId: "missingSpaceBefore", + data: { tokenValue: "]" }, + type: "MethodDefinition", + column: 95, + line: 1 + } + ] + } ] }); From b2498d284b9c30ed1543429c2f45d9014e12fe22 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 03:01:59 +0200 Subject: [PATCH 19/26] Update: Fix handling of property names in no-self-assign (#12105) --- lib/rules/no-self-assign.js | 11 ++++++----- tests/lib/rules/no-self-assign.js | 11 +++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/rules/no-self-assign.js b/lib/rules/no-self-assign.js index dc8bf90147b..6ebd1925e49 100644 --- a/lib/rules/no-self-assign.js +++ b/lib/rules/no-self-assign.js @@ -152,13 +152,14 @@ function eachSelfAssignment(left, right, props, report) { } else if ( left.type === "Property" && right.type === "Property" && - !left.computed && - !right.computed && right.kind === "init" && - !right.method && - left.key.name === right.key.name + !right.method ) { - eachSelfAssignment(left.value, right.value, props, report); + const leftName = astUtils.getStaticPropertyName(left); + + if (leftName !== null && leftName === astUtils.getStaticPropertyName(right)) { + eachSelfAssignment(left.value, right.value, props, report); + } } else if ( props && left.type === "MemberExpression" && diff --git a/tests/lib/rules/no-self-assign.js b/tests/lib/rules/no-self-assign.js index fbf52dcba0e..4e168a89789 100644 --- a/tests/lib/rules/no-self-assign.js +++ b/tests/lib/rules/no-self-assign.js @@ -41,6 +41,8 @@ ruleTester.run("no-self-assign", rule, { { code: "({a} = {a: b})", parserOptions: { ecmaVersion: 6 } }, { code: "({a} = {a() {}})", parserOptions: { ecmaVersion: 6 } }, { code: "({a} = {[a]: a})", parserOptions: { ecmaVersion: 6 } }, + { code: "({[a]: b} = {[a]: b})", parserOptions: { ecmaVersion: 6 } }, + { code: "({'foo': a, 1: a} = {'bar': a, 2: a})", parserOptions: { ecmaVersion: 6 } }, { code: "({a, ...b} = {a, ...b})", parserOptions: { ecmaVersion: 2018 } }, { code: "a.b = a.c", options: [{ props: true }] }, { code: "a.b = c.b", options: [{ props: true }] }, @@ -80,6 +82,15 @@ ruleTester.run("no-self-assign", rule, { { code: "[[a], {b}] = [[a], {b}]", parserOptions: { ecmaVersion: 6 }, errors: ["'a' is assigned to itself.", "'b' is assigned to itself."] }, { code: "({a} = {a})", parserOptions: { ecmaVersion: 6 }, errors: ["'a' is assigned to itself."] }, { code: "({a: b} = {a: b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({'a': b} = {'a': b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({a: b} = {'a': b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({'a': b} = {a: b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({1: b} = {1: b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({1: b} = {'1': b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({'1': b} = {1: b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({['a']: b} = {a: b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({'a': b} = {[`a`]: b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, + { code: "({1: b} = {[1]: b})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself."] }, { code: "({a, b} = {a, b})", parserOptions: { ecmaVersion: 6 }, errors: ["'a' is assigned to itself.", "'b' is assigned to itself."] }, { code: "({a, b} = {b, a})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself.", "'a' is assigned to itself."] }, { code: "({a, b} = {c, a})", parserOptions: { ecmaVersion: 6 }, errors: ["'a' is assigned to itself."] }, From d3c2334646eae9287d5be9e457d041e445efb512 Mon Sep 17 00:00:00 2001 From: David Waller Date: Sat, 14 Sep 2019 03:03:56 +0200 Subject: [PATCH 20/26] Update: flag nested block with declaration as error (#12193) --- lib/rules/no-lone-blocks.js | 7 +++++- tests/lib/rules/no-lone-blocks.js | 36 ++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/rules/no-lone-blocks.js b/lib/rules/no-lone-blocks.js index 6b51795863b..4365b047861 100644 --- a/lib/rules/no-lone-blocks.js +++ b/lib/rules/no-lone-blocks.js @@ -79,7 +79,7 @@ module.exports = { } }; - // ES6: report blocks without block-level bindings + // ES6: report blocks without block-level bindings, or that's only child of another block if (context.parserOptions.ecmaVersion >= 6) { ruleDef = { BlockStatement(node) { @@ -91,6 +91,11 @@ module.exports = { if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) { loneBlocks.pop(); report(node); + } else if ( + node.parent.type === "BlockStatement" && + node.parent.body.length === 1 + ) { + report(node); } } }; diff --git a/tests/lib/rules/no-lone-blocks.js b/tests/lib/rules/no-lone-blocks.js index 3640a10127f..139e24c9d04 100644 --- a/tests/lib/rules/no-lone-blocks.js +++ b/tests/lib/rules/no-lone-blocks.js @@ -56,7 +56,8 @@ ruleTester.run("no-lone-blocks", rule, { baz; } } - ` + `, + { code: "function foo() { { const x = 4 } const x = 3 }", parserOptions: { ecmaVersion: 6 } } ], invalid: [ { code: "{}", errors: [{ message: "Block is redundant.", type: "BlockStatement" }] }, @@ -118,6 +119,39 @@ ruleTester.run("no-lone-blocks", rule, { } `, errors: [{ message: "Block is redundant.", type: "BlockStatement", line: 4 }] + }, + { + code: ` + function foo () { + { + const x = 4; + } + } + `, + parserOptions: { ecmaVersion: 6 }, + errors: [ + { + message: "Nested block is redundant.", + type: "BlockStatement", + line: 3 + } + ] + }, + { + code: ` + function foo () { + { + var x = 4; + } + } + `, + errors: [ + { + message: "Nested block is redundant.", + type: "BlockStatement", + line: 3 + } + ] } ] }); From 540296fcecd232a09dc873a5a22f5839b59b7842 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 14 Sep 2019 03:04:18 +0200 Subject: [PATCH 21/26] Update: enforceForClassMembers option to accessor-pairs (fixes #12063) (#12192) --- docs/rules/accessor-pairs.md | 65 ++- lib/rules/accessor-pairs.js | 62 +- tests/lib/rules/accessor-pairs.js | 925 +++++++++++++++++++++++++++++- 3 files changed, 1034 insertions(+), 18 deletions(-) diff --git a/docs/rules/accessor-pairs.md b/docs/rules/accessor-pairs.md index 183bc42b6e6..43a14cc18b6 100644 --- a/docs/rules/accessor-pairs.md +++ b/docs/rules/accessor-pairs.md @@ -1,4 +1,4 @@ -# Enforces getter/setter pairs in objects (accessor-pairs) +# Enforces getter/setter pairs in objects and classes (accessor-pairs) It's a common mistake in JavaScript to create an object with just a setter for a property but never have a corresponding getter defined for it. Without a getter, you cannot read the property, so it ends up not being used. @@ -32,10 +32,14 @@ This rule enforces a style where it requires to have a getter for every property By activating the option `getWithoutSet` it enforces the presence of a setter for every property which has a getter defined. +By default, this rule checks only object literals and property descriptors. If you want this rule +to also check class declarations and class expressions, activate the option `enforceForClassMembers`. + ## Options * `setWithoutGet` set to `true` will warn for setters without getters (Default `true`). * `getWithoutSet` set to `true` will warn for getters without setters (Default `false`). +* `enforceForClassMembers` set to `true` additionally applies this rule to class getters/setters (Default `false`). ### setWithoutGet @@ -143,6 +147,61 @@ Object.defineProperty(o, 'c', { ``` +### enforceForClassMembers + +By default, this rule does not enforce getter/setter pairs in class declarations and class expressions, +as the default value for `enforceForClassMembers` is `false`. + +When `enforceForClassMembers` is set to `true`: + +* `"getWithoutSet": true` will also warn for getters without setters in classes. +* `"setWithoutGet": true` will also warn for setters without getters in classes. + +Examples of **incorrect** code for `{ "getWithoutSet": true, "enforceForClassMembers": true }`: + +```js +/*eslint accessor-pairs: ["error", { "getWithoutSet": true, "enforceForClassMembers": true }]*/ + +class Foo { + get a() { + return this.val; + } +} + +class Bar { + static get a() { + return this.val; + } +} + +const Baz = class { + get a() { + return this.val; + } + static set a(value) { + this.val = value; + } +} +``` + +Examples of **incorrect** code for `{ "setWithoutGet": true, "enforceForClassMembers": true }`: + +```js +/*eslint accessor-pairs: ["error", { "setWithoutGet": true, "enforceForClassMembers": true }]*/ + +class Foo { + set a(value) { + this.val = value; + } +} + +const Bar = class { + static set a(value) { + this.val = value; + } +} +``` + ## Known Limitations Due to the limits of static analysis, this rule does not account for possible side effects and in certain cases @@ -164,7 +223,7 @@ var o = { }; ``` -Also, this rule does not disallow duplicate keys in object literals, and in certain cases with duplicate keys +Also, this rule does not disallow duplicate keys in object literals and class definitions, and in certain cases with duplicate keys might not report a missing pair for a getter/setter, like in the following example: ```js @@ -186,6 +245,8 @@ The code above creates an object with just a setter for the property `"a"`. See [no-dupe-keys](no-dupe-keys.md) if you also want to disallow duplicate keys in object literals. +See [no-dupe-class-members](no-dupe-class-members.md) if you also want to disallow duplicate names in class definitions. + ## When Not To Use It You can turn this rule off if you are not concerned with the simultaneous presence of setters and getters on objects. diff --git a/lib/rules/accessor-pairs.js b/lib/rules/accessor-pairs.js index 9c78bdc70e0..a33d1f32f2e 100644 --- a/lib/rules/accessor-pairs.js +++ b/lib/rules/accessor-pairs.js @@ -152,7 +152,7 @@ module.exports = { type: "suggestion", docs: { - description: "enforce getter and setter pairs in objects", + description: "enforce getter and setter pairs in objects and classes", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/accessor-pairs" @@ -168,6 +168,10 @@ module.exports = { setWithoutGet: { type: "boolean", default: true + }, + enforceForClassMembers: { + type: "boolean", + default: false } }, additionalProperties: false @@ -177,13 +181,16 @@ module.exports = { missingGetterInPropertyDescriptor: "Getter is not present in property descriptor.", missingSetterInPropertyDescriptor: "Setter is not present in property descriptor.", missingGetterInObjectLiteral: "Getter is not present for {{ name }}.", - missingSetterInObjectLiteral: "Setter is not present for {{ name }}." + missingSetterInObjectLiteral: "Setter is not present for {{ name }}.", + missingGetterInClass: "Getter is not present for class {{ name }}.", + missingSetterInClass: "Setter is not present for class {{ name }}." } }, create(context) { const config = context.options[0] || {}; const checkGetWithoutSet = config.getWithoutSet === true; const checkSetWithoutGet = config.setWithoutGet !== false; + const enforceForClassMembers = config.enforceForClassMembers === true; const sourceCode = context.getSourceCode(); /** @@ -201,6 +208,13 @@ module.exports = { loc: astUtils.getFunctionHeadLoc(node.value, sourceCode), data: { name: astUtils.getFunctionNameWithKind(node.value) } }); + } else if (node.type === "MethodDefinition") { + context.report({ + node, + messageId: `${messageKind}InClass`, + loc: astUtils.getFunctionHeadLoc(node.value, sourceCode), + data: { name: astUtils.getFunctionNameWithKind(node.value) } + }); } else { context.report({ node, @@ -313,15 +327,41 @@ module.exports = { } } - return { - ObjectExpression(node) { - if (checkSetWithoutGet || checkGetWithoutSet) { - checkObjectLiteral(node); - if (isPropertyDescriptor(node)) { - checkPropertyDescriptor(node); - } - } + /** + * Checks the given object expression as an object literal and as a possible property descriptor. + * @param {ASTNode} node `ObjectExpression` node to check. + * @returns {void} + * @private + */ + function checkObjectExpression(node) { + checkObjectLiteral(node); + if (isPropertyDescriptor(node)) { + checkPropertyDescriptor(node); } - }; + } + + /** + * Checks the given class body. + * @param {ASTNode} node `ClassBody` node to check. + * @returns {void} + * @private + */ + function checkClassBody(node) { + const methodDefinitions = node.body.filter(m => m.type === "MethodDefinition"); + + checkList(methodDefinitions.filter(m => m.static)); + checkList(methodDefinitions.filter(m => !m.static)); + } + + const listeners = {}; + + if (checkSetWithoutGet || checkGetWithoutSet) { + listeners.ObjectExpression = checkObjectExpression; + if (enforceForClassMembers) { + listeners.ClassBody = checkClassBody; + } + } + + return listeners; } }; diff --git a/tests/lib/rules/accessor-pairs.js b/tests/lib/rules/accessor-pairs.js index 4f55cd10eb7..c647a37f3a0 100644 --- a/tests/lib/rules/accessor-pairs.js +++ b/tests/lib/rules/accessor-pairs.js @@ -43,6 +43,10 @@ ruleTester.run("accessor-pairs", rule, { // Test default settings, this would be an error if `getWithoutSet` was set to `true` "var o = { get a() {} }", + { + code: "var o = { get a() {} }", + options: [{}] + }, // No accessors { @@ -319,7 +323,315 @@ ruleTester.run("accessor-pairs", rule, { "Object.create(null, {set: {value: function() {}}});", { code: "var o = {get: function() {}}", options: [{ getWithoutSet: true }] }, { code: "var o = {[set]: function() {}}", parserOptions: { ecmaVersion: 6 } }, - { code: "var set = 'value'; Object.defineProperty(obj, 'foo', {[set]: function(value) {}});", parserOptions: { ecmaVersion: 6 } } + { code: "var set = 'value'; Object.defineProperty(obj, 'foo', {[set]: function(value) {}});", parserOptions: { ecmaVersion: 6 } }, + + //------------------------------------------------------------------------------ + // Classes + //------------------------------------------------------------------------------ + + // Test default settings + { + code: "class A { set a(foo) {} }", + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get a() {} set b(foo) {} }", + options: [{}], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get a() {} }", + options: [{ enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { get a() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { get a() {} set b(foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // Explicitly disabled option + { + code: "class A { set a(foo) {} }", + options: [{ enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get a() {} set b(foo) {} static get c() {} static set d(bar) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "(class A { get a() {} set b(foo) {} static get c() {} static set d(bar) {} });", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: false }], + parserOptions: { ecmaVersion: 6 } + }, + + // Disabled accessor kind options + { + code: "class A { get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: false, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { set a(foo) {} }", + options: [{ setWithoutGet: false, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: false, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static set a(foo) {} }", + options: [{ setWithoutGet: false, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { set a(foo) {} };", + options: [{ setWithoutGet: false, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get a() {} set b(foo) {} static get c() {} static set d(bar) {} }", + options: [{ setWithoutGet: false, getWithoutSet: false, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // No accessors + { + code: "class A {}", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "(class {})", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { constructor () {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static a() {} 'b'() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { [a]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { a() {} static a() {} b() {} static c() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // Valid pairs with identifiers + { + code: "class A { get a() {} set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { set a(foo) {} get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static get a() {} static set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static set a(foo) {} static get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "(class { set a(foo) {} get a() {} });", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // Valid pairs with statically computed names + { + code: "class A { get 'a'() {} set ['a'](foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { set [`a`](foo) {} get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get 'a'() {} set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { static get 1e2() {} static set [100](foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // Valid pairs with expressions + { + code: "class A { get [a]() {} set [a](foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { set [(f())](foo) {} get [(f())]() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static set [f(a)](foo) {} static get [f(a)]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // Multiple valid pairs in the same class + { + code: "class A { get a() {} set b(foo) {} set a(bar) {} get b() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get a() {} set a(bar) {} b() {} set c(foo) {} get c() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "(class { get a() {} static set a(foo) {} set a(bar) {} static get a() {} });", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // Valid pairs with other elements + { + code: "class A { get a() {} b() {} set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { set a(foo) {} get a() {} b() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { a() {} get b() {} c() {} set b(foo) {} d() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get a() {} set a(foo) {} static a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { static get a() {} static b() {} static set a(foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { static set a(foo) {} static get a() {} a() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + // Duplicate keys. This is the responsibility of no-dupe-class-members, but this rule still checks if there is the other accessor kind. + { + code: "class A { get a() {} get a() {} set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get [a]() {} set [a](foo) {} set [a](foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { get a() {} set 'a'(foo) {} get [`a`]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { get a() {} set a(foo) {} a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "A = class { a() {} get a() {} set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static set a(foo) {} static set a(foo) {} static get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static get a() {} static set a(foo) {} static get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static set a(foo) {} static get a() {} static a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + + /* + * This code should be invalid by this rule because it creates a class with the setter only, while the getter is ignored. + * However, this edge case is not covered, it should be reported by no-dupe-class-members anyway. + */ + { + code: "class A { get a() {} a() {} set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class A { static set a(foo) {} static a() {} static get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 } + } ], invalid: [ @@ -333,6 +645,11 @@ ruleTester.run("accessor-pairs", rule, { code: "var o = { set a(value) {} };", errors: [{ message: "Getter is not present for setter 'a'.", type: "Property" }] }, + { + code: "var o = { set a(value) {} };", + options: [{}], + errors: [{ message: "Getter is not present for setter 'a'.", type: "Property" }] + }, // Test that the options do not affect each other { @@ -530,7 +847,7 @@ ruleTester.run("accessor-pairs", rule, { code: "var o = { get ''() {}, set ' '(foo) {} };", options: [{ setWithoutGet: true, getWithoutSet: true }], errors: [ - { messageId: "missingSetterInObjectLiteral", type: "Property", column: 11 }, // TODO: Change to message when getFunctionNameWithKind gets fixed + { message: "Setter is not present for getter ''.", type: "Property", column: 11 }, { message: "Getter is not present for setter ' '.", type: "Property", column: 24 } ] }, @@ -538,7 +855,7 @@ ruleTester.run("accessor-pairs", rule, { code: "var o = { get ''() {}, set null(foo) {} };", options: [{ setWithoutGet: true, getWithoutSet: true }], errors: [ - { messageId: "missingSetterInObjectLiteral", type: "Property", column: 11 }, // TODO: Change to message when getFunctionNameWithKind gets fixed + { message: "Setter is not present for getter ''.", type: "Property", column: 11 }, { message: "Getter is not present for setter 'null'.", type: "Property", column: 24 } ] }, @@ -766,7 +1083,6 @@ ruleTester.run("accessor-pairs", rule, { { code: "var o = { get a() {} };", options: [{ setWithoutGet: true, getWithoutSet: true }], - parserOptions: { ecmaVersion: 2018 }, errors: [{ message: "Setter is not present for getter 'a'.", type: "Property", @@ -779,7 +1095,7 @@ ruleTester.run("accessor-pairs", rule, { { code: "var o = {\n set [\n a](foo) {} };", options: [{ setWithoutGet: true, getWithoutSet: true }], - parserOptions: { ecmaVersion: 2018 }, + parserOptions: { ecmaVersion: 2015 }, errors: [{ message: "Getter is not present for setter.", type: "Property", @@ -809,6 +1125,605 @@ ruleTester.run("accessor-pairs", rule, { { code: "Object.create(null, {foo: {set: function(value) {}}});", errors: [{ message: "Getter is not present in property descriptor.", type: "ObjectExpression" }] + }, + + //------------------------------------------------------------------------------ + // Classes + //------------------------------------------------------------------------------ + + // Test default settings + { + code: "class A { set a(value) {} }", + options: [{ enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class setter 'a'.", type: "MethodDefinition" }] + }, + { + code: "class A { static set a(value) {} }", + options: [{ enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class static setter 'a'.", type: "MethodDefinition" }] + }, + { + code: "A = class { set a(value) {} };", + options: [{ enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class setter 'a'.", type: "MethodDefinition" }] + }, + { + code: "(class A { static set a(value) {} });", + options: [{ enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class static setter 'a'.", type: "MethodDefinition" }] + }, + + // Test that the accessor kind options do not affect each other + { + code: "class A { set a(value) {} }", + options: [{ setWithoutGet: true, getWithoutSet: false, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class setter 'a'.", type: "MethodDefinition" }] + }, + { + code: "A = class { static set a(value) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class static setter 'a'.", type: "MethodDefinition" }] + }, + { + code: "let foo = class A { get a() {} };", + options: [{ setWithoutGet: false, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter 'a'.", type: "MethodDefinition" }] + }, + { + code: "class A { static get a() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition" }] + }, + { + code: "(class { get a() {} });", + options: [{ getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter 'a'.", type: "MethodDefinition" }] + }, + + // Various kinds of keys + { + code: "class A { get abc() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter 'abc'.", type: "MethodDefinition" }] + }, + { + code: "A = class { static set 'abc'(foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class static setter 'abc'.", type: "MethodDefinition" }] + }, + { + code: "(class { get 123() {} });", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter '123'.", type: "MethodDefinition" }] + }, + { + code: "class A { static get 1e2() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class static getter '100'.", type: "MethodDefinition" }] + }, + { + code: "A = class { get ['abc']() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter 'abc'.", type: "MethodDefinition" }] + }, + { + code: "class A { set [`abc`](foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class setter 'abc'.", type: "MethodDefinition" }] + }, + { + code: "class A { static get [123]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class static getter '123'.", type: "MethodDefinition" }] + }, + { + code: "class A { get [abc]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter.", type: "MethodDefinition" }] + }, + { + code: "class A { static get [f(abc)]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class static getter.", type: "MethodDefinition" }] + }, + { + code: "A = class { set [a + b](foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class setter.", type: "MethodDefinition" }] + }, + { + code: "class A { get ['constructor']() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter 'constructor'.", type: "MethodDefinition" }] + }, + + // Different keys + { + code: "class A { get a() {} set b(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter 'b'.", type: "MethodDefinition", column: 22 } + ] + }, + { + code: "A = class { set a(foo) {} get b() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Setter is not present for class getter 'b'.", type: "MethodDefinition", column: 27 } + ] + }, + { + code: "A = class { static get a() {} static set b(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Getter is not present for class static setter 'b'.", type: "MethodDefinition", column: 31 } + ] + }, + { + code: "class A { get a() {} set b(foo) {} }", + options: [{ setWithoutGet: false, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 } + ] + }, + { + code: "class A { get a() {} set b(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: false, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class setter 'b'.", type: "MethodDefinition", column: 22 } + ] + }, + { + code: "class A { get 'a '() {} set 'a'(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a '.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 25 } + ] + }, + { + code: "class A { get 'a'() {} set 1(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter '1'.", type: "MethodDefinition", column: 24 } + ] + }, + { + code: "class A { get 1() {} set 2(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter '1'.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter '2'.", type: "MethodDefinition", column: 22 } + ] + }, + { + code: "class A { get ''() {} set null(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter ''.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter 'null'.", type: "MethodDefinition", column: 23 } + ] + }, + { + code: "class A { get a() {} set [a](foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter.", type: "MethodDefinition", column: 22 } + ] + }, + { + code: "class A { get [a]() {} set [b](foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter.", type: "MethodDefinition", column: 24 } + ] + }, + { + code: "class A { get [a]() {} set [a++](foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter.", type: "MethodDefinition", column: 24 } + ] + }, + { + code: "class A { get [a + b]() {} set [a - b](foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter.", type: "MethodDefinition", column: 28 } + ] + }, + + // Prototype and static accessors with same keys + { + code: "class A { get a() {} static set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class static setter 'a'.", type: "MethodDefinition", column: 22 } + ] + }, + { + code: "A = class { static get a() {} set a(foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 31 } + ] + }, + { + code: "class A { set [a](foo) {} static get [a]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class setter.", type: "MethodDefinition", column: 11 }, + { message: "Setter is not present for class static getter.", type: "MethodDefinition", column: 27 } + ] + }, + { + code: "class A { static set [a](foo) {} get [a]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class static setter.", type: "MethodDefinition", column: 11 }, + { message: "Setter is not present for class getter.", type: "MethodDefinition", column: 34 } + ] + }, + + // Multiple invalid of same and different kinds + { + code: "class A { get a() {} get b() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Setter is not present for class getter 'b'.", type: "MethodDefinition", column: 22 } + ] + }, + { + code: "A = class { get a() {} get [b]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Setter is not present for class getter.", type: "MethodDefinition", column: 24 } + ] + }, + { + code: "class A { get [a]() {} get [b]() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter.", type: "MethodDefinition", column: 11 }, + { message: "Setter is not present for class getter.", type: "MethodDefinition", column: 24 } + ] + }, + { + code: "A = class { set a(foo) {} set b(bar) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Getter is not present for class setter 'b'.", type: "MethodDefinition", column: 27 } + ] + }, + { + code: "class A { static get a() {} static get b() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Setter is not present for class static getter 'b'.", type: "MethodDefinition", column: 29 } + ] + }, + { + code: "A = class { static set a(foo) {} static set b(bar) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class static setter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Getter is not present for class static setter 'b'.", type: "MethodDefinition", column: 34 } + ] + }, + { + code: "class A { static get a() {} set b(foo) {} static set c(bar) {} get d() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter 'b'.", type: "MethodDefinition", column: 29 }, + { message: "Getter is not present for class static setter 'c'.", type: "MethodDefinition", column: 43 }, + { message: "Setter is not present for class getter 'd'.", type: "MethodDefinition", column: 64 } + ] + }, + + // Checks per class + { + code: "class A { get a() {} } class B { set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 34 } + ] + }, + { + code: "A = class { set a(foo) {} }, class { get a() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 38 } + ] + }, + { + code: "A = class { get a() {} }, { set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Getter is not present for setter 'a'.", type: "Property", column: 29 } + ] + }, + { + code: "A = { get a() {} }, class { set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for getter 'a'.", type: "Property", column: 7 }, + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 29 } + ] + }, + + // Combinations or valid and invalid + { + code: "class A { get a() {} get b() {} set b(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 }] + }, + { + code: "A = class { get b() {} get a() {} set b(foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 24 }] + }, + { + code: "class A { set b(foo) {} get b() {} set a(bar) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 36 }] + }, + { + code: "A = class { static get b() {} set a(foo) {} static set b(bar) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 31 }] + }, + { + code: "class A { static set a(foo) {} get b() {} set b(bar) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Getter is not present for class static setter 'a'.", type: "MethodDefinition", column: 11 }] + }, + { + code: "class A { get b() {} static get a() {} set b(bar) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 22 }] + }, + { + code: "class A { static set b(foo) {} static get a() {} static get b() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 32 }] + }, + { + code: "class A { get [v1](){} static set i1(foo){} static set v2(bar){} get [i2](){} static get i3(){} set [v1](baz){} static get v2(){} set i4(quux){} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class static setter 'i1'.", type: "MethodDefinition", column: 24 }, + { message: "Setter is not present for class getter.", type: "MethodDefinition", column: 66 }, + { message: "Setter is not present for class static getter 'i3'.", type: "MethodDefinition", column: 79 }, + { message: "Getter is not present for class setter 'i4'.", type: "MethodDefinition", column: 131 } + ] + }, + + // In the case of duplicates which don't have the other kind, all nodes are reported + { + code: "class A { get a() {} get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 22 } + ] + }, + { + code: "A = class { set a(foo) {} set a(foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 27 } + ] + }, + { + code: "A = class { static get a() {} static get a() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 13 }, + { message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 31 } + ] + }, + { + code: "class A { set a(foo) {} set a(foo) {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 11 }, + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 25 } + ] + }, + + // Other elements or even method duplicates in the same class do not affect this rule + { + code: "class A { a() {} get b() {} c() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'b'.", type: "MethodDefinition", column: 18 } + ] + }, + { + code: "A = class { a() {} get b() {} c() {} set d(foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'b'.", type: "MethodDefinition", column: 20 }, + { message: "Getter is not present for class setter 'd'.", type: "MethodDefinition", column: 38 } + ] + }, + { + code: "class A { static a() {} get b() {} static c() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'b'.", type: "MethodDefinition", column: 25 } + ] + }, + { + code: "class A { a() {} get a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class getter 'a'.", type: "MethodDefinition", column: 18 } + ] + }, + { + code: "A = class { static a() {} set a(foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class setter 'a'.", type: "MethodDefinition", column: 27 } + ] + }, + { + code: "class A { a() {} static get b() {} c() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class static getter 'b'.", type: "MethodDefinition", column: 18 } + ] + }, + { + code: "A = class { static a() {} static set b(foo) {} static c() {} d() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class static setter 'b'.", type: "MethodDefinition", column: 27 } + ] + }, + { + code: "class A { a() {} static get a() {} a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Setter is not present for class static getter 'a'.", type: "MethodDefinition", column: 18 } + ] + }, + { + code: "class A { static set a(foo) {} static a() {} }", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { message: "Getter is not present for class static setter 'a'.", type: "MethodDefinition", column: 11 } + ] + }, + + // Full location tests + { + code: "class A { get a() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ + message: "Setter is not present for class getter 'a'.", + type: "MethodDefinition", + line: 1, + column: 11, + endLine: 1, + endColumn: 16 + }] + }, + { + code: "A = class {\n set [\n a](foo) {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ + message: "Getter is not present for class setter.", + type: "MethodDefinition", + line: 2, + column: 3, + endLine: 3, + endColumn: 4 + }] + }, + { + code: "class A { static get a() {} };", + options: [{ setWithoutGet: true, getWithoutSet: true, enforceForClassMembers: true }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ + message: "Setter is not present for class static getter 'a'.", + type: "MethodDefinition", + line: 1, + column: 11, + endLine: 1, + endColumn: 23 + }] } ] }); From e915fffb6089a23ff1cae926cc607f9b87dc1819 Mon Sep 17 00:00:00 2001 From: Yuping Zuo Date: Sat, 14 Sep 2019 09:20:44 +0800 Subject: [PATCH 22/26] Docs: Improve examples and clarify default option (#12067) * Docs: Improve examples and clarify default option The "default" option is now set to `overrides` instead of `after` because examples in after may be misleading. A new incorrect example is added to `overrides` to clarify whether the overridden style can still be used. * Docs: Reformat operator-linebreak --- docs/rules/operator-linebreak.md | 60 ++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/docs/rules/operator-linebreak.md b/docs/rules/operator-linebreak.md index e2a69a1fdc6..3b1986e0fff 100644 --- a/docs/rules/operator-linebreak.md +++ b/docs/rules/operator-linebreak.md @@ -38,7 +38,7 @@ The default configuration is `"after", { "overrides": { "?": "before", ":": "bef ### after -Examples of **incorrect** code for this rule with the default `"after"` option: +Examples of **incorrect** code for this rule with the `"after"` option: ```js /*eslint operator-linebreak: ["error", "after"]*/ @@ -62,7 +62,7 @@ answer = everything : foo; ``` -Examples of **correct** code for this rule with the default `"after"` option: +Examples of **correct** code for this rule with the `"after"` option: ```js /*eslint operator-linebreak: ["error", "after"]*/ @@ -175,6 +175,16 @@ answer = everything ? 42 : foo; ### overrides +Examples of additional **incorrect** code for this rule with the `{ "overrides": { "+=": "before" } }` option: + +```js +/*eslint operator-linebreak: ["error", "after", { "overrides": { "+=": "before" } }]*/ + +var thing = 'thing'; +thing += + 's'; +``` + Examples of additional **correct** code for this rule with the `{ "overrides": { "+=": "before" } }` option: ```js @@ -201,6 +211,52 @@ answer = everything foo; ``` +Examples of **incorrect** code for this rule with the default `"after", { "overrides": { "?": "before", ":": "before" } }` option: + +```js +/*eslint operator-linebreak: ["error", "after", { "overrides": { "?": "before", ":": "before" } }]*/ + +foo = 1 ++ +2; + +foo = 1 + + 2; + +foo + = 5; + +if (someCondition + || otherCondition) { +} + +answer = everything ? + 42 : + foo; +``` + +Examples of **correct** code for this rule with the default `"after", { "overrides": { "?": "before", ":": "before" } }` option: + +```js +/*eslint operator-linebreak: ["error", "after", { "overrides": { "?": "before", ":": "before" } }]*/ + +foo = 1 + 2; + +foo = 1 + + 2; + +foo = + 5; + +if (someCondition || + otherCondition) { +} + +answer = everything + ? 42 + : foo; +``` + ## When Not To Use It If your project will not be using a common operator line break style, turn this rule off. From c847be230a28c1cf26e40a11077428ce7ee32fe3 Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Fri, 13 Sep 2019 21:35:30 -0400 Subject: [PATCH 23/26] Build: changelog update for 6.4.0 --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e35b145164..fd0313ef6f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ +v6.4.0 - September 13, 2019 + +* [`e915fff`](https://github.com/eslint/eslint/commit/e915fffb6089a23ff1cae926cc607f9b87dc1819) Docs: Improve examples and clarify default option (#12067) (Yuping Zuo) +* [`540296f`](https://github.com/eslint/eslint/commit/540296fcecd232a09dc873a5a22f5839b59b7842) Update: enforceForClassMembers option to accessor-pairs (fixes #12063) (#12192) (Milos Djermanovic) +* [`d3c2334`](https://github.com/eslint/eslint/commit/d3c2334646eae9287d5be9e457d041e445efb512) Update: flag nested block with declaration as error (#12193) (David Waller) +* [`b2498d2`](https://github.com/eslint/eslint/commit/b2498d284b9c30ed1543429c2f45d9014e12fe22) Update: Fix handling of property names in no-self-assign (#12105) (Milos Djermanovic) +* [`1ee61b0`](https://github.com/eslint/eslint/commit/1ee61b06715fcc750be2c923034a1e59ba663287) Update: enforceForClassMembers computed-property-spacing (fixes #12049) (#12214) (Milos Djermanovic) +* [`520c922`](https://github.com/eslint/eslint/commit/520c92270eed6e90c1a796e8af275980f01705e0) Docs: Added naming convention details to plugin usage (#12202) (Henrique Barcelos) +* [`f826eab`](https://github.com/eslint/eslint/commit/f826eabbeecddb047f58f4e7308a14c18148d369) Fix: Allow line comment exception in object-curly-spacing (fixes #11902) (#12216) (Milos Djermanovic) +* [`db2a29b`](https://github.com/eslint/eslint/commit/db2a29beb0fa28183f65bf9e659c66c03a8918b5) Update: indentation of comment followed by semicolon (fixes #12232) (#12243) (Kai Cataldo) +* [`ae17d1c`](https://github.com/eslint/eslint/commit/ae17d1ca59dd466aa64da0680ec2453c2dc3b80d) Fix: no-sequences is reporting incorrect locations (#12241) (Milos Djermanovic) +* [`365331a`](https://github.com/eslint/eslint/commit/365331a42e22af5a77ac9cfa9673d6a8f653eb5a) Fix: object-shorthand providing invalid fixes for typescript (#12260) (Brad Zacher) +* [`1c921c6`](https://github.com/eslint/eslint/commit/1c921c6dfd7ddfb0308c8103e53d32c1241475f0) New: add no-import-assign (fixes #12237) (#12252) (Toru Nagashima) +* [`3be04fd`](https://github.com/eslint/eslint/commit/3be04fd6a4e7b3f5a5ecb845a29cf29b71fe2dfb) New: Add prefer-regex-literals rule (fixes #12238) (#12254) (Milos Djermanovic) +* [`37c0fde`](https://github.com/eslint/eslint/commit/37c0fdeb87b92a0b779b125adf45535b79b65757) Update: Report global Atomics calls in no-obj-calls (fixes #12234) (#12258) (Milos Djermanovic) +* [`985c9e5`](https://github.com/eslint/eslint/commit/985c9e5eba351965a8a1491a41dbdcc78154b8f4) Fix: space-before-function-paren autofix removes comments (fixes #12259) (#12264) (Milos Djermanovic) +* [`01da7d0`](https://github.com/eslint/eslint/commit/01da7d04c4e5a7376cf241ec02db7971726a1bf9) Fix: eqeqeq rule reports incorrect locations (#12265) (Milos Djermanovic) +* [`319e4d8`](https://github.com/eslint/eslint/commit/319e4d8386ea846928f0f906c251b46043a53491) Docs: adding finally example (#12256) (Jens Melgaard) +* [`d52328f`](https://github.com/eslint/eslint/commit/d52328f012f3704c7d1ce39427e63f80531c7979) Docs: fix no-sequences `with` examples (#12239) (Milos Djermanovic) +* [`a41fdc0`](https://github.com/eslint/eslint/commit/a41fdc07404a7675d14183fab245fb8f49dcb858) Fix: Remove autofixer for no-unsafe-negation (#12157) (Milos Djermanovic) +* [`e38f5fd`](https://github.com/eslint/eslint/commit/e38f5fdfc786363a3eae642f1a69a8725600aa61) Update: fix no-octal-escape false negatives after \0 (#12079) (Milos Djermanovic) +* [`9418fbe`](https://github.com/eslint/eslint/commit/9418fbe0eb31cace3debe27b620709628df2fad7) Sponsors: Sync README with website (ESLint Jenkins) +* [`acc5ec5`](https://github.com/eslint/eslint/commit/acc5ec5082aed466a29899f651e6767b39155aec) Sponsors: Sync README with website (ESLint Jenkins) +* [`460c5ad`](https://github.com/eslint/eslint/commit/460c5ad176eaf39ff579cd96b3bcbe0539093f8f) Sponsors: Sync README with website (ESLint Jenkins) +* [`0313441`](https://github.com/eslint/eslint/commit/0313441d016c8aa0674c135f9da67a676e766ec5) New: add rule default-param-last (fixes #11361) (#12188) (Chiawen Chen) +* [`7621f5d`](https://github.com/eslint/eslint/commit/7621f5d2aa7d87e798b75ca47d6889c280597e99) Update: add more specific linting messages to space-in-parens (#11121) (Che Fisher) +* [`21eb904`](https://github.com/eslint/eslint/commit/21eb9044135c01b6c12188517bba840614483fc6) Fix: basePath of OverrideTester (fixes #12032) (#12205) (Toru Nagashima) +* [`86e5e65`](https://github.com/eslint/eslint/commit/86e5e657ea3fbf12b10524abcbc197afd215a060) Sponsors: Sync README with website (ESLint Jenkins) +* [`2b1a13f`](https://github.com/eslint/eslint/commit/2b1a13fa0de8360586857f3ced8da514c971297d) Fix: no-extra-boolean-cast reports wrong negation node (fixes #11324) (#12197) (Milos Djermanovic) +* [`ba8c2aa`](https://github.com/eslint/eslint/commit/ba8c2aa0154561fbeca33db0343cb39a7fbd9b4f) Sponsors: Sync README with website (ESLint Jenkins) +* [`a0a9746`](https://github.com/eslint/eslint/commit/a0a9746724ccd22c721ddc1b25c566aa9acea154) Docs: Fix link in no-irregular-whitespace.md (#12196) (Timo Tijhof) +* [`e10eeba`](https://github.com/eslint/eslint/commit/e10eebab4abd193dee697c4de7fb2d95bbab2d8c) Fix: quotes autofix produces syntax error with octal escape sequences (#12118) (Milos Djermanovic) + v6.3.0 - August 30, 2019 * [`0acdefb`](https://github.com/eslint/eslint/commit/0acdefb97f35bb09db2910540c70dc377a01ad62) Chore: refactor code (#12113) (James George) From 5f3024f467893a46bff095d149d02bb39229d0e4 Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Fri, 13 Sep 2019 21:35:31 -0400 Subject: [PATCH 24/26] 6.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1490aeed39..9ce1c59b0d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint", - "version": "6.3.0", + "version": "6.4.0", "author": "Nicholas C. Zakas ", "description": "An AST-based pattern checker for JavaScript.", "bin": { From 9984c3e27c92de76b8c05a58525dbcea12b10b83 Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Fri, 13 Sep 2019 21:43:28 -0400 Subject: [PATCH 25/26] Docs: Update README team and sponsors --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 28f512920c2..9b3e925c3e7 100644 --- a/README.md +++ b/README.md @@ -210,11 +210,6 @@ Toru Nagashima Gyandeep Singh - -
-Kai Cataldo -
-
Teddy Katz @@ -241,6 +236,11 @@ The people who review and implement new features. The people who review and fix bugs and help triage issues.
+ +
+Kai Cataldo +
+

Pig Fang From f9fc695d77c19cd5ecb3f0e97e1ea124c8543409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sat, 14 Sep 2019 18:52:52 +0800 Subject: [PATCH 26/26] Chore: enable default-param-last (#12244) note: this is a breaking change in eslint-config-eslint. refs:https://github.com/eslint/eslint/commit/0313441d016c8aa0674c135f9da67a676e766ec5 --- lib/rules/capitalized-comments.js | 4 ++-- packages/eslint-config-eslint/default.yml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/rules/capitalized-comments.js b/lib/rules/capitalized-comments.js index 47477743598..dd7ef145648 100644 --- a/lib/rules/capitalized-comments.js +++ b/lib/rules/capitalized-comments.js @@ -59,7 +59,7 @@ const DEFAULTS = { * @param {string} which Either "line" or "block". * @returns {Object} The normalized options. */ -function getNormalizedOptions(rawOptions = {}, which) { +function getNormalizedOptions(rawOptions, which) { return Object.assign({}, DEFAULTS, rawOptions[which] || rawOptions); } @@ -70,7 +70,7 @@ function getNormalizedOptions(rawOptions = {}, which) { * @returns {Object} An object with "Line" and "Block" keys and corresponding * normalized options objects. */ -function getAllNormalizedOptions(rawOptions) { +function getAllNormalizedOptions(rawOptions = {}) { return { Line: getNormalizedOptions(rawOptions, "line"), Block: getNormalizedOptions(rawOptions, "block") diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml index 8e8c8c57ad6..526ce5600ef 100644 --- a/packages/eslint-config-eslint/default.yml +++ b/packages/eslint-config-eslint/default.yml @@ -20,6 +20,7 @@ rules: consistent-return: "error" curly: ["error", "all"] default-case: "error" + default-param-last: "error" dot-location: ["error", "property"] dot-notation: ["error", { allowKeywords: true }] eol-last: "error"