refactor(compiler): element.startSourceSpan is required (#38581)

Previously, the `startSourceSpan` property could be null
but in reality it is always well defined - except for a legacy
case in the old i18n extraction/merging code, where the
typings for source-spans are already being undermined.

Making this property non-null, simplifies code elsewhere
in the project.

PR Close #38581
This commit is contained in:
Pete Bacon Darwin 2020-08-26 12:21:29 +01:00 committed by Andrew Scott
parent 86e11f1110
commit a68f1a78a7
14 changed files with 53 additions and 58 deletions

View File

@ -124,7 +124,7 @@ class _Visitor implements html.Visitor {
this._translations = translations; this._translations = translations;
// Construct a single fake root element // Construct a single fake root element
const wrapper = new html.Element('wrapper', [], nodes, undefined!, undefined, undefined); const wrapper = new html.Element('wrapper', [], nodes, undefined!, undefined!, undefined);
const translatedNode = wrapper.visit(this, null); const translatedNode = wrapper.visit(this, null);
@ -492,7 +492,7 @@ class _Visitor implements html.Visitor {
} }
private _reportError(node: html.Node, msg: string): void { private _reportError(node: html.Node, msg: string): void {
this._errors.push(new I18nError(node.sourceSpan!, msg)); this._errors.push(new I18nError(node.sourceSpan, msg));
} }
} }

View File

@ -83,7 +83,7 @@ class _I18nVisitor implements html.Visitor {
const isVoid: boolean = getHtmlTagDefinition(el.name).isVoid; const isVoid: boolean = getHtmlTagDefinition(el.name).isVoid;
const startPhName = const startPhName =
context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid); context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
context.placeholderToContent[startPhName] = el.sourceSpan!.toString(); context.placeholderToContent[startPhName] = el.sourceSpan.toString();
let closePhName = ''; let closePhName = '';
@ -93,7 +93,7 @@ class _I18nVisitor implements html.Visitor {
} }
const node = new i18n.TagPlaceholder( const node = new i18n.TagPlaceholder(
el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan!); el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan);
return context.visitNodeFn(el, node); return context.visitNodeFn(el, node);
} }
@ -103,7 +103,7 @@ class _I18nVisitor implements html.Visitor {
} }
visitText(text: html.Text, context: I18nMessageVisitorContext): i18n.Node { visitText(text: html.Text, context: I18nMessageVisitorContext): i18n.Node {
const node = this._visitTextWithInterpolation(text.value, text.sourceSpan!, context); const node = this._visitTextWithInterpolation(text.value, text.sourceSpan, context);
return context.visitNodeFn(text, node); return context.visitNodeFn(text, node);
} }

View File

