@fgv/ts-utils 5.0.2 → 5.1.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +152 -84
  2. package/dist/index.js +2 -2
  3. package/dist/packlets/base/messageAggregator.js +6 -6
  4. package/dist/packlets/base/result.js +39 -39
  5. package/dist/packlets/base/utils.js +47 -0
  6. package/dist/packlets/collections/aggregatedResultMap.js +722 -0
  7. package/dist/packlets/collections/collector.js +9 -9
  8. package/dist/packlets/collections/collectorValidator.js +4 -4
  9. package/dist/packlets/collections/converters.js +39 -0
  10. package/dist/packlets/collections/convertingCollectorValidator.js +3 -3
  11. package/dist/packlets/collections/convertingResultMap.js +208 -0
  12. package/dist/packlets/collections/index.js +4 -0
  13. package/dist/packlets/collections/keyValueConverters.js +1 -4
  14. package/dist/packlets/collections/readOnlyConvertingResultMap.js +193 -0
  15. package/dist/packlets/collections/resultMapValidator.js +50 -6
  16. package/dist/packlets/collections/validatingConvertingResultMap.js +78 -0
  17. package/dist/packlets/conversion/advancedConverters.js +249 -0
  18. package/dist/packlets/conversion/baseConverter.js +23 -16
  19. package/dist/packlets/conversion/basicConverters.js +571 -0
  20. package/dist/packlets/conversion/converters.js +3 -617
  21. package/dist/packlets/conversion/defaultingConverter.js +21 -15
  22. package/dist/packlets/logging/bootLogger.js +122 -0
  23. package/dist/packlets/logging/index.js +1 -0
  24. package/dist/packlets/logging/logReporter.js +32 -1
  25. package/dist/packlets/logging/logger.js +25 -5
  26. package/dist/packlets/validation/classes.js +1 -0
  27. package/dist/packlets/validation/compositeId.js +60 -0
  28. package/dist/packlets/validation/field.js +1 -1
  29. package/dist/packlets/validation/genericValidator.js +24 -10
  30. package/dist/packlets/validation/object.js +3 -6
  31. package/dist/packlets/validation/validators.js +12 -0
  32. package/dist/ts-utils.d.ts +1633 -200
  33. package/dist/tsdoc-metadata.json +1 -1
  34. package/lib/index.d.ts +2 -2
  35. package/lib/index.js +2 -1
  36. package/lib/packlets/base/mapResults.d.ts +3 -3
  37. package/lib/packlets/base/messageAggregator.d.ts +6 -6
  38. package/lib/packlets/base/messageAggregator.js +6 -6
  39. package/lib/packlets/base/result.d.ts +74 -51
  40. package/lib/packlets/base/result.js +39 -39
  41. package/lib/packlets/base/utils.d.ts +42 -0
  42. package/lib/packlets/base/utils.js +52 -0
  43. package/lib/packlets/collections/aggregatedResultMap.d.ts +433 -0
  44. package/lib/packlets/collections/aggregatedResultMap.js +728 -0
  45. package/lib/packlets/collections/collector.d.ts +11 -10
  46. package/lib/packlets/collections/collector.js +9 -9
  47. package/lib/packlets/collections/collectorValidator.d.ts +12 -10
  48. package/lib/packlets/collections/collectorValidator.js +4 -4
  49. package/lib/packlets/collections/converters.d.ts +18 -0
  50. package/lib/packlets/collections/converters.js +42 -0
  51. package/lib/packlets/collections/convertingCollector.d.ts +4 -4
  52. package/lib/packlets/collections/convertingCollectorValidator.d.ts +10 -7
  53. package/lib/packlets/collections/convertingCollectorValidator.js +3 -3
  54. package/lib/packlets/collections/convertingResultMap.d.ts +176 -0
  55. package/lib/packlets/collections/convertingResultMap.js +213 -0
  56. package/lib/packlets/collections/index.d.ts +4 -0
  57. package/lib/packlets/collections/index.js +4 -0
  58. package/lib/packlets/collections/keyValueConverters.d.ts +1 -4
  59. package/lib/packlets/collections/keyValueConverters.js +1 -4
  60. package/lib/packlets/collections/readOnlyConvertingResultMap.d.ts +153 -0
  61. package/lib/packlets/collections/readOnlyConvertingResultMap.js +197 -0
  62. package/lib/packlets/collections/readonlyResultMap.d.ts +7 -7
  63. package/lib/packlets/collections/resultMap.d.ts +108 -2
  64. package/lib/packlets/collections/resultMapValidator.d.ts +45 -11
  65. package/lib/packlets/collections/resultMapValidator.js +52 -7
  66. package/lib/packlets/collections/validatingCollector.d.ts +5 -5
  67. package/lib/packlets/collections/validatingConvertingCollector.d.ts +3 -3
  68. package/lib/packlets/collections/validatingConvertingResultMap.d.ts +102 -0
  69. package/lib/packlets/collections/validatingConvertingResultMap.js +83 -0
  70. package/lib/packlets/collections/validatingResultMap.d.ts +1 -1
  71. package/lib/packlets/conversion/advancedConverters.d.ts +170 -0
  72. package/lib/packlets/conversion/advancedConverters.js +258 -0
  73. package/lib/packlets/conversion/baseConverter.d.ts +39 -23
  74. package/lib/packlets/conversion/baseConverter.js +23 -16
  75. package/lib/packlets/conversion/basicConverters.d.ts +470 -0
  76. package/lib/packlets/conversion/basicConverters.js +595 -0
  77. package/lib/packlets/conversion/converter.d.ts +7 -0
  78. package/lib/packlets/conversion/converters.d.ts +2 -535
  79. package/lib/packlets/conversion/converters.js +17 -639
  80. package/lib/packlets/conversion/defaultingConverter.d.ts +20 -16
  81. package/lib/packlets/conversion/defaultingConverter.js +21 -15
  82. package/lib/packlets/logging/bootLogger.d.ts +84 -0
  83. package/lib/packlets/logging/bootLogger.js +126 -0
  84. package/lib/packlets/logging/index.d.ts +1 -0
  85. package/lib/packlets/logging/index.js +1 -0
  86. package/lib/packlets/logging/logReporter.d.ts +18 -3
  87. package/lib/packlets/logging/logReporter.js +31 -0
  88. package/lib/packlets/logging/logger.d.ts +39 -6
  89. package/lib/packlets/logging/logger.js +26 -5
  90. package/lib/packlets/validation/classes.d.ts +1 -0
  91. package/lib/packlets/validation/classes.js +3 -1
  92. package/lib/packlets/validation/compositeId.d.ts +29 -0
  93. package/lib/packlets/validation/compositeId.js +64 -0
  94. package/lib/packlets/validation/field.d.ts +1 -1
  95. package/lib/packlets/validation/field.js +1 -1
  96. package/lib/packlets/validation/genericValidator.d.ts +15 -11
  97. package/lib/packlets/validation/genericValidator.js +24 -10
  98. package/lib/packlets/validation/object.d.ts +3 -6
  99. package/lib/packlets/validation/object.js +3 -6
  100. package/lib/packlets/validation/traits.d.ts +3 -3
  101. package/lib/packlets/validation/validator.d.ts +7 -0
  102. package/lib/packlets/validation/validators.d.ts +10 -0
  103. package/lib/packlets/validation/validators.js +13 -0
  104. package/package.json +27 -27
