@fgv/ts-utils 5.0.0-12 → 5.0.0-15

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 (288) hide show
  1. package/.vscode/launch.json +16 -0
  2. package/.vscode/settings.json +36 -0
  3. package/config/api-extractor.json +343 -0
  4. package/config/rig.json +16 -0
  5. package/dist/tsdoc-metadata.json +1 -1
  6. package/lib/test/helpers/jest/helpers/fsHelpers.d.ts +52 -0
  7. package/lib/test/helpers/jest/helpers/fsHelpers.js +180 -0
  8. package/lib/test/helpers/jest/helpers/index.d.ts +2 -0
  9. package/lib/test/helpers/jest/helpers/index.js +18 -0
  10. package/lib/test/helpers/jest/index.d.ts +3 -0
  11. package/lib/test/helpers/jest/index.js +27 -0
  12. package/lib/test/helpers/jest/matchers/index.d.ts +16 -0
  13. package/lib/test/helpers/jest/matchers/index.js +19 -0
  14. package/lib/test/helpers/jest/matchers/toFail/index.d.ts +16 -0
  15. package/lib/test/helpers/jest/matchers/toFail/index.js +25 -0
  16. package/lib/test/helpers/jest/matchers/toFail/predicate.d.ts +4 -0
  17. package/lib/test/helpers/jest/matchers/toFail/predicate.js +9 -0
  18. package/lib/test/helpers/jest/matchers/toFailTest/index.d.ts +16 -0
  19. package/lib/test/helpers/jest/matchers/toFailTest/index.js +30 -0
  20. package/lib/test/helpers/jest/matchers/toFailTest/predicate.d.ts +3 -0
  21. package/lib/test/helpers/jest/matchers/toFailTest/predicate.js +12 -0
  22. package/lib/test/helpers/jest/matchers/toFailTestAndMatchSnapshot/index.d.ts +17 -0
  23. package/lib/test/helpers/jest/matchers/toFailTestAndMatchSnapshot/index.js +26 -0
  24. package/lib/test/helpers/jest/matchers/toFailTestAndMatchSnapshot/predicate.d.ts +4 -0
  25. package/lib/test/helpers/jest/matchers/toFailTestAndMatchSnapshot/predicate.js +15 -0
  26. package/lib/test/helpers/jest/matchers/toFailTestWith/index.d.ts +18 -0
  27. package/lib/test/helpers/jest/matchers/toFailTestWith/index.js +31 -0
  28. package/lib/test/helpers/jest/matchers/toFailTestWith/predicate.d.ts +4 -0
  29. package/lib/test/helpers/jest/matchers/toFailTestWith/predicate.js +30 -0
  30. package/lib/test/helpers/jest/matchers/toFailWith/index.d.ts +18 -0
  31. package/lib/test/helpers/jest/matchers/toFailWith/index.js +29 -0
  32. package/lib/test/helpers/jest/matchers/toFailWith/predicate.d.ts +4 -0
  33. package/lib/test/helpers/jest/matchers/toFailWith/predicate.js +20 -0
  34. package/lib/test/helpers/jest/matchers/toFailWithDetail/index.d.ts +19 -0
  35. package/lib/test/helpers/jest/matchers/toFailWithDetail/index.js +29 -0
  36. package/lib/test/helpers/jest/matchers/toFailWithDetail/predicate.d.ts +4 -0
  37. package/lib/test/helpers/jest/matchers/toFailWithDetail/predicate.js +26 -0
  38. package/lib/test/helpers/jest/matchers/toSucceed/index.d.ts +16 -0
  39. package/lib/test/helpers/jest/matchers/toSucceed/index.js +25 -0
  40. package/lib/test/helpers/jest/matchers/toSucceed/predicate.d.ts +4 -0
  41. package/lib/test/helpers/jest/matchers/toSucceed/predicate.js +9 -0
  42. package/lib/test/helpers/jest/matchers/toSucceedAndMatchInlineSnapshot/index.d.ts +17 -0
  43. package/lib/test/helpers/jest/matchers/toSucceedAndMatchInlineSnapshot/index.js +26 -0
  44. package/lib/test/helpers/jest/matchers/toSucceedAndMatchSnapshot/index.d.ts +17 -0
  45. package/lib/test/helpers/jest/matchers/toSucceedAndMatchSnapshot/index.js +26 -0
  46. package/lib/test/helpers/jest/matchers/toSucceedAndSatisfy/index.d.ts +19 -0
  47. package/lib/test/helpers/jest/matchers/toSucceedAndSatisfy/index.js +55 -0
  48. package/lib/test/helpers/jest/matchers/toSucceedAndSatisfy/predicate.d.ts +4 -0
  49. package/lib/test/helpers/jest/matchers/toSucceedAndSatisfy/predicate.js +21 -0
  50. package/lib/test/helpers/jest/matchers/toSucceedWith/index.d.ts +18 -0
  51. package/lib/test/helpers/jest/matchers/toSucceedWith/index.js +29 -0
  52. package/lib/test/helpers/jest/matchers/toSucceedWith/predicate.d.ts +4 -0
  53. package/lib/test/helpers/jest/matchers/toSucceedWith/predicate.js +16 -0
  54. package/lib/test/helpers/jest/matchers/toSucceedWithDetail/index.d.ts +18 -0
  55. package/lib/test/helpers/jest/matchers/toSucceedWithDetail/index.js +29 -0
  56. package/lib/test/helpers/jest/matchers/toSucceedWithDetail/predicate.d.ts +4 -0
  57. package/lib/test/helpers/jest/matchers/toSucceedWithDetail/predicate.js +21 -0
  58. package/lib/test/helpers/jest/resolvers/cli.d.ts +5 -0
  59. package/lib/test/helpers/jest/resolvers/cli.js +48 -0
  60. package/lib/test/helpers/jest/resolvers/ide.d.ts +5 -0
  61. package/lib/test/helpers/jest/resolvers/ide.js +48 -0
  62. package/lib/test/helpers/jest/ts-utils.d.ts +2 -0
  63. package/lib/test/helpers/jest/ts-utils.js +18 -0
  64. package/lib/test/helpers/jest/types/index.d.ts +79 -0
  65. package/lib/test/helpers/jest/types/index.js +4 -0
  66. package/lib/test/helpers/jest/utils/matcherHelpers.d.ts +6 -0
  67. package/lib/test/helpers/jest/utils/matcherHelpers.js +53 -0
  68. package/lib/test/helpers/jest/utils/snapshotResolver.d.ts +4 -0
  69. package/lib/test/helpers/jest/utils/snapshotResolver.js +19 -0
  70. package/lib/test/unit/collections/collectible.test.d.ts +2 -0
  71. package/lib/test/unit/collections/collector.test.d.ts +2 -0
  72. package/lib/test/unit/collections/collectors.test.d.ts +2 -0
  73. package/lib/test/unit/collections/convertingCollector.test.d.ts +2 -0
  74. package/lib/test/unit/collections/helpers.d.ts +44 -0
  75. package/lib/test/unit/collections/helpers.js +115 -0
  76. package/lib/test/unit/collections/resultMap.test.d.ts +2 -0
  77. package/lib/test/unit/collections/validatingCollector.test.d.ts +2 -0
  78. package/lib/test/unit/collections/validatingConvertingCollector.test.d.ts +2 -0
  79. package/lib/test/unit/collections/validatingResultMap.test.d.ts +2 -0
  80. package/lib/test/unit/converter.test.d.ts +2 -0
  81. package/lib/test/unit/converters.test.d.ts +2 -0
  82. package/lib/test/unit/defaultingConverter.test.d.ts +2 -0
  83. package/lib/test/unit/file-tree/fileItem.test.d.ts +2 -0
  84. package/lib/test/unit/file-tree/fileTree.test.d.ts +2 -0
  85. package/lib/test/unit/file-tree/fsTree.test.d.ts +2 -0
  86. package/lib/test/unit/file-tree/inMemoryTree.test.d.ts +2 -0
  87. package/lib/test/unit/file-tree/sample/rootFile.json +1 -0
  88. package/lib/test/unit/file-tree/sample/some/other/path/file2.json +1 -0
  89. package/lib/test/unit/file-tree/sample/some/path/below/file4.json +1 -0
  90. package/lib/test/unit/file-tree/sample/some/path/file1.json +1 -0
  91. package/lib/test/unit/file-tree/sample/some/path/file3.json +1 -0
  92. package/lib/test/unit/hash.test.d.ts +2 -0
  93. package/lib/test/unit/logger.test.d.ts +2 -0
  94. package/lib/test/unit/mapResults.test.d.ts +3 -0
  95. package/lib/test/unit/messageAggregator.test.d.ts +3 -0
  96. package/lib/test/unit/normalize.test.d.ts +2 -0
  97. package/lib/test/unit/result.test.d.ts +3 -0
  98. package/lib/test/unit/utils.test.d.ts +3 -0
  99. package/lib/test/unit/validation/array.test.d.ts +2 -0
  100. package/lib/test/unit/validation/boolean.test.d.ts +2 -0
  101. package/lib/test/unit/validation/genericValidator.test.d.ts +2 -0
  102. package/lib/test/unit/validation/number.test.d.ts +2 -0
  103. package/lib/test/unit/validation/object.test.d.ts +2 -0
  104. package/lib/test/unit/validation/oneOf.test.d.ts +2 -0
  105. package/lib/test/unit/validation/recordOf.test.d.ts +2 -0
  106. package/lib/test/unit/validation/string.test.d.ts +2 -0
  107. package/lib/test/unit/validation/traits.test.d.ts +2 -0
  108. package/lib/test/unit/validation/typeGuard.test.d.ts +2 -0
  109. package/lib/test/unit/validation/validators.test.d.ts +2 -0
  110. package/package.json +9 -9
  111. package/src/index.ts +63 -0
  112. package/src/packlets/base/brand.ts +28 -0
  113. package/src/packlets/base/index.ts +31 -0
  114. package/src/packlets/base/logger.ts +156 -0
  115. package/src/packlets/base/mapResults.ts +302 -0
  116. package/src/packlets/base/messageAggregator.ts +120 -0
  117. package/src/packlets/base/normalize.ts +144 -0
  118. package/src/packlets/base/result.ts +961 -0
  119. package/src/packlets/base/utils.ts +236 -0
  120. package/src/packlets/collections/collectible.ts +238 -0
  121. package/src/packlets/collections/collector.ts +273 -0
  122. package/src/packlets/collections/collectorValidator.ts +178 -0
  123. package/src/packlets/collections/common.ts +27 -0
  124. package/src/packlets/collections/convertingCollector.ts +223 -0
  125. package/src/packlets/collections/convertingCollectorValidator.ts +164 -0
  126. package/src/packlets/collections/index.ts +39 -0
  127. package/src/packlets/collections/keyValueConverters.ts +142 -0
  128. package/src/packlets/collections/readonlyResultMap.ts +99 -0
  129. package/src/packlets/collections/resultMap.ts +322 -0
  130. package/src/packlets/collections/resultMapValidator.ts +188 -0
  131. package/src/packlets/collections/utils.ts +33 -0
  132. package/src/packlets/collections/validatingCollector.ts +123 -0
  133. package/src/packlets/collections/validatingConvertingCollector.ts +113 -0
  134. package/src/packlets/collections/validatingResultMap.ts +94 -0
  135. package/src/packlets/conversion/baseConverter.ts +330 -0
  136. package/src/packlets/conversion/converter.ts +260 -0
  137. package/src/packlets/conversion/converters.ts +1039 -0
  138. package/src/packlets/conversion/defaultingConverter.ts +188 -0
  139. package/src/packlets/conversion/index.ts +30 -0
  140. package/src/packlets/conversion/objectConverter.ts +259 -0
  141. package/src/packlets/conversion/stringConverter.ts +165 -0
  142. package/src/packlets/file-tree/directoryItem.ts +84 -0
  143. package/src/packlets/file-tree/fileItem.ts +119 -0
  144. package/src/packlets/file-tree/fileTree.ts +152 -0
  145. package/src/packlets/file-tree/fileTreeAccessors.ts +176 -0
  146. package/src/packlets/file-tree/fsTree.ts +118 -0
  147. package/src/packlets/file-tree/in-memory/inMemoryTree.ts +171 -0
  148. package/src/packlets/file-tree/in-memory/index.ts +23 -0
  149. package/src/packlets/file-tree/in-memory/treeBuilder.ts +203 -0
  150. package/src/packlets/file-tree/index.ts +31 -0
  151. package/src/packlets/hash/crcNormalizer.ts +81 -0
  152. package/src/packlets/hash/hashingNormalizer.ts +102 -0
  153. package/src/packlets/hash/index.ts +24 -0
  154. package/src/packlets/validation/array.ts +83 -0
  155. package/src/packlets/validation/boolean.ts +63 -0
  156. package/src/packlets/validation/classes.ts +38 -0
  157. package/src/packlets/validation/common.ts +38 -0
  158. package/src/packlets/validation/field.ts +99 -0
  159. package/src/packlets/validation/genericValidator.ts +205 -0
  160. package/src/packlets/validation/index.ts +31 -0
  161. package/src/packlets/validation/number.ts +66 -0
  162. package/src/packlets/validation/object.ts +208 -0
  163. package/src/packlets/validation/oneOf.ts +77 -0
  164. package/src/packlets/validation/string.ts +66 -0
  165. package/src/packlets/validation/traits.ts +113 -0
  166. package/src/packlets/validation/typeGuard.ts +82 -0
  167. package/src/packlets/validation/validator.ts +145 -0
  168. package/src/packlets/validation/validatorBase.ts +61 -0
  169. package/src/packlets/validation/validators.ts +246 -0
  170. package/CHANGELOG.md +0 -135
  171. package/lib/index.d.ts.map +0 -1
  172. package/lib/index.js.map +0 -1
  173. package/lib/packlets/base/brand.d.ts.map +0 -1
  174. package/lib/packlets/base/brand.js.map +0 -1
  175. package/lib/packlets/base/index.d.ts.map +0 -1
  176. package/lib/packlets/base/index.js.map +0 -1
  177. package/lib/packlets/base/logger.d.ts.map +0 -1
  178. package/lib/packlets/base/logger.js.map +0 -1
  179. package/lib/packlets/base/mapResults.d.ts.map +0 -1
  180. package/lib/packlets/base/mapResults.js.map +0 -1
  181. package/lib/packlets/base/messageAggregator.d.ts.map +0 -1
  182. package/lib/packlets/base/messageAggregator.js.map +0 -1
  183. package/lib/packlets/base/normalize.d.ts.map +0 -1
  184. package/lib/packlets/base/normalize.js.map +0 -1
  185. package/lib/packlets/base/result.d.ts.map +0 -1
  186. package/lib/packlets/base/result.js.map +0 -1
  187. package/lib/packlets/base/utils.d.ts.map +0 -1
  188. package/lib/packlets/base/utils.js.map +0 -1
  189. package/lib/packlets/collections/collectible.d.ts.map +0 -1
  190. package/lib/packlets/collections/collectible.js.map +0 -1
  191. package/lib/packlets/collections/collector.d.ts.map +0 -1
  192. package/lib/packlets/collections/collector.js.map +0 -1
  193. package/lib/packlets/collections/collectorValidator.d.ts.map +0 -1
  194. package/lib/packlets/collections/collectorValidator.js.map +0 -1
  195. package/lib/packlets/collections/common.d.ts.map +0 -1
  196. package/lib/packlets/collections/common.js.map +0 -1
  197. package/lib/packlets/collections/convertingCollector.d.ts.map +0 -1
  198. package/lib/packlets/collections/convertingCollector.js.map +0 -1
  199. package/lib/packlets/collections/convertingCollectorValidator.d.ts.map +0 -1
  200. package/lib/packlets/collections/convertingCollectorValidator.js.map +0 -1
  201. package/lib/packlets/collections/index.d.ts.map +0 -1
  202. package/lib/packlets/collections/index.js.map +0 -1
  203. package/lib/packlets/collections/keyValueConverters.d.ts.map +0 -1
  204. package/lib/packlets/collections/keyValueConverters.js.map +0 -1
  205. package/lib/packlets/collections/readonlyResultMap.d.ts.map +0 -1
  206. package/lib/packlets/collections/readonlyResultMap.js.map +0 -1
  207. package/lib/packlets/collections/resultMap.d.ts.map +0 -1
  208. package/lib/packlets/collections/resultMap.js.map +0 -1
  209. package/lib/packlets/collections/resultMapValidator.d.ts.map +0 -1
  210. package/lib/packlets/collections/resultMapValidator.js.map +0 -1
  211. package/lib/packlets/collections/utils.d.ts.map +0 -1
  212. package/lib/packlets/collections/utils.js.map +0 -1
  213. package/lib/packlets/collections/validatingCollector.d.ts.map +0 -1
  214. package/lib/packlets/collections/validatingCollector.js.map +0 -1
  215. package/lib/packlets/collections/validatingConvertingCollector.d.ts.map +0 -1
  216. package/lib/packlets/collections/validatingConvertingCollector.js.map +0 -1
  217. package/lib/packlets/collections/validatingResultMap.d.ts.map +0 -1
  218. package/lib/packlets/collections/validatingResultMap.js.map +0 -1
  219. package/lib/packlets/conversion/baseConverter.d.ts.map +0 -1
  220. package/lib/packlets/conversion/baseConverter.js.map +0 -1
  221. package/lib/packlets/conversion/converter.d.ts.map +0 -1
  222. package/lib/packlets/conversion/converter.js.map +0 -1
  223. package/lib/packlets/conversion/converters.d.ts.map +0 -1
  224. package/lib/packlets/conversion/converters.js.map +0 -1
  225. package/lib/packlets/conversion/defaultingConverter.d.ts.map +0 -1
  226. package/lib/packlets/conversion/defaultingConverter.js.map +0 -1
  227. package/lib/packlets/conversion/index.d.ts.map +0 -1
  228. package/lib/packlets/conversion/index.js.map +0 -1
  229. package/lib/packlets/conversion/objectConverter.d.ts.map +0 -1
  230. package/lib/packlets/conversion/objectConverter.js.map +0 -1
  231. package/lib/packlets/conversion/stringConverter.d.ts.map +0 -1
  232. package/lib/packlets/conversion/stringConverter.js.map +0 -1
  233. package/lib/packlets/file-tree/directoryItem.d.ts.map +0 -1
  234. package/lib/packlets/file-tree/directoryItem.js.map +0 -1
  235. package/lib/packlets/file-tree/fileItem.d.ts.map +0 -1
  236. package/lib/packlets/file-tree/fileItem.js.map +0 -1
  237. package/lib/packlets/file-tree/fileTree.d.ts.map +0 -1
  238. package/lib/packlets/file-tree/fileTree.js.map +0 -1
  239. package/lib/packlets/file-tree/fileTreeAccessors.d.ts.map +0 -1
  240. package/lib/packlets/file-tree/fileTreeAccessors.js.map +0 -1
  241. package/lib/packlets/file-tree/fsTree.d.ts.map +0 -1
  242. package/lib/packlets/file-tree/fsTree.js.map +0 -1
  243. package/lib/packlets/file-tree/in-memory/inMemoryTree.d.ts.map +0 -1
  244. package/lib/packlets/file-tree/in-memory/inMemoryTree.js.map +0 -1
  245. package/lib/packlets/file-tree/in-memory/index.d.ts.map +0 -1
  246. package/lib/packlets/file-tree/in-memory/index.js.map +0 -1
  247. package/lib/packlets/file-tree/in-memory/treeBuilder.d.ts.map +0 -1
  248. package/lib/packlets/file-tree/in-memory/treeBuilder.js.map +0 -1
  249. package/lib/packlets/file-tree/index.d.ts.map +0 -1
  250. package/lib/packlets/file-tree/index.js.map +0 -1
  251. package/lib/packlets/hash/crcNormalizer.d.ts.map +0 -1
  252. package/lib/packlets/hash/crcNormalizer.js.map +0 -1
  253. package/lib/packlets/hash/hashingNormalizer.d.ts.map +0 -1
  254. package/lib/packlets/hash/hashingNormalizer.js.map +0 -1
  255. package/lib/packlets/hash/index.d.ts.map +0 -1
  256. package/lib/packlets/hash/index.js.map +0 -1
  257. package/lib/packlets/validation/array.d.ts.map +0 -1
  258. package/lib/packlets/validation/array.js.map +0 -1
  259. package/lib/packlets/validation/boolean.d.ts.map +0 -1
  260. package/lib/packlets/validation/boolean.js.map +0 -1
  261. package/lib/packlets/validation/classes.d.ts.map +0 -1
  262. package/lib/packlets/validation/classes.js.map +0 -1
  263. package/lib/packlets/validation/common.d.ts.map +0 -1
  264. package/lib/packlets/validation/common.js.map +0 -1
  265. package/lib/packlets/validation/field.d.ts.map +0 -1
  266. package/lib/packlets/validation/field.js.map +0 -1
  267. package/lib/packlets/validation/genericValidator.d.ts.map +0 -1
  268. package/lib/packlets/validation/genericValidator.js.map +0 -1
  269. package/lib/packlets/validation/index.d.ts.map +0 -1
  270. package/lib/packlets/validation/index.js.map +0 -1
  271. package/lib/packlets/validation/number.d.ts.map +0 -1
  272. package/lib/packlets/validation/number.js.map +0 -1
  273. package/lib/packlets/validation/object.d.ts.map +0 -1
  274. package/lib/packlets/validation/object.js.map +0 -1
  275. package/lib/packlets/validation/oneOf.d.ts.map +0 -1
  276. package/lib/packlets/validation/oneOf.js.map +0 -1
  277. package/lib/packlets/validation/string.d.ts.map +0 -1
  278. package/lib/packlets/validation/string.js.map +0 -1
  279. package/lib/packlets/validation/traits.d.ts.map +0 -1
  280. package/lib/packlets/validation/traits.js.map +0 -1
  281. package/lib/packlets/validation/typeGuard.d.ts.map +0 -1
  282. package/lib/packlets/validation/typeGuard.js.map +0 -1
  283. package/lib/packlets/validation/validator.d.ts.map +0 -1
  284. package/lib/packlets/validation/validator.js.map +0 -1
  285. package/lib/packlets/validation/validatorBase.d.ts.map +0 -1
  286. package/lib/packlets/validation/validatorBase.js.map +0 -1
  287. package/lib/packlets/validation/validators.d.ts.map +0 -1
  288. package/lib/packlets/validation/validators.js.map +0 -1
