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: {
|
app: {
|
||||||
...directive,
|
...directive,
|
||||||
'spec.ts': `
|
'spec.ts': `
|
||||||
import {Component, ContentChild, NgModule} from '@angular/core';
|
import {Component, ContentChild, ContentChildren, NgModule, QueryList} from '@angular/core';
|
||||||
import {SomeDirective} from './some.directive';
|
import {SomeDirective} from './some.directive';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -998,6 +998,7 @@ describe('compiler compliance', () => {
|
||||||
})
|
})
|
||||||
export class ContentQueryComponent {
|
export class ContentQueryComponent {
|
||||||
@ContentChild(SomeDirective) someDir: SomeDirective;
|
@ContentChild(SomeDirective) someDir: SomeDirective;
|
||||||
|
@ContentChildren(SomeDirective) someDirList !: QueryList<SomeDirective>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1021,11 +1022,17 @@ describe('compiler compliance', () => {
|
||||||
type: ContentQueryComponent,
|
type: ContentQueryComponent,
|
||||||
selectors: [["content-query-component"]],
|
selectors: [["content-query-component"]],
|
||||||
factory: function ContentQueryComponent_Factory() {
|
factory: function ContentQueryComponent_Factory() {
|
||||||
return [new ContentQueryComponent(), $r3$.ɵQ(null, SomeDirective, true)];
|
return new ContentQueryComponent();
|
||||||
|
},
|
||||||
|
contentQueries: function ContentQueryComponent_ContentQueries() {
|
||||||
|
$r3$.ɵQr($r3$.ɵQ(null, SomeDirective, true));
|
||||||
|
$r3$.ɵQr($r3$.ɵQ(null, SomeDirective, false));
|
||||||
},
|
},
|
||||||
hostBindings: function ContentQueryComponent_HostBindings(dirIndex, elIndex) {
|
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
||||||
|
const instance = $r3$.ɵd(dirIndex);
|
||||||
var $tmp$;
|
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) {
|
template: function ContentQueryComponent_Template(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
|
|
|
@ -54,16 +54,6 @@ export interface R3FactoryMetadata {
|
||||||
* function could be different, and other options control how it will be invoked.
|
* function could be different, and other options control how it will be invoked.
|
||||||
*/
|
*/
|
||||||
injectFn: o.ExternalReference;
|
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) :
|
const expr = meta.useNew ? new o.InstantiateExpr(meta.fnOrClass, args) :
|
||||||
new o.InvokeFunctionExpr(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(
|
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(
|
function compileInjectDependency(
|
||||||
|
|
|
@ -80,6 +80,7 @@ export class Identifiers {
|
||||||
|
|
||||||
static load: o.ExternalReference = {name: 'ɵld', moduleName: CORE};
|
static load: o.ExternalReference = {name: 'ɵld', moduleName: CORE};
|
||||||
static loadDirective: o.ExternalReference = {name: 'ɵd', 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};
|
static pipe: o.ExternalReference = {name: 'ɵPp', moduleName: CORE};
|
||||||
|
|
||||||
|
@ -142,6 +143,7 @@ export class Identifiers {
|
||||||
|
|
||||||
static query: o.ExternalReference = {name: 'ɵQ', moduleName: CORE};
|
static query: o.ExternalReference = {name: 'ɵQ', moduleName: CORE};
|
||||||
static queryRefresh: o.ExternalReference = {name: 'ɵqR', 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};
|
static NgOnChangesFeature: o.ExternalReference = {name: 'ɵNgOnChangesFeature', moduleName: CORE};
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ function baseDirectiveFields(
|
||||||
// e.g. `selectors: [['', 'someDir', '']]`
|
// e.g. `selectors: [['', 'someDir', '']]`
|
||||||
definitionMap.set('selectors', createDirectiveSelector(meta.selector !));
|
definitionMap.set('selectors', createDirectiveSelector(meta.selector !));
|
||||||
|
|
||||||
const queryDefinitions = createQueryDefinitions(meta.queries, constantPool);
|
|
||||||
|
|
||||||
// e.g. `factory: () => new MyApp(injectElementRef())`
|
// e.g. `factory: () => new MyApp(injectElementRef())`
|
||||||
definitionMap.set('factory', compileFactoryFunction({
|
definitionMap.set('factory', compileFactoryFunction({
|
||||||
|
@ -50,9 +49,12 @@ function baseDirectiveFields(
|
||||||
deps: meta.deps,
|
deps: meta.deps,
|
||||||
useNew: true,
|
useNew: true,
|
||||||
injectFn: R3.directiveInject,
|
injectFn: R3.directiveInject,
|
||||||
extraResults: queryDefinitions,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
definitionMap.set('contentQueries', createContentQueriesFunction(meta, constantPool));
|
||||||
|
|
||||||
|
definitionMap.set('contentQueriesRefresh', createContentQueriesRefreshFunction(meta));
|
||||||
|
|
||||||
// e.g. `hostBindings: (dirIndex, elIndex) => { ... }
|
// e.g. `hostBindings: (dirIndex, elIndex) => { ... }
|
||||||
definitionMap.set('hostBindings', createHostBindingsFunction(meta, bindingParser));
|
definitionMap.set('hostBindings', createHostBindingsFunction(meta, bindingParser));
|
||||||
|
|
||||||
|
@ -366,32 +368,71 @@ function createHostAttributesArray(meta: R3DirectiveMetadata): o.Expression|null
|
||||||
return 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.
|
// Return a host binding function or null if one is not necessary.
|
||||||
function createHostBindingsFunction(
|
function createHostBindingsFunction(
|
||||||
meta: R3DirectiveMetadata, bindingParser: BindingParser): o.Expression|null {
|
meta: R3DirectiveMetadata, bindingParser: BindingParser): o.Expression|null {
|
||||||
const statements: o.Statement[] = [];
|
const statements: o.Statement[] = [];
|
||||||
|
|
||||||
const temporary = temporaryAllocator(statements, TEMPORARY_NAME);
|
|
||||||
|
|
||||||
const hostBindingSourceSpan = meta.typeSourceSpan;
|
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);
|
const directiveSummary = metadataAsSummary(meta);
|
||||||
|
|
||||||
// Calculate the host property bindings
|
// Calculate the host property bindings
|
||||||
|
|
|
@ -38,6 +38,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||||
'ɵcR': r3.cR,
|
'ɵcR': r3.cR,
|
||||||
'ɵcr': r3.cr,
|
'ɵcr': r3.cr,
|
||||||
'ɵd': r3.d,
|
'ɵd': r3.d,
|
||||||
|
'ɵql': r3.ql,
|
||||||
'ɵNH': r3.NH,
|
'ɵNH': r3.NH,
|
||||||
'ɵNM': r3.NM,
|
'ɵNM': r3.NM,
|
||||||
'ɵNS': r3.NS,
|
'ɵNS': r3.NS,
|
||||||
|
@ -77,6 +78,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||||
'ɵPp': r3.Pp,
|
'ɵPp': r3.Pp,
|
||||||
'ɵQ': r3.Q,
|
'ɵQ': r3.Q,
|
||||||
'ɵqR': r3.qR,
|
'ɵqR': r3.qR,
|
||||||
|
'ɵQr': r3.Qr,
|
||||||
'ɵrS': r3.rS,
|
'ɵrS': r3.rS,
|
||||||
'ɵs': r3.s,
|
'ɵs': r3.s,
|
||||||
'ɵsm': r3.sm,
|
'ɵsm': r3.sm,
|
||||||
|
|
Loading…
Reference in New Issue