@@ -0,0 +1,170 @@
1
+ import { Validator } from '../validation';
2
+ import { ConverterResultTypes } from './baseConverter';
3
+ import { Converter } from './converter';
4
+ import { FieldConverters } from './objectConverter';
5
+ /**
6
+ * Represents a composite ID constructed of two strongly-typed string IDs
7
+ * separated by a delimiter.
8
+ * @public
9
+ */
10
+ export interface ICompositeId<TCOLLECTIONID extends string, TITEMID extends string> {
11
+ readonly collectionId: TCOLLECTIONID;
12
+ readonly separator: string;
13
+ readonly itemId: TITEMID;
14
+ }
15
+ /**
16
+ * Represents a partial composite ID, where separator is optional.
17
+ * @public
18
+ */
19
+ export interface IPartialCompositeId<TCOLLECTIONID extends string, TITEMID extends string> {
20
+ readonly collectionId: TCOLLECTIONID;
21
+ readonly separator?: string;
22
+ readonly itemId: TITEMID;
23
+ }
24
+ /**
25
+ * Creates an {@link ObjectConverter | ObjectConverter} for a strongly-typed {@link Converters.ICompositeId | CompositeId}.
26
+ * @param collectionIdValidator - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
27
+ * @param separator - The separator string.
28
+ * @param itemIdValidator - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
29
+ * @returns An {@link ObjectConverter | ObjectConverter} for the strongly-typed composite ICompositeId.
30
+ * @public
31
+ */
32
+ export declare function compositeIdFromObject<TCOLLECTIONID extends string, TITEMID extends string, TC = unknown>(collectionIdValidator: Converter<TCOLLECTIONID, TC> | Validator<TCOLLECTIONID, TC>, separator: string, itemIdValidator: Converter<TITEMID, TC> | Validator<TITEMID, TC>): Converter<ICompositeId<TCOLLECTIONID, TITEMID>, TC>;
33
+ /**
34
+ * Converts a composite ID string into a strongly-typed {@link Converters.ICompositeId | CompositeId}.
35
+ * @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
36
+ * @param separator - The separator string.
37
+ * @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
38
+ * @returns A {@link Converter | Converter} for the strongly-typed {@link Converters.ICompositeId | CompositeId}.
39
+ * @public
40
+ */
41
+ export declare function compositeIdFromString<TCOLLECTIONID extends string, TITEMID extends string, TC = unknown>(collectionIdConverter: Converter<TCOLLECTIONID, TC> | Validator<TCOLLECTIONID, TC>, separator: string, itemIdConverter: Converter<TITEMID, TC> | Validator<TITEMID, TC>): Converter<ICompositeId<TCOLLECTIONID, TITEMID>, TC>;
42
+ /**
43
+ * Creates a {@link Converter | Converter} for a strongly-typed {@link Converters.ICompositeId | CompositeId} from
44
+ * either a string or an object representation.
45
+ * @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
46
+ * @param separator - The separator string.
47
+ * @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
48
+ * @returns A {@link Converter | Converter} for the strongly-typed {@link Converters.ICompositeId | CompositeId}.
49
+ * @public
50
+ */
51
+ export declare function compositeId<TCOLLECTIONID extends string, TITEMID extends string, TC = unknown>(collectionIdConverter: Converter<TCOLLECTIONID, TC> | Validator<TCOLLECTIONID, TC>, separator: string, itemIdConverter: Converter<TITEMID, TC> | Validator<TITEMID, TC>): Converter<ICompositeId<TCOLLECTIONID, TITEMID>, TC>;
52
+ /**
53
+ * Converts a strongly-typed {@link Converters.ICompositeId | CompositeId} into a string.
54
+ * @param compositeIdConverter - {@link Converter | Converter} or {@link Validator | Validator} that validates/converts the composite ID string.
55
+ * @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
56
+ * @param separator - The separator string.
57
+ * @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
58
+ * @returns A {@link Converter | Converter} which produces a composite ID string.
59
+ * @public
60
+ */
61
+ export declare function compositeIdString<T extends string, TCOLLECTIONID extends string, TITEMID extends string, TC = unknown>(compositeIdConverter: Validator<T, TC> | Converter<T, TC>, collectionIdConverter: Converter<TCOLLECTIONID, TC> | Validator<TCOLLECTIONID, TC>, separator: string, itemIdConverter: Converter<TITEMID, TC> | Validator<TITEMID, TC>): Converter<T, TC>;
62
+ /**
63
+ * Helper to create a {@link Converter | Converter} which converts a source object to a new object with a
64
+ * different shape.
65
+ *
66
+ * @remarks
67
+ * On successful conversion, the resulting {@link Converter | Converter} returns {@link Success | Success} with a new
68
+ * object, which contains the converted values under the key names specified at initialization time.
69
+ * It returns {@link Failure | Failure} with an error message if any fields to be extracted do not exist
70
+ * or cannot be converted.
71
+ *
72
+ * Fields that succeed but convert to undefined are omitted from the result object but do not
73
+ * fail the conversion.
74
+ *
75
+ * @param properties - An object with key names that correspond to the target object and an
76
+ * appropriate {@link Conversion.FieldConverters | FieldConverter} which extracts and converts
77
+ * a single filed from the source object.
78
+ * @returns A {@link Converter | Converter} with the specified conversion behavior.
79
+ * @public
80
+ */
81
+ export declare function transform<T, TC = unknown>(properties: FieldConverters<T, TC>): Converter<T, TC>;
82
+ /**
83
+ * Per-property converters and configuration for each field in the destination object of
84
+ * a {@link Converters.transformObject} call.
85
+ * @public
86
+ */
87
+ export type FieldTransformers<TSRC, TDEST, TC = unknown> = {
88
+ [key in keyof TDEST]: {
89
+ /**
90
+ * The name of the property in the source object to be converted.
91
+ */
92
+ from: keyof TSRC;
93
+ /**
94
+ * The converter or validator used to convert the property.
95
+ */
96
+ converter: Converter<TDEST[key], TC> | Validator<TDEST[key], TC>;
97
+ /**
98
+ * If `true` then a missing source property is ignored. If `false` or omitted
99
+ * then a missing source property causes an error.
100
+ */
101
+ optional?: boolean;
102
+ };
103
+ };
104
+ /**
105
+ * Options for a {@link Converters.transformObject} call.
106
+ * @public
107
+ */
108
+ export interface TransformObjectOptions<TSRC> {
109
+ /**
110
+ * If `strict` is `true` then unused properties in the source object cause
111
+ * an error, otherwise they are ignored.
112
+ */
113
+ strict: true;
114
+ /**
115
+ * An optional list of source properties to be ignored when strict mode
116
+ * is enabled.
117
+ */
118
+ ignore?: (keyof TSRC)[];
119
+ /**
120
+ * An optional description of this transform to be used for error messages.
121
+ */
122
+ description?: string;
123
+ }
124
+ /**
125
+ * Helper to create a strongly-typed {@link Converter | Converter} which converts a source object to a
126
+ * new object with a different shape.
127
+ *
128
+ * @remarks
129
+ * On successful conversion, the resulting {@link Converter | Converter} returns {@link Success | Success} with a new
130
+ * object, which contains the converted values under the key names specified at initialization time.
131
+ *
132
+ * It returns {@link Failure | Failure} with an error message if any fields to be extracted do not exist
133
+ * or cannot be converted.
134
+ *
135
+ * @param destinationFields - An object with key names that correspond to the target object and an
136
+ * appropriate {@link Converters.FieldTransformers | FieldTransformers} which specifies the name
137
+ * of the corresponding property in the source object, the converter or validator used for each source
138
+ * property and any other configuration to guide the conversion.
139
+ * @param options - Options which affect the transformation.
140
+ *
141
+ * @returns A {@link Converter | Converter} with the specified conversion behavior.
142
+ * @public
143
+ */
144
+ export declare function transformObject<TSRC, TDEST, TC = unknown>(destinationFields: FieldTransformers<TSRC, TDEST, TC>, options?: TransformObjectOptions<TSRC>): Converter<TDEST, TC>;
145
+ /**
146
+ * Creates a {@link Converter | Converter} that converts an array to a strongly-typed tuple,
147
+ * using the supplied tuple of {@link Converter | Converters} to convert each element.
148
+ *
149
+ * @remarks
150
+ * The resulting {@link Converter | Converter} returns {@link Success | Success} with a tuple
151
+ * containing the converted values if all conversions succeed. Returns {@link Failure | Failure}
152
+ * with an error message if the source is not an array, has the wrong number of elements, or
153
+ * any element conversion fails.
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * const converter = tuple([Converters.string, Converters.number, Converters.boolean]);
158
+ * // Type is Converter<[string, number, boolean]>
159
+ *
160
+ * converter.convert(['hello', 42, true]);
161
+ * // Returns Success with ['hello', 42, true]
162
+ * ```
163
+ *
164
+ * @param converters - A tuple of {@link Converter | Converters} defining the expected types
165
+ * for each element of the tuple.
166
+ * @returns A {@link Converter | Converter} that returns a strongly-typed tuple.
167
+ * @public
168
+ */
169
+ export declare function tuple<T extends readonly Converter<unknown, TC>[], TC = unknown>(converters: [...T]): Converter<ConverterResultTypes<T>, TC>;
170
+ //# sourceMappingURL=advancedConverters.d.ts.map
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2020 Erik Fortune
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ * of this software and associated documentation files (the "Software"), to deal
7
+ * in the Software without restriction, including without limitation the rights
8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ * copies of the Software, and to permit persons to whom the Software is
10
+ * furnished to do so, subject to the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be included in all
13
+ * copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ * SOFTWARE.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.compositeIdFromObject = compositeIdFromObject;
25
+ exports.compositeIdFromString = compositeIdFromString;
26
+ exports.compositeId = compositeId;
27
+ exports.compositeIdString = compositeIdString;
28
+ exports.transform = transform;
29
+ exports.transformObject = transformObject;
30
+ exports.tuple = tuple;
31
+ const base_1 = require("../base");
32
+ const baseConverter_1 = require("./baseConverter");
33
+ const basicConverters_1 = require("./basicConverters");
34
+ const objectConverter_1 = require("./objectConverter");
35
+ /**
36
+ * Creates an {@link ObjectConverter | ObjectConverter} for a strongly-typed {@link Converters.ICompositeId | CompositeId}.
37
+ * @param collectionIdValidator - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
38
+ * @param separator - The separator string.
39
+ * @param itemIdValidator - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
40
+ * @returns An {@link ObjectConverter | ObjectConverter} for the strongly-typed composite ICompositeId.
41
+ * @public
42
+ */
43
+ function compositeIdFromObject(collectionIdValidator, separator, itemIdValidator) {
44
+ return new objectConverter_1.ObjectConverter({
45
+ collectionId: collectionIdValidator,
46
+ separator: (0, basicConverters_1.literal)(separator).optional(),
47
+ itemId: itemIdValidator
48
+ }).map((obj) => {
49
+ var _a;
50
+ return base_1.Success.with({
51
+ collectionId: obj.collectionId,
52
+ separator: (_a = obj.separator) !== null && _a !== void 0 ? _a : separator,
53
+ itemId: obj.itemId
54
+ });
55
+ });
56
+ }
57
+ /**
58
+ * Converts a composite ID string into a strongly-typed {@link Converters.ICompositeId | CompositeId}.
59
+ * @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
60
+ * @param separator - The separator string.
61
+ * @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
62
+ * @returns A {@link Converter | Converter} for the strongly-typed {@link Converters.ICompositeId | CompositeId}.
63
+ * @public
64
+ */
65
+ function compositeIdFromString(collectionIdConverter, separator, itemIdConverter) {
66
+ return new baseConverter_1.BaseConverter((from, __self, context) => {
67
+ if (typeof from !== 'string') {
68
+ return (0, base_1.fail)(`${from}: invalid non-string composite ID.`);
69
+ }
70
+ const parts = from.split(separator);
71
+ if (parts.length < 2) {
72
+ return (0, base_1.fail)(`${from}: invalid composite ID - separator '${separator}' not found.`);
73
+ }
74
+ else if (parts.length > 2) {
75
+ return (0, base_1.fail)(`${from}: invalid composite ID - multiple separators '${separator}.' found.`);
76
+ }
77
+ return collectionIdConverter.convert(parts[0], context).onSuccess((collectionId) => {
78
+ return itemIdConverter.convert(parts[1], context).onSuccess((itemId) => {
79
+ return (0, base_1.succeed)({
80
+ collectionId,
81
+ separator,
82
+ itemId
83
+ });
84
+ });
85
+ });
86
+ });
87
+ }
88
+ /**
89
+ * Creates a {@link Converter | Converter} for a strongly-typed {@link Converters.ICompositeId | CompositeId} from
90
+ * either a string or an object representation.
91
+ * @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
92
+ * @param separator - The separator string.
93
+ * @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
94
+ * @returns A {@link Converter | Converter} for the strongly-typed {@link Converters.ICompositeId | CompositeId}.
95
+ * @public
96
+ */
97
+ function compositeId(collectionIdConverter, separator, itemIdConverter) {
98
+ return compositeIdFromObject(collectionIdConverter, separator, itemIdConverter).or(compositeIdFromString(collectionIdConverter, separator, itemIdConverter));
99
+ }
100
+ /**
101
+ * Converts a strongly-typed {@link Converters.ICompositeId | CompositeId} into a string.
102
+ * @param compositeIdConverter - {@link Converter | Converter} or {@link Validator | Validator} that validates/converts the composite ID string.
103
+ * @param collectionIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the collection ID portion.
104
+ * @param separator - The separator string.
105
+ * @param itemIdConverter - {@link Converter | Converter} or {@link Validator | Validator} for the item ID portion.
106
+ * @returns A {@link Converter | Converter} which produces a composite ID string.
107
+ * @public
108
+ */
109
+ function compositeIdString(compositeIdConverter, collectionIdConverter, separator, itemIdConverter) {
110
+ const objectConverter = compositeIdFromObject(collectionIdConverter, separator, itemIdConverter);
111
+ return new baseConverter_1.BaseConverter((from, __self, context) => {
112
+ if (typeof from === 'string') {
113
+ return compositeIdConverter.convert(from, context);
114
+ }
115
+ return objectConverter.convert(from, context).onSuccess((compositeId) => {
116
+ return compositeIdConverter.convert(`${compositeId.collectionId}${separator}${compositeId.itemId}`);
117
+ });
118
+ });
119
+ }
120
+ /**
121
+ * Helper to create a {@link Converter | Converter} which converts a source object to a new object with a
122
+ * different shape.
123
+ *
124
+ * @remarks
125
+ * On successful conversion, the resulting {@link Converter | Converter} returns {@link Success | Success} with a new
126
+ * object, which contains the converted values under the key names specified at initialization time.
127
+ * It returns {@link Failure | Failure} with an error message if any fields to be extracted do not exist
128
+ * or cannot be converted.
129
+ *
130
+ * Fields that succeed but convert to undefined are omitted from the result object but do not
131
+ * fail the conversion.
132
+ *
133
+ * @param properties - An object with key names that correspond to the target object and an
134
+ * appropriate {@link Conversion.FieldConverters | FieldConverter} which extracts and converts
135
+ * a single filed from the source object.
136
+ * @returns A {@link Converter | Converter} with the specified conversion behavior.
137
+ * @public
138
+ */
139
+ function transform(properties) {
140
+ return new baseConverter_1.BaseConverter((from, __self, context) => {
141
+ // eslint bug thinks key is used before defined
142
+ const converted = {};
143
+ const errors = [];
144
+ for (const key in properties) {
145
+ if (properties[key]) {
146
+ const result = properties[key].convert(from, context);
147
+ if (result.isSuccess() && result.value !== undefined) {
148
+ converted[key] = result.value;
149
+ }
150
+ else if (result.isFailure()) {
151
+ errors.push(result.message);
152
+ }
153
+ }
154
+ }
155
+ return errors.length === 0 ? (0, base_1.succeed)(converted) : (0, base_1.fail)(errors.join('\n'));
156
+ });
157
+ }
158
+ /**
159
+ * Helper to create a strongly-typed {@link Converter | Converter} which converts a source object to a
160
+ * new object with a different shape.
161
+ *
162
+ * @remarks
163
+ * On successful conversion, the resulting {@link Converter | Converter} returns {@link Success | Success} with a new
164
+ * object, which contains the converted values under the key names specified at initialization time.
165
+ *
166
+ * It returns {@link Failure | Failure} with an error message if any fields to be extracted do not exist
167
+ * or cannot be converted.
168
+ *
169
+ * @param destinationFields - An object with key names that correspond to the target object and an
170
+ * appropriate {@link Converters.FieldTransformers | FieldTransformers} which specifies the name
171
+ * of the corresponding property in the source object, the converter or validator used for each source
172
+ * property and any other configuration to guide the conversion.
173
+ * @param options - Options which affect the transformation.
174
+ *
175
+ * @returns A {@link Converter | Converter} with the specified conversion behavior.
176
+ * @public
177
+ */
178
+ function transformObject(destinationFields, options) {
179
+ return new baseConverter_1.BaseConverter((from, __self, context) => {
180
+ // eslint bug thinks key is used before defined
181
+ const converted = {};
182
+ const errors = [];
183
+ const used = new Set(options === null || options === void 0 ? void 0 : options.ignore);
184
+ if (typeof from === 'object' && !Array.isArray(from) && from !== null) {
185
+ for (const destinationKey in destinationFields) {
186
+ if (destinationFields[destinationKey]) {
187
+ const srcKey = destinationFields[destinationKey].from;
188
+ const converter = destinationFields[destinationKey].converter;
189
+ if ((0, base_1.isKeyOf)(srcKey, from)) {
190
+ const result = converter.convert(from[srcKey], context);
191
+ if (result.isSuccess() && result.value !== undefined) {
192
+ converted[destinationKey] = result.value;
193
+ }
194
+ else if (result.isFailure()) {
195
+ errors.push(`${srcKey}->${destinationKey}: ${result.message}`);
196
+ }
197
+ used.add(srcKey);
198
+ }
199
+ else if (destinationFields[destinationKey].optional !== true) {
200
+ errors.push(`${String(srcKey)}: required property missing in source object.`);
201
+ }
202
+ }
203
+ }
204
+ if ((options === null || options === void 0 ? void 0 : options.strict) === true) {
205
+ for (const key in from) {
206
+ if ((0, base_1.isKeyOf)(key, from) && !used.has(key)) {
207
+ errors.push(`${key}: unexpected property in source object`);
208
+ }
209
+ }
210
+ }
211
+ }
212
+ else {
213
+ errors.push('source is not an object');
214
+ }
215
+ return errors.length === 0
216
+ ? (0, base_1.succeed)(converted)
217
+ : (0, base_1.fail)((options === null || options === void 0 ? void 0 : options.description) ? `${options.description}:\n ${errors.join('\n ')}` : errors.join('\n'));
218
+ });
219
+ }
220
+ /**
221
+ * Creates a {@link Converter | Converter} that converts an array to a strongly-typed tuple,
222
+ * using the supplied tuple of {@link Converter | Converters} to convert each element.
223
+ *
224
+ * @remarks
225
+ * The resulting {@link Converter | Converter} returns {@link Success | Success} with a tuple
226
+ * containing the converted values if all conversions succeed. Returns {@link Failure | Failure}
227
+ * with an error message if the source is not an array, has the wrong number of elements, or
228
+ * any element conversion fails.
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * const converter = tuple([Converters.string, Converters.number, Converters.boolean]);
233
+ * // Type is Converter<[string, number, boolean]>
234
+ *
235
+ * converter.convert(['hello', 42, true]);
236
+ * // Returns Success with ['hello', 42, true]
237
+ * ```
238
+ *
239
+ * @param converters - A tuple of {@link Converter | Converters} defining the expected types
240
+ * for each element of the tuple.
241
+ * @returns A {@link Converter | Converter} that returns a strongly-typed tuple.
242
+ * @public
243
+ */
244
+ function tuple(converters) {
245
+ return new baseConverter_1.BaseConverter((from, __self, context) => {
246
+ if (!Array.isArray(from)) {
247
+ return (0, base_1.fail)(`Not an array: ${JSON.stringify(from)}`);
248
+ }
249
+ if (from.length !== converters.length) {
250
+ return (0, base_1.fail)(`Expected array of length ${converters.length}, got ${from.length}: ${JSON.stringify(from)}`);
251
+ }
252
+ const results = converters.map((converter, index) => {
253
+ return converter.convert(from[index], context);
254
+ });
255
+ return (0, base_1.mapResults)(results);
256
+ });
257
+ }
258
+ //# sourceMappingURL=advancedConverters.js.map
@@ -1,22 +1,37 @@
1
1
  import { Brand, Result } from '../base';
