@ezez/utils 4.5.0 → 4.7.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 (375) hide show
  1. package/.github/workflows/docs.yml +4 -3
  2. package/CHANGELOG.md +20 -1
  3. package/README.md +19 -6
  4. package/dist/assertProps.d.ts +6 -0
  5. package/dist/assertProps.d.ts.map +1 -0
  6. package/dist/assertProps.js +11 -0
  7. package/dist/assertProps.js.map +1 -0
  8. package/dist/cap.d.ts.map +1 -1
  9. package/dist/cap.js.map +1 -1
  10. package/dist/capitalize.d.ts.map +1 -1
  11. package/dist/capitalize.js.map +1 -1
  12. package/dist/compareArrays.d.ts +4 -4
  13. package/dist/compareArrays.d.ts.map +1 -1
  14. package/dist/compareArrays.js.map +1 -1
  15. package/dist/ensureError.d.ts.map +1 -1
  16. package/dist/ensureError.js +3 -1
  17. package/dist/ensureError.js.map +1 -1
  18. package/dist/ensurePrefix.d.ts.map +1 -1
  19. package/dist/ensurePrefix.js.map +1 -1
  20. package/dist/ensureSuffix.d.ts.map +1 -1
  21. package/dist/ensureSuffix.js.map +1 -1
  22. package/dist/escapeRegExp.d.ts.map +1 -1
  23. package/dist/escapeRegExp.js.map +1 -1
  24. package/dist/formatDate.d.ts.map +1 -1
  25. package/dist/formatDate.js.map +1 -1
  26. package/dist/getMultiple.d.ts.map +1 -1
  27. package/dist/getMultiple.js.map +1 -1
  28. package/dist/hasProps.d.ts +3 -0
  29. package/dist/hasProps.d.ts.map +1 -0
  30. package/dist/hasProps.js +16 -0
  31. package/dist/hasProps.js.map +1 -0
  32. package/dist/ignore.d.ts +3 -0
  33. package/dist/ignore.d.ts.map +1 -0
  34. package/dist/ignore.js +16 -0
  35. package/dist/ignore.js.map +1 -0
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/isEmpty.d.ts.map +1 -1
  41. package/dist/isEmpty.js +4 -4
  42. package/dist/isEmpty.js.map +1 -1
  43. package/dist/isNumericString.d.ts.map +1 -1
  44. package/dist/isNumericString.js.map +1 -1
  45. package/dist/isPlainObject.d.ts.map +1 -1
  46. package/dist/isPlainObject.js.map +1 -1
  47. package/dist/match.d.ts.map +1 -1
  48. package/dist/match.js.map +1 -1
  49. package/dist/memoize.d.ts.map +1 -1
  50. package/dist/memoize.js.map +1 -1
  51. package/dist/mostFrequent.d.ts.map +1 -1
  52. package/dist/mostFrequent.js.map +1 -1
  53. package/dist/noop.d.ts.map +1 -1
  54. package/dist/noop.js.map +1 -1
  55. package/dist/occurrences.d.ts.map +1 -1
  56. package/dist/occurrences.js.map +1 -1
  57. package/dist/removeCommonProperties.d.ts.map +1 -1
  58. package/dist/removeCommonProperties.js.map +1 -1
  59. package/dist/replace.d.ts.map +1 -1
  60. package/dist/replace.js.map +1 -1
  61. package/dist/rethrow.d.ts +1 -1
  62. package/dist/rethrow.d.ts.map +1 -1
  63. package/dist/rethrow.js.map +1 -1
  64. package/dist/round.d.ts.map +1 -1
  65. package/dist/round.js.map +1 -1
  66. package/dist/safe.d.ts.map +1 -1
  67. package/dist/safe.js.map +1 -1
  68. package/dist/scale.d.ts.map +1 -1
  69. package/dist/scale.js.map +1 -1
  70. package/dist/seq.d.ts.map +1 -1
  71. package/dist/seq.js +5 -1
  72. package/dist/seq.js.map +1 -1
  73. package/dist/serialize.d.ts.map +1 -1
  74. package/dist/serialize.js +2 -2
  75. package/dist/serialize.js.map +1 -1
  76. package/dist/serializeToBuffer/serializeToBuffer.d.ts.map +1 -1
  77. package/dist/serializeToBuffer/serializeToBuffer.js.map +1 -1
  78. package/dist/serializeToBuffer/unserializeFromBuffer.d.ts.map +1 -1
  79. package/dist/serializeToBuffer/unserializeFromBuffer.js.map +1 -1
  80. package/dist/setImmutable.js.map +1 -1
  81. package/dist/sortBy.d.ts +1 -1
  82. package/dist/sortBy.d.ts.map +1 -1
  83. package/dist/sortBy.js.map +1 -1
  84. package/dist/sortByMultiple.d.ts +1 -1
  85. package/dist/sortByMultiple.d.ts.map +1 -1
  86. package/dist/sortByMultiple.js.map +1 -1
  87. package/dist/trim.d.ts.map +1 -1
  88. package/dist/trim.js +1 -1
  89. package/dist/trim.js.map +1 -1
  90. package/dist/trimEnd.d.ts.map +1 -1
  91. package/dist/trimEnd.js.map +1 -1
  92. package/dist/trimStart.d.ts.map +1 -1
  93. package/dist/trimStart.js.map +1 -1
  94. package/dist/unique.d.ts +1 -1
  95. package/dist/unique.d.ts.map +1 -1
  96. package/dist/unique.js.map +1 -1
  97. package/dist/utils/utils.js +1 -0
  98. package/dist/utils/utils.js.map +1 -1
  99. package/dist/wait.d.ts.map +1 -1
  100. package/dist/wait.js.map +1 -1
  101. package/dist/waitFor.d.ts.map +1 -1
  102. package/dist/waitFor.js.map +1 -1
  103. package/dist/waitSync.d.ts.map +1 -1
  104. package/dist/waitSync.js.map +1 -1
  105. package/docs/assets/hierarchy.js +1 -0
  106. package/docs/assets/icons.js +1 -1
  107. package/docs/assets/icons.svg +1 -1
  108. package/docs/assets/main.js +5 -5
  109. package/docs/assets/navigation.js +1 -1
  110. package/docs/assets/search.js +1 -1
  111. package/docs/assets/style.css +1405 -1288
  112. package/docs/documents/Changelog.html +377 -0
  113. package/docs/functions/index.cap.html +3 -3
  114. package/docs/functions/index.capitalize.html +7 -7
  115. package/docs/functions/index.coalesce.html +8 -8
  116. package/docs/functions/index.compareArrays.html +5 -5
  117. package/docs/functions/index.compareProps.html +5 -5
  118. package/docs/functions/index.deserialize.html +4 -4
  119. package/docs/functions/index.ensureArray.html +3 -3
  120. package/docs/functions/index.ensureDate.html +6 -6
  121. package/docs/functions/index.ensureError.html +6 -6
  122. package/docs/functions/index.ensurePrefix.html +5 -5
  123. package/docs/functions/index.ensureSuffix.html +5 -5
  124. package/docs/functions/index.ensureTimestamp.html +6 -6
  125. package/docs/functions/index.escapeRegExp.html +5 -5
  126. package/docs/functions/index.formatDate.html +5 -2
  127. package/docs/functions/index.get.html +8 -8
  128. package/docs/functions/index.getMultiple.html +6 -6
  129. package/docs/functions/index.ignore.html +8 -0
  130. package/docs/functions/index.insertSeparator.html +5 -5
  131. package/docs/functions/index.isEmpty.html +12 -13
  132. package/docs/functions/index.isNumericString.html +3 -3
  133. package/docs/functions/index.isPlainObject.html +8 -8
  134. package/docs/functions/index.last.html +7 -7
  135. package/docs/functions/index.later-1.html +3 -3
  136. package/docs/functions/index.mapAsync.html +5 -5
  137. package/docs/functions/index.mapValues.html +7 -7
  138. package/docs/functions/index.match.html +7 -4
  139. package/docs/functions/index.memoize.html +4 -4
  140. package/docs/functions/index.merge.html +6 -6
  141. package/docs/functions/index.mostFrequent.html +2 -2
  142. package/docs/functions/index.noop.html +2 -2
  143. package/docs/functions/index.occurrences.html +7 -6
  144. package/docs/functions/index.omit.html +7 -7
  145. package/docs/functions/index.pick.html +7 -7
  146. package/docs/functions/index.pull.html +2 -2
  147. package/docs/functions/index.race.html +5 -5
  148. package/docs/functions/index.remove.html +2 -2
  149. package/docs/functions/index.removeCommonProperties.html +5 -5
  150. package/docs/functions/index.replace.html +6 -6
  151. package/docs/functions/index.replaceDeep.html +3 -3
  152. package/docs/functions/index.rethrow.html +2 -2
  153. package/docs/functions/index.retry.html +4 -4
  154. package/docs/functions/index.round.html +4 -4
  155. package/docs/functions/index.safe.html +5 -5
  156. package/docs/functions/index.sample.html +4 -4
  157. package/docs/functions/index.samples.html +3 -3
  158. package/docs/functions/index.scale.html +2 -2
  159. package/docs/functions/index.seq.html +7 -7
  160. package/docs/functions/index.seqEarlyBreak.html +6 -6
  161. package/docs/functions/index.serialize.html +3 -3
  162. package/docs/functions/index.serializeToBuffer.html +7 -7
  163. package/docs/functions/index.set.html +8 -8
  164. package/docs/functions/index.setImmutable.html +7 -7
  165. package/docs/functions/index.shuffle.html +3 -3
  166. package/docs/functions/index.sortBy.html +3 -3
  167. package/docs/functions/index.sortByMultiple.html +5 -5
  168. package/docs/functions/index.sortProps.html +4 -4
  169. package/docs/functions/index.stripPrefix.html +3 -3
  170. package/docs/functions/index.stripSuffix.html +3 -3
  171. package/docs/functions/index.throttle.html +4 -4
  172. package/docs/functions/index.toggle.html +4 -4
  173. package/docs/functions/index.trim.html +4 -4
  174. package/docs/functions/index.trimEnd.html +4 -4
  175. package/docs/functions/index.trimStart.html +4 -4
  176. package/docs/functions/index.truthy.html +4 -4
  177. package/docs/functions/index.unique.html +4 -4
  178. package/docs/functions/index.unserializeFromBuffer.html +6 -6
  179. package/docs/functions/index.wait.html +3 -3
  180. package/docs/functions/index.waitFor.html +4 -4
  181. package/docs/functions/index.waitSync.html +3 -3
  182. package/docs/index.html +35 -22
  183. package/docs/interfaces/index.ComparePropsOptions.html +4 -4
  184. package/docs/interfaces/index.GetMultipleSource.html +3 -3
  185. package/docs/interfaces/index.GetSource.html +3 -3
  186. package/docs/interfaces/index.IsNumericStringOptions.html +5 -5
  187. package/docs/interfaces/index.OccurencesOptions.html +2 -2
  188. package/docs/interfaces/index.SetImmutableSource.html +3 -3
  189. package/docs/interfaces/index.SetSource.html +3 -3
  190. package/docs/interfaces/index.ThrottleOptions.html +3 -3
  191. package/docs/interfaces/index.ThrottledFunctionExtras.html +4 -4
  192. package/docs/modules/index.html +1 -93
  193. package/docs/modules.html +1 -3
  194. package/docs/types/index.CustomDeserializers.html +1 -1
  195. package/docs/types/index.CustomSerializers.html +1 -1
  196. package/docs/types/index.Later.html +4 -4
  197. package/docs/types/index.MapValuesFn.html +7 -7
  198. package/docs/types/index.MatchCallback.html +1 -1
  199. package/docs/types/index.MergeTwo.html +2 -2
  200. package/docs/types/index.SeqEarlyBreaker.html +4 -4
  201. package/docs/types/index.SeqFn.html +3 -3
  202. package/docs/types/index.SeqFunctions.html +3 -3
  203. package/docs/types/index.SetImmutablePath.html +2 -2
  204. package/docs/types/index.ThrottledFunction.html +1 -1
  205. package/docs/variables/index.mapValuesUNSET.html +2 -2
  206. package/docs/variables/index.mergeUNSET.html +3 -3
  207. package/esm/assertProps.d.ts +6 -0
  208. package/esm/assertProps.d.ts.map +1 -0
  209. package/esm/assertProps.js +8 -0
  210. package/esm/assertProps.js.map +1 -0
  211. package/esm/cap.d.ts.map +1 -1
  212. package/esm/cap.js.map +1 -1
  213. package/esm/capitalize.d.ts.map +1 -1
  214. package/esm/capitalize.js.map +1 -1
  215. package/esm/compareArrays.d.ts +4 -4
  216. package/esm/compareArrays.d.ts.map +1 -1
  217. package/esm/compareArrays.js.map +1 -1
  218. package/esm/ensureError.d.ts.map +1 -1
  219. package/esm/ensureError.js +3 -1
  220. package/esm/ensureError.js.map +1 -1
  221. package/esm/ensurePrefix.d.ts.map +1 -1
  222. package/esm/ensurePrefix.js.map +1 -1
  223. package/esm/ensureSuffix.d.ts.map +1 -1
  224. package/esm/ensureSuffix.js.map +1 -1
  225. package/esm/escapeRegExp.d.ts.map +1 -1
  226. package/esm/escapeRegExp.js.map +1 -1
  227. package/esm/formatDate.d.ts.map +1 -1
  228. package/esm/formatDate.js.map +1 -1
  229. package/esm/getMultiple.d.ts.map +1 -1
  230. package/esm/getMultiple.js.map +1 -1
  231. package/esm/hasProps.d.ts +3 -0
  232. package/esm/hasProps.d.ts.map +1 -0
  233. package/esm/hasProps.js +13 -0
  234. package/esm/hasProps.js.map +1 -0
  235. package/esm/ignore.d.ts +3 -0
  236. package/esm/ignore.d.ts.map +1 -0
  237. package/esm/ignore.js +13 -0
  238. package/esm/ignore.js.map +1 -0
  239. package/esm/index.d.ts +1 -0
  240. package/esm/index.d.ts.map +1 -1
  241. package/esm/index.js +1 -0
  242. package/esm/index.js.map +1 -1
  243. package/esm/isEmpty.d.ts.map +1 -1
  244. package/esm/isEmpty.js +4 -4
  245. package/esm/isEmpty.js.map +1 -1
  246. package/esm/isNumericString.d.ts.map +1 -1
  247. package/esm/isNumericString.js.map +1 -1
  248. package/esm/isPlainObject.d.ts.map +1 -1
  249. package/esm/isPlainObject.js.map +1 -1
  250. package/esm/match.d.ts.map +1 -1
  251. package/esm/match.js.map +1 -1
  252. package/esm/memoize.d.ts.map +1 -1
  253. package/esm/memoize.js.map +1 -1
  254. package/esm/mostFrequent.d.ts.map +1 -1
  255. package/esm/mostFrequent.js.map +1 -1
  256. package/esm/noop.d.ts.map +1 -1
  257. package/esm/noop.js.map +1 -1
  258. package/esm/occurrences.d.ts.map +1 -1
  259. package/esm/occurrences.js.map +1 -1
  260. package/esm/removeCommonProperties.d.ts.map +1 -1
  261. package/esm/removeCommonProperties.js.map +1 -1
  262. package/esm/replace.d.ts.map +1 -1
  263. package/esm/replace.js.map +1 -1
  264. package/esm/rethrow.d.ts +1 -1
  265. package/esm/rethrow.d.ts.map +1 -1
  266. package/esm/rethrow.js.map +1 -1
  267. package/esm/round.d.ts.map +1 -1
  268. package/esm/round.js.map +1 -1
  269. package/esm/safe.d.ts.map +1 -1
  270. package/esm/safe.js.map +1 -1
  271. package/esm/scale.d.ts.map +1 -1
  272. package/esm/scale.js.map +1 -1
  273. package/esm/seq.d.ts.map +1 -1
  274. package/esm/seq.js +5 -1
  275. package/esm/seq.js.map +1 -1
  276. package/esm/serialize.d.ts.map +1 -1
  277. package/esm/serialize.js +2 -2
  278. package/esm/serialize.js.map +1 -1
  279. package/esm/serializeToBuffer/serializeToBuffer.d.ts.map +1 -1
  280. package/esm/serializeToBuffer/serializeToBuffer.js.map +1 -1
  281. package/esm/serializeToBuffer/unserializeFromBuffer.d.ts.map +1 -1
  282. package/esm/serializeToBuffer/unserializeFromBuffer.js.map +1 -1
  283. package/esm/setImmutable.js.map +1 -1
  284. package/esm/sortBy.d.ts +1 -1
  285. package/esm/sortBy.d.ts.map +1 -1
  286. package/esm/sortBy.js.map +1 -1
  287. package/esm/sortByMultiple.d.ts +1 -1
  288. package/esm/sortByMultiple.d.ts.map +1 -1
  289. package/esm/sortByMultiple.js.map +1 -1
  290. package/esm/trim.d.ts.map +1 -1
  291. package/esm/trim.js +1 -1
  292. package/esm/trim.js.map +1 -1
  293. package/esm/trimEnd.d.ts.map +1 -1
  294. package/esm/trimEnd.js.map +1 -1
  295. package/esm/trimStart.d.ts.map +1 -1
  296. package/esm/trimStart.js.map +1 -1
  297. package/esm/unique.d.ts +1 -1
  298. package/esm/unique.d.ts.map +1 -1
  299. package/esm/unique.js.map +1 -1
  300. package/esm/utils/utils.js +1 -0
  301. package/esm/utils/utils.js.map +1 -1
  302. package/esm/wait.d.ts.map +1 -1
  303. package/esm/wait.js.map +1 -1
  304. package/esm/waitFor.d.ts.map +1 -1
  305. package/esm/waitFor.js.map +1 -1
  306. package/esm/waitSync.d.ts.map +1 -1
  307. package/esm/waitSync.js.map +1 -1
  308. package/package.json +31 -34
  309. package/src/assertProps.spec.ts +128 -0
  310. package/src/assertProps.ts +37 -0
  311. package/src/cap.ts +1 -1
  312. package/src/capitalize.ts +3 -3
  313. package/src/compareArrays.ts +2 -3
  314. package/src/deserialize.spec.ts +2 -1
  315. package/src/ensureError.ts +6 -2
  316. package/src/ensurePrefix.ts +1 -1
  317. package/src/ensureSuffix.ts +1 -1
  318. package/src/escapeRegExp.ts +1 -1
  319. package/src/formatDate.ts +7 -2
  320. package/src/get.spec.ts +0 -1
  321. package/src/getMultiple.ts +0 -1
  322. package/src/hasProps.spec.ts +122 -0
  323. package/src/hasProps.ts +36 -0
  324. package/src/ignore.spec.ts +80 -0
  325. package/src/ignore.ts +38 -0
  326. package/src/index.ts +1 -0
  327. package/src/isEmpty.ts +9 -15
  328. package/src/isNumericString.ts +1 -1
  329. package/src/isPlainObject.ts +1 -1
  330. package/src/later.spec.ts +1 -0
  331. package/src/mapAsync.ts +4 -4
  332. package/src/match.ts +2 -1
  333. package/src/memoize.spec.ts +1 -1
  334. package/src/memoize.ts +1 -1
  335. package/src/mostFrequent.spec.ts +2 -0
  336. package/src/mostFrequent.ts +0 -1
  337. package/src/noop.ts +1 -1
  338. package/src/occurrences.ts +1 -1
  339. package/src/remove.spec.ts +1 -1
  340. package/src/removeCommonProperties.spec.ts +2 -0
  341. package/src/removeCommonProperties.ts +1 -1
  342. package/src/replace.ts +1 -1
  343. package/src/replaceDeep.spec.ts +2 -0
  344. package/src/replaceDeepByFn.spec.ts +2 -0
  345. package/src/rethrow.ts +1 -1
  346. package/src/round.ts +1 -1
  347. package/src/safe.ts +2 -1
  348. package/src/scale.ts +1 -1
  349. package/src/seq.ts +7 -3
  350. package/src/serialize.spec.ts +2 -1
  351. package/src/serialize.ts +3 -3
  352. package/src/serializeToBuffer/serialization.spec.ts +2 -2
  353. package/src/serializeToBuffer/serializeToBuffer.ts +0 -1
  354. package/src/serializeToBuffer/unserializeFromBuffer.ts +0 -1
  355. package/src/setImmutable.ts +1 -1
  356. package/src/sortBy.ts +3 -1
  357. package/src/sortByMultiple.ts +5 -3
  358. package/src/toggle.spec.ts +2 -0
  359. package/src/trim.spec.ts +2 -0
  360. package/src/trim.ts +3 -2
  361. package/src/trimEnd.spec.ts +2 -0
  362. package/src/trimEnd.ts +1 -1
  363. package/src/trimStart.spec.ts +2 -0
  364. package/src/trimStart.ts +1 -1
  365. package/src/unique.ts +2 -2
  366. package/src/wait.ts +1 -1
  367. package/src/waitFor.spec.ts +9 -8
  368. package/src/waitFor.ts +1 -1
  369. package/src/waitSync.spec.ts +2 -0
  370. package/src/waitSync.ts +1 -1
  371. package/.prettierignore +0 -3
  372. package/.prettierrc.json +0 -1
  373. package/docs/documents/CHANGELOG.html +0 -357
  374. package/pnpm-lock.yaml +0 -6529
  375. package/typedoc.cjs +0 -3
