From 6e5fb99304c12d847a0cfcd93da4b54394d28830 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Thu, 29 Mar 2018 16:41:45 -0700 Subject: [PATCH] refactor(ivy): flatten css selectors (#23074) PR Close #23074 --- .../src/largetable/render3/table.ts | 2 +- modules/benchmarks/src/tree/render3/tree.ts | 4 +- .../core/src/core_render3_private_export.ts | 2 +- packages/core/src/render3/component.ts | 4 +- packages/core/src/render3/definition.ts | 12 +- packages/core/src/render3/index.ts | 2 +- packages/core/src/render3/instructions.ts | 8 +- .../core/src/render3/interfaces/definition.ts | 6 +- .../core/src/render3/interfaces/projection.ts | 68 +++- .../core/src/render3/node_selector_matcher.ts | 121 +++--- packages/core/test/render3/basic_perf.ts | 2 +- .../test/render3/change_detection_spec.ts | 38 +- .../test/render3/common_integration_spec.ts | 2 +- packages/core/test/render3/common_with_def.ts | 2 +- .../component_directives_spec.ts | 54 +-- .../content_projection_spec.ts | 10 +- .../compiler_canonical/elements_spec.ts | 20 +- .../compiler_canonical/injection_spec.ts | 12 +- .../compiler_canonical/life_cycle_spec.ts | 4 +- .../local_reference_spec.ts | 2 +- .../render3/compiler_canonical/pipes_spec.ts | 6 +- .../render3/compiler_canonical/query_spec.ts | 8 +- .../compiler_canonical/sanitize_spec.ts | 4 +- .../compiler_canonical/small_app_spec.ts | 4 +- .../template_variables_spec.ts | 6 +- packages/core/test/render3/component_spec.ts | 16 +- packages/core/test/render3/content_spec.ts | 32 +- .../core/test/render3/control_flow_spec.ts | 8 +- packages/core/test/render3/define_spec.ts | 2 +- packages/core/test/render3/di_spec.ts | 42 +- packages/core/test/render3/directive_spec.ts | 2 +- packages/core/test/render3/exports_spec.ts | 14 +- .../core/test/render3/integration_spec.ts | 14 +- packages/core/test/render3/lifecycle_spec.ts | 26 +- packages/core/test/render3/listeners_spec.ts | 6 +- .../render3/node_selector_matcher_spec.ts | 371 ++++++++++++++---- packages/core/test/render3/outputs_spec.ts | 10 +- packages/core/test/render3/pipe_spec.ts | 2 +- packages/core/test/render3/properties_spec.ts | 18 +- .../core/test/render3/pure_function_spec.ts | 8 +- packages/core/test/render3/query_spec.ts | 2 +- packages/core/test/render3/render_util.ts | 4 +- .../test/render3/renderer_factory_spec.ts | 8 +- .../test/render3/view_container_ref_spec.ts | 4 +- 44 files changed, 631 insertions(+), 361 deletions(-) diff --git a/modules/benchmarks/src/largetable/render3/table.ts b/modules/benchmarks/src/largetable/render3/table.ts index 15cac6a3be..71d62c8a06 100644 --- a/modules/benchmarks/src/largetable/render3/table.ts +++ b/modules/benchmarks/src/largetable/render3/table.ts @@ -17,7 +17,7 @@ export class LargeTableComponent { /** @nocollapse */ static ngComponentDef: ComponentDef = defineComponent({ type: LargeTableComponent, - selector: [[['largetable'], null]], + selectors: [['largetable']], template: function(ctx: LargeTableComponent, cm: boolean) { if (cm) { E(0, 'table'); diff --git a/modules/benchmarks/src/tree/render3/tree.ts b/modules/benchmarks/src/tree/render3/tree.ts index 74c3e5aeaa..1fe8a8aae9 100644 --- a/modules/benchmarks/src/tree/render3/tree.ts +++ b/modules/benchmarks/src/tree/render3/tree.ts @@ -37,7 +37,7 @@ export class TreeComponent { /** @nocollapse */ static ngComponentDef: ComponentDef = defineComponent({ type: TreeComponent, - selector: [[['tree'], null]], + selectors: [['tree']], template: function(ctx: TreeComponent, cm: boolean) { if (cm) { E(0, 'span'); @@ -91,7 +91,7 @@ export class TreeFunction { /** @nocollapse */ static ngComponentDef: ComponentDef = defineComponent({ type: TreeFunction, - selector: [[['tree'], null]], + selectors: [['tree']], template: function(ctx: TreeFunction, cm: boolean) { // bit of a hack TreeTpl(ctx.data, cm); diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 7bb70270f9..37d7778484 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -22,7 +22,7 @@ export { InjectFlags as ɵInjectFlags, PublicFeature as ɵPublicFeature, NgOnChangesFeature as ɵNgOnChangesFeature, - CssSelector as ɵCssSelector, + CssSelectorList as ɵCssSelectorList, NC as ɵNC, C as ɵC, E as ɵE, diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index e46334d35f..f4c654c0fa 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -123,8 +123,8 @@ export function renderComponent( const componentDef = (componentType as ComponentType).ngComponentDef as ComponentDef; if (componentDef.type != componentType) componentDef.type = componentType; let component: T; - // TODO: Replace when flattening CssSelector type - const componentTag = componentDef.selector ![0] ![0] ![0]; + // The first index of the first selector is the tag name. + const componentTag = componentDef.selectors ![0] ![0] as string; const hostNode = locateHostElement(rendererFactory, opts.host || componentTag); const rootContext: RootContext = { // Incomplete initialization due to circular reference. diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index fd8d317238..67f954a548 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -17,7 +17,7 @@ import {resolveRendererType2} from '../view/util'; import {diPublic} from './di'; import {ComponentDef, ComponentDefFeature, ComponentTemplate, DirectiveDef, DirectiveDefFeature, DirectiveDefListOrFactory, PipeDef, PipeDefListOrFactory} from './interfaces/definition'; -import {CssSelector} from './interfaces/projection'; +import {CssSelectorList, SelectorFlags} from './interfaces/projection'; @@ -42,8 +42,8 @@ export function defineComponent(componentDefinition: { */ type: Type; - /** The selector that will be used to match nodes to this component. */ - selector: CssSelector; + /** The selectors that will be used to match nodes to this component. */ + selectors: CssSelectorList; /** * Factory method used to create an instance of directive. @@ -185,7 +185,7 @@ export function defineComponent(componentDefinition: { onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush, directiveDefs: componentDefinition.directiveDefs || null, pipeDefs: componentDefinition.pipeDefs || null, - selector: componentDefinition.selector + selectors: componentDefinition.selectors }; const feature = componentDefinition.features; feature && feature.forEach((fn) => fn(def)); @@ -317,8 +317,8 @@ export const defineDirective = defineComponent as any as(directiveDefinition: */ type: Type; - /** The selector that will be used to match nodes to this directive. */ - selector: CssSelector; + /** The selectors that will be used to match nodes to this directive. */ + selectors: CssSelectorList; /** * Factory method used to create an instance of directive. diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 8965327282..4e6c238fb7 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -12,7 +12,7 @@ import {InjectFlags} from './di'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType} from './interfaces/definition'; export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di'; -export {CssSelector} from './interfaces/projection'; +export {CssSelectorList} from './interfaces/projection'; diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 892218749a..55dcfebb69 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -11,14 +11,14 @@ import './ng_dev_mode'; import {assertEqual, assertLessThan, assertNotEqual, assertNotNull, assertNull, assertSame} from './assert'; import {LContainer, TContainer} from './interfaces/container'; import {LInjector} from './interfaces/injector'; -import {CssSelector, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection'; +import {CssSelectorList, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection'; import {LQueries} from './interfaces/query'; import {LView, LViewFlags, LifecycleStage, RootContext, TData, TView} from './interfaces/view'; import {LContainerNode, LElementNode, LNode, LNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './interfaces/node'; import {assertNodeType} from './node_assert'; import {appendChild, insertChild, insertView, appendProjectedNode, removeView, canInsertNativeNode} from './node_manipulation'; -import {isNodeMatchingSelector, matchingSelectorIndex} from './node_selector_matcher'; +import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, DirectiveType, PipeDef, PipeDefListOrFactory} from './interfaces/definition'; import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer'; import {isDifferent, stringify} from './util'; @@ -532,7 +532,7 @@ function cacheMatchingDirectivesForNode(tNode: TNode): void { for (let i = 0; i < registry.length; i++) { const def = registry[i]; - if (isNodeMatchingSelector(tNode, def.selector !)) { + if (isNodeMatchingSelectorList(tNode, def.selectors !)) { if ((def as ComponentDef).template) { if (componentFlag) throwMultipleComponentError(tNode); componentFlag |= TNodeFlags.Component; @@ -1567,7 +1567,7 @@ function viewAttached(view: LView): boolean { * @param rawSelectors A collection of CSS selectors in the raw, un-parsed form */ export function projectionDef( - index: number, selectors?: CssSelector[], textSelectors?: string[]): void { + index: number, selectors?: CssSelectorList[], textSelectors?: string[]): void { const noOfNodeBuckets = selectors ? selectors.length + 1 : 1; const distributedNodes = new Array(noOfNodeBuckets); for (let i = 0; i < noOfNodeBuckets; i++) { diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index 5c864f3024..ad6689ef39 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -12,7 +12,7 @@ import {Provider} from '../../core'; import {RendererType2} from '../../render/api'; import {Type} from '../../type'; import {resolveRendererType2} from '../../view/util'; -import {CssSelector} from './projection'; +import {CssSelectorList} from './projection'; /** @@ -61,8 +61,8 @@ export interface DirectiveDef { /** Function that makes a directive public to the DI system. */ diPublic: ((def: DirectiveDef) => void)|null; - /** The selector that will be used to match nodes to this directive. */ - selector: CssSelector; + /** The selectors that will be used to match nodes to this directive. */ + selectors: CssSelectorList; /** * A dictionary mapping the inputs' minified property names to their public API names, which diff --git a/packages/core/src/render3/interfaces/projection.ts b/packages/core/src/render3/interfaces/projection.ts index 37d5c3ef96..dce0453813 100644 --- a/packages/core/src/render3/interfaces/projection.ts +++ b/packages/core/src/render3/interfaces/projection.ts @@ -17,33 +17,61 @@ export interface LProjection { } /** - * Parsed selector in the following format: - * [tagName, attr1Name, attr1Val, ..., attrnName, attrnValue, 'class', className1, className2, ..., - * classNameN] + * Expresses a single CSS Selector. * - * * For example, given the following selector: - * `div.foo.bar[attr1=val1][attr2]` a parsed format would be: - * `['div', 'attr1', 'val1', 'attr2', '', 'class', 'foo', 'bar']`. + * Beginning of array + * - First index: element name + * - Subsequent odd indices: attr keys + * - Subsequent even indices: attr values * - * Things to notice: - * - tag name is always at the position 0 - * - the `class` attribute is always the last attribute in a pre-parsed array - * - class names in a selector are at the end of an array (after the attribute with the name - * 'class'). + * After SelectorFlags.CLASS flag + * - Class name values + * + * SelectorFlags.NOT flag + * - Changes the mode to NOT + * - Can be combined with other flags to set the element / attr / class mode + * + * e.g. SelectorFlags.NOT | SelectorFlags.ELEMENT + * + * Example: + * Original: `div.foo.bar[attr1=val1][attr2]` + * Parsed: ['div', 'attr1', 'val1', 'attr2', '', SelectorFlags.CLASS, 'foo', 'bar'] + * + * Original: 'div[attr1]:not(.foo[attr2]) + * Parsed: [ + * 'div', 'attr1', '', + * SelectorFlags.NOT | SelectorFlags.ATTRIBUTE 'attr2', '', SelectorFlags.CLASS, 'foo' + * ] + * + * See more examples in node_selector_matcher_spec.ts */ -export type SimpleCssSelector = string[]; +export type CssSelector = (string | SelectorFlags)[]; /** - * A complex selector expressed as an Array where: - * - element at index 0 is a selector (SimpleCSSSelector) to match - * - elements at index 1..n is a selector (SimpleCSSSelector) that should NOT match + * A list of CssSelectors. + * + * A directive or component can have multiple selectors. This type is used for + * directive defs so any of the selectors in the list will match that directive. + * + * Original: 'form, [ngForm]' + * Parsed: [['form'], ['', 'ngForm', '']] */ -export type CssSelectorWithNegations = [SimpleCssSelector | null, SimpleCssSelector[] | null]; +export type CssSelectorList = CssSelector[]; -/** - * A collection of complex selectors (CSSSelectorWithNegations) in a parsed form - */ -export type CssSelector = CssSelectorWithNegations[]; +/** Flags used to build up CssSelectors */ +export const enum SelectorFlags { + /** Indicates this is the beginning of a new negative selector */ + NOT = 0b0001, + + /** Mode for matching attributes */ + ATTRIBUTE = 0b0010, + + /** Mode for matching tag names */ + ELEMENT = 0b0100, + + /** Mode for matching class names */ + CLASS = 0b1000, +} export const NG_PROJECT_AS_ATTR_NAME = 'ngProjectAs'; diff --git a/packages/core/src/render3/node_selector_matcher.ts b/packages/core/src/render3/node_selector_matcher.ts index 51b0a7974f..e92e3f287d 100644 --- a/packages/core/src/render3/node_selector_matcher.ts +++ b/packages/core/src/render3/node_selector_matcher.ts @@ -10,7 +10,7 @@ import './ng_dev_mode'; import {assertNotNull} from './assert'; import {TNode, unusedValueExportToPlacateAjd as unused1} from './interfaces/node'; -import {CssSelector, CssSelectorWithNegations, NG_PROJECT_AS_ATTR_NAME, SimpleCssSelector, unusedValueExportToPlacateAjd as unused2} from './interfaces/projection'; +import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags, unusedValueExportToPlacateAjd as unused2} from './interfaces/projection'; const unusedValueToPlacateAjd = unused1 + unused2; @@ -35,79 +35,80 @@ function isCssClassMatching(nodeClassAttrVal: string, cssClassToMatch: string): * @param selector * @returns true if node matches the selector. */ -export function isNodeMatchingSimpleSelector(tNode: TNode, selector: SimpleCssSelector): boolean { - const noOfSelectorParts = selector.length; - ngDevMode && assertNotNull(selector[0], 'the selector should have a tag name'); - const tagNameInSelector = selector[0]; +export function isNodeMatchingSelector(tNode: TNode, selector: CssSelector): boolean { + ngDevMode && assertNotNull(selector[0], 'Selector should have a tag name'); - // check tag tame - if (tagNameInSelector !== '' && tagNameInSelector !== tNode.tagName) { - return false; - } + let mode: SelectorFlags = SelectorFlags.ELEMENT; + const nodeAttrs = tNode.attrs !; - // short-circuit case where we are only matching on element's tag name - if (noOfSelectorParts === 1) { - return true; - } + // When processing ":not" selectors, we skip to the next ":not" if the + // current one doesn't match + let skipToNextSelector = false; - // short-circuit case where an element has no attrs but a selector tries to match some - if (noOfSelectorParts > 1 && !tNode.attrs) { - return false; - } + for (let i = 0; i < selector.length; i++) { + const current = selector[i]; + if (typeof current === 'number') { + // If we finish processing a :not selector and it hasn't failed, return false + if (!skipToNextSelector && !isPositive(mode) && !isPositive(current as number)) { + return false; + } + // If we are skipping to the next :not() and this mode flag is positive, + // it's a part of the current :not() selector, and we should keep skipping + if (skipToNextSelector && isPositive(current)) continue; + skipToNextSelector = false; + mode = (current as number) | (mode & SelectorFlags.NOT); + continue; + } - const attrsInNode = tNode.attrs !; + if (skipToNextSelector) continue; - for (let i = 1; i < noOfSelectorParts; i += 2) { - const attrNameInSelector = selector[i]; - const attrIdxInNode = attrsInNode.indexOf(attrNameInSelector); - if (attrIdxInNode % 2 !== 0) { // attribute names are stored at even indexes - return false; + if (mode & SelectorFlags.ELEMENT) { + mode = SelectorFlags.ATTRIBUTE | mode & SelectorFlags.NOT; + if (current !== '' && current !== tNode.tagName) { + if (isPositive(mode)) return false; + skipToNextSelector = true; + } } else { - const attrValInSelector = selector[i + 1]; - if (attrValInSelector !== '') { - // selector should also match on an attribute value - const attrValInNode = attrsInNode[attrIdxInNode + 1]; - if (attrNameInSelector === 'class') { - // iterate over all the remaining items in the selector selector array = class names - for (i++; i < noOfSelectorParts; i++) { - if (!isCssClassMatching(attrValInNode, selector[i])) { - return false; - } - } - } else if (attrValInSelector !== attrValInNode) { - return false; + const attrName = mode & SelectorFlags.CLASS ? 'class' : current; + const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs); + + if (attrIndexInNode === -1) { + if (isPositive(mode)) return false; + skipToNextSelector = true; + continue; + } + + const selectorAttrValue = mode & SelectorFlags.CLASS ? current : selector[++i]; + if (selectorAttrValue !== '') { + const nodeAttrValue = nodeAttrs[attrIndexInNode + 1]; + if (mode & SelectorFlags.CLASS && + !isCssClassMatching(nodeAttrValue, selectorAttrValue as string) || + mode & SelectorFlags.ATTRIBUTE && selectorAttrValue !== nodeAttrValue) { + if (isPositive(mode)) return false; + skipToNextSelector = true; } } } } - return true; + return isPositive(mode) || skipToNextSelector; } -export function isNodeMatchingSelectorWithNegations( - tNode: TNode, selector: CssSelectorWithNegations): boolean { - const positiveSelector = selector[0]; - if (positiveSelector != null && !isNodeMatchingSimpleSelector(tNode, positiveSelector)) { - return false; - } - - // do we have any negation parts in this selector? - const negativeSelectors = selector[1]; - if (negativeSelectors) { - for (let i = 0; i < negativeSelectors.length; i++) { - // if one of negative selectors matched than the whole selector doesn't match - if (isNodeMatchingSimpleSelector(tNode, negativeSelectors[i])) { - return false; - } - } - } - - return true; +function isPositive(mode: SelectorFlags): boolean { + return (mode & SelectorFlags.NOT) === 0; } -export function isNodeMatchingSelector(tNode: TNode, selector: CssSelector): boolean { +function findAttrIndexInNode(name: string, attrs: string[] | null): number { + if (attrs === null) return -1; + for (let i = 0; i < attrs.length; i += 2) { + if (attrs[i] === name) return i; + } + return -1; +} + +export function isNodeMatchingSelectorList(tNode: TNode, selector: CssSelectorList): boolean { for (let i = 0; i < selector.length; i++) { - if (isNodeMatchingSelectorWithNegations(tNode, selector[i])) { + if (isNodeMatchingSelector(tNode, selector[i])) { return true; } } @@ -136,13 +137,13 @@ export function getProjectAsAttrValue(tNode: TNode): string|null { * to the raw (un-parsed) CSS selector instead of using standard selector matching logic. */ export function matchingSelectorIndex( - tNode: TNode, selectors: CssSelector[], textSelectors: string[]): number { + tNode: TNode, selectors: CssSelectorList[], textSelectors: string[]): number { const ngProjectAsAttrVal = getProjectAsAttrValue(tNode); for (let i = 0; i < selectors.length; i++) { // if a node has the ngProjectAs attribute match it against unparsed selector // match a node against a parsed selector only if ngProjectAs attribute is not present if (ngProjectAsAttrVal === textSelectors[i] || - ngProjectAsAttrVal === null && isNodeMatchingSelector(tNode, selectors[i])) { + ngProjectAsAttrVal === null && isNodeMatchingSelectorList(tNode, selectors[i])) { return i + 1; // first matching selector "captures" a given node } } diff --git a/packages/core/test/render3/basic_perf.ts b/packages/core/test/render3/basic_perf.ts index 31659ba6ea..7f2613981c 100644 --- a/packages/core/test/render3/basic_perf.ts +++ b/packages/core/test/render3/basic_perf.ts @@ -34,7 +34,7 @@ describe('iv perf test', () => { class Component { static ngComponentDef = defineComponent({ type: Component, - selector: [[['div'], null]], + selectors: [['div']], template: function Template(ctx: any, cm: any) { if (cm) { container(0); diff --git a/packages/core/test/render3/change_detection_spec.ts b/packages/core/test/render3/change_detection_spec.ts index d5da985842..8d55214201 100644 --- a/packages/core/test/render3/change_detection_spec.ts +++ b/packages/core/test/render3/change_detection_spec.ts @@ -25,7 +25,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: MyComponent, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: () => new MyComponent(), template: (ctx: MyComponent, cm: boolean) => { if (cm) { @@ -96,7 +96,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: MyComponent, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: () => comp = new MyComponent(), /** * {{ doCheckCount }} - {{ name }} @@ -123,7 +123,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp(), /** */ template: (ctx: MyApp, cm: boolean) => { @@ -223,7 +223,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: ButtonParent, - selector: [[['button-parent'], null]], + selectors: [['button-parent']], factory: () => parent = new ButtonParent(), /** {{ doCheckCount }} - */ template: (ctx: ButtonParent, cm: boolean) => { @@ -282,7 +282,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: MyComp, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: () => myComp = new MyComp(injectChangeDetectorRef()), /** {{ name }} */ template: (ctx: MyComp, cm: boolean) => { @@ -304,7 +304,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: ParentComp, - selector: [[['parent-comp'], null]], + selectors: [['parent-comp']], factory: () => new ParentComp(injectChangeDetectorRef()), /** * {{ doCheckCount}} - @@ -327,7 +327,7 @@ describe('change detection', () => { static ngDirectiveDef = defineDirective({ type: Dir, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: () => dir = new Dir(injectChangeDetectorRef()) }); } @@ -436,7 +436,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), /** * {{ name}} @@ -487,7 +487,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: DetectChangesComp, - selector: [[['detect-changes-comp'], null]], + selectors: [['detect-changes-comp']], factory: () => new DetectChangesComp(injectChangeDetectorRef()), /** {{ value }} */ template: (ctx: DetectChangesComp, cm: boolean) => { @@ -516,7 +516,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: DetectChangesComp, - selector: [[['detect-changes-comp'], null]], + selectors: [['detect-changes-comp']], factory: () => new DetectChangesComp(injectChangeDetectorRef()), /** {{ doCheckCount }} */ template: (ctx: DetectChangesComp, cm: boolean) => { @@ -542,7 +542,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), /** */ template: (ctx: MyApp, cm: boolean) => { @@ -565,7 +565,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: DetachedComp, - selector: [[['detached-comp'], null]], + selectors: [['detached-comp']], factory: () => comp = new DetachedComp(injectChangeDetectorRef()), /** {{ value }} */ template: (ctx: DetachedComp, cm: boolean) => { @@ -661,7 +661,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: OnPushComp, - selector: [[['on-push-comp'], null]], + selectors: [['on-push-comp']], factory: () => onPushComp = new OnPushComp(injectChangeDetectorRef()), /** {{ value }} */ template: (ctx: OnPushComp, cm: boolean) => { @@ -717,7 +717,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: OnPushComp, - selector: [[['on-push-comp'], null]], + selectors: [['on-push-comp']], factory: () => comp = new OnPushComp(injectChangeDetectorRef()), /** {{ value }} */ template: (ctx: OnPushComp, cm: boolean) => { @@ -735,7 +735,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: OnPushParent, - selector: [[['on-push-parent'], null]], + selectors: [['on-push-parent']], factory: () => new OnPushParent(), /** * {{ value }} - @@ -802,7 +802,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: EmbeddedViewParent, - selector: [[['embedded-view-parent'], null]], + selectors: [['embedded-view-parent']], factory: () => new EmbeddedViewParent(), /** * {{ value }} - @@ -875,7 +875,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: NoChangesComp, - selector: [[['no-changes-comp'], null]], + selectors: [['no-changes-comp']], factory: () => comp = new NoChangesComp(injectChangeDetectorRef()), template: (ctx: NoChangesComp, cm: boolean) => { if (cm) { @@ -893,7 +893,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: AppComp, - selector: [[['app-comp'], null]], + selectors: [['app-comp']], factory: () => new AppComp(injectChangeDetectorRef()), /** * {{ value }} - @@ -953,7 +953,7 @@ describe('change detection', () => { static ngComponentDef = defineComponent({ type: EmbeddedViewApp, - selector: [[['embedded-view-app'], null]], + selectors: [['embedded-view-app']], factory: () => new EmbeddedViewApp(injectChangeDetectorRef()), /** * % if (showing) { diff --git a/packages/core/test/render3/common_integration_spec.ts b/packages/core/test/render3/common_integration_spec.ts index 9960c4ad16..7a2afb5513 100644 --- a/packages/core/test/render3/common_integration_spec.ts +++ b/packages/core/test/render3/common_integration_spec.ts @@ -23,7 +23,7 @@ describe('@angular/common integration', () => { static ngComponentDef = defineComponent({ type: MyApp, factory: () => new MyApp(), - selector: [[['my-app'], null]], + selectors: [['my-app']], //
    //
  • {{item}}
  • //
diff --git a/packages/core/test/render3/common_with_def.ts b/packages/core/test/render3/common_with_def.ts index a4f6685943..9a60669cdb 100644 --- a/packages/core/test/render3/common_with_def.ts +++ b/packages/core/test/render3/common_with_def.ts @@ -16,7 +16,7 @@ export const NgForOf: DirectiveType> = NgForOfDef as any; NgForOf.ngDirectiveDef = defineDirective({ type: NgForOfDef, - selector: [[['', 'ngForOf', ''], null]], + selectors: [['', 'ngForOf', '']], factory: () => new NgForOfDef( injectViewContainerRef(), injectTemplateRef(), directiveInject(IterableDiffers, InjectFlags.Default, defaultIterableDiffers)), diff --git a/packages/core/test/render3/compiler_canonical/component_directives_spec.ts b/packages/core/test/render3/compiler_canonical/component_directives_spec.ts index 8a280ce71e..104d0af439 100644 --- a/packages/core/test/render3/compiler_canonical/component_directives_spec.ts +++ b/packages/core/test/render3/compiler_canonical/component_directives_spec.ts @@ -28,7 +28,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: ChildComponent, - selector: [[['child'], null]], + selectors: [['child']], factory: () => new ChildComponent(), template: function(ctx: $ChildComponent$, cm: $boolean$) { if (cm) { @@ -47,7 +47,7 @@ describe('components & directives', () => { // NORMATIVE static ngDirectiveDef = $r3$.ɵdefineDirective({ type: SomeDirective, - selector: [[['', 'some-directive', ''], null]], + selectors: [['', 'some-directive', '']], factory: () => new SomeDirective(), }); // /NORMATIVE @@ -63,7 +63,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: () => new MyComponent(), template: function(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -95,7 +95,7 @@ describe('components & directives', () => { // NORMATIVE static ngDirectiveDef = $r3$.ɵdefineDirective({ type: HostBindingDir, - selector: [[['', 'hostBindingDir', ''], null]], + selectors: [['', 'hostBindingDir', '']], factory: function HostBindingDir_Factory() { return new HostBindingDir(); }, hostBindings: function HostBindingDir_HostBindings(dirIndex: $number$, elIndex: $number$) { $r3$.ɵp(elIndex, 'id', $r3$.ɵb($r3$.ɵd(dirIndex).dirId)); @@ -115,7 +115,7 @@ describe('components & directives', () => { class MyApp { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -143,7 +143,7 @@ describe('components & directives', () => { // NORMATIVE static ngDirectiveDef = $r3$.ɵdefineDirective({ - selector: [[['', 'hostListenerDir', ''], null]], + selectors: [['', 'hostListenerDir', '']], type: HostListenerDir, factory: function HostListenerDir_Factory() { const $dir$ = new HostListenerDir(); @@ -165,7 +165,7 @@ describe('components & directives', () => { class MyApp { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -192,7 +192,7 @@ describe('components & directives', () => { class HostAttributeDir { // NORMATIVE static ngDirectiveDef = $r3$.ɵdefineDirective({ - selector: [[['', 'hostAttributeDir', ''], null]], + selectors: [['', 'hostAttributeDir', '']], type: HostAttributeDir, factory: function HostAttributeDir_Factory() { return new HostAttributeDir(); }, attributes: ['role', 'listbox'] @@ -211,7 +211,7 @@ describe('components & directives', () => { class MyApp { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -239,7 +239,7 @@ describe('components & directives', () => { // NORMATIVE static ngDirectiveDef = $r3$.ɵdefineDirective({ type: HostBindingDir, - selector: [[['', 'hostBindingDir', ''], null]], + selectors: [['', 'hostBindingDir', '']], factory: function HostBindingDir_Factory() { return new HostBindingDir(); }, hostBindings: function HostBindingDir_HostBindings(dirIndex: $number$, elIndex: $number$) { $r3$.ɵa(elIndex, 'aria-label', $r3$.ɵb($r3$.ɵd(dirIndex).label)); @@ -259,7 +259,7 @@ describe('components & directives', () => { class MyApp { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -294,7 +294,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComp, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp(); }, template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { if (cm) { @@ -319,7 +319,7 @@ describe('components & directives', () => { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -350,7 +350,7 @@ describe('components & directives', () => { // NORMATIVE static ngDirectiveDef = $r3$.ɵdefineDirective({ type: IfDirective, - selector: [[['', 'if', ''], null]], + selectors: [['', 'if', '']], factory: () => new IfDirective($r3$.ɵinjectTemplateRef()), }); // /NORMATIVE @@ -368,7 +368,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: () => new MyComponent(), template: function(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -411,7 +411,7 @@ describe('components & directives', () => { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyArrayComp, - selector: [[['my-array-comp'], null]], + selectors: [['my-array-comp']], factory: function MyArrayComp_Factory() { return new MyArrayComp(); }, template: function MyArrayComp_Template(ctx: $MyArrayComp$, cm: $boolean$) { if (cm) { @@ -440,7 +440,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -482,7 +482,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -512,7 +512,7 @@ describe('components & directives', () => { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComp, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp(); }, template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { if (cm) { @@ -538,7 +538,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -578,7 +578,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -622,7 +622,7 @@ describe('components & directives', () => { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComp, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp(); }, template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { if (cm) { @@ -683,7 +683,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(c: MyApp, cm: boolean) { if (cm) { @@ -721,7 +721,7 @@ describe('components & directives', () => { static ngComponentDef = $r3$.ɵdefineComponent({ type: ObjectComp, - selector: [[['object-comp'], null]], + selectors: [['object-comp']], factory: function ObjectComp_Factory() { return new ObjectComp(); }, template: function ObjectComp_Template(ctx: $ObjectComp$, cm: $boolean$) { if (cm) { @@ -755,7 +755,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -792,7 +792,7 @@ describe('components & directives', () => { static ngComponentDef = $r3$.ɵdefineComponent({ type: NestedComp, - selector: [[['nested-comp'], null]], + selectors: [['nested-comp']], factory: function NestedComp_Factory() { return new NestedComp(); }, template: function NestedComp_Template(ctx: $NestedComp$, cm: $boolean$) { if (cm) { @@ -835,7 +835,7 @@ describe('components & directives', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { diff --git a/packages/core/test/render3/compiler_canonical/content_projection_spec.ts b/packages/core/test/render3/compiler_canonical/content_projection_spec.ts index 7e06e66608..2541622e21 100644 --- a/packages/core/test/render3/compiler_canonical/content_projection_spec.ts +++ b/packages/core/test/render3/compiler_canonical/content_projection_spec.ts @@ -24,7 +24,7 @@ describe('content projection', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: SimpleComponent, - selector: [[['simple'], null]], + selectors: [['simple']], factory: () => new SimpleComponent(), template: function(ctx: $SimpleComponent$, cm: $boolean$) { if (cm) { @@ -39,8 +39,8 @@ describe('content projection', () => { } // NORMATIVE - const $pD_0P$: $r3$.ɵCssSelector[] = - [[[['span', 'title', 'toFirst'], null]], [[['span', 'title', 'toSecond'], null]]]; + const $pD_0P$: $r3$.ɵCssSelectorList[] = + [[['span', 'title', 'toFirst']], [['span', 'title', 'toSecond']]]; const $pD_0R$: string[] = ['span[title=toFirst]', 'span[title=toSecond]']; // /NORMATIVE @@ -54,7 +54,7 @@ describe('content projection', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: ComplexComponent, - selector: [[['complex'], null]], + selectors: [['complex']], factory: () => new ComplexComponent(), template: function(ctx: $ComplexComponent$, cm: $boolean$) { if (cm) { @@ -79,7 +79,7 @@ describe('content projection', () => { class MyApp { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp(), template: function(ctx: $MyApp$, cm: $boolean$) { if (cm) { diff --git a/packages/core/test/render3/compiler_canonical/elements_spec.ts b/packages/core/test/render3/compiler_canonical/elements_spec.ts index 090640b694..bf54e09ddd 100644 --- a/packages/core/test/render3/compiler_canonical/elements_spec.ts +++ b/packages/core/test/render3/compiler_canonical/elements_spec.ts @@ -32,7 +32,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: () => new MyComponent(), template: function(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -61,7 +61,7 @@ describe('elements', () => { static ngDirectiveDef = $r3$.ɵdefineDirective({ type: Dir, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: function DirA_Factory() { return new Dir(); }, exportAs: 'dir' }); @@ -83,7 +83,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: LocalRefComp, - selector: [[['local-ref-comp'], null]], + selectors: [['local-ref-comp']], factory: function LocalRefComp_Factory() { return new LocalRefComp(); }, template: function LocalRefComp_Template(ctx: $LocalRefComp$, cm: $boolean$) { if (cm) { @@ -123,7 +123,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: ListenerComp, - selector: [[['listener-comp'], null]], + selectors: [['listener-comp']], factory: function ListenerComp_Factory() { return new ListenerComp(); }, template: function ListenerComp_Template(ctx: $ListenerComp$, cm: $boolean$) { if (cm) { @@ -155,7 +155,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -185,7 +185,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -215,7 +215,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -249,7 +249,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -297,7 +297,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -331,7 +331,7 @@ describe('elements', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: StyleComponent, - selector: [[['style-comp'], null]], + selectors: [['style-comp']], factory: function StyleComponent_Factory() { return new StyleComponent(); }, template: function StyleComponent_Template(ctx: $StyleComponent$, cm: $boolean$) { if (cm) { diff --git a/packages/core/test/render3/compiler_canonical/injection_spec.ts b/packages/core/test/render3/compiler_canonical/injection_spec.ts index a997a0f764..4200f6c649 100644 --- a/packages/core/test/render3/compiler_canonical/injection_spec.ts +++ b/packages/core/test/render3/compiler_canonical/injection_spec.ts @@ -30,7 +30,7 @@ describe('injection', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComp, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectChangeDetectorRef()); }, @@ -47,7 +47,7 @@ describe('injection', () => { class MyApp { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, /** */ template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { @@ -77,7 +77,7 @@ describe('injection', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComp, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectAttribute('title')); }, template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) { if (cm) { @@ -92,7 +92,7 @@ describe('injection', () => { class MyApp { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, /** */ template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { @@ -142,7 +142,7 @@ describe('injection', () => { static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp( $r3$.ɵdirectiveInject(ServiceA), $r3$.ɵdirectiveInject(ServiceB), inject(INJECTOR)); @@ -189,4 +189,4 @@ describe('injection', () => { }); -}); \ No newline at end of file +}); diff --git a/packages/core/test/render3/compiler_canonical/life_cycle_spec.ts b/packages/core/test/render3/compiler_canonical/life_cycle_spec.ts index eb02201d3e..23272df9af 100644 --- a/packages/core/test/render3/compiler_canonical/life_cycle_spec.ts +++ b/packages/core/test/render3/compiler_canonical/life_cycle_spec.ts @@ -41,7 +41,7 @@ describe('lifecycle hooks', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: LifecycleComp, - selector: [[['lifecycle-comp'], null]], + selectors: [['lifecycle-comp']], factory: function LifecycleComp_Factory() { return new LifecycleComp(); }, template: function LifecycleComp_Template(ctx: $LifecycleComp$, cm: $boolean$) {}, inputs: {nameMin: 'name'}, @@ -64,7 +64,7 @@ describe('lifecycle hooks', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: SimpleLayout, - selector: [[['simple-layout'], null]], + selectors: [['simple-layout']], factory: function SimpleLayout_Factory() { return simpleLayout = new SimpleLayout(); }, template: function SimpleLayout_Template(ctx: $SimpleLayout$, cm: $boolean$) { if (cm) { diff --git a/packages/core/test/render3/compiler_canonical/local_reference_spec.ts b/packages/core/test/render3/compiler_canonical/local_reference_spec.ts index 6032b236fd..7f60b95517 100644 --- a/packages/core/test/render3/compiler_canonical/local_reference_spec.ts +++ b/packages/core/test/render3/compiler_canonical/local_reference_spec.ts @@ -23,7 +23,7 @@ describe('local references', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: () => new MyComponent, template: function(ctx: $MyComponent$, cm: $boolean$) { if (cm) { diff --git a/packages/core/test/render3/compiler_canonical/pipes_spec.ts b/packages/core/test/render3/compiler_canonical/pipes_spec.ts index d4ebe21be7..b973e25cbc 100644 --- a/packages/core/test/render3/compiler_canonical/pipes_spec.ts +++ b/packages/core/test/render3/compiler_canonical/pipes_spec.ts @@ -79,7 +79,7 @@ describe('pipes', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { @@ -133,7 +133,7 @@ describe('pipes', () => { // NORMATIVE static ngDirectiveDef = $r3$.ɵdefineDirective({ type: OneTimeIf, - selector: [[['', 'oneTimeIf', ''], null]], + selectors: [['', 'oneTimeIf', '']], factory: () => new OneTimeIf($r3$.ɵinjectViewContainerRef(), $r3$.ɵinjectTemplateRef()), inputs: {oneTimeIf: 'oneTimeIf'} }); @@ -152,7 +152,7 @@ describe('pipes', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { let $pi$: $any$; diff --git a/packages/core/test/render3/compiler_canonical/query_spec.ts b/packages/core/test/render3/compiler_canonical/query_spec.ts index 6ebb49f965..10c333ccb6 100644 --- a/packages/core/test/render3/compiler_canonical/query_spec.ts +++ b/packages/core/test/render3/compiler_canonical/query_spec.ts @@ -22,7 +22,7 @@ describe('queries', () => { class SomeDirective { static ngDirectiveDef = $r3$.ɵdefineDirective({ type: SomeDirective, - selector: [[['', 'someDir', ''], null]], + selectors: [['', 'someDir', '']], factory: function SomeDirective_Factory() { return someDir = new SomeDirective(); }, features: [$r3$.ɵPublicFeature] }); @@ -48,7 +48,7 @@ describe('queries', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: ViewQueryComponent, - selector: [[['view-query-component'], null]], + selectors: [['view-query-component']], factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); }, template: function ViewQueryComponent_Template(ctx: $ViewQueryComponent$, cm: $boolean$) { let $tmp$: any; @@ -95,7 +95,7 @@ describe('queries', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: ContentQueryComponent, - selector: [[['content-query-component'], null]], + selectors: [['content-query-component']], factory: function ContentQueryComponent_Factory() { return [ new ContentQueryComponent(), $r3$.ɵQ(null, SomeDirective, false), @@ -136,7 +136,7 @@ describe('queries', () => { // NON-NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) { if (cm) { diff --git a/packages/core/test/render3/compiler_canonical/sanitize_spec.ts b/packages/core/test/render3/compiler_canonical/sanitize_spec.ts index 047c6ad056..78f5792707 100644 --- a/packages/core/test/render3/compiler_canonical/sanitize_spec.ts +++ b/packages/core/test/render3/compiler_canonical/sanitize_spec.ts @@ -38,7 +38,7 @@ describe('compiler sanitization', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -72,4 +72,4 @@ describe('compiler sanitization', () => { expect(img.getAttribute('srcset')).toEqual('unsafe:javascript:evil()'); }); -}); \ No newline at end of file +}); diff --git a/packages/core/test/render3/compiler_canonical/small_app_spec.ts b/packages/core/test/render3/compiler_canonical/small_app_spec.ts index 9079e57e72..69b98adf0d 100644 --- a/packages/core/test/render3/compiler_canonical/small_app_spec.ts +++ b/packages/core/test/render3/compiler_canonical/small_app_spec.ts @@ -58,7 +58,7 @@ class ToDoAppComponent { // NORMATIVE static ngComponentDef = r3.defineComponent({ type: ToDoAppComponent, - selector: [[['todo-app'], null]], + selectors: [['todo-app']], factory: function ToDoAppComponent_Factory() { return new ToDoAppComponent(r3.directiveInject(AppState)); }, @@ -123,7 +123,7 @@ class ToDoItemComponent { // NORMATIVE static ngComponentDef = r3.defineComponent({ type: ToDoItemComponent, - selector: [[['todo'], null]], + selectors: [['todo']], factory: function ToDoItemComponent_Factory() { return new ToDoItemComponent(); }, template: function ToDoItemComponent_Template(ctx: ToDoItemComponent, cm: boolean) { if (cm) { diff --git a/packages/core/test/render3/compiler_canonical/template_variables_spec.ts b/packages/core/test/render3/compiler_canonical/template_variables_spec.ts index 237a19db32..ba1ebe7f67 100644 --- a/packages/core/test/render3/compiler_canonical/template_variables_spec.ts +++ b/packages/core/test/render3/compiler_canonical/template_variables_spec.ts @@ -63,7 +63,7 @@ describe('template variables', () => { // NORMATIVE static ngDirectiveDef = $r3$.ɵdefineDirective({ type: ForOfDirective, - selector: [[['', 'forOf', ''], null]], + selectors: [['', 'forOf', '']], factory: function ForOfDirective_Factory() { return new ForOfDirective($r3$.ɵinjectViewContainerRef(), $r3$.ɵinjectTemplateRef()); }, @@ -91,7 +91,7 @@ describe('template variables', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { if (cm) { @@ -159,7 +159,7 @@ describe('template variables', () => { // NORMATIVE static ngComponentDef = $r3$.ɵdefineComponent({ type: MyComponent, - selector: [[['my-component'], null]], + selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, template: function MyComponent_Template(ctx: $MyComponent$, cm: $boolean$) { if (cm) { diff --git a/packages/core/test/render3/component_spec.ts b/packages/core/test/render3/component_spec.ts index 7f84cf03c8..f6b847d9b9 100644 --- a/packages/core/test/render3/component_spec.ts +++ b/packages/core/test/render3/component_spec.ts @@ -24,7 +24,7 @@ describe('component', () => { static ngComponentDef = defineComponent({ type: CounterComponent, - selector: [[['counter'], null]], + selectors: [['counter']], template: function(ctx: CounterComponent, cm: boolean) { if (cm) { text(0); @@ -87,7 +87,7 @@ describe('component with a container', () => { items: string[]; static ngComponentDef = defineComponent({ type: WrapperComponent, - selector: [[['wrapper'], null]], + selectors: [['wrapper']], template: function ChildComponentTemplate(ctx: {items: string[]}, cm: boolean) { if (cm) { container(0); @@ -131,7 +131,7 @@ describe('encapsulation', () => { class WrapperComponent { static ngComponentDef = defineComponent({ type: WrapperComponent, - selector: [[['wrapper'], null]], + selectors: [['wrapper']], template: function(ctx: WrapperComponent, cm: boolean) { if (cm) { elementStart(0, 'encapsulated'); @@ -146,7 +146,7 @@ describe('encapsulation', () => { class EncapsulatedComponent { static ngComponentDef = defineComponent({ type: EncapsulatedComponent, - selector: [[['encapsulated'], null]], + selectors: [['encapsulated']], template: function(ctx: EncapsulatedComponent, cm: boolean) { if (cm) { text(0, 'foo'); @@ -164,7 +164,7 @@ describe('encapsulation', () => { class LeafComponent { static ngComponentDef = defineComponent({ type: LeafComponent, - selector: [[['leaf'], null]], + selectors: [['leaf']], template: function(ctx: LeafComponent, cm: boolean) { if (cm) { elementStart(0, 'span'); @@ -194,7 +194,7 @@ describe('encapsulation', () => { class WrapperComponentWith { static ngComponentDef = defineComponent({ type: WrapperComponentWith, - selector: [[['wrapper'], null]], + selectors: [['wrapper']], template: function(ctx: WrapperComponentWith, cm: boolean) { if (cm) { elementStart(0, 'leaf'); @@ -211,7 +211,7 @@ describe('encapsulation', () => { class LeafComponentwith { static ngComponentDef = defineComponent({ type: LeafComponentwith, - selector: [[['leaf'], null]], + selectors: [['leaf']], template: function(ctx: LeafComponentwith, cm: boolean) { if (cm) { elementStart(0, 'span'); @@ -250,7 +250,7 @@ describe('recursive components', () => { static ngComponentDef = defineComponent({ type: TreeComponent, - selector: [[['tree-comp'], null]], + selectors: [['tree-comp']], factory: () => new TreeComponent(), template: (ctx: TreeComponent, cm: boolean) => { if (cm) { diff --git a/packages/core/test/render3/content_spec.ts b/packages/core/test/render3/content_spec.ts index 74f0781009..de0f013951 100644 --- a/packages/core/test/render3/content_spec.ts +++ b/packages/core/test/render3/content_spec.ts @@ -6,6 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ +import {SelectorFlags} from '@angular/core/src/render3/interfaces/projection'; + import {detectChanges} from '../../src/render3/index'; import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, projection, projectionDef, text} from '../../src/render3/instructions'; @@ -522,7 +524,7 @@ describe('content projection', () => { const Child = createComponent('child', function(ctx: any, cm: boolean) { if (cm) { projectionDef( - 0, [[[['span', 'title', 'toFirst'], null]], [[['span', 'title', 'toSecond'], null]]], + 0, [[['span', 'title', 'toFirst']], [['span', 'title', 'toSecond']]], ['span[title=toFirst]', 'span[title=toSecond]']); elementStart(1, 'div', ['id', 'first']); { projection(2, 0, 1); } @@ -568,7 +570,11 @@ describe('content projection', () => { const Child = createComponent('child', function(ctx: any, cm: boolean) { if (cm) { projectionDef( - 0, [[[['span', 'class', 'toFirst'], null]], [[['span', 'class', 'toSecond'], null]]], + 0, + [ + [['span', SelectorFlags.CLASS, 'toFirst']], + [['span', SelectorFlags.CLASS, 'toSecond']] + ], ['span.toFirst', 'span.toSecond']); elementStart(1, 'div', ['id', 'first']); { projection(2, 0, 1); } @@ -614,7 +620,11 @@ describe('content projection', () => { const Child = createComponent('child', function(ctx: any, cm: boolean) { if (cm) { projectionDef( - 0, [[[['span', 'class', 'toFirst'], null]], [[['span', 'class', 'toSecond'], null]]], + 0, + [ + [['span', SelectorFlags.CLASS, 'toFirst']], + [['span', SelectorFlags.CLASS, 'toSecond']] + ], ['span.toFirst', 'span.toSecond']); elementStart(1, 'div', ['id', 'first']); { projection(2, 0, 1); } @@ -660,7 +670,7 @@ describe('content projection', () => { const Child = createComponent('child', function(ctx: any, cm: boolean) { if (cm) { projectionDef( - 0, [[[['span'], null]], [[['span', 'class', 'toSecond'], null]]], + 0, [[['span']], [['span', SelectorFlags.CLASS, 'toSecond']]], ['span', 'span.toSecond']); elementStart(1, 'div', ['id', 'first']); { projection(2, 0, 1); } @@ -705,7 +715,7 @@ describe('content projection', () => { */ const Child = createComponent('child', function(ctx: any, cm: boolean) { if (cm) { - projectionDef(0, [[[['span', 'class', 'toFirst'], null]]], ['span.toFirst']); + projectionDef(0, [[['span', SelectorFlags.CLASS, 'toFirst']]], ['span.toFirst']); elementStart(1, 'div', ['id', 'first']); { projection(2, 0, 1); } elementEnd(); @@ -750,7 +760,7 @@ describe('content projection', () => { */ const Child = createComponent('child', function(ctx: any, cm: boolean) { if (cm) { - projectionDef(0, [[[['span', 'class', 'toSecond'], null]]], ['span.toSecond']); + projectionDef(0, [[['span', SelectorFlags.CLASS, 'toSecond']]], ['span.toSecond']); elementStart(1, 'div', ['id', 'first']); { projection(2, 0); } elementEnd(); @@ -802,7 +812,7 @@ describe('content projection', () => { */ const GrandChild = createComponent('grand-child', function(ctx: any, cm: boolean) { if (cm) { - projectionDef(0, [[[['span'], null]]], ['span']); + projectionDef(0, [[['span']]], ['span']); projection(1, 0, 1); elementStart(2, 'hr'); elementEnd(); @@ -865,7 +875,7 @@ describe('content projection', () => { const Card = createComponent('card', function(ctx: any, cm: boolean) { if (cm) { projectionDef( - 0, [[[['', 'card-title', ''], null]], [[['', 'card-content', ''], null]]], + 0, [[['', 'card-title', '']], [['', 'card-content', '']]], ['[card-title]', '[card-content]']); projection(1, 0, 1); elementStart(2, 'hr'); @@ -924,7 +934,7 @@ describe('content projection', () => { const Card = createComponent('card', function(ctx: any, cm: boolean) { if (cm) { projectionDef( - 0, [[[['', 'card-title', ''], null]], [[['', 'card-content', ''], null]]], + 0, [[['', 'card-title', '']], [['', 'card-content', '']]], ['[card-title]', '[card-content]']); projection(1, 0, 1); elementStart(2, 'hr'); @@ -979,7 +989,7 @@ describe('content projection', () => { */ const Child = createComponent('child', function(ctx: any, cm: boolean) { if (cm) { - projectionDef(0, [[[['div'], null]]], ['div']); + projectionDef(0, [[['div']]], ['div']); projection(1, 0, 1); } }); @@ -1018,7 +1028,7 @@ describe('content projection', () => { */ const Child = createComponent('child', function(ctx: any, cm: boolean) { if (cm) { - projectionDef(0, [[[['div'], null]]], ['div']); + projectionDef(0, [[['div']]], ['div']); elementStart(1, 'span'); { projection(2, 0, 1); } elementEnd(); diff --git a/packages/core/test/render3/control_flow_spec.ts b/packages/core/test/render3/control_flow_spec.ts index 246717ddce..c5e8032322 100644 --- a/packages/core/test/render3/control_flow_spec.ts +++ b/packages/core/test/render3/control_flow_spec.ts @@ -541,7 +541,7 @@ describe('JS control flow', () => { class Comp { static ngComponentDef = defineComponent({ type: Comp, - selector: [[['comp'], null]], + selectors: [['comp']], factory: () => { log.push('comp!'); return new Comp(); @@ -556,7 +556,7 @@ describe('JS control flow', () => { static ngComponentDef = defineComponent({ type: App, - selector: [[['app'], null]], + selectors: [['app']], factory: () => new App(), template: function(ctx: any, cm: boolean) { if (cm) { @@ -604,7 +604,7 @@ describe('JS control flow', () => { class Comp { static ngComponentDef = defineComponent({ type: Comp, - selector: [[['comp'], null]], + selectors: [['comp']], factory: () => { log.push('comp!'); return new Comp(); @@ -619,7 +619,7 @@ describe('JS control flow', () => { static ngComponentDef = defineComponent({ type: App, - selector: [[['app'], null]], + selectors: [['app']], factory: () => new App(), template: function(ctx: any, cm: boolean) { if (cm) { diff --git a/packages/core/test/render3/define_spec.ts b/packages/core/test/render3/define_spec.ts index 02aec27408..94ab58d984 100644 --- a/packages/core/test/render3/define_spec.ts +++ b/packages/core/test/render3/define_spec.ts @@ -29,7 +29,7 @@ describe('define', () => { static ngDirectiveDef = defineDirective({ type: MyDirective, - selector: [[['', 'myDir', ''], null]], + selectors: [['', 'myDir', '']], factory: () => new MyDirective(), features: [NgOnChangesFeature()], inputs: {valA: 'valA', valB: 'valB'} diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index ee28639851..531c803040 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -26,7 +26,7 @@ describe('di', () => { value: string = 'Created'; static ngDirectiveDef = defineDirective({ type: Directive, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: () => new Directive, exportAs: 'dir' }); @@ -54,7 +54,7 @@ describe('di', () => { value: string = 'A'; static ngDirectiveDef = defineDirective({ type: DirectiveA, - selector: [[['', 'dirA', ''], null]], + selectors: [['', 'dirA', '']], factory: () => new DirectiveA, features: [PublicFeature] }); @@ -64,7 +64,7 @@ describe('di', () => { value: string = 'B'; static ngDirectiveDef = defineDirective({ type: DirectiveB, - selector: [[['', 'dirB', ''], null]], + selectors: [['', 'dirB', '']], factory: () => new DirectiveB, features: [PublicFeature] }); @@ -75,7 +75,7 @@ describe('di', () => { constructor(a: DirectiveA, b: DirectiveB) { this.value = a.value + b.value; } static ngDirectiveDef = defineDirective({ type: DirectiveC, - selector: [[['', 'dirC', ''], null]], + selectors: [['', 'dirC', '']], factory: () => new DirectiveC(directiveInject(DirectiveA), directiveInject(DirectiveB)), exportAs: 'dirC' }); @@ -116,7 +116,7 @@ describe('di', () => { } static ngDirectiveDef = defineDirective({ type: Directive, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: () => new Directive(injectElementRef()), features: [PublicFeature], exportAs: 'dir' @@ -130,7 +130,7 @@ describe('di', () => { } static ngDirectiveDef = defineDirective({ type: DirectiveSameInstance, - selector: [[['', 'dirSame', ''], null]], + selectors: [['', 'dirSame', '']], factory: () => new DirectiveSameInstance(injectElementRef(), directiveInject(Directive)), exportAs: 'dirSame' }); @@ -168,7 +168,7 @@ describe('di', () => { } static ngDirectiveDef = defineDirective({ type: Directive, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: () => new Directive(injectTemplateRef()), features: [PublicFeature], exportAs: 'dir' @@ -182,7 +182,7 @@ describe('di', () => { } static ngDirectiveDef = defineDirective({ type: DirectiveSameInstance, - selector: [[['', 'dirSame', ''], null]], + selectors: [['', 'dirSame', '']], factory: () => new DirectiveSameInstance(injectTemplateRef(), directiveInject(Directive)), exportAs: 'dirSame' }); @@ -218,7 +218,7 @@ describe('di', () => { } static ngDirectiveDef = defineDirective({ type: Directive, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: () => new Directive(injectViewContainerRef()), features: [PublicFeature], exportAs: 'dir' @@ -232,7 +232,7 @@ describe('di', () => { } static ngDirectiveDef = defineDirective({ type: DirectiveSameInstance, - selector: [[['', 'dirSame', ''], null]], + selectors: [['', 'dirSame', '']], factory: () => new DirectiveSameInstance(injectViewContainerRef(), directiveInject(Directive)), exportAs: 'dirSame' @@ -272,7 +272,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyComp, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: () => comp = new MyComp(injectChangeDetectorRef()), template: function(ctx: MyComp, cm: boolean) { if (cm) { @@ -288,7 +288,7 @@ describe('di', () => { constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; } static ngDirectiveDef = defineDirective({ type: Directive, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: () => dir = new Directive(injectChangeDetectorRef()), features: [PublicFeature], exportAs: 'dir' @@ -300,7 +300,7 @@ describe('di', () => { static ngDirectiveDef = defineDirective({ type: DirectiveSameInstance, - selector: [[['', 'dirSame', ''], null]], + selectors: [['', 'dirSame', '']], factory: () => dirSameInstance = new DirectiveSameInstance(injectChangeDetectorRef()) }); } @@ -319,7 +319,7 @@ describe('di', () => { static ngDirectiveDef = defineDirective({ type: IfDirective, - selector: [[['', 'myIf', ''], null]], + selectors: [['', 'myIf', '']], factory: () => new IfDirective(injectTemplateRef(), injectViewContainerRef()), inputs: {myIf: 'myIf'}, features: [PublicFeature, NgOnChangesFeature()] @@ -360,7 +360,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), /**
{{ dir.value }}
*/ template: function(ctx: any, cm: boolean) { @@ -390,7 +390,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), /** * @@ -432,7 +432,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), /** * % if (showing) { @@ -478,7 +478,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), /**
{{ dir.value }}
*/ template: function(ctx: MyApp, cm: boolean) { @@ -607,7 +607,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyApp, - selector: [[['my-app'], null]], + selectors: [['my-app']], factory: () => new MyApp( directiveInject(String as any, InjectFlags.Default, 'DefaultValue')), template: () => null @@ -626,7 +626,7 @@ describe('di', () => { constructor(public parent: any) { this.value = (parent.constructor as any).name; } static ngDirectiveDef = defineDirective({ type: ChildDirective, - selector: [[['', 'childDir', ''], null]], + selectors: [['', 'childDir', '']], factory: () => new ChildDirective(directiveInject(ParentDirective)), features: [PublicFeature], exportAs: 'childDir' @@ -637,7 +637,7 @@ describe('di', () => { value: boolean; constructor(parent: any, child: ChildDirective) { this.value = parent === child.parent; } static ngDirectiveDef = defineDirective({ - selector: [[['', 'child2Dir', ''], null]], + selectors: [['', 'child2Dir', '']], type: Child2Directive, factory: () => new Child2Directive( directiveInject(ParentDirective), directiveInject(ChildDirective)), diff --git a/packages/core/test/render3/directive_spec.ts b/packages/core/test/render3/directive_spec.ts index d7901ae07f..7446cf9082 100644 --- a/packages/core/test/render3/directive_spec.ts +++ b/packages/core/test/render3/directive_spec.ts @@ -22,7 +22,7 @@ describe('directive', () => { klass = 'foo'; static ngDirectiveDef = defineDirective({ type: Directive, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: () => directiveInstance = new Directive, hostBindings: (directiveIndex: number, elementIndex: number) => { elementProperty( diff --git a/packages/core/test/render3/exports_spec.ts b/packages/core/test/render3/exports_spec.ts index 2b21ea70b3..966e4af2ab 100644 --- a/packages/core/test/render3/exports_spec.ts +++ b/packages/core/test/render3/exports_spec.ts @@ -46,7 +46,7 @@ describe('exports', () => { static ngComponentDef = defineComponent({ type: MyComponent, - selector: [[['comp'], null]], + selectors: [['comp']], template: function() {}, factory: () => new MyComponent }); @@ -63,7 +63,7 @@ describe('exports', () => { constructor() { myComponent = this; } static ngComponentDef = defineComponent({ type: MyComponent, - selector: [[['comp'], null]], + selectors: [['comp']], template: function() {}, factory: () => new MyComponent }); @@ -74,7 +74,7 @@ describe('exports', () => { constructor() { myDir = this; } static ngDirectiveDef = defineDirective({ type: MyDir, - selector: [[['', 'myDir', ''], null]], + selectors: [['', 'myDir', '']], factory: () => new MyDir, inputs: {myDir: 'myDir'} }); @@ -115,7 +115,7 @@ describe('exports', () => { name = 'Drew'; static ngDirectiveDef = defineDirective({ type: SomeDir, - selector: [[['', 'someDir', ''], null]], + selectors: [['', 'someDir', '']], factory: () => new SomeDir, exportAs: 'someDir' }); @@ -216,7 +216,7 @@ describe('exports', () => { static ngComponentDef = defineComponent({ type: MyComponent, - selector: [[['comp'], null]], + selectors: [['comp']], template: function(ctx: MyComponent, cm: boolean) {}, factory: () => new MyComponent }); @@ -229,7 +229,7 @@ describe('exports', () => { static ngDirectiveDef = defineDirective({ type: MyDir, - selector: [[['', 'myDir', ''], null]], + selectors: [['', 'myDir', '']], factory: () => new MyDir, inputs: {myDir: 'myDir'} }); @@ -278,7 +278,7 @@ describe('exports', () => { static ngComponentDef = defineComponent({ type: MyComponent, - selector: [[['comp'], null]], + selectors: [['comp']], template: function() {}, factory: () => new MyComponent }); diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index d1f2bda289..500bb0d873 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -178,7 +178,7 @@ describe('render3 integration test', () => { static ngComponentDef = defineComponent({ type: TodoComponent, - selector: [[['todo'], null]], + selectors: [['todo']], template: function TodoTemplate(ctx: any, cm: boolean) { if (cm) { elementStart(0, 'p'); @@ -242,7 +242,7 @@ describe('render3 integration test', () => { title = 'one'; static ngComponentDef = defineComponent({ type: TodoComponentHostBinding, - selector: [[['todo'], null]], + selectors: [['todo']], template: function TodoComponentHostBindingTemplate( ctx: TodoComponentHostBinding, cm: boolean) { if (cm) { @@ -277,7 +277,7 @@ describe('render3 integration test', () => { class HostAttributeComp { static ngComponentDef = defineComponent({ type: HostAttributeComp, - selector: [[['host-attr-comp'], null]], + selectors: [['host-attr-comp']], factory: () => new HostAttributeComp(), template: (ctx: HostAttributeComp, cm: boolean) => {}, attributes: ['role', 'button'] @@ -294,7 +294,7 @@ describe('render3 integration test', () => { name = 'Bess'; static ngComponentDef = defineComponent({ type: MyComp, - selector: [[['comp'], null]], + selectors: [['comp']], template: function MyCompTemplate(ctx: any, cm: boolean) { if (cm) { elementStart(0, 'p'); @@ -328,7 +328,7 @@ describe('render3 integration test', () => { condition: boolean; static ngComponentDef = defineComponent({ type: MyComp, - selector: [[['comp'], null]], + selectors: [['comp']], template: function MyCompTemplate(ctx: any, cm: boolean) { if (cm) { container(0); @@ -434,7 +434,7 @@ describe('render3 integration test', () => { beforeTree: Tree; afterTree: Tree; static ngComponentDef = defineComponent({ - selector: [[['child'], null]], + selectors: [['child']], type: ChildComponent, template: function ChildComponentTemplate( ctx: {beforeTree: Tree, afterTree: Tree}, cm: boolean) { @@ -640,7 +640,7 @@ describe('render3 integration test', () => { static ngDirectiveDef = defineDirective({ type: HostBindingDir, - selector: [[['', 'hostBindingDir', ''], null]], + selectors: [['', 'hostBindingDir', '']], factory: function HostBindingDir_Factory() { return hostBindingDir = new HostBindingDir(); }, diff --git a/packages/core/test/render3/lifecycle_spec.ts b/packages/core/test/render3/lifecycle_spec.ts index 0a43440886..2f9ad68071 100644 --- a/packages/core/test/render3/lifecycle_spec.ts +++ b/packages/core/test/render3/lifecycle_spec.ts @@ -52,7 +52,7 @@ describe('lifecycles', () => { static ngComponentDef = defineComponent({ type: Component, - selector: [[[name], null]], + selectors: [[name]], factory: () => new Component(), inputs: {val: 'val'}, template, directiveDefs: defs @@ -64,7 +64,7 @@ describe('lifecycles', () => { ngOnInit() { events.push('dir'); } static ngDirectiveDef = defineDirective( - {type: Directive, selector: [[['', 'dir', ''], null]], factory: () => new Directive()}); + {type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()}); } const defs = [ @@ -362,7 +362,7 @@ describe('lifecycles', () => { static ngComponentDef = defineComponent({ type: Component, - selector: [[[name], null]], + selectors: [[name]], factory: () => new Component(), template, directiveDefs: defs }); @@ -373,7 +373,7 @@ describe('lifecycles', () => { ngDoCheck() { events.push('dir'); } static ngDirectiveDef = defineDirective( - {type: Directive, selector: [[['', 'dir', ''], null]], factory: () => new Directive()}); + {type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()}); } const defs = [Comp.ngComponentDef, Parent.ngComponentDef, Directive.ngDirectiveDef]; @@ -516,7 +516,7 @@ describe('lifecycles', () => { static ngComponentDef = defineComponent({ type: Component, - selector: [[[name], null]], + selectors: [[name]], factory: () => new Component(), inputs: {val: 'val'}, template: template, @@ -530,7 +530,7 @@ describe('lifecycles', () => { ngAfterContentChecked() { events.push('check'); } static ngDirectiveDef = defineDirective( - {type: Directive, selector: [[['', 'dir', ''], null]], factory: () => new Directive()}); + {type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()}); } function ForLoopWithChildrenTemplate(ctx: any, cm: boolean) { @@ -886,7 +886,7 @@ describe('lifecycles', () => { static ngComponentDef = defineComponent({ type: Component, - selector: [[[name], null]], + selectors: [[name]], factory: () => new Component(), inputs: {val: 'val'}, template: template, @@ -900,7 +900,7 @@ describe('lifecycles', () => { ngAfterViewChecked() { events.push('check'); } static ngDirectiveDef = defineDirective( - {type: Directive, selector: [[['', 'dir', ''], null]], factory: () => new Directive()}); + {type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()}); } const defs = [ @@ -1313,7 +1313,7 @@ describe('lifecycles', () => { static ngComponentDef = defineComponent({ type: Component, - selector: [[[name], null]], + selectors: [[name]], factory: () => new Component(), inputs: {val: 'val'}, template: template, @@ -1335,7 +1335,7 @@ describe('lifecycles', () => { ngOnDestroy() { events.push('dir'); } static ngDirectiveDef = defineDirective( - {type: Directive, selector: [[['', 'dir', ''], null]], factory: () => new Directive()}); + {type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()}); } const defs = [ @@ -1830,7 +1830,7 @@ describe('lifecycles', () => { static ngComponentDef = defineComponent({ type: Component, - selector: [[[name], null]], + selectors: [[name]], factory: () => new Component(), features: [NgOnChangesFeature({b: 'val2'})], inputs: {a: 'val1', b: 'publicName'}, template, @@ -1851,7 +1851,7 @@ describe('lifecycles', () => { static ngDirectiveDef = defineDirective({ type: Directive, - selector: [[['', 'dir', ''], null]], + selectors: [['', 'dir', '']], factory: () => new Directive(), features: [NgOnChangesFeature({b: 'val2'})], inputs: {a: 'val1', b: 'publicName'} @@ -2207,7 +2207,7 @@ describe('lifecycles', () => { static ngComponentDef = defineComponent({ type: Component, - selector: [[[name], null]], + selectors: [[name]], factory: () => new Component(), inputs: {val: 'val'}, template, features: [NgOnChangesFeature()], diff --git a/packages/core/test/render3/listeners_spec.ts b/packages/core/test/render3/listeners_spec.ts index 5f7b9b9278..fac54ae7fa 100644 --- a/packages/core/test/render3/listeners_spec.ts +++ b/packages/core/test/render3/listeners_spec.ts @@ -24,7 +24,7 @@ describe('event listeners', () => { static ngComponentDef = defineComponent({ type: MyComp, - selector: [[['comp'], null]], + selectors: [['comp']], /** */ template: function CompTemplate(ctx: any, cm: boolean) { if (cm) { @@ -61,7 +61,7 @@ describe('event listeners', () => { static ngComponentDef = defineComponent({ type: PreventDefaultComp, - selector: [[['prevent-default-comp'], null]], + selectors: [['prevent-default-comp']], factory: () => new PreventDefaultComp(), /** */ template: (ctx: PreventDefaultComp, cm: boolean) => { @@ -235,7 +235,7 @@ describe('event listeners', () => { static ngDirectiveDef = defineDirective({ type: HostListenerDir, - selector: [[['', 'hostListenerDir', ''], null]], + selectors: [['', 'hostListenerDir', '']], factory: function HostListenerDir_Factory() { const $dir$ = new HostListenerDir(); listener('click', function() { return $dir$.onClick(); }); diff --git a/packages/core/test/render3/node_selector_matcher_spec.ts b/packages/core/test/render3/node_selector_matcher_spec.ts index 06afeacc72..d04a9adaec 100644 --- a/packages/core/test/render3/node_selector_matcher_spec.ts +++ b/packages/core/test/render3/node_selector_matcher_spec.ts @@ -7,8 +7,8 @@ */ import {TNode} from '../../src/render3/interfaces/node'; -import {CssSelector, CssSelectorWithNegations, NG_PROJECT_AS_ATTR_NAME, SimpleCssSelector} from '../../src/render3/interfaces/projection'; -import {getProjectAsAttrValue, isNodeMatchingSelector, isNodeMatchingSelectorWithNegations, isNodeMatchingSimpleSelector} from '../../src/render3/node_selector_matcher'; +import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags,} from '../../src/render3/interfaces/projection'; +import {getProjectAsAttrValue, isNodeMatchingSelectorList, isNodeMatchingSelector} from '../../src/render3/node_selector_matcher'; function testLStaticData(tagName: string, attrs: string[] | null): TNode { return { @@ -24,19 +24,21 @@ function testLStaticData(tagName: string, attrs: string[] | null): TNode { } describe('css selector matching', () => { + function isMatching(tagName: string, attrs: string[] | null, selector: CssSelector): boolean { + return isNodeMatchingSelector(testLStaticData(tagName, attrs), selector); + } describe('isNodeMatchingSimpleSelector', () => { - function isMatching( - tagName: string, attrs: string[] | null, selector: SimpleCssSelector): boolean { - return isNodeMatchingSimpleSelector(testLStaticData(tagName, attrs), selector); - } describe('element matching', () => { it('should match element name only if names are the same', () => { - expect(isMatching('span', null, ['span'])).toBeTruthy(); - expect(isMatching('span', null, ['div'])).toBeFalsy(); + expect(isMatching('span', null, ['span'])) + .toBeTruthy(`Selector 'span' should match `); + + expect(isMatching('span', null, ['div'])) + .toBeFalsy(`Selector 'div' should NOT match `); }); /** @@ -44,8 +46,10 @@ describe('css selector matching', () => { * and in a selector. */ it('should match element name case-sensitively', () => { - expect(isMatching('span', null, ['SPAN'])).toBeFalsy(); - expect(isMatching('SPAN', null, ['span'])).toBeFalsy(); + expect(isMatching('span', null, ['SPAN'])) + .toBeFalsy(`Selector 'SPAN' should NOT match `); + expect(isMatching('SPAN', null, ['span'])) + .toBeFalsy(`Selector 'span' should NOT match '`); }); }); @@ -55,132 +59,359 @@ describe('css selector matching', () => { // TODO: do we need to differentiate no value and empty value? that is: title vs. title="" ? it('should match single attribute without value', () => { - expect(isMatching('span', ['title', ''], ['', 'title', ''])).toBeTruthy(); - expect(isMatching('span', ['title', 'my title'], ['', 'title', ''])).toBeTruthy(); - expect(isMatching('span', null, ['', 'title', ''])).toBeFalsy(); - expect(isMatching('span', ['title', ''], ['', 'other', ''])).toBeFalsy(); + + expect(isMatching('span', ['title', ''], [ + '', 'title', '' + ])).toBeTruthy(`Selector '[title]' should match `); + + expect(isMatching('span', ['title', 'my title'], [ + '', 'title', '' + ])).toBeTruthy(`Selector '[title]' should match `); + + expect(isMatching('span', ['name', 'name'], [ + '', 'title', '' + ])).toBeFalsy(`Selector '[title]' should NOT match `); + + expect(isMatching('span', null, [ + '', 'title', '' + ])).toBeFalsy(`Selector '[title]' should NOT match `); + + expect(isMatching('span', ['title', ''], [ + '', 'other', '' + ])).toBeFalsy(`Selector '[other]' should NOT match '`); }); it('should match selector with one attribute without value when element has several attributes', () => { expect(isMatching('span', ['id', 'my_id', 'title', 'test_title'], [ '', 'title', '' - ])).toBeTruthy(); + ])).toBeTruthy(`Selector '[title]' should match `); }); it('should match single attribute with value', () => { - expect(isMatching('span', ['title', 'My Title'], ['', 'title', 'My Title'])).toBeTruthy(); - expect(isMatching('span', ['title', 'My Title'], ['', 'title', 'Other Title'])).toBeFalsy(); - }); + expect(isMatching('span', ['title', 'My Title'], [ + '', 'title', 'My Title' + ])).toBeTruthy(`Selector '[title="My Title"]' should match '`); - it('should match single attribute with value', () => { - expect(isMatching('span', ['title', 'My Title'], ['', 'title', 'My Title'])).toBeTruthy(); - expect(isMatching('span', ['title', 'My Title'], ['', 'title', 'Other Title'])).toBeFalsy(); + expect(isMatching('span', ['title', 'My Title'], [ + '', 'title', 'Other Title' + ])).toBeFalsy(`Selector '[title="Other Title"]' should NOT match `); }); it('should not match attribute when element name does not match', () => { - expect(isMatching('span', ['title', 'My Title'], ['div', 'title', ''])).toBeFalsy(); - expect(isMatching('span', ['title', 'My Title'], ['div', 'title', 'My title'])).toBeFalsy(); + expect(isMatching('span', ['title', 'My Title'], [ + 'div', 'title', '' + ])).toBeFalsy(`Selector 'div[title]' should NOT match `); + + expect(isMatching('span', ['title', 'My Title'], [ + 'div', 'title', 'My Title' + ])).toBeFalsy(`Selector 'div[title="My Title"]' should NOT match `); + }); + + it('should match multiple attributes', () => { + // selector: '[title=title][name=name]' + const selector = ['', 'title', 'title', 'name', 'name']; + + // + expect(isMatching('span', ['title', 'title', 'name', 'name'], selector)) + .toBeTruthy( + `Selector '[title=title][name=name]' should NOT match `); + + // + expect(isMatching('span', ['title', 'title'], selector)) + .toBeFalsy(`Selector '[title=title][name=name]' should NOT match `); + + // + expect(isMatching('span', ['name', 'name'], selector)) + .toBeFalsy(`Selector '[title=title][name=name]' should NOT match `); + }); + + it('should handle attribute values that match attribute names', () => { + // selector: [name=name] + const selector = ['', 'name', 'name']; + + // + expect(isMatching('span', ['title', 'name'], selector)) + .toBeFalsy(`Selector '[name=name]' should NOT match `); + + // + expect(isMatching('span', ['title', 'name', 'name', 'name'], selector)) + .toBeTruthy(`Selector '[name=name]' should match `); }); /** * We assume that compiler will lower-case all attribute names when generating code */ it('should match attribute name case-sensitively', () => { - expect(isMatching('span', ['foo', ''], ['', 'foo', ''])).toBeTruthy(); - expect(isMatching('span', ['foo', ''], ['', 'Foo', ''])).toBeFalsy(); + expect(isMatching('span', ['foo', ''], [ + '', 'foo', '' + ])).toBeTruthy(`Selector '[foo]' should match `); + + expect(isMatching('span', ['foo', ''], [ + '', 'Foo', '' + ])).toBeFalsy(`Selector '[Foo]' should NOT match `); }); it('should match attribute values case-sensitively', () => { - expect(isMatching('span', ['foo', 'Bar'], ['', 'foo', 'Bar'])).toBeTruthy(); - expect(isMatching('span', ['foo', 'Bar'], ['', 'Foo', 'bar'])).toBeFalsy(); + expect(isMatching('span', ['foo', 'Bar'], [ + '', 'foo', 'Bar' + ])).toBeTruthy(`Selector '[foo="Bar"]' should match `); + + expect(isMatching('span', ['foo', 'Bar'], [ + '', 'Foo', 'bar' + ])).toBeFalsy(`Selector '[Foo="bar"]' should match `); }); it('should match class as an attribute', () => { - expect(isMatching('span', ['class', 'foo'], ['', 'class', ''])).toBeTruthy(); - expect(isMatching('span', ['class', 'foo'], ['', 'class', 'foo'])).toBeTruthy(); + expect(isMatching('span', ['class', 'foo'], [ + '', 'class', '' + ])).toBeTruthy(`Selector '[class]' should match `); + + expect(isMatching('span', ['class', 'foo'], [ + '', 'class', 'foo' + ])).toBeTruthy(`Selector '[class="foo"]' should match `); }); }); describe('class matching', () => { it('should match with a class selector when an element has multiple classes', () => { - expect(isMatching('span', ['class', 'foo bar'], ['', 'class', 'foo'])).toBeTruthy(); - expect(isMatching('span', ['class', 'foo bar'], ['', 'class', 'bar'])).toBeTruthy(); - expect(isMatching('span', ['class', 'foo bar'], ['', 'class', 'baz'])).toBeFalsy(); + expect(isMatching('span', ['class', 'foo bar'], [ + '', SelectorFlags.CLASS, 'foo' + ])).toBeTruthy(`Selector '.foo' should match `); + + expect(isMatching('span', ['class', 'foo bar'], [ + '', SelectorFlags.CLASS, 'bar' + ])).toBeTruthy(`Selector '.bar' should match `); + + expect(isMatching('span', ['class', 'foo bar'], [ + '', SelectorFlags.CLASS, 'baz' + ])).toBeFalsy(`Selector '.baz' should NOT match `); }); it('should not match on partial class name', () => { - expect(isMatching('span', ['class', 'foobar'], ['', 'class', 'foo'])).toBeFalsy(); - expect(isMatching('span', ['class', 'foobar'], ['', 'class', 'bar'])).toBeFalsy(); - expect(isMatching('span', ['class', 'foobar'], ['', 'class', 'ob'])).toBeFalsy(); - expect(isMatching('span', ['class', 'foobar'], ['', 'class', 'foobar'])).toBeTruthy(); + expect(isMatching('span', ['class', 'foobar'], [ + '', SelectorFlags.CLASS, 'foo' + ])).toBeFalsy(`Selector '.foo' should NOT match `); + + expect(isMatching('span', ['class', 'foobar'], [ + '', SelectorFlags.CLASS, 'bar' + ])).toBeFalsy(`Selector '.bar' should NOT match `); + + expect(isMatching('span', ['class', 'foobar'], [ + '', SelectorFlags.CLASS, 'ob' + ])).toBeFalsy(`Selector '.ob' should NOT match `); + + expect(isMatching('span', ['class', 'foobar'], [ + '', SelectorFlags.CLASS, 'foobar' + ])).toBeTruthy(`Selector '.foobar' should match `); }); it('should support selectors with multiple classes', () => { - expect(isMatching('span', ['class', 'foo bar'], ['', 'class', 'foo', 'bar'])).toBeTruthy(); - expect(isMatching('span', ['class', 'foo'], ['', 'class', 'foo', 'bar'])).toBeFalsy(); - expect(isMatching('span', ['class', 'bar'], ['', 'class', 'foo', 'bar'])).toBeFalsy(); + expect(isMatching('span', ['class', 'foo bar'], [ + '', SelectorFlags.CLASS, 'foo', 'bar' + ])).toBeTruthy(`Selector '.foo.bar' should match `); + + expect(isMatching('span', ['class', 'foo'], [ + '', SelectorFlags.CLASS, 'foo', 'bar' + ])).toBeFalsy(`Selector '.foo.bar' should NOT match `); + + expect(isMatching('span', ['class', 'bar'], [ + '', SelectorFlags.CLASS, 'foo', 'bar' + ])).toBeFalsy(`Selector '.foo.bar' should NOT match `); }); it('should support selectors with multiple classes regardless of class name order', () => { - expect(isMatching('span', ['class', 'foo bar'], ['', 'class', 'foo', 'bar'])).toBeTruthy(); - expect(isMatching('span', ['class', 'foo bar'], ['', 'class', 'bar', 'foo'])).toBeTruthy(); - expect(isMatching('span', ['class', 'bar foo'], ['', 'class', 'foo', 'bar'])).toBeTruthy(); - expect(isMatching('span', ['class', 'bar foo'], ['', 'class', 'bar', 'foo'])).toBeTruthy(); + expect(isMatching('span', ['class', 'foo bar'], [ + '', SelectorFlags.CLASS, 'bar', 'foo' + ])).toBeTruthy(`Selector '.bar.foo' should match `); + + expect(isMatching('span', ['class', 'bar foo'], [ + '', SelectorFlags.CLASS, 'foo', 'bar' + ])).toBeTruthy(`Selector '.foo.bar' should match `); + + expect(isMatching('span', ['class', 'bar foo'], [ + '', SelectorFlags.CLASS, 'bar', 'foo' + ])).toBeTruthy(`Selector '.bar.foo' should match `); }); it('should match class name case-sensitively', () => { - expect(isMatching('span', ['class', 'Foo'], ['', 'class', 'Foo'])).toBeTruthy(); - expect(isMatching('span', ['class', 'Foo'], ['', 'class', 'foo'])).toBeFalsy(); + expect(isMatching('span', ['class', 'Foo'], [ + '', SelectorFlags.CLASS, 'Foo' + ])).toBeTruthy(`Selector '.Foo' should match `); + + expect(isMatching('span', ['class', 'Foo'], [ + '', SelectorFlags.CLASS, 'foo' + ])).toBeFalsy(`Selector '.foo' should NOT match `); }); - }); + it('should work without a class attribute', () => { + // selector: '.foo' + const selector = ['', SelectorFlags.CLASS, 'foo']; + //
+ expect(isMatching('div', ['title', 'title'], selector)) + .toBeFalsy(`Selector '.foo' should NOT match
`); + + //
+ expect(isMatching('div', null, selector)) + .toBeFalsy(`Selector '.foo' should NOT match
`); + }); + + it('should work with elements, attributes, and classes', () => { + // selector: 'div.foo[title=title]' + const selector = ['div', 'title', 'title', SelectorFlags.CLASS, 'foo']; + + //
+ expect(isMatching('div', ['class', 'foo', 'title', 'title'], selector)).toBeTruthy(); + + //
+ expect(isMatching('div', ['title', 'title'], selector)).toBeFalsy(); + + //
+ expect(isMatching('div', ['class', 'foo'], selector)).toBeFalsy(); + }); + }); }); - describe('isNodeMatchingSelectorWithNegations', () => { - function isMatching( - tagName: string, attrs: string[] | null, selector: CssSelectorWithNegations): boolean { - return isNodeMatchingSelectorWithNegations(testLStaticData(tagName, attrs), selector); - } + describe('negations', () => { it('should match when negation part is null', () => { - expect(isMatching('span', null, [['span'], null])).toBeTruthy(); + expect(isMatching('span', null, ['span'])).toBeTruthy(`Selector 'span' should match `); }); it('should not match when negation part does not match', () => { - // not matching ":not(span)" - expect(isMatching('span', ['foo', ''], [null, [['span']]])).toBeFalsy(); - // not matching ":not([foo])" - expect(isMatching('span', ['foo', ''], [['span'], [['', 'foo', '']]])).toBeFalsy(); + expect(isMatching('span', ['foo', ''], [ + '', SelectorFlags.NOT | SelectorFlags.ELEMENT, 'span' + ])).toBeFalsy(`Selector ':not(span)' should NOT match `); + + expect(isMatching('span', ['foo', ''], [ + 'span', SelectorFlags.NOT | SelectorFlags.ATTRIBUTE, 'foo', '' + ])).toBeFalsy(`Selector 'span:not([foo])' should NOT match `); }); + + it('should not match negative selector with tag name and attributes', () => { + // selector: ':not(span[foo])' + const selector = ['', SelectorFlags.NOT | SelectorFlags.ELEMENT, 'span', 'foo', '']; + + // + expect(isMatching('span', ['foo', ''], selector)).toBeFalsy(); + + // + expect(isMatching('span', ['bar', ''], selector)).toBeTruthy(); + }); + + it('should not match negative classes', () => { + // selector: ':not(.foo.bar)' + const selector = ['', SelectorFlags.NOT | SelectorFlags.CLASS, 'foo', 'bar']; + + // + expect(isMatching('span', ['class', 'foo bar'], selector)).toBeFalsy(); + + // + expect(isMatching('span', ['class', 'foo'], selector)).toBeTruthy(); + + // + expect(isMatching('span', ['class', 'bar'], selector)).toBeTruthy(); + }); + + it('should not match negative selector with classes and attributes', () => { + // selector: ':not(.baz[title]) + const selector = [ + '', SelectorFlags.NOT | SelectorFlags.ATTRIBUTE, 'title', '', SelectorFlags.CLASS, 'baz' + ]; + + //
+ expect(isMatching('div', ['class', 'baz'], selector)).toBeTruthy(); + + //
+ expect(isMatching('div', ['title', 'title'], selector)).toBeTruthy(); + + //
+ expect(isMatching('div', ['class', 'baz', 'title', 'title'], selector)).toBeFalsy(); + }); + + it('should not match negative selector with attribute selector after', () => { + // selector: ':not(.baz[title]):not([foo])' + const selector = [ + '', SelectorFlags.NOT | SelectorFlags.ATTRIBUTE, 'title', '', SelectorFlags.CLASS, 'baz', + SelectorFlags.NOT | SelectorFlags.ATTRIBUTE, 'foo', '' + ]; + + //
+ expect(isMatching('div', ['class', 'baz'], selector)).toBeTruthy(); + + //
+ expect(isMatching('div', ['class', 'baz', 'title', ''], selector)).toBeFalsy(); + + //
+ expect(isMatching('div', ['class', 'baz', 'foo', ''], selector)).toBeFalsy(); + }); + + it('should not match with multiple negative selectors', () => { + // selector: ':not(span):not([foo])' + const selector = [ + '', SelectorFlags.NOT | SelectorFlags.ELEMENT, 'span', + SelectorFlags.NOT | SelectorFlags.ATTRIBUTE, 'foo', '' + ]; + + //
+ expect(isMatching('div', ['foo', ''], selector)).toBeFalsy(); + + // + expect(isMatching('span', ['bar', ''], selector)).toBeFalsy(); + + //
+ expect(isMatching('div', ['bar', ''], selector)).toBeTruthy(); + }); + + it('should evaluate complex selector with negative selectors', () => { + // selector: 'div.foo.bar[name=name]:not(.baz):not([title])' + const selector = [ + 'div', 'name', 'name', SelectorFlags.CLASS, 'foo', 'bar', + SelectorFlags.NOT | SelectorFlags.ATTRIBUTE, 'title', '', + SelectorFlags.NOT | SelectorFlags.CLASS, 'baz' + ]; + + //
+ expect(isMatching('div', ['name', 'name', 'class', 'foo bar'], selector)).toBeTruthy(); + + //
+ expect(isMatching('div', ['name', 'name', 'class', 'foo bar baz'], selector)).toBeFalsy(); + + //
+ expect(isMatching('div', ['name', 'name', 'title', '', 'class', 'foo bar'], selector)) + .toBeFalsy(); + }); + }); - describe('isNodeMatchingSelector', () => { + describe('isNodeMatchingSelectorList', () => { - function isMatching(tagName: string, attrs: string[] | null, selector: CssSelector): boolean { - return isNodeMatchingSelector(testLStaticData(tagName, attrs), selector); + function isAnyMatching( + tagName: string, attrs: string[] | null, selector: CssSelectorList): boolean { + return isNodeMatchingSelectorList(testLStaticData(tagName, attrs), selector); } it('should match when there is only one simple selector without negations', () => { - expect(isMatching('span', null, [[['span'], null]])).toBeTruthy(); - expect(isMatching('span', null, [[['div'], null]])).toBeFalsy(); + expect(isAnyMatching('span', null, [['span']])) + .toBeTruthy(`Selector 'span' should match `); + + expect(isAnyMatching('span', null, [['div']])) + .toBeFalsy(`Selector 'div' should NOT match `); }); - it('should atch when there are multiple parts and only one is matching', () => { - // matching "div, [foo=bar]" - expect(isMatching('span', ['foo', 'bar'], [ - [['div'], null], [['', 'foo', 'bar'], null] - ])).toBeTruthy(); + it('should match when there are multiple parts and only one is matching', () => { + expect(isAnyMatching('span', ['foo', 'bar'], [ + ['div'], ['', 'foo', 'bar'] + ])).toBeTruthy(`Selector 'div, [foo=bar]' should match `); }); it('should not match when there are multiple parts and none is matching', () => { - // not matching "div, [foo=baz]" - expect(isMatching('span', ['foo', 'bar'], [ - [['div'], null], [['', 'foo', 'baz'], null] - ])).toBeFalsy(); + expect(isAnyMatching('span', ['foo', 'bar'], [ + ['div'], ['', 'foo', 'baz'] + ])).toBeFalsy(`Selector 'div, [foo=baz]' should NOT match `); }); }); diff --git a/packages/core/test/render3/outputs_spec.ts b/packages/core/test/render3/outputs_spec.ts index 8fc31f2949..1217c18db8 100644 --- a/packages/core/test/render3/outputs_spec.ts +++ b/packages/core/test/render3/outputs_spec.ts @@ -24,7 +24,7 @@ describe('outputs', () => { static ngComponentDef = defineComponent({ type: ButtonToggle, - selector: [[['button-toggle'], null]], + selectors: [['button-toggle']], template: function(ctx: any, cm: boolean) {}, factory: () => buttonToggle = new ButtonToggle(), outputs: {change: 'change', resetStream: 'reset'} @@ -38,7 +38,7 @@ describe('outputs', () => { static ngDirectiveDef = defineDirective({ type: OtherDir, - selector: [[['', 'otherDir', ''], null]], + selectors: [['', 'otherDir', '']], factory: () => otherDir = new OtherDir, outputs: {changeStream: 'change'} }); @@ -50,7 +50,7 @@ describe('outputs', () => { static ngComponentDef = defineComponent({ type: DestroyComp, - selector: [[['destroy-comp'], null]], + selectors: [['destroy-comp']], template: function(ctx: any, cm: boolean) {}, factory: () => destroyComp = new DestroyComp() }); @@ -62,7 +62,7 @@ describe('outputs', () => { static ngDirectiveDef = defineDirective({ type: MyButton, - selector: [[['', 'myButton', ''], null]], + selectors: [['', 'myButton', '']], factory: () => buttonDir = new MyButton, outputs: {click: 'click'} }); @@ -355,7 +355,7 @@ describe('outputs', () => { static ngDirectiveDef = defineDirective({ type: OtherChangeDir, - selector: [[['', 'otherChangeDir', ''], null]], + selectors: [['', 'otherChangeDir', '']], factory: () => otherDir = new OtherChangeDir, inputs: {change: 'change'} }); diff --git a/packages/core/test/render3/pipe_spec.ts b/packages/core/test/render3/pipe_spec.ts index f2a35161fc..de043e1ca5 100644 --- a/packages/core/test/render3/pipe_spec.ts +++ b/packages/core/test/render3/pipe_spec.ts @@ -70,7 +70,7 @@ describe('pipe', () => { static ngDirectiveDef = defineDirective({ type: MyDir, - selector: [[['', 'myDir', ''], null]], + selectors: [['', 'myDir', '']], factory: () => new MyDir(), inputs: {dirProp: 'elprop'} }); diff --git a/packages/core/test/render3/properties_spec.ts b/packages/core/test/render3/properties_spec.ts index 9b9197e887..c7828f0575 100644 --- a/packages/core/test/render3/properties_spec.ts +++ b/packages/core/test/render3/properties_spec.ts @@ -68,7 +68,7 @@ describe('elementProperty', () => { static ngComponentDef = defineComponent({ type: HostBindingComp, - selector: [[['host-binding-comp'], null]], + selectors: [['host-binding-comp']], factory: () => new HostBindingComp(), hostBindings: (dirIndex: number, elIndex: number) => { const instance = loadDirective(dirIndex) as HostBindingComp; @@ -97,7 +97,7 @@ describe('elementProperty', () => { static ngDirectiveDef = defineDirective({ type: MyButton, - selector: [[['', 'myButton', ''], null]], + selectors: [['', 'myButton', '']], factory: () => button = new MyButton(), inputs: {disabled: 'disabled'} }); @@ -109,7 +109,7 @@ describe('elementProperty', () => { static ngDirectiveDef = defineDirective({ type: OtherDir, - selector: [[['', 'otherDir', ''], null]], + selectors: [['', 'otherDir', '']], factory: () => otherDir = new OtherDir(), inputs: {id: 'id'}, outputs: {clickStream: 'click'} @@ -121,7 +121,7 @@ describe('elementProperty', () => { static ngDirectiveDef = defineDirective({ type: OtherDisabledDir, - selector: [[['', 'otherDisabledDir', ''], null]], + selectors: [['', 'otherDisabledDir', '']], factory: () => otherDisabledDir = new OtherDisabledDir(), inputs: {disabled: 'disabled'} }); @@ -132,7 +132,7 @@ describe('elementProperty', () => { static ngDirectiveDef = defineDirective({ type: IdDir, - selector: [[['', 'idDir', ''], null]], + selectors: [['', 'idDir', '']], factory: () => idDir = new IdDir(), inputs: {idNumber: 'id'} }); @@ -207,7 +207,7 @@ describe('elementProperty', () => { static ngComponentDef = defineComponent({ type: Comp, - selector: [[['comp'], null]], + selectors: [['comp']], template: function(ctx: any, cm: boolean) {}, factory: () => comp = new Comp(), inputs: {id: 'id'} @@ -345,7 +345,7 @@ describe('elementProperty', () => { static ngDirectiveDef = defineDirective({ type: MyDir, - selector: [[['', 'myDir', ''], null]], + selectors: [['', 'myDir', '']], factory: () => myDir = new MyDir(), inputs: {role: 'role', direction: 'dir'}, outputs: {changeStream: 'change'}, @@ -359,7 +359,7 @@ describe('elementProperty', () => { static ngDirectiveDef = defineDirective({ type: MyDirB, - selector: [[['', 'myDirB', ''], null]], + selectors: [['', 'myDirB', '']], factory: () => dirB = new MyDirB(), inputs: {roleB: 'role'} }); @@ -527,7 +527,7 @@ describe('elementProperty', () => { class Comp { static ngComponentDef = defineComponent({ type: Comp, - selector: [[['comp'], null]], + selectors: [['comp']], /**
{{ dir.role }} */ template: function(ctx: any, cm: boolean) { if (cm) { diff --git a/packages/core/test/render3/pure_function_spec.ts b/packages/core/test/render3/pure_function_spec.ts index 889607c9f1..50165adf27 100644 --- a/packages/core/test/render3/pure_function_spec.ts +++ b/packages/core/test/render3/pure_function_spec.ts @@ -18,7 +18,7 @@ describe('array literals', () => { static ngComponentDef = defineComponent({ type: MyComp, - selector: [[['my-comp'], null]], + selectors: [['my-comp']], factory: function MyComp_Factory() { return myComp = new MyComp(); }, template: function MyComp_Template(ctx: MyComp, cm: boolean) {}, inputs: {names: 'names'} @@ -69,7 +69,7 @@ describe('array literals', () => { static ngComponentDef = defineComponent({ type: ManyPropComp, - selector: [[['many-prop-comp'], null]], + selectors: [['many-prop-comp']], factory: function ManyPropComp_Factory() { return manyPropComp = new ManyPropComp(); }, template: function ManyPropComp_Template(ctx: ManyPropComp, cm: boolean) {}, inputs: {names1: 'names1', names2: 'names2'} @@ -118,7 +118,7 @@ describe('array literals', () => { static ngComponentDef = defineComponent({ type: ParentComp, - selector: [[['parent-comp'], null]], + selectors: [['parent-comp']], factory: () => new ParentComp(), template: function(ctx: any, cm: boolean) { if (cm) { @@ -313,7 +313,7 @@ describe('object literals', () => { static ngComponentDef = defineComponent({ type: ObjectComp, - selector: [[['object-comp'], null]], + selectors: [['object-comp']], factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); }, template: function ObjectComp_Template(ctx: ObjectComp, cm: boolean) {}, inputs: {config: 'config'} diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index b9a458281e..ad30ed5fc3 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -436,7 +436,7 @@ describe('query', () => { class Child { static ngComponentDef = defineComponent({ type: Child, - selector: [[['child'], null]], + selectors: [['child']], factory: () => childInstance = new Child(), template: (ctx: Child, cm: boolean) => {}, exportAs: 'child' diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 3de933fcef..6c527a9f75 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -197,7 +197,7 @@ export function createComponent( value: any; static ngComponentDef = defineComponent({ type: Component, - selector: [[[name], null]], + selectors: [[name]], factory: () => new Component, template: template, features: [PublicFeature], @@ -212,7 +212,7 @@ export function createDirective( return class Directive { static ngDirectiveDef = defineDirective({ type: Directive, - selector: [[['', name, ''], null]], + selectors: [['', name, '']], factory: () => new Directive(), features: [PublicFeature], exportAs: exportAs, diff --git a/packages/core/test/render3/renderer_factory_spec.ts b/packages/core/test/render3/renderer_factory_spec.ts index 623c96b54e..f1a9d250c9 100644 --- a/packages/core/test/render3/renderer_factory_spec.ts +++ b/packages/core/test/render3/renderer_factory_spec.ts @@ -31,7 +31,7 @@ describe('renderer factory lifecycle', () => { class SomeComponent { static ngComponentDef = defineComponent({ type: SomeComponent, - selector: [[['some-component'], null]], + selectors: [['some-component']], template: function(ctx: SomeComponent, cm: boolean) { logs.push('component'); if (cm) { @@ -45,7 +45,7 @@ describe('renderer factory lifecycle', () => { class SomeComponentWhichThrows { static ngComponentDef = defineComponent({ type: SomeComponentWhichThrows, - selector: [[['some-component-with-Error'], null]], + selectors: [['some-component-with-Error']], template: function(ctx: SomeComponentWhichThrows, cm: boolean) { throw(new Error('SomeComponentWhichThrows threw')); }, @@ -124,7 +124,7 @@ describe('animation renderer factory', () => { class SomeComponent { static ngComponentDef = defineComponent({ type: SomeComponent, - selector: [[['some-component'], null]], + selectors: [['some-component']], template: function(ctx: SomeComponent, cm: boolean) { if (cm) { text(0, 'foo'); @@ -141,7 +141,7 @@ describe('animation renderer factory', () => { } static ngComponentDef = defineComponent({ type: SomeComponentWithAnimation, - selector: [[['some-component'], null]], + selectors: [['some-component']], template: function(ctx: SomeComponentWithAnimation, cm: boolean) { if (cm) { elementStart(0, 'div'); diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index b539a25a90..9b4d72aa27 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -18,7 +18,7 @@ describe('ViewContainerRef', () => { static ngDirectiveDef = defineDirective({ type: TestDirective, - selector: [[['', 'testDir', ''], null]], + selectors: [['', 'testDir', '']], factory: () => new TestDirective(injectViewContainerRef(), injectTemplateRef(), ), }); } @@ -28,7 +28,7 @@ describe('ViewContainerRef', () => { static ngComponentDef = defineComponent({ type: TestComponent, - selector: [[['test-cmp'], null]], + selectors: [['test-cmp']], factory: () => new TestComponent(), template: (cmp: TestComponent, cm: boolean) => { if (cm) {