docs: private Statement handleForeachLoop(
        ForNonemptyNode node,
        Expression limit,
        Function<Expression, Expression> getDataItemFunction) {
      // Build some local variable names.
      String varName = node.getVarName();
      String varPrefix = varName + node.getForNodeId();
  
      // TODO(b/32224284): A more consistent pattern for local variable management.
      String loopIndexName = varPrefix + "Index";
      String dataName = varPrefix + "Data";
  
      Expression loopIndex = id(loopIndexName);
      VariableDeclaration data =
          VariableDeclaration.builder(dataName).setRhs(getDataItemFunction.apply(loopIndex)).build();
  
      // Populate the local var translations with the translations from this node.
      templateTranslationContext
          .soyToJsVariableMappings()
          .put(varName, id(dataName))
          .put(varName + "__isFirst", loopIndex.doubleEquals(number(0)))
          .put(varName + "__isLast", loopIndex.doubleEquals(limit.minus(number(1))))
          .put(varName + "__index", loopIndex);
  
      // Generate the loop body.
      Statement foreachBody = Statement.of(data, visitChildrenReturningCodeChunk(node));
  
      // Create the entire for block.
      return forLoop(loopIndexName, limit, foreachBody);
    }