{"version":3,"names":["VISITOR_KEYS","findParent","callback","path","parentPath","find","getFunctionParent","p","isFunction","getStatementParent","Array","isArray","container","isStatement","isProgram","isFile","Error","getEarliestCommonAncestorFrom","paths","getDeepestCommonAncestorFrom","deepest","i","ancestries","earliest","keys","type","ancestry","listKey","key","earliestKeyIndex","indexOf","parentKey","currentKeyIndex","filter","length","minDepth","Infinity","lastCommonIndex","lastCommon","map","unshift","first","depthLoop","shouldMatch","getAncestry","push","isAncestor","maybeDescendant","isDescendant","maybeAncestor","parent","inType","candidateTypes","node"],"sources":["../../src/path/ancestry.ts"],"sourcesContent":["// This file contains that retrieve or validate anything related to the current paths ancestry.\n\nimport { VISITOR_KEYS } from \"@babel/types\";\nimport type * as t from \"@babel/types\";\nimport type NodePath from \"./index\";\n\n/**\n * Starting at the parent path of the current `NodePath` and going up the\n * tree, return the first `NodePath` that causes the provided `callback`\n * to return a truthy value, or `null` if the `callback` never returns a\n * truthy value.\n */\n\nexport function findParent(\n this: NodePath,\n callback: (path: NodePath) => boolean,\n): NodePath | null {\n let path = this;\n while ((path = path.parentPath)) {\n if (callback(path)) return path;\n }\n return null;\n}\n\n/**\n * Starting at current `NodePath` and going up the tree, return the first\n * `NodePath` that causes the provided `callback` to return a truthy value,\n * or `null` if the `callback` never returns a truthy value.\n */\n\nexport function find(\n this: NodePath,\n callback: (path: NodePath) => boolean,\n): NodePath | null {\n let path = this;\n do {\n if (callback(path)) return path;\n } while ((path = path.parentPath));\n return null;\n}\n\n/**\n * Get the parent function of the current path.\n */\n\nexport function getFunctionParent(this: NodePath): NodePath | null {\n return this.findParent(p => p.isFunction()) as NodePath | null;\n}\n\n/**\n * Walk up the tree until we hit a parent node path in a list.\n */\n\nexport function getStatementParent(this: NodePath): NodePath {\n let path = this;\n\n do {\n if (\n !path.parentPath ||\n (Array.isArray(path.container) && path.isStatement())\n ) {\n break;\n } else {\n path = path.parentPath;\n }\n } while (path);\n\n if (path && (path.isProgram() || path.isFile())) {\n throw new Error(\n \"File/Program node, we can't possibly find a statement parent to this\",\n );\n }\n\n return path as NodePath;\n}\n\n/**\n * Get the deepest common ancestor and then from it, get the earliest relationship path\n * to that ancestor.\n *\n * Earliest is defined as being \"before\" all the other nodes in terms of list container\n * position and visiting key.\n */\n\nexport function getEarliestCommonAncestorFrom(\n this: NodePath,\n paths: Array,\n): NodePath {\n return this.getDeepestCommonAncestorFrom(\n paths,\n function (deepest, i, ancestries) {\n let earliest;\n const keys = VISITOR_KEYS[deepest.type];\n\n for (const ancestry of ancestries) {\n const path = ancestry[i + 1];\n\n // first path\n if (!earliest) {\n earliest = path;\n continue;\n }\n\n // handle containers\n if (path.listKey && earliest.listKey === path.listKey) {\n // we're in the same container so check if we're earlier\n if (path.key < earliest.key) {\n earliest = path;\n continue;\n }\n }\n\n // handle keys\n const earliestKeyIndex = keys.indexOf(earliest.parentKey);\n const currentKeyIndex = keys.indexOf(path.parentKey as string);\n if (earliestKeyIndex > currentKeyIndex) {\n // key appears before so it's earlier\n earliest = path;\n }\n }\n\n return earliest;\n },\n );\n}\n\n/**\n * Get the earliest path in the tree where the provided `paths` intersect.\n *\n * TODO: Possible optimisation target.\n */\n\nexport function getDeepestCommonAncestorFrom(\n this: NodePath,\n paths: Array,\n filter?: (deepest: NodePath, i: number, ancestries: NodePath[][]) => NodePath,\n): NodePath {\n if (!paths.length) {\n return this;\n }\n\n if (paths.length === 1) {\n return paths[0];\n }\n\n // minimum depth of the tree so we know the highest node\n let minDepth = Infinity;\n\n // last common ancestor\n let lastCommonIndex, lastCommon;\n\n // get the ancestors of the path, breaking when the parent exceeds ourselves\n const ancestries = paths.map(path => {\n const ancestry: NodePath[] = [];\n\n do {\n ancestry.unshift(path);\n } while ((path = path.parentPath) && path !== this);\n\n // save min depth to avoid going too far in\n if (ancestry.length < minDepth) {\n minDepth = ancestry.length;\n }\n\n return ancestry;\n });\n\n // get the first ancestry so we have a seed to assess all other ancestries with\n const first = ancestries[0];\n\n // check ancestor equality\n depthLoop: for (let i = 0; i < minDepth; i++) {\n const shouldMatch = first[i];\n\n for (const ancestry of ancestries) {\n if (ancestry[i] !== shouldMatch) {\n // we've hit a snag\n break depthLoop;\n }\n }\n\n // next iteration may break so store these so they can be returned\n lastCommonIndex = i;\n lastCommon = shouldMatch;\n }\n\n if (lastCommon) {\n if (filter) {\n return filter(lastCommon, lastCommonIndex, ancestries);\n } else {\n return lastCommon;\n }\n } else {\n throw new Error(\"Couldn't find intersection\");\n }\n}\n\n/**\n * Build an array of node paths containing the entire ancestry of the current node path.\n *\n * NOTE: The current node path is included in this.\n */\n\nexport function getAncestry(this: NodePath): Array {\n let path = this;\n const paths = [];\n do {\n paths.push(path);\n } while ((path = path.parentPath));\n return paths;\n}\n\n/**\n * A helper to find if `this` path is an ancestor of @param maybeDescendant\n */\nexport function isAncestor(this: NodePath, maybeDescendant: NodePath): boolean {\n return maybeDescendant.isDescendant(this);\n}\n\n/**\n * A helper to find if `this` path is a descendant of @param maybeAncestor\n */\nexport function isDescendant(this: NodePath, maybeAncestor: NodePath): boolean {\n return !!this.findParent(parent => parent === maybeAncestor);\n}\n\nexport function inType(this: NodePath, ...candidateTypes: string[]): boolean {\n let path = this;\n while (path) {\n for (const type of candidateTypes) {\n if (path.node.type === type) return true;\n }\n path = path.parentPath;\n }\n\n return false;\n}\n"],"mappings":"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"}