export default function () { return { visitor: { VariableDeclaration(path, file) { let { node, parent, scope } = path; if (!isBlockScoped(node)) return; convertBlockScopedToVar(path, null, parent, scope, true); if (node._tdzThis) { let nodes = [node]; for (let i = 0; i < node.declarations.length; i++) { let decl = node.declarations[i]; if (decl.init) { let assign = t.assignmentExpression("=", decl.id, decl.init); assign._ignoreBlockScopingTDZ = true; nodes.push(t.expressionStatement(assign)); } decl.init = file.addHelper("temporalUndefined"); } node._blockHoist = 2; if (path.isCompletionRecord()) { // ensure we don't break completion record semantics by returning // the initialiser of the last declarator nodes.push(t.expressionStatement(scope.buildUndefinedNode())); } path.replaceWithMultiple(nodes); } }, Loop(path, file) { let { node, parent, scope } = path; t.ensureBlock(node); let blockScoping = new BlockScoping(path, path.get("body"), parent, scope, file); let replace = blockScoping.run(); if (replace) path.replaceWith(replace); }, CatchClause(path, file) { let { parent, scope } = path; let blockScoping = new BlockScoping(null, path.get("body"), parent, scope, file); blockScoping.run(); }, "BlockStatement|SwitchStatement|Program"(path, file) { if (!ignoreBlock(path)) { let blockScoping = new BlockScoping(null, path, path.parent, path.scope, file); blockScoping.run(); } } } }; }
push(opts: { id: Object; init: ?Object; unique: ?boolean; _blockHoist: ?number; kind: "var" | "let"; }) { let path = this.path; if (!path.isBlockStatement() && !path.isProgram()) { path = this.getBlockParent().path; } if (path.isSwitchStatement()) { path = this.getFunctionParent().path; } if (path.isLoop() || path.isCatchClause() || path.isFunction()) { t.ensureBlock(path.node); path = path.get("body"); } let unique = opts.unique; let kind = opts.kind || "var"; let blockHoist = opts._blockHoist == null ? 2 : opts._blockHoist; let dataKey = `declaration:${kind}:${blockHoist}`; let declarPath = !unique && path.getData(dataKey); if (!declarPath) { let declar = t.variableDeclaration(kind, []); declar._generated = true; declar._blockHoist = blockHoist; [declarPath] = path.unshiftContainer("body", [declar]); if (!unique) path.setData(dataKey, declarPath); } let declarator = t.variableDeclarator(opts.id, opts.init); declarPath.node.declarations.push(declarator); this.registerBinding(kind, declarPath.get("declarations").pop()); }
export function ensureBlock() { return t.ensureBlock(this.node); }