@ -231,9 +231,9 @@ class XliffParser implements ml.Visitor {
break; break;
case _TARGET_TAG: case _TARGET_TAG:
const innerTextStart = element.startSourceSpan!.end.offset; const innerTextStart = element.startSourceSpan.end.offset;
const innerTextEnd = element.endSourceSpan!.start.offset; const innerTextEnd = element.endSourceSpan!.start.offset;
const content = element.startSourceSpan!.start.file.content; const content = element.startSourceSpan.start.file.content;
const innerText = content.slice(innerTextStart, innerTextEnd); const innerText = content.slice(innerTextStart, innerTextEnd);
this._unitMlString = innerText; this._unitMlString = innerText;
break; break;
@ -264,7 +264,7 @@ class XliffParser implements ml.Visitor {
visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {} visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {}
private _addError(node: ml.Node, message: string): void { private _addError(node: ml.Node, message: string): void {
this._errors.push(new I18nError(node.sourceSpan!, message)); this._errors.push(new I18nError(node.sourceSpan, message));
} }
} }
@ -288,14 +288,14 @@ class XmlToI18n implements ml.Visitor {
} }
visitText(text: ml.Text, context: any) { visitText(text: ml.Text, context: any) {
return new i18n.Text(text.value, text.sourceSpan!); return new i18n.Text(text.value, text.sourceSpan);
} }
visitElement(el: ml.Element, context: any): i18n.Placeholder|ml.Node[]|null { visitElement(el: ml.Element, context: any): i18n.Placeholder|ml.Node[]|null {
if (el.name === _PLACEHOLDER_TAG) { if (el.name === _PLACEHOLDER_TAG) {
const nameAttr = el.attrs.find((attr) => attr.name === 'id'); const nameAttr = el.attrs.find((attr) => attr.name === 'id');
if (nameAttr) { if (nameAttr) {
return new i18n.Placeholder('', nameAttr.value, el.sourceSpan!); return new i18n.Placeholder('', nameAttr.value, el.sourceSpan);
} }
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "id" attribute`); this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "id" attribute`);
@ -332,7 +332,7 @@ class XmlToI18n implements ml.Visitor {
visitAttribute(attribute: ml.Attribute, context: any) {} visitAttribute(attribute: ml.Attribute, context: any) {}
private _addError(node: ml.Node, message: string): void { private _addError(node: ml.Node, message: string): void {
this._errors.push(new I18nError(node.sourceSpan!, message)); this._errors.push(new I18nError(node.sourceSpan, message));
} }
} }

View File

@ -246,9 +246,9 @@ class Xliff2Parser implements ml.Visitor {
break; break;
case _TARGET_TAG: case _TARGET_TAG:
const innerTextStart = element.startSourceSpan!.end.offset; const innerTextStart = element.startSourceSpan.end.offset;
const innerTextEnd = element.endSourceSpan!.start.offset; const innerTextEnd = element.endSourceSpan!.start.offset;
const content = element.startSourceSpan!.start.file.content; const content = element.startSourceSpan.start.file.content;
const innerText = content.slice(innerTextStart, innerTextEnd); const innerText = content.slice(innerTextStart, innerTextEnd);
this._unitMlString = innerText; this._unitMlString = innerText;
break; break;

View File

@ -130,9 +130,9 @@ class XtbParser implements ml.Visitor {
if (this._msgIdToHtml.hasOwnProperty(id)) { if (this._msgIdToHtml.hasOwnProperty(id)) {
this._addError(element, `Duplicated translations for msg ${id}`); this._addError(element, `Duplicated translations for msg ${id}`);
} else { } else {
const innerTextStart = element.startSourceSpan!.end.offset; const innerTextStart = element.startSourceSpan.end.offset;
const innerTextEnd = element.endSourceSpan!.start.offset; const innerTextEnd = element.endSourceSpan!.start.offset;
const content = element.startSourceSpan!.start.file.content; const content = element.startSourceSpan.start.file.content;
const innerText = content.slice(innerTextStart!, innerTextEnd!); const innerText = content.slice(innerTextStart!, innerTextEnd!);
this._msgIdToHtml[id] = innerText; this._msgIdToHtml[id] = innerText;
} }
@ -155,7 +155,7 @@ class XtbParser implements ml.Visitor {
visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {} visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {}
private _addError(node: ml.Node, message: string): void { private _addError(node: ml.Node, message: string): void {
this._errors.push(new I18nError(node.sourceSpan!, message)); this._errors.push(new I18nError(node.sourceSpan, message));
} }
} }
@ -179,7 +179,7 @@ class XmlToI18n implements ml.Visitor {
} }
visitText(text: ml.Text, context: any) { visitText(text: ml.Text, context: any) {
return new i18n.Text(text.value, text.sourceSpan!); return new i18n.Text(text.value, text.sourceSpan);
} }
visitExpansion(icu: ml.Expansion, context: any) { visitExpansion(icu: ml.Expansion, context: any) {
@ -203,7 +203,7 @@ class XmlToI18n implements ml.Visitor {
if (el.name === _PLACEHOLDER_TAG) { if (el.name === _PLACEHOLDER_TAG) {
const nameAttr = el.attrs.find((attr) => attr.name === 'name'); const nameAttr = el.attrs.find((attr) => attr.name === 'name');
if (nameAttr) { if (nameAttr) {
return new i18n.Placeholder('', nameAttr.value, el.sourceSpan!); return new i18n.Placeholder('', nameAttr.value, el.sourceSpan);
} }
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "name" attribute`); this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "name" attribute`);
@ -218,6 +218,6 @@ class XmlToI18n implements ml.Visitor {
visitAttribute(attribute: ml.Attribute, context: any) {} visitAttribute(attribute: ml.Attribute, context: any) {}
private _addError(node: ml.Node, message: string): void { private _addError(node: ml.Node, message: string): void {
this._errors.push(new I18nError(node.sourceSpan!, message)); this._errors.push(new I18nError(node.sourceSpan, message));
} }
} }

View File

@ -64,7 +64,7 @@ export class Attribute extends NodeWithI18n {
export class Element extends NodeWithI18n { export class Element extends NodeWithI18n {
constructor( constructor(
public name: string, public attrs: Attribute[], public children: Node[], public name: string, public attrs: Attribute[], public children: Node[],
sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null = null, sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan,
public endSourceSpan: ParseSourceSpan|null = null, i18n?: I18nMeta) { public endSourceSpan: ParseSourceSpan|null = null, i18n?: I18nMeta) {
super(sourceSpan, i18n); super(sourceSpan, i18n);
} }

View File

@ -79,13 +79,8 @@ export class Element implements Node {
constructor( constructor(
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,
public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) { public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) {}
// If the element is empty then the source span should include any closing tag
if (children.length === 0 && startSourceSpan && endSourceSpan) {
this.sourceSpan = new ParseSourceSpan(sourceSpan.start, endSourceSpan.end);
}
}
visit<Result>(visitor: Visitor<Result>): Result { visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitElement(this); return visitor.visitElement(this);
} }
@ -96,7 +91,7 @@ export class Template implements Node {
public tagName: string, public attributes: TextAttribute[], public inputs: BoundAttribute[], public tagName: string, public attributes: TextAttribute[], public inputs: BoundAttribute[],
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,
public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) {} public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) {}
visit<Result>(visitor: Visitor<Result>): Result { visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitTemplate(this); return visitor.visitTemplate(this);

View File

@ -244,9 +244,9 @@ class TemplateParseVisitor implements html.Visitor {
visitText(text: html.Text, parent: ElementContext): any { visitText(text: html.Text, parent: ElementContext): any {
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR())!; const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR())!;
const valueNoNgsp = replaceNgsp(text.value); const valueNoNgsp = replaceNgsp(text.value);
const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan!); const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan);
return expr ? new t.BoundTextAst(expr, ngContentIndex, text.sourceSpan!) : return expr ? new t.BoundTextAst(expr, ngContentIndex, text.sourceSpan) :
new t.TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan!); new t.TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan);
} }
visitAttribute(attribute: html.Attribute, context: any): any { visitAttribute(attribute: html.Attribute, context: any): any {
@ -335,14 +335,14 @@ class TemplateParseVisitor implements html.Visitor {
const boundDirectivePropNames = new Set<string>(); const boundDirectivePropNames = new Set<string>();
const directiveAsts = this._createDirectiveAsts( const directiveAsts = this._createDirectiveAsts(
isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps, isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps,
elementOrDirectiveRefs, element.sourceSpan!, references, boundDirectivePropNames); elementOrDirectiveRefs, element.sourceSpan, references, boundDirectivePropNames);
const elementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts( const elementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts(
element.name, elementOrDirectiveProps, boundDirectivePropNames); element.name, elementOrDirectiveProps, boundDirectivePropNames);
const isViewRoot = parent.isTemplateElement || hasInlineTemplates; const isViewRoot = parent.isTemplateElement || hasInlineTemplates;
const providerContext = new ProviderElementContext( const providerContext = new ProviderElementContext(
this.providerViewContext, parent.providerContext!, isViewRoot, directiveAsts, attrs, this.providerViewContext, parent.providerContext!, isViewRoot, directiveAsts, attrs,
references, isTemplateElement, queryStartIndex, element.sourceSpan!); references, isTemplateElement, queryStartIndex, element.sourceSpan);
const children: t.TemplateAst[] = html.visitAll( const children: t.TemplateAst[] = html.visitAll(
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children, preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
@ -360,26 +360,26 @@ class TemplateParseVisitor implements html.Visitor {
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) { if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
// `<ng-content>` element // `<ng-content>` element
if (element.children && !element.children.every(_isEmptyTextNode)) { if (element.children && !element.children.every(_isEmptyTextNode)) {
this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan!); this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
} }
parsedElement = new t.NgContentAst( parsedElement = new t.NgContentAst(
this.ngContentCount++, hasInlineTemplates ? null! : ngContentIndex, element.sourceSpan!); this.ngContentCount++, hasInlineTemplates ? null! : ngContentIndex, element.sourceSpan);
} else if (isTemplateElement) { } else if (isTemplateElement) {
// `<ng-template>` element // `<ng-template>` element
this._assertAllEventsPublishedByDirectives(directiveAsts, events); this._assertAllEventsPublishedByDirectives(directiveAsts, events);
this._assertNoComponentsNorElementBindingsOnTemplate( this._assertNoComponentsNorElementBindingsOnTemplate(
directiveAsts, elementProps, element.sourceSpan!); directiveAsts, elementProps, element.sourceSpan);
parsedElement = new t.EmbeddedTemplateAst( parsedElement = new t.EmbeddedTemplateAst(
attrs, events, references, elementVars, providerContext.transformedDirectiveAsts, attrs, events, references, elementVars, providerContext.transformedDirectiveAsts,
providerContext.transformProviders, providerContext.transformedHasViewContainer, providerContext.transformProviders, providerContext.transformedHasViewContainer,
providerContext.queryMatches, children, hasInlineTemplates ? null! : ngContentIndex, providerContext.queryMatches, children, hasInlineTemplates ? null! : ngContentIndex,
element.sourceSpan!); element.sourceSpan);
} else { } else {
// element other than `<ng-content>` and `<ng-template>` // element other than `<ng-content>` and `<ng-template>`
this._assertElementExists(matchElement, element); this._assertElementExists(matchElement, element);
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan!); this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
const ngContentIndex = const ngContentIndex =
hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector); hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
@ -397,22 +397,22 @@ class TemplateParseVisitor implements html.Visitor {
const {directives} = this._parseDirectives(this.selectorMatcher, templateSelector); const {directives} = this._parseDirectives(this.selectorMatcher, templateSelector);
const templateBoundDirectivePropNames = new Set<string>(); const templateBoundDirectivePropNames = new Set<string>();
const templateDirectiveAsts = this._createDirectiveAsts( const templateDirectiveAsts = this._createDirectiveAsts(
true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan!, [], true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan, [],
templateBoundDirectivePropNames); templateBoundDirectivePropNames);
const templateElementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts( const templateElementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts(
elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames); elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames);
this._assertNoComponentsNorElementBindingsOnTemplate( this._assertNoComponentsNorElementBindingsOnTemplate(
templateDirectiveAsts, templateElementProps, element.sourceSpan!); templateDirectiveAsts, templateElementProps, element.sourceSpan);
const templateProviderContext = new ProviderElementContext( const templateProviderContext = new ProviderElementContext(
this.providerViewContext, parent.providerContext!, parent.isTemplateElement, this.providerViewContext, parent.providerContext!, parent.isTemplateElement,
templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan!); templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan);
templateProviderContext.afterElement(); templateProviderContext.afterElement();
parsedElement = new t.EmbeddedTemplateAst( parsedElement = new t.EmbeddedTemplateAst(
[], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts, [], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts,
templateProviderContext.transformProviders, templateProviderContext.transformProviders,
templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches, templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches,
[parsedElement], ngContentIndex, element.sourceSpan!); [parsedElement], ngContentIndex, element.sourceSpan);
} }
return parsedElement; return parsedElement;
@ -707,7 +707,7 @@ class TemplateParseVisitor implements html.Visitor {
errorMsg += errorMsg +=
`2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
} }
this._reportError(errorMsg, element.sourceSpan!); this._reportError(errorMsg, element.sourceSpan);
} }
} }
@ -815,7 +815,7 @@ class NonBindableVisitor implements html.Visitor {
visitText(text: html.Text, parent: ElementContext): t.TextAst { visitText(text: html.Text, parent: ElementContext): t.TextAst {
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR())!; const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR())!;
return new t.TextAst(text.value, ngContentIndex, text.sourceSpan!); return new t.TextAst(text.value, ngContentIndex, text.sourceSpan);
} }
visitExpansion(expansion: html.Expansion, context: any): any { visitExpansion(expansion: html.Expansion, context: any): any {

View File

@ -42,7 +42,7 @@ class _Humanizer implements html.Visitor {
visitElement(element: html.Element, context: any): any { visitElement(element: html.Element, context: any): any {
const res = this._appendContext(element, [html.Element, element.name, this.elDepth++]); const res = this._appendContext(element, [html.Element, element.name, this.elDepth++]);
if (this.includeSourceSpan) { if (this.includeSourceSpan) {
res.push(element.startSourceSpan?.toString() ?? null); res.push(element.startSourceSpan.toString() ?? null);
res.push(element.endSourceSpan?.toString() ?? null); res.push(element.endSourceSpan?.toString() ?? null);
} }
this.result.push(res); this.result.push(res);
@ -82,7 +82,7 @@ class _Humanizer implements html.Visitor {
private _appendContext(ast: html.Node, input: any[]): any[] { private _appendContext(ast: html.Node, input: any[]): any[] {
if (!this.includeSourceSpan) return input; if (!this.includeSourceSpan) return input;
input.push(ast.sourceSpan!.toString()); input.push(ast.sourceSpan.toString());
return input; return input;
} }
} }

View File

@ -667,8 +667,8 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe
it('should set the start and end source spans', () => { it('should set the start and end source spans', () => {
const node = <html.Element>parser.parse('<div>a</div>', 'TestComp').rootNodes[0]; const node = <html.Element>parser.parse('<div>a</div>', 'TestComp').rootNodes[0];
expect(node.startSourceSpan!.start.offset).toEqual(0); expect(node.startSourceSpan.start.offset).toEqual(0);
expect(node.startSourceSpan!.end.offset).toEqual(5); expect(node.startSourceSpan.end.offset).toEqual(5);
expect(node.endSourceSpan!.start.offset).toEqual(6); expect(node.endSourceSpan!.start.offset).toEqual(6);
expect(node.endSourceSpan!.end.offset).toEqual(12); expect(node.endSourceSpan!.end.offset).toEqual(12);

View File

@ -56,10 +56,10 @@ import {humanizeNodes} from './ast_spec_utils';
const nodes = expand(`{messages.length, plural,=0 {<b>bold</b>}}`).nodes; const nodes = expand(`{messages.length, plural,=0 {<b>bold</b>}}`).nodes;
const container: html.Element = <html.Element>nodes[0]; const container: html.Element = <html.Element>nodes[0];
expect(container.sourceSpan!.start.col).toEqual(0); expect(container.sourceSpan.start.col).toEqual(0);
expect(container.sourceSpan!.end.col).toEqual(42); expect(container.sourceSpan.end.col).toEqual(42);
expect(container.startSourceSpan!.start.col).toEqual(0); expect(container.startSourceSpan.start.col).toEqual(0);
expect(container.startSourceSpan!.end.col).toEqual(42); expect(container.startSourceSpan.end.col).toEqual(42);
expect(container.endSourceSpan!.start.col).toEqual(0); expect(container.endSourceSpan!.start.col).toEqual(0);
expect(container.endSourceSpan!.end.col).toEqual(42); expect(container.endSourceSpan!.end.col).toEqual(42);
@ -68,15 +68,15 @@ import {humanizeNodes} from './ast_spec_utils';
expect(switchExp.sourceSpan.end.col).toEqual(16); expect(switchExp.sourceSpan.end.col).toEqual(16);
const template: html.Element = <html.Element>container.children[0]; const template: html.Element = <html.Element>container.children[0];
expect(template.sourceSpan!.start.col).toEqual(25); expect(template.sourceSpan.start.col).toEqual(25);
expect(template.sourceSpan!.end.col).toEqual(41); expect(template.sourceSpan.end.col).toEqual(41);
const switchCheck = template.attrs[0]; const switchCheck = template.attrs[0];
expect(switchCheck.sourceSpan.start.col).toEqual(25); expect(switchCheck.sourceSpan.start.col).toEqual(25);
expect(switchCheck.sourceSpan.end.col).toEqual(28); expect(switchCheck.sourceSpan.end.col).toEqual(28);
const b: html.Element = <html.Element>template.children[0]; const b: html.Element = <html.Element>template.children[0];
expect(b.sourceSpan!.start.col).toEqual(29); expect(b.sourceSpan.start.col).toEqual(29);
expect(b.endSourceSpan!.end.col).toEqual(40); expect(b.endSourceSpan!.end.col).toEqual(40);
}); });

View File

@ -140,7 +140,7 @@ class TemplateHumanizer implements TemplateAstVisitor {
private _appendSourceSpan(ast: TemplateAst, input: any[]): any[] { private _appendSourceSpan(ast: TemplateAst, input: any[]): any[] {
if (!this.includeSourceSpan) return input; if (!this.includeSourceSpan) return input;
input.push(ast.sourceSpan!.toString()); input.push(ast.sourceSpan.toString());
return input; return input;
} }
} }

View File

@ -65,7 +65,7 @@ function getBoundedWordSpan(
// The HTML tag may include `-` (e.g. `app-root`), // The HTML tag may include `-` (e.g. `app-root`),
// so use the HtmlAst to get the span before ayazhafiz refactor the code. // so use the HtmlAst to get the span before ayazhafiz refactor the code.
return { return {
start: templateInfo.template.span.start + ast.startSourceSpan!.start.offset + 1, start: templateInfo.template.span.start + ast.startSourceSpan.start.offset + 1,
length: ast.name.length length: ast.name.length
}; };
} }

View File

@ -48,7 +48,7 @@ export function parseInnerRange(element: Element): ParseTreeResult {
* @param element The element whose inner range we want to compute. * @param element The element whose inner range we want to compute.
*/ */
function getInnerRange(element: Element): LexerRange { function getInnerRange(element: Element): LexerRange {
const start = element.startSourceSpan!.end; const start = element.startSourceSpan.end;
const end = element.endSourceSpan!.start; const end = element.endSourceSpan!.start;
return { return {
startPos: start.offset, startPos: start.offset,