@ezez/utils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +3 -0
- package/.prettierrc.json +1 -0
- package/CHANGELOG.md +244 -0
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/babel.config.cjs +6 -0
- package/dist/cap.d.ts +3 -0
- package/dist/cap.d.ts.map +1 -0
- package/dist/cap.js +14 -0
- package/dist/cap.js.map +1 -0
- package/dist/capitalize.d.ts +3 -0
- package/dist/capitalize.d.ts.map +1 -0
- package/dist/capitalize.js +9 -0
- package/dist/capitalize.js.map +1 -0
- package/dist/coalesce.d.ts +3 -0
- package/dist/coalesce.d.ts.map +1 -0
- package/dist/coalesce.js +14 -0
- package/dist/coalesce.js.map +1 -0
- package/dist/ensureArray.d.ts +3 -0
- package/dist/ensureArray.d.ts.map +1 -0
- package/dist/ensureArray.js +11 -0
- package/dist/ensureArray.js.map +1 -0
- package/dist/ensureError.d.ts +3 -0
- package/dist/ensureError.d.ts.map +1 -0
- package/dist/ensureError.js +11 -0
- package/dist/ensureError.js.map +1 -0
- package/dist/get.d.ts +7 -0
- package/dist/get.d.ts.map +1 -0
- package/dist/get.js +19 -0
- package/dist/get.js.map +1 -0
- package/dist/getMultiple.d.ts +7 -0
- package/dist/getMultiple.d.ts.map +1 -0
- package/dist/getMultiple.js +18 -0
- package/dist/getMultiple.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/insertSeparator.d.ts +3 -0
- package/dist/insertSeparator.d.ts.map +1 -0
- package/dist/insertSeparator.js +18 -0
- package/dist/insertSeparator.js.map +1 -0
- package/dist/isEmpty.d.ts +3 -0
- package/dist/isEmpty.d.ts.map +1 -0
- package/dist/isEmpty.js +26 -0
- package/dist/isEmpty.js.map +1 -0
- package/dist/isPlainObject.d.ts +3 -0
- package/dist/isPlainObject.d.ts.map +1 -0
- package/dist/isPlainObject.js +10 -0
- package/dist/isPlainObject.js.map +1 -0
- package/dist/last.d.ts +3 -0
- package/dist/last.d.ts.map +1 -0
- package/dist/last.js +6 -0
- package/dist/last.js.map +1 -0
- package/dist/mapAsync.d.ts +3 -0
- package/dist/mapAsync.d.ts.map +1 -0
- package/dist/mapAsync.js +22 -0
- package/dist/mapAsync.js.map +1 -0
- package/dist/mapValues.d.ts +6 -0
- package/dist/mapValues.d.ts.map +1 -0
- package/dist/mapValues.js +18 -0
- package/dist/mapValues.js.map +1 -0
- package/dist/match.d.ts +8 -0
- package/dist/match.d.ts.map +1 -0
- package/dist/match.js +20 -0
- package/dist/match.js.map +1 -0
- package/dist/merge.d.ts +15 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +28 -0
- package/dist/merge.js.map +1 -0
- package/dist/mostFrequent.d.ts +3 -0
- package/dist/mostFrequent.d.ts.map +1 -0
- package/dist/mostFrequent.js +21 -0
- package/dist/mostFrequent.js.map +1 -0
- package/dist/noop.d.ts +3 -0
- package/dist/noop.d.ts.map +1 -0
- package/dist/noop.js +6 -0
- package/dist/noop.js.map +1 -0
- package/dist/omit.d.ts +5 -0
- package/dist/omit.d.ts.map +1 -0
- package/dist/omit.js +21 -0
- package/dist/omit.js.map +1 -0
- package/dist/package.json +1 -0
- package/dist/pick.d.ts +5 -0
- package/dist/pick.d.ts.map +1 -0
- package/dist/pick.js +20 -0
- package/dist/pick.js.map +1 -0
- package/dist/pull.d.ts +3 -0
- package/dist/pull.d.ts.map +1 -0
- package/dist/pull.js +14 -0
- package/dist/pull.js.map +1 -0
- package/dist/remove.d.ts +3 -0
- package/dist/remove.d.ts.map +1 -0
- package/dist/remove.js +18 -0
- package/dist/remove.js.map +1 -0
- package/dist/rethrow.d.ts +3 -0
- package/dist/rethrow.d.ts.map +1 -0
- package/dist/rethrow.js +8 -0
- package/dist/rethrow.js.map +1 -0
- package/dist/scale.d.ts +3 -0
- package/dist/scale.d.ts.map +1 -0
- package/dist/scale.js +8 -0
- package/dist/scale.js.map +1 -0
- package/dist/seq.d.ts +8 -0
- package/dist/seq.d.ts.map +1 -0
- package/dist/seq.js +45 -0
- package/dist/seq.js.map +1 -0
- package/dist/set.d.ts +7 -0
- package/dist/set.d.ts.map +1 -0
- package/dist/set.js +25 -0
- package/dist/set.js.map +1 -0
- package/dist/setImmutable.d.ts +8 -0
- package/dist/setImmutable.d.ts.map +1 -0
- package/dist/setImmutable.js +59 -0
- package/dist/setImmutable.js.map +1 -0
- package/dist/sortBy.d.ts +3 -0
- package/dist/sortBy.d.ts.map +1 -0
- package/dist/sortBy.js +15 -0
- package/dist/sortBy.js.map +1 -0
- package/dist/throttle.d.ts +13 -0
- package/dist/throttle.d.ts.map +1 -0
- package/dist/throttle.js +82 -0
- package/dist/throttle.js.map +1 -0
- package/dist/truthy.d.ts +3 -0
- package/dist/truthy.d.ts.map +1 -0
- package/dist/truthy.js +8 -0
- package/dist/truthy.js.map +1 -0
- package/dist/wait.d.ts +3 -0
- package/dist/wait.d.ts.map +1 -0
- package/dist/wait.js +10 -0
- package/dist/wait.js.map +1 -0
- package/dist/waitFor.d.ts +3 -0
- package/dist/waitFor.d.ts.map +1 -0
- package/dist/waitFor.js +34 -0
- package/dist/waitFor.js.map +1 -0
- package/dist/waitSync.d.ts +3 -0
- package/dist/waitSync.d.ts.map +1 -0
- package/dist/waitSync.js +9 -0
- package/dist/waitSync.js.map +1 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/highlight.css +78 -0
- package/docs/assets/main.js +58 -0
- package/docs/assets/pages.css +14 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1280 -0
- package/docs/functions/cap.html +116 -0
- package/docs/functions/capitalize.html +121 -0
- package/docs/functions/coalesce.html +127 -0
- package/docs/functions/ensureArray.html +114 -0
- package/docs/functions/ensureError.html +110 -0
- package/docs/functions/get.html +138 -0
- package/docs/functions/getMultiple.html +129 -0
- package/docs/functions/insertSeparator.html +123 -0
- package/docs/functions/isEmpty.html +139 -0
- package/docs/functions/isPlainObject.html +108 -0
- package/docs/functions/last.html +126 -0
- package/docs/functions/mapAsync.html +144 -0
- package/docs/functions/mapValues.html +130 -0
- package/docs/functions/match.html +122 -0
- package/docs/functions/merge.html +464 -0
- package/docs/functions/mostFrequent.html +111 -0
- package/docs/functions/noop.html +101 -0
- package/docs/functions/omit.html +129 -0
- package/docs/functions/pick.html +129 -0
- package/docs/functions/pull.html +113 -0
- package/docs/functions/remove.html +129 -0
- package/docs/functions/rethrow.html +106 -0
- package/docs/functions/scale.html +117 -0
- package/docs/functions/seq.html +128 -0
- package/docs/functions/seqEarlyBreak.html +126 -0
- package/docs/functions/set.html +138 -0
- package/docs/functions/setImmutable.html +137 -0
- package/docs/functions/sortBy.html +135 -0
- package/docs/functions/throttle.html +131 -0
- package/docs/functions/truthy.html +118 -0
- package/docs/functions/wait.html +109 -0
- package/docs/functions/waitFor.html +130 -0
- package/docs/functions/waitSync.html +109 -0
- package/docs/index.html +182 -0
- package/docs/interfaces/GetMultipleSource.html +106 -0
- package/docs/interfaces/GetSource.html +106 -0
- package/docs/interfaces/SetImmutableSource.html +106 -0
- package/docs/interfaces/SetSource.html +106 -0
- package/docs/interfaces/ThrottleOptions.html +80 -0
- package/docs/interfaces/ThrottledFunctionExtras.html +96 -0
- package/docs/modules.html +152 -0
- package/docs/pages/Introduction.html +94 -0
- package/docs/types/MapValuesFn.html +134 -0
- package/docs/types/MatchCallback.html +113 -0
- package/docs/types/SeqEarlyBreaker.html +114 -0
- package/docs/types/SeqFn.html +112 -0
- package/docs/types/SeqFunctions.html +105 -0
- package/docs/types/SetImmutablePath.html +99 -0
- package/docs/types/ThrottledFunction.html +113 -0
- package/docs/variables/mapValuesUNSET.html +101 -0
- package/docs/variables/mergeUNSET.html +103 -0
- package/esm/cap.d.ts +3 -0
- package/esm/cap.d.ts.map +1 -0
- package/esm/cap.js +11 -0
- package/esm/cap.js.map +1 -0
- package/esm/capitalize.d.ts +3 -0
- package/esm/capitalize.d.ts.map +1 -0
- package/esm/capitalize.js +6 -0
- package/esm/capitalize.js.map +1 -0
- package/esm/coalesce.d.ts +3 -0
- package/esm/coalesce.d.ts.map +1 -0
- package/esm/coalesce.js +11 -0
- package/esm/coalesce.js.map +1 -0
- package/esm/ensureArray.d.ts +3 -0
- package/esm/ensureArray.d.ts.map +1 -0
- package/esm/ensureArray.js +8 -0
- package/esm/ensureArray.js.map +1 -0
- package/esm/ensureError.d.ts +3 -0
- package/esm/ensureError.d.ts.map +1 -0
- package/esm/ensureError.js +8 -0
- package/esm/ensureError.js.map +1 -0
- package/esm/get.d.ts +7 -0
- package/esm/get.d.ts.map +1 -0
- package/esm/get.js +16 -0
- package/esm/get.js.map +1 -0
- package/esm/getMultiple.d.ts +7 -0
- package/esm/getMultiple.d.ts.map +1 -0
- package/esm/getMultiple.js +15 -0
- package/esm/getMultiple.js.map +1 -0
- package/esm/index.d.ts +33 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +33 -0
- package/esm/index.js.map +1 -0
- package/esm/insertSeparator.d.ts +3 -0
- package/esm/insertSeparator.d.ts.map +1 -0
- package/esm/insertSeparator.js +15 -0
- package/esm/insertSeparator.js.map +1 -0
- package/esm/isEmpty.d.ts +3 -0
- package/esm/isEmpty.d.ts.map +1 -0
- package/esm/isEmpty.js +23 -0
- package/esm/isEmpty.js.map +1 -0
- package/esm/isPlainObject.d.ts +3 -0
- package/esm/isPlainObject.d.ts.map +1 -0
- package/esm/isPlainObject.js +7 -0
- package/esm/isPlainObject.js.map +1 -0
- package/esm/last.d.ts +3 -0
- package/esm/last.d.ts.map +1 -0
- package/esm/last.js +3 -0
- package/esm/last.js.map +1 -0
- package/esm/mapAsync.d.ts +3 -0
- package/esm/mapAsync.d.ts.map +1 -0
- package/esm/mapAsync.js +19 -0
- package/esm/mapAsync.js.map +1 -0
- package/esm/mapValues.d.ts +6 -0
- package/esm/mapValues.d.ts.map +1 -0
- package/esm/mapValues.js +14 -0
- package/esm/mapValues.js.map +1 -0
- package/esm/match.d.ts +8 -0
- package/esm/match.d.ts.map +1 -0
- package/esm/match.js +17 -0
- package/esm/match.js.map +1 -0
- package/esm/merge.d.ts +15 -0
- package/esm/merge.d.ts.map +1 -0
- package/esm/merge.js +24 -0
- package/esm/merge.js.map +1 -0
- package/esm/mostFrequent.d.ts +3 -0
- package/esm/mostFrequent.d.ts.map +1 -0
- package/esm/mostFrequent.js +18 -0
- package/esm/mostFrequent.js.map +1 -0
- package/esm/noop.d.ts +3 -0
- package/esm/noop.d.ts.map +1 -0
- package/esm/noop.js +3 -0
- package/esm/noop.js.map +1 -0
- package/esm/omit.d.ts +5 -0
- package/esm/omit.d.ts.map +1 -0
- package/esm/omit.js +20 -0
- package/esm/omit.js.map +1 -0
- package/esm/pick.d.ts +5 -0
- package/esm/pick.d.ts.map +1 -0
- package/esm/pick.js +17 -0
- package/esm/pick.js.map +1 -0
- package/esm/pull.d.ts +3 -0
- package/esm/pull.d.ts.map +1 -0
- package/esm/pull.js +11 -0
- package/esm/pull.js.map +1 -0
- package/esm/remove.d.ts +3 -0
- package/esm/remove.d.ts.map +1 -0
- package/esm/remove.js +15 -0
- package/esm/remove.js.map +1 -0
- package/esm/rethrow.d.ts +3 -0
- package/esm/rethrow.d.ts.map +1 -0
- package/esm/rethrow.js +5 -0
- package/esm/rethrow.js.map +1 -0
- package/esm/scale.d.ts +3 -0
- package/esm/scale.d.ts.map +1 -0
- package/esm/scale.js +5 -0
- package/esm/scale.js.map +1 -0
- package/esm/seq.d.ts +8 -0
- package/esm/seq.d.ts.map +1 -0
- package/esm/seq.js +41 -0
- package/esm/seq.js.map +1 -0
- package/esm/set.d.ts +7 -0
- package/esm/set.d.ts.map +1 -0
- package/esm/set.js +22 -0
- package/esm/set.js.map +1 -0
- package/esm/setImmutable.d.ts +8 -0
- package/esm/setImmutable.d.ts.map +1 -0
- package/esm/setImmutable.js +56 -0
- package/esm/setImmutable.js.map +1 -0
- package/esm/sortBy.d.ts +3 -0
- package/esm/sortBy.d.ts.map +1 -0
- package/esm/sortBy.js +12 -0
- package/esm/sortBy.js.map +1 -0
- package/esm/throttle.d.ts +13 -0
- package/esm/throttle.d.ts.map +1 -0
- package/esm/throttle.js +79 -0
- package/esm/throttle.js.map +1 -0
- package/esm/truthy.d.ts +3 -0
- package/esm/truthy.d.ts.map +1 -0
- package/esm/truthy.js +5 -0
- package/esm/truthy.js.map +1 -0
- package/esm/wait.d.ts +3 -0
- package/esm/wait.d.ts.map +1 -0
- package/esm/wait.js +7 -0
- package/esm/wait.js.map +1 -0
- package/esm/waitFor.d.ts +3 -0
- package/esm/waitFor.d.ts.map +1 -0
- package/esm/waitFor.js +31 -0
- package/esm/waitFor.js.map +1 -0
- package/esm/waitSync.d.ts +3 -0
- package/esm/waitSync.d.ts.map +1 -0
- package/esm/waitSync.js +6 -0
- package/esm/waitSync.js.map +1 -0
- package/package.json +75 -0
- package/src/cap.spec.ts +36 -0
- package/src/cap.ts +19 -0
- package/src/capitalize.spec.ts +18 -0
- package/src/capitalize.ts +16 -0
- package/src/coalesce.spec.ts +23 -0
- package/src/coalesce.ts +21 -0
- package/src/ensureArray.spec.ts +87 -0
- package/src/ensureArray.ts +13 -0
- package/src/ensureError.spec.ts +29 -0
- package/src/ensureError.ts +15 -0
- package/src/get.spec.ts +183 -0
- package/src/get.ts +53 -0
- package/src/getMultiple.spec.ts +25 -0
- package/src/getMultiple.ts +47 -0
- package/src/index.ts +33 -0
- package/src/insertSeparator.spec.ts +29 -0
- package/src/insertSeparator.ts +22 -0
- package/src/isEmpty.spec.ts +130 -0
- package/src/isEmpty.ts +50 -0
- package/src/isPlainObject.spec.ts +42 -0
- package/src/isPlainObject.ts +18 -0
- package/src/last.spec.ts +88 -0
- package/src/last.ts +12 -0
- package/src/mapAsync.spec.ts +39 -0
- package/src/mapAsync.ts +41 -0
- package/src/mapValues.spec.ts +178 -0
- package/src/mapValues.ts +57 -0
- package/src/match.spec.ts +11 -0
- package/src/match.ts +30 -0
- package/src/merge.spec.ts +69 -0
- package/src/merge.ts +58 -0
- package/src/mostFrequent.spec.ts +35 -0
- package/src/mostFrequent.ts +27 -0
- package/src/noop.ts +8 -0
- package/src/omit.spec.ts +181 -0
- package/src/omit.ts +43 -0
- package/src/pick.spec.ts +168 -0
- package/src/pick.ts +39 -0
- package/src/pull.spec.ts +54 -0
- package/src/pull.ts +18 -0
- package/src/remove.spec.ts +63 -0
- package/src/remove.ts +26 -0
- package/src/rethrow.ts +12 -0
- package/src/scale.ts +18 -0
- package/src/seq.spec.ts +157 -0
- package/src/seq.ts +104 -0
- package/src/set.spec.ts +348 -0
- package/src/set.ts +59 -0
- package/src/setImmutable.spec.ts +241 -0
- package/src/setImmutable.ts +104 -0
- package/src/sortBy.spec.ts +56 -0
- package/src/sortBy.ts +24 -0
- package/src/throttle.spec.ts +136 -0
- package/src/throttle.ts +153 -0
- package/src/truthy.spec.ts +21 -0
- package/src/truthy.ts +13 -0
- package/src/wait.spec.ts +21 -0
- package/src/wait.ts +14 -0
- package/src/waitFor.ts +47 -0
- package/src/waitSync.spec.ts +21 -0
- package/src/waitSync.ts +14 -0
- package/tutorials/Introduction.md +1 -0
package/src/seq.spec.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { seq, seqEarlyBreak } from "./seq.js";
|
|
2
|
+
|
|
3
|
+
describe("seq", () => {
|
|
4
|
+
// @TODO more tests
|
|
5
|
+
|
|
6
|
+
it("calls methods one by one", async () => {
|
|
7
|
+
let firstCalled = false,
|
|
8
|
+
secondCalled = false;
|
|
9
|
+
const list = [
|
|
10
|
+
() => {
|
|
11
|
+
firstCalled = true;
|
|
12
|
+
return Promise.resolve(1);
|
|
13
|
+
},
|
|
14
|
+
() => {
|
|
15
|
+
secondCalled = true;
|
|
16
|
+
return Promise.resolve(2);
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const res = await seq(list);
|
|
21
|
+
res.must.equal(1);
|
|
22
|
+
firstCalled.must.equal(true);
|
|
23
|
+
secondCalled.must.equal(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("returns first resolved value", async () => {
|
|
27
|
+
let firstCalled = false,
|
|
28
|
+
secondCalled = false;
|
|
29
|
+
const list = [
|
|
30
|
+
() => {
|
|
31
|
+
firstCalled = true;
|
|
32
|
+
return Promise.reject(new Error("Nope"));
|
|
33
|
+
},
|
|
34
|
+
() => {
|
|
35
|
+
secondCalled = true;
|
|
36
|
+
return Promise.resolve(2);
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const res = await seq(list);
|
|
41
|
+
res.must.equal(2);
|
|
42
|
+
firstCalled.must.equal(true);
|
|
43
|
+
secondCalled.must.equal(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("works with non-async functions", async () => {
|
|
47
|
+
let firstCalled = false,
|
|
48
|
+
secondCalled = false;
|
|
49
|
+
const list = [
|
|
50
|
+
() => {
|
|
51
|
+
firstCalled = true;
|
|
52
|
+
throw new Error("Nope");
|
|
53
|
+
},
|
|
54
|
+
() => {
|
|
55
|
+
secondCalled = true;
|
|
56
|
+
return 2;
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
const res = await seq(list);
|
|
61
|
+
res.must.equal(2);
|
|
62
|
+
firstCalled.must.equal(true);
|
|
63
|
+
secondCalled.must.equal(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("rejects if everything rejects", async () => {
|
|
67
|
+
const list = [
|
|
68
|
+
() => {
|
|
69
|
+
throw new Error("Nope");
|
|
70
|
+
},
|
|
71
|
+
() => {
|
|
72
|
+
throw new Error("Also nope");
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
let caught = false;
|
|
77
|
+
try {
|
|
78
|
+
await seq(list);
|
|
79
|
+
}
|
|
80
|
+
catch (e: unknown) {
|
|
81
|
+
caught = true;
|
|
82
|
+
e.must.be.instanceof(Error);
|
|
83
|
+
if (e instanceof Error) {
|
|
84
|
+
e.message.must.equal("Every function had thrown.");
|
|
85
|
+
const errors = e.details?.errors as Error[];
|
|
86
|
+
errors.must.be.an.array();
|
|
87
|
+
errors.must.have.length(2);
|
|
88
|
+
errors[0].must.be.instanceof(Error);
|
|
89
|
+
errors[0].message.must.equal("Nope");
|
|
90
|
+
errors[1].must.be.instanceof(Error);
|
|
91
|
+
errors[1].message.must.equal("Also nope");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
caught.must.be.true();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("rejects if no functions given", async () => {
|
|
99
|
+
let caught = false;
|
|
100
|
+
try {
|
|
101
|
+
await seq();
|
|
102
|
+
}
|
|
103
|
+
catch (e: unknown) {
|
|
104
|
+
caught = true;
|
|
105
|
+
e.must.be.instanceof(TypeError);
|
|
106
|
+
if (e instanceof TypeError) {
|
|
107
|
+
e.message.must.equal("At least one function must be provided.");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
caught.must.be.true();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("allows to break early on rejection", async () => {
|
|
115
|
+
let firstCalled = false,
|
|
116
|
+
secondCalled = false,
|
|
117
|
+
thirdCalled = false;
|
|
118
|
+
|
|
119
|
+
const list = [
|
|
120
|
+
() => {
|
|
121
|
+
firstCalled = true;
|
|
122
|
+
// eslint-disable-next-line prefer-promise-reject-errors
|
|
123
|
+
return Promise.reject(1);
|
|
124
|
+
},
|
|
125
|
+
() => {
|
|
126
|
+
secondCalled = true;
|
|
127
|
+
// eslint-disable-next-line prefer-promise-reject-errors
|
|
128
|
+
return Promise.reject(2);
|
|
129
|
+
},
|
|
130
|
+
() => {
|
|
131
|
+
thirdCalled = true;
|
|
132
|
+
// eslint-disable-next-line prefer-promise-reject-errors
|
|
133
|
+
return Promise.reject(3);
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
let caught = false;
|
|
138
|
+
try {
|
|
139
|
+
await seqEarlyBreak((e: unknown) => {
|
|
140
|
+
if (e === 2) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}, list);
|
|
145
|
+
}
|
|
146
|
+
catch (e: unknown) {
|
|
147
|
+
caught = true;
|
|
148
|
+
e.must.be.equal(2);
|
|
149
|
+
|
|
150
|
+
firstCalled.must.be.true();
|
|
151
|
+
secondCalled.must.be.true();
|
|
152
|
+
thirdCalled.must.be.false();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
caught.must.be.true();
|
|
156
|
+
});
|
|
157
|
+
});
|
package/src/seq.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const fail = function() {
|
|
2
|
+
return Promise.reject(new TypeError("At least one function must be provided."));
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Function to be called.
|
|
7
|
+
*
|
|
8
|
+
* @see {@link seq}
|
|
9
|
+
*/
|
|
10
|
+
type Fn<T> = () => T;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Functions to call sequentially.
|
|
14
|
+
* Either an array of functions or a list of functions.
|
|
15
|
+
*
|
|
16
|
+
* @see {@link seq}
|
|
17
|
+
*/
|
|
18
|
+
type Functions<T> = Fn<T>[] | [Fn<T>[]];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A function that decides if the sequential run should be early stopped.
|
|
22
|
+
*
|
|
23
|
+
* @param {*} e - Value thrown by the function (usually Error).
|
|
24
|
+
* @see {@link seq}
|
|
25
|
+
*/
|
|
26
|
+
type EarlyBreaker = (e: unknown) => boolean;
|
|
27
|
+
|
|
28
|
+
const run = <T>(list: Fn<T>[], earlyBreaker?: EarlyBreaker): Promise<T> => {
|
|
29
|
+
if (!list.length) {
|
|
30
|
+
return fail();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const promises = [...list];
|
|
34
|
+
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
let promise: Promise<T | undefined> = Promise.resolve(undefined);
|
|
37
|
+
|
|
38
|
+
const errors: Error[] = [];
|
|
39
|
+
|
|
40
|
+
const doTry = function(error?: Error) {
|
|
41
|
+
if (error !== undefined && earlyBreaker && earlyBreaker(error)) {
|
|
42
|
+
reject(error);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (error) {
|
|
47
|
+
errors.push(error);
|
|
48
|
+
}
|
|
49
|
+
const fn = promises.shift();
|
|
50
|
+
if (typeof fn !== "function") {
|
|
51
|
+
const finalError = new Error("Every function had thrown.");
|
|
52
|
+
// @ts-expect-error More details on error object are wanted
|
|
53
|
+
finalError.details = { errors };
|
|
54
|
+
reject(finalError);
|
|
55
|
+
}
|
|
56
|
+
promise = (promise.then(fn).then(resolve, doTry)) as unknown as Promise<T>;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
doTry();
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The same as {@link seq} but accepts a function that gets run after each error and using that erro decides if continue
|
|
65
|
+
* to try next functions.
|
|
66
|
+
*
|
|
67
|
+
* @example seqEarlyBreak(
|
|
68
|
+
* (e) => e.message === "important error",
|
|
69
|
+
* () => { throw new Error("important error") }, () => 2, () => 3
|
|
70
|
+
* ) // throws given important error, does not run next functions
|
|
71
|
+
* @param {EarlyBreaker} earlyBreaker - function that decides about early breaking the sequential run
|
|
72
|
+
* @param {...Functions<*>[]} args - functions to run, you can either pass them as many arguments or just single
|
|
73
|
+
* arguments with array
|
|
74
|
+
* @returns {*} - whatever gets returned from given functions
|
|
75
|
+
*/
|
|
76
|
+
const seqEarlyBreak = <T>(earlyBreaker: EarlyBreaker | undefined, ...args: Functions<T>) => {
|
|
77
|
+
if (args.length === 1) {
|
|
78
|
+
return run(Array.isArray(args[0]) ? args[0] : [args[0]], earlyBreaker);
|
|
79
|
+
}
|
|
80
|
+
return run(args as Fn<T>[], earlyBreaker);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Runs given functions sequentially one by one, until any returns value. Supports async functions. Throws with new
|
|
85
|
+
* Error when every function throws.
|
|
86
|
+
*
|
|
87
|
+
* @example seq(() => 1, () => 2, () => 3) // returns 1
|
|
88
|
+
* @example seq(() => { throw new Error("1") }, () => 2, () => 3) // returns 2
|
|
89
|
+
* @example seq(() => { throw new Error("1") }, () => { throw new Error("2") } }) // throws
|
|
90
|
+
* @param {...Functions<*>[]} fns - functions to run, you can either pass them as many arguments or just single
|
|
91
|
+
* arguments with array
|
|
92
|
+
* @returns {*} - whatever gets returned from given functions
|
|
93
|
+
*/
|
|
94
|
+
const seq = <T>(...fns: Functions<T>) => {
|
|
95
|
+
return seqEarlyBreak(undefined, ...fns);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export { seq, seqEarlyBreak };
|
|
99
|
+
|
|
100
|
+
export type {
|
|
101
|
+
EarlyBreaker as SeqEarlyBreaker,
|
|
102
|
+
Functions as SeqFunctions,
|
|
103
|
+
Fn as SeqFn,
|
|
104
|
+
};
|
package/src/set.spec.ts
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { set as _set } from "lodash";
|
|
2
|
+
|
|
3
|
+
import { set } from "./set.js";
|
|
4
|
+
|
|
5
|
+
describe("set", () => {
|
|
6
|
+
it("replaces existing value, behaves like lodash", () => {
|
|
7
|
+
lodash: {
|
|
8
|
+
const obj = {
|
|
9
|
+
title: "Hello",
|
|
10
|
+
};
|
|
11
|
+
_set(obj, "title", "World");
|
|
12
|
+
obj.title.must.equal("World");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
bottom: {
|
|
16
|
+
const obj = {
|
|
17
|
+
title: "Hello",
|
|
18
|
+
};
|
|
19
|
+
set(obj, "title", "World");
|
|
20
|
+
obj.title.must.equal("World");
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("adds new value, behaves like lodash", () => {
|
|
25
|
+
lodash: {
|
|
26
|
+
const obj = {
|
|
27
|
+
title: "Hello",
|
|
28
|
+
};
|
|
29
|
+
_set(obj, "name", "World");
|
|
30
|
+
obj.title.must.equal("Hello");
|
|
31
|
+
obj.name.must.equal("World");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
bottom: {
|
|
35
|
+
const obj = {
|
|
36
|
+
title: "Hello",
|
|
37
|
+
};
|
|
38
|
+
set(obj, "name", "World");
|
|
39
|
+
obj.title.must.equal("Hello");
|
|
40
|
+
obj.name.must.equal("World");
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("allows deep set, behaves like lodash", () => {
|
|
45
|
+
lodash: {
|
|
46
|
+
const obj = {
|
|
47
|
+
data: {
|
|
48
|
+
title: "Bye",
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const dataBefore = obj.data;
|
|
53
|
+
|
|
54
|
+
_set(obj, "data.title", "Hi");
|
|
55
|
+
|
|
56
|
+
obj.data.title.must.equal("Hi");
|
|
57
|
+
obj.data.must.equal(dataBefore);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
bottom: {
|
|
61
|
+
const obj = {
|
|
62
|
+
data: {
|
|
63
|
+
title: "Bye",
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const dataBefore = obj.data;
|
|
68
|
+
|
|
69
|
+
set(obj, "data.title", "Hi");
|
|
70
|
+
|
|
71
|
+
obj.data.title.must.equal("Hi");
|
|
72
|
+
obj.data.must.equal(dataBefore);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("adds objects if not existing on the way, behaves like lodash", () => {
|
|
77
|
+
lodash1: {
|
|
78
|
+
const obj = {
|
|
79
|
+
data: null,
|
|
80
|
+
};
|
|
81
|
+
_set(obj, "data.title", "Hi");
|
|
82
|
+
obj.data.must.be.an.object();
|
|
83
|
+
obj.data.title.must.equal("Hi");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
lodash2: {
|
|
87
|
+
const obj = {};
|
|
88
|
+
_set(obj, "data.title.short", "Hi");
|
|
89
|
+
obj.data.must.be.an.object();
|
|
90
|
+
obj.data.title.must.be.an.object();
|
|
91
|
+
obj.data.title.short.must.equal("Hi");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
bottom1: {
|
|
95
|
+
const obj = {
|
|
96
|
+
data: null,
|
|
97
|
+
};
|
|
98
|
+
set(obj, "data.title", "Hi");
|
|
99
|
+
obj.data.must.be.an.object();
|
|
100
|
+
obj.data.title.must.equal("Hi");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
bottom2: {
|
|
104
|
+
const obj = {};
|
|
105
|
+
set(obj, "data.title.short", "Hi");
|
|
106
|
+
obj.data.must.be.an.object();
|
|
107
|
+
obj.data.title.must.be.an.object();
|
|
108
|
+
obj.data.title.short.must.equal("Hi");
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("replaces primitives with objects on the way, behaves like lodash", () => {
|
|
113
|
+
lodash1: {
|
|
114
|
+
const obj = {
|
|
115
|
+
data: true,
|
|
116
|
+
};
|
|
117
|
+
_set(obj, "data.title.short", "Hi");
|
|
118
|
+
obj.data.must.be.an.object();
|
|
119
|
+
obj.data.title.must.be.an.object();
|
|
120
|
+
obj.data.title.short.must.equal("Hi");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
lodash2: {
|
|
124
|
+
const obj = {
|
|
125
|
+
data: "empty",
|
|
126
|
+
};
|
|
127
|
+
_set(obj, "data.title.short", "Hi");
|
|
128
|
+
obj.data.must.be.an.object();
|
|
129
|
+
obj.data.title.must.be.an.object();
|
|
130
|
+
obj.data.title.short.must.equal("Hi");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
bottom1: {
|
|
134
|
+
const obj = {
|
|
135
|
+
data: true,
|
|
136
|
+
};
|
|
137
|
+
set(obj, "data.title.short", "Hi");
|
|
138
|
+
obj.data.must.be.an.object();
|
|
139
|
+
obj.data.title.must.be.an.object();
|
|
140
|
+
obj.data.title.short.must.equal("Hi");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
bottom2: {
|
|
144
|
+
const obj = {
|
|
145
|
+
data: "empty",
|
|
146
|
+
};
|
|
147
|
+
set(obj, "data.title.short", "Hi");
|
|
148
|
+
obj.data.must.be.an.object();
|
|
149
|
+
obj.data.title.must.be.an.object();
|
|
150
|
+
obj.data.title.short.must.equal("Hi");
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("doesn't crash on nulls as source, but returns new object, behaves NOT like lodash", () => {
|
|
155
|
+
lodash: {
|
|
156
|
+
const obj = null;
|
|
157
|
+
(() => {
|
|
158
|
+
_set(obj, "data.title.short", "Hi");
|
|
159
|
+
}).must.not.throw();
|
|
160
|
+
|
|
161
|
+
const newObj = _set(obj, "data.title.short", "Hi");
|
|
162
|
+
(newObj === null).must.be.true();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
bottom: {
|
|
166
|
+
const obj = null;
|
|
167
|
+
(() => {
|
|
168
|
+
set(obj, "data.title.short", "Hi");
|
|
169
|
+
}).must.not.throw();
|
|
170
|
+
|
|
171
|
+
const newObj = set(obj, "data.title.short", "Hi");
|
|
172
|
+
newObj.must.be.an.object();
|
|
173
|
+
newObj.data.title.short.must.equal("Hi");
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("doesn't crash on primitives as source", () => {
|
|
178
|
+
lodash1: {
|
|
179
|
+
const obj = "hello";
|
|
180
|
+
(() => {
|
|
181
|
+
_set(obj, "data.title.short", "Hi");
|
|
182
|
+
}).must.not.throw();
|
|
183
|
+
|
|
184
|
+
const newObj = _set(obj, "data.title.short", "Hi");
|
|
185
|
+
newObj.must.equal("hello");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
lodash2: {
|
|
189
|
+
const obj = 88;
|
|
190
|
+
(() => {
|
|
191
|
+
_set(obj, "data.title.short", "Hi");
|
|
192
|
+
}).must.not.throw();
|
|
193
|
+
|
|
194
|
+
const newObj = _set(obj, "data.title.short", "Hi");
|
|
195
|
+
newObj.must.equal(88);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
bottom1: {
|
|
199
|
+
const obj = "hello";
|
|
200
|
+
(() => {
|
|
201
|
+
set(obj, "data.title.short", "Hi");
|
|
202
|
+
}).must.not.throw();
|
|
203
|
+
|
|
204
|
+
const newObj = set(obj, "data.title.short", "Hi");
|
|
205
|
+
newObj.must.be.an.object();
|
|
206
|
+
newObj.data.title.short.must.equal("Hi");
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
bottom2: {
|
|
210
|
+
const obj = 88;
|
|
211
|
+
(() => {
|
|
212
|
+
set(obj, "data.title.short", "Hi");
|
|
213
|
+
}).must.not.throw();
|
|
214
|
+
|
|
215
|
+
const newObj = set(obj, "data.title.short", "Hi");
|
|
216
|
+
newObj.must.be.an.object();
|
|
217
|
+
newObj.data.title.short.must.equal("Hi");
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("works on functions as source, behaves like lodash", () => {
|
|
222
|
+
lodash: {
|
|
223
|
+
const obj = () => {};
|
|
224
|
+
(() => {
|
|
225
|
+
_set(obj, "lo.da", "sh");
|
|
226
|
+
}).must.not.throw();
|
|
227
|
+
|
|
228
|
+
obj.lo.da.must.equal("sh");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
bottom: {
|
|
232
|
+
const obj = () => {};
|
|
233
|
+
(() => {
|
|
234
|
+
set(obj, "lo.da", "sh");
|
|
235
|
+
}).must.not.throw();
|
|
236
|
+
|
|
237
|
+
obj.lo.da.must.equal("sh");
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("creates an object when numeric index is used and target isn't set, behaves NOT like lodash", () => {
|
|
242
|
+
lodash1: {
|
|
243
|
+
const obj = {};
|
|
244
|
+
_set(obj, ["items", 5, "title"], "Jan Padeusz");
|
|
245
|
+
obj.items.must.be.an.array();
|
|
246
|
+
obj.items.must.eql([,,,,, // eslint-disable-line no-sparse-arrays
|
|
247
|
+
{
|
|
248
|
+
title: "Jan Padeusz",
|
|
249
|
+
}]);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
lodash2: {
|
|
253
|
+
const obj = {};
|
|
254
|
+
_set(obj, "items.5.title", "Jan Padeusz");
|
|
255
|
+
obj.items.must.be.an.array();
|
|
256
|
+
obj.items.must.eql([,,,,, // eslint-disable-line no-sparse-arrays
|
|
257
|
+
{
|
|
258
|
+
title: "Jan Padeusz",
|
|
259
|
+
}]);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
bottom1: {
|
|
263
|
+
const obj = {};
|
|
264
|
+
set(obj, ["items", 5, "title"], "Jan Padeusz");
|
|
265
|
+
obj.items.must.not.be.an.array();
|
|
266
|
+
obj.items.must.eql({
|
|
267
|
+
5: {
|
|
268
|
+
title: "Jan Padeusz",
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
bottom2: {
|
|
274
|
+
const obj = {};
|
|
275
|
+
set(obj, "items.5.title", "Jan Padeusz");
|
|
276
|
+
obj.items.must.not.be.an.array();
|
|
277
|
+
obj.items.must.eql({
|
|
278
|
+
5: {
|
|
279
|
+
title: "Jan Padeusz",
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("doesn't parse path string as js code, behaves NOT like lodash", () => {
|
|
286
|
+
lodash: {
|
|
287
|
+
const obj = {};
|
|
288
|
+
_set(obj, "hello[world]", "is it me you're looking for?");
|
|
289
|
+
obj.hello.world.must.equal("is it me you're looking for?");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
bottom: {
|
|
293
|
+
const obj = {};
|
|
294
|
+
set(obj, "hello[world]", "is it me you're looking for?");
|
|
295
|
+
obj.must.not.have.property("hello");
|
|
296
|
+
obj.must.have.property("hello[world]");
|
|
297
|
+
obj["hello[world]"].must.equal("is it me you're looking for?");
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("allow dot separated path, behaves like lodash", () => {
|
|
302
|
+
lodash: {
|
|
303
|
+
const obj = {};
|
|
304
|
+
_set(obj, "hello.world", "is it me you're looking for?");
|
|
305
|
+
obj.hello.world.must.equal("is it me you're looking for?");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
bottom: {
|
|
309
|
+
const obj = {};
|
|
310
|
+
set(obj, "hello.world", "is it me you're looking for?");
|
|
311
|
+
obj.hello.world.must.equal("is it me you're looking for?");
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it("allow arrays as path, behaves like lodash", () => {
|
|
316
|
+
lodash: {
|
|
317
|
+
const obj = {};
|
|
318
|
+
_set(obj, ["hello", "world"], "is it me you're looking for?");
|
|
319
|
+
obj.hello.world.must.equal("is it me you're looking for?");
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
bottom: {
|
|
323
|
+
const obj = {};
|
|
324
|
+
set(obj, ["hello", "world"], "is it me you're looking for?");
|
|
325
|
+
obj.hello.world.must.equal("is it me you're looking for?");
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it("doesn't parse mixed array/dot-strings paths, behaves like lodash", () => {
|
|
330
|
+
lodash: {
|
|
331
|
+
const obj = {};
|
|
332
|
+
_set(obj, ["hello", "world.5"], "is it me you're looking for?");
|
|
333
|
+
obj.hello.must.not.have.property("world");
|
|
334
|
+
obj.hello.must.have.property("world.5");
|
|
335
|
+
obj.hello["world.5"].must.equal("is it me you're looking for?");
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
bottom: {
|
|
339
|
+
const obj = {};
|
|
340
|
+
set(obj, ["hello", "world.5"], "is it me you're looking for?");
|
|
341
|
+
obj.hello.must.not.have.property("world");
|
|
342
|
+
obj.hello.must.have.property("world.5");
|
|
343
|
+
obj.hello["world.5"].must.equal("is it me you're looking for?");
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// @todo test Maps, Sets, etc.
|
|
348
|
+
});
|
package/src/set.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source object to mutate.
|
|
3
|
+
*
|
|
4
|
+
* @see {@link set}.
|
|
5
|
+
*/
|
|
6
|
+
interface Source { [key: string]: unknown }
|
|
7
|
+
|
|
8
|
+
const isObject = (value: unknown) => (typeof value === "object" || typeof value === "function") && value !== null;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Updates the value at given path of given object. It mutates the object. If path is not found then objects are created
|
|
12
|
+
* "on the way". If non-objects are found, they are replaced with new plain objects. If primitives are used as source
|
|
13
|
+
* they are ignored and returned value is empty object with updated value at given path.
|
|
14
|
+
*
|
|
15
|
+
* This is still too dynamic in nature to get full TypeScript support. Properties are not typed, return type is unknown.
|
|
16
|
+
* If you are okay with NOT mutating the object but get new one instead it is recommended to use `immutable-assign`
|
|
17
|
+
* package instead.
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} source - source object to mutate
|
|
20
|
+
* @param {string|Array<string>} path - path where value should be stored, written as dot-separated property names or
|
|
21
|
+
* array with property names. Use Array when your keys includes dots.
|
|
22
|
+
* @param {*} value - value to be set
|
|
23
|
+
* @example set(object, "deep.property", value)
|
|
24
|
+
* @example set(object, ["deep", "property"], value)
|
|
25
|
+
* @example set({}, "deep[0].property", value)
|
|
26
|
+
* // will create this structure:
|
|
27
|
+
* { "deep[0]": { "property": value }}
|
|
28
|
+
* @example set({}, "items.0", value)
|
|
29
|
+
* // will create object, not array
|
|
30
|
+
* { "items": { "0": value }}
|
|
31
|
+
* @returns {Object} - given object or new object if source was primitive
|
|
32
|
+
*/
|
|
33
|
+
const set = (source: Source, path: string | string[], value: unknown): Source | unknown => { // eslint-disable-line @typescript-eslint/no-redundant-type-constituents,max-len
|
|
34
|
+
const pathParts = typeof path === "string" ? path.split(".") : path;
|
|
35
|
+
const len = pathParts.length;
|
|
36
|
+
|
|
37
|
+
const result = isObject(source) ? source : {};
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
|
39
|
+
let current: Source | unknown = result;
|
|
40
|
+
for (let i = 0; i < len; i++) {
|
|
41
|
+
const isLast = i === len - 1;
|
|
42
|
+
const key = pathParts[i];
|
|
43
|
+
if (isLast) {
|
|
44
|
+
(current as Source)[key] = value;
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
if (!isObject((current as Source)[key])) {
|
|
48
|
+
(current as Source)[key] = {};
|
|
49
|
+
}
|
|
50
|
+
current = (current as Source)[key];
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export { set };
|
|
56
|
+
|
|
57
|
+
export type {
|
|
58
|
+
Source as SetSource,
|
|
59
|
+
};
|