refactor(compiler): rename i18n `AST` to `i18nMeta` (#33318)

This better reflects what this type represents and what it is used for.

PR Close #33318
This commit is contained in:
Pete Bacon Darwin 2019-10-22 15:05:44 +01:00 committed by Matias Niemelä
parent 447e251736
commit 03103d2d59
8 changed files with 41 additions and 32 deletions

View File

@ -98,7 +98,13 @@ export class IcuPlaceholder implements Node {
visit(visitor: Visitor, context?: any): any { return visitor.visitIcuPlaceholder(this, context); } visit(visitor: Visitor, context?: any): any { return visitor.visitIcuPlaceholder(this, context); }
} }
export type AST = Message | Node; /**
* Each HTML node that is affect by an i18n tag will also have an `i18n` property that is of type
* `I18nMeta`.
* This information is either a `Message`, which indicates it is the root of an i18n message, or a
* `Node`, which indicates is it part of a containing `Message`.
*/
export type I18nMeta = Message | Node;
export interface Visitor { export interface Visitor {
visitText(text: Text, context?: any): any; visitText(text: Text, context?: any): any;

View File

@ -7,7 +7,7 @@
*/ */
import {AstPath} from '../ast_path'; import {AstPath} from '../ast_path';
import {AST as I18nAST} from '../i18n/i18n_ast'; import {I18nMeta} from '../i18n/i18n_ast';
import {ParseSourceSpan} from '../parse_util'; import {ParseSourceSpan} from '../parse_util';
export interface Node { export interface Node {
@ -16,7 +16,7 @@ export interface Node {
} }
export class Text implements Node { export class Text implements Node {
constructor(public value: string, public sourceSpan: ParseSourceSpan, public i18n?: I18nAST) {} constructor(public value: string, public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {}
visit(visitor: Visitor, context: any): any { return visitor.visitText(this, context); } visit(visitor: Visitor, context: any): any { return visitor.visitText(this, context); }
} }
@ -24,7 +24,7 @@ export class Expansion implements Node {
constructor( constructor(
public switchValue: string, public type: string, public cases: ExpansionCase[], public switchValue: string, public type: string, public cases: ExpansionCase[],
public sourceSpan: ParseSourceSpan, public switchValueSourceSpan: ParseSourceSpan, public sourceSpan: ParseSourceSpan, public switchValueSourceSpan: ParseSourceSpan,
public i18n?: I18nAST) {} public i18n?: I18nMeta) {}
visit(visitor: Visitor, context: any): any { return visitor.visitExpansion(this, context); } visit(visitor: Visitor, context: any): any { return visitor.visitExpansion(this, context); }
} }
@ -39,7 +39,7 @@ export class ExpansionCase implements Node {
export class Attribute implements Node { export class Attribute implements Node {
constructor( constructor(
public name: string, public value: string, public sourceSpan: ParseSourceSpan, public name: string, public value: string, public sourceSpan: ParseSourceSpan,
public valueSpan?: ParseSourceSpan, public i18n?: I18nAST) {} public valueSpan?: ParseSourceSpan, public i18n?: I18nMeta) {}
visit(visitor: Visitor, context: any): any { return visitor.visitAttribute(this, context); } visit(visitor: Visitor, context: any): any { return visitor.visitAttribute(this, context); }
} }
@ -47,7 +47,7 @@ export class Element implements Node {
constructor( constructor(
public name: string, public attrs: Attribute[], public children: Node[], public name: string, public attrs: Attribute[], public children: Node[],
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null = null, public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null = null,
public endSourceSpan: ParseSourceSpan|null = null, public i18n?: I18nAST) {} public endSourceSpan: ParseSourceSpan|null = null, public i18n?: I18nMeta) {}
visit(visitor: Visitor, context: any): any { return visitor.visitElement(this, context); } visit(visitor: Visitor, context: any): any { return visitor.visitElement(this, context); }
} }

View File

@ -8,7 +8,7 @@
import {SecurityContext} from '../core'; import {SecurityContext} from '../core';
import {AST, BindingType, BoundElementProperty, ParsedEvent, ParsedEventType} from '../expression_parser/ast'; import {AST, BindingType, BoundElementProperty, ParsedEvent, ParsedEventType} from '../expression_parser/ast';
import {AST as I18nAST} from '../i18n/i18n_ast'; import {I18nMeta} from '../i18n/i18n_ast';
import {ParseSourceSpan} from '../parse_util'; import {ParseSourceSpan} from '../parse_util';
export interface Node { export interface Node {
@ -22,14 +22,14 @@ export class Text implements Node {
} }
export class BoundText implements Node { export class BoundText implements Node {
constructor(public value: AST, public sourceSpan: ParseSourceSpan, public i18n?: I18nAST) {} constructor(public value: AST, public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {}
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitBoundText(this); } visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitBoundText(this); }
} }
export class TextAttribute implements Node { export class TextAttribute implements Node {
constructor( constructor(
public name: string, public value: string, public sourceSpan: ParseSourceSpan, public name: string, public value: string, public sourceSpan: ParseSourceSpan,
public valueSpan?: ParseSourceSpan, public i18n?: I18nAST) {} public valueSpan?: ParseSourceSpan, public i18n?: I18nMeta) {}
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitTextAttribute(this); } visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitTextAttribute(this); }
} }
@ -37,9 +37,9 @@ export class BoundAttribute implements Node {
constructor( constructor(
public name: string, public type: BindingType, public securityContext: SecurityContext, public name: string, public type: BindingType, public securityContext: SecurityContext,
public value: AST, public unit: string|null, public sourceSpan: ParseSourceSpan, public value: AST, public unit: string|null, public sourceSpan: ParseSourceSpan,
public valueSpan?: ParseSourceSpan, public i18n?: I18nAST) {} public valueSpan?: ParseSourceSpan, public i18n?: I18nMeta) {}
static fromBoundElementProperty(prop: BoundElementProperty, i18n?: I18nAST) { static fromBoundElementProperty(prop: BoundElementProperty, i18n?: I18nMeta) {
return new BoundAttribute( return new BoundAttribute(
prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan,
prop.valueSpan, i18n); prop.valueSpan, i18n);
@ -70,7 +70,7 @@ export class Element implements Node {
public name: string, public attributes: TextAttribute[], public inputs: BoundAttribute[], public name: string, public attributes: TextAttribute[], public inputs: BoundAttribute[],
public outputs: BoundEvent[], public children: Node[], public references: Reference[], public outputs: BoundEvent[], public children: Node[], public references: Reference[],
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null, public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null,
public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nAST) { public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) {
// If the element is empty then the source span should include any closing tag // If the element is empty then the source span should include any closing tag
if (children.length === 0 && startSourceSpan && endSourceSpan) { if (children.length === 0 && startSourceSpan && endSourceSpan) {
this.sourceSpan = new ParseSourceSpan(sourceSpan.start, endSourceSpan.end); this.sourceSpan = new ParseSourceSpan(sourceSpan.start, endSourceSpan.end);
@ -85,14 +85,14 @@ export class Template implements Node {
public outputs: BoundEvent[], public templateAttrs: (BoundAttribute|TextAttribute)[], public outputs: BoundEvent[], public templateAttrs: (BoundAttribute|TextAttribute)[],
public children: Node[], public references: Reference[], public variables: Variable[], public children: Node[], public references: Reference[], public variables: Variable[],
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null, public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null,
public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nAST) {} public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) {}
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitTemplate(this); } visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitTemplate(this); }
} }
export class Content implements Node { export class Content implements Node {
constructor( constructor(
public selector: string, public attributes: TextAttribute[], public selector: string, public attributes: TextAttribute[],
public sourceSpan: ParseSourceSpan, public i18n?: I18nAST) {} public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {}
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitContent(this); } visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitContent(this); }
} }
@ -114,7 +114,7 @@ export class Icu implements Node {
constructor( constructor(
public vars: {[name: string]: BoundText}, public vars: {[name: string]: BoundText},
public placeholders: {[name: string]: Text | BoundText}, public sourceSpan: ParseSourceSpan, public placeholders: {[name: string]: Text | BoundText}, public sourceSpan: ParseSourceSpan,
public i18n?: I18nAST) {} public i18n?: I18nMeta) {}
visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitIcu(this); } visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitIcu(this); }
} }

