fix(ivy): queries not being inherited from undecorated classes (#30015)

Fixes view and content queries not being inherited in Ivy, if the base class hasn't been annotated with an Angular decorator (e.g. `Component` or `Directive`).

Also reworks the way the `ngBaseDef` is created so that it is added at the same point as the queries, rather than inside of the `Input` and `Output` decorators.

This PR partially resolves FW-1275. Support for host bindings will be added in a follow-up, because this PR is somewhat large as it is.

PR Close #30015
This commit is contained in:
Kristiyan Kostadinov
2019-04-21 17:37:15 +02:00
committed by Andrew Kushnir
parent 8ca208ff59
commit c7f1b0a97f
15 changed files with 688 additions and 140 deletions

View File

@ -9,12 +9,10 @@
import {ChangeDetectionStrategy} from '../change_detection/constants';
import {Provider} from '../di';
import {Type} from '../interface/type';
import {NG_BASE_DEF} from '../render3/fields';
import {compileComponent as render3CompileComponent, compileDirective as render3CompileDirective} from '../render3/jit/directive';
import {compilePipe as render3CompilePipe} from '../render3/jit/pipe';
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';
import {noop} from '../util/noop';
import {fillProperties} from '../util/property';
import {ViewEncapsulation} from './view';
@ -695,47 +693,12 @@ export interface Input {
bindingPropertyName?: string;
}
const initializeBaseDef = (target: any): void => {
const constructor = target.constructor;
const inheritedBaseDef = constructor.ngBaseDef;
const baseDef = constructor.ngBaseDef = {
inputs: {},
outputs: {},
declaredInputs: {},
};
if (inheritedBaseDef) {
fillProperties(baseDef.inputs, inheritedBaseDef.inputs);
fillProperties(baseDef.outputs, inheritedBaseDef.outputs);
fillProperties(baseDef.declaredInputs, inheritedBaseDef.declaredInputs);
}
};
/**
* Does the work of creating the `ngBaseDef` property for the `Input` and `Output` decorators.
* @param key "inputs" or "outputs"
*/
const updateBaseDefFromIOProp = (getProp: (baseDef: {inputs?: any, outputs?: any}) => any) =>
(target: any, name: string, ...args: any[]) => {
const constructor = target.constructor;
if (!constructor.hasOwnProperty(NG_BASE_DEF)) {
initializeBaseDef(target);
}
const baseDef = constructor.ngBaseDef;
const defProp = getProp(baseDef);
defProp[name] = args[0] || name;
};
/**
* @Annotation
* @publicApi
*/
export const Input: InputDecorator = makePropDecorator(
'Input', (bindingPropertyName?: string) => ({bindingPropertyName}), undefined,
updateBaseDefFromIOProp(baseDef => baseDef.inputs || {}));
export const Input: InputDecorator =
makePropDecorator('Input', (bindingPropertyName?: string) => ({bindingPropertyName}));
/**
* Type of the Output decorator / constructor function.
@ -777,9 +740,8 @@ export interface Output {
* @Annotation
* @publicApi
*/
export const Output: OutputDecorator = makePropDecorator(
'Output', (bindingPropertyName?: string) => ({bindingPropertyName}), undefined,
updateBaseDefFromIOProp(baseDef => baseDef.outputs || {}));
export const Output: OutputDecorator =
makePropDecorator('Output', (bindingPropertyName?: string) => ({bindingPropertyName}));