2
2
  import { ConstraintOptions, ConversionErrorFormatter, Converter, ConverterTraits, DefaultingConverter, OnError } from './converter';
3
3
  /**
4
- * internal
4
+ * Internal helper that recursively unwraps converter and array types.
5
+ * @internal
5
6
  */
6
7
  type InnerInferredType<TCONV> = TCONV extends Converter<infer TTO> ? TTO extends Array<infer TTOELEM> ? InnerInferredType<TTOELEM>[] : TTO : TCONV extends Array<infer TELEM> ? InnerInferredType<TELEM>[] : TCONV;
7
8
  /**
8
- * Infers the type that will be returned by an instantiated converter. Works
9
- * for complex as well as simple types.
9
+ * Infers the type that will be returned by an instantiated converter. Works
10
+ * for complex as well as simple types, including nested arrays.
10
11
  * @example `Infer<typeof Converters.mapOf(Converters.stringArray)>` is `Map<string, string[]>`
11
- * @beta
12
+ * @public
12
13
  */
13
14
  export type Infer<TCONV> = TCONV extends Converter<infer TTO, unknown> ? InnerInferredType<TTO> : never;
14
15
  /**
15
- * Deprecated name for Infer<T> retained for compatibility
16
- * @deprecated use @see Infer instead
17
- * @internal
16
+ * Deprecated name for {@link Conversion.Infer | Infer
17
+ * } retained for compatibility.
18
+ * @deprecated Use {@link Conversion.Infer | Infer} instead.
19
+ * @public
18
20
  */
