docs: 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;
    }
  
    traverse(file, {
      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();
      },
    });
  }