You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1 line
16 KiB

{"version":3,"names":["_helperPluginUtils","require","_core","_loop","_validation","_annexB_3_","_default","exports","default","declare","api","opts","assertVersion","throwIfClosureRequired","tdz","tdzEnabled","Error","name","visitor","traverse","visitors","merge","annexB33FunctionsVisitor","Loop","path","state","isForStatement","headPath","get","isForXStatement","needsBodyWrap","markNeedsBodyWrap","buildCodeFrameError","body","bodyScope","isBlockStatement","scope","bindings","getLoopBodyBindings","binding","capturedInClosure","getUsageInBody","captured","updatedBindingsUsages","Map","isBlockScoped","node","names","Object","keys","getBindingIdentifiers","headScope","_bodyScope","hasOwnBinding","getOwnBinding","crawl","usages","hasConstantViolations","parent","hasBinding","hasGlobal","newName","generateUid","rename","push","set","varPath","wrapLoopBody","isVariableDeclaration","transformBlockScopedVariable","unwrapFunctionEnvironment","VariableDeclaration","ClassDeclaration","id","parentPath","isVarScope","noUids","conflictingFunctionsVisitor","Scope","kind","Expression|Declaration","skip","dynamicTDZNames","validateUsage","bindingNames","isInLoop","isVarInLoopHead","length","decl","declarations","_decl$init","init","buildUndefinedNode","blockScope","varScope","getFunctionParent","getProgramParent","moveBindingTo","t","identifier","addHelper","isLetOrConst","isLoop","isFunctionParent","BLOCK_SCOPED_SYMBOL"],"sources":["../src/index.ts"],"sourcesContent":["import { declare } from \"@babel/helper-plugin-utils\";\nimport type { NodePath, Scope, Visitor, PluginPass } from \"@babel/core\";\nimport { types as t, traverse } from \"@babel/core\";\n\nimport {\n getLoopBodyBindings,\n getUsageInBody,\n isVarInLoopHead,\n wrapLoopBody,\n} from \"./loop.ts\";\nimport { validateUsage } from \"./validation.ts\";\nimport { annexB33FunctionsVisitor, isVarScope } from \"./annex-B_3_3.ts\";\n\nexport interface Options {\n tdz?: boolean;\n throwIfClosureRequired?: boolean;\n}\n\nexport default declare((api, opts: Options) => {\n api.assertVersion(REQUIRED_VERSION(7));\n\n const { throwIfClosureRequired = false, tdz: tdzEnabled = false } = opts;\n if (typeof throwIfClosureRequired !== \"boolean\") {\n throw new Error(`.throwIfClosureRequired must be a boolean, or undefined`);\n }\n if (typeof tdzEnabled !== \"boolean\") {\n throw new Error(`.tdz must be a boolean, or undefined`);\n }\n\n return {\n name: \"transform-block-scoping\",\n\n visitor: traverse.visitors.merge<PluginPass>([\n // TODO: Consider adding an option to control Annex B behavior.\n annexB33FunctionsVisitor,\n {\n Loop(path: NodePath<t.Loop>, state) {\n const isForStatement = path.isForStatement();\n const headPath = isForStatement\n ? path.get(\"init\")\n : path.isForXStatement()\n ? path.get(\"left\")\n : null;\n\n let needsBodyWrap = false;\n const markNeedsBodyWrap = () => {\n if (throwIfClosureRequired) {\n throw path.buildCodeFrameError(\n \"Compiling let/const in this block would add a closure \" +\n \"(throwIfClosureRequired).\",\n );\n }\n needsBodyWrap = true;\n };\n\n const body = path.get(\"body\");\n let bodyScope: Scope | null;\n if (body.isBlockStatement()) {\n bodyScope = body.scope;\n }\n const bindings = getLoopBodyBindings(path);\n for (const binding of bindings) {\n const { capturedInClosure } = getUsageInBody(binding, path);\n if (capturedInClosure) markNeedsBodyWrap();\n }\n\n const captured: string[] = [];\n const updatedBindingsUsages: Map<string, NodePath<t.Identifier>[]> =\n new Map();\n\n if (headPath && isBlockScoped(headPath.node)) {\n const names = Object.keys(headPath.getBindingIdentifiers());\n const headScope = headPath.scope;\n\n for (let name of names) {\n if (bodyScope?.hasOwnBinding(name)) continue; // shadowed\n\n let binding = headScope.getOwnBinding(name);\n if (!binding) {\n headScope.crawl();\n binding = headScope.getOwnBinding(name);\n }\n const { usages, capturedInClosure, hasConstantViolations } =\n getUsageInBody(binding, path);\n\n if (\n headScope.parent.hasBinding(name) ||\n headScope.parent.hasGlobal(name)\n ) {\n // If the binding is not captured, there is no need\n // of adding it to the closure param. However, rename\n // it if it shadows an outer binding, because the\n // closure will be moved to an outer level.\n const newName = headScope.generateUid(name);\n headScope.rename(name, newName);\n name = newName;\n }\n\n if (capturedInClosure) {\n markNeedsBodyWrap();\n captured.push(name);\n }\n\n if (isForStatement && hasConstantViolations) {\n updatedBindingsUsages.set(name, usages);\n }\n }\n }\n\n if (needsBodyWrap) {\n const varPath = wrapLoopBody(path, captured, updatedBindingsUsages);\n\n if (headPath?.isVariableDeclaration()) {\n // If we wrap the loop body, we transform the var\n // declaration in the loop head now, to avoid\n // invalid references that break other plugins:\n //\n // for (let head of x) {\n // let i = head;\n // setTimeout(() => i);\n // }\n //\n // would become\n //\n // function _loop() {\n // let i = head;\n // setTimeout(() => i);\n // }\n // for (let head of x) _loop();\n //\n // which references `head` in a scope where it's not visible.\n transformBlockScopedVariable(headPath, state, tdzEnabled);\n }\n\n varPath.get(\"declarations.0.init\").unwrapFunctionEnvironment();\n }\n },\n\n VariableDeclaration(path, state) {\n transformBlockScopedVariable(path, state, tdzEnabled);\n },\n\n // Class declarations are block-scoped: if there is\n // a class declaration in a nested block that conflicts\n // with an outer block-scoped binding, rename it.\n // TODO: Should this be moved to the classes plugin?\n ClassDeclaration(path) {\n const { id } = path.node;\n if (!id) return;\n\n const { scope } = path.parentPath;\n if (\n !isVarScope(scope) &&\n scope.parent.hasBinding(id.name, { noUids: true })\n ) {\n path.scope.rename(id.name);\n }\n },\n },\n ]),\n };\n});\n\nconst conflictingFunctionsVisitor: Visitor<{ names: string[] }> = {\n Scope(path, { names }) {\n for (const name of names) {\n const binding = path.scope.getOwnBinding(name);\n if (binding && binding.kind === \"hoisted\") {\n path.scope.rename(name);\n }\n }\n },\n \"Expression|Declaration\"(path) {\n path.skip();\n },\n};\n\nfunction transformBlockScopedVariable(\n path: NodePath<t.VariableDeclaration>,\n state: PluginPass,\n tdzEnabled: boolean,\n) {\n if (!isBlockScoped(path.node)) return;\n\n const dynamicTDZNames = validateUsage(path, state, tdzEnabled);\n\n path.node.kind = \"var\";\n\n const bindingNames = Object.keys(path.getBindingIdentifiers());\n for (const name of bindingNames) {\n const binding = path.scope.getOwnBinding(name);\n if (!binding) continue;\n binding.kind = \"var\";\n }\n\n if (\n (isInLoop(path) && !isVarInLoopHead(path)) ||\n dynamicTDZNames.length > 0\n ) {\n for (const decl of path.node.declarations) {\n // We explicitly add `void 0` to cases like\n // for (;;) { let a; }\n // to make sure that `a` doesn't keep the value from\n // the previous iteration.\n decl.init ??= path.scope.buildUndefinedNode();\n }\n }\n\n const blockScope = path.scope;\n const varScope =\n blockScope.getFunctionParent() || blockScope.getProgramParent();\n\n if (varScope !== blockScope) {\n for (const name of bindingNames) {\n let newName = name;\n if (\n // We pass `noUids` true because, if `name` was a generated\n // UID, it has been used to declare the current variable in\n // a nested scope and thus we don't need to assume that it\n // may be declared (but not registered yet) in an upper one.\n blockScope.parent.hasBinding(name, { noUids: true }) ||\n blockScope.parent.hasGlobal(name)\n ) {\n newName = blockScope.generateUid(name);\n blockScope.rename(name, newName);\n }\n\n blockScope.moveBindingTo(newName, varScope);\n }\n }\n\n blockScope.path.traverse(conflictingFunctionsVisitor, {\n names: bindingNames,\n });\n\n for (const name of dynamicTDZNames) {\n path.scope.push({\n id: t.identifier(name),\n init: state.addHelper(\"temporalUndefined\"),\n });\n }\n}\n\nfunction isLetOrConst(kind: string): kind is \"let\" | \"const\" {\n return kind === \"let\" || kind === \"const\";\n}\n\nfunction isInLoop(path: NodePath<t.Node>): boolean {\n if (!path.parentPath) return false;\n if (path.parentPath.isLoop()) return true;\n if (path.parentPath.isFunctionParent()) return false;\n return isInLoop(path.parentPath);\n}\n\nfunction isBlockScoped(node: t.Node): node is t.VariableDeclaration {\n if (!t.isVariableDeclaration(node)) return false;\n if (\n // @ts-expect-error Fixme: document symbol properties\n node[t.BLOCK_SCOPED_SYMBOL]\n ) {\n return true;\n }\n\n if (!isLetOrConst(node.kind) && node.kind !== \"using\") {\n return false;\n }\n\n return true;\n}\n"],"mappings":"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","ignoreList":[]}