refactor(language-service): Add type to `TemplateTarget` that can indicate multi-node targets (#40185)
The current template target implementation only allows a way to represent the template position as targeting a single node in the template AST. However, there is at least one case (banana-in-a-box) where a given template position refers to two template targets. This commit expands the contexts that the `TemplateTarget` can return to include support for the banana-in-a-box syntax, which has two logically targetted AST nodes given a position within the `keySpan` of the binding. PR Close #40185
This commit is contained in:
parent
46ea684351
commit
a893187d51
|
@ -12,7 +12,7 @@ import {isExternalResource} from '@angular/compiler-cli/src/ngtsc/metadata';
|
|||
import {DirectiveSymbol, DomBindingSymbol, ElementSymbol, ShimLocation, Symbol, SymbolKind, TemplateSymbol} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {getTargetAtPosition} from './template_target';
|
||||
import {getTargetAtPosition, TargetNodeKind} from './template_target';
|
||||
import {findTightestNode, getParentClassDeclaration} from './ts_utils';
|
||||
import {flatMap, getDirectiveMatchesForAttribute, getDirectiveMatchesForElementTag, getTemplateInfoAtPosition, getTextSpanOfNode, isDollarEvent, isTypeScriptFile, TemplateInfo, toTextSpan} from './utils';
|
||||
|
||||
|
@ -226,14 +226,16 @@ export class DefinitionBuilder {
|
|||
if (target === null) {
|
||||
return undefined;
|
||||
}
|
||||
const {nodeInContext, parent} = target;
|
||||
const {context, parent} = target;
|
||||
|
||||
const symbol =
|
||||
this.compiler.getTemplateTypeChecker().getSymbolOfNode(nodeInContext.node, component);
|
||||
const node =
|
||||
context.kind === TargetNodeKind.TwoWayBindingContext ? context.nodes[0] : context.node;
|
||||
|
||||
const symbol = this.compiler.getTemplateTypeChecker().getSymbolOfNode(node, component);
|
||||
if (symbol === null) {
|
||||
return undefined;
|
||||
}
|
||||
return {node: nodeInContext.node, parent, symbol};
|
||||
return {node, parent, symbol};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import {CompletionBuilder, CompletionNodeContext} from './completions';
|
|||
import {DefinitionBuilder} from './definitions';
|
||||
import {QuickInfoBuilder} from './quick_info';
|
||||
import {ReferenceBuilder} from './references';
|
||||
import {getTargetAtPosition, TargetNode, TargetNodeKind} from './template_target';
|
||||
import {getTargetAtPosition, TargetContext, TargetNodeKind} from './template_target';
|
||||
import {getTemplateInfoAtPosition, isTypeScriptFile} from './utils';
|
||||
|
||||
export class LanguageService {
|
||||
|
@ -104,10 +104,11 @@ export class LanguageService {
|
|||
if (positionDetails === null) {
|
||||
return undefined;
|
||||
}
|
||||
const results =
|
||||
new QuickInfoBuilder(
|
||||
this.tsLS, compiler, templateInfo.component, positionDetails.nodeInContext.node)
|
||||
.get();
|
||||
|
||||
const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
|
||||
positionDetails.context.nodes[0] :
|
||||
positionDetails.context.node;
|
||||
const results = new QuickInfoBuilder(this.tsLS, compiler, templateInfo.component, node).get();
|
||||
this.compilerFactory.registerLastKnownProgram();
|
||||
return results;
|
||||
}
|
||||
|
@ -131,9 +132,13 @@ export class LanguageService {
|
|||
if (positionDetails === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
|
||||
positionDetails.context.nodes[0] :
|
||||
positionDetails.context.node;
|
||||
return new CompletionBuilder(
|
||||
this.tsLS, compiler, templateInfo.component, positionDetails.nodeInContext.node,
|
||||
nodeContextFromTarget(positionDetails.nodeInContext), positionDetails.parent,
|
||||
this.tsLS, compiler, templateInfo.component, node,
|
||||
nodeContextFromTarget(positionDetails.context), positionDetails.parent,
|
||||
positionDetails.template);
|
||||
}
|
||||
|
||||
|
@ -260,7 +265,7 @@ function getOrCreateTypeCheckScriptInfo(
|
|||
return scriptInfo;
|
||||
}
|
||||
|
||||
function nodeContextFromTarget(target: TargetNode): CompletionNodeContext {
|
||||
function nodeContextFromTarget(target: TargetContext): CompletionNodeContext {
|
||||
switch (target.kind) {
|
||||
case TargetNodeKind.ElementInTagContext:
|
||||
return CompletionNodeContext.ElementTag;
|
||||
|
|
|
@ -12,7 +12,7 @@ import {DirectiveSymbol, SymbolKind, TemplateTypeChecker, TypeCheckingProgramStr
|
|||
import {ExpressionIdentifier, hasExpressionIdentifier} from '@angular/compiler-cli/src/ngtsc/typecheck/src/comments';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {getTargetAtPosition} from './template_target';
|
||||
import {getTargetAtPosition, TargetNodeKind} from './template_target';
|
||||
import {findTightestNode} from './ts_utils';
|
||||
import {getDirectiveMatchesForAttribute, getDirectiveMatchesForElementTag, getTemplateInfoAtPosition, isWithin, TemplateInfo, toTextSpan} from './utils';
|
||||
|
||||
|
@ -39,7 +39,9 @@ export class ReferenceBuilder {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const node = positionDetails.nodeInContext.node;
|
||||
const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
|
||||
positionDetails.context.nodes[0] :
|
||||
positionDetails.context.node;
|
||||
|
||||
// Get the information about the TCB at the template position.
|
||||
const symbol = this.ttc.getSymbolOfNode(node, component);
|
||||
|
@ -74,13 +76,12 @@ export class ReferenceBuilder {
|
|||
case SymbolKind.Variable: {
|
||||
const {positionInShimFile: initializerPosition, shimPath} = symbol.initializerLocation;
|
||||
const localVarPosition = symbol.localVarLocation.positionInShimFile;
|
||||
const templateNode = positionDetails.nodeInContext.node;
|
||||
|
||||
if ((templateNode instanceof TmplAstVariable)) {
|
||||
if (templateNode.valueSpan !== undefined && isWithin(position, templateNode.valueSpan)) {
|
||||
if ((node instanceof TmplAstVariable)) {
|
||||
if (node.valueSpan !== undefined && isWithin(position, node.valueSpan)) {
|
||||
// In the valueSpan of the variable, we want to get the reference of the initializer.
|
||||
return this.getReferencesAtTypescriptPosition(shimPath, initializerPosition);
|
||||
} else if (isWithin(position, templateNode.keySpan)) {
|
||||
} else if (isWithin(position, node.keySpan)) {
|
||||
// In the keySpan of the variable, we want to get the reference of the local variable.
|
||||
return this.getReferencesAtTypescriptPosition(shimPath, localVarPosition);
|
||||
} else {
|
||||
|
|
|
@ -10,7 +10,7 @@ import {ParseSpan, TmplAstBoundEvent} from '@angular/compiler';
|
|||
import * as e from '@angular/compiler/src/expression_parser/ast'; // e for expression AST
|
||||
import * as t from '@angular/compiler/src/render3/r3_ast'; // t for template AST
|
||||
|
||||
import {isTemplateNode, isTemplateNodeWithKeyAndValue, isWithin, isWithinKeyValue} from './utils';
|
||||
import {isTemplateNodeWithKeyAndValue, isWithin, isWithinKeyValue} from './utils';
|
||||
|
||||
/**
|
||||
* Contextual information for a target position within the template.
|
||||
|
@ -22,9 +22,9 @@ export interface TemplateTarget {
|
|||
position: number;
|
||||
|
||||
/**
|
||||
* The template node (or AST expression) closest to the search position.
|
||||
* The template (or AST expression) node or nodes closest to the search position.
|
||||
*/
|
||||
nodeInContext: TargetNode;
|
||||
context: TargetContext;
|
||||
|
||||
/**
|
||||
* The `t.Template` which contains the found node or expression (or `null` if in the root
|
||||
|
@ -39,15 +39,26 @@ export interface TemplateTarget {
|
|||
}
|
||||
|
||||
/**
|
||||
* A node targeted at a given position in the template, including potential contextual information
|
||||
* about the specific aspect of the node being referenced.
|
||||
* A node or nodes targeted at a given position in the template, including potential contextual
|
||||
* information about the specific aspect of the node being referenced.
|
||||
*
|
||||
* Some nodes have multiple interior contexts. For example, `t.Element` nodes have both a tag name
|
||||
* as well as a body, and a given position definitively points to one or the other. `TargetNode`
|
||||
* captures the node itself, as well as this additional contextual disambiguation.
|
||||
*/
|
||||
export type TargetNode = RawExpression|RawTemplateNode|ElementInBodyContext|ElementInTagContext|
|
||||
AttributeInKeyContext|AttributeInValueContext;
|
||||
export type TargetContext = SingleNodeTarget|MultiNodeTarget;
|
||||
|
||||
/** Contexts which logically target only a single node in the template AST. */
|
||||
export type SingleNodeTarget = RawExpression|RawTemplateNode|ElementInBodyContext|
|
||||
ElementInTagContext|AttributeInKeyContext|AttributeInValueContext;
|
||||
|
||||
/**
|
||||
* Contexts which logically target multiple nodes in the template AST, which cannot be
|
||||
* disambiguated given a single position because they are all equally relavent. For example, in the
|
||||
* banana-in-a-box syntax `[(ngModel)]="formValues.person"`, the position in the template for the
|
||||
* key `ngModel` refers to both the bound event `ngModelChange` and the input `ngModel`.
|
||||
*/
|
||||
export type MultiNodeTarget = TwoWayBindingContext;
|
||||
|
||||
/**
|
||||
* Differentiates the various kinds of `TargetNode`s.
|
||||
|
@ -59,6 +70,7 @@ export enum TargetNodeKind {
|
|||
ElementInBodyContext,
|
||||
AttributeInKeyContext,
|
||||
AttributeInValueContext,
|
||||
TwoWayBindingContext,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,6 +117,15 @@ export interface AttributeInValueContext {
|
|||
node: t.TextAttribute|t.BoundAttribute|t.BoundEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* A `t.BoundAttribute` and `t.BoundEvent` pair that are targeted, where the given position is
|
||||
* within the key span of both.
|
||||
*/
|
||||
export interface TwoWayBindingContext {
|
||||
kind: TargetNodeKind.TwoWayBindingContext;
|
||||
nodes: [t.BoundAttribute, t.BoundEvent];
|
||||
}
|
||||
|
||||
/**
|
||||
* This special marker is added to the path when the cursor is within the sourceSpan but not the key
|
||||
* or value span of a node with key/value spans.
|
||||
|
@ -141,7 +162,7 @@ export function getTargetAtPosition(template: t.Node[], position: number): Templ
|
|||
}
|
||||
|
||||
// Given the candidate node, determine the full targeted context.
|
||||
let nodeInContext: TargetNode;
|
||||
let nodeInContext: TargetContext;
|
||||
if (candidate instanceof e.AST) {
|
||||
nodeInContext = {
|
||||
kind: TargetNodeKind.RawExpression,
|
||||
|
@ -188,7 +209,7 @@ export function getTargetAtPosition(template: t.Node[], position: number): Templ
|
|||
};
|
||||
}
|
||||
|
||||
return {position, nodeInContext, template: context, parent};
|
||||
return {position, context: nodeInContext, template: context, parent};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,7 +10,7 @@ import {ParseError, parseTemplate} from '@angular/compiler';
|
|||
import * as e from '@angular/compiler/src/expression_parser/ast'; // e for expression AST
|
||||
import * as t from '@angular/compiler/src/render3/r3_ast'; // t for template AST
|
||||
|
||||
import {getTargetAtPosition, TargetNodeKind} from '../../template_target';
|
||||
import {getTargetAtPosition, SingleNodeTarget, TargetNodeKind} from '../../template_target';
|
||||
import {isExpressionNode, isTemplateNode} from '../../utils';
|
||||
|
||||
interface ParseResult {
|
||||
|
@ -36,8 +36,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate element in opening tag', () => {
|
||||
const {errors, nodes, position} = parse(`<di¦v></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Element);
|
||||
});
|
||||
|
@ -45,8 +45,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate element in closing tag', () => {
|
||||
const {errors, nodes, position} = parse(`<div></di¦v>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Element);
|
||||
});
|
||||
|
@ -54,8 +54,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate element when cursor is at the beginning', () => {
|
||||
const {errors, nodes, position} = parse(`<¦div></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Element);
|
||||
});
|
||||
|
@ -63,8 +63,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate element when cursor is at the end', () => {
|
||||
const {errors, nodes, position} = parse(`<div¦></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Element);
|
||||
});
|
||||
|
@ -72,8 +72,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate attribute key', () => {
|
||||
const {errors, nodes, position} = parse(`<div cla¦ss="foo"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.TextAttribute);
|
||||
});
|
||||
|
@ -81,8 +81,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate attribute value', () => {
|
||||
const {errors, nodes, position} = parse(`<div class="fo¦o"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
// TODO: Note that we do not have the ability to detect the RHS (yet)
|
||||
expect(node).toBeInstanceOf(t.TextAttribute);
|
||||
|
@ -91,8 +91,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate bound attribute key', () => {
|
||||
const {errors, nodes, position} = parse(`<test-cmp [fo¦o]="bar"></test-cmp>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
});
|
||||
|
@ -100,8 +100,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate bound attribute value', () => {
|
||||
const {errors, nodes, position} = parse(`<test-cmp [foo]="b¦ar"></test-cmp>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
});
|
||||
|
@ -116,8 +116,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate bound event key', () => {
|
||||
const {errors, nodes, position} = parse(`<test-cmp (fo¦o)="bar()"></test-cmp>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundEvent);
|
||||
});
|
||||
|
@ -125,8 +125,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate bound event value', () => {
|
||||
const {errors, nodes, position} = parse(`<test-cmp (foo)="b¦ar()"></test-cmp>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.MethodCall);
|
||||
});
|
||||
|
@ -134,8 +134,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate element children', () => {
|
||||
const {errors, nodes, position} = parse(`<div><sp¦an></span></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Element);
|
||||
expect((node as t.Element).name).toBe('span');
|
||||
|
@ -144,8 +144,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate element reference', () => {
|
||||
const {errors, nodes, position} = parse(`<div #my¦div></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Reference);
|
||||
});
|
||||
|
@ -153,8 +153,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template text attribute', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template ng¦If></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.TextAttribute);
|
||||
});
|
||||
|
@ -162,8 +162,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template bound attribute key', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template [ng¦If]="foo"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
});
|
||||
|
@ -171,8 +171,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template bound attribute value', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template [ngIf]="f¦oo"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
});
|
||||
|
@ -180,8 +180,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template bound attribute key in two-way binding', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template [(f¦oo)]="bar"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
expect((node as t.BoundAttribute).name).toBe('foo');
|
||||
|
@ -190,8 +190,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template bound attribute value in two-way binding', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template [(foo)]="b¦ar"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('bar');
|
||||
|
@ -200,8 +200,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template bound event key', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template (cl¦ick)="foo()"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundEvent);
|
||||
});
|
||||
|
@ -209,16 +209,16 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template bound event value', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template (click)="f¦oo()"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(node).toBeInstanceOf(e.MethodCall);
|
||||
});
|
||||
|
||||
it('should locate template attribute key', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template i¦d="foo"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.TextAttribute);
|
||||
});
|
||||
|
@ -226,8 +226,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template attribute value', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template id="f¦oo"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
// TODO: Note that we do not have the ability to detect the RHS (yet)
|
||||
expect(node).toBeInstanceOf(t.TextAttribute);
|
||||
|
@ -236,8 +236,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template reference key via the # notation', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template #f¦oo></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Reference);
|
||||
expect((node as t.Reference).name).toBe('foo');
|
||||
|
@ -246,8 +246,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template reference key via the ref- notation', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template ref-fo¦o></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Reference);
|
||||
expect((node as t.Reference).name).toBe('foo');
|
||||
|
@ -256,8 +256,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template reference value via the # notation', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template #foo="export¦As"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Reference);
|
||||
expect((node as t.Reference).value).toBe('exportAs');
|
||||
|
@ -267,8 +267,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template reference value via the ref- notation', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template ref-foo="export¦As"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Reference);
|
||||
expect((node as t.Reference).value).toBe('exportAs');
|
||||
|
@ -278,8 +278,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template variable key', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template let-f¦oo="bar"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Variable);
|
||||
});
|
||||
|
@ -287,8 +287,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template variable value', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template let-foo="b¦ar"></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Variable);
|
||||
});
|
||||
|
@ -296,8 +296,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate template children', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-template><d¦iv></div></ng-template>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Element);
|
||||
});
|
||||
|
@ -305,8 +305,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate ng-content', () => {
|
||||
const {errors, nodes, position} = parse(`<ng-co¦ntent></ng-content>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Content);
|
||||
});
|
||||
|
@ -314,8 +314,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate ng-content attribute key', () => {
|
||||
const {errors, nodes, position} = parse('<ng-content cla¦ss="red"></ng-content>');
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.TextAttribute);
|
||||
});
|
||||
|
@ -323,8 +323,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate ng-content attribute value', () => {
|
||||
const {errors, nodes, position} = parse('<ng-content class="r¦ed"></ng-content>');
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
// TODO: Note that we do not have the ability to detect the RHS (yet)
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.TextAttribute);
|
||||
|
@ -333,8 +333,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should not locate implicit receiver', () => {
|
||||
const {errors, nodes, position} = parse(`<div [foo]="¦bar"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
});
|
||||
|
@ -342,8 +342,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate bound attribute key in two-way binding', () => {
|
||||
const {errors, nodes, position} = parse(`<cmp [(f¦oo)]="bar"></cmp>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
expect((node as t.BoundAttribute).name).toBe('foo');
|
||||
|
@ -352,8 +352,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate bound attribute value in two-way binding', () => {
|
||||
const {errors, nodes, position} = parse(`<cmp [(foo)]="b¦ar"></cmp>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('bar');
|
||||
|
@ -362,8 +362,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
it('should locate switch value in ICUs', () => {
|
||||
const {errors, nodes, position} = parse(`<span i18n>{sw¦itch, plural, other {text}}"></span>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('switch');
|
||||
|
@ -373,8 +373,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
const {errors, nodes, position} = parse(
|
||||
`<span i18n>{expr, plural, other { {ne¦sted, plural, =1 { {{nestedInterpolation}} }} }}"></span>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('nested');
|
||||
|
@ -384,8 +384,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
const {errors, nodes, position} =
|
||||
parse(`<span i18n>{expr, plural, other { {{ i¦nterpolation }} }}"></span>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('interpolation');
|
||||
|
@ -395,8 +395,8 @@ describe('getTargetAtPosition for template AST', () => {
|
|||
const {errors, nodes, position} = parse(
|
||||
`<span i18n>{expr, plural, other { {nested, plural, =1 { {{n¦estedInterpolation}} }} }}"></span>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('nestedInterpolation');
|
||||
|
@ -407,8 +407,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should not locate implicit receiver', () => {
|
||||
const {errors, nodes, position} = parse(`{{ ¦title }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('title');
|
||||
|
@ -417,8 +417,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate property read', () => {
|
||||
const {errors, nodes, position} = parse(`{{ ti¦tle }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('title');
|
||||
|
@ -427,8 +427,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate safe property read', () => {
|
||||
const {errors, nodes, position} = parse(`{{ foo?¦.bar }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.SafePropertyRead);
|
||||
expect((node as e.SafePropertyRead).name).toBe('bar');
|
||||
|
@ -437,8 +437,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate keyed read', () => {
|
||||
const {errors, nodes, position} = parse(`{{ foo['bar']¦ }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.KeyedRead);
|
||||
});
|
||||
|
@ -446,8 +446,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate property write', () => {
|
||||
const {errors, nodes, position} = parse(`<div (foo)="b¦ar=$event"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyWrite);
|
||||
});
|
||||
|
@ -455,8 +455,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate keyed write', () => {
|
||||
const {errors, nodes, position} = parse(`<div (foo)="bar['baz']¦=$event"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.KeyedWrite);
|
||||
});
|
||||
|
@ -464,8 +464,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate binary', () => {
|
||||
const {errors, nodes, position} = parse(`{{ 1 +¦ 2 }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.Binary);
|
||||
});
|
||||
|
@ -473,8 +473,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate binding pipe with an identifier', () => {
|
||||
const {errors, nodes, position} = parse(`{{ title | p¦ }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.BindingPipe);
|
||||
});
|
||||
|
@ -485,8 +485,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
expect(errors![0].toString())
|
||||
.toContain(
|
||||
'Unexpected end of input, expected identifier or keyword at the end of the expression');
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
// TODO: We want this to be a BindingPipe.
|
||||
expect(node).toBeInstanceOf(e.Interpolation);
|
||||
|
@ -498,7 +498,7 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
// parser throws an error. This case is important for autocomplete.
|
||||
// const {errors, nodes, position} = parse(`{{ title | ¦ }}`);
|
||||
// expect(errors).toBe(null);
|
||||
// const {nodeInContext} = findNodeAtPosition(nodes, position)!;
|
||||
// const {context} = findNodeAtPosition(nodes, position)!;
|
||||
// expect(isExpressionNode(node!)).toBe(true);
|
||||
// expect(node).toBeInstanceOf(e.BindingPipe);
|
||||
});
|
||||
|
@ -507,8 +507,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate method call', () => {
|
||||
const {errors, nodes, position} = parse(`{{ title.toString(¦) }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.MethodCall);
|
||||
});
|
||||
|
@ -516,8 +516,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate safe method call', () => {
|
||||
const {errors, nodes, position} = parse(`{{ title?.toString(¦) }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.SafeMethodCall);
|
||||
});
|
||||
|
@ -525,8 +525,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate literal primitive in interpolation', () => {
|
||||
const {errors, nodes, position} = parse(`{{ title.indexOf('t¦') }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.LiteralPrimitive);
|
||||
expect((node as e.LiteralPrimitive).value).toBe('t');
|
||||
|
@ -535,8 +535,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate literal primitive in binding', () => {
|
||||
const {errors, nodes, position} = parse(`<div [id]="'t¦'"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.LiteralPrimitive);
|
||||
expect((node as e.LiteralPrimitive).value).toBe('t');
|
||||
|
@ -545,8 +545,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate empty expression', () => {
|
||||
const {errors, nodes, position} = parse(`<div [id]="¦"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.EmptyExpr);
|
||||
});
|
||||
|
@ -554,8 +554,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate literal array', () => {
|
||||
const {errors, nodes, position} = parse(`{{ [1, 2,¦ 3] }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.LiteralArray);
|
||||
});
|
||||
|
@ -563,8 +563,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate literal map', () => {
|
||||
const {errors, nodes, position} = parse(`{{ { hello:¦ "world" } }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.LiteralMap);
|
||||
});
|
||||
|
@ -572,8 +572,8 @@ describe('getTargetAtPosition for expression AST', () => {
|
|||
it('should locate conditional', () => {
|
||||
const {errors, nodes, position} = parse(`{{ cond ?¦ true : false }}`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.Conditional);
|
||||
});
|
||||
|
@ -583,8 +583,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate template key', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ng¦If="foo"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
});
|
||||
|
@ -592,8 +592,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate template value', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ngIf="f¦oo"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
});
|
||||
|
@ -601,8 +601,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate property read next to variable in structural directive syntax', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ngIf="fo¦o as bar"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
});
|
||||
|
@ -612,8 +612,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
// ngFor is a text attribute because the desugared form is
|
||||
// <ng-template ngFor let-item [ngForOf]="items">
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBeTrue();
|
||||
expect(node).toBeInstanceOf(t.TextAttribute);
|
||||
expect((node as t.TextAttribute).name).toBe('ngFor');
|
||||
|
@ -629,8 +629,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate let variable', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ngFor="let i¦tem of items"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Variable);
|
||||
expect((node as t.Variable).name).toBe('item');
|
||||
|
@ -639,8 +639,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate bound attribute key', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ngFor="let item o¦f items"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
expect((node as t.BoundAttribute).name).toBe('ngForOf');
|
||||
|
@ -649,8 +649,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate bound attribute key when cursor is at the start', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ngFor="let item ¦of items"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const node = nodeInContext.node;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const node = (context as SingleNodeTarget).node;
|
||||
expect(isTemplateNode(node)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
expect((node as t.BoundAttribute).name).toBe('ngForOf');
|
||||
|
@ -660,8 +660,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
const {errors, nodes, position} =
|
||||
parse(`<div *ngFor="let item of items; trac¦kBy: trackByFn"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
expect((node as t.BoundAttribute).name).toBe('ngForTrackBy');
|
||||
|
@ -674,8 +674,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
const {errors, nodes, position} =
|
||||
parse(`<div *ngFor="let item o¦f items; trackBy: trackByFn"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.BoundAttribute);
|
||||
expect((node as t.BoundAttribute).name).toBe('ngForOf');
|
||||
|
@ -684,8 +684,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate bound attribute value', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ngFor="let item of it¦ems"></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
expect((node as e.PropertyRead).name).toBe('items');
|
||||
|
@ -694,12 +694,12 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate template children', () => {
|
||||
const {errors, nodes, position} = parse(`<di¦v *ngIf></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext, template: context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context, template} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Element);
|
||||
expect((node as t.Element).name).toBe('div');
|
||||
expect(context).toBeInstanceOf(t.Template);
|
||||
expect(template).toBeInstanceOf(t.Template);
|
||||
});
|
||||
|
||||
it('should locate property read of variable declared within template', () => {
|
||||
|
@ -708,8 +708,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
{{ i¦ }}
|
||||
</div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isExpressionNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(e.PropertyRead);
|
||||
});
|
||||
|
@ -717,8 +717,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate LHS of variable declaration', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ngFor="let item of items; let i¦=index">`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Variable);
|
||||
// TODO: Currently there is no way to distinguish LHS from RHS
|
||||
|
@ -728,8 +728,8 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate RHS of variable declaration', () => {
|
||||
const {errors, nodes, position} = parse(`<div *ngFor="let item of items; let i=in¦dex">`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = nodeInContext;
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
const {node} = context as SingleNodeTarget;
|
||||
expect(isTemplateNode(node!)).toBe(true);
|
||||
expect(node).toBeInstanceOf(t.Variable);
|
||||
// TODO: Currently there is no way to distinguish LHS from RHS
|
||||
|
@ -739,16 +739,16 @@ describe('findNodeAtPosition for microsyntax expression', () => {
|
|||
it('should locate an element in its tag context', () => {
|
||||
const {errors, nodes, position} = parse(`<div¦ attr></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
expect(nodeInContext.kind).toBe(TargetNodeKind.ElementInTagContext);
|
||||
expect(nodeInContext.node).toBeInstanceOf(t.Element);
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
expect(context.kind).toBe(TargetNodeKind.ElementInTagContext);
|
||||
expect((context as SingleNodeTarget).node).toBeInstanceOf(t.Element);
|
||||
});
|
||||
|
||||
it('should locate an element in its body context', () => {
|
||||
const {errors, nodes, position} = parse(`<div ¦ attr></div>`);
|
||||
expect(errors).toBe(null);
|
||||
const {nodeInContext} = getTargetAtPosition(nodes, position)!;
|
||||
expect(nodeInContext.kind).toBe(TargetNodeKind.ElementInBodyContext);
|
||||
expect(nodeInContext.node).toBeInstanceOf(t.Element);
|
||||
const {context} = getTargetAtPosition(nodes, position)!;
|
||||
expect(context.kind).toBe(TargetNodeKind.ElementInBodyContext);
|
||||
expect((context as SingleNodeTarget).node).toBeInstanceOf(t.Element);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue