
When we look for matching annotations in TestBed, we should always take the last matching annotation. Otherwise, we will return superclass data for subclasses, which would have unintended consequences like directives matching the wrong selectors. PR Close #28195
55 lines
2.0 KiB
TypeScript
55 lines
2.0 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {Type} from '../interface/type';
|
|
|
|
interface TypeWithMetadata extends Type<any> {
|
|
decorators?: any[];
|
|
ctorParameters?: () => any[];
|
|
propDecorators?: {[field: string]: any};
|
|
}
|
|
|
|
/**
|
|
* Adds decorator, constructor, and property metadata to a given type via static metadata fields
|
|
* on the type.
|
|
*
|
|
* These metadata fields can later be read with Angular's `ReflectionCapabilities` API.
|
|
*
|
|
* Calls to `setClassMetadata` can be marked as pure, resulting in the metadata assignments being
|
|
* tree-shaken away during production builds.
|
|
*/
|
|
export function setClassMetadata(
|
|
type: Type<any>, decorators: any[] | null, ctorParameters: (() => any[]) | null,
|
|
propDecorators: {[field: string]: any} | null): void {
|
|
const clazz = type as TypeWithMetadata;
|
|
if (decorators !== null) {
|
|
if (clazz.hasOwnProperty('decorators') && clazz.decorators !== undefined) {
|
|
clazz.decorators.push(...decorators);
|
|
} else {
|
|
clazz.decorators = decorators;
|
|
}
|
|
}
|
|
if (ctorParameters !== null) {
|
|
// Rather than merging, clobber the existing parameters. If other projects exist which use
|
|
// tsickle-style annotations and reflect over them in the same way, this could cause issues,
|
|
// but that is vanishingly unlikely.
|
|
clazz.ctorParameters = ctorParameters;
|
|
}
|
|
if (propDecorators !== null) {
|
|
// The property decorator objects are merged as it is possible different fields have different
|
|
// decorator types. Decorators on individual fields are not merged, as it's also incredibly
|
|
// unlikely that a field will be decorated both with an Angular decorator and a non-Angular
|
|
// decorator that's also been downleveled.
|
|
if (clazz.propDecorators !== undefined) {
|
|
clazz.propDecorators = {...clazz.propDecorators, ...propDecorators};
|
|
} else {
|
|
clazz.propDecorators = propDecorators;
|
|
}
|
|
}
|
|
}
|