Skip to content

Commit

Permalink
feat: Add metadata inspector
Browse files Browse the repository at this point in the history
  • Loading branch information
raymondfeng committed Dec 15, 2017
1 parent fa6dd30 commit c683019
Show file tree
Hide file tree
Showing 10 changed files with 746 additions and 46 deletions.
23 changes: 11 additions & 12 deletions packages/authentication/src/decorators/authenticate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {Reflector, Constructor} from '@loopback/context';
import {
MetadataInspector,
Constructor,
MethodDecoratorFactory,
} from '@loopback/context';
import {AuthenticationBindings} from '../keys';

/**
Expand All @@ -21,18 +25,13 @@ export interface AuthenticationMetadata {
* @param options Additional options to configure the authentication.
*/
export function authenticate(strategyName: string, options?: Object) {
return function(controllerClass: Object, methodName: string) {
const metadataObj: AuthenticationMetadata = {
return MethodDecoratorFactory.createDecorator<AuthenticationMetadata>(
AuthenticationBindings.METADATA,
{
strategy: strategyName,
options: options || {},
};
Reflector.defineMetadata(
AuthenticationBindings.METADATA,
metadataObj,
controllerClass,
methodName,
);
};
},
);
}

/**
Expand All @@ -45,7 +44,7 @@ export function getAuthenticateMetadata(
controllerClass: Constructor<{}>,
methodName: string,
): AuthenticationMetadata | undefined {
return Reflector.getMetadata(
return MetadataInspector.getMethodMetadata<AuthenticationMetadata>(
AuthenticationBindings.METADATA,
controllerClass.prototype,
methodName,
Expand Down
21 changes: 14 additions & 7 deletions packages/context/src/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
// License text available at https://opensource.org/licenses/MIT

import {
Reflector,
MetadataInspector,
ParameterDecoratorFactory,
PropertyDecoratorFactory,
MetadataMap,
} from '@loopback/metadata';
import {BoundValue, ValueOrPromise} from './binding';
import {Context} from './context';
Expand Down Expand Up @@ -186,9 +187,12 @@ export function describeInjectedArguments(
method?: string | symbol,
): Injection[] {
method = method || '';
const meta = Reflector.getMetadata(PARAMETERS_KEY, target);
if (meta == null) return [];
return meta[method] || [];
const meta = MetadataInspector.getAllParameterMetadata<Injection>(
PARAMETERS_KEY,
target,
method,
);
return meta || [];
}

/**
Expand All @@ -199,8 +203,11 @@ export function describeInjectedArguments(
export function describeInjectedProperties(
// tslint:disable-next-line:no-any
target: any,
): {[p: string]: Injection} {
const metadata: {[name: string]: Injection} =
Reflector.getMetadata(PROPERTIES_KEY, target) || {};
): MetadataMap<Injection> {
const metadata =
MetadataInspector.getAllPropertyMetadata<Injection>(
PROPERTIES_KEY,
target,
) || {};
return metadata;
}
2 changes: 1 addition & 1 deletion packages/metadata/src/decorator-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import {Reflector} from './reflect';
import * as _ from 'lodash';
import * as debugModule from 'debug';
const debug = debugModule('loopback:decorator');
const debug = debugModule('loopback:metadata:decorator');

// tslint:disable:no-any

Expand Down
1 change: 1 addition & 0 deletions packages/metadata/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

export * from './reflect';
export * from './decorator-factory';
export * from './inspector';
166 changes: 166 additions & 0 deletions packages/metadata/src/inspector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright IBM Corp. 2013,2017. All Rights Reserved.
// Node module: @loopback/metadata
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {Reflector, NamespacedReflect} from './reflect';
import {MetadataMap} from './decorator-factory';

const TSReflector = new NamespacedReflect();

/**
* Design time metadata for a method
*/
export interface DesignTimeMethodMetadata {
type: Function;
parameterTypes: Function[];
returnType: Function;
}

