fix(ivy): local refs in View and Content Queries should be pulled out into consts in generated code (#26240)
PR Close #26240
This commit is contained in:
parent
d1b7bb52e7
commit
d5e9405d4f
|
@ -1150,11 +1150,12 @@ describe('compiler compliance', () => {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'view-query-component',
|
selector: 'view-query-component',
|
||||||
template: \`
|
template: \`
|
||||||
<div someDir></div>
|
<div someDir></div>
|
||||||
\`
|
\`
|
||||||
})
|
})
|
||||||
export class ViewQueryComponent {
|
export class ViewQueryComponent {
|
||||||
@ViewChild(SomeDirective) someDir: SomeDirective;
|
@ViewChild(SomeDirective) someDir: SomeDirective;
|
||||||
|
@ViewChildren(SomeDirective) someDirs: QueryList<SomeDirective>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({declarations: [SomeDirective, ViewQueryComponent]})
|
@NgModule({declarations: [SomeDirective, ViewQueryComponent]})
|
||||||
|
@ -1205,8 +1206,8 @@ describe('compiler compliance', () => {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'view-query-component',
|
selector: 'view-query-component',
|
||||||
template: \`
|
template: \`
|
||||||
<div #myRef></div>
|
<div #myRef></div>
|
||||||
<div #myRef1></div>
|
<div #myRef1></div>
|
||||||
\`
|
\`
|
||||||
})
|
})
|
||||||
export class ViewQueryComponent {
|
export class ViewQueryComponent {
|
||||||
|
@ -1221,15 +1222,15 @@ describe('compiler compliance', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ViewQueryComponentDefinition = `
|
const ViewQueryComponentDefinition = `
|
||||||
const $e0_attrs$ = ["myRef", ""];
|
const $e0_attrs$ = ["myRef"];
|
||||||
const $e1_attrs$ = ["myRef1", ""];
|
const $e1_attrs$ = ["myRef1", "myRef2", "myRef3"];
|
||||||
…
|
…
|
||||||
ViewQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
ViewQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
…
|
…
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵquery(0, ["myRef"], true);
|
$r3$.ɵquery(0, $e0_attrs$, true);
|
||||||
$r3$.ɵquery(1, ["myRef1", "myRef2", "myRef3"], true);
|
$r3$.ɵquery(1, $e1_attrs$, true);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
var $tmp$;
|
var $tmp$;
|
||||||
|
@ -1249,19 +1250,24 @@ describe('compiler compliance', () => {
|
||||||
it('should support view queries with read tokens specified', () => {
|
it('should support view queries with read tokens specified', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
|
...directive,
|
||||||
'view_query.component.ts': `
|
'view_query.component.ts': `
|
||||||
import {Component, NgModule, ViewChild, ViewChildren, QueryList, ElementRef} from '@angular/core';
|
import {Component, NgModule, ViewChild, ViewChildren, QueryList, ElementRef, TemplateRef} from '@angular/core';
|
||||||
|
import {SomeDirective} from './some.directive';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'view-query-component',
|
selector: 'view-query-component',
|
||||||
template: \`
|
template: \`
|
||||||
<div #myRef></div>
|
<div someDir></div>
|
||||||
<div #myRef1></div>
|
<div #myRef></div>
|
||||||
|
<div #myRef1></div>
|
||||||
\`
|
\`
|
||||||
})
|
})
|
||||||
export class ViewQueryComponent {
|
export class ViewQueryComponent {
|
||||||
@ViewChild('myRef', {read: ElementRef}) myRef: any;
|
@ViewChild('myRef', {read: TemplateRef}) myRef: TemplateRef;
|
||||||
@ViewChildren('myRef1, myRef2, myRef3', {read: ElementRef}) myRefs: QueryList<any>;
|
@ViewChildren('myRef1, myRef2, myRef3', {read: ElementRef}) myRefs: QueryList<ElementRef>;
|
||||||
|
@ViewChild(SomeDirective, {read: ElementRef}) someDir: ElementRef;
|
||||||
|
@ViewChildren(SomeDirective, {read: TemplateRef}) someDirs: QueryList<TemplateRef>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({declarations: [ViewQueryComponent]})
|
@NgModule({declarations: [ViewQueryComponent]})
|
||||||
|
@ -1271,20 +1277,24 @@ describe('compiler compliance', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ViewQueryComponentDefinition = `
|
const ViewQueryComponentDefinition = `
|
||||||
const $e0_attrs$ = ["myRef", ""];
|
const $e0_attrs$ = ["myRef"];
|
||||||
const $e1_attrs$ = ["myRef1", ""];
|
const $e1_attrs$ = ["myRef1", "myRef2", "myRef3"];
|
||||||
…
|
…
|
||||||
ViewQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
ViewQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
…
|
…
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵquery(0, ["myRef"], true, ElementRef);
|
$r3$.ɵquery(0, $e0_attrs$, true, TemplateRef);
|
||||||
$r3$.ɵquery(1, ["myRef1", "myRef2", "myRef3"], true, ElementRef);
|
$r3$.ɵquery(1, SomeDirective, true, ElementRef);
|
||||||
|
$r3$.ɵquery(2, $e1_attrs$, true, ElementRef);
|
||||||
|
$r3$.ɵquery(3, SomeDirective, true, TemplateRef);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
var $tmp$;
|
var $tmp$;
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(0))) && (ctx.myRef = $tmp$.first));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(0))) && (ctx.myRef = $tmp$.first));
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(1))) && (ctx.myRefs = $tmp$));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(1))) && (ctx.someDir = $tmp$.first));
|
||||||
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(2))) && (ctx.myRefs = $tmp$));
|
||||||
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(3))) && (ctx.someDirs = $tmp$));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
…
|
…
|
||||||
|
@ -1366,104 +1376,112 @@ describe('compiler compliance', () => {
|
||||||
|
|
||||||
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
|
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should support content queries with local refs', () => {
|
it('should support content queries with local refs', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'content_query.component.ts': `
|
'content_query.component.ts': `
|
||||||
import {Component, ContentChild, ContentChildren, NgModule, QueryList} from '@angular/core';
|
import {Component, ContentChild, ContentChildren, NgModule, QueryList} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'content-query-component',
|
selector: 'content-query-component',
|
||||||
template: \`
|
template: \`
|
||||||
<div #myRef></div>
|
<div #myRef></div>
|
||||||
<div #myRef1></div>
|
<div #myRef1></div>
|
||||||
\`
|
\`
|
||||||
})
|
})
|
||||||
export class ContentQueryComponent {
|
export class ContentQueryComponent {
|
||||||
@ContentChild('myRef') myRef: any;
|
@ContentChild('myRef') myRef: any;
|
||||||
@ContentChildren('myRef1, myRef2, myRef3') myRefs: QueryList<any>;
|
@ContentChildren('myRef1, myRef2, myRef3') myRefs: QueryList<any>;
|
||||||
|
}
|
||||||
|
@NgModule({declarations: [ContentQueryComponent]})
|
||||||
|
export class MyModule {}
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@NgModule({declarations: [ContentQueryComponent]})
|
const ContentQueryComponentDefinition = `
|
||||||
export class MyModule {}
|
const $e0_attrs$ = ["myRef"];
|
||||||
`
|
const $e1_attrs$ = ["myRef1", "myRef2", "myRef3"];
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ContentQueryComponentDefinition = `
|
|
||||||
const $e0_attrs$ = ["myRef", ""];
|
|
||||||
const $e1_attrs$ = ["myRef1", ""];
|
|
||||||
…
|
|
||||||
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
|
||||||
…
|
…
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries() {
|
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef"], true));
|
…
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef1", "myRef2", "myRef3"], false));
|
contentQueries: function ContentQueryComponent_ContentQueries() {
|
||||||
},
|
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$, true));
|
||||||
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false));
|
||||||
const instance = $r3$.ɵload(dirIndex);
|
},
|
||||||
var $tmp$;
|
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
|
const instance = $r3$.ɵload(dirIndex);
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));
|
var $tmp$;
|
||||||
},
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
|
||||||
…
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));
|
||||||
});`;
|
},
|
||||||
|
…
|
||||||
|
});`;
|
||||||
|
|
||||||
const result = compile(files, angularFiles);
|
const result = compile(files, angularFiles);
|
||||||
const source = result.source;
|
const source = result.source;
|
||||||
|
|
||||||
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
|
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support content queries with read tokens specified', () => {
|
it('should support content queries with read tokens specified', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
'content_query.component.ts': `
|
...directive,
|
||||||
import {Component, ContentChild, ContentChildren, NgModule, QueryList, ElementRef} from '@angular/core';
|
'content_query.component.ts': `
|
||||||
|
import {Component, ContentChild, ContentChildren, NgModule, QueryList, ElementRef, TemplateRef} from '@angular/core';
|
||||||
|
import {SomeDirective} from './some.directive';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'content-query-component',
|
selector: 'content-query-component',
|
||||||
template: \`
|
template: \`
|
||||||
<div #myRef></div>
|
<div someDir></div>
|
||||||
<div #myRef1></div>
|
<div #myRef></div>
|
||||||
\`
|
<div #myRef1></div>
|
||||||
})
|
\`
|
||||||
export class ContentQueryComponent {
|
})
|
||||||
@ContentChild('myRef', {read: ElementRef}) myRef: any;
|
export class ContentQueryComponent {
|
||||||
@ContentChildren('myRef1, myRef2, myRef3', {read: ElementRef}) myRefs: QueryList<any>;
|
@ContentChild('myRef', {read: TemplateRef}) myRef: TemplateRef;
|
||||||
|
@ContentChildren('myRef1, myRef2, myRef3', {read: ElementRef}) myRefs: QueryList<ElementRef>;
|
||||||
|
@ContentChild(SomeDirective, {read: ElementRef}) someDir: ElementRef;
|
||||||
|
@ContentChildren(SomeDirective, {read: TemplateRef}) someDirs: QueryList<TemplateRef>;
|
||||||
|
}
|
||||||
|
@NgModule({declarations: [ContentQueryComponent]})
|
||||||
|
export class MyModule {}
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@NgModule({declarations: [ContentQueryComponent]})
|
const ContentQueryComponentDefinition = `
|
||||||
export class MyModule {}
|
const $e0_attrs$ = ["myRef"];
|
||||||
`
|
const $e1_attrs$ = ["myRef1", "myRef2", "myRef3"];
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ContentQueryComponentDefinition = `
|
|
||||||
const $e0_attrs$ = ["myRef", ""];
|
|
||||||
const $e1_attrs$ = ["myRef1", ""];
|
|
||||||
…
|
|
||||||
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
|
||||||
…
|
…
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries() {
|
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef"], true, ElementRef));
|
…
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef1", "myRef2", "myRef3"], false, ElementRef));
|
contentQueries: function ContentQueryComponent_ContentQueries() {
|
||||||
},
|
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$ , true, TemplateRef));
|
||||||
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true, ElementRef));
|
||||||
const instance = $r3$.ɵload(dirIndex);
|
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false, ElementRef));
|
||||||
var $tmp$;
|
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false, TemplateRef));
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
|
},
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));
|
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
||||||
},
|
const instance = $r3$.ɵload(dirIndex);
|
||||||
…
|
var $tmp$;
|
||||||
});`;
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
|
||||||
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.someDir = $tmp$.first));
|
||||||
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 2)))) && (instance.myRefs = $tmp$));
|
||||||
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 3)))) && (instance.someDirs = $tmp$));
|
||||||
|
},
|
||||||
|
…
|
||||||
|
});`;
|
||||||
|
|
||||||
const result = compile(files, angularFiles);
|
const result = compile(files, angularFiles);
|
||||||
const source = result.source;
|
const source = result.source;
|
||||||
|
|
||||||
|
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
|
||||||
|
});
|
||||||
|
|
||||||
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('pipes', () => {
|
describe('pipes', () => {
|
||||||
|
|
|
@ -384,6 +384,14 @@ describe('ngtsc behavioral tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate queries for components', () => {
|
it('should generate queries for components', () => {
|
||||||
|
|
||||||
|
// Helper functions to construct RegExps for output validation
|
||||||
|
const varRegExp = (name: string): RegExp => new RegExp(`var \\w+ = \\[\"${name}\"\\];`);
|
||||||
|
const queryRegExp = (id: number | null, descend: boolean, ref?: string): RegExp => {
|
||||||
|
const maybeRef = ref ? `, ${ref}` : ``;
|
||||||
|
return new RegExp(`i0\\.ɵquery\\(${id}, \\w+, ${descend}${maybeRef}\\)`);
|
||||||
|
};
|
||||||
|
|
||||||
env.tsconfig();
|
env.tsconfig();
|
||||||
env.write(`test.ts`, `
|
env.write(`test.ts`, `
|
||||||
import {Component, ContentChild, ContentChildren, TemplateRef, ViewChild} from '@angular/core';
|
import {Component, ContentChild, ContentChildren, TemplateRef, ViewChild} from '@angular/core';
|
||||||
|
@ -406,11 +414,17 @@ describe('ngtsc behavioral tests', () => {
|
||||||
|
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
expect(jsContents).toContain(`i0.ɵquery(null, ["bar"], true, TemplateRef)`);
|
expect(jsContents).toMatch(varRegExp('bar'));
|
||||||
|
expect(jsContents).toMatch(varRegExp('test1'));
|
||||||
|
expect(jsContents).toMatch(varRegExp('test2'));
|
||||||
|
expect(jsContents).toMatch(varRegExp('accessor'));
|
||||||
expect(jsContents).toContain(`i0.ɵquery(null, TemplateRef, false)`);
|
expect(jsContents).toContain(`i0.ɵquery(null, TemplateRef, false)`);
|
||||||
expect(jsContents).toContain(`i0.ɵquery(null, ["test2"], true)`);
|
expect(jsContents)
|
||||||
expect(jsContents).toContain(`i0.ɵquery(0, ["accessor"], true)`);
|
.toMatch(queryRegExp(
|
||||||
expect(jsContents).toContain(`i0.ɵquery(1, ["test1"], true)`);
|
null, true, 'TemplateRef')); // match `i0.ɵquery(null, _c0, true, TemplateRef)`
|
||||||
|
expect(jsContents).toMatch(queryRegExp(null, true)); // match `i0.ɵquery(null, _c0, true)`
|
||||||
|
expect(jsContents).toMatch(queryRegExp(0, true)); // match `i0.ɵquery(0, _c0, true)`
|
||||||
|
expect(jsContents).toMatch(queryRegExp(1, true)); // match `i0.ɵquery(1, _c0, true)`
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle queries that use forwardRef', () => {
|
it('should handle queries that use forwardRef', () => {
|
||||||
|
|
|
@ -112,7 +112,7 @@ export function getQueryPredicate(
|
||||||
const selectors = selector.split(',').map(token => o.literal(token.trim()));
|
const selectors = selector.split(',').map(token => o.literal(token.trim()));
|
||||||
predicate.push(...selectors);
|
predicate.push(...selectors);
|
||||||
});
|
});
|
||||||
return constantPool.getConstLiteral(o.literalArr(predicate));
|
return constantPool.getConstLiteral(o.literalArr(predicate), true);
|
||||||
} else {
|
} else {
|
||||||
return query.predicate;
|
return query.predicate;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue