Skip to content

Commit c683019

Browse files
committed
feat: Add metadata inspector
1 parent fa6dd30 commit c683019

File tree

10 files changed

+746
-46
lines changed

10 files changed

+746
-46
lines changed

packages/authentication/src/decorators/authenticate.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
// This file is licensed under the MIT License.
44
// License text available at https://opensource.org/licenses/MIT
55

6-
import {Reflector, Constructor} from '@loopback/context';
6+
import {
7+
MetadataInspector,
8+
Constructor,
9+
MethodDecoratorFactory,
10+
} from '@loopback/context';
711
import {AuthenticationBindings} from '../keys';
812

913
/**
@@ -21,18 +25,13 @@ export interface AuthenticationMetadata {
2125
* @param options Additional options to configure the authentication.
2226
*/
2327
export function authenticate(strategyName: string, options?: Object) {
24-
return function(controllerClass: Object, methodName: string) {
25-
const metadataObj: AuthenticationMetadata = {
28+
return MethodDecoratorFactory.createDecorator<AuthenticationMetadata>(
29+
AuthenticationBindings.METADATA,
30+
{
2631
strategy: strategyName,
2732
options: options || {},
28-
};
29-
Reflector.defineMetadata(
30-
AuthenticationBindings.METADATA,
31-
metadataObj,
32-
controllerClass,
33-
methodName,
34-
);
35-
};
33+
},
34+
);
3635
}
3736

