1 line
No EOL
16 KiB
Text
Executable file
1 line
No EOL
16 KiB
Text
Executable file
{"version":3,"names":["_t","require","_t2","react","cloneNode","jsxExpressionContainer","variableDeclaration","variableDeclarator","referenceVisitor","ReferencedIdentifier","path","state","isJSXIdentifier","isCompatTag","node","name","parentPath","isJSXMemberExpression","scope","isFunction","isArrowFunctionExpression","parent","breakOnScopePaths","push","binding","getBinding","violation","constantViolations","mutableBinding","stop","bindings","PathHoister","constructor","scopes","attachAfter","isCompatibleScope","key","Object","keys","bindingIdentifierEquals","identifier","getCompatibleScopes","indexOf","getAttachmentPath","_getAttachmentPath","targetScope","isProgram","hasOwnBinding","kind","parentKey","bindingParentPath","getAttachmentParentForPath","violationPath","pop","hasOwnParamBindings","bodies","get","i","length","_blockHoist","getNextScopeAttachmentParent","Array","isArray","container","isStatement","constant","run","traverse","attachTo","getFunctionParent","uid","generateUidIdentifier","declarator","insertFn","attached","isVariableDeclarator","isJSXElement","children","replaceWith","exports","default"],"sources":["../../../src/path/lib/hoister.ts"],"sourcesContent":["import { react } from \"@babel/types\";\nimport {\n cloneNode,\n jsxExpressionContainer,\n variableDeclaration,\n variableDeclarator,\n} from \"@babel/types\";\nimport type * as t from \"@babel/types\";\nimport type Scope from \"../../scope/index.ts\";\nimport type NodePath from \"../index.ts\";\nimport type Binding from \"../../scope/binding.ts\";\nimport type { Visitor } from \"../../types.ts\";\n\nconst referenceVisitor: Visitor<PathHoister> = {\n // This visitor looks for bindings to establish a topmost scope for hoisting.\n ReferencedIdentifier(path, state) {\n // Don't hoist regular JSX identifiers ('div', 'span', etc).\n // We do have to consider member expressions for hoisting (e.g. `this.component`)\n if (\n path.isJSXIdentifier() &&\n react.isCompatTag(path.node.name) &&\n !path.parentPath.isJSXMemberExpression()\n ) {\n return;\n }\n\n // If the identifier refers to `this`, we need to break on the closest non-arrow scope.\n if (path.node.name === \"this\") {\n let scope = path.scope;\n do {\n if (\n scope.path.isFunction() &&\n !scope.path.isArrowFunctionExpression()\n ) {\n break;\n }\n } while ((scope = scope.parent));\n if (scope) state.breakOnScopePaths.push(scope.path);\n }\n\n // direct references that we need to track to hoist this to the highest scope we can\n const binding = path.scope.getBinding(path.node.name);\n if (!binding) return;\n\n // we can handle reassignments only if they happen in the same scope as the declaration\n for (const violation of binding.constantViolations) {\n if (violation.scope !== binding.path.scope) {\n state.mutableBinding = true;\n path.stop();\n return;\n }\n }\n\n // this binding isn't accessible from the parent scope so we can safely ignore it\n // eg. it's in a closure etc\n if (binding !== state.scope.getBinding(path.node.name)) return;\n\n state.bindings[path.node.name] = binding;\n },\n};\n\nexport default class PathHoister<T extends t.Node = t.Node> {\n breakOnScopePaths: NodePath[];\n bindings: { [k: string]: Binding };\n mutableBinding: boolean;\n private scopes: Scope[];\n scope: Scope;\n private path: NodePath<T>;\n private attachAfter: boolean;\n\n constructor(path: NodePath<T>, scope: Scope) {\n // Storage for scopes we can't hoist above.\n this.breakOnScopePaths = [];\n // Storage for bindings that may affect what path we can hoist to.\n this.bindings = {};\n // \"true\" if the current path contains a reference to a binding whose\n // value can change and thus can't be safely hoisted.\n this.mutableBinding = false;\n // Storage for eligible scopes.\n this.scopes = [];\n // Our original scope and path.\n this.scope = scope;\n this.path = path;\n // By default, we attach as far up as we can; but if we're trying\n // to avoid referencing a binding, we may have to go after.\n this.attachAfter = false;\n }\n\n // A scope is compatible if all required bindings are reachable.\n isCompatibleScope(scope: Scope) {\n for (const key of Object.keys(this.bindings)) {\n const binding = this.bindings[key];\n if (!scope.bindingIdentifierEquals(key, binding.identifier)) {\n return false;\n }\n }\n\n return true;\n }\n\n // Look through all scopes and push compatible ones.\n getCompatibleScopes() {\n let scope = this.path.scope;\n do {\n if (this.isCompatibleScope(scope)) {\n this.scopes.push(scope);\n } else {\n break;\n }\n\n // deopt: These scopes are set in the visitor on const violations\n if (this.breakOnScopePaths.indexOf(scope.path) >= 0) {\n break;\n }\n } while ((scope = scope.parent));\n }\n\n getAttachmentPath() {\n let path = this._getAttachmentPath();\n if (!path) return;\n\n let targetScope = path.scope;\n\n // don't allow paths that have their own lexical environments to pollute\n if (targetScope.path === path) {\n targetScope = path.scope.parent;\n }\n\n // avoid hoisting to a scope that contains bindings that are executed after our attachment path\n if (targetScope.path.isProgram() || targetScope.path.isFunction()) {\n for (const name of Object.keys(this.bindings)) {\n // check binding is a direct child of this paths scope\n if (!targetScope.hasOwnBinding(name)) continue;\n\n const binding = this.bindings[name];\n\n // allow parameter references and expressions in params (like destructuring rest)\n if (binding.kind === \"param\" || binding.path.parentKey === \"params\") {\n continue;\n }\n\n // For each binding, get its attachment parent. This gives us an idea of where we might\n // introduce conflicts.\n const bindingParentPath = this.getAttachmentParentForPath(binding.path);\n\n // If the binding's attachment appears at or after our attachment point, then we move after it.\n if (bindingParentPath.key >= path.key) {\n this.attachAfter = true;\n path = binding.path;\n\n // We also move past any constant violations.\n for (const violationPath of binding.constantViolations) {\n if (this.getAttachmentParentForPath(violationPath).key > path.key) {\n path = violationPath;\n }\n }\n }\n }\n }\n\n return path;\n }\n\n _getAttachmentPath() {\n const scopes = this.scopes;\n\n const scope = scopes.pop();\n // deopt: no compatible scopes\n if (!scope) return;\n\n if (scope.path.isFunction()) {\n if (this.hasOwnParamBindings(scope)) {\n // deopt: should ignore this scope since it's ourselves\n if (this.scope === scope) return;\n\n // needs to be attached to the body\n const bodies = scope.path.get(\"body\").get(\"body\") as NodePath[];\n for (let i = 0; i < bodies.length; i++) {\n // Don't attach to something that's going to get hoisted,\n // like a default parameter\n // @ts-expect-error todo(flow->ts): avoid mutating the node, introducing new fields\n if (bodies[i].node._blockHoist) continue;\n return bodies[i];\n }\n // deopt: If here, no attachment path found\n } else {\n // doesn't need to be be attached to this scope\n return this.getNextScopeAttachmentParent();\n }\n } else if (scope.path.isProgram()) {\n return this.getNextScopeAttachmentParent();\n }\n }\n\n getNextScopeAttachmentParent() {\n const scope = this.scopes.pop();\n if (scope) return this.getAttachmentParentForPath(scope.path);\n }\n\n // Find an attachment for this path.\n getAttachmentParentForPath(path: NodePath) {\n do {\n if (\n // Beginning of the scope\n !path.parentPath ||\n // Has siblings and is a statement\n (Array.isArray(path.container) && path.isStatement())\n ) {\n return path;\n }\n } while ((path = path.parentPath));\n }\n\n // Returns true if a scope has param bindings.\n hasOwnParamBindings(scope: Scope) {\n for (const name of Object.keys(this.bindings)) {\n if (!scope.hasOwnBinding(name)) continue;\n\n const binding = this.bindings[name];\n // Ensure constant; without it we could place behind a reassignment\n if (binding.kind === \"param\" && binding.constant) return true;\n }\n return false;\n }\n\n run(): NodePath<t.Expression> | undefined {\n this.path.traverse(referenceVisitor, this);\n\n if (this.mutableBinding) return;\n\n this.getCompatibleScopes();\n\n const attachTo = this.getAttachmentPath();\n if (!attachTo) return;\n\n // don't bother hoisting to the same function as this will cause multiple branches to be\n // evaluated more than once leading to a bad optimisation\n if (attachTo.getFunctionParent() === this.path.getFunctionParent()) return;\n\n // generate declaration and insert it to our point\n let uid: t.Identifier | t.JSXExpressionContainer =\n attachTo.scope.generateUidIdentifier(\"ref\");\n\n // @ts-expect-error todo(flow->ts): more specific type for this.path\n const declarator = variableDeclarator(uid, this.path.node);\n\n const insertFn = this.attachAfter ? \"insertAfter\" : \"insertBefore\";\n const [attached] = attachTo[insertFn]([\n attachTo.isVariableDeclarator()\n ? declarator\n : variableDeclaration(\"var\", [declarator]),\n ]);\n\n const parent = this.path.parentPath;\n if (parent.isJSXElement() && this.path.container === parent.node.children) {\n // turning the `span` in `<div><span /></div>` to an expression so we need to wrap it with\n // an expression container\n uid = jsxExpressionContainer(uid);\n }\n\n this.path.replaceWith(cloneNode(uid));\n\n return attachTo.isVariableDeclarator()\n ? attached.get(\"init\")\n : attached.get(\"declarations.0.init\");\n }\n}\n"],"mappings":"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"} |