function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
  if (localBindings && !id) {
    throw new Error("Unexpected local bindings for module-based helpers.");
  }

  if (!id) return;

  const {
    localBindingNames,
    dependencies,
    exportBindingAssignments,
    exportPath,
    exportName,
    importBindingsReferences,
    importPaths,
  } = metadata;

  const dependenciesRefs = {};
  dependencies.forEach((name, id) => {
    dependenciesRefs[id.name] =
      (typeof getDependency === "function" && getDependency(name)) || id;
  });

  const toRename = {};
  const bindings = new Set(localBindings || []);
  localBindingNames.forEach(name => {
    let newName = name;
    while (bindings.has(newName)) newName = "_" + newName;

    if (newName !== name) toRename[name] = newName;
  });

  if (id.type === "Identifier" && exportName !== id.name) {
    toRename[exportName] = id.name;
  }

  const visitor = {
    Program(path) {
      // We need to compute these in advance because removing nodes would
      // invalidate the paths.
      const exp = path.get(exportPath);
      const imps = importPaths.map(p => path.get(p));
      const impsBindingRefs = importBindingsReferences.map(p => path.get(p));

      const decl = exp.get("declaration");
      if (id.type === "Identifier") {
        if (decl.isFunctionDeclaration()) {
          exp.replaceWith(decl);
        } else {
          exp.replaceWith(
            t.variableDeclaration("var", [t.variableDeclarator(id, decl.node)]),
          );
        }
      } else if (id.type === "MemberExpression") {
        if (decl.isFunctionDeclaration()) {
          exportBindingAssignments.forEach(assignPath => {
            const assign = path.get(assignPath);
            assign.replaceWith(t.assignmentExpression("=", id, assign.node));
          });
          exp.replaceWith(decl);
          path.pushContainer(
            "body",
            t.expressionStatement(
              t.assignmentExpression("=", id, t.identifier(exportName)),
            ),
          );
        } else {
          exp.replaceWith(
            t.expressionStatement(t.assignmentExpression("=", id, decl.node)),
          );
        }
      } else {
        throw new Error("Unexpected helper format.");
      }

      Object.keys(toRename).forEach(name => {
        path.scope.rename(name, toRename[name]);
      });

      for (const path of imps) path.remove();
      for (const path of impsBindingRefs) {
        const node = t.cloneNode(dependenciesRefs[path.node.name]);
        path.replaceWith(node);
      }

      // We only use "traverse" for all the handy scoping helpers, so we can stop immediately without
      // actually doing the traversal.
      path.stop();
    },
  };
  traverse(file.ast, visitor, file.scope);
}
/**
 * Given a helper AST and information about how it will be used, update the AST to match the usage.
 */
