@e22m4u/ts-rest-router 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. package/.c8rc +9 -0
  2. package/.commitlintrc +5 -0
  3. package/.editorconfig +13 -0
  4. package/.husky/commit-msg +1 -0
  5. package/.husky/pre-commit +6 -0
  6. package/.mocharc.json +5 -0
  7. package/.prettierrc +7 -0
  8. package/LICENSE +21 -0
  9. package/README-ru.md +41 -0
  10. package/README.md +41 -0
  11. package/build-cjs.js +16 -0
  12. package/dist/cjs/index.cjs +692 -0
  13. package/dist/esm/controller-registry.d.ts +65 -0
  14. package/dist/esm/controller-registry.js +281 -0
  15. package/dist/esm/controller-registry.spec.d.ts +1 -0
  16. package/dist/esm/controller-registry.spec.js +719 -0
  17. package/dist/esm/debuggable-service.d.ts +18 -0
  18. package/dist/esm/debuggable-service.js +23 -0
  19. package/dist/esm/debuggable-service.spec.d.ts +1 -0
  20. package/dist/esm/debuggable-service.spec.js +16 -0
  21. package/dist/esm/decorators/action/action-decorator.d.ts +53 -0
  22. package/dist/esm/decorators/action/action-decorator.js +66 -0
  23. package/dist/esm/decorators/action/action-decorator.spec.d.ts +1 -0
  24. package/dist/esm/decorators/action/action-decorator.spec.js +59 -0
  25. package/dist/esm/decorators/action/action-metadata.d.ts +23 -0
  26. package/dist/esm/decorators/action/action-metadata.js +5 -0
  27. package/dist/esm/decorators/action/action-reflector.d.ts +22 -0
  28. package/dist/esm/decorators/action/action-reflector.js +29 -0
  29. package/dist/esm/decorators/action/action-reflector.spec.d.ts +1 -0
  30. package/dist/esm/decorators/action/action-reflector.spec.js +84 -0
  31. package/dist/esm/decorators/action/index.d.ts +3 -0
  32. package/dist/esm/decorators/action/index.js +3 -0
  33. package/dist/esm/decorators/controller/controller-decorator.d.ts +13 -0
  34. package/dist/esm/decorators/controller/controller-decorator.js +20 -0
  35. package/dist/esm/decorators/controller/controller-decorator.spec.d.ts +1 -0
  36. package/dist/esm/decorators/controller/controller-decorator.spec.js +53 -0
  37. package/dist/esm/decorators/controller/controller-metadata.d.ts +17 -0
  38. package/dist/esm/decorators/controller/controller-metadata.js +5 -0
  39. package/dist/esm/decorators/controller/controller-reflector.d.ts +20 -0
  40. package/dist/esm/decorators/controller/controller-reflector.js +24 -0
  41. package/dist/esm/decorators/controller/controller-reflector.spec.d.ts +1 -0
  42. package/dist/esm/decorators/controller/controller-reflector.spec.js +45 -0
  43. package/dist/esm/decorators/controller/index.d.ts +3 -0
  44. package/dist/esm/decorators/controller/index.js +3 -0
  45. package/dist/esm/decorators/index.d.ts +4 -0
  46. package/dist/esm/decorators/index.js +4 -0
  47. package/dist/esm/decorators/request-context/index.d.ts +3 -0
  48. package/dist/esm/decorators/request-context/index.js +3 -0
  49. package/dist/esm/decorators/request-context/request-context-decorator.d.ts +17 -0
  50. package/dist/esm/decorators/request-context/request-context-decorator.js +32 -0
  51. package/dist/esm/decorators/request-context/request-context-decorator.spec.d.ts +1 -0
  52. package/dist/esm/decorators/request-context/request-context-decorator.spec.js +59 -0
  53. package/dist/esm/decorators/request-context/request-context-metadata.d.ts +17 -0
  54. package/dist/esm/decorators/request-context/request-context-metadata.js +5 -0
  55. package/dist/esm/decorators/request-context/request-context-reflector.d.ts +24 -0
  56. package/dist/esm/decorators/request-context/request-context-reflector.js +31 -0
  57. package/dist/esm/decorators/request-context/request-context-reflector.spec.d.ts +1 -0
  58. package/dist/esm/decorators/request-context/request-context-reflector.spec.js +59 -0
  59. package/dist/esm/decorators/request-data/index.d.ts +3 -0
  60. package/dist/esm/decorators/request-data/index.js +3 -0
  61. package/dist/esm/decorators/request-data/request-data-decorator.d.ts +28 -0
  62. package/dist/esm/decorators/request-data/request-data-decorator.js +84 -0
  63. package/dist/esm/decorators/request-data/request-data-decorator.spec.d.ts +1 -0
  64. package/dist/esm/decorators/request-data/request-data-decorator.spec.js +534 -0
  65. package/dist/esm/decorators/request-data/request-data-metadata.d.ts +29 -0
  66. package/dist/esm/decorators/request-data/request-data-metadata.js +16 -0
  67. package/dist/esm/decorators/request-data/request-data-reflector.d.ts +24 -0
  68. package/dist/esm/decorators/request-data/request-data-reflector.js +31 -0
  69. package/dist/esm/decorators/request-data/request-data-reflector.spec.d.ts +1 -0
  70. package/dist/esm/decorators/request-data/request-data-reflector.spec.js +60 -0
  71. package/dist/esm/errors/index.d.ts +1 -0
  72. package/dist/esm/errors/index.js +1 -0
  73. package/dist/esm/errors/not-a-controller-error.d.ts +12 -0
  74. package/dist/esm/errors/not-a-controller-error.js +14 -0
  75. package/dist/esm/index.d.ts +5 -0
  76. package/dist/esm/index.js +5 -0
  77. package/dist/esm/rest-router.d.ts +19 -0
  78. package/dist/esm/rest-router.js +24 -0
  79. package/dist/esm/types.d.ts +57 -0
  80. package/dist/esm/types.js +2 -0
  81. package/dist/esm/utils/capitalize.d.ts +6 -0
  82. package/dist/esm/utils/capitalize.js +8 -0
  83. package/dist/esm/utils/capitalize.spec.d.ts +1 -0
  84. package/dist/esm/utils/capitalize.spec.js +8 -0
  85. package/dist/esm/utils/create-debugger.d.ts +11 -0
  86. package/dist/esm/utils/create-debugger.js +15 -0
  87. package/dist/esm/utils/create-debugger.spec.d.ts +1 -0
  88. package/dist/esm/utils/create-debugger.spec.js +8 -0
  89. package/dist/esm/utils/create-error.d.ts +10 -0
  90. package/dist/esm/utils/create-error.js +13 -0
  91. package/dist/esm/utils/create-error.spec.d.ts +1 -0
  92. package/dist/esm/utils/create-error.spec.js +8 -0
  93. package/dist/esm/utils/index.d.ts +4 -0
  94. package/dist/esm/utils/index.js +4 -0
  95. package/dist/esm/utils/to-camel-case.d.ts +6 -0
  96. package/dist/esm/utils/to-camel-case.js +11 -0
  97. package/dist/esm/utils/to-camel-case.spec.d.ts +1 -0
  98. package/dist/esm/utils/to-camel-case.spec.js +10 -0
  99. package/dist/tsconfig.tsbuildinfo +1 -0
  100. package/eslint.config.js +43 -0
  101. package/package.json +74 -0
  102. package/src/controller-registry.spec.ts +592 -0
  103. package/src/controller-registry.ts +355 -0
  104. package/src/debuggable-service.spec.ts +18 -0
  105. package/src/debuggable-service.ts +27 -0
  106. package/src/decorators/action/action-decorator.spec.ts +42 -0
  107. package/src/decorators/action/action-decorator.ts +100 -0
  108. package/src/decorators/action/action-metadata.ts +28 -0
  109. package/src/decorators/action/action-reflector.spec.ts +84 -0
  110. package/src/decorators/action/action-reflector.ts +38 -0
  111. package/src/decorators/action/index.ts +3 -0
  112. package/src/decorators/controller/controller-decorator.spec.ts +41 -0
  113. package/src/decorators/controller/controller-decorator.ts +29 -0
  114. package/src/decorators/controller/controller-metadata.ts +21 -0
  115. package/src/decorators/controller/controller-reflector.spec.ts +45 -0
  116. package/src/decorators/controller/controller-reflector.ts +28 -0
  117. package/src/decorators/controller/index.ts +3 -0
  118. package/src/decorators/index.ts +4 -0
  119. package/src/decorators/request-context/index.ts +3 -0
  120. package/src/decorators/request-context/request-context-decorator.spec.ts +41 -0
  121. package/src/decorators/request-context/request-context-decorator.ts +57 -0
  122. package/src/decorators/request-context/request-context-metadata.ts +21 -0
  123. package/src/decorators/request-context/request-context-reflector.spec.ts +77 -0
  124. package/src/decorators/request-context/request-context-reflector.ts +57 -0
  125. package/src/decorators/request-data/index.ts +3 -0
  126. package/src/decorators/request-data/request-data-decorator.spec.ts +477 -0
  127. package/src/decorators/request-data/request-data-decorator.ts +106 -0
  128. package/src/decorators/request-data/request-data-metadata.ts +34 -0
  129. package/src/decorators/request-data/request-data-reflector.spec.ts +78 -0
  130. package/src/decorators/request-data/request-data-reflector.ts +57 -0
  131. package/src/errors/index.ts +1 -0
  132. package/src/errors/not-a-controller-error.ts +15 -0
  133. package/src/index.ts +5 -0
  134. package/src/rest-router.ts +31 -0
  135. package/src/types.ts +59 -0
  136. package/src/utils/capitalize.spec.ts +9 -0
  137. package/src/utils/capitalize.ts +8 -0
  138. package/src/utils/create-debugger.spec.ts +9 -0
  139. package/src/utils/create-debugger.ts +21 -0
  140. package/src/utils/create-error.spec.ts +9 -0
  141. package/src/utils/create-error.ts +19 -0
  142. package/src/utils/index.ts +4 -0
  143. package/src/utils/to-camel-case.spec.ts +11 -0
  144. package/src/utils/to-camel-case.ts +11 -0
  145. package/tsconfig.json +17 -0
