fix(compiler): process imports first and declarations second while calculating scopes (#35850)

Prior to this commit, while calculating the scope for a module, Ivy compiler processed `declarations` field first and `imports` after that. That results in a couple issues:

* for Pipes with the same `name` and present in `declarations` and in an imported module, Pipe from imported module was selected. In View Engine the logic is opposite: Pipes from `declarations` field receive higher priority.
* for Directives with the same selector and present in `declarations` and in an imported module, we first invoked the logic of a Directive from `declarations` field and after that - imported Directive logic. In View Engine, it was the opposite and the logic of a Directive from the `declarations` field was invoked last.

In order to align Ivy and View Engine behavior, this commit updates the logic in which we populate module scope: we first process all imports and after that handle `declarations` field. As a result, in Ivy both use-cases listed above work similar to View Engine.

Resolves #35502.

PR Close #35850
This commit is contained in:
Andrew Kushnir
2020-03-03 18:06:16 -08:00
committed by Matias Niemelä
parent 191e4d15b5
commit 0bf6e58db2
5 changed files with 422 additions and 42 deletions

View File

@ -455,19 +455,6 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS
},
};
maybeUnwrapFn(def.declarations).forEach(declared => {
const declaredWithDefs = declared as Type<any>& { ɵpipe?: any; };
if (getPipeDef(declaredWithDefs)) {
scopes.compilation.pipes.add(declared);
} else {
// Either declared has a ɵcmp or ɵdir, or it's a component which hasn't
// had its template compiled yet. In either case, it gets added to the compilation's
// directives.
scopes.compilation.directives.add(declared);
}
});
maybeUnwrapFn(def.imports).forEach(<I>(imported: Type<I>) => {
const importedType = imported as Type<I>& {
// If imported is an @NgModule:
@ -485,6 +472,19 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS
importedScope.exported.pipes.forEach(entry => scopes.compilation.pipes.add(entry));
});
maybeUnwrapFn(def.declarations).forEach(declared => {
const declaredWithDefs = declared as Type<any>& { ɵpipe?: any; };
if (getPipeDef(declaredWithDefs)) {
scopes.compilation.pipes.add(declared);
} else {
// Either declared has a ɵcmp or ɵdir, or it's a component which hasn't
// had its template compiled yet. In either case, it gets added to the compilation's
// directives.
scopes.compilation.directives.add(declared);
}
});
maybeUnwrapFn(def.exports).forEach(<E>(exported: Type<E>) => {
const exportedType = exported as Type<E>& {
// Components, Directives, NgModules, and Pipes can all be exported.