19
21
  export type ConvertedToType<TCONV> = Infer<TCONV>;
22
+ /**
23
+ * Helper type to extract the result type from a {@link Converter | Converter}.
24
+ * For simple single-level extraction. For complex nested types, use {@link Conversion.Infer | Infer}.
25
+ * @public
26
+ */
27
+ export type ConverterResultType<C> = C extends Converter<infer T, unknown> ? T : never;
28
+ /**
29
+ * Helper type to map a tuple of {@link Converter | Converters} to a tuple of their result types.
30
+ * @public
31
+ */
32
+ export type ConverterResultTypes<T extends readonly Converter<unknown, unknown>[]> = {
33
+ [K in keyof T]: T[K] extends Converter<infer R, unknown> ? R : never;
34
+ };
20
35
  /**
21
36
  * Function signature for a converter function.
22
37
  * @public
@@ -49,71 +64,72 @@ export declare class BaseConverter<T, TC = unknown> implements Converter<T, TC>
49
64
  */
50
65
  constructor(converter: ConverterFunc<T, TC>, defaultContext?: TC, traits?: ConverterTraits);
51
66
  /**
52
- * {@inheritdoc Converter.isOptional}
67
+ * {@inheritDoc Converter.isOptional}
53
68
  */
54
69
  get isOptional(): boolean;
