@e22m4u/ts-rest-router 0.5.4 → 0.6.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.
Files changed (28) hide show
  1. package/README.md +9 -0
  2. package/dist/cjs/index.cjs +36 -22
  3. package/dist/esm/controller-registry.js +11 -3
  4. package/dist/esm/data-schema-types.d.ts +15 -0
  5. package/dist/esm/data-schema-types.js +1 -0
  6. package/dist/esm/decorators/before-action/before-action-reflector.spec.js +15 -15
  7. package/dist/esm/decorators/request-data/request-data-decorator.d.ts +11 -12
  8. package/dist/esm/decorators/request-data/request-data-decorator.js +20 -12
  9. package/dist/esm/decorators/request-data/request-data-decorator.spec.js +183 -1
  10. package/dist/esm/decorators/request-data/request-data-metadata.d.ts +2 -2
  11. package/dist/esm/decorators/response-body/response-body-decorator.d.ts +2 -3
  12. package/dist/esm/decorators/response-body/response-body-decorator.js +7 -7
  13. package/dist/esm/decorators/response-body/response-body-decorator.spec.js +21 -1
  14. package/dist/esm/decorators/response-body/response-body-metadata.d.ts +2 -2
  15. package/dist/esm/index.d.ts +1 -0
  16. package/dist/esm/index.js +1 -0
  17. package/package.json +5 -5
  18. package/src/controller-registry.spec.ts +178 -5
  19. package/src/controller-registry.ts +11 -7
  20. package/src/data-schema-types.ts +18 -0
  21. package/src/decorators/before-action/before-action-reflector.spec.ts +15 -15
  22. package/src/decorators/request-data/request-data-decorator.spec.ts +174 -1
  23. package/src/decorators/request-data/request-data-decorator.ts +22 -13
  24. package/src/decorators/request-data/request-data-metadata.ts +2 -2
  25. package/src/decorators/response-body/response-body-decorator.spec.ts +17 -1
  26. package/src/decorators/response-body/response-body-decorator.ts +9 -11
  27. package/src/decorators/response-body/response-body-metadata.ts +2 -2
  28. package/src/index.ts +1 -0
