@ezez/utils 3.0.0 → 4.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 (175) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/omit.d.ts +1 -1
  7. package/dist/omit.d.ts.map +1 -1
  8. package/dist/omit.js.map +1 -1
  9. package/dist/replaceDeep.d.ts +5 -1
  10. package/dist/replaceDeep.d.ts.map +1 -1
  11. package/dist/replaceDeep.js +3 -20
  12. package/dist/replaceDeep.js.map +1 -1
  13. package/dist/replaceDeepByFn.d.ts +7 -0
  14. package/dist/replaceDeepByFn.d.ts.map +1 -0
  15. package/dist/replaceDeepByFn.js +47 -0
  16. package/dist/replaceDeepByFn.js.map +1 -0
  17. package/dist/serialize.d.ts.map +1 -1
  18. package/dist/serialize.js +56 -18
  19. package/dist/serialize.js.map +1 -1
  20. package/dist/trim.d.ts +3 -0
  21. package/dist/trim.d.ts.map +1 -0
  22. package/dist/trim.js +10 -0
  23. package/dist/trim.js.map +1 -0
  24. package/dist/trimEnd.d.ts +3 -0
  25. package/dist/trimEnd.d.ts.map +1 -0
  26. package/dist/trimEnd.js +12 -0
  27. package/dist/trimEnd.js.map +1 -0
  28. package/dist/trimStart.d.ts +3 -0
  29. package/dist/trimStart.d.ts.map +1 -0
  30. package/dist/trimStart.js +12 -0
  31. package/dist/trimStart.js.map +1 -0
  32. package/dist/utils/utils.d.ts +6 -0
  33. package/dist/utils/utils.d.ts.map +1 -0
  34. package/dist/utils/utils.js +10 -0
  35. package/dist/utils/utils.js.map +1 -0
  36. package/docs/assets/search.js +1 -1
  37. package/docs/functions/cap.html +8 -5
  38. package/docs/functions/capitalize.html +8 -5
  39. package/docs/functions/coalesce.html +8 -5
  40. package/docs/functions/compareArrays.html +8 -5
  41. package/docs/functions/compareProps.html +8 -5
  42. package/docs/functions/deserialize.html +8 -5
  43. package/docs/functions/ensureArray.html +8 -5
  44. package/docs/functions/ensureDate.html +8 -5
  45. package/docs/functions/ensureError.html +8 -5
  46. package/docs/functions/ensurePrefix.html +8 -5
  47. package/docs/functions/ensureSuffix.html +8 -5
  48. package/docs/functions/ensureTimestamp.html +8 -5
  49. package/docs/functions/escapeRegExp.html +8 -5
  50. package/docs/functions/formatDate.html +8 -5
  51. package/docs/functions/get.html +8 -5
  52. package/docs/functions/getMultiple.html +8 -5
  53. package/docs/functions/insertSeparator.html +8 -5
  54. package/docs/functions/isEmpty.html +8 -5
  55. package/docs/functions/isNumericString.html +8 -5
  56. package/docs/functions/isPlainObject.html +8 -5
  57. package/docs/functions/last.html +8 -5
  58. package/docs/functions/later-1.html +8 -5
  59. package/docs/functions/mapAsync.html +8 -5
  60. package/docs/functions/mapValues.html +8 -5
  61. package/docs/functions/match.html +8 -5
  62. package/docs/functions/merge.html +16 -13
  63. package/docs/functions/mostFrequent.html +8 -5
  64. package/docs/functions/noop.html +8 -5
  65. package/docs/functions/occurrences.html +8 -5
  66. package/docs/functions/omit.html +14 -7
  67. package/docs/functions/pick.html +9 -6
  68. package/docs/functions/pull.html +8 -5
  69. package/docs/functions/remove.html +8 -5
  70. package/docs/functions/removeCommonProperties.html +8 -5
  71. package/docs/functions/replace.html +8 -5
  72. package/docs/functions/replaceDeep.html +19 -7
  73. package/docs/functions/rethrow.html +8 -5
  74. package/docs/functions/round.html +8 -5
  75. package/docs/functions/safe.html +9 -6
  76. package/docs/functions/sample.html +8 -5
  77. package/docs/functions/samples.html +8 -5
  78. package/docs/functions/scale.html +8 -5
  79. package/docs/functions/seq.html +8 -5
  80. package/docs/functions/seqEarlyBreak.html +8 -5
  81. package/docs/functions/serialize.html +8 -5
  82. package/docs/functions/set.html +8 -5
  83. package/docs/functions/setImmutable.html +8 -5
  84. package/docs/functions/shuffle.html +8 -5
  85. package/docs/functions/sortBy.html +8 -5
  86. package/docs/functions/sortProps.html +8 -5
  87. package/docs/functions/stripPrefix.html +8 -5
  88. package/docs/functions/stripSuffix.html +8 -5
  89. package/docs/functions/throttle.html +8 -5
  90. package/docs/functions/toggle.html +8 -5
  91. package/docs/functions/trim.html +152 -0
  92. package/docs/functions/trimEnd.html +152 -0
  93. package/docs/functions/trimStart.html +152 -0
  94. package/docs/functions/truthy.html +8 -5
  95. package/docs/functions/unique.html +8 -5
  96. package/docs/functions/wait.html +8 -5
  97. package/docs/functions/waitFor.html +8 -5
  98. package/docs/functions/waitSync.html +8 -5
  99. package/docs/index.html +7 -4
  100. package/docs/interfaces/ComparePropsOptions.html +6 -6
  101. package/docs/interfaces/GetMultipleSource.html +8 -5
  102. package/docs/interfaces/GetSource.html +8 -5
  103. package/docs/interfaces/IsNumericStringOptions.html +9 -9
  104. package/docs/interfaces/OccurencesOptions.html +6 -6
  105. package/docs/interfaces/SetImmutableSource.html +8 -5
  106. package/docs/interfaces/SetSource.html +8 -5
  107. package/docs/interfaces/ThrottleOptions.html +7 -7
  108. package/docs/interfaces/ThrottledFunctionExtras.html +7 -7
  109. package/docs/modules.html +10 -4
  110. package/docs/pages/CHANGELOG.html +113 -64
  111. package/docs/pages/Introduction.html +7 -4
  112. package/docs/types/CustomDeserializers.html +8 -5
  113. package/docs/types/CustomSerializers.html +8 -5
  114. package/docs/types/Later.html +8 -5
  115. package/docs/types/MapValuesFn.html +8 -5
  116. package/docs/types/MatchCallback.html +8 -5
  117. package/docs/types/SeqEarlyBreaker.html +8 -5
  118. package/docs/types/SeqFn.html +8 -5
  119. package/docs/types/SeqFunctions.html +8 -5
  120. package/docs/types/SetImmutablePath.html +8 -5
  121. package/docs/types/ThrottledFunction.html +8 -5
  122. package/docs/variables/mapValuesUNSET.html +8 -5
  123. package/docs/variables/mergeUNSET.html +8 -5
  124. package/esm/index.d.ts +3 -0
  125. package/esm/index.d.ts.map +1 -1
  126. package/esm/index.js +3 -0
  127. package/esm/index.js.map +1 -1
  128. package/esm/omit.d.ts +1 -1
  129. package/esm/omit.d.ts.map +1 -1
  130. package/esm/omit.js.map +1 -1
  131. package/esm/replaceDeep.d.ts +5 -1
  132. package/esm/replaceDeep.d.ts.map +1 -1
  133. package/esm/replaceDeep.js +3 -20
  134. package/esm/replaceDeep.js.map +1 -1
  135. package/esm/replaceDeepByFn.d.ts +7 -0
  136. package/esm/replaceDeepByFn.d.ts.map +1 -0
  137. package/esm/replaceDeepByFn.js +44 -0
  138. package/esm/replaceDeepByFn.js.map +1 -0
  139. package/esm/serialize.d.ts.map +1 -1
  140. package/esm/serialize.js +56 -18
  141. package/esm/serialize.js.map +1 -1
  142. package/esm/trim.d.ts +3 -0
  143. package/esm/trim.d.ts.map +1 -0
  144. package/esm/trim.js +7 -0
  145. package/esm/trim.js.map +1 -0
  146. package/esm/trimEnd.d.ts +3 -0
  147. package/esm/trimEnd.d.ts.map +1 -0
  148. package/esm/trimEnd.js +9 -0
  149. package/esm/trimEnd.js.map +1 -0
  150. package/esm/trimStart.d.ts +3 -0
  151. package/esm/trimStart.d.ts.map +1 -0
  152. package/esm/trimStart.js +9 -0
  153. package/esm/trimStart.js.map +1 -0
  154. package/esm/utils/utils.d.ts +6 -0
  155. package/esm/utils/utils.d.ts.map +1 -0
  156. package/esm/utils/utils.js +7 -0
  157. package/esm/utils/utils.js.map +1 -0
  158. package/package.json +1 -1
  159. package/src/deserialize.spec.ts +12 -0
  160. package/src/index.ts +3 -0
  161. package/src/omit.ts +8 -2
  162. package/src/pick.ts +1 -1
  163. package/src/replaceDeep.spec.ts +91 -0
  164. package/src/replaceDeep.ts +22 -27
  165. package/src/replaceDeepByFn.spec.ts +162 -0
  166. package/src/replaceDeepByFn.ts +93 -0
  167. package/src/serialize.spec.ts +42 -0
  168. package/src/serialize.ts +65 -18
  169. package/src/trim.spec.ts +22 -0
  170. package/src/trim.ts +23 -0
  171. package/src/trimEnd.spec.ts +20 -0
  172. package/src/trimEnd.ts +22 -0
  173. package/src/trimStart.spec.ts +20 -0
  174. package/src/trimStart.ts +22 -0
  175. package/src/utils/utils.ts +11 -0
