@e280/stz 0.0.0-29 → 0.0.0-30
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/package.json +7 -4
- package/s/index.ts +2 -0
- package/s/queue/queue.test.ts +67 -0
- package/s/queue/queue.ts +21 -0
- package/s/tests.test.ts +2 -0
- package/x/index.d.ts +1 -0
- package/x/index.js +1 -0
- package/x/index.js.map +1 -1
- package/x/queue/queue.d.ts +4 -0
- package/x/queue/queue.js +14 -0
- package/x/queue/queue.js.map +1 -0
- package/x/queue/queue.test.d.ts +8 -0
- package/x/queue/queue.test.js +57 -0
- package/x/queue/queue.test.js.map +1 -0
- package/x/tests.test.js +2 -0
- package/x/tests.test.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e280/stz",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-30",
|
|
4
4
|
"description": "everyday ts fns for everything",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"main": "x/index.js",
|
|
8
|
+
"main": "./x/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./x/index.js"
|
|
11
|
+
},
|
|
9
12
|
"files": [
|
|
10
13
|
"x",
|
|
11
14
|
"s"
|
|
@@ -24,9 +27,9 @@
|
|
|
24
27
|
},
|
|
25
28
|
"devDependencies": {
|
|
26
29
|
"@e280/science": "^0.0.5",
|
|
27
|
-
"@types/node": "^24.
|
|
30
|
+
"@types/node": "^24.2.0",
|
|
28
31
|
"npm-run-all": "^4.1.5",
|
|
29
|
-
"typescript": "^5.
|
|
32
|
+
"typescript": "^5.9.2"
|
|
30
33
|
},
|
|
31
34
|
"keywords": [
|
|
32
35
|
"standard",
|
package/s/index.ts
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
|
|
2
|
+
import {Science, expect} from "@e280/science"
|
|
3
|
+
|
|
4
|
+
import {nap} from "../nap.js"
|
|
5
|
+
import {queue} from "./queue.js"
|
|
6
|
+
|
|
7
|
+
export default Science.suite({
|
|
8
|
+
"job runs": Science.test(async() => {
|
|
9
|
+
let concurrent = 0
|
|
10
|
+
const job = queue(async() => {
|
|
11
|
+
concurrent++
|
|
12
|
+
await nap(100)
|
|
13
|
+
concurrent--
|
|
14
|
+
})
|
|
15
|
+
const promise1 = job()
|
|
16
|
+
await nap(50)
|
|
17
|
+
expect(concurrent).is(1)
|
|
18
|
+
await promise1
|
|
19
|
+
expect(concurrent).is(0)
|
|
20
|
+
}),
|
|
21
|
+
|
|
22
|
+
"sequencing is enforced": Science.test(async() => {
|
|
23
|
+
let concurrent = 0
|
|
24
|
+
const job = queue(async() => {
|
|
25
|
+
concurrent++
|
|
26
|
+
await nap(100)
|
|
27
|
+
concurrent--
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const promise1 = job()
|
|
31
|
+
const promise2 = job()
|
|
32
|
+
|
|
33
|
+
await nap(50)
|
|
34
|
+
expect(concurrent).is(1)
|
|
35
|
+
|
|
36
|
+
await promise1
|
|
37
|
+
await nap(50)
|
|
38
|
+
expect(concurrent).is(1)
|
|
39
|
+
|
|
40
|
+
await promise2
|
|
41
|
+
expect(concurrent).is(0)
|
|
42
|
+
}),
|
|
43
|
+
|
|
44
|
+
"params and return values seem to work": Science.test(async() => {
|
|
45
|
+
const add = queue(async(a: number, b: number) => {
|
|
46
|
+
await nap(100)
|
|
47
|
+
return a + b
|
|
48
|
+
})
|
|
49
|
+
const promise1 = add(1, 2)
|
|
50
|
+
const promise2 = add(10, 20)
|
|
51
|
+
expect(await promise1).is(3)
|
|
52
|
+
expect(await promise2).is(30)
|
|
53
|
+
}),
|
|
54
|
+
|
|
55
|
+
"first job throws, second job unaffected": Science.test(async() => {
|
|
56
|
+
let run = 0
|
|
57
|
+
const job = queue(async() => {
|
|
58
|
+
run++
|
|
59
|
+
await nap(100)
|
|
60
|
+
if (run === 1)
|
|
61
|
+
throw new Error("first job failed")
|
|
62
|
+
})
|
|
63
|
+
expect(async() => job()).throwsAsync()
|
|
64
|
+
expect(async() => job()).not.throwsAsync()
|
|
65
|
+
}),
|
|
66
|
+
})
|
|
67
|
+
|
package/s/queue/queue.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* create a job queue that ensures the given fn is always called in sequence (not concurrently).
|
|
4
|
+
*/
|
|
5
|
+
export function queue<Args extends any[], Result>(
|
|
6
|
+
fn: (...args: Args) => Promise<Result>
|
|
7
|
+
): (...args: Args) => Promise<Result> {
|
|
8
|
+
|
|
9
|
+
let last: Promise<any> = Promise.resolve()
|
|
10
|
+
|
|
11
|
+
return (...args: Args): Promise<Result> => {
|
|
12
|
+
const job = () => fn(...args)
|
|
13
|
+
const current = last.then(job)
|
|
14
|
+
|
|
15
|
+
// prevent unhandled rejection breaking the chain
|
|
16
|
+
last = current.catch(() => {})
|
|
17
|
+
|
|
18
|
+
return current
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
package/s/tests.test.ts
CHANGED
|
@@ -7,6 +7,7 @@ import debounce from "./debounce/debounce.test.js"
|
|
|
7
7
|
import bytename from "./data/bytename/bytename.test.js"
|
|
8
8
|
import deep from "./deep/deep.test.js"
|
|
9
9
|
import data from "./data/data.test.js"
|
|
10
|
+
import queue from "./queue/queue.test.js"
|
|
10
11
|
|
|
11
12
|
await Science.run({
|
|
12
13
|
clone,
|
|
@@ -15,5 +16,6 @@ await Science.run({
|
|
|
15
16
|
debounce,
|
|
16
17
|
deep,
|
|
17
18
|
data,
|
|
19
|
+
queue,
|
|
18
20
|
})
|
|
19
21
|
|
package/x/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./data/txt.js";
|
|
|
9
9
|
export * from "./debounce/debounce.js";
|
|
10
10
|
export * from "./debounce/types.js";
|
|
11
11
|
export * from "./deep/deep.js";
|
|
12
|
+
export * from "./queue/queue.js";
|
|
12
13
|
export * from "./coalesce.js";
|
|
13
14
|
export * from "./concurrent.js";
|
|
14
15
|
export * from "./deadline.js";
|
package/x/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./data/txt.js";
|
|
|
9
9
|
export * from "./debounce/debounce.js";
|
|
10
10
|
export * from "./debounce/types.js";
|
|
11
11
|
export * from "./deep/deep.js";
|
|
12
|
+
export * from "./queue/queue.js";
|
|
12
13
|
export * from "./coalesce.js";
|
|
13
14
|
export * from "./concurrent.js";
|
|
14
15
|
export * from "./deadline.js";
|
package/x/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../s/index.ts"],"names":[],"mappings":"AACA,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAE7B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,gBAAgB,CAAA;AAE9B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,SAAS,CAAA;AACvB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../s/index.ts"],"names":[],"mappings":"AACA,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAE7B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,gBAAgB,CAAA;AAE9B,cAAc,kBAAkB,CAAA;AAEhC,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,SAAS,CAAA;AACvB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA"}
|
package/x/queue/queue.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* create a job queue that ensures the given fn is always called in sequence (not concurrently).
|
|
3
|
+
*/
|
|
4
|
+
export function queue(fn) {
|
|
5
|
+
let last = Promise.resolve();
|
|
6
|
+
return (...args) => {
|
|
7
|
+
const job = () => fn(...args);
|
|
8
|
+
const current = last.then(job);
|
|
9
|
+
// prevent unhandled rejection breaking the chain
|
|
10
|
+
last = current.catch(() => { });
|
|
11
|
+
return current;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../../s/queue/queue.ts"],"names":[],"mappings":"AACA;;GAEG;AACH,MAAM,UAAU,KAAK,CACnB,EAAsC;IAGvC,IAAI,IAAI,GAAiB,OAAO,CAAC,OAAO,EAAE,CAAA;IAE1C,OAAO,CAAC,GAAG,IAAU,EAAmB,EAAE;QACzC,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAE9B,iDAAiD;QACjD,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAE9B,OAAO,OAAO,CAAA;IACf,CAAC,CAAA;AACF,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Science } from "@e280/science";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
"job runs": Science.Test;
|
|
4
|
+
"sequencing is enforced": Science.Test;
|
|
5
|
+
"params and return values seem to work": Science.Test;
|
|
6
|
+
"first job throws, second job unaffected": Science.Test;
|
|
7
|
+
};
|
|
8
|
+
export default _default;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Science, expect } from "@e280/science";
|
|
2
|
+
import { nap } from "../nap.js";
|
|
3
|
+
import { queue } from "./queue.js";
|
|
4
|
+
export default Science.suite({
|
|
5
|
+
"job runs": Science.test(async () => {
|
|
6
|
+
let concurrent = 0;
|
|
7
|
+
const job = queue(async () => {
|
|
8
|
+
concurrent++;
|
|
9
|
+
await nap(100);
|
|
10
|
+
concurrent--;
|
|
11
|
+
});
|
|
12
|
+
const promise1 = job();
|
|
13
|
+
await nap(50);
|
|
14
|
+
expect(concurrent).is(1);
|
|
15
|
+
await promise1;
|
|
16
|
+
expect(concurrent).is(0);
|
|
17
|
+
}),
|
|
18
|
+
"sequencing is enforced": Science.test(async () => {
|
|
19
|
+
let concurrent = 0;
|
|
20
|
+
const job = queue(async () => {
|
|
21
|
+
concurrent++;
|
|
22
|
+
await nap(100);
|
|
23
|
+
concurrent--;
|
|
24
|
+
});
|
|
25
|
+
const promise1 = job();
|
|
26
|
+
const promise2 = job();
|
|
27
|
+
await nap(50);
|
|
28
|
+
expect(concurrent).is(1);
|
|
29
|
+
await promise1;
|
|
30
|
+
await nap(50);
|
|
31
|
+
expect(concurrent).is(1);
|
|
32
|
+
await promise2;
|
|
33
|
+
expect(concurrent).is(0);
|
|
34
|
+
}),
|
|
35
|
+
"params and return values seem to work": Science.test(async () => {
|
|
36
|
+
const add = queue(async (a, b) => {
|
|
37
|
+
await nap(100);
|
|
38
|
+
return a + b;
|
|
39
|
+
});
|
|
40
|
+
const promise1 = add(1, 2);
|
|
41
|
+
const promise2 = add(10, 20);
|
|
42
|
+
expect(await promise1).is(3);
|
|
43
|
+
expect(await promise2).is(30);
|
|
44
|
+
}),
|
|
45
|
+
"first job throws, second job unaffected": Science.test(async () => {
|
|
46
|
+
let run = 0;
|
|
47
|
+
const job = queue(async () => {
|
|
48
|
+
run++;
|
|
49
|
+
await nap(100);
|
|
50
|
+
if (run === 1)
|
|
51
|
+
throw new Error("first job failed");
|
|
52
|
+
});
|
|
53
|
+
expect(async () => job()).throwsAsync();
|
|
54
|
+
expect(async () => job()).not.throwsAsync();
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=queue.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.test.js","sourceRoot":"","sources":["../../s/queue/queue.test.ts"],"names":[],"mappings":"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"}
|
package/x/tests.test.js
CHANGED
|
@@ -5,6 +5,7 @@ import debounce from "./debounce/debounce.test.js";
|
|
|
5
5
|
import bytename from "./data/bytename/bytename.test.js";
|
|
6
6
|
import deep from "./deep/deep.test.js";
|
|
7
7
|
import data from "./data/data.test.js";
|
|
8
|
+
import queue from "./queue/queue.test.js";
|
|
8
9
|
await Science.run({
|
|
9
10
|
clone,
|
|
10
11
|
bytename,
|
|
@@ -12,5 +13,6 @@ await Science.run({
|
|
|
12
13
|
debounce,
|
|
13
14
|
deep,
|
|
14
15
|
data,
|
|
16
|
+
queue,
|
|
15
17
|
});
|
|
16
18
|
//# sourceMappingURL=tests.test.js.map
|
package/x/tests.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tests.test.js","sourceRoot":"","sources":["../s/tests.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAA;AAErC,OAAO,KAAK,MAAM,uBAAuB,CAAA;AACzC,OAAO,UAAU,MAAM,oCAAoC,CAAA;AAC3D,OAAO,QAAQ,MAAM,6BAA6B,CAAA;AAClD,OAAO,QAAQ,MAAM,kCAAkC,CAAA;AACvD,OAAO,IAAI,MAAM,qBAAqB,CAAA;AACtC,OAAO,IAAI,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"tests.test.js","sourceRoot":"","sources":["../s/tests.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAA;AAErC,OAAO,KAAK,MAAM,uBAAuB,CAAA;AACzC,OAAO,UAAU,MAAM,oCAAoC,CAAA;AAC3D,OAAO,QAAQ,MAAM,6BAA6B,CAAA;AAClD,OAAO,QAAQ,MAAM,kCAAkC,CAAA;AACvD,OAAO,IAAI,MAAM,qBAAqB,CAAA;AACtC,OAAO,IAAI,MAAM,qBAAqB,CAAA;AACtC,OAAO,KAAK,MAAM,uBAAuB,CAAA;AAEzC,MAAM,OAAO,CAAC,GAAG,CAAC;IACjB,KAAK;IACL,QAAQ;IACR,UAAU;IACV,QAAQ;IACR,IAAI;IACJ,IAAI;IACJ,KAAK;CACL,CAAC,CAAA"}
|