@radically-straightforward/utilities 1.0.1 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.1 · 2024-02-21
4
+
5
+ - Added date to `log()`.
6
+
7
+ ## 1.1.0 · 2024-02-21
8
+
9
+ - Changed `backgroundJob()` so that in Node.js it terminates gracefully.
10
+
3
11
  ## 1.0.1 · 2024-01-09
4
12
 
5
13
  - Added `log()`.
package/README.md CHANGED
@@ -52,15 +52,16 @@ This is different from `setInterval()` in the following ways:
52
52
 
53
53
  2. We introduce a random `intervalVariance` to avoid many background jobs from starting at the same time and overloading the machine.
54
54
 
55
- 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (not waiting the interval).
55
+ 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of 0).
56
56
 
57
57
  4. You may use `backgroundJob.stop()` to stop the background job. If the background job is running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
58
58
 
59
+ 5. In Node.js the background job is stopped on [`"gracefulTermination"`](https://github.com/radically-straightforward/radically-straightforward/tree/main/node#graceful-termination).
60
+
59
61
  **Example**
60
62
 
61
63
  ```javascript
62
64
  import * as utilities from "@radically-straightforward/utilities";
63
- import * as node from "@radically-straightforward/node";
64
65
 
65
66
  const backgroundJob = utilities.backgroundJob(
66
67
  { interval: 3 * 1000 },
@@ -70,14 +71,12 @@ const backgroundJob = utilities.backgroundJob(
70
71
  console.log("backgroundJob(): ...finished running background job.");
71
72
  },
72
73
  );
73
- console.log(
74
- "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
75
- );
76
74
  process.on("SIGTSTP", () => {
77
75
  backgroundJob.run();
78
76
  });
79
- await node.shouldTerminate();
80
- backgroundJob.stop();
77
+ console.log(
78
+ "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
79
+ );
81
80
  ```
82
81
 
83
82
  ### `sleep()`
@@ -94,7 +93,7 @@ A promisified version of `setTimeout()`. Bare-bones: It doesn’t even offer a w
94
93
  export function randomString(): string;
95
94
  ```
96
95
 
97
- A fast random string generator. The generated strings are 10 or 11 characters in length. The generated strings include the characters `[0-9a-z]`. The generated strings are **not** cryptographically secure—if you need that, then use [`crypto-random-string`](https://npm.im/crypto-random-string).
96
+ A fast random string generator. The generated strings are 10 or 11 characters in length. The generated strings include the characters `[0-9a-z]`. The generated strings are **not** cryptographically secure—if you need that, then use [`crypto-random-string`](https://www.npmjs.com/package/crypto-random-string).
98
97
 
99
98
  ### `log()`
100
99
 
@@ -136,12 +135,12 @@ Utility type for `intern()`.
136
135
 
137
136
  ```typescript
138
137
  export function intern<
139
- T extends
138
+ Type extends
140
139
  | Array<InternInnerValue>
141
140
  | {
142
141
  [key: string]: InternInnerValue;
143
142
  },
144
- >(value: T): Intern<T>;
143
+ >(value: Type): Intern<Type>;
145
144
  ```
146
145
 
147
146
  [Interning](<https://en.wikipedia.org/wiki/Interning_(computer_science)>) a value makes it unique across the program, which is useful for checking equality with `===` (reference equality), using it as a key in a `Map`, adding it to a `Set`, and so forth:
@@ -207,7 +206,7 @@ A proposal to include immutable objects (Records) and immutable arrays (Tuples)
207
206
 
208
207
  It includes a [polyfill](https://github.com/bloomberg/record-tuple-polyfill) which works very similarly to `intern()` but requires different functions for different data types.
209
208
 
210
- **[`collections-deep-equal`](https://npm.im/collections-deep-equal)**
209
+ **[`collections-deep-equal`](https://www.npmjs.com/package/collections-deep-equal)**
211
210
 
212
211
  A previous solution to this problem which took a different approach: Instead of interning the values and allowing you to use JavaScript’s `Map`s and `Set`s, `collections-deep-equal` extends `Map`s and `Set`s with a different notion of equality.
213
212
 
@@ -217,21 +216,21 @@ A previous solution to this problem which took a different approach: Instead of
217
216
 
218
217
  `collections-deep-equal` has different intern pools for each `Map` and `Set` instead of `intern()`’s single global intern pool, which may be advantageous because smaller pools may be faster to traverse.
219
218
 
220
- **[Immutable.js](https://npm.im/immutable), [`collections`](https://npm.im/collections), [`mori`](https://npm.im/mori), [TypeScript Collections](https://npm.im/typescript-collections), [`prelude-ts`](https://npm.im/prelude-ts), [`collectable`](https://npm.im/collectable), and so forth**
219
+ **[Immutable.js](https://www.npmjs.com/package/immutable), [`collections`](https://www.npmjs.com/package/collections), [`mori`](https://www.npmjs.com/package/mori), [TypeScript Collections](https://www.npmjs.com/package/typescript-collections), [`prelude-ts`](https://www.npmjs.com/package/prelude-ts), [`collectable`](https://www.npmjs.com/package/collectable), and so forth**
221
220
 
222
221
  Similar to `collections-deep-equal`, these libraries implement their own data structures instead of relying on JavaScript’s `Map`s and `Set`s. Some of them go a step further and add their own notions of objects and arrays, which requires you to convert your values back and forth, may not show up nicely in the JavaScript inspector, may be less ergonomic to use with TypeScript, and so forth.
223
222
 
224
223
  The advantage of these libraries over interning is that they may be faster.
225
224
 
226
- **[`immer`](https://npm.im/immer) and [`icepick`](https://npm.im/icepick)**
225
+ **[`immer`](https://www.npmjs.com/package/immer) and [`icepick`](https://www.npmjs.com/package/icepick)**
227
226
 
228
227
  Introduce a new way to create values based on existing values.
229
228
 
230
- **[`seamless-immutable`](https://npm.im/seamless-immutable)**
229
+ **[`seamless-immutable`](https://www.npmjs.com/package/seamless-immutable)**
231
230
 
232
231
  Modifies existing values more profoundly than freezing.
233
232
 
234
- **[`es6-array-map`](https://npm.im/es6-array-map), [`valuecollection`](https://npm.im/valuecollection), [`@strong-roots-capital/map-objects`](https://npm.im/@strong-roots-capital/map-objects), and so forth**
233
+ **[`es6-array-map`](https://www.npmjs.com/package/es6-array-map), [`valuecollection`](https://www.npmjs.com/package/valuecollection), [`@strong-roots-capital/map-objects`](https://www.npmjs.com/package/@strong-roots-capital/map-objects), and so forth**
235
234
 
236
235
  Similar to `collections-deep-equal` but either incomplete, or lacking type definitions, and so forth.
237
236
 
package/build/index.d.mts CHANGED
@@ -17,15 +17,16 @@
17
17
  *
18
18
  * 2. We introduce a random `intervalVariance` to avoid many background jobs from starting at the same time and overloading the machine.
19
19
  *
20
- * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (not waiting the interval).
20
+ * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of 0).
21
21
  *
22
22
  * 4. You may use `backgroundJob.stop()` to stop the background job. If the background job is running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
23
23
  *
24
+ * 5. In Node.js the background job is stopped on [`"gracefulTermination"`](https://github.com/radically-straightforward/radically-straightforward/tree/main/node#graceful-termination).
25
+ *
24
26
  * **Example**
25
27
  *
26
28
  * ```javascript
27
29
  * import * as utilities from "@radically-straightforward/utilities";
28
- * import * as node from "@radically-straightforward/node";
29
30
  *
30
31
  * const backgroundJob = utilities.backgroundJob(
31
32
  * { interval: 3 * 1000 },
@@ -35,14 +36,12 @@
35
36
  * console.log("backgroundJob(): ...finished running background job.");
36
37
  * },
37
38
  * );
