@e22m4u/ts-rest-router 0.0.7 → 0.1.1

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.
Files changed (62) hide show
  1. package/README-ru.md +114 -91
  2. package/README.md +106 -85
  3. package/dist/cjs/index.cjs +427 -123
  4. package/dist/esm/controller-registry.d.ts +53 -11
  5. package/dist/esm/controller-registry.js +242 -104
  6. package/dist/esm/debuggable-service.js +1 -1
  7. package/dist/esm/decorators/after/after-decorator.d.ts +9 -0
  8. package/dist/esm/decorators/after/after-decorator.js +22 -0
  9. package/dist/esm/decorators/after/after-decorator.spec.d.ts +1 -0
  10. package/dist/esm/decorators/after/after-decorator.spec.js +115 -0
  11. package/dist/esm/decorators/after/after-metadata.d.ts +13 -0
  12. package/dist/esm/decorators/after/after-metadata.js +5 -0
  13. package/dist/esm/decorators/after/after-reflector.d.ts +22 -0
  14. package/dist/esm/decorators/after/after-reflector.js +29 -0
  15. package/dist/esm/decorators/after/after-reflector.spec.d.ts +1 -0
  16. package/dist/esm/decorators/after/after-reflector.spec.js +102 -0
  17. package/dist/esm/decorators/after/index.d.ts +3 -0
  18. package/dist/esm/decorators/after/index.js +3 -0
  19. package/dist/esm/decorators/before/before-decorator.d.ts +9 -0
  20. package/dist/esm/decorators/before/before-decorator.js +22 -0
  21. package/dist/esm/decorators/before/before-decorator.spec.d.ts +1 -0
  22. package/dist/esm/decorators/before/before-decorator.spec.js +115 -0
  23. package/dist/esm/decorators/before/before-metadata.d.ts +13 -0
  24. package/dist/esm/decorators/before/before-metadata.js +5 -0
  25. package/dist/esm/decorators/before/before-reflector.d.ts +22 -0
  26. package/dist/esm/decorators/before/before-reflector.js +29 -0
  27. package/dist/esm/decorators/before/before-reflector.spec.d.ts +1 -0
  28. package/dist/esm/decorators/before/before-reflector.spec.js +102 -0
  29. package/dist/esm/decorators/before/index.d.ts +3 -0
  30. package/dist/esm/decorators/before/index.js +3 -0
  31. package/dist/esm/decorators/controller/controller-decorator.d.ts +2 -1
  32. package/dist/esm/decorators/controller/controller-decorator.js +26 -1
  33. package/dist/esm/decorators/controller/controller-decorator.spec.js +28 -0
  34. package/dist/esm/decorators/index.d.ts +2 -0
  35. package/dist/esm/decorators/index.js +2 -0
  36. package/dist/esm/decorators/request-data/request-data-decorator.d.ts +1 -1
  37. package/dist/esm/decorators/request-data/request-data-decorator.js +1 -1
  38. package/dist/esm/decorators/request-data/request-data-decorator.spec.js +5 -5
  39. package/dist/esm/utils/create-debugger.d.ts +35 -2
  40. package/dist/esm/utils/create-debugger.js +71 -5
  41. package/package.json +1 -1
  42. package/src/controller-registry.spec.ts +597 -275
  43. package/src/controller-registry.ts +263 -128
  44. package/src/debuggable-service.ts +1 -1
  45. package/src/decorators/after/after-decorator.spec.ts +92 -0
  46. package/src/decorators/after/after-decorator.ts +40 -0
  47. package/src/decorators/after/after-metadata.ts +17 -0
  48. package/src/decorators/after/after-reflector.spec.ts +107 -0
  49. package/src/decorators/after/after-reflector.ts +45 -0
  50. package/src/decorators/after/index.ts +3 -0
  51. package/src/decorators/before/before-decorator.spec.ts +92 -0
  52. package/src/decorators/before/before-decorator.ts +40 -0
  53. package/src/decorators/before/before-metadata.ts +17 -0
  54. package/src/decorators/before/before-reflector.spec.ts +111 -0
  55. package/src/decorators/before/before-reflector.ts +50 -0
  56. package/src/decorators/before/index.ts +3 -0
  57. package/src/decorators/controller/controller-decorator.spec.ts +22 -0
  58. package/src/decorators/controller/controller-decorator.ts +29 -1
  59. package/src/decorators/index.ts +2 -0
  60. package/src/decorators/request-data/request-data-decorator.spec.ts +5 -5
  61. package/src/decorators/request-data/request-data-decorator.ts +1 -1
  62. 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,3 @@
1
+ export * from './after-metadata.js';
2
+ export * from './after-reflector.js';
3
+ export * from './after-decorator.js';
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ export * from './before-metadata.js';
2
+ export * from './before-reflector.js';
3
+ export * from './before-decorator.js';
@@ -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>(options?: ControllerOptions) {
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,
@@ -1,3 +1,5 @@
1
+ export * from './after/index.js';
2
+ export * from './before/index.js';
1
3
  export * from './action/index.js';
2
4
  export * from './controller/index.js';
3
5
  export * from './request-data/index.js';
@@ -4,13 +4,13 @@ import {DataType} from '@e22m4u/ts-data-schema';
4
4
  import {body} from './request-data-decorator.js';
5
5
  import {param} from './request-data-decorator.js';
6
6
  import {query} from './request-data-decorator.js';
7
+ import {field} from './request-data-decorator.js';
7
8
  import {cookie} from './request-data-decorator.js';
8
9
  import {header} from './request-data-decorator.js';
9
10
  import {params} from './request-data-decorator.js';
10
11
  import {queries} from './request-data-decorator.js';
11
12
  import {cookies} from './request-data-decorator.js';
12
13
  import {headers} from './request-data-decorator.js';
13
- import {bodyParam} 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('bodyParam', function () {
412
+ describe('field', function () {
413
413
  it('sets a given "propertyKey" to the target metadata', function () {
414
414
  class Target {
415
415
  myMethod(
416
- @bodyParam('myPropertyKey')
416
+ @field('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
- @bodyParam(propertyKey, propertyType)
433
+ @field(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
- @bodyParam(propertyKey, schema)
460
+ @field(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 bodyParam = createRequestDataPropertyDecoratorWithSource(
112
+ export const field = createRequestDataPropertyDecoratorWithSource(
113
113
  RequestDataSource.BODY,
114
114
  );
115
115