55
70
  /**
56
- * {@inheritdoc Converter.brand}
71
+ * {@inheritDoc Converter.brand}
57
72
  */
58
73
  get brand(): string | undefined;
59
74
  /**
60
- * {@inheritdoc Converter.convert}
75
+ * {@inheritDoc Converter.convert}
61
76
  */
62
77
  convert(from: unknown, context?: TC): Result<T>;
63
78
  /**
64
- * {@inheritdoc Converter.convertOptional}
79
+ * {@inheritDoc Converter.convertOptional}
65
80
  */
66
81
  convertOptional(from: unknown, context?: TC, onError?: OnError): Result<T | undefined>;
67
82
  /**
68
- * {@inheritdoc Converter.optional}
83
+ * {@inheritDoc Converter.optional}
69
84
  */
70
85
  optional(onError?: OnError): Converter<T | undefined, TC>;
71
86
  /**
72
- * {@inheritdoc Converter.map}
87
+ * {@inheritDoc Converter.map}
73
88
  */
74
89
  map<T2>(mapper: (from: T, context?: TC) => Result<T2>): Converter<T2, TC>;
75
90
  /**
76
- * {@inheritdoc Converter.mapConvert}
91
+ * {@inheritDoc Converter.mapConvert}
77
92
  */
78
93
  mapConvert<T2>(mapConverter: Converter<T2>): Converter<T2, TC>;