View File

@ -109,7 +109,7 @@ class HtmlAstToIvyAst implements html.Visitor {
const variables: t.Variable[] = []; const variables: t.Variable[] = [];
const references: t.Reference[] = []; const references: t.Reference[] = [];
const attributes: t.TextAttribute[] = []; const attributes: t.TextAttribute[] = [];
const i18nAttrsMeta: {[key: string]: i18n.AST} = {}; const i18nAttrsMeta: {[key: string]: i18n.I18nMeta} = {};
const templateParsedProperties: ParsedProperty[] = []; const templateParsedProperties: ParsedProperty[] = [];
const templateVariables: t.Variable[] = []; const templateVariables: t.Variable[] = [];
@ -263,7 +263,8 @@ class HtmlAstToIvyAst implements html.Visitor {
// convert view engine `ParsedProperty` to a format suitable for IVY // convert view engine `ParsedProperty` to a format suitable for IVY
private extractAttributes( private extractAttributes(
elementName: string, properties: ParsedProperty[], i18nPropsMeta: {[key: string]: i18n.AST}): elementName: string, properties: ParsedProperty[],
i18nPropsMeta: {[key: string]: i18n.I18nMeta}):
{bound: t.BoundAttribute[], literal: t.TextAttribute[]} { {bound: t.BoundAttribute[], literal: t.TextAttribute[]} {
const bound: t.BoundAttribute[] = []; const bound: t.BoundAttribute[] = [];
const literal: t.TextAttribute[] = []; const literal: t.TextAttribute[] = [];
@ -364,8 +365,8 @@ class HtmlAstToIvyAst implements html.Visitor {
return hasBinding; return hasBinding;
} }
private _visitTextWithInterpolation(value: string, sourceSpan: ParseSourceSpan, i18n?: i18n.AST): private _visitTextWithInterpolation(
t.Text|t.BoundText { value: string, sourceSpan: ParseSourceSpan, i18n?: i18n.I18nMeta): t.Text|t.BoundText {
const valueNoNgsp = replaceNgsp(value); const valueNoNgsp = replaceNgsp(value);
const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan); const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan);
return expr ? new t.BoundText(expr, sourceSpan, i18n) : new t.Text(valueNoNgsp, sourceSpan); return expr ? new t.BoundText(expr, sourceSpan, i18n) : new t.Text(valueNoNgsp, sourceSpan);

View File

@ -51,7 +51,8 @@ export class I18nContext {
constructor( constructor(
readonly index: number, readonly ref: o.ReadVarExpr, readonly level: number = 0, readonly index: number, readonly ref: o.ReadVarExpr, readonly level: number = 0,
readonly templateIndex: number|null = null, readonly meta: i18n.AST, private registry?: any) { readonly templateIndex: number|null = null, readonly meta: i18n.I18nMeta,
private registry?: any) {
this._registry = registry || setupRegistry(); this._registry = registry || setupRegistry();
this.id = this._registry.getUniqueId(); this.id = this._registry.getUniqueId();
} }
@ -81,21 +82,21 @@ export class I18nContext {
appendIcu(name: string, ref: o.Expression) { appendIcu(name: string, ref: o.Expression) {
updatePlaceholderMap(this._registry.icus, name, ref); updatePlaceholderMap(this._registry.icus, name, ref);
} }
appendBoundText(node: i18n.AST) { appendBoundText(node: i18n.I18nMeta) {
const phs = assembleBoundTextPlaceholders(node, this.bindings.size, this.id); const phs = assembleBoundTextPlaceholders(node, this.bindings.size, this.id);
phs.forEach((values, key) => updatePlaceholderMap(this.placeholders, key, ...values)); phs.forEach((values, key) => updatePlaceholderMap(this.placeholders, key, ...values));
} }
appendTemplate(node: i18n.AST, index: number) { appendTemplate(node: i18n.I18nMeta, index: number) {
// add open and close tags at the same time, // add open and close tags at the same time,
// since we process nested templates separately // since we process nested templates separately
this.appendTag(TagType.TEMPLATE, node as i18n.TagPlaceholder, index, false); this.appendTag(TagType.TEMPLATE, node as i18n.TagPlaceholder, index, false);
this.appendTag(TagType.TEMPLATE, node as i18n.TagPlaceholder, index, true); this.appendTag(TagType.TEMPLATE, node as i18n.TagPlaceholder, index, true);
this._unresolvedCtxCount++; this._unresolvedCtxCount++;
} }
appendElement(node: i18n.AST, index: number, closed?: boolean) { appendElement(node: i18n.I18nMeta, index: number, closed?: boolean) {
this.appendTag(TagType.ELEMENT, node as i18n.TagPlaceholder, index, closed); this.appendTag(TagType.ELEMENT, node as i18n.TagPlaceholder, index, closed);
} }
appendProjection(node: i18n.AST, index: number) { appendProjection(node: i18n.I18nMeta, index: number) {
// add open and close tags at the same time, // add open and close tags at the same time,
// since we process projected content separately // since we process projected content separately
this.appendTag(TagType.PROJECTION, node as i18n.TagPlaceholder, index, false); this.appendTag(TagType.PROJECTION, node as i18n.TagPlaceholder, index, false);
@ -112,7 +113,7 @@ export class I18nContext {
* *
* @returns I18nContext instance * @returns I18nContext instance
*/ */
forkChildContext(index: number, templateIndex: number, meta: i18n.AST) { forkChildContext(index: number, templateIndex: number, meta: i18n.I18nMeta) {
return new I18nContext(index, this.ref, this.level + 1, templateIndex, meta, this._registry); return new I18nContext(index, this.ref, this.level + 1, templateIndex, meta, this._registry);
} }

View File

@ -23,7 +23,7 @@ export type I18nMeta = {
meaning?: string meaning?: string
}; };
function setI18nRefs(html: html.Node & {i18n?: i18n.AST}, i18n: i18n.Node): i18n.Node { function setI18nRefs(html: html.Node & {i18n?: i18n.I18nMeta}, i18n: i18n.Node): i18n.Node {
html.i18n = i18n; html.i18n = i18n;
return i18n; return i18n;
} }
@ -42,7 +42,8 @@ export class I18nMetaVisitor implements html.Visitor {
private keepI18nAttrs: boolean = false, private i18nLegacyMessageIdFormat: string = '') {} private keepI18nAttrs: boolean = false, private i18nLegacyMessageIdFormat: string = '') {}
private _generateI18nMessage( private _generateI18nMessage(
nodes: html.Node[], meta: string|i18n.AST = '', visitNodeFn?: VisitNodeFn): i18n.Message { nodes: html.Node[], meta: string|i18n.I18nMeta = '',
visitNodeFn?: VisitNodeFn): i18n.Message {
const parsed: I18nMeta = const parsed: I18nMeta =
typeof meta === 'string' ? parseI18nMeta(meta) : metaFromI18nMessage(meta as i18n.Message); typeof meta === 'string' ? parseI18nMeta(meta) : metaFromI18nMessage(meta as i18n.Message);
const message = this._createI18nMessage( const message = this._createI18nMessage(

View File

@ -33,11 +33,11 @@ export function isI18nAttribute(name: string): boolean {
return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX); return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX);
} }
export function isI18nRootNode(meta?: i18n.AST): meta is i18n.Message { export function isI18nRootNode(meta?: i18n.I18nMeta): meta is i18n.Message {
return meta instanceof i18n.Message; return meta instanceof i18n.Message;
} }
export function isSingleI18nIcu(meta?: i18n.AST): boolean { export function isSingleI18nIcu(meta?: i18n.I18nMeta): boolean {
return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof i18n.Icu; return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof i18n.Icu;
} }
@ -87,7 +87,7 @@ export function updatePlaceholderMap(map: Map<string, any[]>, name: string, ...v
} }
export function assembleBoundTextPlaceholders( export function assembleBoundTextPlaceholders(
meta: i18n.AST, bindingStartIndex: number = 0, contextId: number = 0): Map<string, any[]> { meta: i18n.I18nMeta, bindingStartIndex: number = 0, contextId: number = 0): Map<string, any[]> {
const startIdx = bindingStartIndex; const startIdx = bindingStartIndex;
const placeholders = new Map<string, any>(); const placeholders = new Map<string, any>();
const node = const node =

View File

@ -188,7 +188,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
buildTemplateFunction( buildTemplateFunction(
nodes: t.Node[], variables: t.Variable[], ngContentSelectorsOffset: number = 0, nodes: t.Node[], variables: t.Variable[], ngContentSelectorsOffset: number = 0,
i18n?: i18n.AST): o.FunctionExpr { i18n?: i18n.I18nMeta): o.FunctionExpr {
this._ngContentSelectorsOffset = ngContentSelectorsOffset; this._ngContentSelectorsOffset = ngContentSelectorsOffset;
if (this._namespace !== R3.namespaceHTML) { if (this._namespace !== R3.namespaceHTML) {
@ -415,7 +415,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
} }
} }
private i18nStart(span: ParseSourceSpan|null = null, meta: i18n.AST, selfClosing?: boolean): private i18nStart(span: ParseSourceSpan|null = null, meta: i18n.I18nMeta, selfClosing?: boolean):
void { void {
const index = this.allocateDataSlot(); const index = this.allocateDataSlot();
if (this.i18nContext) { if (this.i18nContext) {