package/README.md CHANGED
@@ -226,6 +226,15 @@ class ProductController {
226
226
  - `@requestQuery(name, schema)` - извлечение одного query-параметра;
227
227
  - `@requestQueries(schema)` - извлечение всех query-параметров в виде объекта;
228
228
 
229
+ **Именование Query-декораторов**
230
+
231
+ Разделение на декораторы в единственном `@requestQuery` и множественном
232
+ `@requestQueries` числе - это осознанное архитектурное решение, направленное
233
+ на консистентность API. Тот же принцип применяется для работы с URL-параметрами,
234
+ заголовками и cookies. Декоратор в единственном числе используется для точечного
235
+ извлечения и валидации отдельных значений, в то время как множественное число
236
+ служит для получения всех данных в виде единого объекта.
237
+
229
238
  ### Тело запроса (`@requestBody`, `@requestField`)
230
239
 
231
240
  Для работы с данными, отправленными в теле POST, PUT, PATCH запросов.
@@ -294,12 +294,12 @@ function requestData(options) {
294
294
  }
295
295
  __name(requestData, "requestData");
296
296
  function createRequestDataDecoratorWithSource(source) {
297
- return function(schemaOrType) {
297
+ return function(schemaInput) {
298
298
  let schema;
299
- if (typeof schemaOrType === "object") {
300
- schema = schemaOrType;
301
- } else if (typeof schemaOrType === "string") {
302
- schema = { type: schemaOrType };
299
+ if (typeof schemaInput === "function" || typeof schemaInput === "object") {
300
+ schema = schemaInput;
301
+ } else if (typeof schemaInput === "string") {
302
+ schema = { type: schemaInput };
303
303
  } else {
304
304
  schema = { type: import_ts_data_schema.DataType.ANY };
305
305
  }
@@ -308,14 +308,21 @@ function createRequestDataDecoratorWithSource(source) {
308
308
  }
309
309
  __name(createRequestDataDecoratorWithSource, "createRequestDataDecoratorWithSource");
310
310
  function createRequestDataPropertyDecoratorWithSource(source) {
311
- return function(propertyKey, schemaOrType) {
312
- const properties = {};
311
+ return function(propertyKey, schemaInput) {
313
312
  const rootSchema = { type: import_ts_data_schema.DataType.OBJECT };
314
- if (typeof schemaOrType === "object") {
315
- properties[propertyKey] = schemaOrType;
313
+ const properties = {};
314
+ let schemaOrFactory = rootSchema;
315
+ if (typeof schemaInput === "function") {
316
+ schemaOrFactory = /* @__PURE__ */ __name((container) => {
317
+ properties[propertyKey] = schemaInput(container);
318
+ rootSchema.properties = properties;
319
+ return rootSchema;
320
+ }, "schemaOrFactory");
321
+ } else if (typeof schemaInput === "object") {
322
+ properties[propertyKey] = schemaInput;
316
323
  rootSchema.properties = properties;
317
- } else if (typeof schemaOrType === "string") {
318
- properties[propertyKey] = { type: schemaOrType };
324
+ } else if (typeof schemaInput === "string") {
325
+ properties[propertyKey] = { type: schemaInput };
319
326
  rootSchema.properties = properties;
320
327
  } else {
321
328
  properties[propertyKey] = { type: import_ts_data_schema.DataType.ANY };
@@ -323,7 +330,7 @@ function createRequestDataPropertyDecoratorWithSource(source) {
323
330
  }
324
331
  return requestData({
325
332
  source,
326
- schema: rootSchema,
333
+ schema: schemaOrFactory,
327
334
  property: propertyKey
328
335
  });
329
336
  };
@@ -478,18 +485,18 @@ __name(_ResponseBodyReflector, "ResponseBodyReflector");
478
485
  var ResponseBodyReflector = _ResponseBodyReflector;
479
486
 
480
487
  // dist/esm/decorators/response-body/response-body-decorator.js
481
- function responseBody(schemaOrType) {
488
+ function responseBody(schemaInput) {
482
489
  return function(target, propertyKey, descriptor) {
483
490
  const decoratorType = (0, import_ts_reflector20.getDecoratorTargetType)(target, propertyKey, descriptor);
484
491
  if (decoratorType !== import_ts_reflector19.DecoratorTargetType.INSTANCE_METHOD)
485
492
  throw new Error("@responseBody decorator is only supported on an instance method.");
486
- let schema;
487
- if (typeof schemaOrType === "object") {
488
- schema = schemaOrType;
489
- } else if (typeof schemaOrType === "string") {
490
- schema = { type: schemaOrType };
493
+ let schemaOrFactory;
494
+ if (typeof schemaInput === "function" || typeof schemaInput === "object") {
495
+ schemaOrFactory = schemaInput;
496
+ } else if (typeof schemaInput === "string") {
497
+ schemaOrFactory = { type: schemaInput };
491
498
  }
492
- ResponseBodyReflector.setMetadata(schema ? { schema } : {}, target.constructor, propertyKey);
499
+ ResponseBodyReflector.setMetadata(schemaOrFactory ? { schema: schemaOrFactory } : {}, target.constructor, propertyKey);
493
500
  };
494
501
  }
495
502
  __name(responseBody, "responseBody");
@@ -935,14 +942,21 @@ var _ControllerRegistry = class _ControllerRegistry extends DebuggableService {
935
942
  }
936
943
  debug("Request data source is %v.", requestDataMd.source);
937
944
  if (requestDataMd.schema) {
938
- data = defaultsApplier.applyDefaultValuesIfNeeded(data, requestDataMd.schema, requestDataMd.source);
945
+ let dataSchema;
946
+ if (typeof requestDataMd.schema === "function") {
947
+ dataSchema = requestDataMd.schema(this.container);
948
+ debug("Data schema extracted from factory function.");
949
+ } else {
950
+ dataSchema = requestDataMd.schema;
951
+ }
952
+ data = defaultsApplier.applyDefaultValuesIfNeeded(data, dataSchema, requestDataMd.source);
939
953
  debug("Default values applied.");
940
- data = dataTypeCaster.cast(data, requestDataMd.schema, {
954
+ data = dataTypeCaster.cast(data, dataSchema, {
941
955
  noTypeCastError: true,
942
956
  sourcePath: requestDataMd.source
943
957
  });
944
958
  debug("Data type casting applied.");
945
- dataValidator.validate(data, requestDataMd.schema, requestDataMd.source);
959
+ dataValidator.validate(data, dataSchema, requestDataMd.source);
946
960
  debug("Data validation passed.");
947
961
  }
948
962
  if (requestDataMd.property == null) {
@@ -384,14 +384,22 @@ export class ControllerRegistry extends DebuggableService {
384
384
  // по умолчанию, выполняется конвертация входящего
385
385
  // значения и валидация согласно схеме
386
386
  if (requestDataMd.schema) {
387
- data = defaultsApplier.applyDefaultValuesIfNeeded(data, requestDataMd.schema, requestDataMd.source);
387
+ let dataSchema;
388
+ if (typeof requestDataMd.schema === 'function') {
389
+ dataSchema = requestDataMd.schema(this.container);
390
+ debug('Data schema extracted from factory function.');
391
+ }
392
+ else {
393
+ dataSchema = requestDataMd.schema;
394
+ }
395
+ data = defaultsApplier.applyDefaultValuesIfNeeded(data, dataSchema, requestDataMd.source);
388
396
  debug('Default values applied.');
389
- data = dataTypeCaster.cast(data, requestDataMd.schema, {
397
+ data = dataTypeCaster.cast(data, dataSchema, {
390
398
  noTypeCastError: true,
391
399
  sourcePath: requestDataMd.source,
392
400
  });
393
401
  debug('Data type casting applied.');
394
- dataValidator.validate(data, requestDataMd.schema, requestDataMd.source);
402
+ dataValidator.validate(data, dataSchema, requestDataMd.source);
395
403
  debug('Data validation passed.');
396
404
  }
397
405
  // если свойство данных не определено,
@@ -0,0 +1,15 @@
1
+ import { DataType } from '@e22m4u/ts-data-schema';
2
+ import { DataSchema } from '@e22m4u/ts-data-schema';
3
+ import { ServiceContainer } from '@e22m4u/js-service';
4
+ /**
5
+ * Data schema factory.
6
+ */
7
+ export type DataSchemaFactory = (container: ServiceContainer) => DataSchema;
8
+ /**
9
+ * Data schema or factory.
10
+ */
11
+ export type DataSchemaOrFactory = DataSchema | DataSchemaFactory;
12
+ /**
13
+ * Data schema input.
14
+ */
15
+ export type DataSchemaInput = DataSchemaOrFactory | DataType;
@@ -0,0 +1 @@
1
+ export {};
@@ -2,17 +2,17 @@ import { expect } from 'chai';
2
2
  import { Reflector } from '@e22m4u/ts-reflector';
3
3
  import { BeforeActionReflector } from './before-action-reflector.js';
4
4
  import { BEFORE_ACTION_METADATA_KEY } from './before-action-metadata.js';
5
- const hook_1 = () => undefined;
6
- const hook_2 = () => undefined;
7
- const hook_3 = () => undefined;
5
+ const HOOK_1 = () => undefined;
6
+ const HOOK_2 = () => undefined;
7
+ const HOOK_3 = () => undefined;
8
8
  describe('BeforeActionReflector', function () {
9
9
  describe('class target', function () {
10
10
  describe('addMetadata', function () {
11
11
  it('adds a given value to the target metadata', function () {
12
12
  class Target {
13
13
  }
14
- const md1 = { hook: hook_1 };
15
- const md2 = { hook: [hook_2, hook_3] };
14
+ const md1 = { hook: HOOK_1 };
15
+ const md2 = { hook: [HOOK_2, HOOK_3] };
16
16
  BeforeActionReflector.addMetadata(md1, Target);
17
17
  BeforeActionReflector.addMetadata(md2, Target);
18
18
  const res = Reflector.getOwnMetadata(BEFORE_ACTION_METADATA_KEY, Target);
@@ -29,8 +29,8 @@ describe('BeforeActionReflector', function () {
29
29
  it('returns existing metadata by the target', function () {
30
30
  class Target {
31
31
  }
32
- const md1 = { hook: hook_1 };
33
- const md2 = { hook: [hook_2, hook_3] };
32
+ const md1 = { hook: HOOK_1 };
33
+ const md2 = { hook: [HOOK_2, HOOK_3] };
34
34
  const mdArray = [md1, md2];
35
35
  Reflector.defineMetadata(BEFORE_ACTION_METADATA_KEY, mdArray, Target);
36
36
  const res = BeforeActionReflector.getMetadata(Target);
@@ -43,8 +43,8 @@ describe('BeforeActionReflector', function () {
43
43
  it('adds a given value to the target metadata', function () {
44
44
  class Target {
45
45
  }
46
- const md1 = { hook: hook_1 };
47
- const md2 = { hook: [hook_2, hook_3] };
46
+ const md1 = { hook: HOOK_1 };
47
+ const md2 = { hook: [HOOK_2, HOOK_3] };
48
48
  BeforeActionReflector.addMetadata(md1, Target, 'prop');
49
49
  BeforeActionReflector.addMetadata(md2, Target, 'prop');
50
50
  const res = Reflector.getOwnMetadata(BEFORE_ACTION_METADATA_KEY, Target, 'prop');
@@ -61,8 +61,8 @@ describe('BeforeActionReflector', function () {
61
61
  it('returns existing metadata by the target', function () {
62
62
  class Target {
63
63
  }
64
- const md1 = { hook: hook_1 };
65
- const md2 = { hook: [hook_2, hook_3] };
64
+ const md1 = { hook: HOOK_1 };
65
+ const md2 = { hook: [HOOK_2, HOOK_3] };
66
66
  const mdArray = [md1, md2];
67
67
  Reflector.defineMetadata(BEFORE_ACTION_METADATA_KEY, mdArray, Target, 'prop');
68
68
  const res = BeforeActionReflector.getMetadata(Target, 'prop');
@@ -74,8 +74,8 @@ describe('BeforeActionReflector', function () {
74
74
  it('can distinguish class and method metadata', function () {
75
75
  class Target {
76
76
  }
77
- const md1 = { hook: hook_1 };
78
- const md2 = { hook: hook_2 };
77
+ const md1 = { hook: HOOK_1 };
78
+ const md2 = { hook: HOOK_2 };
79
79
  BeforeActionReflector.addMetadata(md1, Target);
80
80
  BeforeActionReflector.addMetadata(md2, Target, 'prop');
81
81
  const res1 = Reflector.getOwnMetadata(BEFORE_ACTION_METADATA_KEY, Target);
@@ -88,8 +88,8 @@ describe('BeforeActionReflector', function () {
88
88
  it('can distinguish class and method metadata', function () {
89
89
  class Target {
90
90
  }
91
- const md1 = { hook: hook_1 };
92
- const md2 = { hook: hook_2 };
91
+ const md1 = { hook: HOOK_1 };
92
+ const md2 = { hook: HOOK_2 };
93
93
  Reflector.defineMetadata(BEFORE_ACTION_METADATA_KEY, [md1], Target);
94
94
  Reflector.defineMetadata(BEFORE_ACTION_METADATA_KEY, [md2], Target, 'prop');
95
95
  const res1 = BeforeActionReflector.getMetadata(Target);
@@ -1,6 +1,5 @@
1
1
  import { Prototype } from '../../types.js';
2
- import { DataType } from '@e22m4u/ts-data-schema';
3
- import { DataSchema } from '@e22m4u/ts-data-schema';
2
+ import { DataSchemaInput } from '../../data-schema-types.js';
4
3
  import { RequestDataMetadata } from './request-data-metadata.js';
5
4
  /**
6
5
  * Request data options.
@@ -15,13 +14,13 @@ export declare function requestData<T extends object>(options: RequestDataOption
15
14
  /**
16
15
  * Decorator aliases.
17
16
  */
18
- export declare const requestParams: (schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
19
- export declare const requestParam: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
20
- export declare const requestQueries: (schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
21
- export declare const requestQuery: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
22
- export declare const requestHeaders: (schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
23
- export declare const requestHeader: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
24
- export declare const requestCookies: (schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
25
- export declare const requestCookie: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
26
- export declare const requestBody: (schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
27
- export declare const requestField: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
17
+ export declare const requestParams: (schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
18
+ export declare const requestParam: (propertyKey: string, schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
19
+ export declare const requestQueries: (schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
20
+ export declare const requestQuery: (propertyKey: string, schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
21
+ export declare const requestHeaders: (schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
22
+ export declare const requestHeader: (propertyKey: string, schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
23
+ export declare const requestCookies: (schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
24
+ export declare const requestCookie: (propertyKey: string, schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
25
+ export declare const requestBody: (schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
26
+ export declare const requestField: (propertyKey: string, schemaInput?: DataSchemaInput) => (target: Prototype<object>, propertyKey: string, index: number) => void;
@@ -23,13 +23,13 @@ export function requestData(options) {
23
23
  * @param source
24
24
  */
25
25
  function createRequestDataDecoratorWithSource(source) {
26
- return function (schemaOrType) {
26
+ return function (schemaInput) {
27
27
  let schema;
28
- if (typeof schemaOrType === 'object') {
29
- schema = schemaOrType;
28
+ if (typeof schemaInput === 'function' || typeof schemaInput === 'object') {
29
+ schema = schemaInput;
30
30
  }
31
- else if (typeof schemaOrType === 'string') {
32
- schema = { type: schemaOrType };
31
+ else if (typeof schemaInput === 'string') {
32
+ schema = { type: schemaInput };
33
33
  }
34
34
  else {
35
35
  schema = { type: DataType.ANY };
@@ -43,15 +43,23 @@ function createRequestDataDecoratorWithSource(source) {
43
43
  * @param source
44
44
  */
45
45
  function createRequestDataPropertyDecoratorWithSource(source) {
46
- return function (propertyKey, schemaOrType) {
47
- const properties = {};
46
+ return function (propertyKey, schemaInput) {
48
47
  const rootSchema = { type: DataType.OBJECT };
49
- if (typeof schemaOrType === 'object') {
50
- properties[propertyKey] = schemaOrType;
48
+ const properties = {};
49
+ let schemaOrFactory = rootSchema;
50
+ if (typeof schemaInput === 'function') {
51
+ schemaOrFactory = container => {
52
+ properties[propertyKey] = schemaInput(container);
53
+ rootSchema.properties = properties;
54
+ return rootSchema;
55
+ };
56
+ }
57
+ else if (typeof schemaInput === 'object') {
58
+ properties[propertyKey] = schemaInput;
51
59
  rootSchema.properties = properties;
52
60
  }
53
- else if (typeof schemaOrType === 'string') {
54
- properties[propertyKey] = { type: schemaOrType };
61
+ else if (typeof schemaInput === 'string') {
62
+ properties[propertyKey] = { type: schemaInput };
55
63
  rootSchema.properties = properties;
56
64
  }
57
65
  else {
@@ -60,7 +68,7 @@ function createRequestDataPropertyDecoratorWithSource(source) {
60
68
  }
61
69
  return requestData({
62
70
  source: source,
63
- schema: rootSchema,
71
+ schema: schemaOrFactory,
64
72
  property: propertyKey,
65
73
  });
66
74
  };
@@ -164,7 +164,7 @@ describe('requestData', function () {
164
164
  schema: { type: DataType.STRING },
165
165
  });
166
166
  });
167
- it('set a given DataSchema to the target metadata', function () {
167
+ it('sets a given DataSchema to the target metadata', function () {
168
168
  const schema = { type: DataType.STRING, required: true };
169
169
  class Target {
170
170
  myMethod(prop) { }
@@ -181,6 +181,23 @@ describe('requestData', function () {
181
181
  schema,
182
182
  });
183
183
  });
184
+ it('sets a given DataSchemaFactory to the target metadata', function () {
185
+ const factory = () => ({ type: DataType.STRING, required: true });
186
+ class Target {
187
+ myMethod(prop) { }
188
+ }
189
+ __decorate([
190
+ __param(0, requestBody(factory)),
191
+ __metadata("design:type", Function),
192
+ __metadata("design:paramtypes", [Object]),
193
+ __metadata("design:returntype", void 0)
194
+ ], Target.prototype, "myMethod", null);
195
+ const res = RequestDataReflector.getMetadata(Target, 'myMethod');
196
+ expect(res.get(0)).to.be.eql({
197
+ source: RequestDataSource.BODY,
198
+ schema: factory,
199
+ });
200
+ });
184
201
  });
185
202
  });
186
203
  describe('request data piece by a given property key', function () {
@@ -263,6 +280,39 @@ describe('requestData', function () {
263
280
  property: propertyKey,
264
281
  });
265
282
  });
283
+ it('sets a given DataSchemaFactory to the target metadata', function () {
284
+ const container = {};
285
+ const factory = sc => {
286
+ expect(sc).to.be.eq(container);
287
+ return { type: DataType.STRING, required: true };
288
+ };
289
+ const propertyKey = 'myPropertyKey';
290
+ class Target {
291
+ myMethod(prop) { }
292
+ }
293
+ __decorate([
294
+ __param(0, requestParam(propertyKey, factory)),
295
+ __metadata("design:type", Function),
296
+ __metadata("design:paramtypes", [Object]),
297
+ __metadata("design:returntype", void 0)
298
+ ], Target.prototype, "myMethod", null);
299
+ const mdMap = RequestDataReflector.getMetadata(Target, 'myMethod');
300
+ const md = mdMap.get(0);
301
+ expect(md.source).to.be.eq(RequestDataSource.PARAMS);
302
+ expect(md.schema).to.be.a('function');
303
+ expect(md.property).to.be.eq(propertyKey);
304
+ const res1 = md.schema;
305
+ const res2 = res1(container);
306
+ expect(res2).to.be.eql({
307
+ type: DataType.OBJECT,
308
+ properties: {
309
+ [propertyKey]: {
310
+ type: DataType.STRING,
311
+ required: true,
312
+ },
313
+ },
314
+ });
315
+ });
266
316
  });
267
317
  describe('query', function () {
268
318
  it('sets a given "propertyKey" to the target metadata', function () {
@@ -343,6 +393,39 @@ describe('requestData', function () {
343
393
  property: propertyKey,
344
394
  });
345
395
  });
396
+ it('sets a given DataSchemaFactory to the target metadata', function () {
397
+ const container = {};
398
+ const factory = sc => {
399
+ expect(sc).to.be.eq(container);
400
+ return { type: DataType.STRING, required: true };
401
+ };
402
+ const propertyKey = 'myPropertyKey';
403
+ class Target {
404
+ myMethod(prop) { }
405
+ }
406
+ __decorate([
407
+ __param(0, requestQuery(propertyKey, factory)),
408
+ __metadata("design:type", Function),
409
+ __metadata("design:paramtypes", [Object]),
410
+ __metadata("design:returntype", void 0)
411
+ ], Target.prototype, "myMethod", null);
412
+ const mdMap = RequestDataReflector.getMetadata(Target, 'myMethod');
413
+ const md = mdMap.get(0);
414
+ expect(md.source).to.be.eq(RequestDataSource.QUERY);
415
+ expect(md.schema).to.be.a('function');
416
+ expect(md.property).to.be.eq(propertyKey);
417
+ const res1 = md.schema;
418
+ const res2 = res1(container);
419
+ expect(res2).to.be.eql({
420
+ type: DataType.OBJECT,
421
+ properties: {
422
+ [propertyKey]: {
423
+ type: DataType.STRING,
424
+ required: true,
425
+ },
426
+ },
427
+ });
428
+ });
346
429
  });
347
430
  describe('header', function () {
348
431
  it('sets a given "propertyKey" to the target metadata', function () {
@@ -423,6 +506,39 @@ describe('requestData', function () {
423
506
  property: propertyKey,
424
507
  });
425
508
  });
509
+ it('sets a given DataSchemaFactory to the target metadata', function () {
510
+ const container = {};
511
+ const factory = sc => {
512
+ expect(sc).to.be.eq(container);
513
+ return { type: DataType.STRING, required: true };
514
+ };
515
+ const propertyKey = 'myPropertyKey';
516
+ class Target {
517
+ myMethod(prop) { }
518
+ }
519
+ __decorate([
520
+ __param(0, requestHeader(propertyKey, factory)),
521
+ __metadata("design:type", Function),
522
+ __metadata("design:paramtypes", [Object]),
523
+ __metadata("design:returntype", void 0)
524
+ ], Target.prototype, "myMethod", null);
525
+ const mdMap = RequestDataReflector.getMetadata(Target, 'myMethod');
526
+ const md = mdMap.get(0);
527
+ expect(md.source).to.be.eq(RequestDataSource.HEADERS);
528
+ expect(md.schema).to.be.a('function');
529
+ expect(md.property).to.be.eq(propertyKey);
530
+ const res1 = md.schema;
531
+ const res2 = res1(container);
532
+ expect(res2).to.be.eql({
533
+ type: DataType.OBJECT,
534
+ properties: {
535
+ [propertyKey]: {
536
+ type: DataType.STRING,
537
+ required: true,
538
+ },
539
+ },
540
+ });
541
+ });
426
542
  });
427
543
  describe('cookie', function () {
428
544
  it('sets a given "propertyKey" to the target metadata', function () {
@@ -503,6 +619,39 @@ describe('requestData', function () {
503
619
  property: propertyKey,
504
620
  });
505
621
  });
622
+ it('sets a given DataSchemaFactory to the target metadata', function () {
623
+ const container = {};
624
+ const factory = sc => {
625
+ expect(sc).to.be.eq(container);
626
+ return { type: DataType.STRING, required: true };
627
+ };
628
+ const propertyKey = 'myPropertyKey';
629
+ class Target {
630
+ myMethod(prop) { }
631
+ }
632
+ __decorate([
633
+ __param(0, requestCookie(propertyKey, factory)),
634
+ __metadata("design:type", Function),
635
+ __metadata("design:paramtypes", [Object]),
636
+ __metadata("design:returntype", void 0)
637
+ ], Target.prototype, "myMethod", null);
638
+ const mdMap = RequestDataReflector.getMetadata(Target, 'myMethod');
639
+ const md = mdMap.get(0);
640
+ expect(md.source).to.be.eq(RequestDataSource.COOKIE);
641
+ expect(md.schema).to.be.a('function');
642
+ expect(md.property).to.be.eq(propertyKey);
643
+ const res1 = md.schema;
644
+ const res2 = res1(container);
645
+ expect(res2).to.be.eql({
646
+ type: DataType.OBJECT,
647
+ properties: {
648
+ [propertyKey]: {
649
+ type: DataType.STRING,
650
+ required: true,
651
+ },
652
+ },
653
+ });
654
+ });
506
655
  });
507
656
  describe('field', function () {
508
657
  it('sets a given "propertyKey" to the target metadata', function () {
@@ -583,6 +732,39 @@ describe('requestData', function () {
583
732
  property: propertyKey,
584
733
  });
585
734
  });
735
+ it('sets a given DataSchemaFactory to the target metadata', function () {
736
+ const container = {};
737
+ const factory = sc => {
738
+ expect(sc).to.be.eq(container);
739
+ return { type: DataType.STRING, required: true };
740
+ };
741
+ const propertyKey = 'myPropertyKey';
742
+ class Target {
743
+ myMethod(prop) { }
744
+ }
745
+ __decorate([
746
+ __param(0, requestField(propertyKey, factory)),
747
+ __metadata("design:type", Function),
748
+ __metadata("design:paramtypes", [Object]),
749
+ __metadata("design:returntype", void 0)
750
+ ], Target.prototype, "myMethod", null);
751
+ const mdMap = RequestDataReflector.getMetadata(Target, 'myMethod');
752
+ const md = mdMap.get(0);
753
+ expect(md.source).to.be.eq(RequestDataSource.BODY);
754
+ expect(md.schema).to.be.a('function');
755
+ expect(md.property).to.be.eq(propertyKey);
756
+ const res1 = md.schema;
757
+ const res2 = res1(container);
758
+ expect(res2).to.be.eql({
759
+ type: DataType.OBJECT,
760
+ properties: {
761
+ [propertyKey]: {
762
+ type: DataType.STRING,
763
+ required: true,
764
+ },
765
+ },
766
+ });
767
+ });
586
768
  });
587
769
  });
588
770
  });
@@ -1,5 +1,5 @@
1
1
  import { MetadataKey } from '@e22m4u/ts-reflector';
2
- import { DataSchema } from '@e22m4u/ts-data-schema';
2
+ import { DataSchemaOrFactory } from '../../data-schema-types.js';
3
3
  /**
4
4
  * Request data source.
5
5
  */
@@ -15,7 +15,7 @@ export declare enum RequestDataSource {
15
15
  */
16
16
  export type RequestDataMetadata = {
17
17
  source: RequestDataSource;
18
- schema?: DataSchema;
18
+ schema?: DataSchemaOrFactory;
19
19
  property?: string;
20
20
  };
21
21
  /**
@@ -1,9 +1,8 @@
1
1
  import { Prototype } from '../../types.js';
2
- import { DataType } from '@e22m4u/ts-data-schema';
3
- import { DataSchema } from '@e22m4u/ts-data-schema';
2
+ import { DataSchemaInput } from '../../data-schema-types.js';
4
3
  /**
5
4
  * Response body decorator.
6
5
  *
7
6
  * @param schemaOrType
8
7
  */
9
- export declare function responseBody<T extends object>(schemaOrType?: DataSchema | DataType): (target: Prototype<T>, propertyKey: string, descriptor: PropertyDescriptor) => void;
8
+ export declare function responseBody<T extends object>(schemaInput?: DataSchemaInput): (target: Prototype<T>, propertyKey: string, descriptor: PropertyDescriptor) => void;
@@ -6,18 +6,18 @@ import { ResponseBodyReflector } from './response-body-reflector.js';
6
6
  *
7
7
  * @param schemaOrType
8
8
  */
9
- export function responseBody(schemaOrType) {
9
+ export function responseBody(schemaInput) {
10
10
  return function (target, propertyKey, descriptor) {
11
11
  const decoratorType = getDecoratorTargetType(target, propertyKey, descriptor);
12
12
  if (decoratorType !== DecoratorTargetType.INSTANCE_METHOD)
13
13
  throw new Error('@responseBody decorator is only supported on an instance method.');
14
- let schema;
15
- if (typeof schemaOrType === 'object') {
16
- schema = schemaOrType;
14
+ let schemaOrFactory;
15
+ if (typeof schemaInput === 'function' || typeof schemaInput === 'object') {
16
+ schemaOrFactory = schemaInput;
17
17
  }
18
- else if (typeof schemaOrType === 'string') {
19
- schema = { type: schemaOrType };
18
+ else if (typeof schemaInput === 'string') {
19
+ schemaOrFactory = { type: schemaInput };
20
20
  }
21
- ResponseBodyReflector.setMetadata(schema ? { schema } : {}, target.constructor, propertyKey);
21
+ ResponseBodyReflector.setMetadata(schemaOrFactory ? { schema: schemaOrFactory } : {}, target.constructor, propertyKey);
22
22
  };
23
23
  }