Skip to content

Commit

Permalink
refactor(compiler): introduce deferred block AST (#51050)
Browse files Browse the repository at this point in the history
Adds the logic to create `defer`-specific AST nodes from the generic HTML `BlockGroup` and `Block`. The logic for parsing the triggers will be in the next commit.

PR Close #51050
  • Loading branch information
crisbeto authored and thePunderWoman committed Jul 17, 2023
1 parent 0623158 commit 9e61616
Show file tree
Hide file tree
Showing 16 changed files with 867 additions and 37 deletions.
23 changes: 22 additions & 1 deletion packages/compiler-cli/src/ngtsc/indexer/src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AST, ASTWithSource, BoundTarget, ImplicitReceiver, ParseSourceSpan, PropertyRead, PropertyWrite, RecursiveAstVisitor, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstRecursiveVisitor, TmplAstReference, TmplAstTemplate, TmplAstVariable} from '@angular/compiler';
import {AST, ASTWithSource, BoundTarget, ImplicitReceiver, ParseSourceSpan, PropertyRead, PropertyWrite, RecursiveAstVisitor, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstDeferredBlock, TmplAstDeferredBlockError, TmplAstDeferredBlockLoading, TmplAstDeferredBlockPlaceholder, TmplAstElement, TmplAstNode, TmplAstRecursiveVisitor, TmplAstReference, TmplAstTemplate, TmplAstVariable} from '@angular/compiler';

import {ClassDeclaration, DeclarationNode} from '../../reflection';

Expand Down Expand Up @@ -187,6 +187,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
this.visitAll(element.children);
this.visitAll(element.outputs);
}

override visitTemplate(template: TmplAstTemplate) {
const templateIdentifier = this.elementOrTemplateToIdentifier(template);

Expand All @@ -200,6 +201,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
this.visitAll(template.children);
this.visitAll(template.references);
}

override visitBoundAttribute(attribute: TmplAstBoundAttribute) {
// If the bound attribute has no value, it cannot have any identifiers in the value expression.
if (attribute.valueSpan === undefined) {
Expand Down Expand Up @@ -235,6 +237,25 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
this.identifiers.add(variableIdentifier);
}

override visitDeferredBlock(deferred: TmplAstDeferredBlock) {
this.visitAll(deferred.children);
deferred.placeholder?.visit(this);
deferred.loading?.visit(this);
deferred.error?.visit(this);
}

override visitDeferredBlockPlaceholder(block: TmplAstDeferredBlockPlaceholder) {
this.visitAll(block.children);
}

override visitDeferredBlockError(block: TmplAstDeferredBlockError) {
this.visitAll(block.children);
}

override visitDeferredBlockLoading(block: TmplAstDeferredBlockLoading) {
this.visitAll(block.children);
}

/** Creates an identifier for a template element or template node. */
private elementOrTemplateToIdentifier(node: TmplAstElement|TmplAstTemplate): ElementIdentifier
|TemplateNodeIdentifier|null {
Expand Down
30 changes: 29 additions & 1 deletion packages/compiler-cli/src/ngtsc/typecheck/extended/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {AST, ASTWithSource, ParseSourceSpan, RecursiveAstVisitor, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstContent, TmplAstElement, TmplAstIcu, TmplAstNode, TmplAstRecursiveVisitor, TmplAstReference, TmplAstTemplate, TmplAstText, TmplAstTextAttribute, TmplAstVariable} from '@angular/compiler';
import {AST, ASTWithSource, ParseSourceSpan, RecursiveAstVisitor, TmplAstBoundAttribute, TmplAstBoundDeferredTrigger, TmplAstBoundEvent, TmplAstBoundText, TmplAstContent, TmplAstDeferredBlock, TmplAstDeferredBlockError, TmplAstDeferredBlockLoading, TmplAstDeferredBlockPlaceholder, TmplAstDeferredTrigger, TmplAstElement, TmplAstIcu, TmplAstNode, TmplAstRecursiveVisitor, TmplAstReference, TmplAstTemplate, TmplAstText, TmplAstTextAttribute, TmplAstVariable} from '@angular/compiler';
import ts from 'typescript';

import {NgCompilerOptions} from '../../../core/api';
Expand Down Expand Up @@ -159,6 +159,34 @@ class TemplateVisitor<Code extends ErrorCode> extends RecursiveAstVisitor implem
}
visitIcu(icu: TmplAstIcu): void {}


visitDeferredBlock(deferred: TmplAstDeferredBlock): void {
this.visitAllNodes(deferred.children);
this.visitAllNodes(deferred.triggers);
this.visitAllNodes(deferred.prefetchTriggers);
deferred.placeholder && this.visit(deferred.placeholder);
deferred.loading && this.visit(deferred.loading);
deferred.error && this.visit(deferred.error);
}

visitDeferredTrigger(trigger: TmplAstDeferredTrigger): void {
if (trigger instanceof TmplAstBoundDeferredTrigger) {
this.visitAst(trigger.value);
}
}

visitDeferredBlockPlaceholder(block: TmplAstDeferredBlockPlaceholder): void {
this.visitAllNodes(block.children);
}

visitDeferredBlockError(block: TmplAstDeferredBlockError): void {
this.visitAllNodes(block.children);
}

visitDeferredBlockLoading(block: TmplAstDeferredBlockLoading): void {
this.visitAllNodes(block.children);
}

getDiagnostics(template: TmplAstNode[]): NgTemplateDiagnostic<Code>[] {
this.diagnostics = [];
this.visitAllNodes(template);
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export {SourceMap} from './output/source_map';
export * from './injectable_compiler_2';
export * from './render3/partial/api';
export * from './render3/view/api';
export {BoundAttribute as TmplAstBoundAttribute, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, Element as TmplAstElement, Icu as TmplAstIcu, Node as TmplAstNode, RecursiveVisitor as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text as TmplAstText, TextAttribute as TmplAstTextAttribute, Variable as TmplAstVariable} from './render3/r3_ast';
export {BoundAttribute as TmplAstBoundAttribute, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, Element as TmplAstElement, Icu as TmplAstIcu, Node as TmplAstNode, RecursiveVisitor as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text as TmplAstText, TextAttribute as TmplAstTextAttribute, Variable as TmplAstVariable, DeferredBlock as TmplAstDeferredBlock, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockError as TmplAstDeferredBlockError, DeferredTrigger as TmplAstDeferredTrigger, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger} from './render3/r3_ast';
export * from './render3/view/t2_api';
export * from './render3/view/t2_binder';
export {Identifiers as R3Identifiers} from './render3/r3_identifiers';
Expand Down
105 changes: 105 additions & 0 deletions packages/compiler/src/render3/r3_ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,88 @@ export class Element implements Node {
}
}

export abstract class DeferredTrigger implements Node {
constructor(public sourceSpan: ParseSourceSpan) {}

visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitDeferredTrigger(this);
}
}

