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
{@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; }