@@ -0,0 +1,128 @@
1
+ import must from "must"; // eslint-disable-line @typescript-eslint/no-shadow
2
+
3
+ import { assertProps } from "./assertProps";
4
+
5
+ describe("assertProps", () => {
6
+ it("should not throw for object with valid string properties", () => {
7
+ const obj = { id: "123", name: "John" };
8
+ must(() => { assertProps(obj, { id: "string", name: "string" }); }).not.throw();
9
+ });
10
+
11
+ it("should not throw for object with valid number properties", () => {
12
+ const obj = { age: 25, count: 100 };
13
+ must(() => { assertProps(obj, { age: "number", count: "number" }); }).not.throw();
14
+ });
15
+
16
+ it("should not throw for object with valid boolean properties", () => {
17
+ const obj = { isActive: true, isDeleted: false };
18
+ must(() => {
19
+ assertProps(obj, { isActive: "boolean", isDeleted: "boolean" });
20
+ }).not.throw();
21
+ });
22
+
23
+ it("should not throw for object with mixed property types", () => {
24
+ const obj = { id: "123", age: 30, isActive: true };
25
+ must(() => {
26
+ assertProps(obj, { id: "string", age: "number", isActive: "boolean" });
27
+ }).not.throw();
28
+ });
29
+
30
+ it("should throw for object with wrong property type", () => {
31
+ const obj = { id: 123, name: "John" };
32
+ must(() => {
33
+ assertProps(obj, { id: "string", name: "string" });
34
+ }).throw("Object does not match the required schema");
35
+ });
36
+
37
+ it("should throw for object missing required property", () => {
38
+ const obj = { id: "123" };
39
+ must(() => {
40
+ assertProps(obj, { id: "string", name: "string" });
41
+ }).throw("Object does not match the required schema");
42
+ });
43
+
44
+ it("should throw for null", () => {
45
+ must(() => {
46
+ assertProps(null, { id: "string" });
47
+ }).throw("Object does not match the required schema");
48
+ });
49
+
50
+ it("should throw for undefined", () => {
51
+ must(() => {
52
+ assertProps(undefined, { id: "string" });
53
+ }).throw("Object does not match the required schema");
54
+ });
55
+
56
+ it("should throw for array", () => {
57
+ const arr = [{ id: "123" }];
58
+ must(() => {
59
+ assertProps(arr, { id: "string" });
60
+ }).throw("Object does not match the required schema");
61
+ });
62
+
63
+ it("should throw for primitive string", () => {
64
+ must(() => {
65
+ assertProps("test", { id: "string" });
66
+ }).throw("Object does not match the required schema");
67
+ });
68
+
69
+ it("should throw for primitive number", () => {
70
+ must(() => {
71
+ assertProps(123, { id: "string" });
72
+ }).throw("Object does not match the required schema");
73
+ });
74
+
75
+ it("should throw for primitive boolean", () => {
76
+ must(() => {
77
+ assertProps(true, { id: "string" });
78
+ }).throw("Object does not match the required schema");
79
+ });
80
+
81
+ it("should not throw for empty schema", () => {
82
+ const obj = { id: "123", name: "John" };
83
+ must(() => { assertProps(obj, {}); }).not.throw();
84
+ });
85
+
86
+ it("should allow extra properties on the object", () => {
87
+ const obj = { id: "123", name: "John", extra: "value" };
88
+ must(() => { assertProps(obj, { id: "string", name: "string" }); }).not.throw();
89
+ });
90
+
91
+ it("should throw for objects with null property values", () => {
92
+ const obj = { id: null, name: "John" };
93
+ must(() => {
94
+ assertProps(obj, { id: "string", name: "string" });
95
+ }).throw("Object does not match the required schema");
96
+ });
97
+
98
+ it("should throw for objects with undefined property values", () => {
99
+ const obj = { id: undefined, name: "John" };
100
+ must(() => {
101
+ assertProps(obj, { id: "string", name: "string" });
102
+ }).throw("Object does not match the required schema");
103
+ });
104
+
105
+ it("should correctly validate boolean false value", () => {
106
+ const obj = { isActive: false };
107
+ must(() => { assertProps(obj, { isActive: "boolean" }); }).not.throw();
108
+ });
109
+
110
+ it("should correctly validate number zero value", () => {
111
+ const obj = { count: 0 };
112
+ must(() => { assertProps(obj, { count: "number" }); }).not.throw();
113
+ });
114
+
115
+ it("should correctly validate empty string value", () => {
116
+ const obj = { name: "" };
117
+ must(() => { assertProps(obj, { name: "string" }); }).not.throw();
118
+ });
119
+
120
+ it("should work with objects source only", async () => {
121
+ const source = () => null;
122
+ must(source).have.property("name", "source");
123
+
124
+ must(() => {
125
+ assertProps(source, { name: "string" });
126
+ }).throw("Object does not match the required schema");
127
+ });
128
+ });
@@ -0,0 +1,37 @@
1
+ import { hasProps } from "./hasProps";
2
+
3
+ type AssertPropsFn = <T extends Record<string, "string" | "number" | "boolean">>(
4
+ obj: unknown,
5
+ schema: T,
6
+ ) => asserts obj is {
7
+ [K in keyof T]:
8
+ T[K] extends "string" ? string
9
+ : T[K] extends "number" ? number
10
+ : T[K] extends "boolean" ? boolean
11
+ : never
12
+ };
13
+
14
+ /**
15
+ * Asserts that an object has the specified properties with the specified types. Ideal for quick runtime type checking
16
+ * of API responses if you don't need a full schema validation.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const validated = assertProps(obj, { id: "string", age: "number" });
21
+ * // obj is runtime validated and type is now narrowed down to { id: string; age: number }
22
+ * // if the assertion fails, an error is thrown
23
+ * console.log(obj.id, obj.age);
24
+ * ```
25
+ */
26
+ const assertProps: AssertPropsFn = <T extends Record<string, "string" | "number" | "boolean">>(
27
+ obj: unknown,
28
+ schema: T,
29
+ ) => {
30
+ if (!hasProps(obj, schema)) {
31
+ throw new Error("Object does not match the required schema");
32
+ }
33
+ };
34
+
35
+ export {
36
+ assertProps,
37
+ };
package/src/cap.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * @param {number} upperLimit - upper limit, inclusive
5
5
  * @param {number} [lowerLimit] - lower limit, inclusive
