From db78483df19af1e31e69b9af1eb2ac59da41a0b6 Mon Sep 17 00:00:00 2001 From: Georgii Dolzhykov Date: Tue, 10 Dec 2019 01:41:03 +0200 Subject: [PATCH] refactoring: introduce path.match (#7108) --- src/common/fast-path.js | 36 ++++++++++++ src/common/util.js | 15 ----- src/language-js/embed.js | 93 ++++++++++--------------------- src/language-js/printer-estree.js | 41 ++++++-------- 4 files changed, 83 insertions(+), 102 deletions(-) diff --git a/src/common/fast-path.js b/src/common/fast-path.js index 4c152b2f8..eaf9a84f2 100644 --- a/src/common/fast-path.js +++ b/src/common/fast-path.js @@ -138,4 +138,40 @@ FastPath.prototype.map = function map(callback /*, name1, name2, ... */) { return result; }; +/** + * @param {...( + * | ((node: any, name: string | null, number: number | null) => boolean) + * | undefined + * )} predicates + */ +FastPath.prototype.match = function match(/* predicates */) { + let stackPointer = this.stack.length - 1; + + let name = null; + let node = this.stack[stackPointer--]; + + for (let i = 0; i < arguments.length; ++i) { + if (node === undefined) { + return false; + } + + // skip index/array + let number = null; + if (typeof name === "number") { + number = name; + name = this.stack[stackPointer--]; + node = this.stack[stackPointer--]; + } + + if (arguments[i] && !arguments[i](node, name, number)) { + return false; + } + + name = this.stack[stackPointer--]; + node = this.stack[stackPointer--]; + } + + return true; +}; + module.exports = FastPath; diff --git a/src/common/util.js b/src/common/util.js index 9f13f83c6..a6af62b24 100644 --- a/src/common/util.js +++ b/src/common/util.js @@ -779,20 +779,6 @@ function hasNodeIgnoreComment(node) { ); } -function matchAncestorTypes(path, types, index) { - index = index || 0; - types = types.slice(); - while (types.length) { - const parent = path.getParentNode(index); - const type = types.shift(); - if (!parent || parent.type !== type) { - return false; - } - index++; - } - return true; -} - function addCommentHelper(node, comment) { const comments = node.comments || (node.comments = []); comments.push(comment); @@ -891,7 +877,6 @@ module.exports = { hasIgnoreComment, hasNodeIgnoreComment, makeString, - matchAncestorTypes, addLeadingComment, addDanglingComment, addTrailingComment, diff --git a/src/language-js/embed.js b/src/language-js/embed.js index 0e5454648..0954451dd 100644 --- a/src/language-js/embed.js +++ b/src/language-js/embed.js @@ -389,43 +389,37 @@ function isStyledJsx(path) { * }) */ function isAngularComponentStyles(path) { - return isPathMatch( - path, - [ - node => node.type === "TemplateLiteral", - (node, name) => node.type === "ArrayExpression" && name === "elements", - (node, name) => - node.type === "Property" && - node.key.type === "Identifier" && - node.key.name === "styles" && - name === "value" - ].concat(getAngularComponentObjectExpressionPredicates()) + return path.match( + node => node.type === "TemplateLiteral", + (node, name) => node.type === "ArrayExpression" && name === "elements", + (node, name) => + node.type === "Property" && + node.key.type === "Identifier" && + node.key.name === "styles" && + name === "value", + ...angularComponentObjectExpressionPredicates ); } function isAngularComponentTemplate(path) { - return isPathMatch( - path, - [ - node => node.type === "TemplateLiteral", - (node, name) => - node.type === "Property" && - node.key.type === "Identifier" && - node.key.name === "template" && - name === "value" - ].concat(getAngularComponentObjectExpressionPredicates()) + return path.match( + node => node.type === "TemplateLiteral", + (node, name) => + node.type === "Property" && + node.key.type === "Identifier" && + node.key.name === "template" && + name === "value", + ...angularComponentObjectExpressionPredicates ); } -function getAngularComponentObjectExpressionPredicates() { - return [ - (node, name) => node.type === "ObjectExpression" && name === "properties", - (node, name) => - node.type === "CallExpression" && - node.callee.type === "Identifier" && - node.callee.name === "Component" && - name === "arguments", - (node, name) => node.type === "Decorator" && name === "expression" - ]; -} +const angularComponentObjectExpressionPredicates = [ + (node, name) => node.type === "ObjectExpression" && name === "properties", + (node, name) => + node.type === "CallExpression" && + node.callee.type === "Identifier" && + node.callee.name === "Component" && + name === "arguments", + (node, name) => node.type === "Decorator" && name === "expression" +]; /** * styled-components template literals @@ -536,50 +530,21 @@ function hasLanguageComment(node, languageName) { ); } -function isPathMatch(path, predicateStack) { - const stack = path.stack.slice(); - - let name = null; - let node = stack.pop(); - - for (const predicate of predicateStack) { - if (node === undefined) { - return false; - } - - // skip index/array - if (typeof name === "number") { - name = stack.pop(); - node = stack.pop(); - } - - if (!predicate(node, name)) { - return false; - } - - name = stack.pop(); - node = stack.pop(); - } - - return true; -} - /** * - html`...` * - HTML comment block */ function isHtml(path) { - const node = path.getValue(); return ( - hasLanguageComment(node, "HTML") || - isPathMatch(path, [ + hasLanguageComment(path.getValue(), "HTML") || + path.match( node => node.type === "TemplateLiteral", (node, name) => node.type === "TaggedTemplateExpression" && node.tag.type === "Identifier" && node.tag.name === "html" && name === "quasi" - ]) + ) ); } diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 21cc37f0d..b951fae1b 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -20,7 +20,6 @@ const { getPenultimate, startsWithNoLookaheadToken, getIndentSize, - matchAncestorTypes, getPreferredQuote } = require("../common/util"); const { @@ -1406,18 +1405,19 @@ function printPathNoParens(path, options, print, args) { // If we inline the object as first argument of the parent, we don't want // to create another group so that the object breaks before the return // type - const parentParentParent = path.getParentNode(2); if ( - (n.type === "ObjectPattern" && - parent && - shouldHugArguments(parent) && - !n.decorators && - parent.params[0] === n) || - (shouldHugType(n) && - parentParentParent && - shouldHugArguments(parentParentParent) && - parentParentParent.params[0].typeAnnotation && - parentParentParent.params[0].typeAnnotation.typeAnnotation === n) + path.match( + node => node.type === "ObjectPattern" && !node.decorators, + (node, name, number) => + shouldHugArguments(node) && name === "params" && number === 0 + ) || + path.match( + shouldHugType, + (node, name) => name === "typeAnnotation", + (node, name) => name === "typeAnnotation", + (node, name, number) => + shouldHugArguments(node) && name === "params" && number === 0 + ) ) { return content; } @@ -5563,17 +5563,12 @@ function maybeWrapJSXElementInParens(path, elem, options) { return elem; } - const shouldBreak = - matchAncestorTypes(path, [ - "ArrowFunctionExpression", - "CallExpression", - "JSXExpressionContainer" - ]) || - matchAncestorTypes(path, [ - "ArrowFunctionExpression", - "OptionalCallExpression", - "JSXExpressionContainer" - ]); + const shouldBreak = path.match( + undefined, + node => node.type === "ArrowFunctionExpression", + isCallOrOptionalCallExpression, + node => node.type === "JSXExpressionContainer" + ); const needsParens = pathNeedsParens(path, options);