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

@ -37,6 +37,8 @@ export interface CompilerFacade {
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3DirectiveMetadataFacade): any;
compileComponent(
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any;
compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3BaseMetadataFacade):
any;
createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan;
@ -146,6 +148,13 @@ export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade {
changeDetection?: ChangeDetectionStrategy;
}
export interface R3BaseMetadataFacade {
inputs?: {[key: string]: string | [string, string]};
outputs?: {[key: string]: string};
queries?: R3QueryMetadataFacade[];
viewQueries?: R3QueryMetadataFacade[];
}
export type ViewEncapsulation = number;
export type ChangeDetectionStrategy = number;

View File

@ -7,7 +7,7 @@
*/
import {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, R3ComponentMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface';
import {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, R3BaseMetadataFacade, R3ComponentMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface';
import {ConstantPool} from './constant_pool';
import {HostBinding, HostListener, Input, Output, Type} from './core';
import {compileInjectable} from './injectable_compiler_2';
@ -21,7 +21,7 @@ import {R3InjectorMetadata, R3NgModuleMetadata, compileInjector, compileNgModule
import {compilePipeFromMetadata} from './render3/r3_pipe_compiler';
import {R3Reference} from './render3/util';
import {R3DirectiveMetadata, R3QueryMetadata} from './render3/view/api';
import {ParsedHostBindings, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings} from './render3/view/compiler';
import {ParsedHostBindings, compileBaseDefFromMetadata, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings} from './render3/view/compiler';
import {makeBindingParser, parseTemplate} from './render3/view/template';
import {ResourceLoader} from './resource_loader';
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
@ -151,6 +151,20 @@ export class CompilerFacadeImpl implements CompilerFacade {
res.expression, angularCoreEnv, `ng:///${facade.name}.js`, preStatements);
}
compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, facade: R3BaseMetadataFacade):
any {
const constantPool = new ConstantPool();
const meta = {
...facade,
viewQueries: facade.viewQueries ? facade.viewQueries.map(convertToR3QueryMetadata) :
facade.viewQueries,
queries: facade.queries ? facade.queries.map(convertToR3QueryMetadata) : facade.queries
};
const res = compileBaseDefFromMetadata(meta, constantPool);
return this.jitExpression(
res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
}
createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan {
return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
}

View File

@ -66,11 +66,13 @@ function baseDirectiveFields(
if (meta.queries.length > 0) {
// e.g. `contentQueries: (rf, ctx, dirIndex) => { ... }
definitionMap.set('contentQueries', createContentQueriesFunction(meta, constantPool));
definitionMap.set(
'contentQueries', createContentQueriesFunction(meta.queries, constantPool, meta.name));
}
if (meta.viewQueries.length) {
definitionMap.set('viewQuery', createViewQueriesFunction(meta, constantPool));
definitionMap.set(
'viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name));
}
// Initialize hostVarsCount to number of bound host properties (interpolations illegal),
@ -163,13 +165,15 @@ export function compileDirectiveFromMetadata(
export interface R3BaseRefMetaData {
inputs?: {[key: string]: string | [string, string]};
outputs?: {[key: string]: string};
viewQueries?: R3QueryMetadata[];
queries?: R3QueryMetadata[];
}
/**
* Compile a base definition for the render3 runtime as defined by {@link R3BaseRefMetadata}
* @param meta the metadata used for compilation.
*/
export function compileBaseDefFromMetadata(meta: R3BaseRefMetaData) {
export function compileBaseDefFromMetadata(meta: R3BaseRefMetaData, constantPool: ConstantPool) {
const definitionMap = new DefinitionMap();
if (meta.inputs) {
const inputs = meta.inputs;
@ -188,9 +192,14 @@ export function compileBaseDefFromMetadata(meta: R3BaseRefMetaData) {
});
definitionMap.set('outputs', o.literalMap(outputsMap));
}
if (meta.viewQueries && meta.viewQueries.length > 0) {
definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool));
}
if (meta.queries && meta.queries.length > 0) {
definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool));
}
const expression = o.importExpr(R3.defineBase).callFn([definitionMap.toLiteralMap()]);
const type = new o.ExpressionType(o.importExpr(R3.BaseDef));
return {expression, type};
@ -475,12 +484,12 @@ function convertAttributesToExpressions(attributes: {[name: string]: o.Expressio
// Define and update any content queries
function createContentQueriesFunction(
meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression {
queries: R3QueryMetadata[], constantPool: ConstantPool, name?: string): o.Expression {
const createStatements: o.Statement[] = [];
const updateStatements: o.Statement[] = [];
const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
for (const query of meta.queries) {
for (const query of queries) {
// creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null);
const args = [o.variable('dirIndex'), ...prepareQueryParams(query, constantPool) as any];
@ -498,7 +507,7 @@ function createContentQueriesFunction(
updateStatements.push(refresh.and(updateDirective).toStmt());
}
const contentQueriesFnName = meta.name ? `${meta.name}_ContentQueries` : null;
const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
return o.fn(
[
new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null),
@ -549,12 +558,12 @@ function createTypeForDef(meta: R3DirectiveMetadata, typeBase: o.ExternalReferen
// Define and update any view queries
function createViewQueriesFunction(
meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression {
viewQueries: R3QueryMetadata[], constantPool: ConstantPool, name?: string): o.Expression {
const createStatements: o.Statement[] = [];
const updateStatements: o.Statement[] = [];
const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
meta.viewQueries.forEach((query: R3QueryMetadata) => {
viewQueries.forEach((query: R3QueryMetadata) => {
const queryInstruction = query.static ? R3.staticViewQuery : R3.viewQuery;
// creation, e.g. r3.viewQuery(somePredicate, true);
@ -572,7 +581,7 @@ function createViewQueriesFunction(
updateStatements.push(refresh.and(updateDirective).toStmt());
});
const viewQueryFnName = meta.name ? `${meta.name}_Query` : null;
const viewQueryFnName = name ? `${name}_Query` : null;
return o.fn(
[new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null)],
[