/**
* Inspector for metadata applied by decorators
*/
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
*/
static getClassMetadata<T>(key: string, target: Function): T | undefined {
return Reflector.getMetadata(key, target);
}

/**
* Get the metadata associated with the given key for all methods of the
* target class or prototype
* @param key Metadata key
* @param target Class for static methods or prototype for instance methods
*/
static getAllMethodMetadata<T>(
key: string,
target: Object,
): MetadataMap<T> | undefined {
return Reflector.getMetadata(key, target);
}

/**
* Get the metadata associated with the given key for a given method of the
* target class or prototype
* @param key Metadata key
* @param target Class for static methods or prototype for instance methods
* @param methodName Method name. If not present, default to '' to use
* the constructor
*/
static getMethodMetadata<T>(
key: string,
target: Object,
methodName?: string | symbol,
): T | undefined {
methodName = methodName || '';
const meta: MetadataMap<T> = Reflector.getMetadata(key, target);
return meta && meta[methodName];
}

/**
* Get the metadata associated with the given key for all properties of the
* target class or prototype
* @param key Metadata key
* @param target Class for static methods or prototype for instance methods
*/
static getAllPropertyMetadata<T>(
key: string,
target: Object,
): MetadataMap<T> | undefined {
return Reflector.getMetadata(key, target);
}

/**
* Get the metadata associated with the given key for a given property of the
* target class or prototype
* @param key Metadata key
* @param target Class for static properties or prototype for instance
* properties
* @param propertyName Property name
*/
static getPropertyMetadata<T>(
key: string,
target: Object,
propertyName: string | symbol,
): T | undefined {
const meta: MetadataMap<T> = Reflector.getMetadata(key, target);
return meta && meta[propertyName];
}

/**
* Get the metadata associated with the given key for all parameters of a
* given method
* @param key Metadata key
* @param target Class for static methods or prototype for instance methods
* @param methodName Method name. If not present, default to '' to use
* the constructor
*/
static getAllParameterMetadata<T>(
key: string,
target: Object,
methodName?: string | symbol,
): T[] | undefined {
methodName = methodName || '';
const meta: MetadataMap<T[]> = Reflector.getMetadata(key, target);
return meta && meta[methodName];
}

/**
* Get the metadata associated with the given key for a parameter of a given
* method by index
* @param key Metadata key
* @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 index Index of the parameter, starting with 0
*/
static getParameterMetadata<T>(
key: string,
target: Object,
methodName: string | symbol,
index: number,
): T | undefined {
methodName = methodName || '';
const meta: MetadataMap<T[]> = Reflector.getMetadata(key, target);
const params = meta && meta[methodName];
return params && params[index];
}

/**
* Get TypeScript design time type for the property
* @param target Class or prototype
* @param propertyName Property name
*/
static getDesignTypeForProperty(
target: Object,
propertyName: string | symbol,
): Function {
return TSReflector.getMetadata('design:type', target, propertyName);
}

static getDesignTypeForMethod(
target: Object,
methodName: string | symbol,
): DesignTimeMethodMetadata {
const type = TSReflector.getMetadata('design:type', target, methodName);
const parameterTypes = TSReflector.getMetadata(
'design:paramtypes',
target,
methodName,
);
const returnType = TSReflector.getMetadata(
'design:returntype',
target,
methodName,
);
return {
type,
parameterTypes,
returnType,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@

import {expect} from '@loopback/testlab';
import {
Reflector,
ClassDecoratorFactory,
PropertyDecoratorFactory,
MethodDecoratorFactory,
ParameterDecoratorFactory,
DecoratorFactory,
} from '../..';

import {Reflector} from '../../src/reflect';

describe('ClassDecoratorFactory', () => {
/**
* Define `@classDecorator(spec)`
Expand Down
Loading

0 comments on commit c683019

Please sign in to comment.