From 92a6af22e72cf1d937492fecc591bb41edd16306 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Tue, 18 Oct 2022 14:23:13 +0900 Subject: [PATCH] Remove `prefer-ast-path-node` and add `prefer-ast-path-getters` (#13648) * Support `getParent` * Fix * Fix * Refactor * Rename rule and add tests * Fix by rule * Fix error message * Add error message tests * Run Prettier! * Address review * Improve error message * Refactor * Stricter check & refactor * Minor tweak Co-authored-by: fisker Cheung --- .eslintrc.cjs | 2 +- .../index.js | 2 +- .../prefer-ast-path-getters.js | 92 ++++++++ .../prefer-ast-path-node.js | 50 ---- .../test.js | 217 ++++++++++++++++-- src/language-css/printer-postcss.js | 20 +- src/language-css/utils/index.js | 4 +- src/language-handlebars/printer-glimmer.js | 4 +- src/language-handlebars/utils.js | 6 +- src/language-js/needs-parens.js | 14 +- src/language-js/print/binaryish.js | 6 +- src/language-js/print/block.js | 8 +- src/language-js/print/call-arguments.js | 3 +- src/language-js/print/class.js | 2 +- src/language-js/print/decorators.js | 2 +- src/language-js/print/flow.js | 2 +- src/language-js/print/function-parameters.js | 2 +- src/language-js/print/function.js | 7 +- src/language-js/print/jsx.js | 6 +- src/language-js/print/member-chain.js | 2 +- src/language-js/print/member.js | 2 +- src/language-js/print/misc.js | 4 +- src/language-js/print/object.js | 2 +- src/language-js/print/property.js | 2 +- src/language-js/print/ternary.js | 4 +- src/language-js/print/type-annotation.js | 8 +- src/language-js/print/type-parameters.js | 4 +- src/language-js/print/typescript.js | 6 +- src/language-js/printer-estree-json.js | 2 +- src/language-js/printer-estree.js | 8 +- src/language-js/utils/index.js | 6 +- src/language-yaml/print/misc.js | 2 +- 32 files changed, 359 insertions(+), 142 deletions(-) create mode 100644 scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-getters.js delete mode 100644 scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-node.js diff --git a/.eslintrc.cjs b/.eslintrc.cjs index a06b0cbe9..15504eed1 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -344,7 +344,7 @@ module.exports = { "prettier-internal-rules/prefer-indent-if-break": "error", "prettier-internal-rules/prefer-is-non-empty-array": "error", "prettier-internal-rules/prefer-fs-promises-submodule": "error", - "prettier-internal-rules/prefer-ast-path-node": "error", + "prettier-internal-rules/prefer-ast-path-getters": "error", }, }, { diff --git a/scripts/tools/eslint-plugin-prettier-internal-rules/index.js b/scripts/tools/eslint-plugin-prettier-internal-rules/index.js index 11b8117c0..c0adf5cbc 100644 --- a/scripts/tools/eslint-plugin-prettier-internal-rules/index.js +++ b/scripts/tools/eslint-plugin-prettier-internal-rules/index.js @@ -18,6 +18,6 @@ module.exports = { "prefer-indent-if-break": require("./prefer-indent-if-break.js"), "prefer-is-non-empty-array": require("./prefer-is-non-empty-array.js"), "prefer-fs-promises-submodule": require("./prefer-fs-promises-submodule.js"), - "prefer-ast-path-node": require("./prefer-ast-path-node.js"), + "prefer-ast-path-getters": require("./prefer-ast-path-getters.js"), }, }; diff --git a/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-getters.js b/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-getters.js new file mode 100644 index 000000000..232080a3e --- /dev/null +++ b/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-getters.js @@ -0,0 +1,92 @@ +"use strict"; + +const selector = [ + "CallExpression", + "[optional=false]", + "[arguments.length<2]", + '[callee.type="MemberExpression"]', + "[callee.computed=false]", + "[callee.optional=false]", + '[callee.object.type="Identifier"]', + "[callee.object.name=/[pP]ath$/]", + '[callee.property.type="Identifier"]', +].join(""); + +const messageId = "prefer-ast-path-getters"; + +function getReplacement(callExpression) { + const method = callExpression.callee.property.name; + const description = `${method}()`; + switch (method) { + case "getValue": + case "getNode": + if (callExpression.arguments.length === 0) { + return { getter: "node", description }; + } + break; + + case "getParentNode": { + // `path.getParentNode()` + if (callExpression.arguments.length === 0) { + return { getter: "parent", description }; + } + + // `path.getParentNode(count)` + const [countNode] = callExpression.arguments; + if (countNode.type !== "Literal") { + return; + } + + const count = countNode.value; + if (count === 0) { + return { getter: "parent", description: `${method}(0)` }; + } + + if (count === 1) { + return { getter: "grandparent", description: `${method}(1)` }; + } + break; + } + } +} + +module.exports = { + meta: { + type: "suggestion", + docs: { + url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-getters.js", + }, + fixable: "code", + messages: { + [messageId]: + "Prefer `AstPath#{{ getter }}` over `AstPath#{{ description }}`.", + }, + }, + create(context) { + return { + [selector](callExpression) { + const replacement = getReplacement(callExpression); + if (!replacement) { + return; + } + + context.report({ + node: callExpression.callee, + messageId, + data: { + getter: replacement.getter, + description: replacement.description, + }, + fix: (fixer) => + fixer.replaceTextRange( + [ + callExpression.callee.property.range[0], + callExpression.range[1], + ], + replacement.getter + ), + }); + }, + }; + }, +}; diff --git a/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-node.js b/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-node.js deleted file mode 100644 index 7cd7f089f..000000000 --- a/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-node.js +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; - -const selector = [ - "CallExpression[arguments.length=0]", - "> MemberExpression", -].join(""); - -const messageId = "prefer-ast-path-node"; - -const getNodeFunctionNames = new Set(["getValue", "getNode"]); - -module.exports = { - meta: { - type: "suggestion", - docs: { - url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-node.js", - }, - fixable: "code", - messages: { - [messageId]: - "Prefer `path.node` instead of `path.getValue()` and `path.getNode()`", - }, - }, - create(context) { - return { - [selector](node) { - if (!node.object?.name?.toLowerCase().endsWith("path")) { - return; - } - if (!getNodeFunctionNames.has(node.property?.name)) { - return; - } - context.report({ - node, - messageId, - fix: (fixer) => [ - fixer.replaceTextRange( - [ - node.property.range[0], - // remove `()` for CallExpression - node.property.range[1] + 2, - ], - "node" - ), - ], - }); - }, - }; - }, -}; diff --git a/scripts/tools/eslint-plugin-prettier-internal-rules/test.js b/scripts/tools/eslint-plugin-prettier-internal-rules/test.js index c16fd8aa6..6abc98865 100644 --- a/scripts/tools/eslint-plugin-prettier-internal-rules/test.js +++ b/scripts/tools/eslint-plugin-prettier-internal-rules/test.js @@ -497,44 +497,223 @@ test("prefer-fs-promises-submodule", { })), }); -test("prefer-ast-path-node", { +test("prefer-ast-path-getters", { valid: [ "path.getNode(2)", "path.getNode", "getNode", "this.getNode()", "path.node", + "path.getParentNode(2)", + "path.getParentNode", + "getParentNode", + "this.getParentNode()", + "path.parent", + "path.grandparent", ], invalid: [ + // path.getNode { code: "path.getNode()", output: "path.node", - errors: 1, + errors: [ + { + message: "Prefer `AstPath#node` over `AstPath#getNode()`.", + }, + ], }, { code: "const node = path.getNode()", output: "const node = path.node", - errors: 1, - }, - { - code: "path.getValue()", - output: "path.node", - errors: 1, - }, - { - code: "const node = path.getValue()", - output: "const node = path.node", - errors: 1, - }, - { - code: "fooPath.getValue()", - output: "fooPath.node", - errors: 1, + errors: [ + { + message: "Prefer `AstPath#node` over `AstPath#getNode()`.", + }, + ], }, { code: "fooPath.getNode()", output: "fooPath.node", - errors: 1, + errors: [ + { + message: "Prefer `AstPath#node` over `AstPath#getNode()`.", + }, + ], + }, + + // path.getValue() + { + code: "path.getValue()", + output: "path.node", + errors: [ + { + message: "Prefer `AstPath#node` over `AstPath#getValue()`.", + }, + ], + }, + { + code: "const node = path.getValue()", + output: "const node = path.node", + errors: [ + { + message: "Prefer `AstPath#node` over `AstPath#getValue()`.", + }, + ], + }, + { + code: "fooPath.getValue()", + output: "fooPath.node", + errors: [ + { + message: "Prefer `AstPath#node` over `AstPath#getValue()`.", + }, + ], + }, + + // path.getParentNode() + { + code: "path.getParentNode()", + output: "path.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode()`.", + }, + ], + }, + { + code: "const node = path.getParentNode()", + output: "const node = path.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode()`.", + }, + ], + }, + { + code: "path.getParentNode()", + output: "path.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode()`.", + }, + ], + }, + { + code: "const node = path.getParentNode()", + output: "const node = path.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode()`.", + }, + ], + }, + { + code: "fooPath.getParentNode()", + output: "fooPath.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode()`.", + }, + ], + }, + + // path.getParentNode(0) + { + code: "path.getParentNode(0)", + output: "path.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode(0)`.", + }, + ], + }, + { + code: "const node = path.getParentNode(0)", + output: "const node = path.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode(0)`.", + }, + ], + }, + { + code: "path.getParentNode(0)", + output: "path.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode(0)`.", + }, + ], + }, + { + code: "const node = path.getParentNode(0)", + output: "const node = path.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode(0)`.", + }, + ], + }, + { + code: "fooPath.getParentNode(0)", + output: "fooPath.parent", + errors: [ + { + message: "Prefer `AstPath#parent` over `AstPath#getParentNode(0)`.", + }, + ], + }, + + // path.getParentNode(1) + { + code: "path.getParentNode(1)", + output: "path.grandparent", + errors: [ + { + message: + "Prefer `AstPath#grandparent` over `AstPath#getParentNode(1)`.", + }, + ], + }, + { + code: "const node = path.getParentNode(1)", + output: "const node = path.grandparent", + errors: [ + { + message: + "Prefer `AstPath#grandparent` over `AstPath#getParentNode(1)`.", + }, + ], + }, + { + code: "path.getParentNode(1)", + output: "path.grandparent", + errors: [ + { + message: + "Prefer `AstPath#grandparent` over `AstPath#getParentNode(1)`.", + }, + ], + }, + { + code: "const node = path.getParentNode(1)", + output: "const node = path.grandparent", + errors: [ + { + message: + "Prefer `AstPath#grandparent` over `AstPath#getParentNode(1)`.", + }, + ], + }, + { + code: "fooPath.getParentNode(1)", + output: "fooPath.grandparent", + errors: [ + { + message: + "Prefer `AstPath#grandparent` over `AstPath#getParentNode(1)`.", + }, + ], }, ], }); diff --git a/src/language-css/printer-postcss.js b/src/language-css/printer-postcss.js index 20165c5fa..fbcef204e 100644 --- a/src/language-css/printer-postcss.js +++ b/src/language-css/printer-postcss.js @@ -132,7 +132,7 @@ function genericPrint(path, options, print) { ]; case "css-decl": { - const parentNode = path.getParentNode(); + const parentNode = path.parent; const { between: rawBetween } = node.raws; const trimmedBetween = rawBetween.trim(); @@ -189,7 +189,7 @@ function genericPrint(path, options, print) { ]; } case "css-atrule": { - const parentNode = path.getParentNode(); + const parentNode = path.parent; const isTemplatePlaceholderNodeWithoutSemiColon = isTemplatePlaceholderNode(node) && !parentNode.raws.semicolon && @@ -385,7 +385,7 @@ function genericPrint(path, options, print) { return adjustStrings(node.value, options); case "selector-tag": { - const parentNode = path.getParentNode(); + const parentNode = path.parent; const index = parentNode && parentNode.nodes.indexOf(node); const prevNode = index && parentNode.nodes[index - 1]; @@ -433,7 +433,7 @@ function genericPrint(path, options, print) { node.value === "~" || node.value === ">>>" ) { - const parentNode = path.getParentNode(); + const parentNode = path.parent; const leading = parentNode.type === "selector-selector" && parentNode.nodes[0] === node @@ -484,7 +484,7 @@ function genericPrint(path, options, print) { } // originalText has to be used for Less, see replaceQuotesInInlineComments in loc.js - const parentNode = path.getParentNode(); + const parentNode = path.parent; if (parentNode.raws && parentNode.raws.selector) { const start = locStart(parentNode); const end = start + parentNode.raws.selector.length; @@ -492,7 +492,7 @@ function genericPrint(path, options, print) { } // Same reason above - const grandParent = path.getParentNode(1); + const grandParent = path.grandparent; if ( parentNode.type === "value-paren_group" && grandParent && @@ -519,8 +519,8 @@ function genericPrint(path, options, print) { return options.originalText.slice(locStart(node), locEnd(node)); case "value-comma_group": { - const parentNode = path.getParentNode(); - const parentParentNode = path.getParentNode(1); + const parentNode = path.parent; + const parentParentNode = path.grandparent; const declAncestorProp = getPropOfDeclNode(path); const isGridValue = declAncestorProp && @@ -867,7 +867,7 @@ function genericPrint(path, options, print) { return group(indent(fill(parts))); } case "value-paren_group": { - const parentNode = path.getParentNode(); + const parentNode = path.parent; const printedGroups = path.map(() => { const child = path.node; return typeof child === "string" ? child : print(); @@ -1004,7 +1004,7 @@ function genericPrint(path, options, print) { return node.value; case "value-colon": { - const parentNode = path.getParentNode(); + const parentNode = path.parent; const index = parentNode && parentNode.groups.indexOf(node); const prevNode = index && parentNode.groups[index - 1]; return [ diff --git a/src/language-css/utils/index.js b/src/language-css/utils/index.js index aca98c0ce..386e530fc 100644 --- a/src/language-css/utils/index.js +++ b/src/language-css/utils/index.js @@ -109,7 +109,7 @@ function isVarFunctionNode(node) { } function isLastNode(path, node) { - const nodes = path.getParentNode()?.nodes; + const nodes = path.parent?.nodes; return nodes && nodes.indexOf(node) === nodes.length - 1; } @@ -262,7 +262,7 @@ function isSCSSMapItemNode(path, options) { return false; } - const parentParentNode = path.getParentNode(1); + const parentParentNode = path.grandparent; // Check open parens contain key/value pair (i.e. `(key: value)` and `(key: (value, other-value)`) if ( diff --git a/src/language-handlebars/printer-glimmer.js b/src/language-handlebars/printer-glimmer.js index 51f2d038e..308ba821a 100644 --- a/src/language-handlebars/printer-glimmer.js +++ b/src/language-handlebars/printer-glimmer.js @@ -85,7 +85,7 @@ function print(path, options, print) { } case "BlockStatement": { - const pp = path.getParentNode(1); + const pp = path.grandparent; const isElseIfLike = pp && @@ -550,7 +550,7 @@ function printElseBlock(node, options) { } function printElseIfLikeBlock(path, print, ifLikeKeyword) { - const parentNode = path.getParentNode(1); + const parentNode = path.grandparent; return [ printInverseBlockOpeningMustache(parentNode), diff --git a/src/language-handlebars/utils.js b/src/language-handlebars/utils.js index 16b9d832c..e1e435cb0 100644 --- a/src/language-handlebars/utils.js +++ b/src/language-handlebars/utils.js @@ -2,7 +2,7 @@ import { htmlVoidElements } from "html-void-elements"; function isLastNodeOfSiblings(path) { const { node } = path; - const parentNode = path.getParentNode(0); + const parentNode = path.parent; if ( isParentOfSomeType(path, ["ElementNode"]) && @@ -49,7 +49,7 @@ function isNodeOfSomeType(node, types) { } function isParentOfSomeType(path, types) { - const parentNode = path.getParentNode(0); + const parentNode = path.parent; return isNodeOfSomeType(parentNode, types); } @@ -65,7 +65,7 @@ function isNextNodeOfSomeType(path, types) { function getSiblingNode(path, offset) { const { node } = path; - const parentNode = path.getParentNode(0) ?? {}; + const parentNode = path.parent ?? {}; const children = parentNode.children ?? parentNode.body ?? parentNode.parts ?? []; const index = children.indexOf(node); diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 6c959f1cc..80cd22d2c 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -226,7 +226,7 @@ function needsParens(path, options) { return true; } if (node.operator === "|>" && node.extra && node.extra.parenthesized) { - const grandParent = path.getParentNode(1); + const grandParent = path.grandparent; if ( grandParent.type === "BinaryExpression" && grandParent.operator === "|>" @@ -443,7 +443,7 @@ function needsParens(path, options) { (key === "objectType" && parent.type === "TSIndexedAccessType") || parent.type === "TSTypeOperator" || (parent.type === "TSTypeAnnotation" && - path.getParentNode(1).type.startsWith("TSJSDoc")) + path.grandparent.type.startsWith("TSJSDoc")) ); case "ArrayTypeAnnotation": @@ -471,9 +471,7 @@ function needsParens(path, options) { case "FunctionTypeAnnotation": { const ancestor = - parent.type === "NullableTypeAnnotation" - ? path.getParentNode(1) - : parent; + parent.type === "NullableTypeAnnotation" ? path.grandparent : parent; return ( ancestor.type === "UnionTypeAnnotation" || @@ -516,7 +514,7 @@ function needsParens(path, options) { !parent.directive ) { // To avoid becoming a directive - const grandParent = path.getParentNode(1); + const grandParent = path.grandparent; return ( grandParent.type === "Program" || @@ -531,7 +529,7 @@ function needsParens(path, options) { ); case "AssignmentExpression": { - const grandParent = path.getParentNode(1); + const grandParent = path.grandparent; if (key === "body" && parent.type === "ArrowFunctionExpression") { return true; @@ -684,7 +682,7 @@ function needsParens(path, options) { case "OptionalMemberExpression": case "OptionalCallExpression": { - const parentParent = path.getParentNode(1); + const parentParent = path.grandparent; if ( (key === "object" && parent.type === "MemberExpression") || (key === "callee" && diff --git a/src/language-js/print/binaryish.js b/src/language-js/print/binaryish.js index fe9de443e..04d120142 100644 --- a/src/language-js/print/binaryish.js +++ b/src/language-js/print/binaryish.js @@ -28,8 +28,8 @@ import { let uid = 0; function printBinaryishExpression(path, options, print) { const { node } = path; - const parent = path.getParentNode(); - const parentParent = path.getParentNode(1); + const { parent } = path; + const parentParent = path.grandparent; const isInsideParenthesis = node !== parent.body && (parent.type === "IfStatement" || @@ -278,7 +278,7 @@ function printBinaryishExpressions( // If there's only a single binary expression, we want to create a group // in order to avoid having a small right part like -1 be on its own line. - const parent = path.getParentNode(); + const { parent } = path; const shouldBreak = hasComment( node.left, CommentCheckFlags.Trailing | CommentCheckFlags.Line diff --git a/src/language-js/print/block.js b/src/language-js/print/block.js index 376a0a168..d7a58cae3 100644 --- a/src/language-js/print/block.js +++ b/src/language-js/print/block.js @@ -21,7 +21,7 @@ function printBlock(path, options, print) { } if (node.type === "ClassBody" && isNonEmptyArray(node.body)) { - const parent = path.getParentNode(); + const { parent } = path; parts.push(printHardlineAfterHeritage(parent)); } @@ -30,8 +30,8 @@ function printBlock(path, options, print) { if (printed) { parts.push(indent([hardline, printed]), hardline); } else { - const parent = path.getParentNode(); - const parentParent = path.getParentNode(1); + const { parent } = path; + const parentParent = path.grandparent; if ( !( parent.type === "ArrowFunctionExpression" || @@ -94,7 +94,7 @@ function printBlockBody(path, options, print) { } if (node.type === "Program") { - const parent = path.getParentNode(); + const { parent } = path; if (!parent || parent.type !== "ModuleExpression") { parts.push(hardline); } diff --git a/src/language-js/print/call-arguments.js b/src/language-js/print/call-arguments.js index 98cc718cf..372afc13e 100644 --- a/src/language-js/print/call-arguments.js +++ b/src/language-js/print/call-arguments.js @@ -86,8 +86,7 @@ function printCallArguments(path, options, print) { if ( anyArgEmptyLine || - (path.getParentNode().type !== "Decorator" && - isFunctionCompositionArgs(args)) + (path.parent.type !== "Decorator" && isFunctionCompositionArgs(args)) ) { return allArgsBrokenOut(); } diff --git a/src/language-js/print/class.js b/src/language-js/print/class.js index 7d270bedb..b5a99afbd 100644 --- a/src/language-js/print/class.js +++ b/src/language-js/print/class.js @@ -147,7 +147,7 @@ function printList(path, options, print, listName) { function printSuperClass(path, options, print) { const printed = print("superClass"); - const parent = path.getParentNode(); + const { parent } = path; if (parent.type === "AssignmentExpression") { return group( ifBreak(["(", indent([softline, printed]), softline, ")"], printed) diff --git a/src/language-js/print/decorators.js b/src/language-js/print/decorators.js index 6d003473a..5f2806f3a 100644 --- a/src/language-js/print/decorators.js +++ b/src/language-js/print/decorators.js @@ -35,7 +35,7 @@ function printDecorators(path, options, print) { // If the parent node is an export declaration and the decorator // was written before the export, the export will be responsible // for printing the decorators. - hasDecoratorsBeforeExport(path.getParentNode()) + hasDecoratorsBeforeExport(path.parent) ) { return; } diff --git a/src/language-js/print/flow.js b/src/language-js/print/flow.js index 5824ff2e3..8337e4bd5 100644 --- a/src/language-js/print/flow.js +++ b/src/language-js/print/flow.js @@ -187,7 +187,7 @@ function printFlow(path, options, print) { case "FunctionTypeParam": { const name = node.name ? print("name") - : path.getParentNode().this === node + : path.parent.this === node ? "this" : ""; return [ diff --git a/src/language-js/print/function-parameters.js b/src/language-js/print/function-parameters.js index b01437bf8..751f85ed0 100644 --- a/src/language-js/print/function-parameters.js +++ b/src/language-js/print/function-parameters.js @@ -60,7 +60,7 @@ function printFunctionParameters( ]; } - const parent = path.getParentNode(); + const { parent } = path; const isParametersInTestCall = isTestCall(parent); const shouldHugParameters = shouldHugTheOnlyFunctionParameter(functionNode); const printed = []; diff --git a/src/language-js/print/function.js b/src/language-js/print/function.js index ac4093b83..ad1cafc56 100644 --- a/src/language-js/print/function.js +++ b/src/language-js/print/function.js @@ -55,7 +55,7 @@ function printFunction(path, print, options, args) { node.type === "FunctionExpression") && args?.expandLastArg ) { - const parent = path.getParentNode(); + const { parent } = path; if ( isCallExpression(parent) && (getCallArguments(parent).length > 1 || @@ -246,7 +246,7 @@ function printArrowChain( tailNode ) { const name = path.getName(); - const parent = path.getParentNode(); + const { parent } = path; const isCallee = isCallLikeExpression(parent) && name === "callee"; const isAssignmentRhs = Boolean(args && args.assignmentLayout); const shouldPutBodyOnSeparateLine = @@ -363,8 +363,7 @@ function printArrowFunction(path, options, print, args) { // with the opening (, or if it's inside a JSXExpression (e.g. an attribute) // we should align the expression's closing } with the line with the opening {. const shouldAddSoftLine = - (args?.expandLastArg || - path.getParentNode().type === "JSXExpressionContainer") && + (args?.expandLastArg || path.parent.type === "JSXExpressionContainer") && !hasComment(node); const printTrailingComma = diff --git a/src/language-js/print/jsx.js b/src/language-js/print/jsx.js index 42009b520..7285c3176 100644 --- a/src/language-js/print/jsx.js +++ b/src/language-js/print/jsx.js @@ -106,7 +106,7 @@ function printJsxElementInternal(path, options, print) { containsMultipleAttributes || containsMultipleExpressions; - const isMdxBlock = path.getParentNode().rootMarker === "mdx"; + const isMdxBlock = path.parent.rootMarker === "mdx"; const rawJsxWhitespace = options.singleQuote ? "{' '}" : '{" "}'; const jsxWhitespace = isMdxBlock @@ -422,7 +422,7 @@ function separatorWithWhitespace( } function maybeWrapJsxElementInParens(path, elem, options) { - const parent = path.getParentNode(); + const { parent } = path; /* istanbul ignore next */ if (!parent) { return elem; @@ -514,7 +514,7 @@ function printJsxExpressionContainer(path, options, print) { (isJsxNode(parent) && (node.type === "ConditionalExpression" || isBinaryish(node))))); - if (shouldInline(node.expression, path.getParentNode(0))) { + if (shouldInline(node.expression, path.parent)) { return group(["{", print("expression"), lineSuffixBoundary, "}"]); } diff --git a/src/language-js/print/member-chain.js b/src/language-js/print/member-chain.js index 980aaad9a..cf07efb03 100644 --- a/src/language-js/print/member-chain.js +++ b/src/language-js/print/member-chain.js @@ -48,7 +48,7 @@ import { // MemberExpression and CallExpression. We need to traverse the AST // and make groups out of it to print it in the desired way. function printMemberChain(path, options, print) { - const parent = path.getParentNode(); + const { parent } = path; const isExpressionStatement = !parent || parent.type === "ExpressionStatement"; diff --git a/src/language-js/print/member.js b/src/language-js/print/member.js index c0bb4b6d3..30b0b21c2 100644 --- a/src/language-js/print/member.js +++ b/src/language-js/print/member.js @@ -9,7 +9,7 @@ import { printOptionalToken } from "./misc.js"; function printMemberExpression(path, options, print) { const { node } = path; - const parent = path.getParentNode(); + const { parent } = path; let firstNonMemberParent; let i = 0; do { diff --git a/src/language-js/print/misc.js b/src/language-js/print/misc.js index 245ec9925..4be5a619d 100644 --- a/src/language-js/print/misc.js +++ b/src/language-js/print/misc.js @@ -8,7 +8,7 @@ function printOptionalToken(path) { !node.optional || // It's an optional computed method parsed by typescript-estree. // "?" is printed in `printMethod`. - (node.type === "Identifier" && node === path.getParentNode().key) + (node.type === "Identifier" && node === path.parent.key) ) { return ""; } @@ -49,7 +49,7 @@ function printTypeAnnotation(path, options, print) { return ""; } - const parentNode = path.getParentNode(); + const parentNode = path.parent; const isFunctionDeclarationIdentifier = parentNode.type === "DeclareFunction" && parentNode.id === node; diff --git a/src/language-js/print/object.js b/src/language-js/print/object.js index 0d345bb55..7f3beb010 100644 --- a/src/language-js/print/object.js +++ b/src/language-js/print/object.js @@ -62,7 +62,7 @@ function printObject(path, options, print) { propsAndLoc.sort((a, b) => a.loc - b.loc); } - const parent = path.getParentNode(0); + const { parent } = path; const isFlowInterfaceLikeBody = isTypeAnnotation && parent && diff --git a/src/language-js/print/property.js b/src/language-js/print/property.js index 09159cb10..037c77b61 100644 --- a/src/language-js/print/property.js +++ b/src/language-js/print/property.js @@ -18,7 +18,7 @@ function printPropertyKey(path, options, print) { return ["[", print("key"), "]"]; } - const parent = path.getParentNode(); + const { parent } = path; const { key } = node; // flow has `Identifier` key, other parsers use `PrivateIdentifier` (ESTree) or `PrivateName` diff --git a/src/language-js/print/ternary.js b/src/language-js/print/ternary.js index f8099f54c..310ab3a7d 100644 --- a/src/language-js/print/ternary.js +++ b/src/language-js/print/ternary.js @@ -108,7 +108,7 @@ function printTernaryTest(path, options, print) { ? "alternate" : "falseType"; - const parent = path.getParentNode(); + const { parent } = path; const printed = isConditionalExpression ? print("test") @@ -206,7 +206,7 @@ function printTernary(path, options, print) { // We print a ConditionalExpression in either "JSX mode" or "normal mode". // See `tests/format/jsx/conditional-expression.js` for more info. let jsxMode = false; - const parent = path.getParentNode(); + const { parent } = path; const isParentTest = parent.type === node.type && testNodePropertyNames.some((prop) => parent[prop] === node); diff --git a/src/language-js/print/type-annotation.js b/src/language-js/print/type-annotation.js index e87ca4a64..52e366604 100644 --- a/src/language-js/print/type-annotation.js +++ b/src/language-js/print/type-annotation.js @@ -130,7 +130,7 @@ function printUnionType(path, options, print) { // | B // | C - const parent = path.getParentNode(); + const { parent } = path; // If there's a leading comment, the parent is doing the indentation const shouldIndent = @@ -144,7 +144,7 @@ function printUnionType(path, options, print) { !( parent.type === "FunctionTypeParam" && !parent.name && - path.getParentNode(1).this !== parent + path.grandparent.this !== parent ) && !( (parent.type === "TypeAlias" || @@ -208,8 +208,8 @@ function printFunctionType(path, options, print) { // FunctionTypeAnnotation is ambiguous: // declare function foo(a: B): void; OR // var A: (a: B) => void; - const parent = path.getParentNode(0); - const parentParent = path.getParentNode(1); + const { parent } = path; + const parentParent = path.grandparent; const parentParentParent = path.getParentNode(2); let isArrowFunctionTypeAnnotation = node.type === "TSFunctionType" || diff --git a/src/language-js/print/type-parameters.js b/src/language-js/print/type-parameters.js index 31bd0c497..4d6ccfa5d 100644 --- a/src/language-js/print/type-parameters.js +++ b/src/language-js/print/type-parameters.js @@ -74,7 +74,7 @@ function printTypeParameters(path, options, print, paramsKey) { : getFunctionParameters(node).length === 1 && isTSXFile(options) && !node[paramsKey][0].constraint && - path.getParentNode().type === "ArrowFunctionExpression" + path.parent.type === "ArrowFunctionExpression" ? "," : shouldPrintComma(options, "all") ? ifBreak(",") @@ -112,7 +112,7 @@ function printDanglingCommentsForInline(path, options) { function printTypeParameter(path, options, print) { const { node } = path; const parts = []; - const parent = path.getParentNode(); + const { parent } = path; const name = node.type === "TSTypeParameter" ? print("name") : node.name; diff --git a/src/language-js/print/typescript.js b/src/language-js/print/typescript.js index 942ea8fd1..06fb92e29 100644 --- a/src/language-js/print/typescript.js +++ b/src/language-js/print/typescript.js @@ -144,7 +144,7 @@ function printTypescript(path, options, print) { return printTypeParameter(path, options, print); case "TSAsExpression": { parts.push(print("expression"), " as ", print("typeAnnotation")); - const parent = path.getParentNode(); + const { parent } = path; if ( (isCallExpression(parent) && parent.callee === node) || (isMemberExpression(parent) && parent.object === node) @@ -199,7 +199,7 @@ function printTypescript(path, options, print) { case "TSTypeQuery": return ["typeof ", print("exprName"), print("typeParameters")]; case "TSIndexSignature": { - const parent = path.getParentNode(); + const { parent } = path; // The typescript parser accepts multiple parameters here. If you're // using them, it makes sense to have a trailing comma. But if you @@ -432,7 +432,7 @@ function printTypescript(path, options, print) { case "TSExternalModuleReference": return ["require(", print("expression"), ")"]; case "TSModuleDeclaration": { - const parent = path.getParentNode(); + const { parent } = path; const isExternalModule = isLiteral(node.id); const parentIsDeclaration = parent.type === "TSModuleDeclaration"; const bodyIsDeclaration = diff --git a/src/language-js/printer-estree-json.js b/src/language-js/printer-estree-json.js index 02e7dbe70..cceb5f7ae 100644 --- a/src/language-js/printer-estree-json.js +++ b/src/language-js/printer-estree-json.js @@ -49,7 +49,7 @@ function genericPrint(path, options, print) { case "NumericLiteral": return JSON.stringify(node.value); case "Identifier": { - const parent = path.getParentNode(); + const { parent } = path; if (parent && parent.type === "ObjectProperty" && parent.key === node) { return JSON.stringify(node.name); } diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index b8ca9e55a..81eac1cea 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -220,7 +220,7 @@ function printPathNoParens(path, options, print, args) { options.parser === "__vue_event_binding" || options.parser === "__vue_ts_event_binding" ) { - const parent = path.getParentNode(); + const { parent } = path; if ( parent.type === "Program" && parent.body.length === 1 && @@ -326,7 +326,7 @@ function printPathNoParens(path, options, print, args) { parts.push("await"); if (node.argument) { parts.push(" ", print("argument")); - const parent = path.getParentNode(); + const { parent } = path; if ( (isCallExpression(parent) && parent.callee === node) || (isMemberExpression(parent) && parent.object === node) @@ -395,7 +395,7 @@ function printPathNoParens(path, options, print, args) { case "TupleExpression": return printArray(path, options, print); case "SequenceExpression": { - const parent = path.getParentNode(); + const { parent } = path; if ( parent.type === "ExpressionStatement" || parent.type === "ForStatement" @@ -454,7 +454,7 @@ function printPathNoParens(path, options, print, args) { // We generally want to terminate all variable declarations with a // semicolon, except when they in the () part of for loops. - const parentNode = path.getParentNode(); + const parentNode = path.parent; const isParentForLoop = parentNode.type === "ForStatement" || diff --git a/src/language-js/utils/index.js b/src/language-js/utils/index.js index f2345cd53..70c7cf165 100644 --- a/src/language-js/utils/index.js +++ b/src/language-js/utils/index.js @@ -192,7 +192,7 @@ const isExportDeclaration = createTypeCheckFunction([ * @returns {Node | null} */ function getParentExportDeclaration(path) { - const parentNode = path.getParentNode(); + const parentNode = path.parent; if (path.getName() === "declaration" && isExportDeclaration(parentNode)) { return parentNode; } @@ -322,7 +322,7 @@ function isTheOnlyJsxElementInMarkdown(options, path) { return false; } - const parent = path.getParentNode(); + const { parent } = path; return parent.type === "Program" && parent.body.length === 1; } @@ -775,7 +775,7 @@ function isFunctionCompositionArgs(args) { */ function isLongCurriedCallExpression(path) { const { node } = path; - const parent = path.getParentNode(); + const { parent } = path; return ( isCallExpression(node) && isCallExpression(parent) && diff --git a/src/language-yaml/print/misc.js b/src/language-yaml/print/misc.js index 506310ee4..7dfe37830 100644 --- a/src/language-yaml/print/misc.js +++ b/src/language-yaml/print/misc.js @@ -17,7 +17,7 @@ function printNextEmptyLine(path, originalText) { isNextEmptyLinePrintedSet.add(node.position.end.line); if ( isNextLineEmpty(node, originalText) && - !shouldPrintEndComments(path.getParentNode()) + !shouldPrintEndComments(path.parent) ) { return softline; }