refactor(compiler): track the closing source-span of TagPlaceholders (#38645)

The `TagPlaceholder` can contain children, in which case there are two source
spans of interest: the opening tag and the closing tag. This commit now allows
the closing tag source-span to be tracked, so that it can be used later in
source-mapping.

PR Close #38645
This commit is contained in:
Pete Bacon Darwin 2020-08-31 16:23:01 +01:00 committed by atscott
parent bf31ef29f6
commit 109555b33a
4 changed files with 21 additions and 8 deletions

View File

@ -87,7 +87,7 @@ 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 sourceSpan: ParseSourceSpan, public closeSourceSpan: ParseSourceSpan|null) {}
visit(visitor: Visitor, context?: any): any {
return visitor.visitTagPlaceholder(this, context);
@ -151,7 +151,8 @@ export class CloneVisitor implements Visitor {
visitTagPlaceholder(ph: TagPlaceholder, context?: any): TagPlaceholder {
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.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan,
ph.closeSourceSpan);
}
visitPlaceholder(ph: Placeholder, context?: any): Placeholder {

View File

@ -93,7 +93,8 @@ class _I18nVisitor implements html.Visitor {
}
const node = new i18n.TagPlaceholder(
el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan);
el.name, attrs, startPhName, closePhName, children, isVoid, el.startSourceSpan,
el.endSourceSpan);
return context.visitNodeFn(el, node);
}
@ -167,22 +168,32 @@ class _I18nVisitor implements html.Visitor {
if (splitInterpolation.strings[i].length) {
// No need to add empty strings
nodes.push(new i18n.Text(splitInterpolation.strings[i], sourceSpan));
const stringSpan = getOffsetSourceSpan(sourceSpan, splitInterpolation.stringSpans[i]);
nodes.push(new i18n.Text(splitInterpolation.strings[i], stringSpan));
}
nodes.push(new i18n.Placeholder(expression, phName, sourceSpan));
const expressionSpan =
getOffsetSourceSpan(sourceSpan, splitInterpolation.expressionsSpans[i]);
nodes.push(new i18n.Placeholder(expression, phName, expressionSpan));
context.placeholderToContent[phName] = sDelimiter + expression + eDelimiter;
}
// The last index contains no expression
const lastStringIdx = splitInterpolation.strings.length - 1;
if (splitInterpolation.strings[lastStringIdx].length) {
nodes.push(new i18n.Text(splitInterpolation.strings[lastStringIdx], sourceSpan));
const stringSpan =
getOffsetSourceSpan(sourceSpan, splitInterpolation.stringSpans[lastStringIdx]);
nodes.push(new i18n.Text(splitInterpolation.strings[lastStringIdx], stringSpan));
}
return container;
}
}
function getOffsetSourceSpan(
sourceSpan: ParseSourceSpan, {start, end}: {start: number, end: number}): ParseSourceSpan {
return new ParseSourceSpan(sourceSpan.start.moveBy(start), sourceSpan.start.moveBy(end));
}
const _CUSTOM_PH_EXP =
/\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;

View File

@ -94,7 +94,8 @@ class MapPlaceholderNames extends i18n.CloneVisitor {
const closeName = ph.closeName ? mapper.toPublicName(ph.closeName)! : ph.closeName;
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.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan,
ph.closeSourceSpan);
}
visitPlaceholder(ph: i18n.Placeholder, mapper: PlaceholderMapper): i18n.Placeholder {

View File

@ -41,7 +41,7 @@ import {_extractMessages} from '../i18n_parser_spec';
new i18n.IcuPlaceholder(null!, '', null!),
],
null!);
const tag = new i18n.TagPlaceholder('', {}, '', '', [container], false, null!);
const tag = new i18n.TagPlaceholder('', {}, '', '', [container], false, null!, null);
const icu = new i18n.Icu('', '', {tag}, null!);
icu.visit(visitor);