@e22m4u/js-repository 0.1.6 → 0.1.7

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 (137) hide show
  1. package/README.md +31 -0
  2. package/docs/assets/navigation.js +1 -1
  3. package/docs/assets/search.js +1 -1
  4. package/docs/classes/Adapter.html +1 -1
  5. package/docs/classes/AdapterLoader.html +1 -1
  6. package/docs/classes/AdapterRegistry.html +1 -1
  7. package/docs/classes/BelongsToResolver.html +1 -1
  8. package/docs/classes/DatasourceDefinitionValidator.html +1 -1
  9. package/docs/classes/DefinitionRegistry.html +1 -1
  10. package/docs/classes/FieldsClauseTool.html +1 -1
  11. package/docs/classes/HasManyResolver.html +1 -1
  12. package/docs/classes/HasOneResolver.html +1 -1
  13. package/docs/classes/IncludeClauseTool.html +1 -1
  14. package/docs/classes/InvalidArgumentError.html +1 -1
  15. package/docs/classes/InvalidOperatorValueError.html +1 -1
  16. package/docs/classes/ModelDataSanitizer.html +1 -1
  17. package/docs/classes/ModelDataTransformer.html +16 -0
  18. package/docs/classes/ModelDataValidator.html +1 -1
  19. package/docs/classes/ModelDefinitionUtils.html +1 -1
  20. package/docs/classes/ModelDefinitionValidator.html +1 -1
  21. package/docs/classes/NotImplementedError.html +1 -1
  22. package/docs/classes/OperatorClauseTool.html +1 -1
  23. package/docs/classes/OrderClauseTool.html +1 -1
  24. package/docs/classes/PrimaryKeysDefinitionValidator.html +1 -1
  25. package/docs/classes/PropertiesDefinitionValidator.html +1 -1
  26. package/docs/classes/PropertyTransformerRegistry.html +20 -0
  27. package/docs/classes/PropertyValidatorRegistry.html +1 -1
  28. package/docs/classes/ReferencesManyResolver.html +1 -1
  29. package/docs/classes/RelationsDefinitionValidator.html +1 -1
  30. package/docs/classes/Repository.html +1 -1
  31. package/docs/classes/RepositoryRegistry.html +1 -1
  32. package/docs/classes/Schema.html +1 -1
  33. package/docs/classes/SliceClauseTool.html +1 -1
  34. package/docs/classes/WhereClauseTool.html +1 -1
  35. package/docs/enums/DataType.html +1 -1
  36. package/docs/enums/DecoratorTargetType.html +1 -1
  37. package/docs/enums/RelationType.html +1 -1
  38. package/docs/functions/capitalize.html +1 -1
  39. package/docs/functions/cloneDeep.html +1 -1
  40. package/docs/functions/excludeObjectKeys.html +1 -1
  41. package/docs/functions/getCtorName.html +1 -1
  42. package/docs/functions/getDecoratorTargetType.html +1 -1
  43. package/docs/functions/getValueByPath.html +1 -1
  44. package/docs/functions/isCtor.html +1 -1
  45. package/docs/functions/isPureObject.html +1 -1
  46. package/docs/functions/selectObjectKeys.html +1 -1
  47. package/docs/functions/singularize.html +1 -1
  48. package/docs/functions/stringToRegexp.html +1 -1
  49. package/docs/index.html +16 -1
  50. package/docs/interfaces/AndClause.html +1 -1
  51. package/docs/interfaces/Constructor.html +1 -1
  52. package/docs/interfaces/OrClause.html +1 -1
  53. package/docs/modules.html +6 -1
  54. package/docs/types/AnyObject.html +1 -1
  55. package/docs/types/BelongsToDefinition.html +1 -1
  56. package/docs/types/DEFAULT_PRIMARY_KEY_PROPERTY_NAME.html +1 -1
  57. package/docs/types/DatasourceDefinition.html +1 -1
  58. package/docs/types/FieldsClause.html +1 -1
  59. package/docs/types/FilterClause.html +1 -1
  60. package/docs/types/Flatten.html +1 -1
  61. package/docs/types/FullPropertyDefinition.html +1 -1
  62. package/docs/types/HasManyDefinition.html +1 -1
  63. package/docs/types/HasOneDefinition.html +1 -1
  64. package/docs/types/Identity.html +1 -1
  65. package/docs/types/IncludeClause.html +1 -1
  66. package/docs/types/ItemFilterClause.html +1 -1
  67. package/docs/types/ModelData.html +1 -1
  68. package/docs/types/ModelDefinition.html +1 -1
  69. package/docs/types/ModelId.html +1 -1
  70. package/docs/types/NestedIncludeClause.html +1 -1
  71. package/docs/types/NormalizedFieldsClause.html +1 -1
  72. package/docs/types/NormalizedIncludeClause.html +1 -1
  73. package/docs/types/OperatorClause.html +1 -1
  74. package/docs/types/OptionalUnlessRequiredId.html +1 -1
  75. package/docs/types/OrderClause.html +1 -1
  76. package/docs/types/PartialBy.html +1 -1
  77. package/docs/types/PartialWithoutId.html +1 -1
  78. package/docs/types/PolyBelongsToDefinition.html +1 -1
  79. package/docs/types/PolyHasManyDefinitionWithTargetKeys.html +1 -1
  80. package/docs/types/PolyHasManyDefinitionWithTargetRelationName.html +1 -1
  81. package/docs/types/PolyHasOneDefinitionWithTargetKeys.html +1 -1
  82. package/docs/types/PolyHasOneDefinitionWithTargetRelationName.html +1 -1
  83. package/docs/types/PropertiesClause.html +1 -1
  84. package/docs/types/PropertyDefinition.html +1 -1
  85. package/docs/types/PropertyDefinitionMap.html +1 -1
  86. package/docs/types/PropertyTransformOptions.html +2 -0
  87. package/docs/types/PropertyTransformer.html +2 -0
  88. package/docs/types/PropertyTransformerContext.html +2 -0
  89. package/docs/types/PropertyValidateOptions.html +1 -1
  90. package/docs/types/PropertyValidator.html +1 -1
  91. package/docs/types/PropertyValidatorContext.html +1 -1
  92. package/docs/types/ReferencesManyDefinition.html +1 -1
  93. package/docs/types/RelationDefinition.html +1 -1
  94. package/docs/types/RelationDefinitionMap.html +1 -1
  95. package/docs/types/WhereClause.html +1 -1
  96. package/docs/types/WithoutId.html +1 -1
  97. package/package.json +3 -3
  98. package/src/adapter/adapter.js +2 -0
  99. package/src/adapter/adapter.spec.js +9 -3
  100. package/src/adapter/decorator/data-transformation-decorator.d.ts +14 -0
  101. package/src/adapter/decorator/data-transformation-decorator.js +54 -0
  102. package/src/adapter/decorator/data-transformation-decorator.spec.js +95 -0
  103. package/src/adapter/decorator/data-validation-decorator.js +6 -5
  104. package/src/adapter/decorator/data-validation-decorator.spec.js +49 -21
  105. package/src/adapter/decorator/default-values-decorator.spec.js +89 -113
  106. package/src/adapter/decorator/index.d.ts +1 -0
  107. package/src/adapter/decorator/index.js +1 -0
  108. package/src/definition/model/index.d.ts +1 -0
  109. package/src/definition/model/index.js +1 -0
  110. package/src/definition/model/model-data-transformer.d.ts +15 -0
  111. package/src/definition/model/model-data-transformer.js +96 -0
  112. package/src/definition/model/model-data-transformer.spec.js +534 -0
  113. package/src/definition/model/model-data-validator.js +10 -12
  114. package/src/definition/model/model-data-validator.spec.js +133 -32
  115. package/src/definition/model/properties/index.d.ts +1 -0
  116. package/src/definition/model/properties/index.js +1 -0
  117. package/src/definition/model/properties/properties-definition-validator.js +47 -0
  118. package/src/definition/model/properties/properties-definition-validator.spec.js +52 -0
  119. package/src/definition/model/properties/property-transformer/builtin/index.d.ts +1 -0
  120. package/src/definition/model/properties/property-transformer/builtin/index.js +1 -0
  121. package/src/definition/model/properties/property-transformer/builtin/trim-transformer.d.ts +6 -0
  122. package/src/definition/model/properties/property-transformer/builtin/trim-transformer.js +19 -0
  123. package/src/definition/model/properties/property-transformer/builtin/trim-transformer.spec.js +39 -0
  124. package/src/definition/model/properties/property-transformer/index.d.ts +2 -0
  125. package/src/definition/model/properties/property-transformer/index.js +2 -0
  126. package/src/definition/model/properties/property-transformer/property-transformer-registry.d.ts +29 -0
  127. package/src/definition/model/properties/property-transformer/property-transformer-registry.js +72 -0
  128. package/src/definition/model/properties/property-transformer/property-transformer-registry.spec.js +129 -0
  129. package/src/definition/model/properties/property-transformer/property-transformer.d.ts +25 -0
  130. package/src/definition/model/properties/property-transformer/property-transformer.js +1 -0
  131. package/src/definition/model/properties/property-validator/builtin/max-length-validator.js +1 -1
  132. package/src/definition/model/properties/property-validator/builtin/max-length-validator.spec.js +10 -3
  133. package/src/definition/model/properties/property-validator/builtin/min-length-validator.js +1 -1
  134. package/src/definition/model/properties/property-validator/builtin/min-length-validator.spec.js +10 -3
  135. package/src/definition/model/properties/property-validator/builtin/regexp-validator.js +1 -1
  136. package/src/definition/model/properties/property-validator/builtin/regexp-validator.spec.js +10 -3
  137. package/src/definition/model/properties/property-validator/property-validator-registry.spec.js +51 -39