@@ -0,0 +1,477 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import {expect} from 'chai';
3
+ import {DataType} from '@e22m4u/ts-data-schema';
4
+ import {body} from './request-data-decorator.js';
5
+ import {param} from './request-data-decorator.js';
6
+ import {query} from './request-data-decorator.js';
7
+ import {cookie} from './request-data-decorator.js';
8
+ import {header} from './request-data-decorator.js';
9
+ import {params} from './request-data-decorator.js';
10
+ import {queries} from './request-data-decorator.js';
11
+ import {cookies} from './request-data-decorator.js';
12
+ import {headers} from './request-data-decorator.js';
13
+ import {bodyParam} from './request-data-decorator.js';
14
+ import {requestData} from './request-data-decorator.js';
15
+ import {RequestDataSource} from './request-data-metadata.js';
16
+ import {RequestDataMetadata} from './request-data-metadata.js';
17
+ import {RequestDataReflector} from './request-data-reflector.js';
18
+
19
+ describe('requestData', function () {
20
+ it('sets a given argument to the target metadata', function () {
21
+ const md: RequestDataMetadata = {
22
+ source: RequestDataSource.PARAMS,
23
+ customOption: 'myOption',
24
+ };
25
+ class Target {
26
+ myMethod(
27
+ @requestData(md)
28
+ prop: unknown,
29
+ ) {}
30
+ }
31
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
32
+ expect(res.get(0)).to.be.eql(md);
33
+ });
34
+
35
+ describe('request data by a given source', function () {
36
+ describe('params', function () {
37
+ it('sets metadata with specified source and schema', function () {
38
+ class Target {
39
+ myMethod(
40
+ @params()
41
+ prop: unknown,
42
+ ) {}
43
+ }
44
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
45
+ expect(res.get(0)).to.be.eql({
46
+ source: RequestDataSource.PARAMS,
47
+ schema: {type: DataType.OBJECT},
48
+ });
49
+ });
50
+ });
51
+
52
+ describe('queries', function () {
53
+ it('sets metadata with specified source and schema', function () {
54
+ class Target {
55
+ myMethod(
56
+ @queries()
57
+ prop: unknown,
58
+ ) {}
59
+ }
60
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
61
+ expect(res.get(0)).to.be.eql({
62
+ source: RequestDataSource.QUERY,
63
+ schema: {type: DataType.OBJECT},
64
+ });
65
+ });
66
+ });
67
+
68
+ describe('headers', function () {
69
+ it('sets metadata with specified source and schema', function () {
70
+ class Target {
71
+ myMethod(
72
+ @headers()
73
+ prop: unknown,
74
+ ) {}
75
+ }
76
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
77
+ expect(res.get(0)).to.be.eql({
78
+ source: RequestDataSource.HEADERS,
79
+ schema: {type: DataType.OBJECT},
80
+ });
81
+ });
82
+ });
83
+
84
+ describe('cookies', function () {
85
+ it('sets metadata with specified source and schema', function () {
86
+ class Target {
87
+ myMethod(
88
+ @cookies()
89
+ prop: unknown,
90
+ ) {}
91
+ }
92
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
93
+ expect(res.get(0)).to.be.eql({
94
+ source: RequestDataSource.COOKIE,
95
+ schema: {type: DataType.OBJECT},
96
+ });
97
+ });
98
+ });
99
+
100
+ describe('body', function () {
101
+ it('sets metadata with specified source and schema', function () {
102
+ class Target {
103
+ myMethod(
104
+ @body()
105
+ prop: unknown,
106
+ ) {}
107
+ }
108
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
109
+ expect(res.get(0)).to.be.eql({
110
+ source: RequestDataSource.BODY,
111
+ schema: {type: DataType.ANY},
112
+ });
113
+ });
114
+
115
+ it('sets a given DataType to the target metadata', function () {
116
+ class Target {
117
+ myMethod(
118
+ @body(DataType.STRING)
119
+ prop: unknown,
120
+ ) {}
121
+ }
122
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
123
+ expect(res.get(0)).to.be.eql({
124
+ source: RequestDataSource.BODY,
125
+ schema: {type: DataType.STRING},
126
+ });
127
+ });
128
+
129
+ it('set a given DataSchema to the target metadata', function () {
130
+ const schema = {type: DataType.STRING, required: true};
131
+ class Target {
132
+ myMethod(
133
+ @body(schema)
134
+ prop: unknown,
135
+ ) {}
136
+ }
137
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
138
+ expect(res.get(0)).to.be.eql({
139
+ source: RequestDataSource.BODY,
140
+ schema,
141
+ });
142
+ });
143
+ });
144
+ });
145
+
146
+ describe('request data piece by a given property key', function () {
147
+ describe('param', function () {
148
+ it('sets a given "propertyKey" to the target metadata', function () {
149
+ class Target {
150
+ myMethod(
151
+ @param('myPropertyKey')
152
+ prop: unknown,
153
+ ) {}
154
+ }
155
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
156
+ expect(res.get(0)).to.be.eql({
157
+ source: RequestDataSource.PARAMS,
158
+ schema: {type: DataType.OBJECT},
159
+ property: 'myPropertyKey',
160
+ });
161
+ });
162
+
163
+ it('sets a given DataType as property type', function () {
164
+ const propertyKey = 'myPropertyKey';
165
+ const propertyType = DataType.STRING;
166
+ class Target {
167
+ myMethod(
168
+ @param(propertyKey, propertyType)
169
+ prop: unknown,
170
+ ) {}
171
+ }
172
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
173
+ expect(res.get(0)).to.be.eql({
174
+ source: RequestDataSource.PARAMS,
175
+ schema: {
176
+ type: DataType.OBJECT,
177
+ properties: {
178
+ [propertyKey]: {
179
+ type: propertyType,
180
+ },
181
+ },
182
+ },
183
+ property: propertyKey,
184
+ });
185
+ });
186
+
187
+ it('sets a given DataSchema as property schema', function () {
188
+ const schema = {
189
+ type: DataType.STRING,
190
+ required: true,
191
+ };
192
+ const propertyKey = 'myPropertyKey';
193
+ class Target {
194
+ myMethod(
195
+ @param(propertyKey, schema)
196
+ prop: unknown,
197
+ ) {}
198
+ }
199
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
200
+ expect(res.get(0)).to.be.eql({
201
+ source: RequestDataSource.PARAMS,
202
+ schema: {
203
+ type: DataType.OBJECT,
204
+ properties: {
205
+ [propertyKey]: schema,
206
+ },
207
+ },
208
+ property: propertyKey,
209
+ });
210
+ });
211
+ });
212
+
213
+ describe('query', function () {
214
+ it('sets a given "propertyKey" to the target metadata', function () {
215
+ class Target {
216
+ myMethod(
217
+ @query('myPropertyKey')
218
+ prop: unknown,
219
+ ) {}
220
+ }
221
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
222
+ expect(res.get(0)).to.be.eql({
223
+ source: RequestDataSource.QUERY,
224
+ schema: {type: DataType.OBJECT},
225
+ property: 'myPropertyKey',
226
+ });
227
+ });
228
+
229
+ it('sets a given DataType as property type', function () {
230
+ const propertyKey = 'myPropertyKey';
231
+ const propertyType = DataType.STRING;
232
+ class Target {
233
+ myMethod(
234
+ @query(propertyKey, propertyType)
235
+ prop: unknown,
236
+ ) {}
237
+ }
238
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
239
+ expect(res.get(0)).to.be.eql({
240
+ source: RequestDataSource.QUERY,
241
+ schema: {
242
+ type: DataType.OBJECT,
243
+ properties: {
244
+ [propertyKey]: {
245
+ type: propertyType,
246
+ },
247
+ },
248
+ },
249
+ property: propertyKey,
250
+ });
251
+ });
252
+
253
+ it('sets a given DataSchema as property schema', function () {
254
+ const schema = {
255
+ type: DataType.STRING,
256
+ required: true,
257
+ };
258
+ const propertyKey = 'myPropertyKey';
259
+ class Target {
260
+ myMethod(
261
+ @query(propertyKey, schema)
262
+ prop: unknown,
263
+ ) {}
264
+ }
265
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
266
+ expect(res.get(0)).to.be.eql({
267
+ source: RequestDataSource.QUERY,
268
+ schema: {
269
+ type: DataType.OBJECT,
270
+ properties: {
271
+ [propertyKey]: schema,
272
+ },
273
+ },
274
+ property: propertyKey,
275
+ });
276
+ });
277
+ });
278
+
279
+ describe('header', function () {
280
+ it('sets a given "propertyKey" to the target metadata', function () {
281
+ class Target {
282
+ myMethod(
283
+ @header('myPropertyKey')
284
+ prop: unknown,
285
+ ) {}
286
+ }
287
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
288
+ expect(res.get(0)).to.be.eql({
289
+ source: RequestDataSource.HEADERS,
290
+ schema: {type: DataType.OBJECT},
291
+ property: 'myPropertyKey',
292
+ });
293
+ });
294
+
295
+ it('sets a given DataType as property type', function () {
296
+ const propertyKey = 'myPropertyKey';
297
+ const propertyType = DataType.STRING;
298
+ class Target {
299
+ myMethod(
300
+ @header(propertyKey, propertyType)
301
+ prop: unknown,
302
+ ) {}
303
+ }
304
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
305
+ expect(res.get(0)).to.be.eql({
306
+ source: RequestDataSource.HEADERS,
307
+ schema: {
308
+ type: DataType.OBJECT,
309
+ properties: {
310
+ [propertyKey]: {
311
+ type: propertyType,
312
+ },
313
+ },
314
+ },
315
+ property: propertyKey,
316
+ });
317
+ });
318
+
319
+ it('sets a given DataSchema as property schema', function () {
320
+ const schema = {
321
+ type: DataType.STRING,
322
+ required: true,
323
+ };
324
+ const propertyKey = 'myPropertyKey';
325
+ class Target {
326
+ myMethod(
327
+ @header(propertyKey, schema)
328
+ prop: unknown,
329
+ ) {}
330
+ }
331
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
332
+ expect(res.get(0)).to.be.eql({
333
+ source: RequestDataSource.HEADERS,
334
+ schema: {
335
+ type: DataType.OBJECT,
336
+ properties: {
337
+ [propertyKey]: schema,
338
+ },
339
+ },
340
+ property: propertyKey,
341
+ });
342
+ });
343
+ });
344
+
345
+ describe('cookie', function () {
346
+ it('sets a given "propertyKey" to the target metadata', function () {
347
+ class Target {
348
+ myMethod(
349
+ @cookie('myPropertyKey')
350
+ prop: unknown,
351
+ ) {}
352
+ }
353
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
354
+ expect(res.get(0)).to.be.eql({
355
+ source: RequestDataSource.COOKIE,
356
+ schema: {type: DataType.OBJECT},
357
+ property: 'myPropertyKey',
358
+ });
359
+ });
360
+
361
+ it('sets a given DataType as property type', function () {
362
+ const propertyKey = 'myPropertyKey';
363
+ const propertyType = DataType.STRING;
364
+ class Target {
365
+ myMethod(
366
+ @cookie(propertyKey, propertyType)
367
+ prop: unknown,
368
+ ) {}
369
+ }
370
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
371
+ expect(res.get(0)).to.be.eql({
372
+ source: RequestDataSource.COOKIE,
373
+ schema: {
374
+ type: DataType.OBJECT,
375
+ properties: {
376
+ [propertyKey]: {
377
+ type: propertyType,
378
+ },
379
+ },
380
+ },
381
+ property: propertyKey,
382
+ });
383
+ });
384
+
385
+ it('sets a given DataSchema as property schema', function () {
386
+ const schema = {
387
+ type: DataType.STRING,
388
+ required: true,
389
+ };
390
+ const propertyKey = 'myPropertyKey';
391
+ class Target {
392
+ myMethod(
393
+ @cookie(propertyKey, schema)
394
+ prop: unknown,
395
+ ) {}
396
+ }
397
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
398
+ expect(res.get(0)).to.be.eql({
399
+ source: RequestDataSource.COOKIE,
400
+ schema: {
401
+ type: DataType.OBJECT,
402
+ properties: {
403
+ [propertyKey]: schema,
404
+ },
405
+ },
406
+ property: propertyKey,
407
+ });
408
+ });
409
+ });
410
+
411
+ describe('bodyParam', function () {
412
+ it('sets a given "propertyKey" to the target metadata', function () {
413
+ class Target {
414
+ myMethod(
415
+ @bodyParam('myPropertyKey')
416
+ prop: unknown,
417
+ ) {}
418
+ }
419
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
420
+ expect(res.get(0)).to.be.eql({
421
+ source: RequestDataSource.BODY,
422
+ schema: {type: DataType.OBJECT},
423
+ property: 'myPropertyKey',
424
+ });
425
+ });
426
+
427
+ it('sets a given DataType as property type', function () {
428
+ const propertyKey = 'myPropertyKey';
429
+ const propertyType = DataType.STRING;
430
+ class Target {
431
+ myMethod(
432
+ @bodyParam(propertyKey, propertyType)
433
+ prop: unknown,
434
+ ) {}
435
+ }
436
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
437
+ expect(res.get(0)).to.be.eql({
438
+ source: RequestDataSource.BODY,
439
+ schema: {
440
+ type: DataType.OBJECT,
441
+ properties: {
442
+ [propertyKey]: {
443
+ type: propertyType,
444
+ },
445
+ },
446
+ },
447
+ property: propertyKey,
448
+ });
449
+ });
450
+
451
+ it('sets a given DataSchema as property schema', function () {
452
+ const schema = {
453
+ type: DataType.STRING,
454
+ required: true,
455
+ };
456
+ const propertyKey = 'myPropertyKey';
457
+ class Target {
458
+ myMethod(
459
+ @bodyParam(propertyKey, schema)
460
+ prop: unknown,
461
+ ) {}
462
+ }
463
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
464
+ expect(res.get(0)).to.be.eql({
465
+ source: RequestDataSource.BODY,
466
+ schema: {
467
+ type: DataType.OBJECT,
468
+ properties: {
469
+ [propertyKey]: schema,
470
+ },
471
+ },
472
+ property: propertyKey,
473
+ });
474
+ });
475
+ });
476
+ });
477
+ });
@@ -0,0 +1,106 @@
1
+ import {NoUndef} from '../../types.js';
2
+ import {Prototype} from '../../types.js';
3
+ import {Constructor} from '../../types.js';
4
+ import {DataType} from '@e22m4u/ts-data-schema';
5
+ import {DataSchema} from '@e22m4u/ts-data-schema';
6
+ import {DecoratorTargetType} from '@e22m4u/ts-reflector';
7
+ import {getDecoratorTargetType} from '@e22m4u/ts-reflector';
8
+ import {RequestDataSource} from './request-data-metadata.js';
9
+ import {RequestDataMetadata} from './request-data-metadata.js';
10
+ import {RequestDataReflector} from './request-data-reflector.js';
11
+
12
+ /**
13
+ * Request data decorator.
14
+ *
15
+ * @param metadata
16
+ */
17
+ export function requestData<T extends object>(metadata: RequestDataMetadata) {
18
+ return function (
19
+ target: Prototype<T>,
20
+ propertyKey: string,
21
+ indexOrDescriptor: number,
22
+ ) {
23
+ const decoratorType = getDecoratorTargetType(
24
+ target,
25
+ propertyKey,
26
+ indexOrDescriptor,
27
+ );
28
+ if (decoratorType !== DecoratorTargetType.INSTANCE_METHOD_PARAMETER)
29
+ throw new Error(
30
+ '@requestData decorator is only supported ' +
31
+ 'on an instance method parameter.',
32
+ );
33
+ RequestDataReflector.setMetadata(
34
+ metadata,
35
+ target.constructor as Constructor<T>,
36
+ indexOrDescriptor,
37
+ propertyKey,
38
+ );
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Create data decorator.
44
+ *
45
+ * @param source
46
+ */
47
+ function createDataDecorator(source: RequestDataSource) {
48
+ return function () {
49
+ const schema = {type: DataType.OBJECT};
50
+ return requestData({schema, source});
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Create property decorator.
56
+ *
57
+ * @param source
58
+ */
59
+ function createPropertyDecorator(source: RequestDataSource) {
60
+ return function (propertyKey: string, schemaOrType?: DataSchema | DataType) {
61
+ const properties = {} as NoUndef<DataSchema['properties']>;
62
+ const rootSchema: DataSchema = {type: DataType.OBJECT};
63
+ if (typeof schemaOrType === 'object') {
64
+ properties[propertyKey] = schemaOrType;
65
+ rootSchema.properties = properties;
66
+ } else if (typeof schemaOrType === 'string') {
67
+ properties[propertyKey] = {type: schemaOrType};
68
+ rootSchema.properties = properties;
69
+ }
70
+ return requestData({
71
+ source: source,
72
+ schema: rootSchema,
73
+ property: propertyKey,
74
+ });
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Decorator aliases.
80
+ */
81
+ export const params = createDataDecorator(RequestDataSource.PARAMS);
82
+ export const param = createPropertyDecorator(RequestDataSource.PARAMS);
83
+ export const queries = createDataDecorator(RequestDataSource.QUERY);
84
+ export const query = createPropertyDecorator(RequestDataSource.QUERY);
85
+ export const headers = createDataDecorator(RequestDataSource.HEADERS);
86
+ export const header = createPropertyDecorator(RequestDataSource.HEADERS);
87
+ export const cookies = createDataDecorator(RequestDataSource.COOKIE);
88
+ export const cookie = createPropertyDecorator(RequestDataSource.COOKIE);
89
+ export const bodyParam = createPropertyDecorator(RequestDataSource.BODY);
90
+
91
+ /**
92
+ * Request body decorator.
93
+ *
94
+ * @param schemaOrType
95
+ */
96
+ export function body(schemaOrType?: DataSchema | DataType) {
97
+ let schema: DataSchema;
98
+ if (typeof schemaOrType === 'object') {
99
+ schema = schemaOrType;
100
+ } else if (typeof schemaOrType === 'string') {
101
+ schema = {type: schemaOrType};
102
+ } else {
103
+ schema = {type: DataType.ANY};
104
+ }
105
+ return requestData({schema, source: RequestDataSource.BODY});
106
+ }
@@ -0,0 +1,34 @@
1
+ import {DataSchema} from '@e22m4u/ts-data-schema';
2
+ import {MetadataKey} from '@e22m4u/ts-reflector';
3
+
4
+ /**
5
+ * Request data source.
6
+ */
7
+ export enum RequestDataSource {
8
+ PARAMS = 'params',
9
+ QUERY = 'query',
10
+ HEADERS = 'headers',
11
+ COOKIE = 'cookie',
12
+ BODY = 'body',
13
+ }
14
+
15
+ /**
16
+ * Request data metadata.
17
+ */
18
+ export type RequestDataMetadata = {
19
+ source: RequestDataSource;
20
+ schema?: DataSchema;
21
+ property?: string;
22
+ [option: string]: unknown | undefined;
23
+ };
24
+
25
+ /**
26
+ * Request data metadata map.
27
+ */
28
+ export type RequestDataMetadataMap = Map<number, RequestDataMetadata>;
29
+
30
+ /**
31
+ * Request data metadata key.
32
+ */
33
+ export const REQUEST_DATA_METADATA_KEY =
34
+ new MetadataKey<RequestDataMetadataMap>('requestDataMetadataKey');
@@ -0,0 +1,78 @@
1
+ import {expect} from 'chai';
2
+ import {describe} from 'mocha';
3
+ import {Reflector} from '@e22m4u/ts-reflector';
4
+ import {RequestDataSource} from './request-data-metadata.js';
5
+ import {RequestDataMetadata} from './request-data-metadata.js';
6
+ import {RequestDataReflector} from './request-data-reflector.js';
7
+ import {REQUEST_DATA_METADATA_KEY} from './request-data-metadata.js';
8
+
9
+ describe('RequestDataReflector', function () {
10
+ describe('setMetadata', function () {
11
+ it('sets a given value as target metadata', function () {
12
+ class Target {}
13
+ const md1 = {source: RequestDataSource.PARAMS};
14
+ const md2 = {source: RequestDataSource.QUERY};
15
+ RequestDataReflector.setMetadata(md1, Target, 0, 'propertyKey');
16
+ RequestDataReflector.setMetadata(md2, Target, 1, 'propertyKey');
17
+ const res = Reflector.getOwnMetadata(
18
+ REQUEST_DATA_METADATA_KEY,
19
+ Target,
20
+ 'propertyKey',
21
+ );
22
+ expect(res).to.be.instanceof(Map);
23
+ expect(res!.get(0)).to.be.eq(md1);
24
+ expect(res!.get(1)).to.be.eq(md2);
25
+ });
26
+
27
+ it('overrides existing metadata', function () {
28
+ class Target {}
29
+ const md1 = {source: RequestDataSource.PARAMS};
30
+ const md2 = {source: RequestDataSource.QUERY};
31
+ RequestDataReflector.setMetadata(md1, Target, 0, 'propertyKey');
32
+ const res1 = Reflector.getOwnMetadata(
33
+ REQUEST_DATA_METADATA_KEY,
34
+ Target,
35
+ 'propertyKey',
36
+ );
37
+ expect(res1).to.be.instanceof(Map);
38
+ expect(res1!.get(0)).to.be.eq(md1);
39
+ RequestDataReflector.setMetadata(md2, Target, 0, 'propertyKey');
40
+ const res2 = Reflector.getOwnMetadata(
41
+ REQUEST_DATA_METADATA_KEY,
42
+ Target,
43
+ 'propertyKey',
44
+ );
45
+ expect(res2).to.be.instanceof(Map);
46
+ expect(res2!.get(0)).to.be.eq(md2);
47
+ });
48
+ });
49
+
50
+ describe('getMetadata', function () {
51
+ it('returns an existing metadata of the target', function () {
52
+ class Target {}
53
+ const md1 = {source: RequestDataSource.PARAMS};
54
+ const md2 = {source: RequestDataSource.QUERY};
55
+ const mdMap = new Map<number, RequestDataMetadata>([
56
+ [0, md1],
57
+ [1, md2],
58
+ ]);
59
+ Reflector.defineMetadata(
60
+ REQUEST_DATA_METADATA_KEY,
61
+ mdMap,
62
+ Target,
63
+ 'propertyKey',
64
+ );
65
+ const res = RequestDataReflector.getMetadata(Target, 'propertyKey');
66
+ expect(res).to.be.instanceof(Map);
67
+ expect(res!.get(0)).to.be.eq(md1);
68
+ expect(res!.get(1)).to.be.eq(md2);
69
+ });
70
+
71
+ it('returns an empty map if no metadata', function () {
72
+ class Target {}
73
+ const res = RequestDataReflector.getMetadata(Target, 'propertyKey');
74
+ expect(res).to.be.instanceof(Map);
75
+ expect(res).to.be.empty;
76
+ });
77
+ });
78
+ });