@fgv/ts-utils 5.0.2 → 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.
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 +14 -14
@@ -31,7 +31,7 @@ import { captureResult, failWithDetail, fail, succeed, succeedWithDetail } from
31
31
  */
32
32
  export class Collector {
33
33
  /**
34
- * {@inheritdoc Collections.ResultMap.size}
34
+ * {@inheritDoc Collections.ResultMap.size}
35
35
  */
36
36
  get size() {
37
37
  return this._byIndex.length;
@@ -87,13 +87,13 @@ export class Collector {
87
87
  return succeedWithDetail(item, 'added');
88
88
  }
89
89
  /**
90
- * {@inheritdoc Collections.ResultMap.entries}
90
+ * {@inheritDoc Collections.ResultMap.entries}
91
91
  */
92
92
  entries() {
93
93
  return this._byKey.entries();
94
94
  }
95
95
  /**
96
- * {@inheritdoc Collections.ResultMap.forEach}
96
+ * {@inheritDoc Collections.ResultMap.forEach}
97
97
  */
98
98
  forEach(callback, arg) {
99
99
  for (const [key, value] of this._byKey.entries()) {
@@ -101,14 +101,14 @@ export class Collector {
101
101
  }
102
102
  }
103
103
  /**
104
- * {@inheritdoc Collections.ResultMap.get}
104
+ * {@inheritDoc Collections.ResultMap.get}
105
105
  */
106
106
  get(key) {
107
107
  const item = this._byKey.get(key);
108
108
  return item ? succeedWithDetail(item, 'exists') : failWithDetail(`${key}: not found`, 'not-found');
109
109
  }
110
110
  /**
111
- * {@inheritdoc Collections.IReadOnlyCollector.getAt}
111
+ * {@inheritDoc Collections.IReadOnlyCollector.getAt}
112
112
  */
113
113
  getAt(index) {
114
114
  if (typeof index !== 'number') {
@@ -146,25 +146,25 @@ export class Collector {
146
146
  });
147
147
  }
148
148
  /**
149
- * {@inheritdoc Collections.ResultMap.has}
149
+ * {@inheritDoc Collections.ResultMap.has}
150
150
  */
151
151
  has(key) {
152
152
  return this._byKey.has(key);
153
153
  }
154
154
  /**
155
- * {@inheritdoc Collections.ResultMap.keys}
155
+ * {@inheritDoc Collections.ResultMap.keys}
156
156
  */
157
157
  keys() {
158
158
  return this._byKey.keys();
159
159
  }
160
160
  /**
161
- * {@inheritdoc Collections.ResultMap.values}
161
+ * {@inheritDoc Collections.ResultMap.values}
162
162
  */
163
163
  values() {
164
164
  return this._byKey.values();
165
165
  }
166
166
  /**
167
- * {@inheritdoc Collections.IReadOnlyCollector.valuesByIndex}
167
+ * {@inheritDoc Collections.IReadOnlyCollector.valuesByIndex}
168
168
  */
169
169
  valuesByIndex() {
170
170
  return this._byIndex;
@@ -37,7 +37,7 @@ export class CollectorValidator {
37
37
  this.converters = params.converters;
38
38
  }
39
39
  /**
40
- * {@inheritdoc Collections.Collector.add}
40
+ * {@inheritDoc Collections.Collector.add}
41
41
  */
42
42
  add(item) {
43
43
  return this._convertValue(item).onSuccess((i) => {
@@ -45,7 +45,7 @@ export class CollectorValidator {
45
45
  });
46
46
  }
47
47
  /**
48
- * {@inheritdoc Collections.Collector.get}
48
+ * {@inheritDoc Collections.Collector.get}
49
49
  */
50
50
  get(key) {
51
51
  return this.converters.convertKey(key).onSuccess((k) => {
@@ -64,13 +64,13 @@ export class CollectorValidator {
64
64
  }
65
65
  }
66
66
  /**
67
- * {@inheritdoc Collections.ResultMap.has}
67
+ * {@inheritDoc Collections.ResultMap.has}
68
68
  */
69
69
  has(key) {
70
70
  return this._collector.has(key);
71
71
  }
72
72
  /**
73
- * {@inheritdoc Collections.Collector.toReadOnly}
73
+ * {@inheritDoc Collections.Collector.toReadOnly}
74
74
  */
75
75
  toReadOnly() {
76
76
  return this;
@@ -0,0 +1,39 @@
1
+ /*
2
+ * Copyright (c) 2026 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 { Success } from '../base';
23
+ import { Converters } from '../conversion';
24
+ /**
25
+ * A {@link Converter | Converter} for {@link Collections.KeyValueEntry | KeyValueEntry} instances.
26
+ * @param params - Conversion parameters.
27
+ * @returns A converter for which validates key value entries using the supplied validators.
28
+ * @public
29
+ */
30
+ export function keyValueEntry(params) {
31
+ return Converters.generic((from) => {
32
+ return params.key.convert(from).onSuccess((key) => {
33
+ return params.value.convert(from).onSuccess((value) => {
34
+ return Success.with([key, value]);
35
+ });
36
+ });
37
+ });
38
+ }
39
+ //# sourceMappingURL=converters.js.map
@@ -45,7 +45,7 @@ export class ConvertingCollectorValidator {
45
45
  return this.getOrAdd(key, valueOrFactory);
46
46
  }
47
47
  /**
48
- * {@inheritdoc Collections.Collector.get}
48
+ * {@inheritDoc Collections.Collector.get}
49
49
  */
50
50
  get(key) {
51
51
  return this.converters.convertKey(key).onSuccess((k) => {
@@ -70,13 +70,13 @@ export class ConvertingCollectorValidator {
70
70
  }
71
71
  }
72
72
  /**
73
- * {@inheritdoc Collections.ResultMap.has}
73
+ * {@inheritDoc Collections.ResultMap.has}
74
74
  */
75
75
  has(key) {
76
76
  return this._collector.has(key);
77
77
  }
78
78
  /**
79
- * {@inheritdoc Collections.Collector.toReadOnly}
79
+ * {@inheritDoc Collections.Collector.toReadOnly}
80
80
  */
81
81
  toReadOnly() {
82
82
  return this;
@@ -0,0 +1,208 @@
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
+ /**
25
+ * A wrapper around a mutable result map that invalidates cache entries
26
+ * in the parent {@link Collections.ConvertingResultMap | ConvertingResultMap} when mutations occur.
27
+ * @public
28
+ */
29
+ export class CacheInvalidatingResultMapWrapper {
30
+ /**
31
+ * Constructs a new cache-invalidating wrapper.
32
+ * @param inner - The inner map to wrap.
33
+ * @param parent - The parent converting map whose cache should be invalidated.
34
+ */
35
+ constructor(inner, parent) {
36
+ this._inner = inner;
37
+ this._parent = parent;
38
+ }
39
+ /**
40
+ * The number of entries in the map.
41
+ */
42
+ get size() {
43
+ return this._inner.size;
44
+ }
45
+ /**
46
+ * Adds a key/value pair to the map if the key does not already exist.
47
+ * Invalidates the cache entry for the key.
48
+ * @param key - The key to add.
49
+ * @param value - The value to add.
50
+ * @returns The result of the add operation.
51
+ */
52
+ add(key, value) {
53
+ this._parent._clearCacheEntry(key);
54
+ return this._inner.add(key, value);
55
+ }
56
+ /**
57
+ * Sets a key/value pair in the map.
58
+ * Invalidates the cache entry for the key.
59
+ * @param key - The key to set.
60
+ * @param value - The value to set.
61
+ * @returns The result of the set operation.
62
+ */
63
+ set(key, value) {
64
+ this._parent._clearCacheEntry(key);
65
+ return this._inner.set(key, value);
66
+ }
67
+ /**
68
+ * Updates an existing key in the map.
69
+ * Invalidates the cache entry for the key.
70
+ * @param key - The key to update.
71
+ * @param value - The new value.
72
+ * @returns The result of the update operation.
73
+ */
74
+ update(key, value) {
75
+ this._parent._clearCacheEntry(key);
76
+ return this._inner.update(key, value);
77
+ }
78
+ /**
79
+ * Deletes a key from the map.
80
+ * Invalidates the cache entry for the key.
81
+ * @param key - The key to delete.
82
+ * @returns The result of the delete operation.
83
+ */
84
+ delete(key) {
85
+ this._parent._clearCacheEntry(key);
86
+ return this._inner.delete(key);
87
+ }
88
+ /**
89
+ * Gets a value from the map.
90
+ * @param key - The key to retrieve.
91
+ * @returns The result of the get operation.
92
+ */
93
+ get(key) {
94
+ return this._inner.get(key);
95
+ }
96
+ getOrAdd(key, valueOrFactory) {
97
+ const result = typeof valueOrFactory === 'function'
98
+ ? this._inner.getOrAdd(key, valueOrFactory)
99
+ : this._inner.getOrAdd(key, valueOrFactory);
100
+ if (result.isSuccess() && result.detail === 'added') {
101
+ this._parent._clearCacheEntry(key);
102
+ }
103
+ return result;
104
+ }
105
+ /**
106
+ * Checks if the map contains a key.
107
+ * @param key - The key to check.
108
+ * @returns `true` if the key exists, `false` otherwise.
109
+ */
110
+ has(key) {
111
+ return this._inner.has(key);
112
+ }
113
+ /**
114
+ * Clears all entries from the map.
115
+ * Clears the entire cache.
116
+ */
117
+ clear() {
118
+ this._parent._clearCache();
119
+ this._inner.clear();
120
+ }
121
+ /**
122
+ * Returns an iterator over the map entries.
123
+ * @returns An iterator over the map entries.
124
+ */
125
+ entries() {
126
+ return this._inner.entries();
127
+ }
128
+ /**
129
+ * Returns an iterator over the map keys.
130
+ * @returns An iterator over the map keys.
131
+ */
132
+ keys() {
133
+ return this._inner.keys();
134
+ }
135
+ /**
136
+ * Returns an iterator over the map values.
137
+ * @returns An iterator over the map values.
138
+ */
139
+ values() {
140
+ return this._inner.values();
141
+ }
142
+ /**
143
+ * Calls a callback for each entry in the map.
144
+ * @param cb - The callback to call for each entry.
145
+ * @param thisArg - Optional `this` argument for the callback.
146
+ */
147
+ forEach(cb, thisArg) {
148
+ this._inner.forEach(cb, thisArg);
149
+ }
150
+ /**
151
+ * Gets an iterator over the map entries.
152
+ * @returns An iterator over the map entries.
153
+ */
154
+ [Symbol.iterator]() {
155
+ return this._inner[Symbol.iterator]();
156
+ }
157
+ /**
158
+ * Gets a read-only version of this map.
159
+ * @returns A read-only version of this map.
160
+ */
161
+ toReadOnly() {
162
+ return this._inner.toReadOnly();
163
+ }
164
+ }
165
+ /**
166
+ * A result map that wraps an inner {@link Collections.IResultMap | IResultMap} of source type
167
+ * and returns lazily-converted, cached values of a target type. Exposes the inner map
168
+ * via a {@link Collections.CacheInvalidatingResultMapWrapper | source} property that
169
+ * invalidates cache entries when mutations occur.
170
+ * @public
171
+ */
172
+ export class ConvertingResultMap extends ReadOnlyConvertingResultMap {
173
+ /**
174
+ * Constructs a new {@link Collections.ConvertingResultMap | ConvertingResultMap}.
175
+ * @param params - Parameters for constructing the map.
176
+ */
177
+ constructor(params) {
178
+ super(params);
179
+ this._typedInner = params.inner;
180
+ this.source = new CacheInvalidatingResultMapWrapper(params.inner, this);
181
+ }
182
+ /**
183
+ * Creates a new {@link Collections.ConvertingResultMap | ConvertingResultMap}.
184
+ * @param params - Parameters for constructing the map.
185
+ * @returns `Success` with the new map, or `Failure` with error details if an error occurred.
186
+ */
187
+ static create(params) {
188
+ return captureResult(() => new ConvertingResultMap(params));
189
+ }
190
+ /**
191
+ * Clears a single entry from the cache.
192
+ * This method is public to allow the cache-invalidating wrapper to call it.
193
+ * @param key - The key to clear from the cache.
194
+ * @internal
195
+ */
196
+ _clearCacheEntry(key) {
197
+ super._clearCacheEntry(key);
198
+ }
199
+ /**
200
+ * Clears all entries from the cache.
201
+ * This method is public to allow the cache-invalidating wrapper to call it.
202
+ * @internal
203
+ */
204
+ _clearCache() {
205
+ super._clearCache();
206
+ }
207
+ }
208
+ //# sourceMappingURL=convertingResultMap.js.map
@@ -22,6 +22,7 @@
22
22
  import * as Utils from './utils';
23
23
  export * from './collectible';
24
24
  export * from './convertingCollector';
25
+ export * from './convertingResultMap';
25
26
  export * from './collector';
26
27
  export * from './collectorValidator';
27
28
  export * from './convertingCollectorValidator';
@@ -29,9 +30,12 @@ export * from './validatingConvertingCollector';
29
30
  export * from './common';
30
31
  export * from './keyValueConverters';
31
32
  export * from './readonlyResultMap';
33
+ export * from './readOnlyConvertingResultMap';
32
34
  export * from './resultMap';
33
35
  export * from './resultMapValidator';
34
36
  export * from './validatingCollector';
37
+ export * from './validatingConvertingResultMap';
35
38
  export * from './validatingResultMap';
39
+ export * from './aggregatedResultMap';
36
40
  export { Utils };
37
41
  //# sourceMappingURL=index.js.map
@@ -29,10 +29,7 @@ import { Converters } from '../conversion';
29
29
  export class KeyValueConverters {
30
30
  /**
31
31
  * Constructs a new key-value validator.
32
- * @param key - Required key {@link Validator | validator}, {@link Converter | converter},
33
- * or {@link Conversion.ConverterFunc | converter function}.
34
- * @param value - Required value {@link Validator | validator}, {@link Converter | converter},
35
- * or {@link Conversion.ConverterFunc | converter function}.
32
+ * @param params - Key and value converters or validators.
36
33
  */
37
34
  constructor({ key, value }) {
38
35
  this.key = typeof key === 'function' ? Converters.generic(key) : key;
@@ -0,0 +1,193 @@
1
+ /*
2
+ * Copyright (c) 2026 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, failWithDetail, succeedWithDetail } from '../base';
23
+ /**
24
+ * A read-only result map that wraps an inner {@link Collections.IReadOnlyResultMap | IReadOnlyResultMap}
25
+ * of source type and returns lazily-converted, cached values of a target type.
26
+ * @public
27
+ */
28
+ export class ReadOnlyConvertingResultMap {
29
+ /**
30
+ * Constructs a new {@link Collections.ReadOnlyConvertingResultMap | ReadOnlyConvertingResultMap}.
31
+ * @param params - Parameters for constructing the map.
32
+ */
33
+ constructor(params) {
34
+ var _a;
35
+ this._inner = params.inner;
36
+ this._converter = params.converter;
37
+ this._cache = new Map();
38
+ this._onConversionError = (_a = params.onConversionError) !== null && _a !== void 0 ? _a : 'ignore';
39
+ this._logger = params.logger;
40
+ }
41
+ /**
42
+ * Creates a new {@link Collections.ReadOnlyConvertingResultMap | ReadOnlyConvertingResultMap}.
43
+ * @param params - Parameters for constructing the map.
44
+ * @returns `Success` with the new map, or `Failure` with error details if an error occurred.
45
+ */
46
+ static create(params) {
47
+ return captureResult(() => new ReadOnlyConvertingResultMap(params));
48
+ }
49
+ /**
50
+ * The number of entries in the map.
51
+ */
52
+ get size() {
53
+ return this._inner.size;
54
+ }
55
+ /**
56
+ * Gets a converted value from the map by key.
57
+ * @param key - The key to retrieve.
58
+ * @returns `Success` with the converted value and detail `exists` if the key was found,
59
+ * `Failure` with detail `not-found` if the key was not found, or `Failure` with
60
+ * detail `invalid-value` if conversion failed.
61
+ */
62
+ get(key) {
63
+ const cached = this._cache.get(key);
64
+ if (cached !== undefined) {
65
+ return succeedWithDetail(cached, 'exists');
66
+ }
67
+ return this._inner.get(key).onSuccess((src) => {
68
+ return this._convertAndCache(key, src);
69
+ });
70
+ }
71
+ /**
72
+ * Checks if the map contains a key.
73
+ * @param key - The key to check.
74
+ * @returns `true` if the key exists, `false` otherwise.
75
+ */
76
+ has(key) {
77
+ return this._inner.has(key);
78
+ }
79
+ /**
80
+ * Returns an iterator over the map entries with converted values.
81
+ * @returns An iterator over the map entries.
82
+ */
83
+ *entries() {
84
+ for (const [key, src] of this._inner.entries()) {
85
+ const target = this._getOrConvert(key, src);
86
+ if (target !== undefined) {
87
+ yield [key, target];
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Returns an iterator over the map keys.
93
+ * @returns An iterator over the map keys.
94
+ */
95
+ keys() {
96
+ return this._inner.keys();
97
+ }
98
+ /**
99
+ * Returns an iterator over the converted map values.
100
+ * @returns An iterator over the map values.
101
+ */
102
+ *values() {
103
+ for (const [key, src] of this._inner.entries()) {
104
+ const target = this._getOrConvert(key, src);
105
+ if (target !== undefined) {
106
+ yield target;
107
+ }
108
+ }
109
+ }
110
+ /**
111
+ * Calls a callback for each entry in the map with converted values.
112
+ * @param cb - The callback to call for each entry.
113
+ * @param thisArg - Optional `this` argument for the callback.
114
+ */
115
+ forEach(cb, thisArg) {
116
+ for (const [key, src] of this._inner.entries()) {
117
+ const target = this._getOrConvert(key, src);
118
+ if (target !== undefined) {
119
+ cb.call(thisArg, target, key, this);
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * Gets an iterator over the map entries.
125
+ * @returns An iterator over the map entries.
126
+ */
127
+ [Symbol.iterator]() {
128
+ return this.entries();
129
+ }
130
+ /**
131
+ * Gets a read-only version of this map.
132
+ * @returns A read-only version of this map.
133
+ */
134
+ toReadOnly() {
135
+ return this;
136
+ }
137
+ /**
138
+ * Converts a source value to a target value and caches the result.
139
+ * @param key - The key of the value.
140
+ * @param src - The source value to convert.
141
+ * @returns `Success` with the converted value if successful, `Failure` otherwise.
142
+ */
143
+ _convertAndCache(key, src) {
144
+ const result = this._converter(src, key);
145
+ if (result.isFailure()) {
146
+ return failWithDetail(result.message, 'invalid-value');
147
+ }
148
+ this._cache.set(key, result.value);
149
+ return succeedWithDetail(result.value, 'exists');
150
+ }
151
+ /**
152
+ * Gets a cached value or converts and caches a source value.
153
+ * Used by iterators. Handles conversion failures according to `_onConversionError`.
154
+ * @param key - The key of the value.
155
+ * @param src - The source value to convert if not cached.
156
+ * @returns The converted value, or `undefined` if conversion failed.
157
+ * @throws Error if `_onConversionError` is `'fail'` and conversion fails.
158
+ */
159
+ _getOrConvert(key, src) {
160
+ var _a;
161
+ const cached = this._cache.get(key);
162
+ if (cached !== undefined) {
163
+ return cached;
164
+ }
165
+ const result = this._converter(src, key);
166
+ if (result.isSuccess()) {
167
+ this._cache.set(key, result.value);
168
+ return result.value;
169
+ }
170
+ switch (this._onConversionError) {
171
+ case 'fail':
172
+ throw new Error(`Conversion failed for key '${key}': ${result.message}`);
173
+ case 'warn':
174
+ (_a = this._logger) === null || _a === void 0 ? void 0 : _a.log('warning', `Conversion failed for key '${key}': ${result.message}`);
175
+ break;
176
+ }
177
+ return undefined;
178
+ }
179
+ /**
180
+ * Clears a single entry from the cache.
181
+ * @param key - The key to clear from the cache.
182
+ */
183
+ _clearCacheEntry(key) {
184
+ this._cache.delete(key);
185
+ }
186
+ /**
187
+ * Clears all entries from the cache.
188
+ */
189
+ _clearCache() {
190
+ this._cache.clear();
191
+ }
192
+ }
193
+ //# sourceMappingURL=readOnlyConvertingResultMap.js.map