@@ -0,0 +1,236 @@
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
+
23
+ import { Result, fail, succeed } from './result';
24
+
25
+ /**
26
+ * Helper type-guard function to report whether a specified key is present in
27
+ * a supplied object.
28
+ * @param key - The key to be tested.
29
+ * @param item - The object to be tested.
30
+ * @returns Returns `true` if the key is present, `false` otherwise.
31
+ * @public
32
+ */
33
+ export function isKeyOf<T extends object>(key: string | number | symbol, item: T): key is keyof T {
34
+ return item.hasOwnProperty(key);
35
+ }
36
+
37
+ /**
38
+ * Simple implicit pick function, which picks a set of properties from a supplied
39
+ * object. Ignores picked properties that do not exist regardless of type signature.
40
+ * @param from - The object from which keys are to be picked.
41
+ * @param include - The keys of the properties to be picked from `from`.
42
+ * @returns A new object containing the requested properties from `from`, where present.
43
+ * @public
44
+ */
45
+ export function pick<T extends object, K extends keyof T>(from: T, include: K[]): Pick<T, K> {
46
+ const rtrn: Partial<Pick<T, K>> = {};
47
+ for (const key of include) {
48
+ if (key in from) {
49
+ rtrn[key] = from[key];
50
+ }
51
+ }
52
+ return rtrn as Pick<T, K>;
53
+ }
54
+
55
+ /**
56
+ * Simple implicit omit function, which picks all of the properties from a supplied
57
+ * object except those specified for exclusion.
58
+ * @param from - The object from which keys are to be picked.
59
+ * @param exclude - The keys of the properties to be excluded from the returned object.
60
+ * @returns A new object containing all of the properties from `from` that were not
61
+ * explicitly excluded.
62
+ * @public
63
+ */
64
+ export function omit<T extends object, K extends keyof T>(from: T, exclude: K[]): Omit<T, K> {
65
+ const rtrn: Partial<Omit<T, K>> = {};
66
+ for (const entry of Object.entries(from).filter((e) => !exclude.includes(e[0] as keyof T as K))) {
67
+ rtrn[entry[0] as unknown as keyof Omit<T, K>] = entry[1];
68
+ }
69
+
70
+ return rtrn as Omit<T, K>;
71
+ }
72
+
73
+ /**
74
+ * Gets the value of a property specified by key from an arbitrary object,
75
+ * or a default value if the property does not exist.
76
+ * @param key - The key specifying the property to be retrieved.
77
+ * @param item - The object from which the property is to be retrieved.
78
+ * @param defaultValue - An optional default value to be returned if the property
79
+ * is not present (default `undefined`).
80
+ * @returns The value of the requested property, or the default value if the
81
+ * requested property does not exist.
82
+ * @public
83
+ */
84
+ export function getValueOfPropertyOrDefault<T extends object>(
85
+ key: string | number | symbol,
86
+ item: T,
87
+ defaultValue?: unknown
88
+ ): unknown | undefined {
89
+ return isKeyOf(key, item) ? item[key] : defaultValue;
90
+ }
91
+
92
+ /**
93
+ * Gets the type of a property specified by key from an arbitrary object.
94
+ * @param key - The key specifying the property to be tested.
95
+ * @param item - The object from which the property is to be tested.
96
+ * @returns The type of the requested property, or `undefined` if the
97
+ * property does not exist.
98
+ * @example
99
+ * Returns `'undefined'` (a string) if the property exists but has the value
100
+ * undefined but `undefined` (the literal) if the property does not exist.
101
+ * @public
102
+ */
103
+ export function getTypeOfProperty<T extends object>(
104
+ key: string | number | symbol,
105
+ item: T
106
+ ):
107
+ | 'string'
108
+ | 'number'
109
+ | 'bigint'
110
+ | 'boolean'
111
+ | 'symbol'
112
+ | 'undefined'
113
+ | 'undefined'
114
+ | 'object'
115
+ | 'function'
116
+ | undefined {
117
+ return isKeyOf(key, item) ? typeof item[key] : undefined;
118
+ }
119
+
120
+ /**
121
+ * Type for factory methods which convert a key-value pair to a new unique value.
122
+ * @public
123
+ */
124
+ type KeyedThingFactory<TS, TD, TK extends string = string> = (key: TK, thing: TS) => Result<TD>;
125
+
126
+ /**
127
+ * Applies a factory method to convert a `Record<TK, TS>` into a `Map<TK, TD>`.
128
+ * @param src - The `Record` to be converted.
129
+ * @param factory - The factory method used to convert elements.
130
+ * @returns {@link Success} with the resulting map on success, or {@link Failure} with a
131
+ * message if an error occurs.
132
+ * @public
133
+ */
134
+ export function recordToMap<TS, TD, TK extends string = string>(
135
+ src: Record<TK, TS>,
136
+ factory: KeyedThingFactory<TS, TD, TK>
137
+ ): Result<Map<TK, TD>> {
138
+ const map = new Map<TK, TD>();
139
+ for (const key in src) {
140
+ if (src[key] !== undefined) {
141
+ const itemResult = factory(key, src[key]);
142
+ if (itemResult.isSuccess()) {
143
+ map.set(key, itemResult.value);
144
+ } else {
145
+ return fail(`${key}: ${itemResult.message}`);
146
+ }
147
+ }
148
+ }
149
+ return succeed(map);
150
+ }
151
+
152
+ /**
153
+ * Applies a factory method to convert an optional `Record<TK, TS>` into a `Map<TK, TD>`, or `undefined`.
154
+ * @param src - The `Record` to be converted, or undefined.
155
+ * @param factory - The factory method used to convert elements.
156
+ * @returns {@link Success} with the resulting map if conversion succeeds, or {@link Success} with `undefined`
157
+ * if `src` is `undefined`. Returns {@link Failure} with a message if an error occurs.
158
+ * @public
159
+ */
160
+ export function optionalRecordToMap<TS, TD, TK extends string = string>(
161
+ src: Record<TK, TS> | undefined,
162
+ factory: KeyedThingFactory<TS, TD, TK>
163
+ ): Result<Map<TK, TD> | undefined> {
164
+ return src === undefined ? succeed(undefined) : recordToMap(src, factory);
165
+ }
166
+
167
+ /**
168
+ * Applies a factory method to convert an optional `Record<TK, TS>` into a `Map<TK, TD>`
169
+ * @param src - The `Record` to be converted, or `undefined`.
170
+ * @param factory - The factory method used to convert elements.
171
+ * @returns {@link Success} with the resulting map (empty if `src` is `undefined`) if conversion succeeds.
172
+ * Returns {@link Failure} with a message if an error occurs.
173
+ * @public
174
+ */
175
+ export function optionalRecordToPossiblyEmptyMap<TS, TD, TK extends string = string>(
176
+ src: Record<TK, TS> | undefined,
177
+ factory: KeyedThingFactory<TS, TD, TK>
178
+ ): Result<Map<TK, TD>> {
179
+ return src === undefined ? succeed(new Map<TK, TD>()) : recordToMap(src, factory);
180
+ }
181
+
182
+ /**
183
+ * Applies a factory method to convert a `ReadonlyMap<TK, TS>` into a `Record<TK, TD>`.
184
+ * @param src - The `Map` object to be converted.
185
+ * @param factory - The factory method used to convert elements.
186
+ * @returns {@link Success} with the resulting `Record<TK, TD>` if conversion succeeds, or
187
+ * {@link Failure} with an error message if an error occurs.
188
+ * @public
189
+ */
190
+ export function mapToRecord<TS, TD, TK extends string = string>(
191
+ src: ReadonlyMap<TK, TS>,
192
+ factory: KeyedThingFactory<TS, TD, TK>
193
+ ): Result<Record<TK, TD>> {
194
+ const record: Record<TK, TD> = {} as Record<TK, TD>;
195
+ for (const kvp of src) {
196
+ if (kvp[1] !== undefined) {
197
+ const itemResult = factory(kvp[0], kvp[1]);
198
+ if (itemResult.isSuccess()) {
199
+ record[kvp[0]] = itemResult.value;
200
+ } else {
201
+ return fail(`${kvp[0]}: ${itemResult.message}`);
202
+ }
203
+ }
204
+ }
205
+ return succeed(record);
206
+ }
207
+
208
+ /**
209
+ * Applies a factory method to convert an optional `ReadonlyMap<string, TS>` into a `Record<string, TD>` or `undefined`.
210
+ * @param src - The `Map` object to be converted, or `undefined`.
211
+ * @param factory - The factory method used to convert elements.
212
+ * @returns {@link Success} with the resulting record if conversion succeeds, or {@link Success} with `undefined` if
213
+ * `src` is `undefined`. Returns {@link Failure} with a message if an error occurs.
214
+ * @public
215
+ */
216
+ export function optionalMapToRecord<TS, TD, TK extends string = string>(
217
+ src: ReadonlyMap<TK, TS> | undefined,
218
+ factory: KeyedThingFactory<TS, TD, TK>
219
+ ): Result<Record<TK, TD> | undefined> {
220
+ return src === undefined ? succeed(undefined) : mapToRecord(src, factory);
221
+ }
222
+
223
+ /**
224
+ * Applies a factory method to convert an optional `ReadonlyMap<string, TS>` into a `Record<string, TD>`
225
+ * @param src - The `ReadonlyMap` object to be converted, or `undefined`.
226
+ * @param factory - The factory method used to convert elements.
227
+ * @returns {@link Success} with the resulting record (empty if `src` is `undefined`) if conversion succeeds.
228
+ * Returns {@link Failure} with a message if an error occurs.
229
+ * @public
230
+ */
231
+ export function optionalMapToPossiblyEmptyRecord<TS, TD, TK extends string = string>(
232
+ src: ReadonlyMap<TK, TS> | undefined,
233
+ factory: KeyedThingFactory<TS, TD, TK>
234
+ ): Result<Record<TK, TD>> {
235
+ return src === undefined ? succeed({} as Record<TK, TD>) : mapToRecord(src, factory);
236
+ }
@@ -0,0 +1,238 @@
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
+
23
+ import { Result, captureResult, fail, succeed } from '../base';
24
+ import { Converter, ConverterFunc, Converters } from '../conversion';
25
+ import { Validator } from '../validation';
26
+
27
+ /**
28
+ * An item that can be collected by some {@link ConvertingCollector | Collector}.
29
+ * @public
30
+ */
31
+ export interface ICollectible<TKEY extends string = string, TINDEX extends number = number> {
32
+ readonly key: TKEY;
33
+ readonly index: TINDEX | undefined;
34
+ setIndex(index: number): Result<TINDEX>;
35
+ }
36
+
37
+ /**
38
+ * Infer the key type from an {@link Collections.ICollectible | ICollectible} type.
39
+ * @public
40
+ */
41
+ export type CollectibleKey<TITEM extends ICollectible> = TITEM extends ICollectible<infer TKEY>
42
+ ? TKEY
43
+ : never;
44
+
45
+ /**
46
+ * Infer the index type from an {@link Collections.ICollectible | ICollectible} type.
47
+ * @public
48
+ */
49
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
+ export type CollectibleIndex<TITEM extends ICollectible> = TITEM extends ICollectible<any, infer TINDEX>
51
+ ? TINDEX
52
+ : never;
53
+
54
+ /**
55
+ * Factory function for creating a new {@link Collections.ICollectible | ICollectible} instance given a key, an index and a source representation
56
+ * of the item to be added.
57
+ * @public
58
+ */
59
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
+ export type CollectibleFactory<TITEM extends ICollectible<any, any>, TSRC> = (
61
+ key: CollectibleKey<TITEM>,
62
+ index: number,
63
+ item: TSRC
64
+ ) => Result<TITEM>;
65
+
66
+ /**
67
+ * Factory function for creating a new {@link Collections.ICollectible | ICollectible} instance given a key and an index.
68
+ * @public
69
+ */
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ export type CollectibleFactoryCallback<TITEM extends ICollectible<any, any>> = (
72
+ key: CollectibleKey<TITEM>,
73
+ index: number
74
+ ) => Result<TITEM>;
75
+
76
+ /**
77
+ * Parameters for constructing a new {@link Collections.ICollectible | ICollectible} instance with
78
+ * a defined, strongly-typed index.
79
+ * @public
80
+ */
81
+ export interface ICollectibleConstructorParamsWithIndex<
82
+ TKEY extends string = string,
83
+ TINDEX extends number = number
84
+ > {
85
+ key: TKEY;
86
+ index: TINDEX;
87
+ }
88
+
89
+ /**
90
+ * Parameters for constructing a new {@link Collections.ICollectible | ICollectible} instance with an
91
+ * index converter.
92
+ * @public
93
+ */
94
+ export interface ICollectibleConstructorParamsWithConverter<
95
+ TKEY extends string = string,
96
+ TINDEX extends number = number
97
+ > {
98
+ key: TKEY;
99
+ index?: number;
100
+ indexConverter: Validator<TINDEX, unknown> | Converter<TINDEX, unknown> | ConverterFunc<TINDEX, undefined>;
101
+ }
102
+
103
+ /**
104
+ * Parameters for constructing a new {@link Collections.ICollectible | ICollectible} instance.
105
+ * @public
106
+ */
107
+ export type ICollectibleConstructorParams<TKEY extends string = string, TINDEX extends number = number> =
108
+ | ICollectibleConstructorParamsWithIndex<TKEY, TINDEX>
109
+ | ICollectibleConstructorParamsWithConverter<TKEY, TINDEX>;
110
+
111
+ /**
112
+ * Simple implementation of {@link Collections.ICollectible | ICollectible} which does not allow the index to be
113
+ * changed once set.
114
+ * @public
115
+ */
116
+ export class Collectible<TKEY extends string = string, TINDEX extends number = number>
117
+ implements ICollectible<TKEY, TINDEX>
118
+ {
119
+ /**
120
+ * {@link Collections.ICollectible.key}
121
+ */
122
+ public readonly key: TKEY;
123
+
124
+ /**
125
+ * {@link Collections.ICollectible.index}
126
+ */
127
+ public get index(): TINDEX | undefined {
128
+ return this._index;
129
+ }
130
+
131
+ protected _index: TINDEX | undefined;
132
+ protected readonly _indexConverter?: Validator<TINDEX, unknown> | Converter<TINDEX, unknown>;
133
+
134
+ /**
135
+ * Constructs a new {@link Collections.Collectible | Collectible} instance
136
+ * with a defined, strongly-typed index.
137
+ * @param params - {@link Collections.ICollectibleConstructorParamsWithIndex | Parameters} for constructing
138
+ * the collectible.
139
+ */
140
+ public constructor(params: ICollectibleConstructorParamsWithIndex<TKEY, TINDEX>);
141
+
142
+ /**
143
+ * Constructs a new {@link Collections.Collectible | Collectible} instance with
144
+ * an undefined index and an index converter to validate te index when it is set.
145
+ * @param params - {@link Collections.ICollectibleConstructorParamsWithConverter | Parameters} for constructing
146
+ * the collectible.
147
+ */
148
+ public constructor(params: ICollectibleConstructorParamsWithConverter<TKEY, TINDEX>);
149
+
150
+ /**
151
+ * Constructs a new {@link Collections.Collectible | Collectible} instance.
152
+ * @param params - {@link Collections.ICollectibleConstructorParams | Parameters} for constructing
153
+ * the collectible.
154
+ */
155
+ public constructor(params: ICollectibleConstructorParams<TKEY, TINDEX>);
156
+ public constructor(params: ICollectibleConstructorParams<TKEY, TINDEX>) {
157
+ this.key = params.key;
158
+ if ('indexConverter' in params) {
159
+ this._indexConverter =
160
+ typeof params.indexConverter === 'function'
161
+ ? Converters.generic(params.indexConverter)
162
+ : params.indexConverter;
163
+ if (params.index !== undefined) {
164
+ this._index = this._indexConverter.convert(params.index).orThrow();
165
+ }
166
+ } else {
167
+ /* c8 ignore next 3 - coverage is having a bad day */
168
+ this._index = params.index;
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Creates a new {@link Collections.Collectible | Collectible} instance with a defined, strongly-typed index.
174
+ * @param params - {@link Collections.ICollectibleConstructorParamsWithIndex | Parameters} for constructing
175
+ * the collectible.
176
+ * @returns {@link Success} with the new collectible if successful, {@link Failure} otherwise.
177
+ */
178
+ public static createCollectible<TKEY extends string = string, TINDEX extends number = number>(
179
+ params: ICollectibleConstructorParamsWithIndex<TKEY, TINDEX>
180
+ ): Result<Collectible<TKEY, TINDEX>>;
181
+
182
+ /**
183
+ * Creates a new {@link Collections.Collectible | Collectible} instance with an undefined index and an index
184
+ * converter to validate the index when it is set.
185
+ * @param params - {@link Collections.ICollectibleConstructorParamsWithConverter | Parameters} for constructing
186
+ * the collectible.
187
+ * @returns {@link Success} with the new collectible if successful, {@link Failure} otherwise.
188
+ */
189
+ public static createCollectible<TKEY extends string = string, TINDEX extends number = number>(
190
+ params: ICollectibleConstructorParamsWithConverter<TKEY, TINDEX>
191
+ ): Result<Collectible<TKEY, TINDEX>>;
192
+
193
+ /**
194
+ * Creates a new {@link Collections.Collectible | Collectible} instance.
195
+ * @param params - {@link Collections.ICollectibleConstructorParams | Parameters} for constructing
196
+ * the collectible.
197
+ * @returns {@link Success} with the new collectible if successful, {@link Failure} otherwise
198
+ * @public
199
+ */
200
+ public static createCollectible<TKEY extends string = string, TINDEX extends number = number>(
201
+ params: ICollectibleConstructorParams<TKEY, TINDEX>
202
+ ): Result<Collectible<TKEY, TINDEX>>;
203
+
204
+ public static createCollectible<TKEY extends string = string, TINDEX extends number = number>(
205
+ params: ICollectibleConstructorParams<TKEY, TINDEX>
206
+ ): Result<Collectible<TKEY, TINDEX>> {
207
+ return captureResult(() => new Collectible(params));
208
+ }
209
+
210
+ /**
211
+ * {@link Collections.ICollectible.setIndex}
212
+ */
213
+ public setIndex(index: number): Result<TINDEX> {
214
+ let converted: TINDEX | undefined;
215
+ if (this._indexConverter) {
216
+ const { value, message } = this._indexConverter.convert(index);
217
+ /* c8 ignore next 3 - there's a test for this but coverage is having a bad day */
218
+ if (message) {
219
+ return fail(message);
220
+ }
221
+ converted = value;
222
+ }
223
+
224
+ if (index === this.index) {
225
+ return succeed(this.index);
226
+ } else if (this._index !== undefined) {
227
+ return fail(`index ${this.index} is immutable and cannot be changed to ${index}`);
228
+ }
229
+
230
+ /* c8 ignore next 3 - should be impossible */
231
+ if (converted === undefined) {
232
+ return fail(`index ${index} cannot be set on a Collectible without an index converter`);
233
+ }
234
+
235
+ this._index = converted;
236
+ return succeed(converted);
237
+ }
238
+ }