package/esm/serialize.js CHANGED
@@ -1,5 +1,29 @@
1
1
  import { sortProps } from "./sortProps.js";
2
+ import { replaceDeepByFn } from "./replaceDeepByFn.js";
3
+ import { isPlainObject } from "./isPlainObject.js";
4
+ import { DataWrapper } from "./utils/utils.js";
2
5
  const serialize = (data, customSerializers, options) => {
6
+ const sourceData = Object.keys(customSerializers ?? {}).length
7
+ ? replaceDeepByFn(data, value => {
8
+ if (["string", "number", "bigint", "undefined", "boolean"].includes(typeof value)) {
9
+ return false;
10
+ }
11
+ if (value === null || Array.isArray(value)) {
12
+ return false;
13
+ }
14
+ if (isPlainObject(value)) {
15
+ return false;
16
+ }
17
+ const serializerKeys = Object.keys(customSerializers ?? {});
18
+ for (const key of serializerKeys) {
19
+ const serialized = customSerializers[key](value);
20
+ if (typeof serialized === "string") {
21
+ return true;
22
+ }
23
+ }
24
+ return false;
25
+ }, value => new DataWrapper(value))
26
+ : data;
3
27
  const replacer = (_key, value) => {
4
28
  if (typeof value === "string") {
5
29
  return `s:${value}`;
@@ -19,40 +43,54 @@ const serialize = (data, customSerializers, options) => {
19
43
  if (value === null) {
20
44
  return "l:";
21
45
  }
46
+ if (Array.isArray(value)) {
47
+ return value;
48
+ }
49
+ if (isPlainObject(value)) {
50
+ return value;
51
+ }
22
52
  const serializerKeys = Object.keys(customSerializers ?? {});
23
53
  for (const key of serializerKeys) {
24
- const serialized = customSerializers[key](value);
54
+ const serialized = customSerializers[key](value instanceof DataWrapper ? value.data : value);
25
55
  if (typeof serialized === "string") {
26
56
  return `${key}:${serialized}`;
27
57
  }
58
+ if (serialized !== null) {
59
+ throw new Error(`Custom serializer for key ${key} returned a non-string value: ${String(serialized)}`);
60
+ }
28
61
  }
29
62
  if (typeof value === "object") {
30
63
  return value;
31
64
  }
32
65
  throw new Error(`Unsupported data type: ${typeof value}`);
33
66
  };
34
- if (data == null
35
- || typeof data === "string"
36
- || typeof data === "number"
37
- || typeof data === "bigint"
38
- || typeof data === "undefined"
39
- || typeof data === "boolean"
40
- || Array.isArray(data)) {
41
- return JSON.stringify(data, replacer);
67
+ if (sourceData == null
68
+ || typeof sourceData === "string"
69
+ || typeof sourceData === "number"
70
+ || typeof sourceData === "bigint"
71
+ || typeof sourceData === "undefined"
72
+ || typeof sourceData === "boolean"
73
+ || Array.isArray(sourceData)) {
74
+ return JSON.stringify(sourceData, replacer);
42
75
  }
43
- const serializerKeysGlobal = Object.keys(customSerializers ?? {});
44
- for (const key of serializerKeysGlobal) {
45
- const serialized = customSerializers[key](data);
46
- if (typeof serialized === "string") {
47
- return `"${key}:${serialized}"`;
76
+ if (!isPlainObject(sourceData)) {
77
+ const serializerKeysGlobal = Object.keys(customSerializers ?? {});
78
+ for (const key of serializerKeysGlobal) {
79
+ const serialized = customSerializers[key](sourceData instanceof DataWrapper ? sourceData.data : sourceData);
80
+ if (typeof serialized === "string") {
81
+ return `"${key}:${serialized}"`;
82
+ }
83
+ if (serialized !== null) {
84
+ throw new Error(`Custom serializer for key ${key} returned a non-string value: ${String(serialized)}`);
85
+ }
48
86
  }
49
87
  }
50
- if (typeof data === "object") {
88
+ if (typeof sourceData === "object") {
51
89
  return JSON.stringify(options?.sortProps === false
52
- ? data
53
- : sortProps(data), replacer);
90
+ ? sourceData
91
+ : sortProps(sourceData), replacer);
54
92
  }
55
- throw new Error(`Unsupported data type: ${typeof data}`);
93
+ throw new Error(`Unsupported data type: ${typeof sourceData}`);
56
94
  };
57
95
  export { serialize };
58
96
  //# sourceMappingURL=serialize.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAkC3C,MAAM,SAAS,GAAG,CAAC,IAAa,EAAE,iBAAqC,EAAE,OAAiB,EAAE,EAAE;IAC1F,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC3B,OAAO,KAAK,KAAK,EAAE,CAAC;SACvB;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC3B,OAAO,KAAK,KAAK,EAAE,CAAC;SACvB;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC3B,OAAO,KAAK,KAAK,EAAE,CAAC;SACvB;QACD,IAAI,OAAO,KAAK,KAAK,WAAW,EAAE;YAC9B,OAAO,IAAI,CAAC;SACf;QACD,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE;YAC5B,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACpC;QACD,IAAI,KAAK,KAAK,IAAI,EAAE;YAChB,OAAO,IAAI,CAAC;SACf;QACD,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE;YAC9B,MAAM,UAAU,GAAG,iBAAkB,CAAC,GAAG,CAAE,CAAC,KAAK,CAAC,CAAC;YACnD,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;gBAChC,OAAO,GAAG,GAAG,IAAI,UAAU,EAAE,CAAC;aACjC;SACJ;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC3B,OAAO,KAAK,CAAC;SAChB;QAED,MAAM,IAAI,KAAK,CAAC,0BAA0B,OAAO,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC;IAEF,IACI,IAAI,IAAI,IAAI;WACT,OAAO,IAAI,KAAK,QAAQ;WACxB,OAAO,IAAI,KAAK,QAAQ;WACxB,OAAO,IAAI,KAAK,QAAQ;WACxB,OAAO,IAAI,KAAK,WAAW;WAC3B,OAAO,IAAI,KAAK,SAAS;WACzB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EACxB;QACE,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;KACzC;IAED,MAAM,oBAAoB,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;IAClE,KAAK,MAAM,GAAG,IAAI,oBAAoB,EAAE;QACpC,MAAM,UAAU,GAAG,iBAAkB,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;YAChC,OAAO,IAAI,GAAG,IAAI,UAAU,GAAG,CAAC;SACnC;KACJ;IAED,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC1B,OAAO,IAAI,CAAC,SAAS,CACjB,OAAO,EAAE,SAAS,KAAK,KAAK;YACxB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,SAAS,CAAC,IAA+B,CAAC,EAChD,QAAQ,CACX,CAAC;KACL;IAED,MAAM,IAAI,KAAK,CAAC,0BAA0B,OAAO,IAAI,EAAE,CAAC,CAAC;AAC7D,CAAC,CAAC;AAGF,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"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"}
package/esm/trim.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ declare const trim: (source: string, characters: string) => string;
2
+ export { trim, };
3
+ //# sourceMappingURL=trim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim.d.ts","sourceRoot":"","sources":["../src/trim.ts"],"names":[],"mappings":"AAgBA,QAAA,MAAM,IAAI,WAAY,MAAM,cAAc,MAAM,WAE/C,CAAC;AAEF,OAAO,EACH,IAAI,GACP,CAAC"}
package/esm/trim.js ADDED
@@ -0,0 +1,7 @@
1
+ import { trimStart } from "./trimStart.js";
2
+ import { trimEnd } from "./trimEnd.js";
3
+ const trim = (source, characters) => {
4
+ return trimStart(trimEnd(source, characters), characters);
5
+ };
6
+ export { trim, };
7
+ //# sourceMappingURL=trim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim.js","sourceRoot":"","sources":["../src/trim.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAevC,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,UAAkB,EAAE,EAAE;IAChD,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;AAC9D,CAAC,CAAC;AAEF,OAAO,EACH,IAAI,GACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const trimEnd: (source: string, characters: string) => string;
2
+ export { trimEnd, };
3
+ //# sourceMappingURL=trimEnd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trimEnd.d.ts","sourceRoot":"","sources":["../src/trimEnd.ts"],"names":[],"mappings":"AAWA,QAAA,MAAM,OAAO,WAAY,MAAM,cAAc,MAAM,WAMlD,CAAC;AAEF,OAAO,EACH,OAAO,GACV,CAAC"}
package/esm/trimEnd.js ADDED
@@ -0,0 +1,9 @@
1
+ const trimEnd = (source, characters) => {
2
+ let s = source;
3
+ while (s.endsWith(characters)) {
4
+ s = s.slice(0, -characters.length);
5
+ }
6
+ return s;
7
+ };
8
+ export { trimEnd, };
9
+ //# sourceMappingURL=trimEnd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trimEnd.js","sourceRoot":"","sources":["../src/trimEnd.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,UAAkB,EAAE,EAAE;IACnD,IAAI,CAAC,GAAG,MAAM,CAAC;IACf,OAAO,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;QAC3B,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;KACtC;IACD,OAAO,CAAC,CAAC;AACb,CAAC,CAAC;AAEF,OAAO,EACH,OAAO,GACV,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const trimStart: (source: string, characters: string) => string;
2
+ export { trimStart, };
3
+ //# sourceMappingURL=trimStart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trimStart.d.ts","sourceRoot":"","sources":["../src/trimStart.ts"],"names":[],"mappings":"AAWA,QAAA,MAAM,SAAS,WAAY,MAAM,cAAc,MAAM,WAMpD,CAAC;AAEF,OAAO,EACH,SAAS,GACZ,CAAC"}
@@ -0,0 +1,9 @@
1
+ const trimStart = (source, characters) => {
2
+ let s = source;
3
+ while (s.startsWith(characters)) {
4
+ s = s.slice(characters.length);
5
+ }
6
+ return s;
7
+ };
8
+ export { trimStart, };
9
+ //# sourceMappingURL=trimStart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trimStart.js","sourceRoot":"","sources":["../src/trimStart.ts"],"names":[],"mappings":"AAWA,MAAM,SAAS,GAAG,CAAC,MAAc,EAAE,UAAkB,EAAE,EAAE;IACrD,IAAI,CAAC,GAAG,MAAM,CAAC;IACf,OAAO,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QAC7B,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;KAClC;IACD,OAAO,CAAC,CAAC;AACb,CAAC,CAAC;AAEF,OAAO,EACH,SAAS,GACZ,CAAC"}
@@ -0,0 +1,6 @@
1
+ declare class DataWrapper<T> {
2
+ data: T;
3
+ constructor(data: T);
4
+ }
5
+ export { DataWrapper, };
6
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAAA,cAAM,WAAW,CAAC,CAAC;IACR,IAAI,EAAE,CAAC,CAAC;gBAEI,IAAI,EAAE,CAAC;CAG7B;AAED,OAAO,EACH,WAAW,GACd,CAAC"}
@@ -0,0 +1,7 @@
1
+ class DataWrapper {
2
+ constructor(data) {
3
+ this.data = data;
4
+ }
5
+ }
6
+ export { DataWrapper, };
7
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW;IAGb,YAAmB,IAAO;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;CACJ;AAED,OAAO,EACH,WAAW,GACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ezez/utils",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "repository": "https://github.com/dzek69/bottom-line.git",
5
5
  "author": "Jacek Nowacki @dzek69 <git-public@dzek.eu>",
6
6
  "license": "MIT",
@@ -66,4 +66,16 @@ describe("deserialize", () => {
66
66
  it("throws on unknown data type", () => {
67
67
  must(() => deserialize(`"v:test"`)).throw("Unsupported data type: v");
68
68
  });
69
+
70
+ it("supports deserializers with things like Date", async () => {
71
+ const customSerializers: CustomDeserializers = {
72
+ D: (value) => {
73
+ return new Date(Number(value));
74
+ },
75
+ };
76
+
77
+ const result = deserialize(`"D:1714398481437"`, customSerializers);
78
+ must(result).be.instanceof(Date);
79
+ must(result.getTime()).equal(1714398481437);
80
+ });
69
81
  });
package/src/index.ts CHANGED
@@ -52,6 +52,9 @@ export * from "./stripPrefix.js";
52
52
  export * from "./stripSuffix.js";
53
53
  export * from "./throttle.js";
54
54
  export * from "./toggle.js";
55
+ export * from "./trim.js";
56
+ export * from "./trimEnd.js";
57
+ export * from "./trimStart.js";
55
58
  export * from "./truthy.js";
56
59
  export * from "./unique.js";
57
60
  export * from "./wait.js";
package/src/omit.ts CHANGED
@@ -1,7 +1,13 @@
1
1
  // TODO verify & maybe fix typings when object is an Array
2
2
 
3
3
  /**
4
- * Returns new object with copied all properties without these specified.
4
+ * Returns a cloned source object but without specified properties.
5
+ *
6
+ * TypeScript tip: if you want to omit properties that TS think does not exist in the object, call the function like
7
+ * that:
8
+ * ```typescript
9
+ * omit<Record<string, unknown>>(source, ["property"]);
10
+ * ```
5
11
  *
6
12
  * @param {Object} object - source object
7
13
  * @param {Array.<string>} props - properties to skip
@@ -13,7 +19,7 @@
13
19
  * // { 1: "world" }
14
20
  * @returns {Object} - new object without given properties
15
21
  */
16
- const omit = <T extends object, K extends keyof T>(
22
+ const omit = <T extends object, K extends keyof T = keyof T>(
17
23
  object: T | null, props: K[],
18
24
  ): T extends null ? { [key: string]: never } : Omit<T, K> => {
19
25
  if (!object || (typeof object !== "object" && typeof object !== "function")) {
package/src/pick.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // TODO verify & maybe fix typings when object is an Array
2
2
 
3
3
  /**
4
- * Returns new object with copied given properties from source object.
4
+ * Returns a new object with given properties copied from a source object.
5
5
  *
6
6
  * @param {Object} object - source object
7
7
  * @param {Array.<string>} props - properties to copy
@@ -1,5 +1,13 @@
1
1
  import { replaceDeep } from "./replaceDeep";
2
2
 
3
+ class MyClass {
4
+ public value: number;
5
+
6
+ public constructor(value: number) {
7
+ this.value = value;
8
+ }
9
+ }
10
+
3
11
  describe("replaceDeep", () => {
4
12
  it("should replace given value in a deep object", () => {
5
13
  const source = [
@@ -68,4 +76,87 @@ describe("replaceDeep", () => {
68
76
  b: 123,
69
77
  });
70
78
  });
79
+
80
+ it("should allow to replace nils", async () => {
81
+ must(replaceDeep(null, null, 300)).equal(300);
82
+ // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
83
+ must(replaceDeep(undefined, undefined, 300)).equal(300);
84
+ });
85
+
86
+ it("does not mutate original object", () => {
87
+ const source = {
88
+ a: 1,
89
+ b: {
90
+ c: 2,
91
+ },
92
+ };
93
+ const result = replaceDeep(source, 2, 3);
94
+ must(result).not.equal(source);
95
+ must(result.b).not.equal(source.b);
96
+ must(result).eql({
97
+ a: 1,
98
+ b: {
99
+ c: 3,
100
+ },
101
+ });
102
+ });
103
+
104
+ it("does not mutate original array", async () => {
105
+ const source = [1, 2, 3, [2, 3]];
106
+ const result = replaceDeep(source, 2, 4);
107
+ must(result).not.equal(source);
108
+ must(result[3]).not.equal(source[3]);
109
+ must(result).eql([1, 4, 3, [4, 3]]);
110
+ });
111
+
112
+ it("mutates original object when enabled", () => {
113
+ const source = {
114
+ a: 1,
115
+ b: {
116
+ c: 2,
117
+ },
118
+ };
119
+ const result = replaceDeep(source, 2, 3, { mutate: true });
120
+ must(result).equal(source);
121
+ must(result.b).equal(source.b);
122
+ must(result).eql({
123
+ a: 1,
124
+ b: {
125
+ c: 3,
126
+ },
127
+ });
128
+ });
129
+
130
+ it("mutates original array when enabled", async () => {
131
+ const source = [1, 2, 3, [2, 3]];
132
+ const result = replaceDeep(source, 2, 4, { mutate: true });
133
+ must(result).equal(source);
134
+ must(result[3]).equal(source[3]);
135
+ must(result).eql([1, 4, 3, [4, 3]]);
136
+ });
137
+
138
+ it("does not get into instances by default", async () => {
139
+ const source = new MyClass(100);
140
+ const result = replaceDeep(source, 100, 200);
141
+ must(result).equal(source);
142
+ must(source.value).equal(100);
143
+ });
144
+
145
+ it("gets into instances when allowed", async () => {
146
+ const source = new MyClass(100);
147
+ const result = replaceDeep(source, 100, 200, {
148
+ replaceInstancesProps: true,
149
+ mutate: true,
150
+ });
151
+ must(result).equal(source);
152
+ must(source.value).equal(200);
153
+ });
154
+
155
+ it("requires `mutate` option if `replaceInstancesProps` is defined", async () => {
156
+ const source = new MyClass(100);
157
+ must(() => replaceDeep(source, 100, 200, {
158
+ replaceInstancesProps: true,
159
+ mutate: false,
160
+ })).throw("`replaceInstancesProps` option requires `mutate` to be enabled");
161
+ });
71
162
  });
@@ -1,8 +1,26 @@
1
+ import { replaceDeepByFn } from "./replaceDeepByFn.js";
2
+
3
+ type Options = {
4
+ /**
5
+ * If true, the source objects and arrays will be mutated. Default is false.
6
+ */
7
+ mutate?: boolean;
8
+ /**
9
+ * If true, the function will go into instances for replacement. Otherwise, it will only replace properties of plain
10
+ * objects. Default is false.
11
+ * Warning: This option requires `mutate` to be enabled, because we can't clone instances.
12
+ */
13
+ replaceInstancesProps?: boolean;
14
+ };
15
+
1
16
  /**
2
17
  * Replaces all occurrences of `search` with `value` in `source` object/array. Comparison is done with `Object.is`.
3
18
  * If `source` is exactly the `search` a `value` will be returned. It does not do a substring replacements.
4
19
  *
5
- * It mutates the `source` object/array!
20
+ * Warnings:
21
+ * - By default, it does not mutate the `source`/deep objects/arrays, but it can be enabled with `mutate` option.
22
+ * - By default, it does not go into instances for replacement, only plain objects.
23
+ * - If your instances are cross-referenced, you may end up in an infinite loop.
6
24
  *
7
25
  * TypeScript users: This is way too dynamic to type properly, therefore, typing assumes the most basic form of
8
26
  * replacement where search and value are of the same type. If that's not the case for you - you'll have to typecast.
@@ -10,33 +28,10 @@
10
28
  * @param source - source object/array/value
11
29
  * @param search - value to search for
12
30
  * @param value - value to replace with
31
+ * @param options - optional options
13
32
  */
14
- const replaceDeep = <T>(source: T, search: unknown, value: unknown): T => {
15
- if (Object.is(source, search)) {
16
- return value as T;
17
- }
18
-
19
- if (source == null) {
20
- return source;
21
- }
22
-
23
- if (typeof source === "object") {
24
- if (Array.isArray(source)) {
25
- for (let i = 0; i < source.length; i++) {
26
- // eslint-disable-next-line no-param-reassign,@typescript-eslint/no-unsafe-assignment
27
- source[i] = replaceDeep(source[i], search, value);
28
- }
29
- return source;
30
- }
31
-
32
- return Object.keys(source).reduce<Record<string, unknown>>((acc, key) => {
33
- // eslint-disable-next-line no-param-reassign
34
- acc[key] = replaceDeep((source as Record<string, unknown>)[key], search, value);
35
- return acc;
36
- }, {}) as T;
37
- }
38
-
39
- return source;
33
+ const replaceDeep = <T>(source: T, search: unknown, value: unknown, options?: Options): T => {
34
+ return replaceDeepByFn(source, (v) => Object.is(v, search), () => value, options);
40
35
  };
41
36
 
42
37
  export {
@@ -0,0 +1,162 @@
1
+ import { replaceDeepByFn } from "./replaceDeepByFn";
2
+
3
+ class MyClass {
4
+ public value: number;
5
+
6
+ public constructor(value: number) {
7
+ this.value = value;
8
+ }
9
+ }
10
+
11
+ describe("replaceDeepByFn", () => {
12
+ it("should replace given value in a deep object", () => {
13
+ const source = [
14
+ 99,
15
+ 100,
16
+ {
17
+ favouriteBook: {
18
+ title: "The Ring of The Lord",
19
+ price: 100,
20
+ },
21
+ otherBooks: [
22
+ {
23
+ title: "Parry Hotter",
24
+ price: 50,
25
+ tag: "100",
26
+ },
27
+ {
28
+ title: "The Hobbyte 100",
29
+ price: [100],
30
+ },
31
+ ],
32
+ },
33
+ ];
34
+
35
+ must(replaceDeepByFn(source, v => v === 100, () => 200)).eql([
36
+ 99,
37
+ 200,
38
+ {
39
+ favouriteBook: {
40
+ title: "The Ring of The Lord",
41
+ price: 200,
42
+ },
43
+ otherBooks: [
44
+ {
45
+ title: "Parry Hotter",
46
+ price: 50,
47
+ tag: "100",
48
+ },
49
+ {
50
+ title: "The Hobbyte 100",
51
+ price: [200],
52
+ },
53
+ ],
54
+ },
55
+ ]);
56
+ });
57
+
58
+ it("should leave primitives as-is unless they equal to the search value", () => {
59
+ must(replaceDeepByFn(100, v => v === 200, () => 300)).equal(100);
60
+ must(replaceDeepByFn(200, v => v === 200, () => 300)).equal(300);
61
+ must(replaceDeepByFn("100", v => v === 200, () => 300)).equal("100");
62
+ // ESLINT BUG: (see replaceDeep.spec.ts)
63
+ // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
64
+ must(replaceDeepByFn(undefined, v => v === 200, () => 300)).equal(undefined);
65
+ must(replaceDeepByFn(null, v => v === 200, () => 300)).equal(null);
66
+ must(replaceDeepByFn(true, v => v === 200, () => 300)).equal(true);
67
+ must(replaceDeepByFn(666n, v => v === 200, () => 300)).equal(666n);
68
+ });
69
+
70
+ it("should work with nans", async () => {
71
+ must(replaceDeepByFn({
72
+ a: NaN,
73
+ b: 123,
74
+ }, v => Number.isNaN(v), () => 300)).eql({
75
+ a: 300,
76
+ b: 123,
77
+ });
78
+ });
79
+
80
+ it("should allow to replace nils", async () => {
81
+ must(replaceDeepByFn(null, v => v === null, () => 300)).equal(300);
82
+ // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
83
+ must(replaceDeepByFn(undefined, v => v === undefined, () => 300)).equal(300);
84
+ });
85
+
86
+ it("does not mutate the original object", () => {
87
+ const source = {
88
+ a: 1,
89
+ b: {
90
+ c: 2,
91
+ },
92
+ };
93
+ const result = replaceDeepByFn(source, v => v === 2, () => 3);
94
+ must(result).not.equal(source);
95
+ must(result.b).not.equal(source.b);
96
+ must(result).eql({
97
+ a: 1,
98
+ b: {
99
+ c: 3,
100
+ },
101
+ });
102
+ });
103
+
104
+ it("does not mutate original array", async () => {
105
+ const source = [1, 2, 3, [2, 3]];
106
+ const result = replaceDeepByFn(source, v => v === 2, () => 4);
107
+ must(result).not.equal(source);
108
+ must(result[3]).not.equal(source[3]);
109
+ must(result).eql([1, 4, 3, [4, 3]]);
110
+ });
111
+
112
+ it("mutates the original object when enabled", () => {
113
+ const source = {
114
+ a: 1,
115
+ b: {
116
+ c: 2,
117
+ },
118
+ };
119
+ const result = replaceDeepByFn(source, v => v === 2, () => 3, { mutate: true });
120
+ must(result).equal(source);
121
+ must(result.b).equal(source.b);
122
+ must(result).eql({
123
+ a: 1,
124
+ b: {
125
+ c: 3,
126
+ },
127
+ });
128
+ });
129
+
130
+ it("mutates original array when enabled", async () => {
131
+ const source = [1, 2, 3, [2, 3]];
132
+ const result = replaceDeepByFn(source, v => v === 2, () => 4, { mutate: true });
133
+ must(result).equal(source);
134
+ must(result[3]).equal(source[3]);
135
+ must(result).eql([1, 4, 3, [4, 3]]);
136
+ });
137
+
138
+ it("does not get into instances by default", async () => {
139
+ const source = new MyClass(100);
140
+ const result = replaceDeepByFn(source, v => v === 100, () => 200);
141
+ must(result).equal(source);
142
+ must(source.value).equal(100);
143
+ });
144
+
145
+ it("gets into instances when allowed", async () => {
146
+ const source = new MyClass(100);
147
+ const result = replaceDeepByFn(source, v => v === 100, () => 200, {
148
+ replaceInstancesProps: true,
149
+ mutate: true,
150
+ });
151
+ must(result).equal(source);
152
+ must(source.value).equal(200);
153
+ });
154
+
155
+ it("requires `mutate` option if `replaceInstancesProps` is defined", async () => {
156
+ const source = new MyClass(100);
157
+ must(() => replaceDeepByFn(source, v => v === 100, () => 200, {
158
+ replaceInstancesProps: true,
159
+ mutate: false,
160
+ })).throw("`replaceInstancesProps` option requires `mutate` to be enabled");
161
+ });
162
+ });