fix(ivy): update content query compilation to latest runtime (#24957)
PR Close #24957
This commit is contained in:
parent
edef58f466
commit
13f3157823
|
@ -987,7 +987,7 @@ describe('compiler compliance', () => {
|
|||
app: {
|
||||
...directive,
|
||||
'spec.ts': `
|
||||
import {Component, ContentChild, NgModule} from '@angular/core';
|
||||
import {Component, ContentChild, ContentChildren, NgModule, QueryList} from '@angular/core';
|
||||
import {SomeDirective} from './some.directive';
|
||||
|
||||
@Component({
|
||||
|
@ -998,6 +998,7 @@ describe('compiler compliance', () => {
|
|||
})
|
||||
export class ContentQueryComponent {
|
||||
@ContentChild(SomeDirective) someDir: SomeDirective;
|
||||
@ContentChildren(SomeDirective) someDirList !: QueryList<SomeDirective>;
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
@ -1021,11 +1022,17 @@ describe('compiler compliance', () => {
|
|||
type: ContentQueryComponent,
|
||||
selectors: [["content-query-component"]],
|
||||
factory: function ContentQueryComponent_Factory() {
|
||||
return [new ContentQueryComponent(), $r3$.ɵQ(null, SomeDirective, true)];
|
||||
return new ContentQueryComponent();
|
||||
},
|
||||
hostBindings: function ContentQueryComponent_HostBindings(dirIndex, elIndex) {
|
||||
contentQueries: function ContentQueryComponent_ContentQueries() {
|
||||
$r3$.ɵQr($r3$.ɵQ(null, SomeDirective, true));
|
||||
$r3$.ɵQr($r3$.ɵQ(null, SomeDirective, false));
|
||||
},
|
||||
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
||||
const instance = $r3$.ɵd(dirIndex);
|
||||
var $tmp$;
|
||||
($r3$.ɵqR(($tmp$ = $r3$.ɵd(dirIndex)[1])) && ($r3$.ɵd(dirIndex)[0].someDir = $tmp$.first));
|
||||
($r3$.ɵqR(($tmp$ = $r3$.ɵql(queryStartIndex))) && ($instance$.someDir = $tmp$.first));
|
||||
($r3$.ɵqR(($tmp$ = $r3$.ɵql((queryStartIndex + 1)))) && ($instance$.someDirList = $tmp$));
|
||||
},
|
||||
template: function ContentQueryComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
|
|
|
@ -54,16 +54,6 @@ export interface R3FactoryMetadata {
|
|||
* function could be different, and other options control how it will be invoked.
|
||||
*/
|
||||
injectFn: o.ExternalReference;
|
||||
|
||||
/**
|
||||
* If present, the return of the factory function will be an array with the injected value in the
|
||||
* 0th position and the extra results included in subsequent positions.
|
||||
*
|
||||
* Occasionally APIs want to construct additional values when the factory function is called. The
|
||||
* paradigm there is to have the factory function return an array, with the DI-created value as
|
||||
* well as other values. Specifying `extraResults` enables this functionality.
|
||||
*/
|
||||
extraResults?: o.Expression[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,12 +150,8 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): o.Expression {
|
|||
const expr = meta.useNew ? new o.InstantiateExpr(meta.fnOrClass, args) :
|
||||
new o.InvokeFunctionExpr(meta.fnOrClass, args);
|
||||
|
||||
// If `extraResults` is specified, then the result is an array consisting of the instantiated
|
||||
// value plus any extra results.
|
||||
const retExpr =
|
||||
meta.extraResults === undefined ? expr : o.literalArr([expr, ...meta.extraResults]);
|
||||
return o.fn(
|
||||
[], [new o.ReturnStatement(retExpr)], o.INFERRED_TYPE, undefined, `${meta.name}_Factory`);
|
||||
[], [new o.ReturnStatement(expr)], o.INFERRED_TYPE, undefined, `${meta.name}_Factory`);
|
||||
}
|
||||
|
||||
function compileInjectDependency(
|
||||
|
|
|
@ -80,6 +80,7 @@ export class Identifiers {
|
|||
|
||||
static load: o.ExternalReference = {name: 'ɵld', moduleName: CORE};
|
||||
static loadDirective: o.ExternalReference = {name: 'ɵd', moduleName: CORE};
|
||||
static loadQueryList: o.ExternalReference = {name: 'ɵql', moduleName: CORE};
|
||||
|
||||
static pipe: o.ExternalReference = {name: 'ɵPp', moduleName: CORE};
|
||||
|
||||
|
@ -142,6 +143,7 @@ export class Identifiers {
|
|||
|
||||
static query: o.ExternalReference = {name: 'ɵQ', moduleName: CORE};
|
||||
static queryRefresh: o.ExternalReference = {name: 'ɵqR', moduleName: CORE};
|
||||
static registerContentQuery: o.ExternalReference = {name: 'ɵQr', moduleName: CORE};
|
||||
|
||||
static NgOnChangesFeature: o.ExternalReference = {name: 'ɵNgOnChangesFeature', moduleName: CORE};
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ function baseDirectiveFields(
|
|||
// e.g. `selectors: [['', 'someDir', '']]`
|
||||
definitionMap.set('selectors', createDirectiveSelector(meta.selector !));
|
||||
|
||||
const queryDefinitions = createQueryDefinitions(meta.queries, constantPool);
|
||||
|
||||
// e.g. `factory: () => new MyApp(injectElementRef())`
|
||||
definitionMap.set('factory', compileFactoryFunction({
|
||||
|
@ -50,9 +49,12 @@ function baseDirectiveFields(
|
|||
deps: meta.deps,
|
||||
useNew: true,
|
||||
injectFn: R3.directiveInject,
|
||||
extraResults: queryDefinitions,
|
||||
}));
|
||||
|
||||
definitionMap.set('contentQueries', createContentQueriesFunction(meta, constantPool));
|
||||
|
||||
definitionMap.set('contentQueriesRefresh', createContentQueriesRefreshFunction(meta));
|
||||
|
||||
// e.g. `hostBindings: (dirIndex, elIndex) => { ... }
|
||||
definitionMap.set('hostBindings', createHostBindingsFunction(meta, bindingParser));
|
||||
|
||||
|
@ -366,32 +368,71 @@ function createHostAttributesArray(meta: R3DirectiveMetadata): o.Expression|null
|
|||
return null;
|
||||
}
|
||||
|
||||
// Return a contentQueries function or null if one is not necessary.
|
||||
function createContentQueriesFunction(
|
||||
meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression|null {
|
||||
const queryDefinitions = createQueryDefinitions(meta.queries, constantPool);
|
||||
|
||||
if (queryDefinitions) {
|
||||
const statements: o.Statement[] = queryDefinitions.map((qd: o.Expression) => {
|
||||
return o.importExpr(R3.registerContentQuery).callFn([qd]).toStmt();
|
||||
});
|
||||
const typeName = meta.name;
|
||||
return o.fn(
|
||||
[], statements, o.INFERRED_TYPE, null, typeName ? `${typeName}_ContentQueries` : null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Return a contentQueriesRefresh function or null if one is not necessary.
|
||||
function createContentQueriesRefreshFunction(meta: R3DirectiveMetadata): o.Expression|null {
|
||||
if (meta.queries.length > 0) {
|
||||
const statements: o.Statement[] = [];
|
||||
const typeName = meta.name;
|
||||
const parameters = [
|
||||
new o.FnParam('dirIndex', o.NUMBER_TYPE),
|
||||
new o.FnParam('queryStartIndex', o.NUMBER_TYPE),
|
||||
];
|
||||
const directiveInstanceVar = o.variable('instance');
|
||||
// var $tmp$: any;
|
||||
const temporary = temporaryAllocator(statements, TEMPORARY_NAME);
|
||||
|
||||
// const $instance$ = $r3$.ɵd(dirIndex);
|
||||
statements.push(
|
||||
directiveInstanceVar.set(o.importExpr(R3.loadDirective).callFn([o.variable('dirIndex')]))
|
||||
.toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||
|
||||
meta.queries.forEach((query: R3QueryMetadata, idx: number) => {
|
||||
const loadQLArg = o.variable('queryStartIndex');
|
||||
const getQueryList = o.importExpr(R3.loadQueryList).callFn([
|
||||
idx > 0 ? loadQLArg.plus(o.literal(idx)) : loadQLArg
|
||||
]);
|
||||
const assignToTemporary = temporary().set(getQueryList);
|
||||
const callQueryRefresh = o.importExpr(R3.queryRefresh).callFn([assignToTemporary]);
|
||||
|
||||
const updateDirective = directiveInstanceVar.prop(query.propertyName)
|
||||
.set(query.first ? temporary().prop('first') : temporary());
|
||||
const refreshQueryAndUpdateDirective = callQueryRefresh.and(updateDirective);
|
||||
|
||||
statements.push(refreshQueryAndUpdateDirective.toStmt());
|
||||
});
|
||||
|
||||
return o.fn(
|
||||
parameters, statements, o.INFERRED_TYPE, null,
|
||||
typeName ? `${typeName}_ContentQueriesRefresh` : null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Return a host binding function or null if one is not necessary.
|
||||
function createHostBindingsFunction(
|
||||
meta: R3DirectiveMetadata, bindingParser: BindingParser): o.Expression|null {
|
||||
const statements: o.Statement[] = [];
|
||||
|
||||
const temporary = temporaryAllocator(statements, TEMPORARY_NAME);
|
||||
|
||||
const hostBindingSourceSpan = meta.typeSourceSpan;
|
||||
|
||||
// Calculate the queries
|
||||
for (let index = 0; index < meta.queries.length; index++) {
|
||||
const query = meta.queries[index];
|
||||
|
||||
// e.g. r3.qR(tmp = r3.d(dirIndex)[1]) && (r3.d(dirIndex)[0].someDir = tmp);
|
||||
const getDirectiveMemory = o.importExpr(R3.loadDirective).callFn([o.variable('dirIndex')]);
|
||||
// The query list is at the query index + 1 because the directive itself is in slot 0.
|
||||
const getQueryList = getDirectiveMemory.key(o.literal(index + 1));
|
||||
const assignToTemporary = temporary().set(getQueryList);
|
||||
const callQueryRefresh = o.importExpr(R3.queryRefresh).callFn([assignToTemporary]);
|
||||
const updateDirective = getDirectiveMemory.key(o.literal(0, o.INFERRED_TYPE))
|
||||
.prop(query.propertyName)
|
||||
.set(query.first ? temporary().prop('first') : temporary());
|
||||
const andExpression = callQueryRefresh.and(updateDirective);
|
||||
statements.push(andExpression.toStmt());
|
||||
}
|
||||
|
||||
const directiveSummary = metadataAsSummary(meta);
|
||||
|
||||
// Calculate the host property bindings
|
||||
|
|
|
@ -38,6 +38,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
|||
'ɵcR': r3.cR,
|
||||
'ɵcr': r3.cr,
|
||||
'ɵd': r3.d,
|
||||
'ɵql': r3.ql,
|
||||
'ɵNH': r3.NH,
|
||||
'ɵNM': r3.NM,
|
||||
'ɵNS': r3.NS,
|
||||
|
@ -77,6 +78,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
|||
'ɵPp': r3.Pp,
|
||||
'ɵQ': r3.Q,
|
||||
'ɵqR': r3.qR,
|
||||
'ɵQr': r3.Qr,
|
||||
'ɵrS': r3.rS,
|
||||
'ɵs': r3.s,
|
||||
'ɵsm': r3.sm,
|
||||
|
|
Loading…
Reference in New Issue