fix(ivy): ngtsc should pay attention to declaration order (#25392)
When generating the 'directives:' property of ngComponentDef, ngtsc needs to be conscious of declaration order. If a directive being written into the array is declarated after the component currently being compiled, then the entire directives array needs to be wrapped in a closure. This commit fixes ngtsc to pay attention to such ordering issues within directives arrays. PR Close #25392
This commit is contained in:

committed by
Ben Lesh

parent
6f085f8610
commit
2befc65777
@ -1002,7 +1002,7 @@ describe('compiler compliance', () => {
|
||||
$r3$.ɵEe(1, "div", $e0_attrs$);
|
||||
}
|
||||
},
|
||||
directives:[SomeDirective]
|
||||
directives: function () { return [SomeDirective]; }
|
||||
});`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
@ -1582,7 +1582,7 @@ describe('compiler compliance', () => {
|
||||
}
|
||||
if (rf & 2) { $r3$.ɵp(1,"forOf",$r3$.ɵb(ctx.items)); }
|
||||
},
|
||||
directives: [ForOfDirective]
|
||||
directives: function() { return [ForOfDirective]; }
|
||||
});
|
||||
`;
|
||||
|
||||
@ -1660,7 +1660,7 @@ describe('compiler compliance', () => {
|
||||
$r3$.ɵp(1, "forOf", $r3$.ɵb(ctx.items));
|
||||
}
|
||||
},
|
||||
directives: [ForOfDirective]
|
||||
directives: function() { return [ForOfDirective]; }
|
||||
});
|
||||
`;
|
||||
|
||||
@ -1758,7 +1758,7 @@ describe('compiler compliance', () => {
|
||||
$r3$.ɵp(1, "forOf", $r3$.ɵb(ctx.items));
|
||||
}
|
||||
},
|
||||
directives: [ForOfDirective]
|
||||
directives: function () { return [ForOfDirective]; }
|
||||
});`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
|
@ -715,4 +715,36 @@ describe('ngtsc behavioral tests', () => {
|
||||
expect(jsContents)
|
||||
.toContain('function GrandChild_Factory(t) { return new (t || GrandChild)(); }');
|
||||
});
|
||||
|
||||
it('should wrap "directives" in component metadata in a closure when forward references are present',
|
||||
() => {
|
||||
writeConfig();
|
||||
write('test.ts', `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'cmp-a',
|
||||
template: '<cmp-b></cmp-b>',
|
||||
})
|
||||
class CmpA {}
|
||||
|
||||
@Component({
|
||||
selector: 'cmp-b',
|
||||
template: 'This is B',
|
||||
})
|
||||
class CmpB {}
|
||||
|
||||
@NgModule({
|
||||
declarations: [CmpA, CmpB],
|
||||
})
|
||||
class Module {}
|
||||
`);
|
||||
|
||||
const exitCode = main(['-p', basePath], errorSpy);
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const jsContents = getContents('test.js');
|
||||
expect(jsContents).toContain('directives: function () { return [CmpB]; }');
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user