38
- * console.log(
39
- * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
40
- * );
41
39
  * process.on("SIGTSTP", () => {
42
40
  * backgroundJob.run();
43
41
  * });
44
- * await node.shouldTerminate();
45
- * backgroundJob.stop();
42
+ * console.log(
43
+ * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
44
+ * );
46
45
  * ```
47
46
  */
48
47
  export declare function backgroundJob({ interval, intervalVariance, }: {
@@ -57,7 +56,7 @@ export declare function backgroundJob({ interval, intervalVariance, }: {
57
56
  */
58
57
  export declare function sleep(duration: number): Promise<void>;
59
58
  /**
60
- * A fast random string generator. The generated strings are 10 or 11 characters in length. The generated strings include the characters `[0-9a-z]`. The generated strings are **not** cryptographically secure—if you need that, then use [`crypto-random-string`](https://npm.im/crypto-random-string).
59
+ * A fast random string generator. The generated strings are 10 or 11 characters in length. The generated strings include the characters `[0-9a-z]`. The generated strings are **not** cryptographically secure—if you need that, then use [`crypto-random-string`](https://www.npmjs.com/package/crypto-random-string).
61
60
  */
62
61
  export declare function randomString(): string;
63
62
  /**
@@ -138,7 +137,7 @@ export type InternInnerValue = string | number | bigint | boolean | symbol | und
138
137
  *
139
138
  * It includes a [polyfill](https://github.com/bloomberg/record-tuple-polyfill) which works very similarly to `intern()` but requires different functions for different data types.
140
139
  *
141
- * **[`collections-deep-equal`](https://npm.im/collections-deep-equal)**
140
+ * **[`collections-deep-equal`](https://www.npmjs.com/package/collections-deep-equal)**
142
141
  *
143
142
  * A previous solution to this problem which took a different approach: Instead of interning the values and allowing you to use JavaScript’s `Map`s and `Set`s, `collections-deep-equal` extends `Map`s and `Set`s with a different notion of equality.
144
143
  *
@@ -148,21 +147,21 @@ export type InternInnerValue = string | number | bigint | boolean | symbol | und
148
147
  *
149
148
  * `collections-deep-equal` has different intern pools for each `Map` and `Set` instead of `intern()`’s single global intern pool, which may be advantageous because smaller pools may be faster to traverse.
150
149
  *
151
- * **[Immutable.js](https://npm.im/immutable), [`collections`](https://npm.im/collections), [`mori`](https://npm.im/mori), [TypeScript Collections](https://npm.im/typescript-collections), [`prelude-ts`](https://npm.im/prelude-ts), [`collectable`](https://npm.im/collectable), and so forth**
150
+ * **[Immutable.js](https://www.npmjs.com/package/immutable), [`collections`](https://www.npmjs.com/package/collections), [`mori`](https://www.npmjs.com/package/mori), [TypeScript Collections](https://www.npmjs.com/package/typescript-collections), [`prelude-ts`](https://www.npmjs.com/package/prelude-ts), [`collectable`](https://www.npmjs.com/package/collectable), and so forth**
152
151
  *
153
152
  * Similar to `collections-deep-equal`, these libraries implement their own data structures instead of relying on JavaScript’s `Map`s and `Set`s. Some of them go a step further and add their own notions of objects and arrays, which requires you to convert your values back and forth, may not show up nicely in the JavaScript inspector, may be less ergonomic to use with TypeScript, and so forth.
154
153
  *
155
154
  * The advantage of these libraries over interning is that they may be faster.
156
155
  *
157
- * **[`immer`](https://npm.im/immer) and [`icepick`](https://npm.im/icepick)**
156
+ * **[`immer`](https://www.npmjs.com/package/immer) and [`icepick`](https://www.npmjs.com/package/icepick)**
158
157
  *
159
158
  * Introduce a new way to create values based on existing values.
160
159
  *
161
- * **[`seamless-immutable`](https://npm.im/seamless-immutable)**
160
+ * **[`seamless-immutable`](https://www.npmjs.com/package/seamless-immutable)**
162
161
  *
163
162
  * Modifies existing values more profoundly than freezing.
164
163
  *
165
- * **[`es6-array-map`](https://npm.im/es6-array-map), [`valuecollection`](https://npm.im/valuecollection), [`@strong-roots-capital/map-objects`](https://npm.im/@strong-roots-capital/map-objects), and so forth**
164
+ * **[`es6-array-map`](https://www.npmjs.com/package/es6-array-map), [`valuecollection`](https://www.npmjs.com/package/valuecollection), [`@strong-roots-capital/map-objects`](https://www.npmjs.com/package/@strong-roots-capital/map-objects), and so forth**
166
165
  *
167
166
  * Similar to `collections-deep-equal` but either incomplete, or lacking type definitions, and so forth.
168
167
  *
@@ -176,9 +175,9 @@ export type InternInnerValue = string | number | bigint | boolean | symbol | und
176
175
  * - <https://twitter.com/swannodette/status/1067962983924539392>
177
176
  * - <https://gist.github.com/modernserf/c000e62d40f678cf395e3f360b9b0e43>
178
177
  */
179
- export declare function intern<T extends Array<InternInnerValue> | {
178
+ export declare function intern<Type extends Array<InternInnerValue> | {
180
179
  [key: string]: InternInnerValue;
181
- }>(value: T): Intern<T>;
180
+ }>(value: Type): Intern<Type>;
182
181
  export declare namespace intern {
183
182
  var pool: {
184
183
  tuple: Map<Symbol, WeakRef<Readonly<InternInnerValue[] & {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../source/index.mts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,aAAa,CAC3B,EACE,QAAQ,EACR,gBAAsB,GACvB,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,EAClD,GAAG,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC9B;IAAE,GAAG,EAAE,MAAM,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAuCvC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,GAAG,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAEnD;AAED;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,GAAG;IAAE,CAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,SAAS,GACT,IAAI,GACJ,MAAM,CAAC,OAAO,CAAC,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AACH,wBAAgB,MAAM,CACpB,CAAC,SAAS,KAAK,CAAC,gBAAgB,CAAC,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAA;CAAE,EACvE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CA2CrB;yBA7Ce,MAAM;;;;;;;;;;;;;;;;AA+CtB,eAAO,MAAM,YAAY,eAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../source/index.mts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,aAAa,CAC3B,EACE,QAAQ,EACR,gBAAsB,GACvB,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,EAClD,GAAG,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAC9B;IAAE,GAAG,EAAE,MAAM,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAuCvC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,GAAG,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAEnD;AAED;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,GAAG;IAAE,CAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,SAAS,GACT,IAAI,GACJ,MAAM,CAAC,OAAO,CAAC,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AACH,wBAAgB,MAAM,CACpB,IAAI,SAAS,KAAK,CAAC,gBAAgB,CAAC,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAA;CAAE,EAC1E,KAAK,EAAE,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAyC3B;yBA3Ce,MAAM;;;;;;;;;;;;;;;;AA6CtB,eAAO,MAAM,YAAY,eAAmB,CAAC"}
package/build/index.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ if (process !== undefined)
2
+ await import("@radically-straightforward/node");
1
3
  /**
2
4
  * Start a background job that runs every `interval`.
3
5
  *
@@ -17,15 +19,16 @@
17
19
  *
18
20
  * 2. We introduce a random `intervalVariance` to avoid many background jobs from starting at the same time and overloading the machine.
19
21
  *
20
- * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (not waiting the interval).
22
+ * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of 0).
21
23
  *
22
24
  * 4. You may use `backgroundJob.stop()` to stop the background job. If the background job is running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
23
25
  *
26
+ * 5. In Node.js the background job is stopped on [`"gracefulTermination"`](https://github.com/radically-straightforward/radically-straightforward/tree/main/node#graceful-termination).
27
+ *
24
28
  * **Example**
25
29
  *
26
30
  * ```javascript