6
6
  */
7
- const cap = (value: number, upperLimit: number, lowerLimit?: number) => {
7
+ const cap = (value: number, upperLimit: number, lowerLimit?: number): number => {
8
8
  if (lowerLimit == null) {
9
9
  return Math.min(value, upperLimit);
10
10
  }
package/src/capitalize.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Capitalize the first letter of a string.
3
- * @param {string} text - source string
4
- * @param {boolean} [restLowercase=false] - should the rest of the string be forced to lowercase?
3
+ * @param text - source string
4
+ * @param restLowercase - should the rest of the string be forced to lowercase?
5
5
  * @example capitalize("hello") // "Hello"
6
6
  * @example capitalize("hello my Friend", true) // "Hello my friend"
7
7
  * @example capitalize("hello my Friend", false) // "Hello my Friend"
8
8
  */
9
- const capitalize = (text: string, restLowercase = false) => {
9
+ const capitalize = (text: string, restLowercase = false): string => {
10
10
  const rest = restLowercase ? text.slice(1).toLowerCase() : text.slice(1);
11
11
  return text.charAt(0).toUpperCase() + rest;
12
12
  };
@@ -9,12 +9,11 @@ import { unique } from "./unique.js";
9
9
  * onlyB - items that exists only in second array,
10
10
  * both - items that exists in both arrays
11
11
  */
12
- const compareArrays = <T extends unknown[]>(arrayA: T, arrayB: T): { onlyA: T; onlyB: T; both: T } => {
12
+ const compareArrays = <T>(arrayA: T[], arrayB: T[]): { onlyA: T[]; onlyB: T[]; both: T[] } => {
13
13
  const onlyA = unique(arrayA.filter((item) => !arrayB.includes(item)));
14
14
  const onlyB = unique(arrayB.filter((item) => !arrayA.includes(item)));
15
15
  const both = unique(arrayA.filter((item) => arrayB.includes(item)));
16
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
17
- return { onlyA, onlyB, both } as { onlyA: T; onlyB: T; both: T };
16
+ return { onlyA, onlyB, both };
18
17
  };
19
18
 
20
19
  export {
@@ -1,3 +1,5 @@
1
+ import must from "must"; // eslint-disable-line @typescript-eslint/no-shadow
2
+
1
3
  import type { CustomDeserializers } from "./deserialize";
2
4
 
3
5
  import { deserialize } from "./deserialize";
@@ -5,7 +7,6 @@ import { deserialize } from "./deserialize";
5
7
  class Person {
6
8
  public name: string;
7
9
 
8
- // eslint-disable-next-line @typescript-eslint/no-shadow
9
10
  public constructor(name: string) {
10
11
  this.name = name;
11
12
  }
@@ -10,11 +10,15 @@
10
10
  * @param {*} e - value to check
11
11
  * @returns Error - original error or new Error instance
12
12
  */
13
- const ensureError = (e: unknown) => {
13
+ const ensureError = (e: unknown): Error => {
14
14
  if (e instanceof Error) {
15
15
  return e;
16
16
  }
17
- return new Error("Expected error instance, got something else: " + String(e));
17
+
18
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
19
+ return new Error("Expected error instance, got something else: " + String(e), {
20
+ cause: e,
21
+ });
18
22
  };
19
23
 
20
24
  export {
@@ -6,7 +6,7 @@
6
6
  * @param {string} string - string to add prefix to
7
7
  * @param {string} prefix - prefix to add
8
8
  */
9
- const ensurePrefix = (string: string, prefix: string) => {
9
+ const ensurePrefix = (string: string, prefix: string): string => {
10
10
  if (string.startsWith(prefix)) {
11
11
  return string;
12
12
  }
@@ -6,7 +6,7 @@
6
6
  * @param {string} string - string to add suffix to
7
7
  * @param {string} suffix - suffix to add
8
8
  */
9
- const ensureSuffix = (string: string, suffix: string) => {
9
+ const ensureSuffix = (string: string, suffix: string): string => {
10
10
  if (string.endsWith(suffix)) {
11
11
  return string;
12
12
  }
@@ -9,7 +9,7 @@
9
9
  * regex.test(badName); // true
10
10
  * ```
11
11
  */
12
- const escapeRegExp = (string: string) => {
12
+ const escapeRegExp = (string: string): string => {
13
13
  return string.replace(/[/\-\\^$*+?.()|[\]{}]/gu, "\\$&");
14
14
  };
15
15
 
package/src/formatDate.ts CHANGED
@@ -8,10 +8,15 @@ import { ensureDate } from "./ensureDate.js";
8
8
  *
9
9
  * Important: this is work in progress. All locale-based values are not supported yet. Formats that heavily depend on
10
10
  * locale won't ever be supported.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * formatDate(Date.now(), "%Y-%m-%d %H:%M:%S"); // ie: "2024-06-26 14:23:45"
15
+ * ```
11
16
  */
12
17
  const formatDate = (date: Date | number, format: string, locale = "en-US"): string => { // eslint-disable-line max-lines-per-function
13
18
  const d = ensureDate(date);
14
- return format.replace(/%([%a-zA-Z])/gu, (_, c) => {
19
+ return format.replace(/%([%a-zA-Z])/gu, (_, c: string) => {
15
20
  switch (c) {
16
21
  case "%": return "%";
17
22
  // Day
@@ -64,7 +69,7 @@ const formatDate = (date: Date | number, format: string, locale = "en-US"): stri
64
69
  case "n": return "\n";
65
70
  case "t": return "\t";
66
71
  }
67
- return c as string;
72
+ return c;
68
73
  });
69
74
  };
70
75
 
package/src/get.spec.ts CHANGED
@@ -54,7 +54,6 @@ describe("get", () => {
54
54
 
55
55
  it("doesn't parse string as js code, behaves NOT like lodash", () => {
56
56
  // Lodash intention-guessing example, inconsistency detected
57
- // eslint-disable-next-line @typescript-eslint/no-shadow
58
57
  const name = get(testObject, "product[name]");
59
58
  (name === undefined).must.be.true();
60
59
 
@@ -29,7 +29,6 @@ const DEFAULT = {};
29
29
  * @returns {*} - found value or default value
30
30
  */
31
31
  const getMultiple = (source: Source, defaultValue: unknown, ...paths: (string | string[])[]): unknown => {
32
- // eslint-disable-next-line @typescript-eslint/no-shadow
33
32
  const length = paths.length;
34
33
  for (let i = 0; i < length; i++) {
35
34
  const properties = paths[i]!;
@@ -0,0 +1,122 @@
1
+ import must from "must"; // eslint-disable-line @typescript-eslint/no-shadow
2
+
3
+ import { hasProps } from "./hasProps";
4
+
5
+ describe("hasProps", () => {
6
+ it("should return true for object with valid string properties", () => {
7
+ const obj = { id: "123", name: "John" };
8
+ const result = hasProps(obj, { id: "string", name: "string" });
9
+ must(result).be.true();
10
+ });
11
+
12
+ it("should return true for object with valid number properties", () => {
13
+ const obj = { age: 25, count: 100 };
14
+ const result = hasProps(obj, { age: "number", count: "number" });
15
+ must(result).be.true();
16
+ });
17
+
18
+ it("should return true for object with valid boolean properties", () => {
19
+ const obj = { isActive: true, isDeleted: false };
20
+ const result = hasProps(obj, { isActive: "boolean", isDeleted: "boolean" });
21
+ must(result).be.true();
22
+ });
23
+
24
+ it("should return true for object with mixed property types", () => {
25
+ const obj = { id: "123", age: 30, isActive: true };
26
+ const result = hasProps(obj, { id: "string", age: "number", isActive: "boolean" });
27
+ must(result).be.true();
28
+ });
29
+
30
+ it("should return false for object with wrong property type", () => {
31
+ const obj = { id: 123, name: "John" };
32
+ const result = hasProps(obj, { id: "string", name: "string" });
33
+ must(result).be.false();
34
+ });
35
+
36
+ it("should return false for object missing required property", () => {
37
+ const obj = { id: "123" };
38
+ const result = hasProps(obj, { id: "string", name: "string" });
39
+ must(result).be.false();
40
+ });
41
+
42
+ it("should return false for null", () => {
43
+ const result = hasProps(null, { id: "string" });
44
+ must(result).be.false();
45
+ });
46
+
47
+ it("should return false for undefined", () => {
48
+ const result = hasProps(undefined, { id: "string" });
49
+ must(result).be.false();
50
+ });
51
+
52
+ it("should return false for array", () => {
53
+ const arr = [{ id: "123" }];
54
+ const result = hasProps(arr, { id: "string" });
55
+ must(result).be.false();
56
+ });
57
+
58
+ it("should return false for primitive string", () => {
59
+ const result = hasProps("test", { id: "string" });
60
+ must(result).be.false();
61
+ });
62
+
63
+ it("should return false for primitive number", () => {
64
+ const result = hasProps(123, { id: "string" });
65
+ must(result).be.false();
66
+ });
67
+
68
+ it("should return false for primitive boolean", () => {
69
+ const result = hasProps(true, { id: "string" });
70
+ must(result).be.false();
71
+ });
72
+
73
+ it("should return true for empty schema", () => {
74
+ const obj = { id: "123", name: "John" };
75
+ const result = hasProps(obj, {});
76
+ must(result).be.true();
77
+ });
78
+
79
+ it("should allow extra properties on the object", () => {
80
+ const obj = { id: "123", name: "John", extra: "value" };
81
+ const result = hasProps(obj, { id: "string", name: "string" });
82
+ must(result).be.true();
83
+ });
84
+
85
+ it("should handle objects with null property values", () => {
86
+ const obj = { id: null, name: "John" };
87
+ const result = hasProps(obj, { id: "string", name: "string" });
88
+ must(result).be.false();
89
+ });
90
+
91
+ it("should handle objects with undefined property values", () => {
92
+ const obj = { id: undefined, name: "John" };
93
+ const result = hasProps(obj, { id: "string", name: "string" });
94
+ must(result).be.false();
95
+ });
96
+
97
+ it("should correctly validate boolean false value", () => {
98
+ const obj = { isActive: false };
99
+ const result = hasProps(obj, { isActive: "boolean" });
100
+ must(result).be.true();
101
+ });
102
+
103
+ it("should correctly validate number zero value", () => {
104
+ const obj = { count: 0 };
105
+ const result = hasProps(obj, { count: "number" });
106
+ must(result).be.true();
107
+ });
108
+
109
+ it("should correctly validate empty string value", () => {
110
+ const obj = { name: "" };
111
+ const result = hasProps(obj, { name: "string" });
112
+ must(result).be.true();
113
+ });
114
+
115
+ it("should work with objects source only", async () => {
116
+ const source = () => null;
117
+ must(source).have.property("name", "source");
118
+
119
+ const result = hasProps(source, { name: "string" });
120
+ must(result).be.false();
121
+ });
122
+ });
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Check if an object has the specified properties with the specified types. Ideal for quick runtime type checking of
3
+ * API responses if you don't need a full schema validation.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * const validated = hasProps(obj, { id: "string", age: "number" });
8
+ * if (validated) {
9
+ * // obj is runtime validated and type is now narrowed down to { id: string; age: number }
10
+ * console.log(obj.id, obj.age);
11
+ * }
12
+ * ```
13
+ */
14
+ const hasProps = <
15
+ T extends Record<string, "string" | "number" | "boolean">,
16
+ >(
17
+ obj: unknown,
18
+ schema: T,
19
+ ): obj is {
20
+ [K in keyof T]:
21
+ T[K] extends "string" ? string
22
+ : T[K] extends "number" ? number
23
+ : T[K] extends "boolean" ? boolean
24
+ : never
25
+ } => {
26
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj)) { return false; }
27
+ for (const [key, type] of Object.entries(schema)) {
28
+ // eslint-disable-next-line valid-typeof
29
+ if (typeof (obj as { [key]: unknown })[key] !== type) { return false; }
30
+ }
31
+ return true;
32
+ };
33
+
34
+ export {
35
+ hasProps,
36
+ };
@@ -0,0 +1,80 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-shadow
2
+ import must from "must";
3
+
4
+ // @ts-ignore
5
+ import createSpy from "../test/createSpy";
6
+ import { ignore } from "./ignore";
7
+ import { wait } from "./wait";
8
+
9
+ const syncCrashingFunction = createSpy(() => {
10
+ throw new Error("Sync function crashed");
11
+ });
12
+
13
+ const promiseTypedSyncCrashingFunction = createSpy((): Promise<void> => {
14
+ throw new Error("Promise typed sync function crashed");
15
+ });
16
+
17
+ const asyncCrashingFunction = createSpy(async () => {
18
+ throw new Error("Async function crashed");
19
+ });
20
+
21
+ const asyncCrashingFunctionSlow = createSpy(async () => {
22
+ await wait(500);
23
+ throw new Error("Async function crashed");
24
+ });
25
+
26
+ const get5 = createSpy(() => 5);
27
+
28
+ describe("ignore", () => {
29
+ beforeEach(() => {
30
+ syncCrashingFunction.__spy.reset();
31
+ promiseTypedSyncCrashingFunction.__spy.reset();
32
+ asyncCrashingFunction.__spy.reset();
33
+ asyncCrashingFunctionSlow.__spy.reset();
34
+ get5.__spy.reset();
35
+ });
36
+
37
+ it("it should not crash on sync function crash", async () => {
38
+ ignore(syncCrashingFunction);
39
+ ignore(promiseTypedSyncCrashingFunction);
40
+ // ^ technically this is also a sync crash
41
+ });
42
+
43
+ it("it should not crash on async function crash", async () => {
44
+ ignore(asyncCrashingFunction);
45
+ });
46
+
47
+ it("it should not wait for async function", async () => {
48
+ const now = Date.now();
49
+ ignore(asyncCrashingFunctionSlow);
50
+ const after = Date.now();
51
+ if (after - now > 100) {
52
+ throw new Error("Took too long, it waited for the async function");
53
+ }
54
+ });
55
+
56
+ it("should not return a value", async () => {
57
+ // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
58
+ const res = ignore(get5);
59
+ must(res).be.undefined();
60
+ });
61
+
62
+ it("actually calls the function", async () => {
63
+ must(syncCrashingFunction.__spy.calls.length).be.equal(0);
64
+ must(promiseTypedSyncCrashingFunction.__spy.calls.length).be.equal(0);
65
+ must(asyncCrashingFunction.__spy.calls.length).be.equal(0);
66
+ must(get5.__spy.calls.length).be.equal(0);
67
+
68
+ ignore(syncCrashingFunction);
69
+ must(syncCrashingFunction.__spy.calls.length).be.equal(1);
70
+
71
+ ignore(promiseTypedSyncCrashingFunction);
72
+ must(promiseTypedSyncCrashingFunction.__spy.calls.length).be.equal(1);
73
+
74
+ ignore(asyncCrashingFunction);
75
+ must(asyncCrashingFunction.__spy.calls.length).be.equal(1);
76
+
77
+ ignore(get5);
78
+ must(get5.__spy.calls.length).be.equal(1);
79
+ });
80
+ });
package/src/ignore.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A function that executes a callback and ignores it completely, if it throws an error, returns any value, rejects
3
+ * a promise - it will be all ignored. It will attach a catch handler to any returned promise to avoid unhandled
4
+ * rejections.
5
+ *
6
+ * Use it whenever you want to call a function, but you are not interested in its result or failure.
7
+ *
8
+ * @example
9
+ * ```javascript
10
+ * import { trackPageVisit } from "analytics-service";
11
+ *
12
+ * function onButtonClick() {
13
+ * ignore(() => trackPageVisit("button-click"));
14
+ * // ^ prevent uncaught errors or unhandled promise rejections from trackPageVisit
15
+ * }
16
+ * Promise.resolve(5).then(ignore(trackPageVisit)).then((value) => {
17
+ * console.log(value); // 5, won't ever crash due to errors in trackPageVisit
18
+ * });
19
+ * ```
20
+ * @param callback
21
+ */
22
+ const ignore = (callback: () => unknown): undefined => {
23
+ try {
24
+ // eslint-disable-next-line callback-return
25
+ const p = callback();
26
+ if (p && typeof p === "object"
27
+ && "then" in p && typeof p.then === "function"
28
+ && "catch" in p && typeof p.catch === "function") {
29
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
30
+ p.catch(() => null);
31
+ }
32
+ }
33
+ catch {}
34
+ };
35
+
36
+ export {
37
+ ignore,
38
+ };
package/src/index.ts CHANGED
@@ -17,6 +17,7 @@ export * from "./escapeRegExp.js";
17
17
  export * from "./formatDate.js";
18
18
  export * from "./get.js";
19
19
  export * from "./getMultiple.js";
20
+ export * from "./ignore.js";
20
21
  export * from "./insertSeparator.js";
21
22
  export * from "./isEmpty.js";
22
23
  export * from "./isNumericString.js";
package/src/isEmpty.ts CHANGED
@@ -1,11 +1,3 @@
1
- interface ObjectWithLength {
2
- length: number;
3
- }
4
-
5
- interface ObjectWithSize {
6
- size: number;
7
- }
8
-
9
1
  /**
10
2
  * Returns true if passed argument seems to be empty.
11
3
  * Nil values are empty.
@@ -15,7 +7,7 @@ interface ObjectWithSize {
15
7
  * Arrays and array-like objects are considered empty when length value is 0.
16
8
  * Map, Set and -like objects are considered empty when size value is 0.
17
9
  *
18
- * @param {*} obj - source value
10
+ * @param obj - source value
19
11
  * @example isEmpty({}) // true
20
12
  * @example isEmpty(100) // throws
21
13
  * @example isEmpty([]) // true
@@ -23,9 +15,11 @@ interface ObjectWithSize {
23
15
  * @example isEmpty({ length: 5 }) // false
24
16
  * @example isEmpty({ length: 0 }) // true
25
17
  * @example isEmpty({ size: 0 }) // true
26
- * @returns {boolean} - is value considered empty
18
+ * @returns is value considered empty
19
+ *
20
+ * @deprecated This function is not needed in a modern, type-safe code and is encouraging bad practices in general.
27
21
  */
28
- const isEmpty = (obj: unknown) => {
22
+ const isEmpty = (obj: unknown): boolean => {
29
23
  if (typeof obj === "string") {
30
24
  return !obj.length;
31
25
  }
@@ -38,11 +32,11 @@ const isEmpty = (obj: unknown) => {
38
32
  if (Array.isArray(obj)) {
39
33
  return !Object.keys(obj).length;
40
34
  }
41
- if ("length" in obj) {
42
- return !(obj as ObjectWithLength).length;
35
+ if ("length" in obj && typeof obj.length === "number") {
36
+ return !(obj).length;
43
37
  }
44
- if ("size" in obj) {
45
- return !(obj as ObjectWithSize).size;
38
+ if ("size" in obj && typeof obj.size === "number") {
39
+ return !(obj).size;
46
40
  }
47
41
  return !Object.keys(obj).length;
48
42
  };
@@ -17,7 +17,7 @@ const NOT_FOUND = -1;
17
17
  * @param {boolean} [options.allowInfinity=false] - Allow Infinity and -Infinity (casing matters)
18
18
  * @param {boolean} [options.allowNaN=false] - Allow NaN (casing matters)
19
19
  */
20
- const isNumericString = (string: string, options: Options = {}) => { // eslint-disable-line max-statements, max-lines-per-function
20
+ const isNumericString = (string: string, options: Options = {}): boolean => { // eslint-disable-line max-statements, max-lines-per-function
21
21
  if (typeof string !== "string") {
22
22
  throw new TypeError("Expected a string");
23
23
  }