refactor(compiler): move `ParsedTemplate` interface to compiler (#38594)

Previously this interface was mostly stored in compiler-cli, but it
contains some properties that would be useful for compiling the
"declare component" prelink code.

This commit moves some of the interface over to the compiler
package so that it can be referenced there without creating a
circular dependency between the compiler and compiler-cli.

PR Close #38594
This commit is contained in:
Pete Bacon Darwin 2020-08-26 17:10:04 +01:00 committed by atscott
parent 4007422cc6
commit 687477279b
7 changed files with 165 additions and 146 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {compileComponentFromMetadata, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DomElementSchemaRegistry, Expression, ExternalExpr, Identifiers, InterpolationConfig, LexerRange, makeBindingParser, ParseError, ParseSourceFile, parseTemplate, ParseTemplateOptions, R3ComponentMetadata, R3FactoryTarget, R3TargetBinder, SchemaMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr} from '@angular/compiler'; import {compileComponentFromMetadata, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DomElementSchemaRegistry, Expression, ExternalExpr, Identifiers, InterpolationConfig, LexerRange, makeBindingParser, ParsedTemplate, ParseSourceFile, parseTemplate, R3ComponentMetadata, R3FactoryTarget, R3TargetBinder, SchemaMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr} from '@angular/compiler';
import * as ts from 'typescript'; import * as ts from 'typescript';
import {CycleAnalyzer} from '../../cycles'; import {CycleAnalyzer} from '../../cycles';
@ -31,7 +31,7 @@ import {createValueHasWrongTypeError, getDirectiveDiagnostics, getProviderDiagno
import {extractDirectiveMetadata, parseFieldArrayValue} from './directive'; import {extractDirectiveMetadata, parseFieldArrayValue} from './directive';
import {compileNgFactoryDefField} from './factory'; import {compileNgFactoryDefField} from './factory';
import {generateSetClassMetadataCall} from './metadata'; import {generateSetClassMetadataCall} from './metadata';
import {findAngularDecorator, isAngularCoreReference, isExpressionForwardReference, makeDuplicateDeclarationError, readBaseClass, resolveProvidersRequiringFactory, unwrapExpression, wrapFunctionExpressionsInParens} from './util'; import {findAngularDecorator, isAngularCoreReference, isExpressionForwardReference, readBaseClass, resolveProvidersRequiringFactory, unwrapExpression, wrapFunctionExpressionsInParens} from './util';
const EMPTY_MAP = new Map<string, Expression>(); const EMPTY_MAP = new Map<string, Expression>();
const EMPTY_ARRAY: any[] = []; const EMPTY_ARRAY: any[] = [];
@ -260,7 +260,7 @@ export class ComponentDecoratorHandler implements
let diagnostics: ts.Diagnostic[]|undefined = undefined; let diagnostics: ts.Diagnostic[]|undefined = undefined;
if (template.errors !== undefined) { if (template.errors !== null) {
// If there are any template parsing errors, convert them to `ts.Diagnostic`s for display. // If there are any template parsing errors, convert them to `ts.Diagnostic`s for display.
const id = getTemplateId(node); const id = getTemplateId(node);
diagnostics = template.errors.map(error => { diagnostics = template.errors.map(error => {
@ -336,11 +336,11 @@ export class ComponentDecoratorHandler implements
meta: { meta: {
...metadata, ...metadata,
template: { template: {
nodes: template.emitNodes, nodes: template.nodes,
ngContentSelectors: template.ngContentSelectors, ngContentSelectors: template.ngContentSelectors,
}, },
encapsulation, encapsulation,
interpolation: template.interpolation, interpolation: template.interpolationConfig ?? DEFAULT_INTERPOLATION_CONFIG,
styles: styles || [], styles: styles || [],
// These will be replaced during the compilation step, after all `NgModule`s have been // These will be replaced during the compilation step, after all `NgModule`s have been
@ -772,7 +772,7 @@ export class ComponentDecoratorHandler implements
private _parseTemplate( private _parseTemplate(
component: Map<string, ts.Expression>, templateStr: string, templateUrl: string, component: Map<string, ts.Expression>, templateStr: string, templateUrl: string,
templateRange: LexerRange|undefined, escapedString: boolean): ParsedTemplate { templateRange: LexerRange|undefined, escapedString: boolean): ParsedComponentTemplate {
let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces; let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces;
if (component.has('preserveWhitespaces')) { if (component.has('preserveWhitespaces')) {
const expr = component.get('preserveWhitespaces')!; const expr = component.get('preserveWhitespaces')!;
@ -783,7 +783,7 @@ export class ComponentDecoratorHandler implements
preserveWhitespaces = value; preserveWhitespaces = value;
} }
let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG; let interpolationConfig = DEFAULT_INTERPOLATION_CONFIG;
if (component.has('interpolation')) { if (component.has('interpolation')) {
const expr = component.get('interpolation')!; const expr = component.get('interpolation')!;
const value = this.evaluator.evaluate(expr); const value = this.evaluator.evaluate(expr);
@ -792,21 +792,20 @@ export class ComponentDecoratorHandler implements
throw createValueHasWrongTypeError( throw createValueHasWrongTypeError(
expr, value, 'interpolation must be an array with 2 elements of string type'); expr, value, 'interpolation must be an array with 2 elements of string type');
} }
interpolation = InterpolationConfig.fromArray(value as [string, string]); interpolationConfig = InterpolationConfig.fromArray(value as [string, string]);
} }
// We always normalize line endings if the template has been escaped (i.e. is inline). // We always normalize line endings if the template has been escaped (i.e. is inline).
const i18nNormalizeLineEndingsInICUs = escapedString || this.i18nNormalizeLineEndingsInICUs; const i18nNormalizeLineEndingsInICUs = escapedString || this.i18nNormalizeLineEndingsInICUs;
const {errors, nodes: emitNodes, styleUrls, styles, ngContentSelectors} = const parsedTemplate = parseTemplate(templateStr, templateUrl, {
parseTemplate(templateStr, templateUrl, { preserveWhitespaces,
preserveWhitespaces, interpolationConfig,
interpolationConfig: interpolation, range: templateRange,
range: templateRange, escapedString,
escapedString, enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat, i18nNormalizeLineEndingsInICUs,
i18nNormalizeLineEndingsInICUs, });
});
// Unfortunately, the primary parse of the template above may not contain accurate source map // Unfortunately, the primary parse of the template above may not contain accurate source map
// information. If used directly, it would result in incorrect code locations in template // information. If used directly, it would result in incorrect code locations in template
@ -823,7 +822,7 @@ export class ComponentDecoratorHandler implements
const {nodes: diagNodes} = parseTemplate(templateStr, templateUrl, { const {nodes: diagNodes} = parseTemplate(templateStr, templateUrl, {
preserveWhitespaces: true, preserveWhitespaces: true,
interpolationConfig: interpolation, interpolationConfig,
range: templateRange, range: templateRange,
escapedString, escapedString,
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat, enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
@ -832,13 +831,8 @@ export class ComponentDecoratorHandler implements
}); });
return { return {
interpolation, ...parsedTemplate,
emitNodes,
diagNodes, diagNodes,
styleUrls,
styles,
ngContentSelectors,
errors,
template: templateStr, template: templateStr,
templateUrl, templateUrl,
isInline: component.has('template'), isInline: component.has('template'),
@ -905,12 +899,7 @@ function sourceMapUrl(resourceUrl: string): string {
* This contains the actual parsed template as well as any metadata collected during its parsing, * This contains the actual parsed template as well as any metadata collected during its parsing,
* some of which might be useful for re-parsing the template with different options. * some of which might be useful for re-parsing the template with different options.
*/ */
export interface ParsedTemplate { export interface ParsedComponentTemplate extends ParsedTemplate {
/**
* The `InterpolationConfig` specified by the user.
*/
interpolation: InterpolationConfig;
/** /**
* A full path to the file which contains the template. * A full path to the file which contains the template.
* *
@ -920,22 +909,10 @@ export interface ParsedTemplate {
templateUrl: string; templateUrl: string;
/** /**
* The string contents of the template. * True if the original template was stored inline;
* * False if the template was in an external file.
* This is the "logical" template string, after expansion of any escaped characters (for inline
* templates). This may differ from the actual template bytes as they appear in the .ts file.
*/ */
template: string; isInline: boolean;
/**
* Any errors from parsing the template the first time.
*/
errors?: ParseError[]|undefined;
/**
* The template AST, parsed according to the user's specifications.
*/
emitNodes: TmplAstNode[];
/** /**
* The template AST, parsed in a manner which preserves source map information for diagnostics. * The template AST, parsed in a manner which preserves source map information for diagnostics.
@ -944,36 +921,12 @@ export interface ParsedTemplate {
*/ */
diagNodes: TmplAstNode[]; diagNodes: TmplAstNode[];
/**
*
*/
/**
* Any styleUrls extracted from the metadata.
*/
styleUrls: string[];
/**
* Any inline styles extracted from the metadata.
*/
styles: string[];
/**
* Any ng-content selectors extracted from the template.
*/
ngContentSelectors: string[];
/**
* Whether the template was inline.
*/
isInline: boolean;
/** /**
* The `ParseSourceFile` for the template. * The `ParseSourceFile` for the template.
*/ */
file: ParseSourceFile; file: ParseSourceFile;
} }
export interface ParsedTemplateWithSource extends ParsedTemplate { export interface ParsedTemplateWithSource extends ParsedComponentTemplate {
sourceMapping: TemplateSourceMapping; sourceMapping: TemplateSourceMapping;
} }

View File

@ -79,7 +79,7 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker {
leadingTriviaChars: [], leadingTriviaChars: [],
}); });
if (errors !== undefined) { if (errors !== null) {
return {nodes, errors}; return {nodes, errors};
} }

View File

@ -354,7 +354,7 @@ export function setup(targets: TypeCheckingTarget[], overrides: {
const templateUrl = `${className}.html`; const templateUrl = `${className}.html`;
const templateFile = new ParseSourceFile(template, templateUrl); const templateFile = new ParseSourceFile(template, templateUrl);
const {nodes, errors} = parseTemplate(template, templateUrl); const {nodes, errors} = parseTemplate(template, templateUrl);
if (errors !== undefined) { if (errors !== null) {
throw new Error('Template parse errors: \n' + errors.join('\n')); throw new Error('Template parse errors: \n' + errors.join('\n'));
} }

View File

@ -99,7 +99,7 @@ export {Identifiers as R3Identifiers} from './render3/r3_identifiers';
export {R3DependencyMetadata, R3ResolvedDependencyType, compileFactoryFunction, R3FactoryMetadata, R3FactoryTarget} from './render3/r3_factory'; export {R3DependencyMetadata, R3ResolvedDependencyType, compileFactoryFunction, R3FactoryMetadata, R3FactoryTarget} from './render3/r3_factory';
export {compileInjector, compileNgModule, R3InjectorMetadata, R3NgModuleMetadata} from './render3/r3_module_compiler'; export {compileInjector, compileNgModule, R3InjectorMetadata, R3NgModuleMetadata} from './render3/r3_module_compiler';
export {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compiler'; export {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compiler';
export {makeBindingParser, parseTemplate, ParseTemplateOptions} from './render3/view/template'; export {makeBindingParser, ParsedTemplate, parseTemplate, ParseTemplateOptions} from './render3/view/template';
export {R3Reference} from './render3/util'; export {R3Reference} from './render3/util';
export {compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, ParsedHostBindings, verifyHostBindings} from './render3/view/compiler'; export {compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, ParsedHostBindings, verifyHostBindings} from './render3/view/compiler';
export {publishFacade} from './jit_compiler_facade'; export {publishFacade} from './jit_compiler_facade';

View File

@ -129,7 +129,7 @@ export class CompilerFacadeImpl implements CompilerFacade {
const template = parseTemplate( const template = parseTemplate(
facade.template, sourceMapUrl, facade.template, sourceMapUrl,
{preserveWhitespaces: facade.preserveWhitespaces, interpolationConfig}); {preserveWhitespaces: facade.preserveWhitespaces, interpolationConfig});
if (template.errors !== undefined) { if (template.errors !== null) {
const errors = template.errors.map(err => err.toString()).join(', '); const errors = template.errors.map(err => err.toString()).join(', ');
throw new Error(`Errors during JIT compilation of template for ${facade.name}: ${errors}`); throw new Error(`Errors during JIT compilation of template for ${facade.name}: ${errors}`);
} }

View File

@ -2025,13 +2025,7 @@ export interface ParseTemplateOptions {
* @param options options to modify how the template is parsed * @param options options to modify how the template is parsed
*/ */
export function parseTemplate( export function parseTemplate(
template: string, templateUrl: string, options: ParseTemplateOptions = {}): { template: string, templateUrl: string, options: ParseTemplateOptions = {}): ParsedTemplate {
errors?: ParseError[],
nodes: t.Node[],
styleUrls: string[],
styles: string[],
ngContentSelectors: string[]
} {
const {interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat} = options; const {interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat} = options;
const bindingParser = makeBindingParser(interpolationConfig); const bindingParser = makeBindingParser(interpolationConfig);
const htmlParser = new HtmlParser(); const htmlParser = new HtmlParser();
@ -2041,6 +2035,9 @@ export function parseTemplate(
if (parseResult.errors && parseResult.errors.length > 0) { if (parseResult.errors && parseResult.errors.length > 0) {
return { return {
interpolationConfig,
preserveWhitespaces,
template,
errors: parseResult.errors, errors: parseResult.errors,
nodes: [], nodes: [],
styleUrls: [], styleUrls: [],
@ -2076,10 +2073,28 @@ export function parseTemplate(
const {nodes, errors, styleUrls, styles, ngContentSelectors} = const {nodes, errors, styleUrls, styles, ngContentSelectors} =
htmlAstToRender3Ast(rootNodes, bindingParser); htmlAstToRender3Ast(rootNodes, bindingParser);
if (errors && errors.length > 0) { if (errors && errors.length > 0) {
return {errors, nodes: [], styleUrls: [], styles: [], ngContentSelectors: []}; return {
interpolationConfig,
preserveWhitespaces,
template,
errors,
nodes: [],
styleUrls: [],
styles: [],
ngContentSelectors: []
};
} }
return {nodes, styleUrls, styles, ngContentSelectors}; return {
interpolationConfig,
preserveWhitespaces,
errors: null,
template,
nodes,
styleUrls,
styles,
ngContentSelectors
};
} }
const elementRegistry = new DomElementSchemaRegistry(); const elementRegistry = new DomElementSchemaRegistry();
@ -2196,3 +2211,54 @@ function createClosureModeGuard(): o.BinaryOperatorExpr {
.notIdentical(o.literal('undefined', o.STRING_TYPE)) .notIdentical(o.literal('undefined', o.STRING_TYPE))
.and(o.variable(NG_I18N_CLOSURE_MODE)); .and(o.variable(NG_I18N_CLOSURE_MODE));
} }
/**
* Information about the template which was extracted during parsing.
*
* This contains the actual parsed template as well as any metadata collected during its parsing,
* some of which might be useful for re-parsing the template with different options.
*/
export interface ParsedTemplate {
/**
* Include whitespace nodes in the parsed output.
*/
preserveWhitespaces?: boolean;
/**
* How to parse interpolation markers.
*/
interpolationConfig?: InterpolationConfig;
/**
* The string contents of the template.
*
* This is the "logical" template string, after expansion of any escaped characters (for inline
* templates). This may differ from the actual template bytes as they appear in the .ts file.
*/
template: string;
/**
* Any errors from parsing the template the first time.
*/
errors: ParseError[]|null;
/**
* The template AST, parsed from the template.
*/
nodes: t.Node[];
/**
* Any styleUrls extracted from the metadata.
*/
styleUrls: string[];
/**
* Any inline styles extracted from the metadata.
*/
styles: string[];
/**
* Any ng-content selectors extracted from the template.
*/
ngContentSelectors: string[];
}

View File

@ -14,7 +14,7 @@ import {findNodeAtPosition, isExpressionNode, isTemplateNode} from '../hybrid_vi
interface ParseResult { interface ParseResult {
nodes: t.Node[]; nodes: t.Node[];
errors?: ParseError[]; errors: ParseError[]|null;
position: number; position: number;
} }
@ -34,7 +34,7 @@ function parse(template: string): ParseResult {
describe('findNodeAtPosition for template AST', () => { describe('findNodeAtPosition for template AST', () => {
it('should locate element in opening tag', () => { it('should locate element in opening tag', () => {
const {errors, nodes, position} = parse(`<di¦v></div>`); const {errors, nodes, position} = parse(`<di¦v></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Element); expect(node).toBeInstanceOf(t.Element);
@ -42,7 +42,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate element in closing tag', () => { it('should locate element in closing tag', () => {
const {errors, nodes, position} = parse(`<div></di¦v>`); const {errors, nodes, position} = parse(`<div></di¦v>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Element); expect(node).toBeInstanceOf(t.Element);
@ -50,7 +50,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate element when cursor is at the beginning', () => { it('should locate element when cursor is at the beginning', () => {
const {errors, nodes, position} = parse(`<¦div></div>`); const {errors, nodes, position} = parse(`<¦div></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Element); expect(node).toBeInstanceOf(t.Element);
@ -58,7 +58,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate element when cursor is at the end', () => { it('should locate element when cursor is at the end', () => {
const {errors, nodes, position} = parse(`<div¦></div>`); const {errors, nodes, position} = parse(`<div¦></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Element); expect(node).toBeInstanceOf(t.Element);
@ -66,7 +66,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate attribute key', () => { it('should locate attribute key', () => {
const {errors, nodes, position} = parse(`<div cla¦ss="foo"></div>`); const {errors, nodes, position} = parse(`<div cla¦ss="foo"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.TextAttribute); expect(node).toBeInstanceOf(t.TextAttribute);
@ -74,7 +74,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate attribute value', () => { it('should locate attribute value', () => {
const {errors, nodes, position} = parse(`<div class="fo¦o"></div>`); const {errors, nodes, position} = parse(`<div class="fo¦o"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
// TODO: Note that we do not have the ability to detect the RHS (yet) // TODO: Note that we do not have the ability to detect the RHS (yet)
@ -83,7 +83,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate bound attribute key', () => { it('should locate bound attribute key', () => {
const {errors, nodes, position} = parse(`<test-cmp [fo¦o]="bar"></test-cmp>`); const {errors, nodes, position} = parse(`<test-cmp [fo¦o]="bar"></test-cmp>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.BoundAttribute); expect(node).toBeInstanceOf(t.BoundAttribute);
@ -91,7 +91,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate bound attribute value', () => { it('should locate bound attribute value', () => {
const {errors, nodes, position} = parse(`<test-cmp [foo]="b¦ar"></test-cmp>`); const {errors, nodes, position} = parse(`<test-cmp [foo]="b¦ar"></test-cmp>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -99,7 +99,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate bound event key', () => { it('should locate bound event key', () => {
const {errors, nodes, position} = parse(`<test-cmp (fo¦o)="bar()"></test-cmp>`); const {errors, nodes, position} = parse(`<test-cmp (fo¦o)="bar()"></test-cmp>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.BoundEvent); expect(node).toBeInstanceOf(t.BoundEvent);
@ -107,7 +107,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate bound event value', () => { it('should locate bound event value', () => {
const {errors, nodes, position} = parse(`<test-cmp (foo)="b¦ar()"></test-cmp>`); const {errors, nodes, position} = parse(`<test-cmp (foo)="b¦ar()"></test-cmp>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.MethodCall); expect(node).toBeInstanceOf(e.MethodCall);
@ -115,7 +115,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate element children', () => { it('should locate element children', () => {
const {errors, nodes, position} = parse(`<div><sp¦an></span></div>`); const {errors, nodes, position} = parse(`<div><sp¦an></span></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Element); expect(node).toBeInstanceOf(t.Element);
@ -124,7 +124,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate element reference', () => { it('should locate element reference', () => {
const {errors, nodes, position} = parse(`<div #my¦div></div>`); const {errors, nodes, position} = parse(`<div #my¦div></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Reference); expect(node).toBeInstanceOf(t.Reference);
@ -132,7 +132,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template text attribute', () => { it('should locate template text attribute', () => {
const {errors, nodes, position} = parse(`<ng-template ng¦If></ng-template>`); const {errors, nodes, position} = parse(`<ng-template ng¦If></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.TextAttribute); expect(node).toBeInstanceOf(t.TextAttribute);
@ -140,7 +140,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template bound attribute key', () => { it('should locate template bound attribute key', () => {
const {errors, nodes, position} = parse(`<ng-template [ng¦If]="foo"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template [ng¦If]="foo"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.BoundAttribute); expect(node).toBeInstanceOf(t.BoundAttribute);
@ -148,7 +148,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template bound attribute value', () => { it('should locate template bound attribute value', () => {
const {errors, nodes, position} = parse(`<ng-template [ngIf]="f¦oo"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template [ngIf]="f¦oo"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -156,7 +156,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template bound attribute key in two-way binding', () => { it('should locate template bound attribute key in two-way binding', () => {
const {errors, nodes, position} = parse(`<ng-template [(f¦oo)]="bar"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template [(f¦oo)]="bar"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.BoundAttribute); expect(node).toBeInstanceOf(t.BoundAttribute);
@ -165,7 +165,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template bound attribute value in two-way binding', () => { it('should locate template bound attribute value in two-way binding', () => {
const {errors, nodes, position} = parse(`<ng-template [(foo)]="b¦ar"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template [(foo)]="b¦ar"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -174,7 +174,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template bound event key', () => { it('should locate template bound event key', () => {
const {errors, nodes, position} = parse(`<ng-template (cl¦ick)="foo()"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template (cl¦ick)="foo()"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.BoundEvent); expect(node).toBeInstanceOf(t.BoundEvent);
@ -182,14 +182,14 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template bound event value', () => { it('should locate template bound event value', () => {
const {errors, nodes, position} = parse(`<ng-template (click)="f¦oo()"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template (click)="f¦oo()"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(node).toBeInstanceOf(e.MethodCall); expect(node).toBeInstanceOf(e.MethodCall);
}); });
it('should locate template attribute key', () => { it('should locate template attribute key', () => {
const {errors, nodes, position} = parse(`<ng-template i¦d="foo"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template i¦d="foo"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.TextAttribute); expect(node).toBeInstanceOf(t.TextAttribute);
@ -197,7 +197,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template attribute value', () => { it('should locate template attribute value', () => {
const {errors, nodes, position} = parse(`<ng-template id="f¦oo"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template id="f¦oo"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
// TODO: Note that we do not have the ability to detect the RHS (yet) // TODO: Note that we do not have the ability to detect the RHS (yet)
@ -206,7 +206,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template reference key via the # notation', () => { it('should locate template reference key via the # notation', () => {
const {errors, nodes, position} = parse(`<ng-template #f¦oo></ng-template>`); const {errors, nodes, position} = parse(`<ng-template #f¦oo></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Reference); expect(node).toBeInstanceOf(t.Reference);
@ -215,7 +215,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template reference key via the ref- notation', () => { it('should locate template reference key via the ref- notation', () => {
const {errors, nodes, position} = parse(`<ng-template ref-fo¦o></ng-template>`); const {errors, nodes, position} = parse(`<ng-template ref-fo¦o></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Reference); expect(node).toBeInstanceOf(t.Reference);
@ -224,7 +224,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template reference value via the # notation', () => { it('should locate template reference value via the # notation', () => {
const {errors, nodes, position} = parse(`<ng-template #foo="export¦As"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template #foo="export¦As"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Reference); expect(node).toBeInstanceOf(t.Reference);
@ -234,7 +234,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template reference value via the ref- notation', () => { it('should locate template reference value via the ref- notation', () => {
const {errors, nodes, position} = parse(`<ng-template ref-foo="export¦As"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template ref-foo="export¦As"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Reference); expect(node).toBeInstanceOf(t.Reference);
@ -244,7 +244,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template variable key', () => { it('should locate template variable key', () => {
const {errors, nodes, position} = parse(`<ng-template let-f¦oo="bar"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template let-f¦oo="bar"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Variable); expect(node).toBeInstanceOf(t.Variable);
@ -252,7 +252,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template variable value', () => { it('should locate template variable value', () => {
const {errors, nodes, position} = parse(`<ng-template let-foo="b¦ar"></ng-template>`); const {errors, nodes, position} = parse(`<ng-template let-foo="b¦ar"></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Variable); expect(node).toBeInstanceOf(t.Variable);
@ -260,7 +260,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate template children', () => { it('should locate template children', () => {
const {errors, nodes, position} = parse(`<ng-template><d¦iv></div></ng-template>`); const {errors, nodes, position} = parse(`<ng-template><d¦iv></div></ng-template>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Element); expect(node).toBeInstanceOf(t.Element);
@ -268,7 +268,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate ng-content', () => { it('should locate ng-content', () => {
const {errors, nodes, position} = parse(`<ng-co¦ntent></ng-content>`); const {errors, nodes, position} = parse(`<ng-co¦ntent></ng-content>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Content); expect(node).toBeInstanceOf(t.Content);
@ -276,7 +276,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate ng-content attribute key', () => { it('should locate ng-content attribute key', () => {
const {errors, nodes, position} = parse('<ng-content cla¦ss="red"></ng-content>'); const {errors, nodes, position} = parse('<ng-content cla¦ss="red"></ng-content>');
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.TextAttribute); expect(node).toBeInstanceOf(t.TextAttribute);
@ -284,7 +284,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate ng-content attribute value', () => { it('should locate ng-content attribute value', () => {
const {errors, nodes, position} = parse('<ng-content class="r¦ed"></ng-content>'); const {errors, nodes, position} = parse('<ng-content class="r¦ed"></ng-content>');
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
// TODO: Note that we do not have the ability to detect the RHS (yet) // TODO: Note that we do not have the ability to detect the RHS (yet)
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
@ -293,7 +293,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should not locate implicit receiver', () => { it('should not locate implicit receiver', () => {
const {errors, nodes, position} = parse(`<div [foo]="¦bar"></div>`); const {errors, nodes, position} = parse(`<div [foo]="¦bar"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -301,7 +301,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate bound attribute key in two-way binding', () => { it('should locate bound attribute key in two-way binding', () => {
const {errors, nodes, position} = parse(`<cmp [(f¦oo)]="bar"></cmp>`); const {errors, nodes, position} = parse(`<cmp [(f¦oo)]="bar"></cmp>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.BoundAttribute); expect(node).toBeInstanceOf(t.BoundAttribute);
@ -310,7 +310,7 @@ describe('findNodeAtPosition for template AST', () => {
it('should locate bound attribute value in two-way binding', () => { it('should locate bound attribute value in two-way binding', () => {
const {errors, nodes, position} = parse(`<cmp [(foo)]="b¦ar"></cmp>`); const {errors, nodes, position} = parse(`<cmp [(foo)]="b¦ar"></cmp>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -321,7 +321,7 @@ describe('findNodeAtPosition for template AST', () => {
describe('findNodeAtPosition for expression AST', () => { describe('findNodeAtPosition for expression AST', () => {
it('should not locate implicit receiver', () => { it('should not locate implicit receiver', () => {
const {errors, nodes, position} = parse(`{{ ¦title }}`); const {errors, nodes, position} = parse(`{{ ¦title }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -330,7 +330,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate property read', () => { it('should locate property read', () => {
const {errors, nodes, position} = parse(`{{ ti¦tle }}`); const {errors, nodes, position} = parse(`{{ ti¦tle }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -339,7 +339,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate safe property read', () => { it('should locate safe property read', () => {
const {errors, nodes, position} = parse(`{{ foo?¦.bar }}`); const {errors, nodes, position} = parse(`{{ foo?¦.bar }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.SafePropertyRead); expect(node).toBeInstanceOf(e.SafePropertyRead);
@ -348,7 +348,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate keyed read', () => { it('should locate keyed read', () => {
const {errors, nodes, position} = parse(`{{ foo['bar']¦ }}`); const {errors, nodes, position} = parse(`{{ foo['bar']¦ }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.KeyedRead); expect(node).toBeInstanceOf(e.KeyedRead);
@ -356,7 +356,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate property write', () => { it('should locate property write', () => {
const {errors, nodes, position} = parse(`<div (foo)="b¦ar=$event"></div>`); const {errors, nodes, position} = parse(`<div (foo)="b¦ar=$event"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyWrite); expect(node).toBeInstanceOf(e.PropertyWrite);
@ -364,7 +364,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate keyed write', () => { it('should locate keyed write', () => {
const {errors, nodes, position} = parse(`<div (foo)="bar['baz']¦=$event"></div>`); const {errors, nodes, position} = parse(`<div (foo)="bar['baz']¦=$event"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.KeyedWrite); expect(node).toBeInstanceOf(e.KeyedWrite);
@ -372,7 +372,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate binary', () => { it('should locate binary', () => {
const {errors, nodes, position} = parse(`{{ 1 +¦ 2 }}`); const {errors, nodes, position} = parse(`{{ 1 +¦ 2 }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.Binary); expect(node).toBeInstanceOf(e.Binary);
@ -380,7 +380,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate binding pipe with an identifier', () => { it('should locate binding pipe with an identifier', () => {
const {errors, nodes, position} = parse(`{{ title | p¦ }}`); const {errors, nodes, position} = parse(`{{ title | p¦ }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.BindingPipe); expect(node).toBeInstanceOf(e.BindingPipe);
@ -391,7 +391,7 @@ describe('findNodeAtPosition for expression AST', () => {
// TODO: We are not able to locate pipe if identifier is missing because the // TODO: We are not able to locate pipe if identifier is missing because the
// parser throws an error. This case is important for autocomplete. // parser throws an error. This case is important for autocomplete.
// const {errors, nodes, position} = parse(`{{ title | ¦ }}`); // const {errors, nodes, position} = parse(`{{ title | ¦ }}`);
// expect(errors).toBeUndefined(); // expect(errors).toBe(null);
// const node = findNodeAtPosition(nodes, position); // const node = findNodeAtPosition(nodes, position);
// expect(isExpressionNode(node!)).toBe(true); // expect(isExpressionNode(node!)).toBe(true);
// expect(node).toBeInstanceOf(e.BindingPipe); // expect(node).toBeInstanceOf(e.BindingPipe);
@ -399,7 +399,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate method call', () => { it('should locate method call', () => {
const {errors, nodes, position} = parse(`{{ title.toString(¦) }}`); const {errors, nodes, position} = parse(`{{ title.toString(¦) }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.MethodCall); expect(node).toBeInstanceOf(e.MethodCall);
@ -407,7 +407,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate safe method call', () => { it('should locate safe method call', () => {
const {errors, nodes, position} = parse(`{{ title?.toString(¦) }}`); const {errors, nodes, position} = parse(`{{ title?.toString(¦) }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.SafeMethodCall); expect(node).toBeInstanceOf(e.SafeMethodCall);
@ -415,7 +415,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate literal primitive in interpolation', () => { it('should locate literal primitive in interpolation', () => {
const {errors, nodes, position} = parse(`{{ title.indexOf('t¦') }}`); const {errors, nodes, position} = parse(`{{ title.indexOf('t¦') }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.LiteralPrimitive); expect(node).toBeInstanceOf(e.LiteralPrimitive);
@ -424,7 +424,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate literal primitive in binding', () => { it('should locate literal primitive in binding', () => {
const {errors, nodes, position} = parse(`<div [id]="'t¦'"></div>`); const {errors, nodes, position} = parse(`<div [id]="'t¦'"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.LiteralPrimitive); expect(node).toBeInstanceOf(e.LiteralPrimitive);
@ -433,7 +433,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate empty expression', () => { it('should locate empty expression', () => {
const {errors, nodes, position} = parse(`<div [id]="¦"></div>`); const {errors, nodes, position} = parse(`<div [id]="¦"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.EmptyExpr); expect(node).toBeInstanceOf(e.EmptyExpr);
@ -441,7 +441,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate literal array', () => { it('should locate literal array', () => {
const {errors, nodes, position} = parse(`{{ [1, 2,¦ 3] }}`); const {errors, nodes, position} = parse(`{{ [1, 2,¦ 3] }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.LiteralArray); expect(node).toBeInstanceOf(e.LiteralArray);
@ -449,7 +449,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate literal map', () => { it('should locate literal map', () => {
const {errors, nodes, position} = parse(`{{ { hello:¦ "world" } }}`); const {errors, nodes, position} = parse(`{{ { hello:¦ "world" } }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.LiteralMap); expect(node).toBeInstanceOf(e.LiteralMap);
@ -457,7 +457,7 @@ describe('findNodeAtPosition for expression AST', () => {
it('should locate conditional', () => { it('should locate conditional', () => {
const {errors, nodes, position} = parse(`{{ cond ?¦ true : false }}`); const {errors, nodes, position} = parse(`{{ cond ?¦ true : false }}`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.Conditional); expect(node).toBeInstanceOf(e.Conditional);
@ -467,7 +467,7 @@ describe('findNodeAtPosition for expression AST', () => {
describe('findNodeAtPosition for microsyntax expression', () => { describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate template key', () => { it('should locate template key', () => {
const {errors, nodes, position} = parse(`<div *ng¦If="foo"></div>`); const {errors, nodes, position} = parse(`<div *ng¦If="foo"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.BoundAttribute); expect(node).toBeInstanceOf(t.BoundAttribute);
@ -475,7 +475,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate template value', () => { it('should locate template value', () => {
const {errors, nodes, position} = parse(`<div *ngIf="f¦oo"></div>`); const {errors, nodes, position} = parse(`<div *ngIf="f¦oo"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -485,7 +485,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
const {errors, nodes, position} = parse(`<div *ng¦For="let item of items"></div>`); const {errors, nodes, position} = parse(`<div *ng¦For="let item of items"></div>`);
// ngFor is a text attribute because the desugared form is // ngFor is a text attribute because the desugared form is
// <ng-template ngFor let-item [ngForOf]="items"> // <ng-template ngFor let-item [ngForOf]="items">
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
// TODO: this is currently wrong because it should point to ngFor text // TODO: this is currently wrong because it should point to ngFor text
// attribute instead of ngForOf bound attribute // attribute instead of ngForOf bound attribute
@ -493,7 +493,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate not let keyword', () => { it('should locate not let keyword', () => {
const {errors, nodes, position} = parse(`<div *ngFor="l¦et item of items"></div>`); const {errors, nodes, position} = parse(`<div *ngFor="l¦et item of items"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
// TODO: this is currently wrong because node is currently pointing to // TODO: this is currently wrong because node is currently pointing to
// "item". In this case, it should return undefined. // "item". In this case, it should return undefined.
@ -501,7 +501,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate let variable', () => { it('should locate let variable', () => {
const {errors, nodes, position} = parse(`<div *ngFor="let i¦tem of items"></div>`); const {errors, nodes, position} = parse(`<div *ngFor="let i¦tem of items"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Variable); expect(node).toBeInstanceOf(t.Variable);
@ -510,7 +510,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate bound attribute key', () => { it('should locate bound attribute key', () => {
const {errors, nodes, position} = parse(`<div *ngFor="let item o¦f items"></div>`); const {errors, nodes, position} = parse(`<div *ngFor="let item o¦f items"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.BoundAttribute); expect(node).toBeInstanceOf(t.BoundAttribute);
@ -519,7 +519,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate bound attribute value', () => { it('should locate bound attribute value', () => {
const {errors, nodes, position} = parse(`<div *ngFor="let item of it¦ems"></div>`); const {errors, nodes, position} = parse(`<div *ngFor="let item of it¦ems"></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -528,7 +528,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate template children', () => { it('should locate template children', () => {
const {errors, nodes, position} = parse(`<di¦v *ngIf></div>`); const {errors, nodes, position} = parse(`<di¦v *ngIf></div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Element); expect(node).toBeInstanceOf(t.Element);
@ -540,7 +540,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
<div *ngFor="let item of items; let i=index"> <div *ngFor="let item of items; let i=index">
{{ i¦ }} {{ i¦ }}
</div>`); </div>`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isExpressionNode(node!)).toBe(true); expect(isExpressionNode(node!)).toBe(true);
expect(node).toBeInstanceOf(e.PropertyRead); expect(node).toBeInstanceOf(e.PropertyRead);
@ -548,7 +548,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate LHS of variable declaration', () => { it('should locate LHS of variable declaration', () => {
const {errors, nodes, position} = parse(`<div *ngFor="let item of items; let i¦=index">`); const {errors, nodes, position} = parse(`<div *ngFor="let item of items; let i¦=index">`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Variable); expect(node).toBeInstanceOf(t.Variable);
@ -558,7 +558,7 @@ describe('findNodeAtPosition for microsyntax expression', () => {
it('should locate RHS of variable declaration', () => { it('should locate RHS of variable declaration', () => {
const {errors, nodes, position} = parse(`<div *ngFor="let item of items; let i=in¦dex">`); const {errors, nodes, position} = parse(`<div *ngFor="let item of items; let i=in¦dex">`);
expect(errors).toBeUndefined(); expect(errors).toBe(null);
const node = findNodeAtPosition(nodes, position); const node = findNodeAtPosition(nodes, position);
expect(isTemplateNode(node!)).toBe(true); expect(isTemplateNode(node!)).toBe(true);
expect(node).toBeInstanceOf(t.Variable); expect(node).toBeInstanceOf(t.Variable);