@fgv/ts-utils 5.0.2-0 → 5.1.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +21 -0
- package/README.md +152 -84
- package/dist/index.js +2 -2
- package/dist/packlets/base/messageAggregator.js +6 -6
- package/dist/packlets/base/result.js +39 -39
- package/dist/packlets/base/utils.js +47 -0
- package/dist/packlets/collections/aggregatedResultMap.js +722 -0
- package/dist/packlets/collections/collector.js +9 -9
- package/dist/packlets/collections/collectorValidator.js +4 -4
- package/dist/packlets/collections/converters.js +39 -0
- package/dist/packlets/collections/convertingCollectorValidator.js +3 -3
- package/dist/packlets/collections/convertingResultMap.js +208 -0
- package/dist/packlets/collections/index.js +4 -0
- package/dist/packlets/collections/keyValueConverters.js +1 -4
- package/dist/packlets/collections/readOnlyConvertingResultMap.js +193 -0
- package/dist/packlets/collections/resultMapValidator.js +50 -6
- package/dist/packlets/collections/validatingConvertingResultMap.js +78 -0
- package/dist/packlets/conversion/advancedConverters.js +249 -0
- package/dist/packlets/conversion/baseConverter.js +23 -16
- package/dist/packlets/conversion/basicConverters.js +571 -0
- package/dist/packlets/conversion/converters.js +3 -617
- package/dist/packlets/conversion/defaultingConverter.js +21 -15
- package/dist/packlets/logging/bootLogger.js +122 -0
- package/dist/packlets/logging/index.js +1 -0
- package/dist/packlets/logging/logReporter.js +32 -1
- package/dist/packlets/logging/logger.js +25 -5
- package/dist/packlets/validation/classes.js +1 -0
- package/dist/packlets/validation/compositeId.js +60 -0
- package/dist/packlets/validation/field.js +1 -1
- package/dist/packlets/validation/genericValidator.js +24 -10
- package/dist/packlets/validation/object.js +3 -6
- package/dist/packlets/validation/validators.js +12 -0
- package/dist/ts-utils.d.ts +1633 -200
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -1
- package/lib/packlets/base/mapResults.d.ts +3 -3
- package/lib/packlets/base/messageAggregator.d.ts +6 -6
- package/lib/packlets/base/messageAggregator.js +6 -6
- package/lib/packlets/base/result.d.ts +74 -51
- package/lib/packlets/base/result.js +39 -39
- package/lib/packlets/base/utils.d.ts +42 -0
- package/lib/packlets/base/utils.js +52 -0
- package/lib/packlets/collections/aggregatedResultMap.d.ts +433 -0
- package/lib/packlets/collections/aggregatedResultMap.js +728 -0
- package/lib/packlets/collections/collector.d.ts +11 -10
- package/lib/packlets/collections/collector.js +9 -9
- package/lib/packlets/collections/collectorValidator.d.ts +12 -10
- package/lib/packlets/collections/collectorValidator.js +4 -4
- package/lib/packlets/collections/converters.d.ts +18 -0
- package/lib/packlets/collections/converters.js +42 -0
- package/lib/packlets/collections/convertingCollector.d.ts +4 -4
- package/lib/packlets/collections/convertingCollectorValidator.d.ts +10 -7
- package/lib/packlets/collections/convertingCollectorValidator.js +3 -3
- package/lib/packlets/collections/convertingResultMap.d.ts +176 -0
- package/lib/packlets/collections/convertingResultMap.js +213 -0
- package/lib/packlets/collections/index.d.ts +4 -0
- package/lib/packlets/collections/index.js +4 -0
- package/lib/packlets/collections/keyValueConverters.d.ts +1 -4
- package/lib/packlets/collections/keyValueConverters.js +1 -4
- package/lib/packlets/collections/readOnlyConvertingResultMap.d.ts +153 -0
- package/lib/packlets/collections/readOnlyConvertingResultMap.js +197 -0
- package/lib/packlets/collections/readonlyResultMap.d.ts +7 -7
- package/lib/packlets/collections/resultMap.d.ts +108 -2
- package/lib/packlets/collections/resultMapValidator.d.ts +45 -11
- package/lib/packlets/collections/resultMapValidator.js +52 -7
- package/lib/packlets/collections/validatingCollector.d.ts +5 -5
- package/lib/packlets/collections/validatingConvertingCollector.d.ts +3 -3
- package/lib/packlets/collections/validatingConvertingResultMap.d.ts +102 -0
- package/lib/packlets/collections/validatingConvertingResultMap.js +83 -0
- package/lib/packlets/collections/validatingResultMap.d.ts +1 -1
- package/lib/packlets/conversion/advancedConverters.d.ts +170 -0
- package/lib/packlets/conversion/advancedConverters.js +258 -0
- package/lib/packlets/conversion/baseConverter.d.ts +39 -23
- package/lib/packlets/conversion/baseConverter.js +23 -16
- package/lib/packlets/conversion/basicConverters.d.ts +470 -0
- package/lib/packlets/conversion/basicConverters.js +595 -0
- package/lib/packlets/conversion/converter.d.ts +7 -0
- package/lib/packlets/conversion/converters.d.ts +2 -535
- package/lib/packlets/conversion/converters.js +17 -639
- package/lib/packlets/conversion/defaultingConverter.d.ts +20 -16
- package/lib/packlets/conversion/defaultingConverter.js +21 -15
- package/lib/packlets/logging/bootLogger.d.ts +84 -0
- package/lib/packlets/logging/bootLogger.js +126 -0
- package/lib/packlets/logging/index.d.ts +1 -0
- package/lib/packlets/logging/index.js +1 -0
- package/lib/packlets/logging/logReporter.d.ts +18 -3
- package/lib/packlets/logging/logReporter.js +31 -0
- package/lib/packlets/logging/logger.d.ts +39 -6
- package/lib/packlets/logging/logger.js +26 -5
- package/lib/packlets/validation/classes.d.ts +1 -0
- package/lib/packlets/validation/classes.js +3 -1
- package/lib/packlets/validation/compositeId.d.ts +29 -0
- package/lib/packlets/validation/compositeId.js +64 -0
- package/lib/packlets/validation/field.d.ts +1 -1
- package/lib/packlets/validation/field.js +1 -1
- package/lib/packlets/validation/genericValidator.d.ts +15 -11
- package/lib/packlets/validation/genericValidator.js +24 -10
- package/lib/packlets/validation/object.d.ts +3 -6
- package/lib/packlets/validation/object.js +3 -6
- package/lib/packlets/validation/traits.d.ts +3 -3
- package/lib/packlets/validation/validator.d.ts +7 -0
- package/lib/packlets/validation/validators.d.ts +10 -0
- package/lib/packlets/validation/validators.js +13 -0
- package/package.json +14 -14
|
@@ -20,6 +20,50 @@
|
|
|
20
20
|
* SOFTWARE.
|
|
21
21
|
*/
|
|
22
22
|
import { failWithDetail, succeedWithDetail } from '../base';
|
|
23
|
+
/**
|
|
24
|
+
* A read-only validator for any {@link Collections.IReadOnlyResultMap | IReadOnlyResultMap}
|
|
25
|
+
* that validates weakly-typed keys before accessing values.
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export class ReadOnlyResultMapValidator {
|
|
29
|
+
/**
|
|
30
|
+
* The underlying map.
|
|
31
|
+
*/
|
|
32
|
+
get map() {
|
|
33
|
+
return this._map;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Constructs a new {@link Collections.ReadOnlyResultMapValidator | ReadOnlyResultMapValidator}.
|
|
37
|
+
* @param map - The map to validate access to.
|
|
38
|
+
* @param converters - The key-value converters for validation.
|
|
39
|
+
*/
|
|
40
|
+
constructor(map, converters) {
|
|
41
|
+
this._map = map;
|
|
42
|
+
this.converters = converters;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Gets a value from the map by key, validating the key first.
|
|
46
|
+
* @param key - The key to retrieve (will be validated).
|
|
47
|
+
* @returns `Success` with the value if found, `Failure` otherwise.
|
|
48
|
+
*/
|
|
49
|
+
get(key) {
|
|
50
|
+
return this.converters.convertKey(key).onSuccess((validKey) => {
|
|
51
|
+
return this._map.get(validKey);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Checks if the map contains a key, validating the key first.
|
|
56
|
+
* @param key - The key to check (will be validated).
|
|
57
|
+
* @returns `true` if the key exists and is valid, `false` otherwise.
|
|
58
|
+
*/
|
|
59
|
+
has(key) {
|
|
60
|
+
const result = this.converters.convertKey(key);
|
|
61
|
+
if (result.isFailure()) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return this._map.has(result.value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
23
67
|
/**
|
|
24
68
|
* A {@link Collections.ResultMap | ResultMap} wrapper which validates weakly-typed keys
|
|
25
69
|
* before calling the wrapped result map.
|
|
@@ -38,7 +82,7 @@ export class ResultMapValidator {
|
|
|
38
82
|
this.converters = params.converters;
|
|
39
83
|
}
|
|
40
84
|
/**
|
|
41
|
-
* {@
|
|
85
|
+
* {@inheritDoc Collections.ResultMap.add}
|
|
42
86
|
*/
|
|
43
87
|
add(key, value) {
|
|
44
88
|
return this.converters.convertEntry([key, value]).onSuccess(([vk, vv]) => {
|
|
@@ -46,7 +90,7 @@ export class ResultMapValidator {
|
|
|
46
90
|
});
|
|
47
91
|
}
|
|
48
92
|
/**
|
|
49
|
-
* {@
|
|
93
|
+
* {@inheritDoc Collections.ResultMap.delete}
|
|
50
94
|
*/
|
|
51
95
|
delete(key) {
|
|
52
96
|
return this.converters.convertKey(key).onSuccess((k) => {
|
|
@@ -54,7 +98,7 @@ export class ResultMapValidator {
|
|
|
54
98
|
});
|
|
55
99
|
}
|
|
56
100
|
/**
|
|
57
|
-
* {@
|
|
101
|
+
* {@inheritDoc Collections.ResultMap.get}
|
|
58
102
|
*/
|
|
59
103
|
get(key) {
|
|
60
104
|
return this.converters.convertKey(key).onSuccess((k) => {
|
|
@@ -81,13 +125,13 @@ export class ResultMapValidator {
|
|
|
81
125
|
}
|
|
82
126
|
}
|
|
83
127
|
/**
|
|
84
|
-
* {@
|
|
128
|
+
* {@inheritDoc Collections.ResultMap.has}
|
|
85
129
|
*/
|
|
86
130
|
has(key) {
|
|
87
131
|
return this._map.has(key);
|
|
88
132
|
}
|
|
89
133
|
/**
|
|
90
|
-
* {@
|
|
134
|
+
* {@inheritDoc Collections.ResultMap.set}
|
|
91
135
|
*/
|
|
92
136
|
set(key, value) {
|
|
93
137
|
return this.converters.convertEntry([key, value]).onSuccess(([vk, vv]) => {
|
|
@@ -95,7 +139,7 @@ export class ResultMapValidator {
|
|
|
95
139
|
});
|
|
96
140
|
}
|
|
97
141
|
/**
|
|
98
|
-
* {@
|
|
142
|
+
* {@inheritDoc Collections.ResultMap.update}
|
|
99
143
|
*/
|
|
100
144
|
update(key, value) {
|
|
101
145
|
return this.converters.convertEntry([key, value]).onSuccess(([vk, vv]) => {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import { captureResult } from '../base';
|
|
23
|
+
import { ReadOnlyConvertingResultMap } from './readOnlyConvertingResultMap';
|
|
24
|
+
import { ConvertingResultMap } from './convertingResultMap';
|
|
25
|
+
import { ReadOnlyResultMapValidator } from './resultMapValidator';
|
|
26
|
+
/**
|
|
27
|
+
* A read-only result map that wraps an inner {@link Collections.IReadOnlyResultMap | IReadOnlyResultMap}
|
|
28
|
+
* of source type and returns lazily-converted, cached values of a target type, with a
|
|
29
|
+
* {@link Collections.ReadOnlyResultMapValidator | validating} property for weakly-typed access.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export class ValidatingReadOnlyConvertingResultMap extends ReadOnlyConvertingResultMap {
|
|
33
|
+
/**
|
|
34
|
+
* Constructs a new {@link Collections.ValidatingReadOnlyConvertingResultMap | ValidatingReadOnlyConvertingResultMap}.
|
|
35
|
+
* @param params - Parameters for constructing the map.
|
|
36
|
+
*/
|
|
37
|
+
constructor(params) {
|
|
38
|
+
super({ inner: params.inner, converter: params.converter });
|
|
39
|
+
this._converters = params.converters;
|
|
40
|
+
this.validating = new ReadOnlyResultMapValidator(this, params.converters);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new {@link Collections.ValidatingReadOnlyConvertingResultMap | ValidatingReadOnlyConvertingResultMap}.
|
|
44
|
+
* @param params - Parameters for constructing the map.
|
|
45
|
+
* @returns `Success` with the new map, or `Failure` with error details if an error occurred.
|
|
46
|
+
*/
|
|
47
|
+
static create(params) {
|
|
48
|
+
return captureResult(() => new ValidatingReadOnlyConvertingResultMap(params));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A result map that wraps an inner {@link Collections.IResultMap | IResultMap} of source type
|
|
53
|
+
* and returns lazily-converted, cached values of a target type, with a
|
|
54
|
+
* {@link Collections.ReadOnlyResultMapValidator | validating} property for weakly-typed access
|
|
55
|
+
* and a {@link Collections.CacheInvalidatingResultMapWrapper | source} property for mutable access
|
|
56
|
+
* to the underlying source map.
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
export class ValidatingConvertingResultMap extends ConvertingResultMap {
|
|
60
|
+
/**
|
|
61
|
+
* Constructs a new {@link Collections.ValidatingConvertingResultMap | ValidatingConvertingResultMap}.
|
|
62
|
+
* @param params - Parameters for constructing the map.
|
|
63
|
+
*/
|
|
64
|
+
constructor(params) {
|
|
65
|
+
super({ inner: params.inner, converter: params.converter });
|
|
66
|
+
this._converters = params.converters;
|
|
67
|
+
this.validating = new ReadOnlyResultMapValidator(this, params.converters);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Creates a new {@link Collections.ValidatingConvertingResultMap | ValidatingConvertingResultMap}.
|
|
71
|
+
* @param params - Parameters for constructing the map.
|
|
72
|
+
* @returns `Success` with the new map, or `Failure` with error details if an error occurred.
|
|
73
|
+
*/
|
|
74
|
+
static create(params) {
|
|
75
|
+
return captureResult(() => new ValidatingConvertingResultMap(params));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=validatingConvertingResultMap.js.map
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2020 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import { fail, isKeyOf, mapResults, succeed, Success } from '../base';
|
|
23
|
+
import { BaseConverter } from './baseConverter';
|
|
24
|
+
import { literal } from './basicConverters';
|
|
25
|
+
import { ObjectConverter } from './objectConverter';
|
|
26
|
+
/**
|
|
27
|
+
* Creates an {@link ObjectConverter | ObjectConverter} for a strongly-typed {@link Converters.ICompositeId | CompositeId}.
|
|
28
|
+
* @param collectionIdValidator - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
|
|
29
|
+
* @param separator - The separator string.
|
|
30
|
+
* @param itemIdValidator - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
|
|
31
|
+
* @returns An {@link ObjectConverter | ObjectConverter} for the strongly-typed composite ICompositeId.
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
export function compositeIdFromObject(collectionIdValidator, separator, itemIdValidator) {
|
|
35
|
+
return new ObjectConverter({
|
|
36
|
+
collectionId: collectionIdValidator,
|
|
37
|
+
separator: literal(separator).optional(),
|
|
38
|
+
itemId: itemIdValidator
|
|
39
|
+
}).map((obj) => {
|
|
40
|
+
var _a;
|
|
41
|
+
return Success.with({
|
|
42
|
+
collectionId: obj.collectionId,
|
|
43
|
+
separator: (_a = obj.separator) !== null && _a !== void 0 ? _a : separator,
|
|
44
|
+
itemId: obj.itemId
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Converts a composite ID string into a strongly-typed {@link Converters.ICompositeId | CompositeId}.
|
|
50
|
+
* @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
|
|
51
|
+
* @param separator - The separator string.
|
|
52
|
+
* @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
|
|
53
|
+
* @returns A {@link Converter | Converter} for the strongly-typed {@link Converters.ICompositeId | CompositeId}.
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
56
|
+
export function compositeIdFromString(collectionIdConverter, separator, itemIdConverter) {
|
|
57
|
+
return new BaseConverter((from, __self, context) => {
|
|
58
|
+
if (typeof from !== 'string') {
|
|
59
|
+
return fail(`${from}: invalid non-string composite ID.`);
|
|
60
|
+
}
|
|
61
|
+
const parts = from.split(separator);
|
|
62
|
+
if (parts.length < 2) {
|
|
63
|
+
return fail(`${from}: invalid composite ID - separator '${separator}' not found.`);
|
|
64
|
+
}
|
|
65
|
+
else if (parts.length > 2) {
|
|
66
|
+
return fail(`${from}: invalid composite ID - multiple separators '${separator}.' found.`);
|
|
67
|
+
}
|
|
68
|
+
return collectionIdConverter.convert(parts[0], context).onSuccess((collectionId) => {
|
|
69
|
+
return itemIdConverter.convert(parts[1], context).onSuccess((itemId) => {
|
|
70
|
+
return succeed({
|
|
71
|
+
collectionId,
|
|
72
|
+
separator,
|
|
73
|
+
itemId
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Creates a {@link Converter | Converter} for a strongly-typed {@link Converters.ICompositeId | CompositeId} from
|
|
81
|
+
* either a string or an object representation.
|
|
82
|
+
* @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
|
|
83
|
+
* @param separator - The separator string.
|
|
84
|
+
* @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
|
|
85
|
+
* @returns A {@link Converter | Converter} for the strongly-typed {@link Converters.ICompositeId | CompositeId}.
|
|
86
|
+
* @public
|
|
87
|
+
*/
|
|
88
|
+
export function compositeId(collectionIdConverter, separator, itemIdConverter) {
|
|
89
|
+
return compositeIdFromObject(collectionIdConverter, separator, itemIdConverter).or(compositeIdFromString(collectionIdConverter, separator, itemIdConverter));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Converts a strongly-typed {@link Converters.ICompositeId | CompositeId} into a string.
|
|
93
|
+
* @param compositeIdConverter - {@link Converter | Converter} or {@link Validator | Validator} that validates/converts the composite ID string.
|
|
94
|
+
* @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
|
|
95
|
+
* @param separator - The separator string.
|
|
96
|
+
* @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
|
|
97
|
+
* @returns A {@link Converter | Converter} which produces a composite ID string.
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
export function compositeIdString(compositeIdConverter, collectionIdConverter, separator, itemIdConverter) {
|
|
101
|
+
const objectConverter = compositeIdFromObject(collectionIdConverter, separator, itemIdConverter);
|
|
102
|
+
return new BaseConverter((from, __self, context) => {
|
|
103
|
+
if (typeof from === 'string') {
|
|
104
|
+
return compositeIdConverter.convert(from, context);
|
|
105
|
+
}
|
|
106
|
+
return objectConverter.convert(from, context).onSuccess((compositeId) => {
|
|
107
|
+
return compositeIdConverter.convert(`${compositeId.collectionId}${separator}${compositeId.itemId}`);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Helper to create a {@link Converter | Converter} which converts a source object to a new object with a
|
|
113
|
+
* different shape.
|
|
114
|
+
*
|
|
115
|
+
* @remarks
|
|
116
|
+
* On successful conversion, the resulting {@link Converter | Converter} returns {@link Success | Success} with a new
|
|
117
|
+
* object, which contains the converted values under the key names specified at initialization time.
|
|
118
|
+
* It returns {@link Failure | Failure} with an error message if any fields to be extracted do not exist
|
|
119
|
+
* or cannot be converted.
|
|
120
|
+
*
|
|
121
|
+
* Fields that succeed but convert to undefined are omitted from the result object but do not
|
|
122
|
+
* fail the conversion.
|
|
123
|
+
*
|
|
124
|
+
* @param properties - An object with key names that correspond to the target object and an
|
|
125
|
+
* appropriate {@link Conversion.FieldConverters | FieldConverter} which extracts and converts
|
|
126
|
+
* a single filed from the source object.
|
|
127
|
+
* @returns A {@link Converter | Converter} with the specified conversion behavior.
|
|
128
|
+
* @public
|
|
129
|
+
*/
|
|
130
|
+
export function transform(properties) {
|
|
131
|
+
return new BaseConverter((from, __self, context) => {
|
|
132
|
+
// eslint bug thinks key is used before defined
|
|
133
|
+
const converted = {};
|
|
134
|
+
const errors = [];
|
|
135
|
+
for (const key in properties) {
|
|
136
|
+
if (properties[key]) {
|
|
137
|
+
const result = properties[key].convert(from, context);
|
|
138
|
+
if (result.isSuccess() && result.value !== undefined) {
|
|
139
|
+
converted[key] = result.value;
|
|
140
|
+
}
|
|
141
|
+
else if (result.isFailure()) {
|
|
142
|
+
errors.push(result.message);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return errors.length === 0 ? succeed(converted) : fail(errors.join('\n'));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Helper to create a strongly-typed {@link Converter | Converter} which converts a source object to a
|
|
151
|
+
* new object with a different shape.
|
|
152
|
+
*
|
|
153
|
+
* @remarks
|
|
154
|
+
* On successful conversion, the resulting {@link Converter | Converter} returns {@link Success | Success} with a new
|
|
155
|
+
* object, which contains the converted values under the key names specified at initialization time.
|
|
156
|
+
*
|
|
157
|
+
* It returns {@link Failure | Failure} with an error message if any fields to be extracted do not exist
|
|
158
|
+
* or cannot be converted.
|
|
159
|
+
*
|
|
160
|
+
* @param destinationFields - An object with key names that correspond to the target object and an
|
|
161
|
+
* appropriate {@link Converters.FieldTransformers | FieldTransformers} which specifies the name
|
|
162
|
+
* of the corresponding property in the source object, the converter or validator used for each source
|
|
163
|
+
* property and any other configuration to guide the conversion.
|
|
164
|
+
* @param options - Options which affect the transformation.
|
|
165
|
+
*
|
|
166
|
+
* @returns A {@link Converter | Converter} with the specified conversion behavior.
|
|
167
|
+
* @public
|
|
168
|
+
*/
|
|
169
|
+
export function transformObject(destinationFields, options) {
|
|
170
|
+
return new BaseConverter((from, __self, context) => {
|
|
171
|
+
// eslint bug thinks key is used before defined
|
|
172
|
+
const converted = {};
|
|
173
|
+
const errors = [];
|
|
174
|
+
const used = new Set(options === null || options === void 0 ? void 0 : options.ignore);
|
|
175
|
+
if (typeof from === 'object' && !Array.isArray(from) && from !== null) {
|
|
176
|
+
for (const destinationKey in destinationFields) {
|
|
177
|
+
if (destinationFields[destinationKey]) {
|
|
178
|
+
const srcKey = destinationFields[destinationKey].from;
|
|
179
|
+
const converter = destinationFields[destinationKey].converter;
|
|
180
|
+
if (isKeyOf(srcKey, from)) {
|
|
181
|
+
const result = converter.convert(from[srcKey], context);
|
|
182
|
+
if (result.isSuccess() && result.value !== undefined) {
|
|
183
|
+
converted[destinationKey] = result.value;
|
|
184
|
+
}
|
|
185
|
+
else if (result.isFailure()) {
|
|
186
|
+
errors.push(`${srcKey}->${destinationKey}: ${result.message}`);
|
|
187
|
+
}
|
|
188
|
+
used.add(srcKey);
|
|
189
|
+
}
|
|
190
|
+
else if (destinationFields[destinationKey].optional !== true) {
|
|
191
|
+
errors.push(`${String(srcKey)}: required property missing in source object.`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if ((options === null || options === void 0 ? void 0 : options.strict) === true) {
|
|
196
|
+
for (const key in from) {
|
|
197
|
+
if (isKeyOf(key, from) && !used.has(key)) {
|
|
198
|
+
errors.push(`${key}: unexpected property in source object`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
errors.push('source is not an object');
|
|
205
|
+
}
|
|
206
|
+
return errors.length === 0
|
|
207
|
+
? succeed(converted)
|
|
208
|
+
: fail((options === null || options === void 0 ? void 0 : options.description) ? `${options.description}:\n ${errors.join('\n ')}` : errors.join('\n'));
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Creates a {@link Converter | Converter} that converts an array to a strongly-typed tuple,
|
|
213
|
+
* using the supplied tuple of {@link Converter | Converters} to convert each element.
|
|
214
|
+
*
|
|
215
|
+
* @remarks
|
|
216
|
+
* The resulting {@link Converter | Converter} returns {@link Success | Success} with a tuple
|
|
217
|
+
* containing the converted values if all conversions succeed. Returns {@link Failure | Failure}
|
|
218
|
+
* with an error message if the source is not an array, has the wrong number of elements, or
|
|
219
|
+
* any element conversion fails.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* const converter = tuple([Converters.string, Converters.number, Converters.boolean]);
|
|
224
|
+
* // Type is Converter<[string, number, boolean]>
|
|
225
|
+
*
|
|
226
|
+
* converter.convert(['hello', 42, true]);
|
|
227
|
+
* // Returns Success with ['hello', 42, true]
|
|
228
|
+
* ```
|
|
229
|
+
*
|
|
230
|
+
* @param converters - A tuple of {@link Converter | Converters} defining the expected types
|
|
231
|
+
* for each element of the tuple.
|
|
232
|
+
* @returns A {@link Converter | Converter} that returns a strongly-typed tuple.
|
|
233
|
+
* @public
|
|
234
|
+
*/
|
|
235
|
+
export function tuple(converters) {
|
|
236
|
+
return new BaseConverter((from, __self, context) => {
|
|
237
|
+
if (!Array.isArray(from)) {
|
|
238
|
+
return fail(`Not an array: ${JSON.stringify(from)}`);
|
|
239
|
+
}
|
|
240
|
+
if (from.length !== converters.length) {
|
|
241
|
+
return fail(`Expected array of length ${converters.length}, got ${from.length}: ${JSON.stringify(from)}`);
|
|
242
|
+
}
|
|
243
|
+
const results = converters.map((converter, index) => {
|
|
244
|
+
return converter.convert(from[index], context);
|
|
245
|
+
});
|
|
246
|
+
return mapResults(results);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=advancedConverters.js.map
|
|
@@ -44,25 +44,25 @@ export class BaseConverter {
|
|
|
44
44
|
this._brand = traits === null || traits === void 0 ? void 0 : traits.brand;
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
|
-
* {@
|
|
47
|
+
* {@inheritDoc Converter.isOptional}
|
|
48
48
|
*/
|
|
49
49
|
get isOptional() {
|
|
50
50
|
return this._isOptional;
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
* {@
|
|
53
|
+
* {@inheritDoc Converter.brand}
|
|
54
54
|
*/
|
|
55
55
|
get brand() {
|
|
56
56
|
return this._brand;
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* {@
|
|
59
|
+
* {@inheritDoc Converter.convert}
|
|
60
60
|
*/
|
|
61
61
|
convert(from, context) {
|
|
62
62
|
return this._converter(from, this, context !== null && context !== void 0 ? context : this._defaultContext);
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
* {@
|
|
65
|
+
* {@inheritDoc Converter.convertOptional}
|
|
66
66
|
*/
|
|
67
67
|
convertOptional(from, context, onError) {
|
|
68
68
|
const result = this._converter(from, this, this._context(context));
|
|
@@ -73,7 +73,7 @@ export class BaseConverter {
|
|
|
73
73
|
return result;
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
|
-
* {@
|
|
76
|
+
* {@inheritDoc Converter.optional}
|
|
77
77
|
*/
|
|
78
78
|
optional(onError) {
|
|
79
79
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -82,7 +82,7 @@ export class BaseConverter {
|
|
|
82
82
|
})._with(this._traits({ isOptional: true }));
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
|
-
* {@
|
|
85
|
+
* {@inheritDoc Converter.map}
|
|
86
86
|
*/
|
|
87
87
|
map(mapper) {
|
|
88
88
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -94,7 +94,7 @@ export class BaseConverter {
|
|
|
94
94
|
})._with(this._traits());
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
|
-
* {@
|
|
97
|
+
* {@inheritDoc Converter.mapConvert}
|
|
98
98
|
*/
|
|
99
99
|
mapConvert(mapConverter) {
|
|
100
100
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -106,7 +106,7 @@ export class BaseConverter {
|
|
|
106
106
|
})._with(this._traits());
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
109
|
-
* {@
|
|
109
|
+
* {@inheritDoc Converter.mapItems}
|
|
110
110
|
*/
|
|
111
111
|
mapItems(mapper) {
|
|
112
112
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -119,7 +119,7 @@ export class BaseConverter {
|
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
122
|
-
* {@
|
|
122
|
+
* {@inheritDoc Converter.mapConvertItems}
|
|
123
123
|
*/
|
|
124
124
|
mapConvertItems(mapConverter) {
|
|
125
125
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -132,7 +132,7 @@ export class BaseConverter {
|
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
|
-
* {@
|
|
135
|
+
* {@inheritDoc Converter.withAction}
|
|
136
136
|
*/
|
|
137
137
|
withAction(action) {
|
|
138
138
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -140,7 +140,7 @@ export class BaseConverter {
|
|
|
140
140
|
})._with(this._traits());
|
|
141
141
|
}
|
|
142
142
|
/**
|
|
143
|
-
* {@
|
|
143
|
+
* {@inheritDoc Converter.withTypeGuard}
|
|
144
144
|
*/
|
|
145
145
|
withTypeGuard(guard, message) {
|
|
146
146
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -153,7 +153,7 @@ export class BaseConverter {
|
|
|
153
153
|
})._with(this._traits());
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
|
-
* {@
|
|
156
|
+
* {@inheritDoc Converter.withItemTypeGuard}
|
|
157
157
|
*/
|
|
158
158
|
withItemTypeGuard(guard, message) {
|
|
159
159
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -171,7 +171,7 @@ export class BaseConverter {
|
|
|
171
171
|
})._with(this._traits());
|
|
172
172
|
}
|
|
173
173
|
/**
|
|
174
|
-
* {@
|
|
174
|
+
* {@inheritDoc Converter.withConstraint}
|
|
175
175
|
*/
|
|
176
176
|
withConstraint(constraint, options) {
|
|
177
177
|
return new BaseConverter((from, __self, context) => {
|
|
@@ -190,7 +190,7 @@ export class BaseConverter {
|
|
|
190
190
|
})._with(this._traits());
|
|
191
191
|
}
|
|
192
192
|
/**
|
|
193
|
-
* {@
|
|
193
|
+
* {@inheritDoc Converter.withBrand}
|
|
194
194
|
*/
|
|
195
195
|
withBrand(brand) {
|
|
196
196
|
if (this._brand) {
|
|
@@ -203,11 +203,18 @@ export class BaseConverter {
|
|
|
203
203
|
})._with(this._traits({ brand }));
|
|
204
204
|
}
|
|
205
205
|
/**
|
|
206
|
-
* {@
|
|
206
|
+
* {@inheritDoc Converter.withDefault}
|
|
207
207
|
*/
|
|
208
208
|
withDefault(defaultValue) {
|
|
209
209
|
return new GenericDefaultingConverter(this, defaultValue);
|
|
210
210
|
}
|
|
211
|
+
or(other) {
|
|
212
|
+
return new BaseConverter((from, __self, context) => {
|
|
213
|
+
return this._converter(from, this, this._context(context)).onFailure(() => {
|
|
214
|
+
return other.convert(from, this._context(context));
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
211
218
|
/**
|
|
212
219
|
* @internal
|
|
213
220
|
*/
|
|
@@ -215,7 +222,7 @@ export class BaseConverter {
|
|
|
215
222
|
return supplied !== null && supplied !== void 0 ? supplied : this._defaultContext;
|
|
216
223
|
}
|
|
217
224
|
/**
|
|
218
|
-
* {@
|
|
225
|
+
* {@inheritDoc Converter.withFormattedError}
|
|
219
226
|
*/
|
|
220
227
|
withFormattedError(formatter) {
|
|
221
228
|
return new BaseConverter((from, __self, context) => {
|