@e22m4u/ts-rest-router 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.c8rc +9 -0
- package/.commitlintrc +5 -0
- package/.editorconfig +13 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +6 -0
- package/.mocharc.json +5 -0
- package/.prettierrc +7 -0
- package/LICENSE +21 -0
- package/README-ru.md +41 -0
- package/README.md +41 -0
- package/build-cjs.js +16 -0
- package/dist/cjs/index.cjs +692 -0
- package/dist/esm/controller-registry.d.ts +65 -0
- package/dist/esm/controller-registry.js +281 -0
- package/dist/esm/controller-registry.spec.d.ts +1 -0
- package/dist/esm/controller-registry.spec.js +719 -0
- package/dist/esm/debuggable-service.d.ts +18 -0
- package/dist/esm/debuggable-service.js +23 -0
- package/dist/esm/debuggable-service.spec.d.ts +1 -0
- package/dist/esm/debuggable-service.spec.js +16 -0
- package/dist/esm/decorators/action/action-decorator.d.ts +53 -0
- package/dist/esm/decorators/action/action-decorator.js +66 -0
- package/dist/esm/decorators/action/action-decorator.spec.d.ts +1 -0
- package/dist/esm/decorators/action/action-decorator.spec.js +59 -0
- package/dist/esm/decorators/action/action-metadata.d.ts +23 -0
- package/dist/esm/decorators/action/action-metadata.js +5 -0
- package/dist/esm/decorators/action/action-reflector.d.ts +22 -0
- package/dist/esm/decorators/action/action-reflector.js +29 -0
- package/dist/esm/decorators/action/action-reflector.spec.d.ts +1 -0
- package/dist/esm/decorators/action/action-reflector.spec.js +84 -0
- package/dist/esm/decorators/action/index.d.ts +3 -0
- package/dist/esm/decorators/action/index.js +3 -0
- package/dist/esm/decorators/controller/controller-decorator.d.ts +13 -0
- package/dist/esm/decorators/controller/controller-decorator.js +20 -0
- package/dist/esm/decorators/controller/controller-decorator.spec.d.ts +1 -0
- package/dist/esm/decorators/controller/controller-decorator.spec.js +53 -0
- package/dist/esm/decorators/controller/controller-metadata.d.ts +17 -0
- package/dist/esm/decorators/controller/controller-metadata.js +5 -0
- package/dist/esm/decorators/controller/controller-reflector.d.ts +20 -0
- package/dist/esm/decorators/controller/controller-reflector.js +24 -0
- package/dist/esm/decorators/controller/controller-reflector.spec.d.ts +1 -0
- package/dist/esm/decorators/controller/controller-reflector.spec.js +45 -0
- package/dist/esm/decorators/controller/index.d.ts +3 -0
- package/dist/esm/decorators/controller/index.js +3 -0
- package/dist/esm/decorators/index.d.ts +4 -0
- package/dist/esm/decorators/index.js +4 -0
- package/dist/esm/decorators/request-context/index.d.ts +3 -0
- package/dist/esm/decorators/request-context/index.js +3 -0
- package/dist/esm/decorators/request-context/request-context-decorator.d.ts +17 -0
- package/dist/esm/decorators/request-context/request-context-decorator.js +32 -0
- package/dist/esm/decorators/request-context/request-context-decorator.spec.d.ts +1 -0
- package/dist/esm/decorators/request-context/request-context-decorator.spec.js +59 -0
- package/dist/esm/decorators/request-context/request-context-metadata.d.ts +17 -0
- package/dist/esm/decorators/request-context/request-context-metadata.js +5 -0
- package/dist/esm/decorators/request-context/request-context-reflector.d.ts +24 -0
- package/dist/esm/decorators/request-context/request-context-reflector.js +31 -0
- package/dist/esm/decorators/request-context/request-context-reflector.spec.d.ts +1 -0
- package/dist/esm/decorators/request-context/request-context-reflector.spec.js +59 -0
- package/dist/esm/decorators/request-data/index.d.ts +3 -0
- package/dist/esm/decorators/request-data/index.js +3 -0
- package/dist/esm/decorators/request-data/request-data-decorator.d.ts +28 -0
- package/dist/esm/decorators/request-data/request-data-decorator.js +84 -0
- package/dist/esm/decorators/request-data/request-data-decorator.spec.d.ts +1 -0
- package/dist/esm/decorators/request-data/request-data-decorator.spec.js +534 -0
- package/dist/esm/decorators/request-data/request-data-metadata.d.ts +29 -0
- package/dist/esm/decorators/request-data/request-data-metadata.js +16 -0
- package/dist/esm/decorators/request-data/request-data-reflector.d.ts +24 -0
- package/dist/esm/decorators/request-data/request-data-reflector.js +31 -0
- package/dist/esm/decorators/request-data/request-data-reflector.spec.d.ts +1 -0
- package/dist/esm/decorators/request-data/request-data-reflector.spec.js +60 -0
- package/dist/esm/errors/index.d.ts +1 -0
- package/dist/esm/errors/index.js +1 -0
- package/dist/esm/errors/not-a-controller-error.d.ts +12 -0
- package/dist/esm/errors/not-a-controller-error.js +14 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/rest-router.d.ts +19 -0
- package/dist/esm/rest-router.js +24 -0
- package/dist/esm/types.d.ts +57 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/utils/capitalize.d.ts +6 -0
- package/dist/esm/utils/capitalize.js +8 -0
- package/dist/esm/utils/capitalize.spec.d.ts +1 -0
- package/dist/esm/utils/capitalize.spec.js +8 -0
- package/dist/esm/utils/create-debugger.d.ts +11 -0
- package/dist/esm/utils/create-debugger.js +15 -0
- package/dist/esm/utils/create-debugger.spec.d.ts +1 -0
- package/dist/esm/utils/create-debugger.spec.js +8 -0
- package/dist/esm/utils/create-error.d.ts +10 -0
- package/dist/esm/utils/create-error.js +13 -0
- package/dist/esm/utils/create-error.spec.d.ts +1 -0
- package/dist/esm/utils/create-error.spec.js +8 -0
- package/dist/esm/utils/index.d.ts +4 -0
- package/dist/esm/utils/index.js +4 -0
- package/dist/esm/utils/to-camel-case.d.ts +6 -0
- package/dist/esm/utils/to-camel-case.js +11 -0
- package/dist/esm/utils/to-camel-case.spec.d.ts +1 -0
- package/dist/esm/utils/to-camel-case.spec.js +10 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/eslint.config.js +43 -0
- package/package.json +74 -0
- package/src/controller-registry.spec.ts +592 -0
- package/src/controller-registry.ts +355 -0
- package/src/debuggable-service.spec.ts +18 -0
- package/src/debuggable-service.ts +27 -0
- package/src/decorators/action/action-decorator.spec.ts +42 -0
- package/src/decorators/action/action-decorator.ts +100 -0
- package/src/decorators/action/action-metadata.ts +28 -0
- package/src/decorators/action/action-reflector.spec.ts +84 -0
- package/src/decorators/action/action-reflector.ts +38 -0
- package/src/decorators/action/index.ts +3 -0
- package/src/decorators/controller/controller-decorator.spec.ts +41 -0
- package/src/decorators/controller/controller-decorator.ts +29 -0
- package/src/decorators/controller/controller-metadata.ts +21 -0
- package/src/decorators/controller/controller-reflector.spec.ts +45 -0
- package/src/decorators/controller/controller-reflector.ts +28 -0
- package/src/decorators/controller/index.ts +3 -0
- package/src/decorators/index.ts +4 -0
- package/src/decorators/request-context/index.ts +3 -0
- package/src/decorators/request-context/request-context-decorator.spec.ts +41 -0
- package/src/decorators/request-context/request-context-decorator.ts +57 -0
- package/src/decorators/request-context/request-context-metadata.ts +21 -0
- package/src/decorators/request-context/request-context-reflector.spec.ts +77 -0
- package/src/decorators/request-context/request-context-reflector.ts +57 -0
- package/src/decorators/request-data/index.ts +3 -0
- package/src/decorators/request-data/request-data-decorator.spec.ts +477 -0
- package/src/decorators/request-data/request-data-decorator.ts +106 -0
- package/src/decorators/request-data/request-data-metadata.ts +34 -0
- package/src/decorators/request-data/request-data-reflector.spec.ts +78 -0
- package/src/decorators/request-data/request-data-reflector.ts +57 -0
- package/src/errors/index.ts +1 -0
- package/src/errors/not-a-controller-error.ts +15 -0
- package/src/index.ts +5 -0
- package/src/rest-router.ts +31 -0
- package/src/types.ts +59 -0
- package/src/utils/capitalize.spec.ts +9 -0
- package/src/utils/capitalize.ts +8 -0
- package/src/utils/create-debugger.spec.ts +9 -0
- package/src/utils/create-debugger.ts +21 -0
- package/src/utils/create-error.spec.ts +9 -0
- package/src/utils/create-error.ts +19 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/to-camel-case.spec.ts +11 -0
- package/src/utils/to-camel-case.ts +11 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Debugger } from './utils/index.js';
|
|
2
|
+
import { Service } from '@e22m4u/js-service';
|
|
3
|
+
import { ServiceContainer } from '@e22m4u/js-service';
|
|
4
|
+
/**
|
|
5
|
+
* Service.
|
|
6
|
+
*/
|
|
7
|
+
export declare class DebuggableService extends Service {
|
|
8
|
+
/**
|
|
9
|
+
* Debug.
|
|
10
|
+
*/
|
|
11
|
+
debug: Debugger;
|
|
12
|
+
/**
|
|
13
|
+
* Constructor.
|
|
14
|
+
*
|
|
15
|
+
* @param container
|
|
16
|
+
*/
|
|
17
|
+
constructor(container?: ServiceContainer);
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Service } from '@e22m4u/js-service';
|
|
2
|
+
import { toCamelCase } from './utils/index.js';
|
|
3
|
+
import { createDebugger } from './utils/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Service.
|
|
6
|
+
*/
|
|
7
|
+
export class DebuggableService extends Service {
|
|
8
|
+
/**
|
|
9
|
+
* Debug.
|
|
10
|
+
*/
|
|
11
|
+
debug;
|
|
12
|
+
/**
|
|
13
|
+
* Constructor.
|
|
14
|
+
*
|
|
15
|
+
* @param container
|
|
16
|
+
*/
|
|
17
|
+
constructor(container) {
|
|
18
|
+
super(container);
|
|
19
|
+
const serviceName = toCamelCase(this.constructor.name);
|
|
20
|
+
this.debug = createDebugger(serviceName);
|
|
21
|
+
this.debug('%v is created.', this.constructor);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { describe } from 'mocha';
|
|
3
|
+
import { Service } from '@e22m4u/js-service';
|
|
4
|
+
import { DebuggableService } from './debuggable-service.js';
|
|
5
|
+
describe('DebuggableService', function () {
|
|
6
|
+
it('has the debug method', function () {
|
|
7
|
+
const res = new DebuggableService();
|
|
8
|
+
expect(typeof res.debug).to.be.eq('function');
|
|
9
|
+
});
|
|
10
|
+
describe('constructor', function () {
|
|
11
|
+
it('extends the Service class', function () {
|
|
12
|
+
const res = new DebuggableService();
|
|
13
|
+
expect(res).to.be.instanceof(Service);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Flatten } from '../../types.js';
|
|
2
|
+
import { Prototype } from '../../types.js';
|
|
3
|
+
import { ActionMetadata } from './action-metadata.js';
|
|
4
|
+
/**
|
|
5
|
+
* Action options.
|
|
6
|
+
*/
|
|
7
|
+
export type ActionOptions = Flatten<Omit<ActionMetadata, 'propertyKey'>>;
|
|
8
|
+
/**
|
|
9
|
+
* Action decorator.
|
|
10
|
+
*
|
|
11
|
+
* @param options
|
|
12
|
+
*/
|
|
13
|
+
export declare function action<T extends object>(options: ActionOptions): (target: Prototype<T>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Action alias options.
|
|
16
|
+
*/
|
|
17
|
+
type ActionAliasOptions = Flatten<Omit<ActionOptions, 'method' | 'path'>>;
|
|
18
|
+
/**
|
|
19
|
+
* Get decorator.
|
|
20
|
+
*
|
|
21
|
+
* @param path
|
|
22
|
+
* @param options
|
|
23
|
+
*/
|
|
24
|
+
export declare const get: (path: string, options?: ActionAliasOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Post decorator.
|
|
27
|
+
*
|
|
28
|
+
* @param path
|
|
29
|
+
* @param options
|
|
30
|
+
*/
|
|
31
|
+
export declare const post: (path: string, options?: ActionAliasOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Put decorator.
|
|
34
|
+
*
|
|
35
|
+
* @param path
|
|
36
|
+
* @param options
|
|
37
|
+
*/
|
|
38
|
+
export declare const put: (path: string, options?: ActionAliasOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Patch decorator.
|
|
41
|
+
*
|
|
42
|
+
* @param path
|
|
43
|
+
* @param options
|
|
44
|
+
*/
|
|
45
|
+
export declare const patch: (path: string, options?: ActionAliasOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Del decorator.
|
|
48
|
+
*
|
|
49
|
+
* @param path
|
|
50
|
+
* @param options
|
|
51
|
+
*/
|
|
52
|
+
export declare const del: (path: string, options?: ActionAliasOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { HttpMethod } from '@e22m4u/js-trie-router';
|
|
2
|
+
import { ActionReflector } from './action-reflector.js';
|
|
3
|
+
import { DecoratorTargetType } from '@e22m4u/ts-reflector';
|
|
4
|
+
import { getDecoratorTargetType } from '@e22m4u/ts-reflector';
|
|
5
|
+
/**
|
|
6
|
+
* Action decorator.
|
|
7
|
+
*
|
|
8
|
+
* @param options
|
|
9
|
+
*/
|
|
10
|
+
export function action(options) {
|
|
11
|
+
return function (target, propertyKey, descriptor) {
|
|
12
|
+
const decoratorType = getDecoratorTargetType(target, propertyKey, descriptor);
|
|
13
|
+
if (decoratorType !== DecoratorTargetType.INSTANCE_METHOD)
|
|
14
|
+
throw new Error('@action decorator is only supported on an instance method.');
|
|
15
|
+
const metadata = {
|
|
16
|
+
...options,
|
|
17
|
+
propertyKey,
|
|
18
|
+
};
|
|
19
|
+
ActionReflector.setMetadata(metadata, target.constructor, propertyKey);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get decorator.
|
|
24
|
+
*
|
|
25
|
+
* @param path
|
|
26
|
+
* @param options
|
|
27
|
+
*/
|
|
28
|
+
export const get = (path, options) => {
|
|
29
|
+
return action({ ...options, path, method: HttpMethod.GET });
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Post decorator.
|
|
33
|
+
*
|
|
34
|
+
* @param path
|
|
35
|
+
* @param options
|
|
36
|
+
*/
|
|
37
|
+
export const post = (path, options) => {
|
|
38
|
+
return action({ ...options, path, method: HttpMethod.POST });
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Put decorator.
|
|
42
|
+
*
|
|
43
|
+
* @param path
|
|
44
|
+
* @param options
|
|
45
|
+
*/
|
|
46
|
+
export const put = (path, options) => {
|
|
47
|
+
return action({ ...options, path, method: HttpMethod.PUT });
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Patch decorator.
|
|
51
|
+
*
|
|
52
|
+
* @param path
|
|
53
|
+
* @param options
|
|
54
|
+
*/
|
|
55
|
+
export const patch = (path, options) => {
|
|
56
|
+
return action({ ...options, path, method: HttpMethod.PATCH });
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Del decorator.
|
|
60
|
+
*
|
|
61
|
+
* @param path
|
|
62
|
+
* @param options
|
|
63
|
+
*/
|
|
64
|
+
export const del = (path, options) => {
|
|
65
|
+
return action({ ...options, path, method: HttpMethod.DELETE });
|
|
66
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { expect } from 'chai';
|
|
11
|
+
import { action } from './action-decorator.js';
|
|
12
|
+
import { HttpMethod } from '@e22m4u/js-trie-router';
|
|
13
|
+
import { ActionReflector } from './action-reflector.js';
|
|
14
|
+
describe('action', function () {
|
|
15
|
+
it('sets given options to the target metadata', function () {
|
|
16
|
+
const method = HttpMethod.GET;
|
|
17
|
+
const path = 'myPath';
|
|
18
|
+
const before = () => undefined;
|
|
19
|
+
const after = () => undefined;
|
|
20
|
+
const customOption = 'customOption';
|
|
21
|
+
class Target {
|
|
22
|
+
method() { }
|
|
23
|
+
}
|
|
24
|
+
__decorate([
|
|
25
|
+
action({ method, path, before, after, customOption }),
|
|
26
|
+
__metadata("design:type", Function),
|
|
27
|
+
__metadata("design:paramtypes", []),
|
|
28
|
+
__metadata("design:returntype", void 0)
|
|
29
|
+
], Target.prototype, "method", null);
|
|
30
|
+
const res = ActionReflector.getMetadata(Target);
|
|
31
|
+
expect(res.get('method')).to.be.eql({
|
|
32
|
+
propertyKey: 'method',
|
|
33
|
+
method,
|
|
34
|
+
path,
|
|
35
|
+
before,
|
|
36
|
+
after,
|
|
37
|
+
customOption,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
it('overrides a given "propertyKey" option by the target method name', function () {
|
|
41
|
+
const method = HttpMethod.GET;
|
|
42
|
+
const path = 'myPath';
|
|
43
|
+
class Target {
|
|
44
|
+
method() { }
|
|
45
|
+
}
|
|
46
|
+
__decorate([
|
|
47
|
+
action({ propertyKey: 'myMethod', method, path }),
|
|
48
|
+
__metadata("design:type", Function),
|
|
49
|
+
__metadata("design:paramtypes", []),
|
|
50
|
+
__metadata("design:returntype", void 0)
|
|
51
|
+
], Target.prototype, "method", null);
|
|
52
|
+
const res = ActionReflector.getMetadata(Target);
|
|
53
|
+
expect(res.get('method')).to.be.eql({
|
|
54
|
+
propertyKey: 'method',
|
|
55
|
+
method,
|
|
56
|
+
path,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { MetadataKey } from '@e22m4u/ts-reflector';
|
|
2
|
+
import { HttpMethod } from '@e22m4u/js-trie-router';
|
|
3
|
+
import { RoutePreHandler } from '@e22m4u/js-trie-router';
|
|
4
|
+
import { RoutePostHandler } from '@e22m4u/js-trie-router';
|
|
5
|
+
/**
|
|
6
|
+
* Action metadata.
|
|
7
|
+
*/
|
|
8
|
+
export type ActionMetadata = {
|
|
9
|
+
propertyKey: string;
|
|
10
|
+
method: HttpMethod;
|
|
11
|
+
path: string;
|
|
12
|
+
before?: RoutePreHandler | RoutePreHandler[];
|
|
13
|
+
after?: RoutePostHandler | RoutePostHandler[];
|
|
14
|
+
[option: string]: unknown | undefined;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Action metadata map.
|
|
18
|
+
*/
|
|
19
|
+
export type ActionMetadataMap = Map<string, ActionMetadata>;
|
|
20
|
+
/**
|
|
21
|
+
* Actions metadata key.
|
|
22
|
+
*/
|
|
23
|
+
export declare const ACTIONS_METADATA_KEY: MetadataKey<ActionMetadataMap>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Constructor } from '../../types.js';
|
|
2
|
+
import { ActionMetadata } from './action-metadata.js';
|
|
3
|
+
import { ActionMetadataMap } from './action-metadata.js';
|
|
4
|
+
/**
|
|
5
|
+
* Action reflector.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ActionReflector {
|
|
8
|
+
/**
|
|
9
|
+
* Set metadata.
|
|
10
|
+
*
|
|
11
|
+
* @param metadata
|
|
12
|
+
* @param target
|
|
13
|
+
* @param propertyKey
|
|
14
|
+
*/
|
|
15
|
+
static setMetadata(metadata: ActionMetadata, target: Constructor, propertyKey: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Get metadata.
|
|
18
|
+
*
|
|
19
|
+
* @param target
|
|
20
|
+
*/
|
|
21
|
+
static getMetadata(target: Constructor): ActionMetadataMap;
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Reflector } from '@e22m4u/ts-reflector';
|
|
2
|
+
import { ACTIONS_METADATA_KEY } from './action-metadata.js';
|
|
3
|
+
/**
|
|
4
|
+
* Action reflector.
|
|
5
|
+
*/
|
|
6
|
+
export class ActionReflector {
|
|
7
|
+
/**
|
|
8
|
+
* Set metadata.
|
|
9
|
+
*
|
|
10
|
+
* @param metadata
|
|
11
|
+
* @param target
|
|
12
|
+
* @param propertyKey
|
|
13
|
+
*/
|
|
14
|
+
static setMetadata(metadata, target, propertyKey) {
|
|
15
|
+
const oldMap = Reflector.getOwnMetadata(ACTIONS_METADATA_KEY, target);
|
|
16
|
+
const newMap = new Map(oldMap);
|
|
17
|
+
newMap.set(propertyKey, metadata);
|
|
18
|
+
Reflector.defineMetadata(ACTIONS_METADATA_KEY, newMap, target);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get metadata.
|
|
22
|
+
*
|
|
23
|
+
* @param target
|
|
24
|
+
*/
|
|
25
|
+
static getMetadata(target) {
|
|
26
|
+
const metadata = Reflector.getOwnMetadata(ACTIONS_METADATA_KEY, target);
|
|
27
|
+
return metadata ?? new Map();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { describe } from 'mocha';
|
|
3
|
+
import { Reflector } from '@e22m4u/ts-reflector';
|
|
4
|
+
import { HttpMethod } from '@e22m4u/js-trie-router';
|
|
5
|
+
import { ActionReflector } from './action-reflector.js';
|
|
6
|
+
import { ACTIONS_METADATA_KEY } from './action-metadata.js';
|
|
7
|
+
describe('ActionReflector', function () {
|
|
8
|
+
describe('setMetadata', function () {
|
|
9
|
+
it('sets a given value as target metadata', function () {
|
|
10
|
+
class Target {
|
|
11
|
+
}
|
|
12
|
+
const md1 = {
|
|
13
|
+
propertyKey: 'propertyKey1',
|
|
14
|
+
method: HttpMethod.GET,
|
|
15
|
+
path: '/foo',
|
|
16
|
+
};
|
|
17
|
+
const md2 = {
|
|
18
|
+
propertyKey: 'propertyKey2',
|
|
19
|
+
method: HttpMethod.GET,
|
|
20
|
+
path: '/bar',
|
|
21
|
+
};
|
|
22
|
+
ActionReflector.setMetadata(md1, Target, 'propertyKey1');
|
|
23
|
+
ActionReflector.setMetadata(md2, Target, 'propertyKey2');
|
|
24
|
+
const res = Reflector.getOwnMetadata(ACTIONS_METADATA_KEY, Target);
|
|
25
|
+
expect(res).to.be.instanceof(Map);
|
|
26
|
+
expect(res.get('propertyKey1')).to.be.eq(md1);
|
|
27
|
+
expect(res.get('propertyKey2')).to.be.eq(md2);
|
|
28
|
+
});
|
|
29
|
+
it('overrides existing metadata', function () {
|
|
30
|
+
class Target {
|
|
31
|
+
}
|
|
32
|
+
const md1 = {
|
|
33
|
+
propertyKey: 'propertyKey',
|
|
34
|
+
method: HttpMethod.GET,
|
|
35
|
+
path: '/foo',
|
|
36
|
+
};
|
|
37
|
+
const md2 = {
|
|
38
|
+
propertyKey: 'propertyKey',
|
|
39
|
+
method: HttpMethod.POST,
|
|
40
|
+
path: '/bar',
|
|
41
|
+
};
|
|
42
|
+
ActionReflector.setMetadata(md1, Target, 'propertyKey');
|
|
43
|
+
const res1 = Reflector.getOwnMetadata(ACTIONS_METADATA_KEY, Target);
|
|
44
|
+
expect(res1).to.be.instanceof(Map);
|
|
45
|
+
expect(res1.get('propertyKey')).to.be.eq(md1);
|
|
46
|
+
ActionReflector.setMetadata(md2, Target, 'propertyKey');
|
|
47
|
+
const res2 = Reflector.getOwnMetadata(ACTIONS_METADATA_KEY, Target);
|
|
48
|
+
expect(res2).to.be.instanceof(Map);
|
|
49
|
+
expect(res2.get('propertyKey')).to.be.eq(md2);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('getMetadata', function () {
|
|
53
|
+
it('returns an existing metadata of the target', function () {
|
|
54
|
+
class Target {
|
|
55
|
+
}
|
|
56
|
+
const md1 = {
|
|
57
|
+
propertyKey: 'propertyKey1',
|
|
58
|
+
method: HttpMethod.GET,
|
|
59
|
+
path: '/foo',
|
|
60
|
+
};
|
|
61
|
+
const md2 = {
|
|
62
|
+
propertyKey: 'propertyKey2',
|
|
63
|
+
method: HttpMethod.GET,
|
|
64
|
+
path: '/bar',
|
|
65
|
+
};
|
|
66
|
+
const mdMap = new Map([
|
|
67
|
+
['propertyKey1', md1],
|
|
68
|
+
['propertyKey2', md2],
|
|
69
|
+
]);
|
|
70
|
+
Reflector.defineMetadata(ACTIONS_METADATA_KEY, mdMap, Target);
|
|
71
|
+
const res = ActionReflector.getMetadata(Target);
|
|
72
|
+
expect(res).to.be.instanceof(Map);
|
|
73
|
+
expect(res.get('propertyKey1')).to.be.eq(md1);
|
|
74
|
+
expect(res.get('propertyKey2')).to.be.eq(md2);
|
|
75
|
+
});
|
|
76
|
+
it('returns an empty map if no metadata', function () {
|
|
77
|
+
class Target {
|
|
78
|
+
}
|
|
79
|
+
const res = ActionReflector.getMetadata(Target);
|
|
80
|
+
expect(res).to.be.instanceof(Map);
|
|
81
|
+
expect(res).to.be.empty;
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Flatten } from '../../types.js';
|
|
2
|
+
import { Constructor } from '../../types.js';
|
|
3
|
+
import { ControllerMetadata } from './controller-metadata.js';
|
|
4
|
+
/**
|
|
5
|
+
* Controller options.
|
|
6
|
+
*/
|
|
7
|
+
export type ControllerOptions = Flatten<Omit<ControllerMetadata, 'className'>>;
|
|
8
|
+
/**
|
|
9
|
+
* Controller decorator.
|
|
10
|
+
*
|
|
11
|
+
* @param options
|
|
12
|
+
*/
|
|
13
|
+
export declare function controller<T extends object>(options?: ControllerOptions): (target: Constructor<T>) => void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DecoratorTargetType } from '@e22m4u/ts-reflector';
|
|
2
|
+
import { getDecoratorTargetType } from '@e22m4u/ts-reflector';
|
|
3
|
+
import { ControllerReflector } from './controller-reflector.js';
|
|
4
|
+
/**
|
|
5
|
+
* Controller decorator.
|
|
6
|
+
*
|
|
7
|
+
* @param options
|
|
8
|
+
*/
|
|
9
|
+
export function controller(options) {
|
|
10
|
+
return function (target) {
|
|
11
|
+
const decoratorType = getDecoratorTargetType(target);
|
|
12
|
+
if (decoratorType !== DecoratorTargetType.CONSTRUCTOR)
|
|
13
|
+
throw new Error('@controller decorator is only supported on a class.');
|
|
14
|
+
const metadata = {
|
|
15
|
+
...options,
|
|
16
|
+
className: target.name,
|
|
17
|
+
};
|
|
18
|
+
ControllerReflector.setMetadata(metadata, target);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { expect } from 'chai';
|
|
8
|
+
import { controller } from './controller-decorator.js';
|
|
9
|
+
import { ControllerReflector } from './controller-reflector.js';
|
|
10
|
+
describe('controller', function () {
|
|
11
|
+
it('does not requires options', function () {
|
|
12
|
+
let Target = class Target {
|
|
13
|
+
};
|
|
14
|
+
Target = __decorate([
|
|
15
|
+
controller()
|
|
16
|
+
], Target);
|
|
17
|
+
const res = ControllerReflector.getMetadata(Target);
|
|
18
|
+
expect(res).to.be.eql({ className: 'Target' });
|
|
19
|
+
});
|
|
20
|
+
it('sets given options to the target metadata', function () {
|
|
21
|
+
const path = 'myPath';
|
|
22
|
+
const before = () => undefined;
|
|
23
|
+
const after = () => undefined;
|
|
24
|
+
const extraOption = 'extraOption';
|
|
25
|
+
let Target = class Target {
|
|
26
|
+
};
|
|
27
|
+
Target = __decorate([
|
|
28
|
+
controller({
|
|
29
|
+
path,
|
|
30
|
+
before,
|
|
31
|
+
after,
|
|
32
|
+
extraOption,
|
|
33
|
+
})
|
|
34
|
+
], Target);
|
|
35
|
+
const res = ControllerReflector.getMetadata(Target);
|
|
36
|
+
expect(res).to.be.eql({
|
|
37
|
+
className: 'Target',
|
|
38
|
+
path,
|
|
39
|
+
before,
|
|
40
|
+
after,
|
|
41
|
+
extraOption,
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
it('overrides given "className" option by the target class name', function () {
|
|
45
|
+
let Target = class Target {
|
|
46
|
+
};
|
|
47
|
+
Target = __decorate([
|
|
48
|
+
controller({ className: 'myClassName' })
|
|
49
|
+
], Target);
|
|
50
|
+
const res = ControllerReflector.getMetadata(Target);
|
|
51
|
+
expect(res).to.be.eql({ className: 'Target' });
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RoutePreHandler } from '@e22m4u/js-trie-router';
|
|
2
|
+
import { RoutePostHandler } from '@e22m4u/js-trie-router';
|
|
3
|
+
import { MetadataKey } from '@e22m4u/ts-reflector';
|
|
4
|
+
/**
|
|
5
|
+
* Controller metadata.
|
|
6
|
+
*/
|
|
7
|
+
export type ControllerMetadata = {
|
|
8
|
+
className: string;
|
|
9
|
+
path?: string;
|
|
10
|
+
before?: RoutePreHandler | RoutePreHandler[];
|
|
11
|
+
after?: RoutePostHandler | RoutePostHandler[];
|
|
12
|
+
[option: string]: unknown | undefined;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Controller metadata key.
|
|
16
|
+
*/
|
|
17
|
+
export declare const CONTROLLER_METADATA_KEY: MetadataKey<ControllerMetadata>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Constructor } from '../../types.js';
|
|
2
|
+
import { ControllerMetadata } from './controller-metadata.js';
|
|
3
|
+
/**
|
|
4
|
+
* Controller reflector.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ControllerReflector {
|
|
7
|
+
/**
|
|
8
|
+
* Set metadata.
|
|
9
|
+
*
|
|
10
|
+
* @param metadata
|
|
11
|
+
* @param target
|
|
12
|
+
*/
|
|
13
|
+
static setMetadata(metadata: ControllerMetadata, target: Constructor): void;
|
|
14
|
+
/**
|
|
15
|
+
* Get metadata.
|
|
16
|
+
*
|
|
17
|
+
* @param target
|
|
18
|
+
*/
|
|
19
|
+
static getMetadata(target: Constructor): ControllerMetadata | undefined;
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Reflector } from '@e22m4u/ts-reflector';
|
|
2
|
+
import { CONTROLLER_METADATA_KEY } from './controller-metadata.js';
|
|
3
|
+
/**
|
|
4
|
+
* Controller reflector.
|
|
5
|
+
*/
|
|
6
|
+
export class ControllerReflector {
|
|
7
|
+
/**
|
|
8
|
+
* Set metadata.
|
|
9
|
+
*
|
|
10
|
+
* @param metadata
|
|
11
|
+
* @param target
|
|
12
|
+
*/
|
|
13
|
+
static setMetadata(metadata, target) {
|
|
14
|
+
return Reflector.defineMetadata(CONTROLLER_METADATA_KEY, metadata, target);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get metadata.
|
|
18
|
+
*
|
|
19
|
+
* @param target
|
|
20
|
+
*/
|
|
21
|
+
static getMetadata(target) {
|
|
22
|
+
return Reflector.getOwnMetadata(CONTROLLER_METADATA_KEY, target);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { describe } from 'mocha';
|
|
3
|
+
import { Reflector } from '@e22m4u/ts-reflector';
|
|
4
|
+
import { ControllerReflector } from './controller-reflector.js';
|
|
5
|
+
import { CONTROLLER_METADATA_KEY } from './controller-metadata.js';
|
|
6
|
+
describe('ControllerReflector', function () {
|
|
7
|
+
describe('setMetadata', function () {
|
|
8
|
+
it('sets a given value as target metadata', function () {
|
|
9
|
+
class Target {
|
|
10
|
+
}
|
|
11
|
+
const md = { className: 'Target' };
|
|
12
|
+
ControllerReflector.setMetadata(md, Target);
|
|
13
|
+
const res = Reflector.getOwnMetadata(CONTROLLER_METADATA_KEY, Target);
|
|
14
|
+
expect(res).to.be.eq(md);
|
|
15
|
+
});
|
|
16
|
+
it('overrides existing metadata', function () {
|
|
17
|
+
class Target {
|
|
18
|
+
}
|
|
19
|
+
const md1 = { className: 'Target', path: 'path1' };
|
|
20
|
+
const md2 = { className: 'Target', path: 'path2' };
|
|
21
|
+
ControllerReflector.setMetadata(md1, Target);
|
|
22
|
+
const res1 = Reflector.getOwnMetadata(CONTROLLER_METADATA_KEY, Target);
|
|
23
|
+
expect(res1).to.be.eq(md1);
|
|
24
|
+
ControllerReflector.setMetadata(md2, Target);
|
|
25
|
+
const res2 = Reflector.getOwnMetadata(CONTROLLER_METADATA_KEY, Target);
|
|
26
|
+
expect(res2).to.be.eq(md2);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('getMetadata', function () {
|
|
30
|
+
it('returns an existing metadata of the target', function () {
|
|
31
|
+
class Target {
|
|
32
|
+
}
|
|
33
|
+
const md = { className: 'Target' };
|
|
34
|
+
Reflector.defineMetadata(CONTROLLER_METADATA_KEY, md, Target);
|
|
35
|
+
const res = ControllerReflector.getMetadata(Target);
|
|
36
|
+
expect(res).to.be.eq(md);
|
|
37
|
+
});
|
|
38
|
+
it('returns undefined if no metadata', function () {
|
|
39
|
+
class Target {
|
|
40
|
+
}
|
|
41
|
+
const res = ControllerReflector.getMetadata(Target);
|
|
42
|
+
expect(res).to.be.undefined;
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|