fix(compiler-cli): compute source-mappings for localized strings (#38645)

Previously, localized strings had very limited or incorrect source-mapping
information available.

Now the i18n AST nodes and related output AST nodes include source-span
information about message-parts and placeholders - including closing tag
placeholders.

This information is then used when generating the final localized string
ASTs to ensure that the correct source-mapping is rendered.

See #38588 (comment)

PR Close #38645
This commit is contained in:
Pete Bacon Darwin
2020-08-31 16:27:44 +01:00
committed by atscott
parent 7a6a061a9e
commit 7e0b3fd953
7 changed files with 217 additions and 113 deletions

View File

@ -87,7 +87,9 @@ export class TagPlaceholder implements Node {
constructor(
public tag: string, public attrs: {[k: string]: string}, public startName: string,
public closeName: string, public children: Node[], public isVoid: boolean,
public sourceSpan: ParseSourceSpan, public closeSourceSpan: ParseSourceSpan|null) {}
// TODO sourceSpan should cover all (we need a startSourceSpan and endSourceSpan)
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null,
public endSourceSpan: ParseSourceSpan|null) {}
visit(visitor: Visitor, context?: any): any {
return visitor.visitTagPlaceholder(this, context);
@ -152,7 +154,7 @@ export class CloneVisitor implements Visitor {
const children = ph.children.map(n => n.visit(this, context));
return new TagPlaceholder(
ph.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan,
ph.closeSourceSpan);
ph.startSourceSpan, ph.endSourceSpan);
}
visitPlaceholder(ph: Placeholder, context?: any): Placeholder {

View File

@ -93,8 +93,8 @@ class _I18nVisitor implements html.Visitor {
}
const node = new i18n.TagPlaceholder(
el.name, attrs, startPhName, closePhName, children, isVoid, el.startSourceSpan,
el.endSourceSpan);
el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan,
el.startSourceSpan, el.endSourceSpan);
return context.visitNodeFn(el, node);
}

View File

@ -95,7 +95,7 @@ class MapPlaceholderNames extends i18n.CloneVisitor {
const children = ph.children.map(n => n.visit(this, mapper));
return new i18n.TagPlaceholder(
ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan,
ph.closeSourceSpan);
ph.startSourceSpan, ph.endSourceSpan);
}
visitPlaceholder(ph: i18n.Placeholder, mapper: PlaceholderMapper): i18n.Placeholder {

View File

@ -48,10 +48,10 @@ class LocalizeSerializerVisitor implements i18n.Visitor {
}
visitTagPlaceholder(ph: i18n.TagPlaceholder, context: o.MessagePiece[]): any {
context.push(this.createPlaceholderPiece(ph.startName, ph.sourceSpan));
context.push(this.createPlaceholderPiece(ph.startName, ph.startSourceSpan ?? ph.sourceSpan));
if (!ph.isVoid) {
ph.children.forEach(child => child.visit(this, context));
context.push(this.createPlaceholderPiece(ph.closeName, ph.closeSourceSpan ?? ph.sourceSpan));
context.push(this.createPlaceholderPiece(ph.closeName, ph.endSourceSpan ?? ph.sourceSpan));
}
}