export class BoundDeferredTrigger extends DeferredTrigger {
constructor(public value: AST, sourceSpan: ParseSourceSpan) {
super(sourceSpan);
}
}

export class IdleDeferredTrigger extends DeferredTrigger {}

export class ImmediateDeferredTrigger extends DeferredTrigger {}

export class HoverDeferredTrigger extends DeferredTrigger {}

export class TimerDeferredTrigger extends DeferredTrigger {
constructor(public delay: number, sourceSpan: ParseSourceSpan) {
super(sourceSpan);
}
}

export class InteractionDeferredTrigger extends DeferredTrigger {
constructor(public reference: string|null, sourceSpan: ParseSourceSpan) {
super(sourceSpan);
}
}

export class ViewportDeferredTrigger extends DeferredTrigger {
constructor(public reference: string|null, sourceSpan: ParseSourceSpan) {
super(sourceSpan);
}
}

export class DeferredBlockPlaceholder implements Node {
constructor(
public children: Node[], public minimumTime: number|null, public sourceSpan: ParseSourceSpan,
public startSourceSpan: ParseSourceSpan, public endSourceSpan: ParseSourceSpan|null) {}

visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitDeferredBlockPlaceholder(this);
}
}

export class DeferredBlockLoading implements Node {
constructor(
public children: Node[], public afterTime: number|null, public minimumTime: number|null,
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan,
public endSourceSpan: ParseSourceSpan|null) {}

visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitDeferredBlockLoading(this);
}
}

export class DeferredBlockError implements Node {
constructor(
public children: Node[], public sourceSpan: ParseSourceSpan,
public startSourceSpan: ParseSourceSpan, public endSourceSpan: ParseSourceSpan|null) {}

visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitDeferredBlockError(this);
}
}

export class DeferredBlock implements Node {
constructor(
public children: Node[], public triggers: DeferredTrigger[],
public prefetchTriggers: DeferredTrigger[], public placeholder: DeferredBlockPlaceholder|null,
public loading: DeferredBlockLoading|null, public error: DeferredBlockError|null,
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan,
public endSourceSpan: ParseSourceSpan|null) {}

visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitDeferredBlock(this);
}
}

export class Template implements Node {
constructor(
// tagName is the name of the container element, if applicable.
Expand Down Expand Up @@ -196,6 +278,11 @@ export interface Visitor<Result = any> {
visitText(text: Text): Result;
visitBoundText(text: BoundText): Result;
visitIcu(icu: Icu): Result;
visitDeferredBlock(deferred: DeferredBlock): Result;
visitDeferredBlockPlaceholder(block: DeferredBlockPlaceholder): Result;
visitDeferredBlockError(block: DeferredBlockError): Result;
visitDeferredBlockLoading(block: DeferredBlockLoading): Result;
visitDeferredTrigger(trigger: DeferredTrigger): Result;
}

export class RecursiveVisitor implements Visitor<void> {
Expand All @@ -214,6 +301,23 @@ export class RecursiveVisitor implements Visitor<void> {
visitAll(this, template.references);
visitAll(this, template.variables);
}
visitDeferredBlock(deferred: DeferredBlock): void {
visitAll(this, deferred.triggers);
visitAll(this, deferred.prefetchTriggers);
visitAll(this, deferred.children);
deferred.placeholder?.visit(this);
deferred.loading?.visit(this);
deferred.error?.visit(this);
}
visitDeferredBlockPlaceholder(block: DeferredBlockPlaceholder): void {
visitAll(this, block.children);
}
visitDeferredBlockError(block: DeferredBlockError): void {
visitAll(this, block.children);
}
visitDeferredBlockLoading(block: DeferredBlockLoading): void {
visitAll(this, block.children);
}
visitContent(content: Content): void {}
visitVariable(variable: Variable): void {}
visitReference(reference: Reference): void {}
Expand All @@ -223,6 +327,7 @@ export class RecursiveVisitor implements Visitor<void> {
visitText(text: Text): void {}
visitBoundText(text: BoundText): void {}
visitIcu(icu: Icu): void {}
visitDeferredTrigger(trigger: DeferredTrigger): void {}
}


Expand Down
Loading

0 comments on commit 9e61616

Please sign in to comment.