refactor(compiler): element.sourceSpan should span the outerHTML (#38581)

Previously, the `sourceSpan` and `startSourceSpan` were the same
object, which meant that you had the following situation:

```
element = <div>some content</div>
sourceSpan = <div>
startSourceSpan = <div>
endSourceSpan = </div>
```

This made `sourceSpan` redundant and meant that if you
wanted a span for the whole element including its content
and closing tag, it had to be computed.

Now `sourceSpan` is separated from `startSourceSpan`
resulting in:

```
element = <div>some content</div>
sourceSpan = <div>some content</div>
startSourceSpan = <div>
endSourceSpan = </div>
```

PR Close #38581
This commit is contained in:
Pete Bacon Darwin
2020-08-26 11:56:38 +01:00
committed by Andrew Scott
parent a68f1a78a7
commit 1d8c5d88cd
11 changed files with 59 additions and 43 deletions

View File

@ -83,7 +83,7 @@ class _I18nVisitor implements html.Visitor {
const isVoid: boolean = getHtmlTagDefinition(el.name).isVoid;
const startPhName =
context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
context.placeholderToContent[startPhName] = el.sourceSpan.toString();
context.placeholderToContent[startPhName] = el.startSourceSpan.toString();
let closePhName = '';

View File

@ -258,7 +258,9 @@ class _TreeBuilder {
}
const end = this._peek.sourceSpan.start;
const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end);
const el = new html.Element(fullName, attrs, [], span, span, undefined);
// Create a separate `startSpan` because `span` will be modified when there is an `end` span.
const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end);
const el = new html.Element(fullName, attrs, [], span, startSpan, undefined);
this._pushElement(el);
if (selfClosing) {
// Elements that are self-closed have their `endSourceSpan` set to the full span, as the
@ -301,6 +303,7 @@ class _TreeBuilder {
// removed from the element stack at this point are closed implicitly, so they won't get
// an end source span (as there is no explicit closing element).
el.endSourceSpan = endSourceSpan;
el.sourceSpan.end = endSourceSpan.end || el.sourceSpan.end;
this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
return true;

View File

@ -544,7 +544,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
private addNamespaceInstruction(nsInstruction: o.ExternalReference, element: t.Element) {
this._namespace = nsInstruction;
this.creationInstruction(element.sourceSpan, nsInstruction);
this.creationInstruction(element.startSourceSpan, nsInstruction);
}
/**
@ -671,15 +671,16 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
trimTrailingNulls(parameters));
} else {
this.creationInstruction(
element.sourceSpan, isNgContainer ? R3.elementContainerStart : R3.elementStart,
element.startSourceSpan, isNgContainer ? R3.elementContainerStart : R3.elementStart,
trimTrailingNulls(parameters));
if (isNonBindableMode) {
this.creationInstruction(element.sourceSpan, R3.disableBindings);
this.creationInstruction(element.startSourceSpan, R3.disableBindings);
}
if (i18nAttrs.length > 0) {
this.i18nAttributesInstruction(elementIndex, i18nAttrs, element.sourceSpan);
this.i18nAttributesInstruction(
elementIndex, i18nAttrs, element.startSourceSpan ?? element.sourceSpan);
}
// Generate Listeners (outputs)
@ -695,7 +696,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
// Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
// listeners, to make sure i18nAttributes instruction targets current element at runtime.
if (isI18nRootElement) {
this.i18nStart(element.sourceSpan, element.i18n!, createSelfClosingI18nInstruction);
this.i18nStart(element.startSourceSpan, element.i18n!, createSelfClosingI18nInstruction);
}
}
@ -827,7 +828,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
if (!createSelfClosingInstruction) {
// Finish element construction mode.
const span = element.endSourceSpan || element.sourceSpan;
const span = element.endSourceSpan ?? element.sourceSpan;
if (isI18nRootElement) {
this.i18nEnd(span, createSelfClosingI18nInstruction);
}
@ -919,7 +920,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
// elements, in case of inline templates, corresponding instructions will be generated in the
// nested template function.
if (i18nAttrs.length > 0) {
this.i18nAttributesInstruction(templateIndex, i18nAttrs, template.sourceSpan);
this.i18nAttributesInstruction(
templateIndex, i18nAttrs, template.startSourceSpan ?? template.sourceSpan);
}
// Add the input bindings