diff --git a/java/src/com/google/template/soy/incrementaldomsrc/AssistantForHtmlMsgs.java b/java/src/com/google/template/soy/incrementaldomsrc/AssistantForHtmlMsgs.java index 0d3803cdc3..281699598c 100644 --- a/java/src/com/google/template/soy/incrementaldomsrc/AssistantForHtmlMsgs.java +++ b/java/src/com/google/template/soy/incrementaldomsrc/AssistantForHtmlMsgs.java @@ -195,14 +195,10 @@ Statement generateMsgGroupCode(MsgFallbackGroupNode node) { if (phNode.getParent() instanceof VeLogNode) { VeLogNode parent = (VeLogNode) phNode.getParent(); if (parent.getChild(0) == phNode) { - GenIncrementalDomTemplateBodyVisitor.VeLogStateHolder state = - idomTemplateBodyVisitor.openVeLogNode(parent); - // It is a compiler failure to have a logOnly in a message node. - Preconditions.checkState(state.logOnlyConditional == null); - value = Statements.of(state.enterStatement, value); + value = Statements.of(idomTemplateBodyVisitor.openVeLogNode(parent), value); } if (parent.getChild(parent.numChildren() - 1) == phNode) { - value = Statements.of(value, idomTemplateBodyVisitor.exitVeLogNode(parent, null)); + value = Statements.of(value, idomTemplateBodyVisitor.exitVeLogNode(parent)); } } switchBuilder.addCase(Expressions.stringLiteral(ph.getKey()), value); diff --git a/java/src/com/google/template/soy/incrementaldomsrc/GenIncrementalDomTemplateBodyVisitor.java b/java/src/com/google/template/soy/incrementaldomsrc/GenIncrementalDomTemplateBodyVisitor.java index 7b1ae4add3..cdbc8697a4 100644 --- a/java/src/com/google/template/soy/incrementaldomsrc/GenIncrementalDomTemplateBodyVisitor.java +++ b/java/src/com/google/template/soy/incrementaldomsrc/GenIncrementalDomTemplateBodyVisitor.java @@ -25,8 +25,8 @@ import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_ATTR; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_CLOSE; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_ELEMENT_CLOSE; -import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_ENTER; -import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_EXIT; +import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_ENTER_VELOG; +import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_EXIT_VELOG; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_KEEP_GOING; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_LOGGING_FUNCTION_ATTR; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_OPEN; @@ -38,9 +38,6 @@ import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_PUSH_KEY; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_PUSH_MANUAL_KEY; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_TEXT; -import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_TODEFAULT; -import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_TONULL; -import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_VERIFY_LOGONLY; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.INCREMENTAL_DOM_VISIT_HTML_COMMENT; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.SOY_IDOM_CALL_DYNAMIC_ATTRIBUTES; import static com.google.template.soy.incrementaldomsrc.IncrementalDomRuntime.SOY_IDOM_CALL_DYNAMIC_CSS; @@ -139,33 +136,6 @@ * print the function calls and changing how statements are combined. */ public final class GenIncrementalDomTemplateBodyVisitor extends GenJsTemplateBodyVisitor { - - /** - * Class that contains the state generated from visiting the beginning of a velogging statement. - * This allows one to generate code such as - * - *
-   *   var velog_1 = foobar;
-   *   if (velog_1) {
-   *     idom = idom.toNullRenderer();
-   *   }
-   *   idom.enter(new Metadata(...));
-   *   ...
-   *   if (velog_1) {
-   *     idom = idom.toDefaultRenderer();
-   *   }
-   * 
- */ - static class VeLogStateHolder { - Expression logOnlyConditional; // Holds the variable reference to velog_1 - Statement enterStatement; // Contains the idom.enter(...) statement - - public VeLogStateHolder(Expression logOnlyConditional, Statement enterStatement) { - this.logOnlyConditional = logOnlyConditional; - this.enterStatement = enterStatement; - } - } - private final Deque contentKind; private final List staticVarDeclarations; private final boolean generatePositionalParamsSignature; @@ -1080,45 +1050,29 @@ protected Statement visitSkipNode(SkipNode node) { @Override protected Statement visitVeLogNode(VeLogNode node) { List statements = new ArrayList<>(); - VeLogStateHolder state = openVeLogNode(node); - statements.add(state.enterStatement); + statements.add(openVeLogNode(node)); statements.addAll(visitChildren(node)); - statements.add(exitVeLogNode(node, state.logOnlyConditional)); + statements.add(exitVeLogNode(node)); return Statements.of(statements); } - VeLogStateHolder openVeLogNode(VeLogNode node) { - Expression isLogOnly = Expressions.LITERAL_FALSE; - VariableDeclaration isLogOnlyVar; - Expression isLogOnlyReference = null; - List stmts = new ArrayList<>(); + Statement openVeLogNode(VeLogNode node) { + Expression veData = getExprTranslator().exec(node.getVeDataExpression()); if (node.getLogonlyExpression() != null) { - String idName = "velog_" + staticsCounter++; - isLogOnlyReference = id(idName); - isLogOnly = getExprTranslator().exec(node.getLogonlyExpression()); - isLogOnlyVar = VariableDeclaration.builder(idName).setRhs(isLogOnly).build(); - stmts.add(isLogOnlyVar); - stmts.add( - Statements.ifStatement( - INCREMENTAL_DOM_VERIFY_LOGONLY.call(isLogOnlyVar.ref()), - Statements.assign(INCREMENTAL_DOM, INCREMENTAL_DOM_TONULL.call())) - .build()); + return Statements.assign( + INCREMENTAL_DOM, + INCREMENTAL_DOM_ENTER_VELOG.call( + veData, getExprTranslator().exec(node.getLogonlyExpression()))); } - Expression veData = getExprTranslator().exec(node.getVeDataExpression()); - stmts.add(INCREMENTAL_DOM_ENTER.call(veData, isLogOnly).asStatement()); - return new VeLogStateHolder(isLogOnlyReference, Statements.of(stmts)); + return INCREMENTAL_DOM_ENTER_VELOG.call(veData).asStatement(); } - Statement exitVeLogNode(VeLogNode node, @Nullable Expression isLogOnly) { - Statement exit = INCREMENTAL_DOM_EXIT.call().asStatement(); - if (isLogOnly != null) { - return Statements.of( - exit, - Statements.ifStatement( - isLogOnly, Statements.assign(INCREMENTAL_DOM, INCREMENTAL_DOM_TODEFAULT.call())) - .build()); + Statement exitVeLogNode(VeLogNode node) { + var exit = INCREMENTAL_DOM_EXIT_VELOG.call(); + if (node.getLogonlyExpression() != null) { + return Statements.assign(INCREMENTAL_DOM, exit); } - return exit; + return exit.asStatement(); } @Override diff --git a/java/src/com/google/template/soy/incrementaldomsrc/IncrementalDomRuntime.java b/java/src/com/google/template/soy/incrementaldomsrc/IncrementalDomRuntime.java index 7b1752462f..8375b13bfd 100644 --- a/java/src/com/google/template/soy/incrementaldomsrc/IncrementalDomRuntime.java +++ b/java/src/com/google/template/soy/incrementaldomsrc/IncrementalDomRuntime.java @@ -70,18 +70,11 @@ final class IncrementalDomRuntime { public static final Expression INCREMENTAL_DOM_APPLY_ATTRS = INCREMENTAL_DOM.dotAccess("applyAttrs"); - public static final Expression INCREMENTAL_DOM_ENTER = INCREMENTAL_DOM.dotAccess("enter"); + public static final Expression INCREMENTAL_DOM_ENTER_VELOG = + INCREMENTAL_DOM.dotAccess("enterVeLog"); - public static final Expression INCREMENTAL_DOM_EXIT = INCREMENTAL_DOM.dotAccess("exit"); - - public static final Expression INCREMENTAL_DOM_VERIFY_LOGONLY = - INCREMENTAL_DOM.dotAccess("verifyLogOnly"); - - public static final Expression INCREMENTAL_DOM_TODEFAULT = - INCREMENTAL_DOM.dotAccess("toDefaultRenderer"); - - public static final Expression INCREMENTAL_DOM_TONULL = - INCREMENTAL_DOM.dotAccess("toNullRenderer"); + public static final Expression INCREMENTAL_DOM_EXIT_VELOG = + INCREMENTAL_DOM.dotAccess("exitVeLog"); public static final Expression INCREMENTAL_DOM_TEXT = INCREMENTAL_DOM.dotAccess("text"); public static final Expression INCREMENTAL_DOM_PRINT = INCREMENTAL_DOM.dotAccess("print"); diff --git a/java/src/com/google/template/soy/jssrc/internal/VeLogInstrumentationVisitor.java b/java/src/com/google/template/soy/jssrc/internal/VeLogInstrumentationVisitor.java index 0236703063..968e68f331 100644 --- a/java/src/com/google/template/soy/jssrc/internal/VeLogInstrumentationVisitor.java +++ b/java/src/com/google/template/soy/jssrc/internal/VeLogInstrumentationVisitor.java @@ -124,7 +124,7 @@ private static LoggingFunctionInfo getLoggingFunctionInfo(CallParamNode paramNod /** * Element composition calls are deconstructed into call nodes. However, some of the attributes * contain velogging functions. This takes those attributes and puts them on a wrapping `veAttr` - * element, which the runtime libarary then manages. So the overall DOM structure becomes + * element, which the runtime library then manages. So the overall DOM structure becomes * *
{@code
    * 
diff --git a/javascript/api_idom.ts b/javascript/api_idom.ts
index 915c68bdff..aacc3177ef 100644
--- a/javascript/api_idom.ts
+++ b/javascript/api_idom.ts
@@ -1,5 +1,4 @@
 /**
-
  * @fileoverview
  *
  * Functions necessary to interact with the Soy-Idom runtime.
@@ -113,13 +112,13 @@ export interface IncrementalDomRenderer {
   skipNode(): void;
   applyAttrs(): void;
   applyStatics(statics: incrementaldom.Statics): void;
-  enter(veData: $$VisualElementData, logOnly: boolean): void;
-  exit(): void;
-  toNullRenderer(): IncrementalDomRenderer;
-  toDefaultRenderer(): IncrementalDomRenderer;
-  setLogger(logger: Logger | null): void;
-  getLogger(): Logger | null;
-  verifyLogOnly(logOnly: boolean): boolean;
+  enterVeLog(
+    veData: $$VisualElementData,
+    logOnly?: boolean,
+  ): IncrementalDomRenderer;
+  exitVeLog(): IncrementalDomRenderer;
+  setLogger(logger: Logger | undefined): void;
+  getLogger(): Logger | undefined;
   evalLoggingFunction(
     name: string,
     args: Array<{}>,
@@ -159,7 +158,7 @@ export class IncrementalDomRendererImpl implements IncrementalDomRenderer {
   // Note that for performance, the "stack" is implemented as a string with
   // the items being `${SIZE OF KEY}${DELIMITER}${KEY}`.
   private readonly keyStackHolder: string[] = [];
-  private logger: Logger | null = null;
+  private logger: Logger | undefined;
 
   /**
    * Pushes/pops the given key from `keyStack` (versus `Array#concat`)
@@ -436,40 +435,37 @@ export class IncrementalDomRendererImpl implements IncrementalDomRenderer {
   /**
    * Called when a `{velog}` statement is entered.
    */
-  enter(veData: $$VisualElementData, logOnly: boolean) {
-    if (this.logger) {
-      this.logger.enter(
-        new ElementMetadata(veData.getVe().getId(), veData.getData(), logOnly),
+  enterVeLog(
+    veData: $$VisualElementData,
+    logOnly?: boolean,
+  ): IncrementalDomRenderer {
+    const logger = this.logger;
+    if (logger) {
+      logger.enter(
+        new ElementMetadata(
+          veData.getVe().getId(),
+          veData.getData(),
+          !!logOnly,
+        ),
+      );
+    } else if (logOnly) {
+      throw new Error(
+        'Cannot set logonly="true" unless there is a logger configured',
       );
     }
+    return logOnly ? new NullRenderer(this) : this;
   }
 
   /**
    * Called when a `{velog}` statement is exited.
    */
-  exit() {
-    if (this.logger) {
-      this.logger.exit();
-    }
-  }
-
-  /**
-   * Switches runtime to produce incremental dom calls that do not traverse
-   * the DOM. This happens when logOnly in a velogging node is set to true.
-   */
-  toNullRenderer(): IncrementalDomRenderer {
-    const nullRenderer = new NullRenderer(this);
-    return nullRenderer;
-  }
-
-  toDefaultRenderer(): IncrementalDomRenderer {
-    throw new Error(
-      'Cannot transition a default renderer to a default renderer',
-    );
+  exitVeLog(): IncrementalDomRenderer {
+    this.logger?.exit();
+    return this;
   }
 
   /** Called by user code to configure logging */
-  setLogger(logger: Logger | null) {
+  setLogger(logger: Logger | undefined) {
     this.logger = logger;
   }
 
@@ -477,19 +473,6 @@ export class IncrementalDomRendererImpl implements IncrementalDomRenderer {
     return this.logger;
   }
 
-  /**
-   * Used to trigger the requirement that logOnly can only be true when a
-   * logger is configured. Otherwise, it is a passthrough function.
-   */
-  verifyLogOnly(logOnly: boolean) {
-    if (!this.logger && logOnly) {
-      throw new Error(
-        'Cannot set logonly="true" unless there is a logger configured',
-      );
-    }
-    return logOnly;
-  }
-
   /*
    * Called when a logging function is evaluated.
    */
@@ -598,6 +581,7 @@ export class IncrementalDomRendererImpl implements IncrementalDomRenderer {
  * Renderer that mutes all IDOM commands and returns void.
  */
 export class NullRenderer extends IncrementalDomRendererImpl {
+  private depth = 1;
   constructor(private readonly renderer: IncrementalDomRenderer) {
     super();
     this.setLogger(renderer.getLogger());
@@ -639,10 +623,23 @@ export class NullRenderer extends IncrementalDomRendererImpl {
 
   override skipNode() {}
 
+  override enterVeLog(
+    data: $$VisualElementData,
+    logOnly?: boolean,
+  ): IncrementalDomRenderer {
+    super.enterVeLog(data, logOnly);
+    this.depth++;
+    return this;
+  }
+
   /** Returns to the default renderer which will traverse the DOM. */
-  override toDefaultRenderer() {
-    this.renderer.setLogger(this.getLogger());
-    return this.renderer;
+  override exitVeLog(): IncrementalDomRenderer {
+    super.exitVeLog();
+    this.depth--;
+    if (this.depth === 0) {
+      return this.renderer;
+    }
+    return this;
   }
 }
 
@@ -729,15 +726,17 @@ export class FalsinessRenderer extends IncrementalDomRendererImpl {
   override popManualKey(): void {}
   override pushKey(key: string): void {}
   override popKey(): void {}
-  override enter(): void {}
-  override exit(): void {}
-  override setLogger(logger: Logger | null): void {}
-  override getLogger(): Logger | null {
-    return null;
+  override enterVeLog(): IncrementalDomRenderer {
+    return this;
   }
-  override verifyLogOnly(logOnly: boolean): boolean {
-    return logOnly;
+  override exitVeLog(): IncrementalDomRenderer {
+    return this;
   }
+  override setLogger(logger: Logger | undefined): void {}
+  override getLogger(): Logger | undefined {
+    return undefined;
+  }
+
   override evalLoggingFunction(
     name: string,
     args: Array<{}>,
@@ -838,8 +837,8 @@ const noArgCallConsts = {
   popKey: (actual: IncrementalDomRenderer) => {
     actual.popKey();
   },
-  exit: (actual: IncrementalDomRenderer) => {
-    actual.exit();
+  exitVeLog: (actual: IncrementalDomRenderer) => {
+    actual.exitVeLog();
   },
   close: (actual: IncrementalDomRenderer) => {
     actual.close();
@@ -885,35 +884,30 @@ export class BufferingIncrementalDomRenderer implements IncrementalDomRenderer {
   popKey(): void {
     this.buffer.push(noArgCallConsts.popKey);
   }
-  enter(veData: $$VisualElementData, logOnly: boolean): void {
+  enterVeLog(
+    veData: $$VisualElementData,
+    logOnly?: boolean,
+  ): IncrementalDomRenderer {
     this.buffer.push((actual) => {
-      actual.enter(veData, logOnly);
+      actual.enterVeLog(veData, logOnly);
     });
+    return logOnly ? new NullRenderer(this) : this;
   }
-  exit(): void {
-    this.buffer.push(noArgCallConsts.exit);
+  exitVeLog(): IncrementalDomRenderer {
+    this.buffer.push(noArgCallConsts.exitVeLog);
+    return this;
   }
-  toNullRenderer(): IncrementalDomRenderer {
-    return new NullRenderer(this);
-  }
-  toDefaultRenderer(): IncrementalDomRenderer {
-    throw new Error(
-      'Cannot transition a buffered renderer to a default renderer',
-    );
-  }
-  setLogger(logger: Logger | null): void {
+
+  setLogger(logger: Logger | undefined): void {
     throw new Error(
       'Tried to call setLogger on BufferingIncrementalDomRenderer.',
     );
   }
-  getLogger(): Logger | null {
+  getLogger(): Logger | undefined {
     throw new Error(
       'Tried to call getLogger on BufferingIncrementalDomRenderer.',
     );
   }
-  verifyLogOnly(logOnly: boolean): boolean {
-    return logOnly;
-  }
   evalLoggingFunction(
     name: string,
     args: Array<{}>,
diff --git a/javascript/element_lib_idom.ts b/javascript/element_lib_idom.ts
index 15f95854fa..a61c6b3e15 100644
--- a/javascript/element_lib_idom.ts
+++ b/javascript/element_lib_idom.ts
@@ -52,7 +52,7 @@ export abstract class SoyElement
   private patchHandler: ((prev: TInterface, next: TInterface) => void) | null =
     null;
   private syncState = true;
-  private loggerPrivate: Logger | null = null;
+  private loggerPrivate: Logger | undefined;
   // Marker so that future element accesses can find this Soy element from the
   // DOM
   key: string = '';
@@ -79,7 +79,7 @@ export abstract class SoyElement
    * is called with a Renderer that has its own Logger, Renderer's Logger is
    * used instead.
    */
-  setLogger(logger: Logger | null): this {
+  setLogger(logger: Logger | undefined): this {
     this.loggerPrivate = logger;
     return this;
   }