27
31
  * import * as utilities from "@radically-straightforward/utilities";
28
- * import * as node from "@radically-straightforward/node";
29
32
  *
30
33
  * const backgroundJob = utilities.backgroundJob(
31
34
  * { interval: 3 * 1000 },
@@ -35,36 +38,32 @@
35
38
  * console.log("backgroundJob(): ...finished running background job.");
36
39
  * },
37
40
  * );
38
- * console.log(
39
- * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
40
- * );
41
41
  * process.on("SIGTSTP", () => {
42
42
  * backgroundJob.run();
43
43
  * });
44
- * await node.shouldTerminate();
45
- * backgroundJob.stop();
44
+ * console.log(
45
+ * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
46
+ * );
46
47
  * ```
47
48
  */
48
49
  export function backgroundJob({ interval, intervalVariance = 0.1, }, job) {
49
- let state = "initial";
50
+ let state = "sleeping";
50
51
  let timeout = undefined;
51
- async function run() {
52
- state = "running";
53
- await job();
54
- if (state === "running" || state === "runningAndMarkedForRerun") {
55
- timeout = setTimeout(run, state === "runningAndMarkedForRerun"
56
- ? 0
57
- : interval + interval * intervalVariance * Math.random());
58
- state = "sleeping";
59
- }
60
- }
61
- run();
62
- return {
63
- run: () => {
52
+ const scheduler = {
53
+ run: async () => {
64
54
  switch (state) {
65
55
  case "sleeping":
66
56
  clearTimeout(timeout);
67
- run();
57
+ state = "running";
58
+ await job();
59
+ if (state === "running" || state === "runningAndMarkedForRerun") {
60
+ timeout = setTimeout(() => {
61
+ scheduler.run();
62
+ }, state === "runningAndMarkedForRerun"
63
+ ? 0
64
+ : interval + interval * intervalVariance * Math.random());
65
+ state = "sleeping";
66
+ }
68
67
  break;
69
68
  case "running":
70
69
  state = "runningAndMarkedForRerun";
@@ -72,11 +71,16 @@ export function backgroundJob({ interval, intervalVariance = 0.1, }, job) {
72
71
  }
73
72
  },
74
73
  stop: () => {
75
- if (state === "sleeping")
76
- clearTimeout(timeout);
74
+ clearTimeout(timeout);
77
75
  state = "stopped";
78
76
  },
79
77
  };
78
+ scheduler.run();
79
+ if (process !== undefined)
80
+ process.once("gracefulTermination", () => {
81
+ scheduler.stop();
82
+ });
83
+ return scheduler;
80
84
  }
81
85
  /**
82
86
  * A promisified version of `setTimeout()`. Bare-bones: It doesn’t even offer a way to `clearTimeout()`. Useful in JavaScript that may run in the browser—if you’re only targeting Node.js then you’re better served by [`timersPromises.setTimeout()`](https://nodejs.org/dist/latest-v21.x/docs/api/timers.html#timerspromisessettimeoutdelay-value-options).
@@ -85,7 +89,7 @@ export function sleep(duration) {
85
89
  return new Promise((resolve) => setTimeout(resolve, duration));
86
90
  }
87
91
  /**
88
- * A fast random string generator. The generated strings are 10 or 11 characters in length. The generated strings include the characters `[0-9a-z]`. The generated strings are **not** cryptographically secure—if you need that, then use [`crypto-random-string`](https://npm.im/crypto-random-string).
92
+ * A fast random string generator. The generated strings are 10 or 11 characters in length. The generated strings include the characters `[0-9a-z]`. The generated strings are **not** cryptographically secure—if you need that, then use [`crypto-random-string`](https://www.npmjs.com/package/crypto-random-string).
89
93
  */
90
94
  export function randomString() {
91
95
  return Math.random().toString(36).slice(2);
@@ -94,7 +98,7 @@ export function randomString() {
94
98
  * Tab-separated logging.
95
99
  */
96
100
  export function log(...messageParts) {
97
- console.log(messageParts.join(" \t"));
101
+ console.log([new Date().toISOString(), ...messageParts].join(" \t"));
98
102
  }
99
103
  /**
100
104
  * [Interning](<https://en.wikipedia.org/wiki/Interning_(computer_science)>) a value makes it unique across the program, which is useful for checking equality with `===` (reference equality), using it as a key in a `Map`, adding it to a `Set`, and so forth:
@@ -160,7 +164,7 @@ export function log(...messageParts) {
160
164
  *
161
165
  * It includes a [polyfill](https://github.com/bloomberg/record-tuple-polyfill) which works very similarly to `intern()` but requires different functions for different data types.
162
166
  *
163
- * **[`collections-deep-equal`](https://npm.im/collections-deep-equal)**
167
+ * **[`collections-deep-equal`](https://www.npmjs.com/package/collections-deep-equal)**
164
168
  *
165
169
  * A previous solution to this problem which took a different approach: Instead of interning the values and allowing you to use JavaScript’s `Map`s and `Set`s, `collections-deep-equal` extends `Map`s and `Set`s with a different notion of equality.
166
170
  *
@@ -170,21 +174,21 @@ export function log(...messageParts) {
170
174
  *
171
175
  * `collections-deep-equal` has different intern pools for each `Map` and `Set` instead of `intern()`’s single global intern pool, which may be advantageous because smaller pools may be faster to traverse.
172
176
  *
173
- * **[Immutable.js](https://npm.im/immutable), [`collections`](https://npm.im/collections), [`mori`](https://npm.im/mori), [TypeScript Collections](https://npm.im/typescript-collections), [`prelude-ts`](https://npm.im/prelude-ts), [`collectable`](https://npm.im/collectable), and so forth**
177
+ * **[Immutable.js](https://www.npmjs.com/package/immutable), [`collections`](https://www.npmjs.com/package/collections), [`mori`](https://www.npmjs.com/package/mori), [TypeScript Collections](https://www.npmjs.com/package/typescript-collections), [`prelude-ts`](https://www.npmjs.com/package/prelude-ts), [`collectable`](https://www.npmjs.com/package/collectable), and so forth**
174
178
  *
175
179
  * Similar to `collections-deep-equal`, these libraries implement their own data structures instead of relying on JavaScript’s `Map`s and `Set`s. Some of them go a step further and add their own notions of objects and arrays, which requires you to convert your values back and forth, may not show up nicely in the JavaScript inspector, may be less ergonomic to use with TypeScript, and so forth.
176
180
  *
177
181
  * The advantage of these libraries over interning is that they may be faster.
178
182
  *
179
- * **[`immer`](https://npm.im/immer) and [`icepick`](https://npm.im/icepick)**
183
+ * **[`immer`](https://www.npmjs.com/package/immer) and [`icepick`](https://www.npmjs.com/package/icepick)**
180
184
  *
181
185
  * Introduce a new way to create values based on existing values.
182
186
  *
183
- * **[`seamless-immutable`](https://npm.im/seamless-immutable)**
187
+ * **[`seamless-immutable`](https://www.npmjs.com/package/seamless-immutable)**
184
188
  *
185
189
  * Modifies existing values more profoundly than freezing.
186
190
  *
187
- * **[`es6-array-map`](https://npm.im/es6-array-map), [`valuecollection`](https://npm.im/valuecollection), [`@strong-roots-capital/map-objects`](https://npm.im/@strong-roots-capital/map-objects), and so forth**
191
+ * **[`es6-array-map`](https://www.npmjs.com/package/es6-array-map), [`valuecollection`](https://www.npmjs.com/package/valuecollection), [`@strong-roots-capital/map-objects`](https://www.npmjs.com/package/@strong-roots-capital/map-objects), and so forth**
188
192
  *
189
193
  * Similar to `collections-deep-equal` but either incomplete, or lacking type definitions, and so forth.
190
194
  *
@@ -216,14 +220,12 @@ export function intern(value) {
216
220
  return internValue;
217
221
  }
218
222
  for (const innerValue of Object.values(value))
219
- if (!([
220
- "string",
221
- "number",
222
- "bigint",
223
- "boolean",
224
- "symbol",
225
- "undefined",
226
- ].includes(typeof innerValue) ||
223
+ if (!(typeof innerValue === "string" ||
224
+ typeof innerValue === "number" ||
225
+ typeof innerValue === "bigint" ||
226
+ typeof innerValue === "boolean" ||
227
+ typeof innerValue === "symbol" ||
228
+ innerValue === undefined ||
227
229
  innerValue === null ||
228
230
  innerValue[internSymbol] === true))
229
231
  throw new Error(`Failed to intern value because of non-interned inner value.`);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../source/index.mts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,MAAM,UAAU,aAAa,CAC3B,EACE,QAAQ,EACR,gBAAgB,GAAG,GAAG,GAC0B,EAClD,GAA+B;IAE/B,IAAI,KAAK,GAKO,SAAS,CAAC;IAC1B,IAAI,OAAO,GAAQ,SAAS,CAAC;IAC7B,KAAK,UAAU,GAAG;QAChB,KAAK,GAAG,SAAS,CAAC;QAClB,MAAM,GAAG,EAAE,CAAC;QACZ,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,0BAA0B,EAAE,CAAC;YAChE,OAAO,GAAG,UAAU,CAClB,GAAG,EACF,KAAa,KAAK,0BAA0B;gBAC3C,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,IAAI,CAAC,MAAM,EAAE,CAC3D,CAAC;YACF,KAAK,GAAG,UAAU,CAAC;QACrB,CAAC;IACH,CAAC;IACD,GAAG,EAAE,CAAC;IACN,OAAO;QACL,GAAG,EAAE,GAAG,EAAE;YACR,QAAQ,KAAK,EAAE,CAAC;gBACd,KAAK,UAAU;oBACb,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,GAAG,EAAE,CAAC;oBACN,MAAM;gBACR,KAAK,SAAS;oBACZ,KAAK,GAAG,0BAA0B,CAAC;oBACnC,MAAM;YACV,CAAC;QACH,CAAC;QACD,IAAI,EAAE,GAAG,EAAE;YACT,IAAI,KAAK,KAAK,UAAU;gBAAE,YAAY,CAAC,OAAO,CAAC,CAAC;YAChD,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,QAAgB;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,GAAG,YAAsB;IAC3C,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACxC,CAAC;AAoBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AACH,MAAM,UAAU,MAAM,CAEpB,KAAQ;IACR,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC/B,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAC3C,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,CAAC,GAAG,EAAE;gBACJ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC7C,CAAC,CAAC,EAAE,CAAC;IACX,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QACvD,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC;QAC1C,IACE,WAAW,KAAK,SAAS;YACzB,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM;YAE/C,SAAS;QACX,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAE,KAAa,CAAC,GAAG,CAAC,KAAM,WAAmB,CAAC,GAAG,CAAC,CAAC;YACxE,OAAO,WAAkB,CAAC;IAC9B,CAAC;IACD,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;QAC3C,IACE,CAAC,CACC;YACE,QAAQ;YACR,QAAQ;YACR,QAAQ;YACR,SAAS;YACT,QAAQ;YACR,WAAW;SACZ,CAAC,QAAQ,CAAC,OAAO,UAAU,CAAC;YAC7B,UAAU,KAAK,IAAI;YAClB,UAAkB,CAAC,YAAY,CAAC,KAAK,IAAI,CAC3C;YAED,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACN,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACpB,KAAa,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IACpC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,KAAY,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,oBAAoB,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3D,OAAO,KAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,CAAC,IAAI,GAAG;IACZ,KAAK,EAAE,IAAI,GAAG,EAA+C;IAC7D,MAAM,EAAE,IAAI,GAAG,EAGZ;CACJ,CAAC;AAEF,MAAM,CAAC,oBAAoB,GAAG,IAAI,oBAAoB,CAGnD,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;IACnB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../source/index.mts"],"names":[],"mappings":"AAAA,IAAI,OAAO,KAAK,SAAS;IAAE,MAAM,MAAM,CAAC,iCAAiC,CAAC,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,UAAU,aAAa,CAC3B,EACE,QAAQ,EACR,gBAAgB,GAAG,GAAG,GAC0B,EAClD,GAA+B;IAE/B,IAAI,KAAK,GACP,UAAU,CAAC;IACb,IAAI,OAAO,GAAQ,SAAS,CAAC;IAC7B,MAAM,SAAS,GAAG;QAChB,GAAG,EAAE,KAAK,IAAI,EAAE;YACd,QAAQ,KAAK,EAAE,CAAC;gBACd,KAAK,UAAU;oBACb,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,KAAK,GAAG,SAAS,CAAC;oBAClB,MAAM,GAAG,EAAE,CAAC;oBACZ,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,0BAA0B,EAAE,CAAC;wBAChE,OAAO,GAAG,UAAU,CAClB,GAAG,EAAE;4BACH,SAAS,CAAC,GAAG,EAAE,CAAC;wBAClB,CAAC,EACA,KAAa,KAAK,0BAA0B;4BAC3C,CAAC,CAAC,CAAC;4BACH,CAAC,CAAC,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,IAAI,CAAC,MAAM,EAAE,CAC3D,CAAC;wBACF,KAAK,GAAG,UAAU,CAAC;oBACrB,CAAC;oBACD,MAAM;gBACR,KAAK,SAAS;oBACZ,KAAK,GAAG,0BAA0B,CAAC;oBACnC,MAAM;YACV,CAAC;QACH,CAAC;QACD,IAAI,EAAE,GAAG,EAAE;YACT,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;KACF,CAAC;IACF,SAAS,CAAC,GAAG,EAAE,CAAC;IAChB,IAAI,OAAO,KAAK,SAAS;QACvB,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE;YACvC,SAAS,CAAC,IAAI,EAAE,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,QAAgB;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,GAAG,YAAsB;IAC3C,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACvE,CAAC;AAoBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AACH,MAAM,UAAU,MAAM,CAEpB,KAAW;IACX,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC/B,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAC3C,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,CAAC,GAAG,EAAE;gBACJ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC7C,CAAC,CAAC,EAAE,CAAC;IACX,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QACvD,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC;QAC1C,IACE,WAAW,KAAK,SAAS;YACzB,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM;YAE/C,SAAS;QACX,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAE,KAAa,CAAC,GAAG,CAAC,KAAM,WAAmB,CAAC,GAAG,CAAC,CAAC;YACxE,OAAO,WAAkB,CAAC;IAC9B,CAAC;IACD,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;QAC3C,IACE,CAAC,CACC,OAAO,UAAU,KAAK,QAAQ;YAC9B,OAAO,UAAU,KAAK,QAAQ;YAC9B,OAAO,UAAU,KAAK,QAAQ;YAC9B,OAAO,UAAU,KAAK,SAAS;YAC/B,OAAO,UAAU,KAAK,QAAQ;YAC9B,UAAU,KAAK,SAAS;YACxB,UAAU,KAAK,IAAI;YAClB,UAAkB,CAAC,YAAY,CAAC,KAAK,IAAI,CAC3C;YAED,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACN,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACpB,KAAa,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IACpC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,KAAY,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,oBAAoB,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3D,OAAO,KAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,CAAC,IAAI,GAAG;IACZ,KAAK,EAAE,IAAI,GAAG,EAA+C;IAC7D,MAAM,EAAE,IAAI,GAAG,EAGZ;CACJ,CAAC;AAEF,MAAM,CAAC,oBAAoB,GAAG,IAAI,oBAAoB,CAGnD,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;IACnB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC"}
@@ -1,26 +1,21 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import * as node from "@radically-straightforward/node";
4
- import * as utilities from "./index.mjs";
5
- import { intern as $ } from "./index.mjs";
3
+ import * as utilities from "@radically-straightforward/utilities";
4
+ import { intern as $ } from "@radically-straightforward/utilities";
6
5
  test("backgroundJob()", {
7
- ...(!process.stdin.isTTY
8
- ? {
9
- skip: "Run interactive test with ‘node ./build/index.test.mjs’.",
10
- }
11
- : {}),
6
+ skip: process.stdin.isTTY
7
+ ? false
8
+ : "Run interactive test with ‘node ./build/index.test.mjs’.",
12
9
  }, async () => {
13
10
  const backgroundJob = utilities.backgroundJob({ interval: 3 * 1000 }, async () => {
14
11
  console.log("backgroundJob(): Running background job...");
15
12
  await utilities.sleep(3 * 1000);
16
13
  console.log("backgroundJob(): ...finished running background job.");
17
14
  });
18
- console.log("backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...");
19
15
  process.on("SIGTSTP", () => {
20
16
  backgroundJob.run();
21
17
  });
22
- await node.shouldTerminate();
23
- backgroundJob.stop();
18
+ console.log("backgroundJob(): Press ⌃Z to force background job to run and ⌃C to gracefully terminate...");
24
19
  });
25
20
  test("sleep()", async () => {
26
21
  const before = Date.now();
@@ -78,5 +73,20 @@ test("intern()", () => {
78
73
  // @ts-expect-error
79
74
  $([1])[0] = 2;
80
75
  });
76
+ {
77
+ const iterations = 1000;
78
+ console.time("intern()");
79
+ const objects = [];
80
+ for (let iteration = 0; iteration < iterations; iteration++) {
81
+ const entries = [];
82
+ for (let key = 0; key < Math.floor(Math.random() * 15); key++) {
83
+ entries.push([String(key + Math.floor(Math.random() * 15)), true]);
84
+ }
85
+ objects.push($(Object.fromEntries(entries)));
86
+ objects.push($(entries.flat()));
87
+ }
88
+ // console.log($.pool.record.size);
89
+ console.timeEnd("intern()");
90
+ }
81
91
  });
82
92
  //# sourceMappingURL=index.test.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.test.mjs","sourceRoot":"","sources":["../source/index.test.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.test.mjs","sourceRoot":"","sources":["../source/index.test.mts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radically-straightforward/utilities",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "🛠️ Utilities for Node.js and the browser",
5
5
  "keywords": [
6
6
  "node",
@@ -25,11 +25,13 @@
25
25
  "types": "./build/index.d.mts",
26
26
  "scripts": {
27
27
  "prepare": "tsc && documentation",
28
- "test": "npm run prepare && node --test && prettier --check \"./README.md\" --check \"./package.json\" --check \"./tsconfig.json\" --check \"./source/**/*.mts\""
28
+ "test": "npm run prepare && node --test && prettier --check \"./README.md\" --check \"./CHANGELOG.md\" --check \"./package.json\" --check \"./tsconfig.json\" --check \"./source/**/*.mts\""
29
+ },
30
+ "dependencies": {
31
+ "@radically-straightforward/node": "^3.0.0"
29
32
  },
30
33
  "devDependencies": {
31
34
  "@radically-straightforward/documentation": "^1.0.1",
32
- "@radically-straightforward/node": "^2.0.1",
33
35
  "@radically-straightforward/tsconfig": "^1.0.0",
34
36
  "@types/node": "^20.10.6",
35
37
  "prettier": "^3.1.1",
package/source/index.mts CHANGED
@@ -1,3 +1,5 @@
1
+ if (process !== undefined) await import("@radically-straightforward/node");
2
+
1
3
  /**
2
4
  * Start a background job that runs every `interval`.
3
5
  *
@@ -17,15 +19,16 @@
17
19
  *
18
20
  * 2. We introduce a random `intervalVariance` to avoid many background jobs from starting at the same time and overloading the machine.
19
21
  *
20
- * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (not waiting the interval).
22
+ * 3. You may use `backgroundJob.run()` to force the background job to run right away. If the background job is already running, calling `backgroundJob.run()` schedules it to run again as soon as possible (with a wait interval of 0).
21
23
  *
22
24
  * 4. You may use `backgroundJob.stop()` to stop the background job. If the background job is running, it will finish but it will not be scheduled to run again. This is similar to how an HTTP server may terminate gracefully by stopping accepting new requests but finishing responding to existing requests. After a job has been stopped, you may not `backgroundJob.run()` it again (calling `backgroundJob.run()` has no effect).
23
25
  *
26
+ * 5. In Node.js the background job is stopped on [`"gracefulTermination"`](https://github.com/radically-straightforward/radically-straightforward/tree/main/node#graceful-termination).
27
+ *
24
28
  * **Example**
25
29
  *
26
30
  * ```javascript
