@e22m4u/ts-rest-router 0.0.7 → 0.1.0
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/README-ru.md +114 -91
- package/README.md +106 -85
- package/dist/cjs/index.cjs +427 -123
- package/dist/esm/controller-registry.d.ts +53 -11
- package/dist/esm/controller-registry.js +242 -104
- package/dist/esm/debuggable-service.js +1 -1
- package/dist/esm/decorators/after/after-decorator.d.ts +9 -0
- package/dist/esm/decorators/after/after-decorator.js +22 -0
- package/dist/esm/decorators/after/after-decorator.spec.d.ts +1 -0
- package/dist/esm/decorators/after/after-decorator.spec.js +115 -0
- package/dist/esm/decorators/after/after-metadata.d.ts +13 -0
- package/dist/esm/decorators/after/after-metadata.js +5 -0
- package/dist/esm/decorators/after/after-reflector.d.ts +22 -0
- package/dist/esm/decorators/after/after-reflector.js +29 -0
- package/dist/esm/decorators/after/after-reflector.spec.d.ts +1 -0
- package/dist/esm/decorators/after/after-reflector.spec.js +102 -0
- package/dist/esm/decorators/after/index.d.ts +3 -0
- package/dist/esm/decorators/after/index.js +3 -0
- package/dist/esm/decorators/before/before-decorator.d.ts +9 -0
- package/dist/esm/decorators/before/before-decorator.js +22 -0
- package/dist/esm/decorators/before/before-decorator.spec.d.ts +1 -0
- package/dist/esm/decorators/before/before-decorator.spec.js +115 -0
- package/dist/esm/decorators/before/before-metadata.d.ts +13 -0
- package/dist/esm/decorators/before/before-metadata.js +5 -0
- package/dist/esm/decorators/before/before-reflector.d.ts +22 -0
- package/dist/esm/decorators/before/before-reflector.js +29 -0
- package/dist/esm/decorators/before/before-reflector.spec.d.ts +1 -0
- package/dist/esm/decorators/before/before-reflector.spec.js +102 -0
- package/dist/esm/decorators/before/index.d.ts +3 -0
- package/dist/esm/decorators/before/index.js +3 -0
- package/dist/esm/decorators/controller/controller-decorator.d.ts +2 -1
- package/dist/esm/decorators/controller/controller-decorator.js +26 -1
- package/dist/esm/decorators/controller/controller-decorator.spec.js +28 -0
- package/dist/esm/decorators/index.d.ts +2 -0
- package/dist/esm/decorators/index.js +2 -0
- package/dist/esm/decorators/request-data/request-data-decorator.d.ts +1 -1
- package/dist/esm/decorators/request-data/request-data-decorator.js +1 -1
- package/dist/esm/decorators/request-data/request-data-decorator.spec.js +5 -5
- package/dist/esm/utils/create-debugger.d.ts +35 -2
- package/dist/esm/utils/create-debugger.js +71 -5
- package/package.json +1 -1
- package/src/controller-registry.spec.ts +601 -275
- package/src/controller-registry.ts +263 -128
- package/src/debuggable-service.ts +1 -1
- package/src/decorators/after/after-decorator.spec.ts +92 -0
- package/src/decorators/after/after-decorator.ts +40 -0
- package/src/decorators/after/after-metadata.ts +17 -0
- package/src/decorators/after/after-reflector.spec.ts +107 -0
- package/src/decorators/after/after-reflector.ts +45 -0
- package/src/decorators/after/index.ts +3 -0
- package/src/decorators/before/before-decorator.spec.ts +92 -0
- package/src/decorators/before/before-decorator.ts +40 -0
- package/src/decorators/before/before-metadata.ts +17 -0
- package/src/decorators/before/before-reflector.spec.ts +111 -0
- package/src/decorators/before/before-reflector.ts +50 -0
- package/src/decorators/before/index.ts +3 -0
- package/src/decorators/controller/controller-decorator.spec.ts +22 -0
- package/src/decorators/controller/controller-decorator.ts +29 -1
- package/src/decorators/index.ts +2 -0
- package/src/decorators/request-data/request-data-decorator.spec.ts +5 -5
- package/src/decorators/request-data/request-data-decorator.ts +1 -1
- package/src/utils/create-debugger.ts +84 -7
@@ -0,0 +1,40 @@
|
|
1
|
+
import {Prototype} from '../../types.js';
|
2
|
+
import {Constructor} from '../../types.js';
|
3
|
+
import {AfterMetadata} from './after-metadata.js';
|
4
|
+
import {AfterReflector} from './after-reflector.js';
|
5
|
+
import {DecoratorTargetType} from '@e22m4u/ts-reflector';
|
6
|
+
import {getDecoratorTargetType} from '@e22m4u/ts-reflector';
|
7
|
+
|
8
|
+
/**
|
9
|
+
* After decorator.
|
10
|
+
*
|
11
|
+
* @param options
|
12
|
+
*/
|
13
|
+
export function after<T extends object>(
|
14
|
+
middleware: AfterMetadata['middleware'],
|
15
|
+
) {
|
16
|
+
return function (
|
17
|
+
target: Constructor<T> | Prototype<T>,
|
18
|
+
propertyKey?: string,
|
19
|
+
descriptor?: PropertyDescriptor,
|
20
|
+
) {
|
21
|
+
const decoratorType = getDecoratorTargetType(
|
22
|
+
target,
|
23
|
+
propertyKey,
|
24
|
+
descriptor,
|
25
|
+
);
|
26
|
+
if (decoratorType === DecoratorTargetType.CONSTRUCTOR) {
|
27
|
+
AfterReflector.addMetadata({middleware}, target as Constructor<T>);
|
28
|
+
} else if (decoratorType === DecoratorTargetType.INSTANCE_METHOD) {
|
29
|
+
AfterReflector.addMetadata(
|
30
|
+
{propertyKey, middleware},
|
31
|
+
target.constructor as Constructor<T>,
|
32
|
+
propertyKey,
|
33
|
+
);
|
34
|
+
} else {
|
35
|
+
throw new Error(
|
36
|
+
'@after decorator is only supported on a class or an instance method.',
|
37
|
+
);
|
38
|
+
}
|
39
|
+
};
|
40
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import {MetadataKey} from '@e22m4u/ts-reflector';
|
2
|
+
import {RoutePostHandler} from '@e22m4u/js-trie-router';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* After metadata.
|
6
|
+
*/
|
7
|
+
export type AfterMetadata = {
|
8
|
+
propertyKey?: string;
|
9
|
+
middleware: RoutePostHandler | RoutePostHandler[];
|
10
|
+
};
|
11
|
+
|
12
|
+
/**
|
13
|
+
* After metadata key.
|
14
|
+
*/
|
15
|
+
export const AFTER_METADATA_KEY = new MetadataKey<AfterMetadata[]>(
|
16
|
+
'afterMetadataKey',
|
17
|
+
);
|
@@ -0,0 +1,107 @@
|
|
1
|
+
import {expect} from 'chai';
|
2
|
+
import {describe} from 'mocha';
|
3
|
+
import {Reflector} from '@e22m4u/ts-reflector';
|
4
|
+
import {AfterReflector} from './after-reflector.js';
|
5
|
+
import {AFTER_METADATA_KEY} from './after-metadata.js';
|
6
|
+
|
7
|
+
const MIDDLEWARE_1 = () => undefined;
|
8
|
+
const MIDDLEWARE_2 = () => undefined;
|
9
|
+
const MIDDLEWARE_3 = () => undefined;
|
10
|
+
|
11
|
+
describe('AfterReflector', function () {
|
12
|
+
describe('class target', function () {
|
13
|
+
describe('addMetadata', function () {
|
14
|
+
it('adds a given value to the target metadata', function () {
|
15
|
+
class Target {}
|
16
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
17
|
+
const md2 = {middleware: [MIDDLEWARE_2, MIDDLEWARE_3]};
|
18
|
+
AfterReflector.addMetadata(md1, Target);
|
19
|
+
AfterReflector.addMetadata(md2, Target);
|
20
|
+
const res = Reflector.getOwnMetadata(AFTER_METADATA_KEY, Target);
|
21
|
+
expect(res).to.be.eql([md2, md1]);
|
22
|
+
});
|
23
|
+
});
|
24
|
+
|
25
|
+
describe('getMetadata', function () {
|
26
|
+
it('returns an empty array if no metadata', function () {
|
27
|
+
class Target {}
|
28
|
+
const res = AfterReflector.getMetadata(Target);
|
29
|
+
expect(res).to.be.eql([]);
|
30
|
+
});
|
31
|
+
|
32
|
+
it('returns existing metadata by the target', function () {
|
33
|
+
class Target {}
|
34
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
35
|
+
const md2 = {middleware: [MIDDLEWARE_2, MIDDLEWARE_3]};
|
36
|
+
const mdArray = [md1, md2];
|
37
|
+
Reflector.defineMetadata(AFTER_METADATA_KEY, mdArray, Target);
|
38
|
+
const res = AfterReflector.getMetadata(Target);
|
39
|
+
expect(res).to.be.eql(mdArray);
|
40
|
+
});
|
41
|
+
});
|
42
|
+
});
|
43
|
+
|
44
|
+
describe('method target', function () {
|
45
|
+
describe('addMetadata', function () {
|
46
|
+
it('adds a given value to the target metadata', function () {
|
47
|
+
class Target {}
|
48
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
49
|
+
const md2 = {middleware: [MIDDLEWARE_2, MIDDLEWARE_3]};
|
50
|
+
AfterReflector.addMetadata(md1, Target, 'prop');
|
51
|
+
AfterReflector.addMetadata(md2, Target, 'prop');
|
52
|
+
const res = Reflector.getOwnMetadata(
|
53
|
+
AFTER_METADATA_KEY,
|
54
|
+
Target,
|
55
|
+
'prop',
|
56
|
+
);
|
57
|
+
expect(res).to.be.eql([md2, md1]);
|
58
|
+
});
|
59
|
+
});
|
60
|
+
|
61
|
+
describe('getMetadata', function () {
|
62
|
+
it('returns an empty array if no metadata', function () {
|
63
|
+
class Target {}
|
64
|
+
const res = AfterReflector.getMetadata(Target, 'prop');
|
65
|
+
expect(res).to.be.eql([]);
|
66
|
+
});
|
67
|
+
|
68
|
+
it('returns existing metadata by the target', function () {
|
69
|
+
class Target {}
|
70
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
71
|
+
const md2 = {middleware: [MIDDLEWARE_2, MIDDLEWARE_3]};
|
72
|
+
const mdArray = [md1, md2];
|
73
|
+
Reflector.defineMetadata(AFTER_METADATA_KEY, mdArray, Target, 'prop');
|
74
|
+
const res = AfterReflector.getMetadata(Target, 'prop');
|
75
|
+
expect(res).to.be.eql(mdArray);
|
76
|
+
});
|
77
|
+
});
|
78
|
+
});
|
79
|
+
|
80
|
+
describe('addMetadata', function () {
|
81
|
+
it('can distinguish class and method metadata', function () {
|
82
|
+
class Target {}
|
83
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
84
|
+
const md2 = {middleware: MIDDLEWARE_2};
|
85
|
+
AfterReflector.addMetadata(md1, Target);
|
86
|
+
AfterReflector.addMetadata(md2, Target, 'prop');
|
87
|
+
const res1 = Reflector.getOwnMetadata(AFTER_METADATA_KEY, Target);
|
88
|
+
const res2 = Reflector.getOwnMetadata(AFTER_METADATA_KEY, Target, 'prop');
|
89
|
+
expect(res1).to.be.eql([md1]);
|
90
|
+
expect(res2).to.be.eql([md2]);
|
91
|
+
});
|
92
|
+
});
|
93
|
+
|
94
|
+
describe('getMetadata', function () {
|
95
|
+
it('can distinguish class and method metadata', function () {
|
96
|
+
class Target {}
|
97
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
98
|
+
const md2 = {middleware: MIDDLEWARE_2};
|
99
|
+
Reflector.defineMetadata(AFTER_METADATA_KEY, [md1], Target);
|
100
|
+
Reflector.defineMetadata(AFTER_METADATA_KEY, [md2], Target, 'prop');
|
101
|
+
const res1 = AfterReflector.getMetadata(Target);
|
102
|
+
const res2 = AfterReflector.getMetadata(Target, 'prop');
|
103
|
+
expect(res1).to.be.eql([md1]);
|
104
|
+
expect(res2).to.be.eql([md2]);
|
105
|
+
});
|
106
|
+
});
|
107
|
+
});
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import {Constructor} from '../../types.js';
|
2
|
+
import {Reflector} from '@e22m4u/ts-reflector';
|
3
|
+
import {AfterMetadata} from './after-metadata.js';
|
4
|
+
import {AFTER_METADATA_KEY} from './after-metadata.js';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* After reflector.
|
8
|
+
*/
|
9
|
+
export class AfterReflector {
|
10
|
+
/**
|
11
|
+
* Set metadata.
|
12
|
+
*
|
13
|
+
* @param metadata
|
14
|
+
* @param target
|
15
|
+
* @param propertyKey
|
16
|
+
*/
|
17
|
+
static addMetadata(
|
18
|
+
metadata: AfterMetadata,
|
19
|
+
target: Constructor,
|
20
|
+
propertyKey?: string,
|
21
|
+
) {
|
22
|
+
const oldArray =
|
23
|
+
Reflector.getOwnMetadata(AFTER_METADATA_KEY, target, propertyKey) ?? [];
|
24
|
+
const newArray = [metadata, ...oldArray];
|
25
|
+
Reflector.defineMetadata(AFTER_METADATA_KEY, newArray, target, propertyKey);
|
26
|
+
}
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Get metadata.
|
30
|
+
*
|
31
|
+
* @param target
|
32
|
+
* @param propertyKey
|
33
|
+
*/
|
34
|
+
static getMetadata(
|
35
|
+
target: Constructor,
|
36
|
+
propertyKey?: string,
|
37
|
+
): AfterMetadata[] {
|
38
|
+
const metadata = Reflector.getOwnMetadata(
|
39
|
+
AFTER_METADATA_KEY,
|
40
|
+
target,
|
41
|
+
propertyKey,
|
42
|
+
);
|
43
|
+
return metadata ?? [];
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
/* eslint mocha/no-sibling-hooks: 0 */
|
2
|
+
import {expect} from 'chai';
|
3
|
+
import {before} from './before-decorator.js';
|
4
|
+
import {BeforeReflector} from './before-reflector.js';
|
5
|
+
|
6
|
+
const MIDDLEWARE_1 = () => undefined;
|
7
|
+
const MIDDLEWARE_2 = () => undefined;
|
8
|
+
const MIDDLEWARE_3 = () => undefined;
|
9
|
+
|
10
|
+
describe('before', function () {
|
11
|
+
describe('class target', function () {
|
12
|
+
it('sets given middleware to the target metadata', function () {
|
13
|
+
@before(MIDDLEWARE_1)
|
14
|
+
class Target {
|
15
|
+
method() {}
|
16
|
+
}
|
17
|
+
const res = BeforeReflector.getMetadata(Target);
|
18
|
+
expect(res).to.be.eql([{middleware: MIDDLEWARE_1}]);
|
19
|
+
});
|
20
|
+
|
21
|
+
it('sets miltiple middlewares to the target metadata', function () {
|
22
|
+
@before([MIDDLEWARE_1, MIDDLEWARE_2])
|
23
|
+
class Target {
|
24
|
+
method() {}
|
25
|
+
}
|
26
|
+
const res = BeforeReflector.getMetadata(Target);
|
27
|
+
expect(res).to.be.eql([{middleware: [MIDDLEWARE_1, MIDDLEWARE_2]}]);
|
28
|
+
});
|
29
|
+
|
30
|
+
it('allows to use the decorator multiple times', function () {
|
31
|
+
@before(MIDDLEWARE_1)
|
32
|
+
@before([MIDDLEWARE_2, MIDDLEWARE_3])
|
33
|
+
class Target {
|
34
|
+
method() {}
|
35
|
+
}
|
36
|
+
const res = BeforeReflector.getMetadata(Target);
|
37
|
+
expect(res).to.be.eql([
|
38
|
+
{middleware: MIDDLEWARE_1},
|
39
|
+
{middleware: [MIDDLEWARE_2, MIDDLEWARE_3]},
|
40
|
+
]);
|
41
|
+
});
|
42
|
+
});
|
43
|
+
|
44
|
+
describe('method target', function () {
|
45
|
+
it('sets given middleware to the target metadata', function () {
|
46
|
+
class Target {
|
47
|
+
@before(MIDDLEWARE_1)
|
48
|
+
method() {}
|
49
|
+
}
|
50
|
+
const res = BeforeReflector.getMetadata(Target, 'method');
|
51
|
+
expect(res).to.be.eql([
|
52
|
+
{
|
53
|
+
propertyKey: 'method',
|
54
|
+
middleware: MIDDLEWARE_1,
|
55
|
+
},
|
56
|
+
]);
|
57
|
+
});
|
58
|
+
|
59
|
+
it('sets miltiple middlewares to the target metadata', function () {
|
60
|
+
class Target {
|
61
|
+
@before([MIDDLEWARE_1, MIDDLEWARE_2])
|
62
|
+
method() {}
|
63
|
+
}
|
64
|
+
const res = BeforeReflector.getMetadata(Target, 'method');
|
65
|
+
expect(res).to.be.eql([
|
66
|
+
{
|
67
|
+
propertyKey: 'method',
|
68
|
+
middleware: [MIDDLEWARE_1, MIDDLEWARE_2],
|
69
|
+
},
|
70
|
+
]);
|
71
|
+
});
|
72
|
+
|
73
|
+
it('allows to use the decorator multiple times', function () {
|
74
|
+
class Target {
|
75
|
+
@before(MIDDLEWARE_1)
|
76
|
+
@before([MIDDLEWARE_2, MIDDLEWARE_3])
|
77
|
+
method() {}
|
78
|
+
}
|
79
|
+
const res = BeforeReflector.getMetadata(Target, 'method');
|
80
|
+
expect(res).to.be.eql([
|
81
|
+
{
|
82
|
+
propertyKey: 'method',
|
83
|
+
middleware: MIDDLEWARE_1,
|
84
|
+
},
|
85
|
+
{
|
86
|
+
propertyKey: 'method',
|
87
|
+
middleware: [MIDDLEWARE_2, MIDDLEWARE_3],
|
88
|
+
},
|
89
|
+
]);
|
90
|
+
});
|
91
|
+
});
|
92
|
+
});
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import {Prototype} from '../../types.js';
|
2
|
+
import {Constructor} from '../../types.js';
|
3
|
+
import {BeforeMetadata} from './before-metadata.js';
|
4
|
+
import {BeforeReflector} from './before-reflector.js';
|
5
|
+
import {DecoratorTargetType} from '@e22m4u/ts-reflector';
|
6
|
+
import {getDecoratorTargetType} from '@e22m4u/ts-reflector';
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Before decorator.
|
10
|
+
*
|
11
|
+
* @param options
|
12
|
+
*/
|
13
|
+
export function before<T extends object>(
|
14
|
+
middleware: BeforeMetadata['middleware'],
|
15
|
+
) {
|
16
|
+
return function (
|
17
|
+
target: Constructor<T> | Prototype<T>,
|
18
|
+
propertyKey?: string,
|
19
|
+
descriptor?: PropertyDescriptor,
|
20
|
+
) {
|
21
|
+
const decoratorType = getDecoratorTargetType(
|
22
|
+
target,
|
23
|
+
propertyKey,
|
24
|
+
descriptor,
|
25
|
+
);
|
26
|
+
if (decoratorType === DecoratorTargetType.CONSTRUCTOR) {
|
27
|
+
BeforeReflector.addMetadata({middleware}, target as Constructor<T>);
|
28
|
+
} else if (decoratorType === DecoratorTargetType.INSTANCE_METHOD) {
|
29
|
+
BeforeReflector.addMetadata(
|
30
|
+
{propertyKey, middleware},
|
31
|
+
target.constructor as Constructor<T>,
|
32
|
+
propertyKey,
|
33
|
+
);
|
34
|
+
} else {
|
35
|
+
throw new Error(
|
36
|
+
'@before decorator is only supported on a class or an instance method.',
|
37
|
+
);
|
38
|
+
}
|
39
|
+
};
|
40
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import {MetadataKey} from '@e22m4u/ts-reflector';
|
2
|
+
import {RoutePreHandler} from '@e22m4u/js-trie-router';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Before metadata.
|
6
|
+
*/
|
7
|
+
export type BeforeMetadata = {
|
8
|
+
propertyKey?: string;
|
9
|
+
middleware: RoutePreHandler | RoutePreHandler[];
|
10
|
+
};
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Before metadata key.
|
14
|
+
*/
|
15
|
+
export const BEFORE_METADATA_KEY = new MetadataKey<BeforeMetadata[]>(
|
16
|
+
'beforeMetadataKey',
|
17
|
+
);
|
@@ -0,0 +1,111 @@
|
|
1
|
+
import {expect} from 'chai';
|
2
|
+
import {describe} from 'mocha';
|
3
|
+
import {Reflector} from '@e22m4u/ts-reflector';
|
4
|
+
import {BeforeReflector} from './before-reflector.js';
|
5
|
+
import {BEFORE_METADATA_KEY} from './before-metadata.js';
|
6
|
+
|
7
|
+
const MIDDLEWARE_1 = () => undefined;
|
8
|
+
const MIDDLEWARE_2 = () => undefined;
|
9
|
+
const MIDDLEWARE_3 = () => undefined;
|
10
|
+
|
11
|
+
describe('BeforeReflector', function () {
|
12
|
+
describe('class target', function () {
|
13
|
+
describe('addMetadata', function () {
|
14
|
+
it('adds a given value to the target metadata', function () {
|
15
|
+
class Target {}
|
16
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
17
|
+
const md2 = {middleware: [MIDDLEWARE_2, MIDDLEWARE_3]};
|
18
|
+
BeforeReflector.addMetadata(md1, Target);
|
19
|
+
BeforeReflector.addMetadata(md2, Target);
|
20
|
+
const res = Reflector.getOwnMetadata(BEFORE_METADATA_KEY, Target);
|
21
|
+
expect(res).to.be.eql([md2, md1]);
|
22
|
+
});
|
23
|
+
});
|
24
|
+
|
25
|
+
describe('getMetadata', function () {
|
26
|
+
it('returns an empty array if no metadata', function () {
|
27
|
+
class Target {}
|
28
|
+
const res = BeforeReflector.getMetadata(Target);
|
29
|
+
expect(res).to.be.eql([]);
|
30
|
+
});
|
31
|
+
|
32
|
+
it('returns existing metadata by the target', function () {
|
33
|
+
class Target {}
|
34
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
35
|
+
const md2 = {middleware: [MIDDLEWARE_2, MIDDLEWARE_3]};
|
36
|
+
const mdArray = [md1, md2];
|
37
|
+
Reflector.defineMetadata(BEFORE_METADATA_KEY, mdArray, Target);
|
38
|
+
const res = BeforeReflector.getMetadata(Target);
|
39
|
+
expect(res).to.be.eql(mdArray);
|
40
|
+
});
|
41
|
+
});
|
42
|
+
});
|
43
|
+
|
44
|
+
describe('method target', function () {
|
45
|
+
describe('addMetadata', function () {
|
46
|
+
it('adds a given value to the target metadata', function () {
|
47
|
+
class Target {}
|
48
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
49
|
+
const md2 = {middleware: [MIDDLEWARE_2, MIDDLEWARE_3]};
|
50
|
+
BeforeReflector.addMetadata(md1, Target, 'prop');
|
51
|
+
BeforeReflector.addMetadata(md2, Target, 'prop');
|
52
|
+
const res = Reflector.getOwnMetadata(
|
53
|
+
BEFORE_METADATA_KEY,
|
54
|
+
Target,
|
55
|
+
'prop',
|
56
|
+
);
|
57
|
+
expect(res).to.be.eql([md2, md1]);
|
58
|
+
});
|
59
|
+
});
|
60
|
+
|
61
|
+
describe('getMetadata', function () {
|
62
|
+
it('returns an empty array if no metadata', function () {
|
63
|
+
class Target {}
|
64
|
+
const res = BeforeReflector.getMetadata(Target, 'prop');
|
65
|
+
expect(res).to.be.eql([]);
|
66
|
+
});
|
67
|
+
|
68
|
+
it('returns existing metadata by the target', function () {
|
69
|
+
class Target {}
|
70
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
71
|
+
const md2 = {middleware: [MIDDLEWARE_2, MIDDLEWARE_3]};
|
72
|
+
const mdArray = [md1, md2];
|
73
|
+
Reflector.defineMetadata(BEFORE_METADATA_KEY, mdArray, Target, 'prop');
|
74
|
+
const res = BeforeReflector.getMetadata(Target, 'prop');
|
75
|
+
expect(res).to.be.eql(mdArray);
|
76
|
+
});
|
77
|
+
});
|
78
|
+
});
|
79
|
+
|
80
|
+
describe('addMetadata', function () {
|
81
|
+
it('can distinguish class and method metadata', function () {
|
82
|
+
class Target {}
|
83
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
84
|
+
const md2 = {middleware: MIDDLEWARE_2};
|
85
|
+
BeforeReflector.addMetadata(md1, Target);
|
86
|
+
BeforeReflector.addMetadata(md2, Target, 'prop');
|
87
|
+
const res1 = Reflector.getOwnMetadata(BEFORE_METADATA_KEY, Target);
|
88
|
+
const res2 = Reflector.getOwnMetadata(
|
89
|
+
BEFORE_METADATA_KEY,
|
90
|
+
Target,
|
91
|
+
'prop',
|
92
|
+
);
|
93
|
+
expect(res1).to.be.eql([md1]);
|
94
|
+
expect(res2).to.be.eql([md2]);
|
95
|
+
});
|
96
|
+
});
|
97
|
+
|
98
|
+
describe('getMetadata', function () {
|
99
|
+
it('can distinguish class and method metadata', function () {
|
100
|
+
class Target {}
|
101
|
+
const md1 = {middleware: MIDDLEWARE_1};
|
102
|
+
const md2 = {middleware: MIDDLEWARE_2};
|
103
|
+
Reflector.defineMetadata(BEFORE_METADATA_KEY, [md1], Target);
|
104
|
+
Reflector.defineMetadata(BEFORE_METADATA_KEY, [md2], Target, 'prop');
|
105
|
+
const res1 = BeforeReflector.getMetadata(Target);
|
106
|
+
const res2 = BeforeReflector.getMetadata(Target, 'prop');
|
107
|
+
expect(res1).to.be.eql([md1]);
|
108
|
+
expect(res2).to.be.eql([md2]);
|
109
|
+
});
|
110
|
+
});
|
111
|
+
});
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import {Constructor} from '../../types.js';
|
2
|
+
import {Reflector} from '@e22m4u/ts-reflector';
|
3
|
+
import {BeforeMetadata} from './before-metadata.js';
|
4
|
+
import {BEFORE_METADATA_KEY} from './before-metadata.js';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Before reflector.
|
8
|
+
*/
|
9
|
+
export class BeforeReflector {
|
10
|
+
/**
|
11
|
+
* Set metadata.
|
12
|
+
*
|
13
|
+
* @param metadata
|
14
|
+
* @param target
|
15
|
+
* @param propertyKey
|
16
|
+
*/
|
17
|
+
static addMetadata(
|
18
|
+
metadata: BeforeMetadata,
|
19
|
+
target: Constructor,
|
20
|
+
propertyKey?: string,
|
21
|
+
) {
|
22
|
+
const oldArray =
|
23
|
+
Reflector.getOwnMetadata(BEFORE_METADATA_KEY, target, propertyKey) ?? [];
|
24
|
+
const newArray = [metadata, ...oldArray];
|
25
|
+
Reflector.defineMetadata(
|
26
|
+
BEFORE_METADATA_KEY,
|
27
|
+
newArray,
|
28
|
+
target,
|
29
|
+
propertyKey,
|
30
|
+
);
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Get metadata.
|
35
|
+
*
|
36
|
+
* @param target
|
37
|
+
* @param propertyKey
|
38
|
+
*/
|
39
|
+
static getMetadata(
|
40
|
+
target: Constructor,
|
41
|
+
propertyKey?: string,
|
42
|
+
): BeforeMetadata[] {
|
43
|
+
const metadata = Reflector.getOwnMetadata(
|
44
|
+
BEFORE_METADATA_KEY,
|
45
|
+
target,
|
46
|
+
propertyKey,
|
47
|
+
);
|
48
|
+
return metadata ?? [];
|
49
|
+
}
|
50
|
+
}
|
@@ -33,4 +33,26 @@ describe('controller', function () {
|
|
33
33
|
const res = ControllerReflector.getMetadata(Target);
|
34
34
|
expect(res).to.be.eql({className: 'Target'});
|
35
35
|
});
|
36
|
+
|
37
|
+
it('allows to pass the path option to the first parameter', function () {
|
38
|
+
@controller('myPath')
|
39
|
+
class Target {}
|
40
|
+
const res = ControllerReflector.getMetadata(Target);
|
41
|
+
expect(res).to.be.eql({className: 'Target', path: 'myPath'});
|
42
|
+
});
|
43
|
+
|
44
|
+
it('merges two given arguments in the target metadata', function () {
|
45
|
+
const before = () => undefined;
|
46
|
+
@controller('myPath', {before})
|
47
|
+
class Target {}
|
48
|
+
const res = ControllerReflector.getMetadata(Target);
|
49
|
+
expect(res).to.be.eql({className: 'Target', path: 'myPath', before});
|
50
|
+
});
|
51
|
+
|
52
|
+
it('overrides the path option by the first argument', function () {
|
53
|
+
@controller('myPath1', {path: 'myPath2'})
|
54
|
+
class Target {}
|
55
|
+
const res = ControllerReflector.getMetadata(Target);
|
56
|
+
expect(res).to.be.eql({className: 'Target', path: 'myPath1'});
|
57
|
+
});
|
36
58
|
});
|
@@ -13,13 +13,41 @@ export type ControllerOptions = Flatten<Omit<ControllerMetadata, 'className'>>;
|
|
13
13
|
/**
|
14
14
|
* Controller decorator.
|
15
15
|
*
|
16
|
+
* @param pathOrOptions
|
16
17
|
* @param options
|
17
18
|
*/
|
18
|
-
export function controller<T extends object>(
|
19
|
+
export function controller<T extends object>(
|
20
|
+
pathOrOptions?: string | ControllerOptions,
|
21
|
+
options?: ControllerOptions,
|
22
|
+
) {
|
19
23
|
return function (target: Constructor<T>) {
|
20
24
|
const decoratorType = getDecoratorTargetType(target);
|
21
25
|
if (decoratorType !== DecoratorTargetType.CONSTRUCTOR)
|
22
26
|
throw new Error('@controller decorator is only supported on a class.');
|
27
|
+
// если первый аргумент является строкой,
|
28
|
+
// то значение используется в качестве
|
29
|
+
// базового пути контроллера
|
30
|
+
if (typeof pathOrOptions === 'string') {
|
31
|
+
// если второй аргумент не определен,
|
32
|
+
// то создается новый объект опций,
|
33
|
+
// который включает базовый путь
|
34
|
+
if (!options) {
|
35
|
+
options = {path: pathOrOptions};
|
36
|
+
}
|
37
|
+
// если второй аргумент определен,
|
38
|
+
// то базовый путь из первого аргумента
|
39
|
+
// передается в объект опций декоратора
|
40
|
+
else {
|
41
|
+
options.path = pathOrOptions;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
// если первый аргумент является объектом,
|
45
|
+
// то его значение используется в качестве
|
46
|
+
// объекта опций декоратора, а второй
|
47
|
+
// аргумент игнорируется
|
48
|
+
else if (typeof pathOrOptions === 'object') {
|
49
|
+
options = pathOrOptions;
|
50
|
+
}
|
23
51
|
ControllerReflector.setMetadata(
|
24
52
|
{...options, className: target.name},
|
25
53
|
target,
|
package/src/decorators/index.ts
CHANGED
@@ -10,7 +10,7 @@ import {params} from './request-data-decorator.js';
|
|
10
10
|
import {queries} from './request-data-decorator.js';
|
11
11
|
import {cookies} from './request-data-decorator.js';
|
12
12
|
import {headers} from './request-data-decorator.js';
|
13
|
-
import {
|
13
|
+
import {bodyProp} from './request-data-decorator.js';
|
14
14
|
import {requestData} from './request-data-decorator.js';
|
15
15
|
import {RequestDataSource} from './request-data-metadata.js';
|
16
16
|
import {RequestDataReflector} from './request-data-reflector.js';
|
@@ -409,11 +409,11 @@ describe('requestData', function () {
|
|
409
409
|
});
|
410
410
|
});
|
411
411
|
|
412
|
-
describe('
|
412
|
+
describe('bodyProp', function () {
|
413
413
|
it('sets a given "propertyKey" to the target metadata', function () {
|
414
414
|
class Target {
|
415
415
|
myMethod(
|
416
|
-
@
|
416
|
+
@bodyProp('myPropertyKey')
|
417
417
|
prop: unknown,
|
418
418
|
) {}
|
419
419
|
}
|
@@ -430,7 +430,7 @@ describe('requestData', function () {
|
|
430
430
|
const propertyType = DataType.STRING;
|
431
431
|
class Target {
|
432
432
|
myMethod(
|
433
|
-
@
|
433
|
+
@bodyProp(propertyKey, propertyType)
|
434
434
|
prop: unknown,
|
435
435
|
) {}
|
436
436
|
}
|
@@ -457,7 +457,7 @@ describe('requestData', function () {
|
|
457
457
|
const propertyKey = 'myPropertyKey';
|
458
458
|
class Target {
|
459
459
|
myMethod(
|
460
|
-
@
|
460
|
+
@bodyProp(propertyKey, schema)
|
461
461
|
prop: unknown,
|
462
462
|
) {}
|
463
463
|
}
|
@@ -109,7 +109,7 @@ export const cookies = createRequestDataDecoratorWithSource(
|
|
109
109
|
export const cookie = createRequestDataPropertyDecoratorWithSource(
|
110
110
|
RequestDataSource.COOKIE,
|
111
111
|
);
|
112
|
-
export const
|
112
|
+
export const bodyProp = createRequestDataPropertyDecoratorWithSource(
|
113
113
|
RequestDataSource.BODY,
|
114
114
|
);
|
115
115
|
|