@@ -3,6 +3,7 @@ import {Schema} from '../../schema.js';
3
3
  import {format} from '@e22m4u/js-format';
4
4
  import {DataType} from './properties/index.js';
5
5
  import {ModelDataValidator} from './model-data-validator.js';
6
+ import {DefinitionRegistry} from '../definition-registry.js';
6
7
  import {PropertyValidatorRegistry} from './properties/index.js';
7
8
 
8
9
  describe('ModelDataValidator', function () {
@@ -1998,7 +1999,7 @@ describe('ModelDataValidator', function () {
1998
1999
 
1999
2000
  describe('validate by property validators', function () {
2000
2001
  describe('the option "validate" with the string value', function () {
2001
- it('do not validate null and undefined values', function () {
2002
+ it('validates a property value even is not provided', function () {
2002
2003
  const S = new Schema();
2003
2004
  S.getService(PropertyValidatorRegistry).addValidator(
2004
2005
  'myValidator',
@@ -2011,20 +2012,41 @@ describe('ModelDataValidator', function () {
2011
2012
  type: DataType.ANY,
2012
2013
  validate: 'myValidator',
2013
2014
  },
2014
- bar: {
2015
- type: DataType.ANY,
2016
- validate: 'myValidator',
2017
- },
2018
- baz: {
2015
+ },
2016
+ });
2017
+ const validator = S.getService(ModelDataValidator);
2018
+ const throwable = () => validator.validate('model', {});
2019
+ expect(throwable).to.throw(
2020
+ 'The property "foo" of the model "model" has an invalid value undefined ' +
2021
+ 'that caught by the validator "myValidator".',
2022
+ );
2023
+ });
2024
+
2025
+ it('validates undefined and null values', function () {
2026
+ const S = new Schema();
2027
+ S.getService(PropertyValidatorRegistry).addValidator(
2028
+ 'myValidator',
2029
+ () => false,
2030
+ );
2031
+ S.defineModel({
2032
+ name: 'model',
2033
+ properties: {
2034
+ foo: {
2019
2035
  type: DataType.ANY,
2020
2036
  validate: 'myValidator',
2021
2037
  },
2022
2038
  },
2023
2039
  });
2024
- S.getService(ModelDataValidator).validate('model', {
2025
- foo: null,
2026
- bar: undefined,
2027
- });
2040
+ const validator = S.getService(ModelDataValidator);
2041
+ const throwable = v => () => validator.validate('model', {foo: v});
2042
+ const error = v =>
2043
+ format(
2044
+ 'The property "foo" of the model "model" has an invalid value %s ' +
2045
+ 'that caught by the validator "myValidator".',
2046
+ v,
2047
+ );
2048
+ expect(throwable(undefined)).to.throw(error('undefined'));
2049
+ expect(throwable(null)).to.throw(error('null'));
2028
2050
  });
2029
2051
 
2030
2052
  it('throws an error from the validator', function () {
@@ -2211,7 +2233,7 @@ describe('ModelDataValidator', function () {
2211
2233
  });
2212
2234
  });
2213
2235
 
2214
- it('do not validate null and undefined values', function () {
2236
+ it('validates a property value even is not provided', function () {
2215
2237
  const S = new Schema();
2216
2238
  S.getService(PropertyValidatorRegistry).addValidator(
2217
2239
  'myValidator',
@@ -2224,20 +2246,41 @@ describe('ModelDataValidator', function () {
2224
2246
  type: DataType.ANY,
2225
2247
  validate: ['myValidator'],
2226
2248
  },
2227
- bar: {
2228
- type: DataType.ANY,
2229
- validate: ['myValidator'],
2230
- },
2231
- baz: {
2249
+ },
2250
+ });
2251
+ const validator = S.getService(ModelDataValidator);
2252
+ const throwable = () => validator.validate('model', {});
2253
+ expect(throwable).to.throw(
2254
+ 'The property "foo" of the model "model" has an invalid value undefined ' +
2255
+ 'that caught by the validator "myValidator".',
2256
+ );
2257
+ });
2258
+
2259
+ it('validates undefined and null values', function () {
2260
+ const S = new Schema();
2261
+ S.getService(PropertyValidatorRegistry).addValidator(
2262
+ 'myValidator',
2263
+ () => false,
2264
+ );
2265
+ S.defineModel({
2266
+ name: 'model',
2267
+ properties: {
2268
+ foo: {
2232
2269
  type: DataType.ANY,
2233
2270
  validate: ['myValidator'],
2234
2271
  },
2235
2272
  },
2236
2273
  });
2237
- S.getService(ModelDataValidator).validate('model', {
2238
- foo: null,
2239
- bar: undefined,
2240
- });
2274
+ const validator = S.getService(ModelDataValidator);
2275
+ const throwable = v => () => validator.validate('model', {foo: v});
2276
+ const error = v =>
2277
+ format(
2278
+ 'The property "foo" of the model "model" has an invalid value %s ' +
2279
+ 'that caught by the validator "myValidator".',
2280
+ v,
2281
+ );
2282
+ expect(throwable(undefined)).to.throw(error('undefined'));
2283
+ expect(throwable(null)).to.throw(error('null'));
2241
2284
  });
2242
2285
 
2243
2286
  it('throws an error from the validator', function () {
@@ -2425,7 +2468,7 @@ describe('ModelDataValidator', function () {
2425
2468
  });
2426
2469
  });
2427
2470
 
2428
- it('do not validate null and undefined values', function () {
2471
+ it('validates a property value even is not provided', function () {
2429
2472
  const S = new Schema();
2430
2473
  S.getService(PropertyValidatorRegistry).addValidator(
2431
2474
  'myValidator',
@@ -2440,13 +2483,26 @@ describe('ModelDataValidator', function () {
2440
2483
  myValidator: true,
2441
2484
  },
2442
2485
  },
2443
- bar: {
2444
- type: DataType.ANY,
2445
- validate: {
2446
- myValidator: true,
2447
- },
2448
- },
2449
- baz: {
2486
+ },
2487
+ });
2488
+ const validator = S.getService(ModelDataValidator);
2489
+ const throwable = () => validator.validate('model', {});
2490
+ expect(throwable).to.throw(
2491
+ 'The property "foo" of the model "model" has an invalid value undefined ' +
2492
+ 'that caught by the validator "myValidator".',
2493
+ );
2494
+ });
2495
+
2496
+ it('validates undefined and null values', function () {
2497
+ const S = new Schema();
2498
+ S.getService(PropertyValidatorRegistry).addValidator(
2499
+ 'myValidator',
2500
+ () => false,
2501
+ );
2502
+ S.defineModel({
2503
+ name: 'model',
2504
+ properties: {
2505
+ foo: {
2450
2506
  type: DataType.ANY,
2451
2507
  validate: {
2452
2508
  myValidator: true,
@@ -2454,10 +2510,16 @@ describe('ModelDataValidator', function () {
2454
2510
  },
2455
2511
  },
2456
2512
  });
2457
- S.getService(ModelDataValidator).validate('model', {
2458
- foo: null,
2459
- bar: undefined,
2460
- });
2513
+ const validator = S.getService(ModelDataValidator);
2514
+ const throwable = v => () => validator.validate('model', {foo: v});
2515
+ const error = v =>
2516
+ format(
2517
+ 'The property "foo" of the model "model" has an invalid value %s ' +
2518
+ 'that caught by the validator "myValidator".',
2519
+ v,
2520
+ );
2521
+ expect(throwable(undefined)).to.throw(error('undefined'));
2522
+ expect(throwable(null)).to.throw(error('null'));
2461
2523
  });
2462
2524
 
2463
2525
  it('throws an error from the validator', function () {
@@ -2676,6 +2738,45 @@ describe('ModelDataValidator', function () {
2676
2738
  expect(validated).to.be.true;
2677
2739
  });
2678
2740
  });
2741
+
2742
+ it('the option "validate" requires a non-empty String, an Array or an Object', function () {
2743
+ const schema = new Schema();
2744
+ schema
2745
+ .getService(PropertyValidatorRegistry)
2746
+ .addValidator('myValidator', () => true);
2747
+ schema.defineModel({
2748
+ name: 'model',
2749
+ properties: {
2750
+ foo: {
2751
+ type: DataType.STRING,
2752
+ validate: undefined,
2753
+ },
2754
+ },
2755
+ });
2756
+ const V = schema.getService(ModelDataValidator);
2757
+ const throwable = v => () => {
2758
+ const models = schema.getService(DefinitionRegistry)['_models'];
2759
+ models.model.properties.foo.validate = v;
2760
+ V.validate('model', {});
2761
+ };
2762
+ const error = v =>
2763
+ format(
2764
+ 'The provided option "validate" of the property "foo" in the model "model" ' +
2765
+ 'should be a non-empty String, an Array of String or an Object, ' +
2766
+ 'but %s given.',
2767
+ v,
2768
+ );
2769
+ expect(throwable('')).to.throw(error('""'));
2770
+ expect(throwable(10)).to.throw(error('10'));
2771
+ expect(throwable(0)).to.throw(error('0'));
2772
+ expect(throwable(true)).to.throw(error('true'));
2773
+ expect(throwable(false)).to.throw(error('false'));
2774
+ throwable('myValidator')();
2775
+ throwable(['myValidator'])();
2776
+ throwable([])();
2777
+ throwable({myValidator: true})();
2778
+ throwable({})();
2779
+ });
2679
2780
  });
2680
2781
  });
2681
2782
  });
@@ -1,5 +1,6 @@
1
1
  export * from './data-type.js';
2
2
  export * from './property-definition.js';
3
3
  export * from './property-validator/index.js';
4
+ export * from './property-transformer/index.js';
4
5
  export * from './properties-definition-validator.js';
5
6
  export * from './primary-keys-definition-validator.js';
@@ -1,5 +1,6 @@
1
1
  export * from './data-type.js';
2
2
  export * from './property-definition.js';
3
3
  export * from './property-validator/index.js';
4
+ export * from './property-transformer/index.js';
4
5
  export * from './properties-definition-validator.js';
5
6
  export * from './primary-keys-definition-validator.js';
@@ -3,6 +3,7 @@ import {DataType as Type} from './data-type.js';
3
3
  import {capitalize} from '../../../utils/index.js';
4
4
  import {InvalidArgumentError} from '../../../errors/index.js';
5
5
  import {PropertyValidatorRegistry} from './property-validator/index.js';
6
+ import {PropertyTransformerRegistry} from './property-transformer/index.js';
6
7
  import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
7
8
 
8
9
  /**
@@ -250,5 +251,51 @@ export class PropertiesDefinitionValidator extends Service {
250
251
  );
251
252
  }
252
253
  }
254
+ if (propDef.transform != null) {
255
+ const propertyTransformerRegistry = this.getService(
256
+ PropertyTransformerRegistry,
257
+ );
258
+ if (propDef.transform && typeof propDef.transform === 'string') {
259
+ if (!propertyTransformerRegistry.hasTransformer(propDef.transform))
260
+ throw new InvalidArgumentError(
261
+ 'The property transformer %v is not found.',
262
+ propDef.transform,
263
+ );
264
+ } else if (Array.isArray(propDef.transform)) {
265
+ for (const transformerName of propDef.transform) {
266
+ if (typeof transformerName !== 'string')
267
+ throw new InvalidArgumentError(
268
+ 'The provided option "transform" of the property %v in the model %v ' +
269
+ 'has an Array value that should have a non-empty String, ' +
270
+ 'but %v given.',
271
+ propName,
272
+ modelName,
273
+ transformerName,
274
+ );
275
+ if (!propertyTransformerRegistry.hasTransformer(transformerName))
276
+ throw new InvalidArgumentError(
277
+ 'The property transformer %v is not found.',
278
+ transformerName,
279
+ );
280
+ }
281
+ } else if (typeof propDef.transform === 'object') {
282
+ for (const transformerName in propDef.transform) {
283
+ if (!propertyTransformerRegistry.hasTransformer(transformerName))
284
+ throw new InvalidArgumentError(
285
+ 'The property transformer %v is not found.',
286
+ transformerName,
287
+ );
288
+ }
289
+ } else {
290
+ throw new InvalidArgumentError(
291
+ 'The provided option "transform" of the property %v in the model %v ' +
292
+ 'should be a non-empty String, an Array of String or an Object, ' +
293
+ 'but %v given.',
294
+ propName,
295
+ modelName,
296
+ propDef.transform,
297
+ );
298
+ }
299
+ }
253
300
  }
254
301
  }
@@ -3,6 +3,7 @@ import {expect} from 'chai';
3
3
  import {DataType} from './data-type.js';
4
4
  import {format} from '@e22m4u/js-format';
5
5
  import {PropertyValidatorRegistry} from './property-validator/index.js';
6
+ import {PropertyTransformerRegistry} from './property-transformer/index.js';
6
7
  import {PropertiesDefinitionValidator} from './properties-definition-validator.js';
7
8
  import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
8
9
 
@@ -10,6 +11,10 @@ const S = new PropertiesDefinitionValidator();
10
11
  const sandbox = chai.spy.sandbox();
11
12
 
12
13
  S.getService(PropertyValidatorRegistry).addValidator('myValidator', () => true);
14
+ S.getService(PropertyTransformerRegistry).addTransformer(
15
+ 'myTransformer',
16
+ () => true,
17
+ );
13
18
 
14
19
  describe('PropertiesDefinitionValidator', function () {
15
20
  afterEach(function () {
@@ -436,5 +441,52 @@ describe('PropertiesDefinitionValidator', function () {
436
441
  validate(['myValidator'])();
437
442
  validate({myValidator: true})();
438
443
  });
444
+
445
+ it('the option "transform" should have a non-empty String, an Array of String or an Object', function () {
446
+ const validate = v => () => {
447
+ const foo = {
448
+ type: DataType.ANY,
449
+ transform: v,
450
+ };
451
+ S.validate('model', {foo});
452
+ };
453
+ const error = v =>
454
+ format(
455
+ 'The provided option "transform" of the property "foo" in the model "model" ' +
456
+ 'should be a non-empty String, an Array of String or an Object, ' +
457
+ 'but %s given.',
458
+ v,
459
+ );
460
+ expect(validate('')).to.throw(error('""'));
461
+ expect(validate(10)).to.throw(error('10'));
462
+ expect(validate(0)).to.throw(error('0'));
463
+ expect(validate(true)).to.throw(error('true'));
464
+ expect(validate(false)).to.throw(error('false'));
465
+ expect(validate(() => undefined)).to.throw(error('Function'));
466
+ validate('myTransformer')();
467
+ validate(['myTransformer'])();
468
+ validate([])();
469
+ validate({myTransformer: true})();
470
+ validate({})();
471
+ validate(null)();
472
+ validate(undefined)();
473
+ });
474
+
475
+ it('the option "transform" requires only existing transformer names', function () {
476
+ const validate = v => () => {
477
+ const foo = {
478
+ type: DataType.ANY,
479
+ transform: v,
480
+ };
481
+ S.validate('model', {foo});
482
+ };
483
+ const error = v => format('The property transformer %s is not found.', v);
484
+ expect(validate('unknown')).to.throw(error('"unknown"'));
485
+ expect(validate({unknown: true})).to.throw(error('"unknown"'));
486
+ expect(validate(['unknown'])).to.throw(error('"unknown"'));
487
+ validate('myTransformer')();
488
+ validate(['myTransformer'])();
489
+ validate({myTransformer: true})();
490
+ });
439
491
  });
440
492
  });
@@ -0,0 +1 @@
1
+ export * from './trim-transformer.js';
@@ -0,0 +1 @@
1
+ export * from './trim-transformer.js';
@@ -0,0 +1,6 @@
1
+ import {PropertyTransformer} from '../property-transformer.js';
2
+
3
+ /**
4
+ * Trim transformer.
5
+ */
6
+ export declare type trimTransformer = PropertyTransformer;
@@ -0,0 +1,19 @@
1
+ import {InvalidArgumentError} from '../../../../../errors/index.js';
2
+
3
+ /**
4
+ * Trim transformer.
5
+ *
6
+ * @param {*} value
7
+ * @param {undefined} options
8
+ * @param {object} context
9
+ * @returns {string|undefined|null}
10
+ */
11
+ export function trimTransformer(value, options, context) {
12
+ if (value == null) return value;
13
+ if (typeof value === 'string') return value.trim();
14
+ throw new InvalidArgumentError(
15
+ 'The property transformer %v requires a String value, but %v given.',
16
+ context.transformerName,
17
+ value,
18
+ );
19
+ }
@@ -0,0 +1,39 @@
1
+ import {expect} from 'chai';
2
+ import {format} from '@e22m4u/js-format';
3
+ import {trimTransformer} from './trim-transformer.js';
4
+
5
+ describe('trimTransformer', function () {
6
+ it('returns undefined and null values as is', function () {
7
+ const res1 = trimTransformer(undefined, undefined, {});
8
+ const res2 = trimTransformer(null, undefined, {});
9
+ expect(res1).to.be.undefined;
10
+ expect(res2).to.be.null;
11
+ });
12
+
13
+ it('trims the given string', function () {
14
+ const res = trimTransformer(' test ', undefined, {});
15
+ expect(res).to.be.eq('test');
16
+ });
17
+
18
+ it('throws an error if the given value is not a string', function () {
19
+ const throwable = v => () =>
20
+ trimTransformer(v, undefined, {
21
+ transformerName: 'trim',
22
+ });
23
+ const error = v =>
24
+ format(
25
+ 'The property transformer "trim" requires a String value, but %s given.',
26
+ v,
27
+ );
28
+ expect(throwable(10)).to.throw(error('10'));
29
+ expect(throwable(0)).to.throw(error('0'));
30
+ expect(throwable(true)).to.throw(error('true'));
31
+ expect(throwable(false)).to.throw(error('false'));
32
+ expect(throwable({})).to.throw(error('Object'));
33
+ expect(throwable([])).to.throw(error('Array'));
34
+ throwable('str')();
35
+ throwable('')();
36
+ throwable(undefined)();
37
+ throwable(null)();
38
+ });
39
+ });
@@ -0,0 +1,2 @@
1
+ export * from './property-transformer.js';
2
+ export * from './property-transformer-registry.js';
@@ -0,0 +1,2 @@
1
+ export * from './property-transformer.js';
2
+ export * from './property-transformer-registry.js';
@@ -0,0 +1,29 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {PropertyTransformer} from './property-transformer.js';
3
+
4
+ /**
5
+ * Property transformer registry.
6
+ */
7
+ export declare class PropertyTransformerRegistry extends Service {
8
+ /**
9
+ * Add transformer.
10
+ *
11
+ * @param name
12
+ * @param transformer
13
+ */
14
+ addTransformer(name: string, transformer: PropertyTransformer): this;
15
+
16
+ /**
17
+ * Has transformer.
18
+ *
19
+ * @param name
20
+ */
21
+ hasTransformer(name: string): boolean;
22
+
23
+ /**
24
+ * Get transformer.
25
+ *
26
+ * @param name
27
+ */
28
+ getTransformer(name: string): PropertyTransformer;
29
+ }
@@ -0,0 +1,72 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {trimTransformer} from './builtin/index.js';
3
+ import {InvalidArgumentError} from '../../../../errors/index.js';
4
+
5
+ /**
6
+ * Property transformer registry.
7
+ */
8
+ export class PropertyTransformerRegistry extends Service {
9
+ /**
10
+ * Transformers.
11
+ *
12
+ * @type {object}
13
+ */
14
+ _transformers = {
15
+ trim: trimTransformer,
16
+ };
17
+
18
+ /**
19
+ * Add transformer.
20
+ *
21
+ * @param {string} name
22
+ * @param {Function} transformer
23
+ * @returns {PropertyTransformerRegistry}
24
+ */
25
+ addTransformer(name, transformer) {
26
+ if (!name || typeof name !== 'string')
27
+ throw new InvalidArgumentError(
28
+ 'A name of the property transformer must ' +
29
+ 'be a non-empty String, but %v given.',
30
+ name,
31
+ );
32
+ if (name in this._transformers)
33
+ throw new InvalidArgumentError(
34
+ 'The property transformer %v is already defined.',
35
+ name,
36
+ );
37
+ if (typeof transformer !== 'function')
38
+ throw new InvalidArgumentError(
39
+ 'The property transformer %v must be a Function, but %v given.',
40
+ name,
41
+ transformer,
42
+ );
43
+ this._transformers[name] = transformer;
44
+ return this;
45
+ }
46
+
47
+ /**
48
+ * Has transformer.
49
+ *
50
+ * @param {string} name
51
+ * @returns {boolean}
52
+ */
53
+ hasTransformer(name) {
54
+ return Boolean(this._transformers[name]);
55
+ }
56
+
57
+ /**
58
+ * Get transformer.
59
+ *
60
+ * @param {string} name
61
+ * @returns {Function}
62
+ */
63
+ getTransformer(name) {
64
+ const transformer = this._transformers[name];
65
+ if (!transformer)
66
+ throw new InvalidArgumentError(
67
+ 'The property transformer %v is not defined.',
68
+ name,
69
+ );
70
+ return transformer;
71
+ }
72
+ }