79
94
  /**
80
- * {@inheritdoc Converter.mapItems}
95
+ * {@inheritDoc Converter.mapItems}
81
96
  */
82
97
  mapItems<TI>(mapper: (from: unknown, context?: TC) => Result<TI>): Converter<TI[], TC>;
83
98
  /**
84
- * {@inheritdoc Converter.mapConvertItems}
99
+ * {@inheritDoc Converter.mapConvertItems}
85
100
  */
86
101
  mapConvertItems<TI>(mapConverter: Converter<TI, unknown>): Converter<TI[], TC>;
87
102
  /**
88
- * {@inheritdoc Converter.withAction}
103
+ * {@inheritDoc Converter.withAction}
89
104
  */
90
105
  withAction<TI>(action: (result: Result<T>, context?: TC) => Result<TI>): Converter<TI, TC>;
91
106
  /**
92
- * {@inheritdoc Converter.withTypeGuard}
107
+ * {@inheritDoc Converter.withTypeGuard}
93
108
  */
94
109
  withTypeGuard<TI>(guard: (from: unknown, context?: TC) => from is TI, message?: string): Converter<TI, TC>;
95
110
  /**
96
- * {@inheritdoc Converter.withItemTypeGuard}
111
+ * {@inheritDoc Converter.withItemTypeGuard}
97
112
  */