Given a helper AST and information about how it will be used, update the AST to match the usage.
Given a helper AST and information about how it will be used update the AST to match the usage .
function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
  if (localBindings && !id) {
    throw new Error("Unexpected local bindings for module-based helpers.");
  }
  if (!id) return;
  const {
    localBindingNames,
    dependencies,
    exportBindingAssignments,
    exportPath,
    exportName,
    importBindingsReferences,
    importPaths,
  } = metadata;
  const dependenciesRefs = {};
  dependencies.forEach((name, id) => {
    dependenciesRefs[id.name] =
      (typeof getDependency === "function" && getDependency(name)) || id;
  });
  const toRename = {};
  const bindings = new Set(localBindings || []);
  localBindingNames.forEach(name => {
    let newName = name;
    while (bindings.has(newName)) newName = "_" + newName;
    if (newName !== name) toRename[name] = newName;
  });
  if (id.type === "Identifier" && exportName !== id.name) {
    toRename[exportName] = id.name;
  }
  const visitor = {
    Program(path) {
      const exp = path.get(exportPath);
      const imps = importPaths.map(p => path.get(p));
      const impsBindingRefs = importBindingsReferences.map(p => path.get(p));
      const decl = exp.get("declaration");
      if (id.type === "Identifier") {
        if (decl.isFunctionDeclaration()) {
          exp.replaceWith(decl);
        } else {
          exp.replaceWith(
            t.variableDeclaration("var", [t.variableDeclarator(id, decl.node)]),
          );
        }
      } else if (id.type === "MemberExpression") {
        if (decl.isFunctionDeclaration()) {
          exportBindingAssignments.forEach(assignPath => {
            const assign = path.get(assignPath);
            assign.replaceWith(t.assignmentExpression("=", id, assign.node));
          });
          exp.replaceWith(decl);
          path.pushContainer(
            "body",
            t.expressionStatement(
              t.assignmentExpression("=", id, t.identifier(exportName)),
            ),
          );
        } else {
          exp.replaceWith(
            t.expressionStatement(t.assignmentExpression("=", id, decl.node)),
          );
        }
      } else {
        throw new Error("Unexpected helper format.");
      }
      Object.keys(toRename).forEach(name => {
        path.scope.rename(name, toRename[name]);
      });
      for (const path of imps) path.remove();
      for (const path of impsBindingRefs) {
        const node = t.cloneNode(dependenciesRefs[path.node.name]);
        path.replaceWith(node);
      }
      path.stop();
    },
  };
  traverse(file.ast, visitor, file.scope);
}
function permuteHelperAST ( file , metadata , id , localBindings , getDependency ) { if ( localBindings && ! id ) { throw new Error ( "Unexpected local bindings for module-based helpers." ) ; } if ( ! id ) return ; const { localBindingNames , dependencies , exportBindingAssignments , exportPath , exportName , importBindingsReferences , importPaths , } = metadata ; const dependenciesRefs = { } ; dependencies . forEach ( ( name , id ) => { dependenciesRefs [ id . name ] = ( typeof getDependency === "function" && getDependency ( name ) ) || id ; } ) ; const toRename = { } ; const bindings = new Set ( localBindings || [ ] ) ; localBindingNames . forEach ( name => { let newName = name ; while ( bindings . has ( newName ) ) newName = "_" + newName ; if ( newName !== name ) toRename [ name ] = newName ; } ) ; if ( id . type === "Identifier" && exportName !== id . name ) { toRename [ exportName ] = id . name ; } const visitor = { Program ( path ) { const exp = path . get ( exportPath ) ; const imps = importPaths . map ( p => path . get ( p ) ) ; const impsBindingRefs = importBindingsReferences . map ( p => path . get ( p ) ) ; const decl = exp . get ( "declaration" ) ; if ( id . type === "Identifier" ) { if ( decl . isFunctionDeclaration ( ) ) { exp . replaceWith ( decl ) ; } else { exp . replaceWith ( t . variableDeclaration ( "var" , [ t . variableDeclarator ( id , decl . node ) ] ) , ) ; } } else if ( id . type === "MemberExpression" ) { if ( decl . isFunctionDeclaration ( ) ) { exportBindingAssignments . forEach ( assignPath => { const assign = path . get ( assignPath ) ; assign . replaceWith ( t . assignmentExpression ( "=" , id , assign . node ) ) ; } ) ; exp . replaceWith ( decl ) ; path . pushContainer ( "body" , t . expressionStatement ( t . assignmentExpression ( "=" , id , t . identifier ( exportName ) ) , ) , ) ; } else { exp . replaceWith ( t . expressionStatement ( t . assignmentExpression ( "=" , id , decl . node ) ) , ) ; } } else { throw new Error ( "Unexpected helper format." ) ; } Object . keys ( toRename ) . forEach ( name => { path . scope . rename ( name , toRename [ name ] ) ; } ) ; for ( const path of imps ) path . remove ( ) ; for ( const path of impsBindingRefs ) { const node = t . cloneNode ( dependenciesRefs [ path . node . name ] ) ; path . replaceWith ( node ) ; } path . stop ( ) ; } , } ; traverse ( file . ast , visitor , file . scope ) ; }
Given a helper AST and information about how it will be used, update the AST to match the usage.
Given a helper AST and information about how it will be used update the AST to match the usage .
// We need to compute these in advance because removing nodes would // invalidate the paths. // We only use "traverse" for all the handy scoping helpers, so we can stop immediately without // actually doing the traversal.