| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 | "use strict";Object.defineProperty(exports, "__esModule", {  value: true});exports.getLoopBodyBindings = getLoopBodyBindings;exports.getUsageInBody = getUsageInBody;exports.isVarInLoopHead = isVarInLoopHead;exports.wrapLoopBody = wrapLoopBody;var _core = require("@babel/core");const collectLoopBodyBindingsVisitor = {  "Expression|Declaration|Loop"(path) {    path.skip();  },  Scope(path, state) {    if (path.isFunctionParent()) path.skip();    const {      bindings    } = path.scope;    for (const name of Object.keys(bindings)) {      const binding = bindings[name];      if (binding.kind === "let" || binding.kind === "const" || binding.kind === "hoisted") {        state.blockScoped.push(binding);      }    }  }};function getLoopBodyBindings(loopPath) {  const state = {    blockScoped: []  };  loopPath.traverse(collectLoopBodyBindingsVisitor, state);  return state.blockScoped;}function getUsageInBody(binding, loopPath) {  const seen = new WeakSet();  let capturedInClosure = false;  const constantViolations = filterMap(binding.constantViolations, path => {    const {      inBody,      inClosure    } = relativeLoopLocation(path, loopPath);    if (!inBody) return null;    capturedInClosure || (capturedInClosure = inClosure);    const id = path.isUpdateExpression() ? path.get("argument") : path.isAssignmentExpression() ? path.get("left") : null;    if (id) seen.add(id.node);    return id;  });  const references = filterMap(binding.referencePaths, path => {    if (seen.has(path.node)) return null;    const {      inBody,      inClosure    } = relativeLoopLocation(path, loopPath);    if (!inBody) return null;    capturedInClosure || (capturedInClosure = inClosure);    return path;  });  return {    capturedInClosure,    hasConstantViolations: constantViolations.length > 0,    usages: references.concat(constantViolations)  };}function relativeLoopLocation(path, loopPath) {  const bodyPath = loopPath.get("body");  let inClosure = false;  for (let currPath = path; currPath; currPath = currPath.parentPath) {    if (currPath.isFunction() || currPath.isClass() || currPath.isMethod()) {      inClosure = true;    }    if (currPath === bodyPath) {      return {        inBody: true,        inClosure      };    } else if (currPath === loopPath) {      return {        inBody: false,        inClosure      };    }  }  throw new Error("Internal Babel error: path is not in loop. Please report this as a bug.");}const collectCompletionsAndVarsVisitor = {  Function(path) {    path.skip();  },  LabeledStatement: {    enter({      node    }, state) {      state.labelsStack.push(node.label.name);    },    exit({      node    }, state) {      const popped = state.labelsStack.pop();      if (popped !== node.label.name) {        throw new Error("Assertion failure. Please report this bug to Babel.");      }    }  },  Loop: {    enter(_, state) {      state.labellessContinueTargets++;      state.labellessBreakTargets++;    },    exit(_, state) {      state.labellessContinueTargets--;      state.labellessBreakTargets--;    }  },  SwitchStatement: {    enter(_, state) {      state.labellessBreakTargets++;    },    exit(_, state) {      state.labellessBreakTargets--;    }  },  "BreakStatement|ContinueStatement"(path, state) {    const {      label    } = path.node;    if (label) {      if (state.labelsStack.includes(label.name)) return;    } else if (path.isBreakStatement() ? state.labellessBreakTargets > 0 : state.labellessContinueTargets > 0) {      return;    }    state.breaksContinues.push(path);  },  ReturnStatement(path, state) {    state.returns.push(path);  },  VariableDeclaration(path, state) {    if (path.parent === state.loopNode && isVarInLoopHead(path)) return;    if (path.node.kind === "var") state.vars.push(path);  }};function wrapLoopBody(loopPath, captured, updatedBindingsUsages) {  const loopNode = loopPath.node;  const state = {    breaksContinues: [],    returns: [],    labelsStack: [],    labellessBreakTargets: 0,    labellessContinueTargets: 0,    vars: [],    loopNode  };  loopPath.traverse(collectCompletionsAndVarsVisitor, state);  const callArgs = [];  const closureParams = [];  const updater = [];  for (const [name, updatedUsage] of updatedBindingsUsages) {    callArgs.push(_core.types.identifier(name));    const innerName = loopPath.scope.generateUid(name);    closureParams.push(_core.types.identifier(innerName));    updater.push(_core.types.assignmentExpression("=", _core.types.identifier(name), _core.types.identifier(innerName)));    for (const path of updatedUsage) path.replaceWith(_core.types.identifier(innerName));  }  for (const name of captured) {    if (updatedBindingsUsages.has(name)) continue;    callArgs.push(_core.types.identifier(name));    closureParams.push(_core.types.identifier(name));  }  const id = loopPath.scope.generateUid("loop");  const fn = _core.types.functionExpression(null, closureParams, _core.types.toBlock(loopNode.body));  let call = _core.types.callExpression(_core.types.identifier(id), callArgs);  const fnParent = loopPath.findParent(p => p.isFunction());  if (fnParent) {    const {      async,      generator    } = fnParent.node;    fn.async = async;    fn.generator = generator;    if (generator) call = _core.types.yieldExpression(call, true);else if (async) call = _core.types.awaitExpression(call);  }  const updaterNode = updater.length > 0 ? _core.types.expressionStatement(_core.types.sequenceExpression(updater)) : null;  if (updaterNode) fn.body.body.push(updaterNode);  const [varPath] = loopPath.insertBefore(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.identifier(id), fn)]));  const bodyStmts = [];  const varNames = [];  for (const varPath of state.vars) {    const assign = [];    for (const decl of varPath.node.declarations) {      varNames.push(...Object.keys(_core.types.getBindingIdentifiers(decl.id)));      if (decl.init) {        assign.push(_core.types.assignmentExpression("=", decl.id, decl.init));      } else if (_core.types.isForXStatement(varPath.parent, {        left: varPath.node      })) {        assign.push(decl.id);      }    }    if (assign.length > 0) {      const replacement = assign.length === 1 ? assign[0] : _core.types.sequenceExpression(assign);      varPath.replaceWith(replacement);    } else {      varPath.remove();    }  }  if (varNames.length) {    varPath.pushContainer("declarations", varNames.map(name => _core.types.variableDeclarator(_core.types.identifier(name))));  }  const labelNum = state.breaksContinues.length;  const returnNum = state.returns.length;  if (labelNum + returnNum === 0) {    bodyStmts.push(_core.types.expressionStatement(call));  } else if (labelNum === 1 && returnNum === 0) {    for (const path of state.breaksContinues) {      const {        node      } = path;      const {        type,        label      } = node;      let name = type === "BreakStatement" ? "break" : "continue";      if (label) name += " " + label.name;      path.replaceWith(_core.types.addComment(_core.types.returnStatement(_core.types.numericLiteral(1)), "trailing", " " + name, true));      if (updaterNode) path.insertBefore(_core.types.cloneNode(updaterNode));      bodyStmts.push(_core.template.statement.ast`        if (${call}) ${node}      `);    }  } else {    const completionId = loopPath.scope.generateUid("ret");    if (varPath.isVariableDeclaration()) {      varPath.pushContainer("declarations", [_core.types.variableDeclarator(_core.types.identifier(completionId))]);      bodyStmts.push(_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.identifier(completionId), call)));    } else {      bodyStmts.push(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.identifier(completionId), call)]));    }    const injected = [];    for (const path of state.breaksContinues) {      const {        node      } = path;      const {        type,        label      } = node;      let name = type === "BreakStatement" ? "break" : "continue";      if (label) name += " " + label.name;      let i = injected.indexOf(name);      const hasInjected = i !== -1;      if (!hasInjected) {        injected.push(name);        i = injected.length - 1;      }      path.replaceWith(_core.types.addComment(_core.types.returnStatement(_core.types.numericLiteral(i)), "trailing", " " + name, true));      if (updaterNode) path.insertBefore(_core.types.cloneNode(updaterNode));      if (hasInjected) continue;      bodyStmts.push(_core.template.statement.ast`        if (${_core.types.identifier(completionId)} === ${_core.types.numericLiteral(i)}) ${node}      `);    }    if (returnNum) {      for (const path of state.returns) {        const arg = path.node.argument || path.scope.buildUndefinedNode();        path.replaceWith(_core.template.statement.ast`          return { v: ${arg} };        `);      }      bodyStmts.push(_core.template.statement.ast`          if (${_core.types.identifier(completionId)}) return ${_core.types.identifier(completionId)}.v;        `);    }  }  loopNode.body = _core.types.blockStatement(bodyStmts);  return varPath;}function isVarInLoopHead(path) {  if (_core.types.isForStatement(path.parent)) return path.key === "init";  if (_core.types.isForXStatement(path.parent)) return path.key === "left";  return false;}function filterMap(list, fn) {  const result = [];  for (const item of list) {    const mapped = fn(item);    if (mapped) result.push(mapped);  }  return result;}//# sourceMappingURL=loop.js.map
 |