98
113
  withItemTypeGuard<TI>(guard: (from: unknown, context?: TC) => from is TI, message?: string): Converter<TI[], TC>;
99
114
  /**
100
- * {@inheritdoc Converter.withConstraint}
115
+ * {@inheritDoc Converter.withConstraint}
101
116
  */
102
117
  withConstraint(constraint: (val: T, context?: TC) => boolean | Result<T>, options?: ConstraintOptions): Converter<T, TC>;
103
118
  /**
104
- * {@inheritdoc Converter.withBrand}
119
+ * {@inheritDoc Converter.withBrand}
105
120
  */
106
121
  withBrand<B extends string>(brand: B): Converter<Brand<T, B>, TC>;
107
122
  /**
108
- * {@inheritdoc Converter.withDefault}
123
+ * {@inheritDoc Converter.withDefault}
109
124
  */
110
125
  withDefault<TD = T>(defaultValue: TD): DefaultingConverter<T, TD, TC>;
126
+ or(other: Converter<T, TC>): Converter<T, TC>;
111
127
  /**
112
128
  * @internal
113
129
  */
114
130
  protected _context(supplied?: TC): TC | undefined;
115
131
  /**
116
- * {@inheritdoc Converter.withFormattedError}
132
+ * {@inheritDoc Converter.withFormattedError}
117
133
  */
118
134
  withFormattedError(formatter: ConversionErrorFormatter<TC>): Converter<T, TC>;
119
135
  /**