diff --git a/packages/context/src/inject.ts b/packages/context/src/inject.ts index 8631acdc7bd5..9ae4a48cd5cc 100644 --- a/packages/context/src/inject.ts +++ b/packages/context/src/inject.ts @@ -107,6 +107,10 @@ export function inject( propDecorator(target, propertyKey!); } else { // It won't happen here as `@inject` is not compatible with ClassDecorator + /* istanbul ignore next */ + throw new Error( + '@inject can only be used on a property or a method parameter', + ); } }; } diff --git a/packages/metadata/src/inspector.ts b/packages/metadata/src/inspector.ts index f96d51a6a85b..dcc172339530 100644 --- a/packages/metadata/src/inspector.ts +++ b/packages/metadata/src/inspector.ts @@ -25,6 +25,8 @@ export class MetadataInspector { * Get the metadata associated with the given key for a given class * @param key Metadata key * @param target Class that contains the metadata + * @param ownOnly Optional flag to control if only own metadata is inspected. + * The default value is `false` and inherited metadata is inspected. */ static getClassMetadata( key: string, @@ -41,6 +43,8 @@ export class MetadataInspector { * target class or prototype * @param key Metadata key * @param target Class for static methods or prototype for instance methods + * @param ownOnly Optional flag to control if only own metadata is inspected. + * The default value is `false` and inherited metadata is inspected. */ static getAllMethodMetadata( key: string, @@ -59,6 +63,8 @@ export class MetadataInspector { * @param target Class for static methods or prototype for instance methods * @param methodName Method name. If not present, default to '' to use * the constructor + * @param ownOnly Optional flag to control if only own metadata is inspected. + * The default value is `false` and inherited metadata is inspected. */ static getMethodMetadata( key: string, @@ -78,6 +84,8 @@ export class MetadataInspector { * target class or prototype * @param key Metadata key * @param target Class for static methods or prototype for instance methods + * @param ownOnly Optional flag to control if only own metadata is inspected. + * The default value is `false` and inherited metadata is inspected. */ static getAllPropertyMetadata( key: string, @@ -96,6 +104,8 @@ export class MetadataInspector { * @param target Class for static properties or prototype for instance * properties * @param propertyName Property name + * @param ownOnly Optional flag to control if only own metadata is inspected. + * The default value is `false` and inherited metadata is inspected. */ static getPropertyMetadata( key: string, @@ -116,6 +126,8 @@ export class MetadataInspector { * @param target Class for static methods or prototype for instance methods * @param methodName Method name. If not present, default to '' to use * the constructor + * @param ownOnly Optional flag to control if only own metadata is inspected. + * The default value is `false` and inherited metadata is inspected. */ static getAllParameterMetadata( key: string, @@ -138,6 +150,8 @@ export class MetadataInspector { * @param methodName Method name. If not present, default to '' to use * the constructor * @param index Index of the parameter, starting with 0 + * @param ownOnly Optional flag to control if only own metadata is inspected. + * The default value is `false` and inherited metadata is inspected. */ static getParameterMetadata( key: string, @@ -155,7 +169,7 @@ export class MetadataInspector { } /** - * Get TypeScript design time type for the property + * Get TypeScript design time type for a property * @param target Class or prototype * @param propertyName Property name */ @@ -166,6 +180,11 @@ export class MetadataInspector { return TSReflector.getMetadata('design:type', target, propertyName); } + /** + * Get TypeScript design time type for a method + * @param target Class or prototype + * @param methodName Method name + */ static getDesignTypeForMethod( target: Object, methodName: string | symbol, diff --git a/packages/metadata/test/unit/inspector.test.ts b/packages/metadata/test/unit/inspector.test.ts index e8fa577b8e08..c5ca61c14eb2 100644 --- a/packages/metadata/test/unit/inspector.test.ts +++ b/packages/metadata/test/unit/inspector.test.ts @@ -45,6 +45,51 @@ describe('Inspector for a class', () => { }); }); +describe('Inspector for a class for its own metadata', () => { + /** + * Define `@classDecorator(spec)` + * @param spec + */ + function classDecorator(spec: object): ClassDecorator { + return ClassDecoratorFactory.createDecorator('test', spec); + } + + @classDecorator({x: 1}) + class BaseController {} + + @classDecorator({y: 2}) + class SubController extends BaseController {} + + class AnotherController extends BaseController {} + + it('inspects metadata of a base class', () => { + const meta = MetadataInspector.getClassMetadata( + 'test', + BaseController, + true, + ); + expect(meta).to.eql({x: 1}); + }); + + it('inspects metadata of a sub class', () => { + const meta = MetadataInspector.getClassMetadata( + 'test', + SubController, + true, + ); + expect(meta).to.eql({x: 1, y: 2}); + }); + + it('inspects metadata of a sub class without override', () => { + const meta = MetadataInspector.getClassMetadata( + 'test', + AnotherController, + true, + ); + expect(meta).to.be.undefined(); + }); +}); + describe('Inspector for instance properties', () => { /** * Define `@propertyDecorator(spec)` @@ -64,6 +109,10 @@ describe('Inspector for instance properties', () => { myProp: string; } + class AnotherController extends BaseController { + myProp: string; + } + it('inspects metadata of all properties of a base class', () => { const meta = MetadataInspector.getAllPropertyMetadata( 'test', @@ -88,6 +137,23 @@ describe('Inspector for instance properties', () => { ); expect(meta).to.eql({myProp: {x: 1, y: 2}}); }); + + it('inspects own metadata of all properties of a sub class', () => { + const meta = MetadataInspector.getAllPropertyMetadata( + 'test', + AnotherController.prototype, + true, + ); + expect(meta).to.be.undefined(); + + const propertyMeta = MetadataInspector.getPropertyMetadata( + 'test', + AnotherController.prototype, + 'myProp', + true, + ); + expect(propertyMeta).to.be.undefined(); + }); }); describe('Inspector for static properties', () => { @@ -109,6 +175,10 @@ describe('Inspector for static properties', () => { static myProp: string; } + class AnotherController extends BaseController { + static myProp: string; + } + it('inspects metadata of all properties of a base class', () => { const meta = MetadataInspector.getAllPropertyMetadata( 'test', @@ -133,6 +203,23 @@ describe('Inspector for static properties', () => { ); expect(meta).to.eql({myProp: {x: 1, y: 2}}); }); + + it('inspects own metadata of all properties of a sub class', () => { + const meta = MetadataInspector.getAllPropertyMetadata( + 'test', + AnotherController, + true, + ); + expect(meta).to.be.undefined(); + + const propertyMeta = MetadataInspector.getPropertyMetadata( + 'test', + AnotherController, + 'myProp', + true, + ); + expect(propertyMeta).to.be.undefined(); + }); }); describe('Inspector for instance methods', () => { @@ -154,6 +241,8 @@ describe('Inspector for instance methods', () => { myMethod() {} } + class AnotherController extends BaseController {} + it('inspects metadata of all methods of a base class', () => { const meta = MetadataInspector.getAllMethodMetadata( 'test', @@ -178,6 +267,23 @@ describe('Inspector for instance methods', () => { ); expect(meta).to.eql({myMethod: {x: 1, y: 2}}); }); + + it('inspects own metadata of all methods of a sub class', () => { + const meta = MetadataInspector.getAllMethodMetadata( + 'test', + AnotherController.prototype, + true, + ); + expect(meta).to.be.undefined(); + + const methodMeta = MetadataInspector.getMethodMetadata( + 'test', + AnotherController.prototype, + 'myMethod', + true, + ); + expect(methodMeta).to.be.undefined(); + }); }); describe('Inspector for static methods', () => { @@ -199,6 +305,8 @@ describe('Inspector for static methods', () => { static myMethod() {} } + class AnotherController extends BaseController {} + it('inspects metadata of all methods of a base class', () => { const meta = MetadataInspector.getAllMethodMetadata('test', BaseController); expect(meta).to.eql({myMethod: {x: 1}}); @@ -217,6 +325,29 @@ describe('Inspector for static methods', () => { const meta = MetadataInspector.getAllMethodMetadata('test', SubController); expect(meta).to.eql({myMethod: {x: 1, y: 2}}); }); + + it('inspects own metadata of all methods of a sub class', () => { + const meta = MetadataInspector.getAllMethodMetadata( + 'test', + AnotherController, + true, + ); + expect(meta).to.be.undefined(); + + const methodMeta = MetadataInspector.getMethodMetadata( + 'test', + AnotherController, + 'myMethod', + true, + ); + expect(methodMeta).to.be.undefined(); + + const inherited = MetadataInspector.getAllMethodMetadata( + 'test', + AnotherController, + ); + expect(inherited).to.eql({myMethod: {x: 1}}); + }); }); describe('Inspector for parameters of an instance method', () => { @@ -245,6 +376,8 @@ describe('Inspector for parameters of an instance method', () => { ) {} } + class AnotherController extends BaseController {} + it('inspects metadata of all parameters of a method of the base class', () => { const meta = MetadataInspector.getAllParameterMetadata( 'test', @@ -272,6 +405,31 @@ describe('Inspector for parameters of an instance method', () => { ); expect(meta).to.eql({x: 1, y: 2}); }); + + it('inspects own metadata of all method parameters of a sub class', () => { + const meta = MetadataInspector.getAllParameterMetadata( + 'test', + AnotherController.prototype, + 'myMethod', + true, + ); + expect(meta).to.be.undefined(); + + const paramsMeta = MetadataInspector.getParameterMetadata( + 'test', + AnotherController.prototype, + 'myMethod', + 0, + true, + ); + expect(paramsMeta).to.be.undefined(); + + const inherited = MetadataInspector.getAllMethodMetadata( + 'test', + AnotherController.prototype, + ); + expect(inherited).to.eql({myMethod: [{x: 1}, undefined]}); + }); }); describe('Inspector for parameters of a static method', () => { @@ -300,6 +458,8 @@ describe('Inspector for parameters of a static method', () => { ) {} } + class AnotherController extends BaseController {} + it('inspects metadata of all parameters of a method of the base class', () => { const meta = MetadataInspector.getAllParameterMetadata( 'test', @@ -327,6 +487,31 @@ describe('Inspector for parameters of a static method', () => { ); expect(meta).to.eql({x: 1, y: 2}); }); + + it('inspects own metadata of all method parameters of a sub class', () => { + const meta = MetadataInspector.getAllParameterMetadata( + 'test', + AnotherController, + 'myMethod', + true, + ); + expect(meta).to.be.undefined(); + + const paramsMeta = MetadataInspector.getParameterMetadata( + 'test', + AnotherController, + 'myMethod', + 0, + true, + ); + expect(paramsMeta).to.be.undefined(); + + const inherited = MetadataInspector.getAllMethodMetadata( + 'test', + AnotherController, + ); + expect(inherited).to.eql({myMethod: [{x: 1}, undefined]}); + }); }); describe('Inspector for parameters of a constructor', () => {