3837
/**
@@ -45,7 +44,7 @@ export function getAuthenticateMetadata(
4544
controllerClass: Constructor<{}>,
4645
methodName: string,
4746
): AuthenticationMetadata | undefined {
48-
return Reflector.getMetadata(
47+
return MetadataInspector.getMethodMetadata<AuthenticationMetadata>(
4948
AuthenticationBindings.METADATA,
5049
controllerClass.prototype,
5150
methodName,

packages/context/src/inject.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
// License text available at https://opensource.org/licenses/MIT
55

66
import {
7-
Reflector,
7+
MetadataInspector,
88
ParameterDecoratorFactory,
99
PropertyDecoratorFactory,
10+
MetadataMap,
1011
} from '@loopback/metadata';
1112
import {BoundValue, ValueOrPromise} from './binding';
1213
import {Context} from './context';
@@ -186,9 +187,12 @@ export function describeInjectedArguments(
186187
method?: string | symbol,
187188
): Injection[] {
188189
method = method || '';
189-
const meta = Reflector.getMetadata(PARAMETERS_KEY, target);
190-
if (meta == null) return [];
191-
return meta[method] || [];
190+
const meta = MetadataInspector.getAllParameterMetadata<Injection>(
191+
PARAMETERS_KEY,
192+
target,
193+
method,
194+
);
195+
return meta || [];
192196
}
193197

194198
/**
@@ -199,8 +203,11 @@ export function describeInjectedArguments(
199203
export function describeInjectedProperties(
200204
// tslint:disable-next-line:no-any
201205
target: any,
202-
): {[p: string]: Injection} {
203-
const metadata: {[name: string]: Injection} =
204-
Reflector.getMetadata(PROPERTIES_KEY, target) || {};
206+
): MetadataMap<Injection> {
207+
const metadata =
208+
MetadataInspector.getAllPropertyMetadata<Injection>(
209+
PROPERTIES_KEY,
210+
target,
211+
) || {};
205212
return metadata;
206213
}

packages/metadata/src/decorator-factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import {Reflector} from './reflect';
77
import * as _ from 'lodash';
88
import * as debugModule from 'debug';
9-
const debug = debugModule('loopback:decorator');
9+
const debug = debugModule('loopback:metadata:decorator');
1010

1111
// tslint:disable:no-any
1212

packages/metadata/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55

66
export * from './reflect';
77
export * from './decorator-factory';
8+
export * from './inspector';

packages/metadata/src/inspector.ts

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Copyright IBM Corp. 2013,2017. All Rights Reserved.
2+
// Node module: @loopback/metadata
3+
// This file is licensed under the MIT License.
4+
// License text available at https://opensource.org/licenses/MIT
5+
6+
import {Reflector, NamespacedReflect} from './reflect';
7+
import {MetadataMap} from './decorator-factory';
8+
9+
const TSReflector = new NamespacedReflect();
10+
11+
/**
12+
* Design time metadata for a method
13+
*/
14+
export interface DesignTimeMethodMetadata {
15+
type: Function;
16+
parameterTypes: Function[];
17+
returnType: Function;
18+
}
19+
20+
/**
21+
* Inspector for metadata applied by decorators
22+
*/
23+
export class MetadataInspector {
24+
/**
25+
* Get the metadata associated with the given key for a given class
26+
* @param key Metadata key
27+
* @param target Class that contains the metadata
28+
*/
29+
static getClassMetadata<T>(key: string, target: Function): T | undefined {
30+
return Reflector.getMetadata(key, target);
31+
}
32+
33+
/**
34+
* Get the metadata associated with the given key for all methods of the
35+
* target class or prototype
36+
* @param key Metadata key
37+
* @param target Class for static methods or prototype for instance methods
38+
*/
39+
static getAllMethodMetadata<T>(
40+
key: string,
41+
target: Object,
42+
): MetadataMap<T> | undefined {
43+
return Reflector.getMetadata(key, target);
44+
}
45+
46+
/**
47+
* Get the metadata associated with the given key for a given method of the
48+
* target class or prototype
49+
* @param key Metadata key
50+
* @param target Class for static methods or prototype for instance methods
51+
* @param methodName Method name. If not present, default to '' to use
52+
* the constructor
53+
*/
54+
static getMethodMetadata<T>(
55+
key: string,
56+
target: Object,
57+
methodName?: string | symbol,
58+
): T | undefined {
59+
methodName = methodName || '';
60+
const meta: MetadataMap<T> = Reflector.getMetadata(key, target);
61+
return meta && meta[methodName];
62+
}
63+
64+
/**
65+
* Get the metadata associated with the given key for all properties of the
66+
* target class or prototype
67+
* @param key Metadata key
68+
* @param target Class for static methods or prototype for instance methods
69+
*/
70+
static getAllPropertyMetadata<T>(
71+
key: string,
72+
target: Object,
73+
): MetadataMap<T> | undefined {
74+
return Reflector.getMetadata(key, target);
75+
}
76+
77+
/**
78+
* Get the metadata associated with the given key for a given property of the
79+
* target class or prototype
80+
* @param key Metadata key
81+
* @param target Class for static properties or prototype for instance
82+
* properties
83+
* @param propertyName Property name
84+
*/
85+
static getPropertyMetadata<T>(
86+
key: string,
87+
target: Object,
88+
propertyName: string | symbol,
89+
): T | undefined {
90+
const meta: MetadataMap<T> = Reflector.getMetadata(key, target);
91+
return meta && meta[propertyName];
92+
}
93+
94+
/**
95+
* Get the metadata associated with the given key for all parameters of a
96+
* given method
97+
* @param key Metadata key
98+
* @param target Class for static methods or prototype for instance methods
99+
* @param methodName Method name. If not present, default to '' to use
100+
* the constructor
101+
*/
102+
static getAllParameterMetadata<T>(
103+
key: string,
104+
target: Object,
105+
methodName?: string | symbol,
106+
): T[] | undefined {
107+
methodName = methodName || '';
108+
const meta: MetadataMap<T[]> = Reflector.getMetadata(key, target);
109+
return meta && meta[methodName];
110+
}
111+
112+
/**
113+
* Get the metadata associated with the given key for a parameter of a given
114+
* method by index
115+
* @param key Metadata key
116+
* @param target Class for static methods or prototype for instance methods
117+
* @param methodName Method name. If not present, default to '' to use
118+
* the constructor
119+
* @param index Index of the parameter, starting with 0
120+
*/
121+
static getParameterMetadata<T>(
122+
key: string,
123+
target: Object,
124+
methodName: string | symbol,
125+
index: number,
126+
): T | undefined {
127+
methodName = methodName || '';
128+
const meta: MetadataMap<T[]> = Reflector.getMetadata(key, target);
129+
const params = meta && meta[methodName];
130+
return params && params[index];
131+
}
132+
133+
/**
134+
* Get TypeScript design time type for the property
135+
* @param target Class or prototype
136+
* @param propertyName Property name
137+
*/
138+
static getDesignTypeForProperty(
139+
target: Object,
140+
propertyName: string | symbol,
141+
): Function {
142+
return TSReflector.getMetadata('design:type', target, propertyName);
143+
}
144+
145+
static getDesignTypeForMethod(
146+
target: Object,
147+
methodName: string | symbol,
148+
): DesignTimeMethodMetadata {
149+
const type = TSReflector.getMetadata('design:type', target, methodName);
150+
const parameterTypes = TSReflector.getMetadata(
151+
'design:paramtypes',
152+
target,
153+
methodName,
154+
);
155+
const returnType = TSReflector.getMetadata(
156+
'design:returntype',
157+
target,
158+
methodName,
159+
);
160+
return {
161+
type,
162+
parameterTypes,
163+
returnType,
164+
};
165+
}
166+
}

packages/metadata/test/unit/decorator-factory.ts renamed to packages/metadata/test/unit/decorator-factory.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55

66
import {expect} from '@loopback/testlab';
77
import {
8-
Reflector,
98
ClassDecoratorFactory,
109
PropertyDecoratorFactory,
1110
MethodDecoratorFactory,
1211
ParameterDecoratorFactory,
1312
DecoratorFactory,
1413
} from '../..';
1514

15+
import {Reflector} from '../../src/reflect';
16+
1617
describe('ClassDecoratorFactory', () => {
1718
/**
1819
* Define `@classDecorator(spec)`

0 commit comments

Comments
 (0)