27
31
  * import * as utilities from "@radically-straightforward/utilities";
28
- * import * as node from "@radically-straightforward/node";
29
32
  *
30
33
  * const backgroundJob = utilities.backgroundJob(
31
34
  * { interval: 3 * 1000 },
@@ -35,14 +38,12 @@
35
38
  * console.log("backgroundJob(): ...finished running background job.");
36
39
  * },
37
40
  * );
38
- * console.log(
39
- * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
40
- * );
41
41
  * process.on("SIGTSTP", () => {
42
42
  * backgroundJob.run();
43
43
  * });
44
- * await node.shouldTerminate();
45
- * backgroundJob.stop();
44
+ * console.log(
45
+ * "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
46
+ * );
46
47
  * ```
47
48
  */
48
49
  export function backgroundJob(
@@ -52,33 +53,27 @@ export function backgroundJob(
52
53
  }: { interval: number; intervalVariance?: number },
53
54
  job: () => void | Promise<void>,
54
55
  ): { run: () => void; stop: () => void } {
55
- let state:
56
- | "initial"
57
- | "running"
58
- | "runningAndMarkedForRerun"
59
- | "sleeping"
60
- | "stopped" = "initial";
56
+ let state: "sleeping" | "running" | "runningAndMarkedForRerun" | "stopped" =
57
+ "sleeping";
61
58
  let timeout: any = undefined;
62
- async function run() {
63
- state = "running";
64
- await job();
65
- if (state === "running" || state === "runningAndMarkedForRerun") {
66
- timeout = setTimeout(
67
- run,
68
- (state as any) === "runningAndMarkedForRerun"
69
- ? 0
70
- : interval + interval * intervalVariance * Math.random(),
71
- );
72
- state = "sleeping";
73
- }
74
- }
75
- run();
76
- return {
77
- run: () => {
59
+ const scheduler = {
60
+ run: async () => {
78
61
  switch (state) {
79
62
  case "sleeping":
80
63
  clearTimeout(timeout);
81
- run();
64
+ state = "running";
65
+ await job();
66
+ if (state === "running" || state === "runningAndMarkedForRerun") {
67
+ timeout = setTimeout(
68
+ () => {
69
+ scheduler.run();
70
+ },
71
+ (state as any) === "runningAndMarkedForRerun"
72
+ ? 0
73
+ : interval + interval * intervalVariance * Math.random(),
74
+ );
75
+ state = "sleeping";
76
+ }
82
77
  break;
83
78
  case "running":
84
79
  state = "runningAndMarkedForRerun";
@@ -86,10 +81,16 @@ export function backgroundJob(
86
81
  }
87
82
  },
88
83
  stop: () => {
89
- if (state === "sleeping") clearTimeout(timeout);
84
+ clearTimeout(timeout);
90
85
  state = "stopped";
91
86
  },
92
87
  };
88
+ scheduler.run();
89
+ if (process !== undefined)
90
+ process.once("gracefulTermination", () => {
91
+ scheduler.stop();
92
+ });
93
+ return scheduler;
93
94
  }
94
95
 
95
96
  /**
@@ -100,7 +101,7 @@ export function sleep(duration: number): Promise<void> {
100
101
  }
101
102
 
102
103
  /**
103
- * A fast random string generator. The generated strings are 10 or 11 characters in length. The generated strings include the characters `[0-9a-z]`. The generated strings are **not** cryptographically secure—if you need that, then use [`crypto-random-string`](https://npm.im/crypto-random-string).
104
+ * A fast random string generator. The generated strings are 10 or 11 characters in length. The generated strings include the characters `[0-9a-z]`. The generated strings are **not** cryptographically secure—if you need that, then use [`crypto-random-string`](https://www.npmjs.com/package/crypto-random-string).
104
105
  */
105
106
  export function randomString(): string {
106
107
  return Math.random().toString(36).slice(2);
@@ -110,7 +111,7 @@ export function randomString(): string {
110
111
  * Tab-separated logging.
111
112
  */
112
113
  export function log(...messageParts: string[]): void {
113
- console.log(messageParts.join(" \t"));
114
+ console.log([new Date().toISOString(), ...messageParts].join(" \t"));
114
115
  }
115
116
 
116
117
  /**
@@ -195,7 +196,7 @@ export type InternInnerValue =
195
196
  *
196
197
  * It includes a [polyfill](https://github.com/bloomberg/record-tuple-polyfill) which works very similarly to `intern()` but requires different functions for different data types.
197
198
  *
198
- * **[`collections-deep-equal`](https://npm.im/collections-deep-equal)**
199
+ * **[`collections-deep-equal`](https://www.npmjs.com/package/collections-deep-equal)**
199
200
  *
200
201
  * A previous solution to this problem which took a different approach: Instead of interning the values and allowing you to use JavaScript’s `Map`s and `Set`s, `collections-deep-equal` extends `Map`s and `Set`s with a different notion of equality.
201
202
  *
@@ -205,21 +206,21 @@ export type InternInnerValue =
205
206
  *
206
207
  * `collections-deep-equal` has different intern pools for each `Map` and `Set` instead of `intern()`’s single global intern pool, which may be advantageous because smaller pools may be faster to traverse.
207
208
  *
208
- * **[Immutable.js](https://npm.im/immutable), [`collections`](https://npm.im/collections), [`mori`](https://npm.im/mori), [TypeScript Collections](https://npm.im/typescript-collections), [`prelude-ts`](https://npm.im/prelude-ts), [`collectable`](https://npm.im/collectable), and so forth**
209
+ * **[Immutable.js](https://www.npmjs.com/package/immutable), [`collections`](https://www.npmjs.com/package/collections), [`mori`](https://www.npmjs.com/package/mori), [TypeScript Collections](https://www.npmjs.com/package/typescript-collections), [`prelude-ts`](https://www.npmjs.com/package/prelude-ts), [`collectable`](https://www.npmjs.com/package/collectable), and so forth**
209
210
  *
210
211
  * Similar to `collections-deep-equal`, these libraries implement their own data structures instead of relying on JavaScript’s `Map`s and `Set`s. Some of them go a step further and add their own notions of objects and arrays, which requires you to convert your values back and forth, may not show up nicely in the JavaScript inspector, may be less ergonomic to use with TypeScript, and so forth.
211
212
  *
212
213
  * The advantage of these libraries over interning is that they may be faster.
213
214
  *
214
- * **[`immer`](https://npm.im/immer) and [`icepick`](https://npm.im/icepick)**
215
+ * **[`immer`](https://www.npmjs.com/package/immer) and [`icepick`](https://www.npmjs.com/package/icepick)**
215
216
  *
216
217
  * Introduce a new way to create values based on existing values.
217
218
  *
218
- * **[`seamless-immutable`](https://npm.im/seamless-immutable)**
219
+ * **[`seamless-immutable`](https://www.npmjs.com/package/seamless-immutable)**
219
220
  *
220
221
  * Modifies existing values more profoundly than freezing.
221
222
  *
222
- * **[`es6-array-map`](https://npm.im/es6-array-map), [`valuecollection`](https://npm.im/valuecollection), [`@strong-roots-capital/map-objects`](https://npm.im/@strong-roots-capital/map-objects), and so forth**
223
+ * **[`es6-array-map`](https://www.npmjs.com/package/es6-array-map), [`valuecollection`](https://www.npmjs.com/package/valuecollection), [`@strong-roots-capital/map-objects`](https://www.npmjs.com/package/@strong-roots-capital/map-objects), and so forth**
223
224
  *
224
225
  * Similar to `collections-deep-equal` but either incomplete, or lacking type definitions, and so forth.
225
226
  *
@@ -234,8 +235,8 @@ export type InternInnerValue =
234
235
  * - <https://gist.github.com/modernserf/c000e62d40f678cf395e3f360b9b0e43>
235
236
  */
236
237
  export function intern<
237
- T extends Array<InternInnerValue> | { [key: string]: InternInnerValue },
238
- >(value: T): Intern<T> {
238
+ Type extends Array<InternInnerValue> | { [key: string]: InternInnerValue },
239
+ >(value: Type): Intern<Type> {
239
240
  const type = Array.isArray(value)
240
241
  ? "tuple"
241
242
  : typeof value === "object" && value !== null
@@ -257,14 +258,12 @@ export function intern<
257
258
  for (const innerValue of Object.values(value))
258
259
  if (
259
260
  !(
260
- [
261
- "string",
262
- "number",
263
- "bigint",
264
- "boolean",
265
- "symbol",
266
- "undefined",
267
- ].includes(typeof innerValue) ||
261
+ typeof innerValue === "string" ||
262
+ typeof innerValue === "number" ||
263
+ typeof innerValue === "bigint" ||
264
+ typeof innerValue === "boolean" ||
265
+ typeof innerValue === "symbol" ||
266
+ innerValue === undefined ||
268
267
  innerValue === null ||
269
268
  (innerValue as any)[internSymbol] === true
270
269
  )
@@ -1,17 +1,14 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import * as node from "@radically-straightforward/node";
4
- import * as utilities from "./index.mjs";
5
- import { intern as $ } from "./index.mjs";
3
+ import * as utilities from "@radically-straightforward/utilities";
4
+ import { intern as $ } from "@radically-straightforward/utilities";
6
5
 
7
6
  test(
8
7
  "backgroundJob()",
9
8
  {
10
- ...(!process.stdin.isTTY
11
- ? {
12
- skip: "Run interactive test with ‘node ./build/index.test.mjs’.",
13
- }
14
- : {}),
9
+ skip: process.stdin.isTTY
10
+ ? false
11
+ : "Run interactive test with ‘node ./build/index.test.mjs’.",
15
12
  },
16
13
  async () => {
17
14
  const backgroundJob = utilities.backgroundJob(
@@ -22,14 +19,12 @@ test(
22
19
  console.log("backgroundJob(): ...finished running background job.");
23
20
  },
24
21
  );
25
- console.log(
26
- "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to continue...",
27
- );
28
22
  process.on("SIGTSTP", () => {
29
23
  backgroundJob.run();
30
24
  });
31
- await node.shouldTerminate();
32
- backgroundJob.stop();
25
+ console.log(
26
+ "backgroundJob(): Press ⌃Z to force background job to run and ⌃C to gracefully terminate...",
27
+ );
33
28
  },
34
29
  );
35
30
 
@@ -99,4 +94,20 @@ test("intern()", () => {
99
94
  // @ts-expect-error
100
95
  $([1])[0] = 2;
101
96
  });
97
+
98
+ {
99
+ const iterations = 1000;
100
+ console.time("intern()");
101
+ const objects = [];
102
+ for (let iteration = 0; iteration < iterations; iteration++) {
103
+ const entries = [];
104
+ for (let key = 0; key < Math.floor(Math.random() * 15); key++) {
105
+ entries.push([String(key + Math.floor(Math.random() * 15)), true]);
106
+ }
107
+ objects.push($(Object.fromEntries(entries)));
108
+ objects.push($(entries.flat()));
109
+ }
110
+ // console.log($.pool.record.size);
111
+ console.timeEnd("intern()");
112
+ }
102
113
  });