Skip to content

Commit

Permalink
feat(ivy): add query inheritance
Browse files Browse the repository at this point in the history
Adds inheritance handling for the following:

- viewQuery
- contentQueries
- contentQueriesRefresh
  • Loading branch information
benlesh committed Aug 17, 2018
1 parent e9026a5 commit 7b099ed
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 89 deletions.
49 changes: 48 additions & 1 deletion packages/core/src/render3/features/inherit_definition_feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Type} from '../../type';
import {fillProperties} from '../../util/property';
import {ComponentDefInternal, DirectiveDefFeature, DirectiveDefInternal} from '../interfaces/definition';
import {ComponentDefInternal, DirectiveDefFeature, DirectiveDefInternal, RenderFlags} from '../interfaces/definition';


/**
Expand Down Expand Up @@ -68,6 +68,53 @@ export function InheritDefinitionFeature(
}
}

// Merge View Queries
if (isComponentDef(definition) && isComponentDef(superDef)) {
const prevViewQuery = definition.viewQuery;
const superViewQuery = superDef.viewQuery;
if (superViewQuery) {
if (prevViewQuery) {
// tslint:disable-next-line:no-any viewQuery is readonly, but we need to set it
(definition as any).viewQuery = <T>(rf: RenderFlags, ctx: T): void => {
superViewQuery(rf, ctx);
prevViewQuery(rf, ctx);
};
} else {
// tslint:disable-next-line:no-any viewQuery is readonly, but we need to set it
(definition as any).viewQuery = superViewQuery;
}
}
}

// Merge Content Queries
const prevContentQueries = definition.contentQueries;
const superContentQueries = superDef.contentQueries;
if (superContentQueries) {
if (prevContentQueries) {
definition.contentQueries = () => {
superContentQueries();
prevContentQueries();
};
} else {
definition.contentQueries = superContentQueries;
}
}

// Merge Content Queries Refresh
const prevContentQueriesRefresh = definition.contentQueriesRefresh;
const superContentQueriesRefresh = superDef.contentQueriesRefresh;
if (superContentQueriesRefresh) {
if (prevContentQueriesRefresh) {
definition.contentQueriesRefresh = (directiveIndex: number, queryIndex: number) => {
superContentQueriesRefresh(directiveIndex, queryIndex);
prevContentQueriesRefresh(directiveIndex, queryIndex);
};
} else {
definition.contentQueriesRefresh = superContentQueriesRefresh;
}
}


// Merge inputs and outputs
fillProperties(definition.inputs, superDef.inputs);
fillProperties(definition.declaredInputs, superDef.declaredInputs);
Expand Down
87 changes: 0 additions & 87 deletions packages/core/test/bundling/hello_world/bundle.golden_symbols.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
{
"name": "BINDING_INDEX"
},
{
"name": "BLOOM_MASK"
},
{
"name": "CLEAN_PROMISE"
},
Expand All @@ -17,18 +14,9 @@
{
"name": "CONTEXT"
},
{
"name": "ChangeDetectionStrategy"
},
{
"name": "DIRECTIVES"
},
{
"name": "EMPTY$1"
},
{
"name": "EMPTY_ARRAY"
},
{
"name": "FLAGS"
},
Expand All @@ -47,9 +35,6 @@
{
"name": "NEXT"
},
{
"name": "NG_ELEMENT_ID"
},
{
"name": "NG_HOST_SYMBOL"
},
Expand All @@ -59,18 +44,12 @@
{
"name": "PARENT"
},
{
"name": "PublicFeature"
},
{
"name": "QUERIES"
},
{
"name": "RENDERER"
},
{
"name": "RENDER_PARENT"
},
{
"name": "ROOT_DIRECTIVE_INDICES"
},
Expand All @@ -89,30 +68,12 @@
{
"name": "_getComponentHostLElementNode"
},
{
"name": "_renderCompCount"
},
{
"name": "appendChild"
},
{
"name": "baseDirectiveCreate"
},
{
"name": "bloomAdd"
},
{
"name": "callHooks"
},
{
"name": "canInsertNativeChildOfElement"
},
{
"name": "canInsertNativeChildOfView"
},
{
"name": "canInsertNativeNode"
},
{
"name": "checkNoChangesMode"
},
Expand All @@ -137,24 +98,12 @@
{
"name": "createTView"
},
{
"name": "createTextNode"
},
{
"name": "createViewQuery"
},
{
"name": "defineComponent"
},
{
"name": "detectChangesInternal"
},
{
"name": "diPublic"
},
{
"name": "diPublicInInjector"
},
{
"name": "domRendererFactory3"
},
Expand All @@ -170,42 +119,21 @@
{
"name": "executeInitHooks"
},
{
"name": "extractDirectiveDef"
},
{
"name": "extractPipeDef"
},
{
"name": "firstTemplatePass"
},
{
"name": "getChildLNode"
},
{
"name": "getLViewChild"
},
{
"name": "getOrCreateNodeInjector"
},
{
"name": "getOrCreateNodeInjectorForNode"
},
{
"name": "getOrCreateTView"
},
{
"name": "getParentLNode"
},
{
"name": "getPreviousOrParentNode"
},
{
"name": "getRenderFlags"
},
{
"name": "getRenderParent"
},
{
"name": "getRootView"
},
Expand All @@ -215,9 +143,6 @@
{
"name": "initChangeDetectorIfExisting"
},
{
"name": "invertObject"
},
{
"name": "isProceduralRenderer"
},
Expand All @@ -230,12 +155,6 @@
{
"name": "namespaceHTML"
},
{
"name": "nativeInsertBefore"
},
{
"name": "nextNgElementId"
},
{
"name": "readElementValue"
},
Expand Down Expand Up @@ -269,12 +188,6 @@
{
"name": "setUpAttributes"
},
{
"name": "stringify$2"
},
{
"name": "text"
},
{
"name": "tickRootContext"
},
Expand Down
107 changes: 106 additions & 1 deletion packages/core/test/render3/Inherit_definition_feature_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {EventEmitter, Output} from '../../src/core';
import {InheritDefinitionFeature} from '../../src/render3/features/inherit_definition_feature';
import {DirectiveDefInternal, defineBase, defineComponent, defineDirective} from '../../src/render3/index';
import {ComponentDefInternal, DirectiveDefInternal, RenderFlags, defineBase, defineComponent, defineDirective} from '../../src/render3/index';

describe('InheritDefinitionFeature', () => {
it('should inherit lifecycle hooks', () => {
Expand Down Expand Up @@ -307,6 +307,111 @@ describe('InheritDefinitionFeature', () => {
expect(log).toEqual([['super', 1, 2], ['sub', 1, 2]]);
});

it('should compose viewQuery', () => {
const log: Array<[string, RenderFlags, any]> = [];

// tslint:disable-next-line:class-as-namespace
class SuperComponent {
static ngComponentDef = defineComponent({
type: SuperComponent,
template: () => {},
selectors: [['', 'superDir', '']],
viewQuery: <T>(rf: RenderFlags, ctx: T) => {
log.push(['super', rf, ctx]);
},
factory: () => new SuperComponent(),
});
}

// tslint:disable-next-line:class-as-namespace
class SubComponent extends SuperComponent {
static ngComponentDef = defineComponent({
type: SubComponent,
template: () => {},
selectors: [['', 'subDir', '']],
viewQuery: (directiveIndex: number, elementIndex: number) => {
log.push(['sub', directiveIndex, elementIndex]);
},
factory: () => new SubComponent(),
features: [InheritDefinitionFeature]
});
}

const subDef = SubComponent.ngComponentDef as ComponentDefInternal<any>;

const context = {foo: 'bar'};

subDef.viewQuery !(1, context);

expect(log).toEqual([['super', 1, context], ['sub', 1, context]]);
});

it('should compose contentQueries', () => {
const log: string[] = [];

// tslint:disable-next-line:class-as-namespace
class SuperDirective {
static ngDirectiveDef = defineDirective({
type: SuperDirective,
selectors: [['', 'superDir', '']],
contentQueries: () => { log.push('super'); },
factory: () => new SuperDirective(),
});
}

// tslint:disable-next-line:class-as-namespace
class SubDirective extends SuperDirective {
static ngDirectiveDef = defineDirective({
type: SubDirective,
selectors: [['', 'subDir', '']],
contentQueries: () => { log.push('sub'); },
factory: () => new SubDirective(),
features: [InheritDefinitionFeature]
});
}

const subDef = SubDirective.ngDirectiveDef as DirectiveDefInternal<any>;

subDef.contentQueries !();

expect(log).toEqual(['super', 'sub']);
});

it('should compose contentQueriesRefresh', () => {
const log: Array<[string, number, number]> = [];

// tslint:disable-next-line:class-as-namespace
class SuperDirective {
static ngDirectiveDef = defineDirective({
type: SuperDirective,
selectors: [['', 'superDir', '']],
contentQueriesRefresh: (directiveIndex: number, queryIndex: number) => {
log.push(['super', directiveIndex, queryIndex]);
},
factory: () => new SuperDirective(),
});
}

// tslint:disable-next-line:class-as-namespace
class SubDirective extends SuperDirective {
static ngDirectiveDef = defineDirective({
type: SubDirective,
selectors: [['', 'subDir', '']],
contentQueriesRefresh: (directiveIndex: number, queryIndex: number) => {
log.push(['sub', directiveIndex, queryIndex]);
},
factory: () => new SubDirective(),
features: [InheritDefinitionFeature]
});
}

const subDef = SubDirective.ngDirectiveDef as DirectiveDefInternal<any>;

subDef.contentQueriesRefresh !(1, 2);

expect(log).toEqual([['super', 1, 2], ['sub', 1, 2]]);
});

it('should throw if inheriting a component from a directive', () => {
// tslint:disable-next-line:class-as-namespace
class SuperComponent {
Expand Down

0 comments on commit 7b099ed

Please sign in to comment.