@dr.pogodin/js-utils 0.0.18 → 0.1.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/README.md CHANGED
@@ -52,6 +52,10 @@ and used in the same way):
52
52
  ### Classes
53
53
  - [Barrier] — A [Promise] with **resolve()** and **reject()** exposed as
54
54
  instance methods.
55
+
56
+ - `Cached` — Implements a cache of (a)synchronously retrieved items with
57
+ timestamp-based expiration. _To be documented_.
58
+
55
59
  - [Emitter](https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Emitter)
56
60
  — Simple listeneable data emitter.
57
61
  - [Semaphore](https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Semaphore)
@@ -34,7 +34,7 @@ var STATE = /*#__PURE__*/function (STATE) {
34
34
  * Docs: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier
35
35
  */
36
36
  class Barrier extends Promise {
37
- pState = (() => STATE.PENDING)();
37
+ pState = STATE.PENDING;
38
38
  constructor(executor) {
39
39
  let resolveRef;
40
40
  let rejectRef;
@@ -1 +1 @@
1
- {"version":3,"file":"Barrier.js","names":["STATE","Barrier","Promise","pState","PENDING","constructor","executor","resolveRef","rejectRef","resolve","reject","value","RESOLVED","reason","REJECTED","pResolve","pReject","arg","resolved","rejected","settled","catch","onRejected","finally","onFinally","then","onFulfilled","res","exports","default"],"sources":["../../src/Barrier.ts"],"sourcesContent":["export type Executor<T> = ConstructorParameters<typeof Promise<T>>[0];\n\ntype Resolver<T> = Parameters<Executor<T>>[0];\ntype Rejecter = Parameters<Executor<unknown>>[1];\n\nenum STATE {\n PENDING = 'PENDING',\n REJECTED = 'REJECTED',\n RESOLVED = 'RESOLVED',\n}\n\n/**\n * Barrier is just a Promise which has resolve and reject exposed as instance\n * methods.\n *\n * It has two generic arguments T and TR which correspond to the argument of\n * the .resolve() method, and to the value resolved by the promise (barrier).\n * For a simple barrier TR equals to T, however for barriers created via .then()\n * chain, T corresponds to the argument of the original barrier, and TR to\n * the value resolved by the latest promise in the chain. Consider this:\n *\n * const b = new Barrier<string>();\n * b.resolve('result');\n * const s = await b; // `s` has `string` type, and equals \"result\".\n *\n * const b = (new Barrier<string>()).then((s) => s.length);\n * b.resolve('result'); // Chained barrier exposes .resolve() method of\n * // the first barrier in the chain, which expects\n * // `string` arugment (T), but the chained barrier\n * // resolves to `number` (TR).\n * const n = await b; // `n` has `number` type, and equals 6.\n *\n * Docs: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier\n */\nexport default class Barrier<T = unknown, TR = T> extends Promise<TR> {\n private pResolve: Resolver<T>;\n\n private pReject: Rejecter;\n\n private pState = STATE.PENDING;\n\n constructor(executor?: Executor<TR>) {\n let resolveRef: Resolver<TR>;\n let rejectRef: Rejecter;\n\n super((resolve, reject) => {\n // Note: Enforcing `void` return type because of the BEWARE note below.\n resolveRef = (value: TR | PromiseLike<TR>): void => {\n resolve(value);\n this.pState = STATE.RESOLVED;\n\n // BEWARE: Don't try to return `this` here, it will easily cause\n // infinite loops in React Native, which are extremely difficult\n // to troubleshoot (I wasn't able to figure out, are they due to\n // internal Promise implementation in RN, or because of some bad\n // patterns in the host code).\n };\n\n // Note: Enforcing `void` return type because of the BEWARE note below.\n rejectRef = (reason?: unknown): void => {\n reject(reason);\n this.pState = STATE.REJECTED;\n };\n\n if (executor) executor(resolveRef, rejectRef);\n });\n\n // NOTE: We assume, the only scenario where TR is not equal T is when\n // the Barrier is constructed by a .then() call on a \"parent\" barrier,\n // and in that scenario .then() itself will replace .p_resolve by another\n // resolver immediately after this constructor returns.\n this.pResolve = resolveRef! as Resolver<T>;\n\n this.pReject = rejectRef!;\n }\n\n get resolve() {\n return (arg: Parameters<Resolver<T>>[0]): this => {\n this.pResolve(arg);\n return this;\n };\n }\n\n get reject() {\n return (arg: Parameters<Rejecter>[0]): this => {\n this.pReject(arg);\n return this;\n };\n }\n\n get resolved(): boolean {\n return this.pState === STATE.RESOLVED;\n }\n\n get rejected(): boolean {\n return this.pState === STATE.REJECTED;\n }\n\n get settled(): boolean {\n return this.pState !== STATE.PENDING;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n catch<TR1>(\n onRejected?: ((reason: unknown) => TR1 | PromiseLike<TR1>) | null,\n ): Barrier<T, TR1> {\n return super.catch(onRejected) as Barrier<T, TR1>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n finally(onFinally?: (() => void) | null): Barrier<TR> {\n return super.finally(onFinally) as Barrier<TR>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n then<TR1, TR2>(\n onFulfilled?: ((value: TR) => TR1 | PromiseLike<TR1>) | null,\n onRejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null,\n ): Barrier<T, TR1 | TR2> {\n const res = super.then(onFulfilled, onRejected) as Barrier<T, TR1 | TR2>;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pResolve = this.resolve;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pReject = this.reject;\n return res;\n }\n}\n"],"mappings":";;;;;;IAKKA,KAAK,0BAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAAA,OAALA,KAAK;AAAA,EAALA,KAAK;AAMV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,MAAMC,OAAO,SAA8BC,OAAO,CAAK;EAK5DC,MAAM,UAAGH,KAAK,CAACI,OAAO;EAE9BC,WAAWA,CAACC,QAAuB,EAAE;IACnC,IAAIC,UAAwB;IAC5B,IAAIC,SAAmB;IAEvB,KAAK,CAAC,CAACC,OAAO,EAAEC,MAAM,KAAK;MACzB;MACAH,UAAU,GAAII,KAA2B,IAAW;QAClDF,OAAO,CAACE,KAAK,CAAC;QACd,IAAI,CAACR,MAAM,GAAGH,KAAK,CAACY,QAAQ;;QAE5B;QACA;QACA;QACA;QACA;MACF,CAAC;;MAED;MACAJ,SAAS,GAAIK,MAAgB,IAAW;QACtCH,MAAM,CAACG,MAAM,CAAC;QACd,IAAI,CAACV,MAAM,GAAGH,KAAK,CAACc,QAAQ;MAC9B,CAAC;MAED,IAAIR,QAAQ,EAAEA,QAAQ,CAACC,UAAU,EAAEC,SAAS,CAAC;IAC/C,CAAC,CAAC;;IAEF;IACA;IACA;IACA;IACA,IAAI,CAACO,QAAQ,GAAGR,UAA0B;IAE1C,IAAI,CAACS,OAAO,GAAGR,SAAU;EAC3B;EAEA,IAAIC,OAAOA,CAAA,EAAG;IACZ,OAAQQ,GAA+B,IAAW;MAChD,IAAI,CAACF,QAAQ,CAACE,GAAG,CAAC;MAClB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIP,MAAMA,CAAA,EAAG;IACX,OAAQO,GAA4B,IAAW;MAC7C,IAAI,CAACD,OAAO,CAACC,GAAG,CAAC;MACjB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIC,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAACf,MAAM,KAAKH,KAAK,CAACY,QAAQ;EACvC;EAEA,IAAIO,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAAChB,MAAM,KAAKH,KAAK,CAACc,QAAQ;EACvC;EAEA,IAAIM,OAAOA,CAAA,EAAY;IACrB,OAAO,IAAI,CAACjB,MAAM,KAAKH,KAAK,CAACI,OAAO;EACtC;;EAEA;EACA;EACA;EACA;EACA;EACAiB,KAAKA,CACHC,UAAiE,EAChD;IACjB,OAAO,KAAK,CAACD,KAAK,CAACC,UAAU,CAAC;EAChC;;EAEA;EACA;EACA;EACA;EACA;EACAC,OAAOA,CAACC,SAA+B,EAAe;IACpD,OAAO,KAAK,CAACD,OAAO,CAACC,SAAS,CAAC;EACjC;;EAEA;EACA;EACA;EACA;EACA;EACAC,IAAIA,CACFC,WAA4D,EAC5DJ,UAAiE,EAC1C;IACvB,MAAMK,GAAG,GAAG,KAAK,CAACF,IAAI,CAACC,WAAW,EAAEJ,UAAU,CAA0B;IACxE;IACA;IACAK,GAAG,CAACZ,QAAQ,GAAG,IAAI,CAACN,OAAO;IAC3B;IACA;IACAkB,GAAG,CAACX,OAAO,GAAG,IAAI,CAACN,MAAM;IACzB,OAAOiB,GAAG;EACZ;AACF;AAACC,OAAA,CAAAC,OAAA,GAAA5B,OAAA","ignoreList":[]}
1
+ {"version":3,"file":"Barrier.js","names":["STATE","Barrier","Promise","pState","PENDING","constructor","executor","resolveRef","rejectRef","resolve","reject","value","RESOLVED","reason","REJECTED","pResolve","pReject","arg","resolved","rejected","settled","catch","onRejected","finally","onFinally","then","onFulfilled","res","exports","default"],"sources":["../../src/Barrier.ts"],"sourcesContent":["export type Executor<T> = ConstructorParameters<typeof Promise<T>>[0];\n\ntype Resolver<T> = Parameters<Executor<T>>[0];\ntype Rejecter = Parameters<Executor<unknown>>[1];\n\nenum STATE {\n PENDING = 'PENDING',\n REJECTED = 'REJECTED',\n RESOLVED = 'RESOLVED',\n}\n\n/**\n * Barrier is just a Promise which has resolve and reject exposed as instance\n * methods.\n *\n * It has two generic arguments T and TR which correspond to the argument of\n * the .resolve() method, and to the value resolved by the promise (barrier).\n * For a simple barrier TR equals to T, however for barriers created via .then()\n * chain, T corresponds to the argument of the original barrier, and TR to\n * the value resolved by the latest promise in the chain. Consider this:\n *\n * const b = new Barrier<string>();\n * b.resolve('result');\n * const s = await b; // `s` has `string` type, and equals \"result\".\n *\n * const b = (new Barrier<string>()).then((s) => s.length);\n * b.resolve('result'); // Chained barrier exposes .resolve() method of\n * // the first barrier in the chain, which expects\n * // `string` arugment (T), but the chained barrier\n * // resolves to `number` (TR).\n * const n = await b; // `n` has `number` type, and equals 6.\n *\n * Docs: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier\n */\nexport default class Barrier<T = unknown, TR = T> extends Promise<TR> {\n private pResolve: Resolver<T>;\n\n private pReject: Rejecter;\n\n private pState = STATE.PENDING;\n\n constructor(executor?: Executor<TR>) {\n let resolveRef: Resolver<TR>;\n let rejectRef: Rejecter;\n\n super((resolve, reject) => {\n // Note: Enforcing `void` return type because of the BEWARE note below.\n resolveRef = (value: TR | PromiseLike<TR>): void => {\n resolve(value);\n this.pState = STATE.RESOLVED;\n\n // BEWARE: Don't try to return `this` here, it will easily cause\n // infinite loops in React Native, which are extremely difficult\n // to troubleshoot (I wasn't able to figure out, are they due to\n // internal Promise implementation in RN, or because of some bad\n // patterns in the host code).\n };\n\n // Note: Enforcing `void` return type because of the BEWARE note below.\n rejectRef = (reason?: unknown): void => {\n reject(reason);\n this.pState = STATE.REJECTED;\n };\n\n if (executor) executor(resolveRef, rejectRef);\n });\n\n // NOTE: We assume, the only scenario where TR is not equal T is when\n // the Barrier is constructed by a .then() call on a \"parent\" barrier,\n // and in that scenario .then() itself will replace .p_resolve by another\n // resolver immediately after this constructor returns.\n this.pResolve = resolveRef! as Resolver<T>;\n\n this.pReject = rejectRef!;\n }\n\n get resolve() {\n return (arg: Parameters<Resolver<T>>[0]): this => {\n this.pResolve(arg);\n return this;\n };\n }\n\n get reject() {\n return (arg: Parameters<Rejecter>[0]): this => {\n this.pReject(arg);\n return this;\n };\n }\n\n get resolved(): boolean {\n return this.pState === STATE.RESOLVED;\n }\n\n get rejected(): boolean {\n return this.pState === STATE.REJECTED;\n }\n\n get settled(): boolean {\n return this.pState !== STATE.PENDING;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n catch<TR1>(\n onRejected?: ((reason: unknown) => TR1 | PromiseLike<TR1>) | null,\n ): Barrier<T, TR1> {\n return super.catch(onRejected) as Barrier<T, TR1>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n finally(onFinally?: (() => void) | null): Barrier<TR> {\n return super.finally(onFinally) as Barrier<TR>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n then<TR1, TR2>(\n onFulfilled?: ((value: TR) => TR1 | PromiseLike<TR1>) | null,\n onRejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null,\n ): Barrier<T, TR1 | TR2> {\n const res = super.then(onFulfilled, onRejected) as Barrier<T, TR1 | TR2>;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pResolve = this.resolve;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pReject = this.reject;\n return res;\n }\n}\n"],"mappings":";;;;;;IAKKA,KAAK,0BAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAAA,OAALA,KAAK;AAAA,EAALA,KAAK;AAMV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,MAAMC,OAAO,SAA8BC,OAAO,CAAK;EAK5DC,MAAM,GAAGH,KAAK,CAACI,OAAO;EAE9BC,WAAWA,CAACC,QAAuB,EAAE;IACnC,IAAIC,UAAwB;IAC5B,IAAIC,SAAmB;IAEvB,KAAK,CAAC,CAACC,OAAO,EAAEC,MAAM,KAAK;MACzB;MACAH,UAAU,GAAII,KAA2B,IAAW;QAClDF,OAAO,CAACE,KAAK,CAAC;QACd,IAAI,CAACR,MAAM,GAAGH,KAAK,CAACY,QAAQ;;QAE5B;QACA;QACA;QACA;QACA;MACF,CAAC;;MAED;MACAJ,SAAS,GAAIK,MAAgB,IAAW;QACtCH,MAAM,CAACG,MAAM,CAAC;QACd,IAAI,CAACV,MAAM,GAAGH,KAAK,CAACc,QAAQ;MAC9B,CAAC;MAED,IAAIR,QAAQ,EAAEA,QAAQ,CAACC,UAAU,EAAEC,SAAS,CAAC;IAC/C,CAAC,CAAC;;IAEF;IACA;IACA;IACA;IACA,IAAI,CAACO,QAAQ,GAAGR,UAA0B;IAE1C,IAAI,CAACS,OAAO,GAAGR,SAAU;EAC3B;EAEA,IAAIC,OAAOA,CAAA,EAAG;IACZ,OAAQQ,GAA+B,IAAW;MAChD,IAAI,CAACF,QAAQ,CAACE,GAAG,CAAC;MAClB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIP,MAAMA,CAAA,EAAG;IACX,OAAQO,GAA4B,IAAW;MAC7C,IAAI,CAACD,OAAO,CAACC,GAAG,CAAC;MACjB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIC,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAACf,MAAM,KAAKH,KAAK,CAACY,QAAQ;EACvC;EAEA,IAAIO,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAAChB,MAAM,KAAKH,KAAK,CAACc,QAAQ;EACvC;EAEA,IAAIM,OAAOA,CAAA,EAAY;IACrB,OAAO,IAAI,CAACjB,MAAM,KAAKH,KAAK,CAACI,OAAO;EACtC;;EAEA;EACA;EACA;EACA;EACA;EACAiB,KAAKA,CACHC,UAAiE,EAChD;IACjB,OAAO,KAAK,CAACD,KAAK,CAACC,UAAU,CAAC;EAChC;;EAEA;EACA;EACA;EACA;EACA;EACAC,OAAOA,CAACC,SAA+B,EAAe;IACpD,OAAO,KAAK,CAACD,OAAO,CAACC,SAAS,CAAC;EACjC;;EAEA;EACA;EACA;EACA;EACA;EACAC,IAAIA,CACFC,WAA4D,EAC5DJ,UAAiE,EAC1C;IACvB,MAAMK,GAAG,GAAG,KAAK,CAACF,IAAI,CAACC,WAAW,EAAEJ,UAAU,CAA0B;IACxE;IACA;IACAK,GAAG,CAACZ,QAAQ,GAAG,IAAI,CAACN,OAAO;IAC3B;IACA;IACAkB,GAAG,CAACX,OAAO,GAAG,IAAI,CAACN,MAAM;IACzB,OAAOiB,GAAG;EACZ;AACF;AAACC,OAAA,CAAAC,OAAA,GAAA5B,OAAA","ignoreList":[]}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Cached = void 0;
7
+ /** Adds timestamp to the promise. */
8
+ function addTimestamp(promise, timestamp) {
9
+ const res = promise;
10
+ res.timestamp = timestamp;
11
+ return res;
12
+ }
13
+
14
+ /** Gets entry timestamp. */
15
+ function getTimestamp(e) {
16
+ return Array.isArray(e) ? e[1] : e.timestamp;
17
+ }
18
+ class Cached {
19
+ data = {};
20
+ oldestTimestamp = Number.MAX_SAFE_INTEGER;
21
+
22
+ /** For test use only. */
23
+ get _data() {
24
+ return this.data;
25
+ }
26
+
27
+ /** For test use only. */
28
+ get _oldestTimestamp() {
29
+ return this.oldestTimestamp;
30
+ }
31
+ constructor(maxage, getter) {
32
+ this.maxage = maxage;
33
+ this.getter = getter;
34
+ }
35
+
36
+ /** Removes stale items from the cache, and updates .oldestTimestamp. */
37
+ cleanCache() {
38
+ const deadline = Date.now() - this.maxage;
39
+ this.oldestTimestamp = Number.MAX_SAFE_INTEGER;
40
+ for (const [key, entry] of Object.entries(this.data)) {
41
+ const timestamp = getTimestamp(entry);
42
+ if (timestamp < deadline) delete this.data[key];else if (timestamp < this.oldestTimestamp) {
43
+ this.oldestTimestamp = timestamp;
44
+ }
45
+ }
46
+ }
47
+
48
+ /** Adds `datum` to the cache, and removes stale items from the cache. */
49
+ set(id, datum) {
50
+ const now = Date.now();
51
+ if (this.oldestTimestamp < now - this.maxage) this.cleanCache();
52
+ if (now < this.oldestTimestamp) this.oldestTimestamp = now;
53
+ const res = [datum, now];
54
+ this.data[id] = res;
55
+ return res;
56
+ }
57
+
58
+ /** Retrieves envelope of the specified datum, either read from the cache,
59
+ * or retrieved using the getter provided at construction time. */
60
+ getEntry(id) {
61
+ const now = Date.now();
62
+ let cached = this.data[id];
63
+ if (cached && getTimestamp(cached) >= now - this.maxage) return cached;
64
+ const itemOrPromise = this.getter(id);
65
+ if (!(itemOrPromise instanceof Promise)) {
66
+ return this.set(id, itemOrPromise);
67
+ }
68
+ cached = addTimestamp(itemOrPromise.then(item => this.set(id, item)), now);
69
+ if (now < this.oldestTimestamp) this.oldestTimestamp = now;
70
+ this.data[id] = cached;
71
+ return cached;
72
+ }
73
+
74
+ /** Gets item. */
75
+ get(id) {
76
+ const entry = this.getEntry(id);
77
+ return Array.isArray(entry) ? entry[0] : entry.then(e => e[0]);
78
+ }
79
+ }
80
+ exports.Cached = Cached;
81
+ //# sourceMappingURL=Cached.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cached.js","names":["addTimestamp","promise","timestamp","res","getTimestamp","e","Array","isArray","Cached","data","oldestTimestamp","Number","MAX_SAFE_INTEGER","_data","_oldestTimestamp","constructor","maxage","getter","cleanCache","deadline","Date","now","key","entry","Object","entries","set","id","datum","getEntry","cached","itemOrPromise","Promise","then","item","get","exports"],"sources":["../../src/Cached.ts"],"sourcesContent":["type CachedT<T> = [T, number];\ntype TimestampedPromise<T> = Promise<T> & { timestamp: number };\ntype EntryT<T> = CachedT<T> | TimestampedPromise<CachedT<T>>;\n\n/** Adds timestamp to the promise. */\nfunction addTimestamp<T>(\n promise: Promise<T>,\n timestamp: number,\n): TimestampedPromise<T> {\n const res = promise as TimestampedPromise<T>;\n res.timestamp = timestamp;\n return res;\n}\n\n/** Gets entry timestamp. */\nfunction getTimestamp<T>(e: EntryT<T>): number {\n return Array.isArray(e) ? e[1] : e.timestamp;\n}\n\nexport class Cached<T> {\n private data: Record<string, EntryT<T>> = {};\n private oldestTimestamp = Number.MAX_SAFE_INTEGER;\n\n /** For test use only. */\n get _data(): Readonly<Record<string, EntryT<T>>> {\n return this.data;\n }\n\n /** For test use only. */\n get _oldestTimestamp(): number {\n return this.oldestTimestamp;\n }\n\n constructor(\n public readonly maxage: number,\n private getter: (id: string) => T | Promise<T>,\n ) {}\n\n /** Removes stale items from the cache, and updates .oldestTimestamp. */\n private cleanCache() {\n const deadline = Date.now() - this.maxage;\n this.oldestTimestamp = Number.MAX_SAFE_INTEGER;\n for (const [key, entry] of Object.entries(this.data)) {\n const timestamp = getTimestamp(entry);\n if (timestamp < deadline) delete this.data[key];\n else if (timestamp < this.oldestTimestamp) {\n this.oldestTimestamp = timestamp;\n }\n }\n }\n\n /** Adds `datum` to the cache, and removes stale items from the cache. */\n private set(id: string, datum: T): CachedT<T> {\n const now = Date.now();\n if (this.oldestTimestamp < now - this.maxage) this.cleanCache();\n if (now < this.oldestTimestamp) this.oldestTimestamp = now;\n const res: CachedT<T> = [datum, now];\n this.data[id] = res;\n return res;\n }\n\n /** Retrieves envelope of the specified datum, either read from the cache,\n * or retrieved using the getter provided at construction time. */\n private getEntry(id: string): EntryT<T> {\n const now = Date.now();\n\n let cached = this.data[id];\n if (cached && getTimestamp(cached) >= now - this.maxage) return cached;\n\n const itemOrPromise = this.getter(id);\n if (!(itemOrPromise instanceof Promise)) {\n return this.set(id, itemOrPromise);\n }\n\n cached = addTimestamp(\n itemOrPromise.then((item) => this.set(id, item)),\n now,\n );\n if (now < this.oldestTimestamp) this.oldestTimestamp = now;\n this.data[id] = cached;\n return cached;\n }\n\n /** Gets item. */\n get(id: string): T | Promise<T> {\n const entry = this.getEntry(id);\n return Array.isArray(entry) ? entry[0] : entry.then((e) => e[0]);\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -39,9 +39,9 @@ class Emitter {
39
39
  * Calls every connected listener with the given arguments.
40
40
  * @param args
41
41
  */
42
- emit() {
42
+ emit(...args) {
43
43
  const listeners = this.pListeners.slice();
44
- for (const listener of listeners) listener(...arguments);
44
+ for (const listener of listeners) listener(...args);
45
45
  }
46
46
 
47
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Emitter.js","names":["Emitter","pListeners","hasListeners","length","listeners","addListener","listener","includes","push","removeListener","emit","slice","arguments","removeAllListeners","idx","indexOf","splice","exports"],"sources":["../../src/Emitter.ts"],"sourcesContent":["export type Listener<T extends unknown[] = unknown[]> = (...args: T) => void;\n\n/**\n * Simple listeneable data Emitter.\n */\nexport class Emitter<T extends unknown[] = unknown[]> {\n private pListeners: Array<Listener<T>> = [];\n\n /**\n * Returns \"true\" if any listener is connected; \"false\" otherwise.\n * @return {boolean}\n */\n get hasListeners(): boolean {\n return !!this.pListeners.length;\n }\n\n get listeners(): ReadonlyArray<Listener<T>> {\n return this.pListeners;\n }\n\n /**\n * Adds `listener` if it is not already connected.\n * @param {function} listener\n * @return {function} Unsubscribe function.\n */\n addListener(listener: Listener<T>): () => void {\n if (!this.pListeners.includes(listener)) {\n this.pListeners.push(listener);\n }\n return () => {\n this.removeListener(listener);\n };\n }\n\n /**\n * Calls every connected listener with the given arguments.\n * @param args\n */\n emit(...args: T): void {\n const listeners = this.pListeners.slice();\n for (const listener of listeners) listener(...args);\n }\n\n /**\n * Removes all connected listeners.\n */\n removeAllListeners(): void {\n this.pListeners = [];\n }\n\n /**\n * Removes specified `listener`, if connected.\n * @param listener\n */\n removeListener(listener: Listener<T>): void {\n const idx = this.pListeners.indexOf(listener);\n if (idx >= 0) this.pListeners.splice(idx, 1);\n }\n}\n"],"mappings":";;;;;;AAEA;AACA;AACA;AACO,MAAMA,OAAO,CAAkC;EAC5CC,UAAU,GAAuB,EAAE;;EAE3C;AACF;AACA;AACA;EACE,IAAIC,YAAYA,CAAA,EAAY;IAC1B,OAAO,CAAC,CAAC,IAAI,CAACD,UAAU,CAACE,MAAM;EACjC;EAEA,IAAIC,SAASA,CAAA,EAA+B;IAC1C,OAAO,IAAI,CAACH,UAAU;EACxB;;EAEA;AACF;AACA;AACA;AACA;EACEI,WAAWA,CAACC,QAAqB,EAAc;IAC7C,IAAI,CAAC,IAAI,CAACL,UAAU,CAACM,QAAQ,CAACD,QAAQ,CAAC,EAAE;MACvC,IAAI,CAACL,UAAU,CAACO,IAAI,CAACF,QAAQ,CAAC;IAChC;IACA,OAAO,MAAM;MACX,IAAI,CAACG,cAAc,CAACH,QAAQ,CAAC;IAC/B,CAAC;EACH;;EAEA;AACF;AACA;AACA;EACEI,IAAIA,CAAA,EAAmB;IACrB,MAAMN,SAAS,GAAG,IAAI,CAACH,UAAU,CAACU,KAAK,CAAC,CAAC;IACzC,KAAK,MAAML,QAAQ,IAAIF,SAAS,EAAEE,QAAQ,CAAC,GAAAM,SAAO,CAAC;EACrD;;EAEA;AACF;AACA;EACEC,kBAAkBA,CAAA,EAAS;IACzB,IAAI,CAACZ,UAAU,GAAG,EAAE;EACtB;;EAEA;AACF;AACA;AACA;EACEQ,cAAcA,CAACH,QAAqB,EAAQ;IAC1C,MAAMQ,GAAG,GAAG,IAAI,CAACb,UAAU,CAACc,OAAO,CAACT,QAAQ,CAAC;IAC7C,IAAIQ,GAAG,IAAI,CAAC,EAAE,IAAI,CAACb,UAAU,CAACe,MAAM,CAACF,GAAG,EAAE,CAAC,CAAC;EAC9C;AACF;AAACG,OAAA,CAAAjB,OAAA,GAAAA,OAAA","ignoreList":[]}
1
+ {"version":3,"file":"Emitter.js","names":["Emitter","pListeners","hasListeners","length","listeners","addListener","listener","includes","push","removeListener","emit","args","slice","removeAllListeners","idx","indexOf","splice","exports"],"sources":["../../src/Emitter.ts"],"sourcesContent":["export type Listener<T extends unknown[] = unknown[]> = (...args: T) => void;\n\n/**\n * Simple listeneable data Emitter.\n */\nexport class Emitter<T extends unknown[] = unknown[]> {\n private pListeners: Array<Listener<T>> = [];\n\n /**\n * Returns \"true\" if any listener is connected; \"false\" otherwise.\n * @return {boolean}\n */\n get hasListeners(): boolean {\n return !!this.pListeners.length;\n }\n\n get listeners(): ReadonlyArray<Listener<T>> {\n return this.pListeners;\n }\n\n /**\n * Adds `listener` if it is not already connected.\n * @param {function} listener\n * @return {function} Unsubscribe function.\n */\n addListener(listener: Listener<T>): () => void {\n if (!this.pListeners.includes(listener)) {\n this.pListeners.push(listener);\n }\n return () => {\n this.removeListener(listener);\n };\n }\n\n /**\n * Calls every connected listener with the given arguments.\n * @param args\n */\n emit(...args: T): void {\n const listeners = this.pListeners.slice();\n for (const listener of listeners) listener(...args);\n }\n\n /**\n * Removes all connected listeners.\n */\n removeAllListeners(): void {\n this.pListeners = [];\n }\n\n /**\n * Removes specified `listener`, if connected.\n * @param listener\n */\n removeListener(listener: Listener<T>): void {\n const idx = this.pListeners.indexOf(listener);\n if (idx >= 0) this.pListeners.splice(idx, 1);\n }\n}\n"],"mappings":";;;;;;AAEA;AACA;AACA;AACO,MAAMA,OAAO,CAAkC;EAC5CC,UAAU,GAAuB,EAAE;;EAE3C;AACF;AACA;AACA;EACE,IAAIC,YAAYA,CAAA,EAAY;IAC1B,OAAO,CAAC,CAAC,IAAI,CAACD,UAAU,CAACE,MAAM;EACjC;EAEA,IAAIC,SAASA,CAAA,EAA+B;IAC1C,OAAO,IAAI,CAACH,UAAU;EACxB;;EAEA;AACF;AACA;AACA;AACA;EACEI,WAAWA,CAACC,QAAqB,EAAc;IAC7C,IAAI,CAAC,IAAI,CAACL,UAAU,CAACM,QAAQ,CAACD,QAAQ,CAAC,EAAE;MACvC,IAAI,CAACL,UAAU,CAACO,IAAI,CAACF,QAAQ,CAAC;IAChC;IACA,OAAO,MAAM;MACX,IAAI,CAACG,cAAc,CAACH,QAAQ,CAAC;IAC/B,CAAC;EACH;;EAEA;AACF;AACA;AACA;EACEI,IAAIA,CAAC,GAAGC,IAAO,EAAQ;IACrB,MAAMP,SAAS,GAAG,IAAI,CAACH,UAAU,CAACW,KAAK,CAAC,CAAC;IACzC,KAAK,MAAMN,QAAQ,IAAIF,SAAS,EAAEE,QAAQ,CAAC,GAAGK,IAAI,CAAC;EACrD;;EAEA;AACF;AACA;EACEE,kBAAkBA,CAAA,EAAS;IACzB,IAAI,CAACZ,UAAU,GAAG,EAAE;EACtB;;EAEA;AACF;AACA;AACA;EACEQ,cAAcA,CAACH,QAAqB,EAAQ;IAC1C,MAAMQ,GAAG,GAAG,IAAI,CAACb,UAAU,CAACc,OAAO,CAACT,QAAQ,CAAC;IAC7C,IAAIQ,GAAG,IAAI,CAAC,EAAE,IAAI,CAACb,UAAU,CAACe,MAAM,CAACF,GAAG,EAAE,CAAC,CAAC;EAC9C;AACF;AAACG,OAAA,CAAAjB,OAAA,GAAAA,OAAA","ignoreList":[]}
@@ -10,14 +10,19 @@ var _Barrier = _interopRequireDefault(require("./Barrier"));
10
10
  * Implements a simple semaphore for async code logic.
11
11
  */
12
12
  class Semaphore {
13
- constructor() {
14
- let ready = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
13
+ constructor(ready = false) {
14
+ // TODO: Boolean conversion is performed for backward compatibility with
15
+ // plain JS projects. Drop it in future.
16
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
15
17
  this.pReady = !!ready;
16
18
  }
17
19
  get ready() {
18
20
  return this.pReady;
19
21
  }
20
22
  setReady(ready) {
23
+ // TODO: Boolean conversion is performed for backward compatibility with
24
+ // plain JS projects. Drop it in future.
25
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
21
26
  const bool = !!ready;
22
27
  if (this.pReady !== bool) {
23
28
  this.pReady = bool;
@@ -33,8 +38,7 @@ class Semaphore {
33
38
  async seize() {
34
39
  return this.waitReady(true);
35
40
  }
36
- async waitReady() {
37
- let seize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
41
+ async waitReady(seize = false) {
38
42
  if (!this.pReady || this.pQueue.length) {
39
43
  const barrier = new _Barrier.default();
40
44
  this.pQueue.push(barrier);
@@ -1 +1 @@
1
- {"version":3,"file":"Semaphore.js","names":["_Barrier","_interopRequireDefault","require","Semaphore","constructor","ready","arguments","length","undefined","pReady","setReady","bool","pDraining","pQueue","pDrainQueue","seize","waitReady","barrier","Barrier","push","pDrainLock","resolve","shift","exports","default"],"sources":["../../src/Semaphore.ts"],"sourcesContent":["import Barrier from './Barrier';\n\n/**\n * Implements a simple semaphore for async code logic.\n */\nexport default class Semaphore {\n constructor(ready = false) {\n this.pReady = !!ready;\n }\n\n get ready(): boolean {\n return this.pReady;\n }\n\n setReady(ready: boolean): void {\n const bool = !!ready;\n if (this.pReady !== bool) {\n this.pReady = bool;\n if (bool && !this.pDraining && this.pQueue.length) {\n void this.pDrainQueue();\n }\n }\n }\n\n /**\n * Waits until the semaphore is ready, and marks it as non-ready (seizes it).\n */\n async seize(): Promise<void> {\n return this.waitReady(true);\n }\n\n async waitReady(seize = false): Promise<void> {\n if (!this.pReady || this.pQueue.length) {\n const barrier = new Barrier<void>();\n this.pQueue.push(barrier);\n await barrier;\n if (seize) this.pReady = false;\n void this.pDrainLock!.resolve();\n } else if (seize) this.pReady = false;\n }\n\n // Private members below this point.\n\n /**\n * If semaphore is ready, it releases the next barrier in the queue, if any,\n * and reschedules itself for a call in the next event loop iteration.\n * Otherwise, it breaks the queue draining loop, which will be restarted\n * the next time the semaphore is set ready.\n */\n async pDrainQueue(): Promise<void> {\n this.pDraining = true;\n while (this.pReady && this.pQueue.length) {\n this.pDrainLock = new Barrier();\n void this.pQueue[0]!.resolve();\n await this.pDrainLock;\n void this.pQueue.shift();\n }\n this.pDraining = false;\n this.pDrainLock = null;\n }\n\n // \"true\" when the drain queue process is running (and thus no need to start\n // a new one).\n private pDraining = false;\n\n // Each time a Promise from drain queue is resolved this drainLock is set\n // to block further queue draining until the promise resolution handler\n // (.seize() or .waitReady()) unlocks it, thus confirming it is fine\n // to continue the draining. This is specifically important for .seize(),\n // which should have a chance to switch semaphore state to non-ready prior\n // to next Promise in the queue being unlocked.\n private pDrainLock: Barrier<void> | null = null;\n\n // The array of barriers set for each async code flow awaiting for\n // the Semaphore to become ready.\n private pQueue: Array<Barrier<void>> = [];\n\n private pReady: boolean;\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,QAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA;AACA;AACA;AACe,MAAMC,SAAS,CAAC;EAC7BC,WAAWA,CAAA,EAAgB;IAAA,IAAfC,KAAK,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,KAAK;IACvB,IAAI,CAACG,MAAM,GAAG,CAAC,CAACJ,KAAK;EACvB;EAEA,IAAIA,KAAKA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACI,MAAM;EACpB;EAEAC,QAAQA,CAACL,KAAc,EAAQ;IAC7B,MAAMM,IAAI,GAAG,CAAC,CAACN,KAAK;IACpB,IAAI,IAAI,CAACI,MAAM,KAAKE,IAAI,EAAE;MACxB,IAAI,CAACF,MAAM,GAAGE,IAAI;MAClB,IAAIA,IAAI,IAAI,CAAC,IAAI,CAACC,SAAS,IAAI,IAAI,CAACC,MAAM,CAACN,MAAM,EAAE;QACjD,KAAK,IAAI,CAACO,WAAW,CAAC,CAAC;MACzB;IACF;EACF;;EAEA;AACF;AACA;EACE,MAAMC,KAAKA,CAAA,EAAkB;IAC3B,OAAO,IAAI,CAACC,SAAS,CAAC,IAAI,CAAC;EAC7B;EAEA,MAAMA,SAASA,CAAA,EAA+B;IAAA,IAA9BD,KAAK,GAAAT,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,KAAK;IAC3B,IAAI,CAAC,IAAI,CAACG,MAAM,IAAI,IAAI,CAACI,MAAM,CAACN,MAAM,EAAE;MACtC,MAAMU,OAAO,GAAG,IAAIC,gBAAO,CAAO,CAAC;MACnC,IAAI,CAACL,MAAM,CAACM,IAAI,CAACF,OAAO,CAAC;MACzB,MAAMA,OAAO;MACb,IAAIF,KAAK,EAAE,IAAI,CAACN,MAAM,GAAG,KAAK;MAC9B,KAAK,IAAI,CAACW,UAAU,CAAEC,OAAO,CAAC,CAAC;IACjC,CAAC,MAAM,IAAIN,KAAK,EAAE,IAAI,CAACN,MAAM,GAAG,KAAK;EACvC;;EAEA;;EAEA;AACF;AACA;AACA;AACA;AACA;EACE,MAAMK,WAAWA,CAAA,EAAkB;IACjC,IAAI,CAACF,SAAS,GAAG,IAAI;IACrB,OAAO,IAAI,CAACH,MAAM,IAAI,IAAI,CAACI,MAAM,CAACN,MAAM,EAAE;MACxC,IAAI,CAACa,UAAU,GAAG,IAAIF,gBAAO,CAAC,CAAC;MAC/B,KAAK,IAAI,CAACL,MAAM,CAAC,CAAC,CAAC,CAAEQ,OAAO,CAAC,CAAC;MAC9B,MAAM,IAAI,CAACD,UAAU;MACrB,KAAK,IAAI,CAACP,MAAM,CAACS,KAAK,CAAC,CAAC;IAC1B;IACA,IAAI,CAACV,SAAS,GAAG,KAAK;IACtB,IAAI,CAACQ,UAAU,GAAG,IAAI;EACxB;;EAEA;EACA;EACQR,SAAS,GAAG,KAAK;;EAEzB;EACA;EACA;EACA;EACA;EACA;EACQQ,UAAU,GAAyB,IAAI;;EAE/C;EACA;EACQP,MAAM,GAAyB,EAAE;AAG3C;AAACU,OAAA,CAAAC,OAAA,GAAArB,SAAA","ignoreList":[]}
1
+ {"version":3,"file":"Semaphore.js","names":["_Barrier","_interopRequireDefault","require","Semaphore","constructor","ready","pReady","setReady","bool","pDraining","pQueue","length","pDrainQueue","seize","waitReady","barrier","Barrier","push","pDrainLock","resolve","shift","exports","default"],"sources":["../../src/Semaphore.ts"],"sourcesContent":["import Barrier from './Barrier';\n\n/**\n * Implements a simple semaphore for async code logic.\n */\nexport default class Semaphore {\n constructor(ready = false) {\n // TODO: Boolean conversion is performed for backward compatibility with\n // plain JS projects. Drop it in future.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n this.pReady = !!ready;\n }\n\n get ready(): boolean {\n return this.pReady;\n }\n\n setReady(ready: boolean): void {\n // TODO: Boolean conversion is performed for backward compatibility with\n // plain JS projects. Drop it in future.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n const bool = !!ready;\n if (this.pReady !== bool) {\n this.pReady = bool;\n if (bool && !this.pDraining && this.pQueue.length) {\n void this.pDrainQueue();\n }\n }\n }\n\n /**\n * Waits until the semaphore is ready, and marks it as non-ready (seizes it).\n */\n async seize(): Promise<void> {\n return this.waitReady(true);\n }\n\n async waitReady(seize = false): Promise<void> {\n if (!this.pReady || this.pQueue.length) {\n const barrier = new Barrier<void>();\n this.pQueue.push(barrier);\n await barrier;\n if (seize) this.pReady = false;\n void this.pDrainLock!.resolve();\n } else if (seize) this.pReady = false;\n }\n\n // Private members below this point.\n\n /**\n * If semaphore is ready, it releases the next barrier in the queue, if any,\n * and reschedules itself for a call in the next event loop iteration.\n * Otherwise, it breaks the queue draining loop, which will be restarted\n * the next time the semaphore is set ready.\n */\n async pDrainQueue(): Promise<void> {\n this.pDraining = true;\n while (this.pReady && this.pQueue.length) {\n this.pDrainLock = new Barrier();\n void this.pQueue[0]!.resolve();\n await this.pDrainLock;\n void this.pQueue.shift();\n }\n this.pDraining = false;\n this.pDrainLock = null;\n }\n\n // \"true\" when the drain queue process is running (and thus no need to start\n // a new one).\n private pDraining = false;\n\n // Each time a Promise from drain queue is resolved this drainLock is set\n // to block further queue draining until the promise resolution handler\n // (.seize() or .waitReady()) unlocks it, thus confirming it is fine\n // to continue the draining. This is specifically important for .seize(),\n // which should have a chance to switch semaphore state to non-ready prior\n // to next Promise in the queue being unlocked.\n private pDrainLock: Barrier<void> | null = null;\n\n // The array of barriers set for each async code flow awaiting for\n // the Semaphore to become ready.\n private pQueue: Array<Barrier<void>> = [];\n\n private pReady: boolean;\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,QAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA;AACA;AACA;AACe,MAAMC,SAAS,CAAC;EAC7BC,WAAWA,CAACC,KAAK,GAAG,KAAK,EAAE;IACzB;IACA;IACA;IACA,IAAI,CAACC,MAAM,GAAG,CAAC,CAACD,KAAK;EACvB;EAEA,IAAIA,KAAKA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACC,MAAM;EACpB;EAEAC,QAAQA,CAACF,KAAc,EAAQ;IAC7B;IACA;IACA;IACA,MAAMG,IAAI,GAAG,CAAC,CAACH,KAAK;IACpB,IAAI,IAAI,CAACC,MAAM,KAAKE,IAAI,EAAE;MACxB,IAAI,CAACF,MAAM,GAAGE,IAAI;MAClB,IAAIA,IAAI,IAAI,CAAC,IAAI,CAACC,SAAS,IAAI,IAAI,CAACC,MAAM,CAACC,MAAM,EAAE;QACjD,KAAK,IAAI,CAACC,WAAW,CAAC,CAAC;MACzB;IACF;EACF;;EAEA;AACF;AACA;EACE,MAAMC,KAAKA,CAAA,EAAkB;IAC3B,OAAO,IAAI,CAACC,SAAS,CAAC,IAAI,CAAC;EAC7B;EAEA,MAAMA,SAASA,CAACD,KAAK,GAAG,KAAK,EAAiB;IAC5C,IAAI,CAAC,IAAI,CAACP,MAAM,IAAI,IAAI,CAACI,MAAM,CAACC,MAAM,EAAE;MACtC,MAAMI,OAAO,GAAG,IAAIC,gBAAO,CAAO,CAAC;MACnC,IAAI,CAACN,MAAM,CAACO,IAAI,CAACF,OAAO,CAAC;MACzB,MAAMA,OAAO;MACb,IAAIF,KAAK,EAAE,IAAI,CAACP,MAAM,GAAG,KAAK;MAC9B,KAAK,IAAI,CAACY,UAAU,CAAEC,OAAO,CAAC,CAAC;IACjC,CAAC,MAAM,IAAIN,KAAK,EAAE,IAAI,CAACP,MAAM,GAAG,KAAK;EACvC;;EAEA;;EAEA;AACF;AACA;AACA;AACA;AACA;EACE,MAAMM,WAAWA,CAAA,EAAkB;IACjC,IAAI,CAACH,SAAS,GAAG,IAAI;IACrB,OAAO,IAAI,CAACH,MAAM,IAAI,IAAI,CAACI,MAAM,CAACC,MAAM,EAAE;MACxC,IAAI,CAACO,UAAU,GAAG,IAAIF,gBAAO,CAAC,CAAC;MAC/B,KAAK,IAAI,CAACN,MAAM,CAAC,CAAC,CAAC,CAAES,OAAO,CAAC,CAAC;MAC9B,MAAM,IAAI,CAACD,UAAU;MACrB,KAAK,IAAI,CAACR,MAAM,CAACU,KAAK,CAAC,CAAC;IAC1B;IACA,IAAI,CAACX,SAAS,GAAG,KAAK;IACtB,IAAI,CAACS,UAAU,GAAG,IAAI;EACxB;;EAEA;EACA;EACQT,SAAS,GAAG,KAAK;;EAEzB;EACA;EACA;EACA;EACA;EACA;EACQS,UAAU,GAAyB,IAAI;;EAE/C;EACA;EACQR,MAAM,GAAyB,EAAE;AAG3C;AAACW,OAAA,CAAAC,OAAA,GAAAnB,SAAA","ignoreList":[]}
@@ -28,6 +28,18 @@ Object.defineProperty(exports, "withRetries", {
28
28
  }
29
29
  });
30
30
  var _Barrier = _interopRequireDefault(require("./Barrier"));
31
+ var _Cached = require("./Cached");
32
+ Object.keys(_Cached).forEach(function (key) {
33
+ if (key === "default" || key === "__esModule") return;
34
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
35
+ if (key in exports && exports[key] === _Cached[key]) return;
36
+ Object.defineProperty(exports, key, {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _Cached[key];
40
+ }
41
+ });
42
+ });
31
43
  var _Emitter = require("./Emitter");
32
44
  Object.keys(_Emitter).forEach(function (key) {
33
45
  if (key === "default" || key === "__esModule") return;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_Barrier","_interopRequireDefault","require","_Emitter","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_Semaphore","_time","_withRetries"],"sources":["../../src/index.ts"],"sourcesContent":["export { default as Barrier } from './Barrier';\nexport * from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport * from './time';\nexport { default as withRetries } from './withRetries';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,QAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAF,QAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,QAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,QAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,UAAA,GAAAf,sBAAA,CAAAC,OAAA;AACA,IAAAe,KAAA,GAAAf,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAY,KAAA,EAAAX,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAU,KAAA,CAAAV,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,KAAA,CAAAV,GAAA;IAAA;EAAA;AAAA;AACA,IAAAW,YAAA,GAAAjB,sBAAA,CAAAC,OAAA","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["_Barrier","_interopRequireDefault","require","_Cached","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_Emitter","_Semaphore","_time","_withRetries"],"sources":["../../src/index.ts"],"sourcesContent":["export { default as Barrier } from './Barrier';\nexport * from './Cached';\nexport * from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport * from './time';\nexport { default as withRetries } from './withRetries';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,QAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAF,OAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,OAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,OAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,QAAA,GAAAd,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAW,QAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAS,QAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,QAAA,CAAAT,GAAA;IAAA;EAAA;AAAA;AACA,IAAAU,UAAA,GAAAhB,sBAAA,CAAAC,OAAA;AACA,IAAAgB,KAAA,GAAAhB,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAa,KAAA,EAAAZ,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAW,KAAA,CAAAX,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,KAAA,CAAAX,GAAA;IAAA;EAAA;AAAA;AACA,IAAAY,YAAA,GAAAlB,sBAAA,CAAAC,OAAA","ignoreList":[]}
@@ -16,9 +16,7 @@ var _time = require("./time");
16
16
  * @returns Resolves to the result of the successful `action` execution;
17
17
  * or rejects with the error from the last faileda attempt.
18
18
  */
19
- async function withRetries(action) {
20
- let maxRetries = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
21
- let interval = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 300;
19
+ async function withRetries(action, maxRetries = 3, interval = 300) {
22
20
  for (let n = 1;; ++n) {
23
21
  try {
24
22
  const res = action();
@@ -1 +1 @@
1
- {"version":3,"file":"withRetries.js","names":["_time","require","withRetries","action","maxRetries","arguments","length","undefined","interval","n","res","Promise","error","timer"],"sources":["../../src/withRetries.ts"],"sourcesContent":["import { timer } from './time';\n\n/**\n * Attempts to perform the given async `action` up to `maxRetries` times with\n * the specified `interval`, stopping at the first successful (non-throwing)\n * execution.\n * @param action\n * @param maxRetries Optional. The maximum number of re-tries. Defaults 3.\n * @param interval Optional. The interval between re-tries (in milliseconds).\n * Defaults to 300ms.\n * @returns Resolves to the result of the successful `action` execution;\n * or rejects with the error from the last faileda attempt.\n */\nexport default async function withRetries<T>(\n action: () => T,\n maxRetries = 3,\n interval = 300,\n): Promise<Awaited<T>> {\n for (let n = 1; ; ++n) {\n try {\n const res = action();\n return res instanceof Promise ? await res : (res as Awaited<T>);\n } catch (error) {\n if (n < maxRetries) await timer(interval);\n else throw error;\n }\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,KAAA,GAAAC,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,eAAeC,WAAWA,CACvCC,MAAe,EAGM;EAAA,IAFrBC,UAAU,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC;EAAA,IACdG,QAAQ,GAAAH,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,GAAG;EAEd,KAAK,IAAII,CAAC,GAAG,CAAC,GAAI,EAAEA,CAAC,EAAE;IACrB,IAAI;MACF,MAAMC,GAAG,GAAGP,MAAM,CAAC,CAAC;MACpB,OAAOO,GAAG,YAAYC,OAAO,GAAG,MAAMD,GAAG,GAAIA,GAAkB;IACjE,CAAC,CAAC,OAAOE,KAAK,EAAE;MACd,IAAIH,CAAC,GAAGL,UAAU,EAAE,MAAM,IAAAS,WAAK,EAACL,QAAQ,CAAC,CAAC,KACrC,MAAMI,KAAK;IAClB;EACF;AACF","ignoreList":[]}
1
+ {"version":3,"file":"withRetries.js","names":["_time","require","withRetries","action","maxRetries","interval","n","res","Promise","error","timer"],"sources":["../../src/withRetries.ts"],"sourcesContent":["import { timer } from './time';\n\n/**\n * Attempts to perform the given async `action` up to `maxRetries` times with\n * the specified `interval`, stopping at the first successful (non-throwing)\n * execution.\n * @param action\n * @param maxRetries Optional. The maximum number of re-tries. Defaults 3.\n * @param interval Optional. The interval between re-tries (in milliseconds).\n * Defaults to 300ms.\n * @returns Resolves to the result of the successful `action` execution;\n * or rejects with the error from the last faileda attempt.\n */\nexport default async function withRetries<T>(\n action: () => T,\n maxRetries = 3,\n interval = 300,\n): Promise<Awaited<T>> {\n for (let n = 1; ; ++n) {\n try {\n const res = action();\n return res instanceof Promise ? await res : (res as Awaited<T>);\n } catch (error) {\n if (n < maxRetries) await timer(interval);\n else throw error;\n }\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,KAAA,GAAAC,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,eAAeC,WAAWA,CACvCC,MAAe,EACfC,UAAU,GAAG,CAAC,EACdC,QAAQ,GAAG,GAAG,EACO;EACrB,KAAK,IAAIC,CAAC,GAAG,CAAC,GAAI,EAAEA,CAAC,EAAE;IACrB,IAAI;MACF,MAAMC,GAAG,GAAGJ,MAAM,CAAC,CAAC;MACpB,OAAOI,GAAG,YAAYC,OAAO,GAAG,MAAMD,GAAG,GAAIA,GAAkB;IACjE,CAAC,CAAC,OAAOE,KAAK,EAAE;MACd,IAAIH,CAAC,GAAGF,UAAU,EAAE,MAAM,IAAAM,WAAK,EAACL,QAAQ,CAAC,CAAC,KACrC,MAAMI,KAAK;IAClB;EACF;AACF","ignoreList":[]}
@@ -28,7 +28,7 @@ var STATE = /*#__PURE__*/function (STATE) {
28
28
  * Docs: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier
29
29
  */
30
30
  export default class Barrier extends Promise {
31
- pState = (() => STATE.PENDING)();
31
+ pState = STATE.PENDING;
32
32
  constructor(executor) {
33
33
  let resolveRef;
34
34
  let rejectRef;
@@ -1 +1 @@
1
- {"version":3,"file":"Barrier.js","names":["STATE","Barrier","Promise","pState","PENDING","constructor","executor","resolveRef","rejectRef","resolve","reject","value","RESOLVED","reason","REJECTED","pResolve","pReject","arg","resolved","rejected","settled","catch","onRejected","finally","onFinally","then","onFulfilled","res"],"sources":["../../src/Barrier.ts"],"sourcesContent":["export type Executor<T> = ConstructorParameters<typeof Promise<T>>[0];\n\ntype Resolver<T> = Parameters<Executor<T>>[0];\ntype Rejecter = Parameters<Executor<unknown>>[1];\n\nenum STATE {\n PENDING = 'PENDING',\n REJECTED = 'REJECTED',\n RESOLVED = 'RESOLVED',\n}\n\n/**\n * Barrier is just a Promise which has resolve and reject exposed as instance\n * methods.\n *\n * It has two generic arguments T and TR which correspond to the argument of\n * the .resolve() method, and to the value resolved by the promise (barrier).\n * For a simple barrier TR equals to T, however for barriers created via .then()\n * chain, T corresponds to the argument of the original barrier, and TR to\n * the value resolved by the latest promise in the chain. Consider this:\n *\n * const b = new Barrier<string>();\n * b.resolve('result');\n * const s = await b; // `s` has `string` type, and equals \"result\".\n *\n * const b = (new Barrier<string>()).then((s) => s.length);\n * b.resolve('result'); // Chained barrier exposes .resolve() method of\n * // the first barrier in the chain, which expects\n * // `string` arugment (T), but the chained barrier\n * // resolves to `number` (TR).\n * const n = await b; // `n` has `number` type, and equals 6.\n *\n * Docs: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier\n */\nexport default class Barrier<T = unknown, TR = T> extends Promise<TR> {\n private pResolve: Resolver<T>;\n\n private pReject: Rejecter;\n\n private pState = STATE.PENDING;\n\n constructor(executor?: Executor<TR>) {\n let resolveRef: Resolver<TR>;\n let rejectRef: Rejecter;\n\n super((resolve, reject) => {\n // Note: Enforcing `void` return type because of the BEWARE note below.\n resolveRef = (value: TR | PromiseLike<TR>): void => {\n resolve(value);\n this.pState = STATE.RESOLVED;\n\n // BEWARE: Don't try to return `this` here, it will easily cause\n // infinite loops in React Native, which are extremely difficult\n // to troubleshoot (I wasn't able to figure out, are they due to\n // internal Promise implementation in RN, or because of some bad\n // patterns in the host code).\n };\n\n // Note: Enforcing `void` return type because of the BEWARE note below.\n rejectRef = (reason?: unknown): void => {\n reject(reason);\n this.pState = STATE.REJECTED;\n };\n\n if (executor) executor(resolveRef, rejectRef);\n });\n\n // NOTE: We assume, the only scenario where TR is not equal T is when\n // the Barrier is constructed by a .then() call on a \"parent\" barrier,\n // and in that scenario .then() itself will replace .p_resolve by another\n // resolver immediately after this constructor returns.\n this.pResolve = resolveRef! as Resolver<T>;\n\n this.pReject = rejectRef!;\n }\n\n get resolve() {\n return (arg: Parameters<Resolver<T>>[0]): this => {\n this.pResolve(arg);\n return this;\n };\n }\n\n get reject() {\n return (arg: Parameters<Rejecter>[0]): this => {\n this.pReject(arg);\n return this;\n };\n }\n\n get resolved(): boolean {\n return this.pState === STATE.RESOLVED;\n }\n\n get rejected(): boolean {\n return this.pState === STATE.REJECTED;\n }\n\n get settled(): boolean {\n return this.pState !== STATE.PENDING;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n catch<TR1>(\n onRejected?: ((reason: unknown) => TR1 | PromiseLike<TR1>) | null,\n ): Barrier<T, TR1> {\n return super.catch(onRejected) as Barrier<T, TR1>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n finally(onFinally?: (() => void) | null): Barrier<TR> {\n return super.finally(onFinally) as Barrier<TR>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n then<TR1, TR2>(\n onFulfilled?: ((value: TR) => TR1 | PromiseLike<TR1>) | null,\n onRejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null,\n ): Barrier<T, TR1 | TR2> {\n const res = super.then(onFulfilled, onRejected) as Barrier<T, TR1 | TR2>;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pResolve = this.resolve;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pReject = this.reject;\n return res;\n }\n}\n"],"mappings":"IAKKA,KAAK,0BAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAAA,OAALA,KAAK;AAAA,EAALA,KAAK;AAMV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,MAAMC,OAAO,SAA8BC,OAAO,CAAK;EAK5DC,MAAM,UAAGH,KAAK,CAACI,OAAO;EAE9BC,WAAWA,CAACC,QAAuB,EAAE;IACnC,IAAIC,UAAwB;IAC5B,IAAIC,SAAmB;IAEvB,KAAK,CAAC,CAACC,OAAO,EAAEC,MAAM,KAAK;MACzB;MACAH,UAAU,GAAII,KAA2B,IAAW;QAClDF,OAAO,CAACE,KAAK,CAAC;QACd,IAAI,CAACR,MAAM,GAAGH,KAAK,CAACY,QAAQ;;QAE5B;QACA;QACA;QACA;QACA;MACF,CAAC;;MAED;MACAJ,SAAS,GAAIK,MAAgB,IAAW;QACtCH,MAAM,CAACG,MAAM,CAAC;QACd,IAAI,CAACV,MAAM,GAAGH,KAAK,CAACc,QAAQ;MAC9B,CAAC;MAED,IAAIR,QAAQ,EAAEA,QAAQ,CAACC,UAAU,EAAEC,SAAS,CAAC;IAC/C,CAAC,CAAC;;IAEF;IACA;IACA;IACA;IACA,IAAI,CAACO,QAAQ,GAAGR,UAA0B;IAE1C,IAAI,CAACS,OAAO,GAAGR,SAAU;EAC3B;EAEA,IAAIC,OAAOA,CAAA,EAAG;IACZ,OAAQQ,GAA+B,IAAW;MAChD,IAAI,CAACF,QAAQ,CAACE,GAAG,CAAC;MAClB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIP,MAAMA,CAAA,EAAG;IACX,OAAQO,GAA4B,IAAW;MAC7C,IAAI,CAACD,OAAO,CAACC,GAAG,CAAC;MACjB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIC,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAACf,MAAM,KAAKH,KAAK,CAACY,QAAQ;EACvC;EAEA,IAAIO,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAAChB,MAAM,KAAKH,KAAK,CAACc,QAAQ;EACvC;EAEA,IAAIM,OAAOA,CAAA,EAAY;IACrB,OAAO,IAAI,CAACjB,MAAM,KAAKH,KAAK,CAACI,OAAO;EACtC;;EAEA;EACA;EACA;EACA;EACA;EACAiB,KAAKA,CACHC,UAAiE,EAChD;IACjB,OAAO,KAAK,CAACD,KAAK,CAACC,UAAU,CAAC;EAChC;;EAEA;EACA;EACA;EACA;EACA;EACAC,OAAOA,CAACC,SAA+B,EAAe;IACpD,OAAO,KAAK,CAACD,OAAO,CAACC,SAAS,CAAC;EACjC;;EAEA;EACA;EACA;EACA;EACA;EACAC,IAAIA,CACFC,WAA4D,EAC5DJ,UAAiE,EAC1C;IACvB,MAAMK,GAAG,GAAG,KAAK,CAACF,IAAI,CAACC,WAAW,EAAEJ,UAAU,CAA0B;IACxE;IACA;IACAK,GAAG,CAACZ,QAAQ,GAAG,IAAI,CAACN,OAAO;IAC3B;IACA;IACAkB,GAAG,CAACX,OAAO,GAAG,IAAI,CAACN,MAAM;IACzB,OAAOiB,GAAG;EACZ;AACF","ignoreList":[]}
1
+ {"version":3,"file":"Barrier.js","names":["STATE","Barrier","Promise","pState","PENDING","constructor","executor","resolveRef","rejectRef","resolve","reject","value","RESOLVED","reason","REJECTED","pResolve","pReject","arg","resolved","rejected","settled","catch","onRejected","finally","onFinally","then","onFulfilled","res"],"sources":["../../src/Barrier.ts"],"sourcesContent":["export type Executor<T> = ConstructorParameters<typeof Promise<T>>[0];\n\ntype Resolver<T> = Parameters<Executor<T>>[0];\ntype Rejecter = Parameters<Executor<unknown>>[1];\n\nenum STATE {\n PENDING = 'PENDING',\n REJECTED = 'REJECTED',\n RESOLVED = 'RESOLVED',\n}\n\n/**\n * Barrier is just a Promise which has resolve and reject exposed as instance\n * methods.\n *\n * It has two generic arguments T and TR which correspond to the argument of\n * the .resolve() method, and to the value resolved by the promise (barrier).\n * For a simple barrier TR equals to T, however for barriers created via .then()\n * chain, T corresponds to the argument of the original barrier, and TR to\n * the value resolved by the latest promise in the chain. Consider this:\n *\n * const b = new Barrier<string>();\n * b.resolve('result');\n * const s = await b; // `s` has `string` type, and equals \"result\".\n *\n * const b = (new Barrier<string>()).then((s) => s.length);\n * b.resolve('result'); // Chained barrier exposes .resolve() method of\n * // the first barrier in the chain, which expects\n * // `string` arugment (T), but the chained barrier\n * // resolves to `number` (TR).\n * const n = await b; // `n` has `number` type, and equals 6.\n *\n * Docs: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier\n */\nexport default class Barrier<T = unknown, TR = T> extends Promise<TR> {\n private pResolve: Resolver<T>;\n\n private pReject: Rejecter;\n\n private pState = STATE.PENDING;\n\n constructor(executor?: Executor<TR>) {\n let resolveRef: Resolver<TR>;\n let rejectRef: Rejecter;\n\n super((resolve, reject) => {\n // Note: Enforcing `void` return type because of the BEWARE note below.\n resolveRef = (value: TR | PromiseLike<TR>): void => {\n resolve(value);\n this.pState = STATE.RESOLVED;\n\n // BEWARE: Don't try to return `this` here, it will easily cause\n // infinite loops in React Native, which are extremely difficult\n // to troubleshoot (I wasn't able to figure out, are they due to\n // internal Promise implementation in RN, or because of some bad\n // patterns in the host code).\n };\n\n // Note: Enforcing `void` return type because of the BEWARE note below.\n rejectRef = (reason?: unknown): void => {\n reject(reason);\n this.pState = STATE.REJECTED;\n };\n\n if (executor) executor(resolveRef, rejectRef);\n });\n\n // NOTE: We assume, the only scenario where TR is not equal T is when\n // the Barrier is constructed by a .then() call on a \"parent\" barrier,\n // and in that scenario .then() itself will replace .p_resolve by another\n // resolver immediately after this constructor returns.\n this.pResolve = resolveRef! as Resolver<T>;\n\n this.pReject = rejectRef!;\n }\n\n get resolve() {\n return (arg: Parameters<Resolver<T>>[0]): this => {\n this.pResolve(arg);\n return this;\n };\n }\n\n get reject() {\n return (arg: Parameters<Rejecter>[0]): this => {\n this.pReject(arg);\n return this;\n };\n }\n\n get resolved(): boolean {\n return this.pState === STATE.RESOLVED;\n }\n\n get rejected(): boolean {\n return this.pState === STATE.REJECTED;\n }\n\n get settled(): boolean {\n return this.pState !== STATE.PENDING;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n catch<TR1>(\n onRejected?: ((reason: unknown) => TR1 | PromiseLike<TR1>) | null,\n ): Barrier<T, TR1> {\n return super.catch(onRejected) as Barrier<T, TR1>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n finally(onFinally?: (() => void) | null): Barrier<TR> {\n return super.finally(onFinally) as Barrier<TR>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n then<TR1, TR2>(\n onFulfilled?: ((value: TR) => TR1 | PromiseLike<TR1>) | null,\n onRejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null,\n ): Barrier<T, TR1 | TR2> {\n const res = super.then(onFulfilled, onRejected) as Barrier<T, TR1 | TR2>;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pResolve = this.resolve;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pReject = this.reject;\n return res;\n }\n}\n"],"mappings":"IAKKA,KAAK,0BAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAAA,OAALA,KAAK;AAAA,EAALA,KAAK;AAMV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,MAAMC,OAAO,SAA8BC,OAAO,CAAK;EAK5DC,MAAM,GAAGH,KAAK,CAACI,OAAO;EAE9BC,WAAWA,CAACC,QAAuB,EAAE;IACnC,IAAIC,UAAwB;IAC5B,IAAIC,SAAmB;IAEvB,KAAK,CAAC,CAACC,OAAO,EAAEC,MAAM,KAAK;MACzB;MACAH,UAAU,GAAII,KAA2B,IAAW;QAClDF,OAAO,CAACE,KAAK,CAAC;QACd,IAAI,CAACR,MAAM,GAAGH,KAAK,CAACY,QAAQ;;QAE5B;QACA;QACA;QACA;QACA;MACF,CAAC;;MAED;MACAJ,SAAS,GAAIK,MAAgB,IAAW;QACtCH,MAAM,CAACG,MAAM,CAAC;QACd,IAAI,CAACV,MAAM,GAAGH,KAAK,CAACc,QAAQ;MAC9B,CAAC;MAED,IAAIR,QAAQ,EAAEA,QAAQ,CAACC,UAAU,EAAEC,SAAS,CAAC;IAC/C,CAAC,CAAC;;IAEF;IACA;IACA;IACA;IACA,IAAI,CAACO,QAAQ,GAAGR,UAA0B;IAE1C,IAAI,CAACS,OAAO,GAAGR,SAAU;EAC3B;EAEA,IAAIC,OAAOA,CAAA,EAAG;IACZ,OAAQQ,GAA+B,IAAW;MAChD,IAAI,CAACF,QAAQ,CAACE,GAAG,CAAC;MAClB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIP,MAAMA,CAAA,EAAG;IACX,OAAQO,GAA4B,IAAW;MAC7C,IAAI,CAACD,OAAO,CAACC,GAAG,CAAC;MACjB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIC,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAACf,MAAM,KAAKH,KAAK,CAACY,QAAQ;EACvC;EAEA,IAAIO,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAAChB,MAAM,KAAKH,KAAK,CAACc,QAAQ;EACvC;EAEA,IAAIM,OAAOA,CAAA,EAAY;IACrB,OAAO,IAAI,CAACjB,MAAM,KAAKH,KAAK,CAACI,OAAO;EACtC;;EAEA;EACA;EACA;EACA;EACA;EACAiB,KAAKA,CACHC,UAAiE,EAChD;IACjB,OAAO,KAAK,CAACD,KAAK,CAACC,UAAU,CAAC;EAChC;;EAEA;EACA;EACA;EACA;EACA;EACAC,OAAOA,CAACC,SAA+B,EAAe;IACpD,OAAO,KAAK,CAACD,OAAO,CAACC,SAAS,CAAC;EACjC;;EAEA;EACA;EACA;EACA;EACA;EACAC,IAAIA,CACFC,WAA4D,EAC5DJ,UAAiE,EAC1C;IACvB,MAAMK,GAAG,GAAG,KAAK,CAACF,IAAI,CAACC,WAAW,EAAEJ,UAAU,CAA0B;IACxE;IACA;IACAK,GAAG,CAACZ,QAAQ,GAAG,IAAI,CAACN,OAAO;IAC3B;IACA;IACAkB,GAAG,CAACX,OAAO,GAAG,IAAI,CAACN,MAAM;IACzB,OAAOiB,GAAG;EACZ;AACF","ignoreList":[]}
@@ -0,0 +1,74 @@
1
+ /** Adds timestamp to the promise. */
2
+ function addTimestamp(promise, timestamp) {
3
+ const res = promise;
4
+ res.timestamp = timestamp;
5
+ return res;
6
+ }
7
+
8
+ /** Gets entry timestamp. */
9
+ function getTimestamp(e) {
10
+ return Array.isArray(e) ? e[1] : e.timestamp;
11
+ }
12
+ export class Cached {
13
+ data = {};
14
+ oldestTimestamp = Number.MAX_SAFE_INTEGER;
15
+
16
+ /** For test use only. */
17
+ get _data() {
18
+ return this.data;
19
+ }
20
+
21
+ /** For test use only. */
22
+ get _oldestTimestamp() {
23
+ return this.oldestTimestamp;
24
+ }
25
+ constructor(maxage, getter) {
26
+ this.maxage = maxage;
27
+ this.getter = getter;
28
+ }
29
+
30
+ /** Removes stale items from the cache, and updates .oldestTimestamp. */
31
+ cleanCache() {
32
+ const deadline = Date.now() - this.maxage;
33
+ this.oldestTimestamp = Number.MAX_SAFE_INTEGER;
34
+ for (const [key, entry] of Object.entries(this.data)) {
35
+ const timestamp = getTimestamp(entry);
36
+ if (timestamp < deadline) delete this.data[key];else if (timestamp < this.oldestTimestamp) {
37
+ this.oldestTimestamp = timestamp;
38
+ }
39
+ }
40
+ }
41
+
42
+ /** Adds `datum` to the cache, and removes stale items from the cache. */
43
+ set(id, datum) {
44
+ const now = Date.now();
45
+ if (this.oldestTimestamp < now - this.maxage) this.cleanCache();
46
+ if (now < this.oldestTimestamp) this.oldestTimestamp = now;
47
+ const res = [datum, now];
48
+ this.data[id] = res;
49
+ return res;
50
+ }
51
+
52
+ /** Retrieves envelope of the specified datum, either read from the cache,
53
+ * or retrieved using the getter provided at construction time. */
54
+ getEntry(id) {
55
+ const now = Date.now();
56
+ let cached = this.data[id];
57
+ if (cached && getTimestamp(cached) >= now - this.maxage) return cached;
58
+ const itemOrPromise = this.getter(id);
59
+ if (!(itemOrPromise instanceof Promise)) {
60
+ return this.set(id, itemOrPromise);
61
+ }
62
+ cached = addTimestamp(itemOrPromise.then(item => this.set(id, item)), now);
63
+ if (now < this.oldestTimestamp) this.oldestTimestamp = now;
64
+ this.data[id] = cached;
65
+ return cached;
66
+ }
67
+
68
+ /** Gets item. */
69
+ get(id) {
70
+ const entry = this.getEntry(id);
71
+ return Array.isArray(entry) ? entry[0] : entry.then(e => e[0]);
72
+ }
73
+ }
74
+ //# sourceMappingURL=Cached.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cached.js","names":["addTimestamp","promise","timestamp","res","getTimestamp","e","Array","isArray","Cached","data","oldestTimestamp","Number","MAX_SAFE_INTEGER","_data","_oldestTimestamp","constructor","maxage","getter","cleanCache","deadline","Date","now","key","entry","Object","entries","set","id","datum","getEntry","cached","itemOrPromise","Promise","then","item","get"],"sources":["../../src/Cached.ts"],"sourcesContent":["type CachedT<T> = [T, number];\ntype TimestampedPromise<T> = Promise<T> & { timestamp: number };\ntype EntryT<T> = CachedT<T> | TimestampedPromise<CachedT<T>>;\n\n/** Adds timestamp to the promise. */\nfunction addTimestamp<T>(\n promise: Promise<T>,\n timestamp: number,\n): TimestampedPromise<T> {\n const res = promise as TimestampedPromise<T>;\n res.timestamp = timestamp;\n return res;\n}\n\n/** Gets entry timestamp. */\nfunction getTimestamp<T>(e: EntryT<T>): number {\n return Array.isArray(e) ? e[1] : e.timestamp;\n}\n\nexport class Cached<T> {\n private data: Record<string, EntryT<T>> = {};\n private oldestTimestamp = Number.MAX_SAFE_INTEGER;\n\n /** For test use only. */\n get _data(): Readonly<Record<string, EntryT<T>>> {\n return this.data;\n }\n\n /** For test use only. */\n get _oldestTimestamp(): number {\n return this.oldestTimestamp;\n }\n\n constructor(\n public readonly maxage: number,\n private getter: (id: string) => T | Promise<T>,\n ) {}\n\n /** Removes stale items from the cache, and updates .oldestTimestamp. */\n private cleanCache() {\n const deadline = Date.now() - this.maxage;\n this.oldestTimestamp = Number.MAX_SAFE_INTEGER;\n for (const [key, entry] of Object.entries(this.data)) {\n const timestamp = getTimestamp(entry);\n if (timestamp < deadline) delete this.data[key];\n else if (timestamp < this.oldestTimestamp) {\n this.oldestTimestamp = timestamp;\n }\n }\n }\n\n /** Adds `datum` to the cache, and removes stale items from the cache. */\n private set(id: string, datum: T): CachedT<T> {\n const now = Date.now();\n if (this.oldestTimestamp < now - this.maxage) this.cleanCache();\n if (now < this.oldestTimestamp) this.oldestTimestamp = now;\n const res: CachedT<T> = [datum, now];\n this.data[id] = res;\n return res;\n }\n\n /** Retrieves envelope of the specified datum, either read from the cache,\n * or retrieved using the getter provided at construction time. */\n private getEntry(id: string): EntryT<T> {\n const now = Date.now();\n\n let cached = this.data[id];\n if (cached && getTimestamp(cached) >= now - this.maxage) return cached;\n\n const itemOrPromise = this.getter(id);\n if (!(itemOrPromise instanceof Promise)) {\n return this.set(id, itemOrPromise);\n }\n\n cached = addTimestamp(\n itemOrPromise.then((item) => this.set(id, item)),\n now,\n );\n if (now < this.oldestTimestamp) this.oldestTimestamp = now;\n this.data[id] = cached;\n return cached;\n }\n\n /** Gets item. */\n get(id: string): T | Promise<T> {\n const entry = this.getEntry(id);\n return Array.isArray(entry) ? entry[0] : entry.then((e) => e[0]);\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -33,9 +33,9 @@ export class Emitter {
33
33
  * Calls every connected listener with the given arguments.
34
34
  * @param args
35
35
  */
36
- emit() {
36
+ emit(...args) {
37
37
  const listeners = this.pListeners.slice();
38
- for (const listener of listeners) listener(...arguments);
38
+ for (const listener of listeners) listener(...args);
39
39
  }
40
40
 
41
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Emitter.js","names":["Emitter","pListeners","hasListeners","length","listeners","addListener","listener","includes","push","removeListener","emit","slice","arguments","removeAllListeners","idx","indexOf","splice"],"sources":["../../src/Emitter.ts"],"sourcesContent":["export type Listener<T extends unknown[] = unknown[]> = (...args: T) => void;\n\n/**\n * Simple listeneable data Emitter.\n */\nexport class Emitter<T extends unknown[] = unknown[]> {\n private pListeners: Array<Listener<T>> = [];\n\n /**\n * Returns \"true\" if any listener is connected; \"false\" otherwise.\n * @return {boolean}\n */\n get hasListeners(): boolean {\n return !!this.pListeners.length;\n }\n\n get listeners(): ReadonlyArray<Listener<T>> {\n return this.pListeners;\n }\n\n /**\n * Adds `listener` if it is not already connected.\n * @param {function} listener\n * @return {function} Unsubscribe function.\n */\n addListener(listener: Listener<T>): () => void {\n if (!this.pListeners.includes(listener)) {\n this.pListeners.push(listener);\n }\n return () => {\n this.removeListener(listener);\n };\n }\n\n /**\n * Calls every connected listener with the given arguments.\n * @param args\n */\n emit(...args: T): void {\n const listeners = this.pListeners.slice();\n for (const listener of listeners) listener(...args);\n }\n\n /**\n * Removes all connected listeners.\n */\n removeAllListeners(): void {\n this.pListeners = [];\n }\n\n /**\n * Removes specified `listener`, if connected.\n * @param listener\n */\n removeListener(listener: Listener<T>): void {\n const idx = this.pListeners.indexOf(listener);\n if (idx >= 0) this.pListeners.splice(idx, 1);\n }\n}\n"],"mappings":"AAEA;AACA;AACA;AACA,OAAO,MAAMA,OAAO,CAAkC;EAC5CC,UAAU,GAAuB,EAAE;;EAE3C;AACF;AACA;AACA;EACE,IAAIC,YAAYA,CAAA,EAAY;IAC1B,OAAO,CAAC,CAAC,IAAI,CAACD,UAAU,CAACE,MAAM;EACjC;EAEA,IAAIC,SAASA,CAAA,EAA+B;IAC1C,OAAO,IAAI,CAACH,UAAU;EACxB;;EAEA;AACF;AACA;AACA;AACA;EACEI,WAAWA,CAACC,QAAqB,EAAc;IAC7C,IAAI,CAAC,IAAI,CAACL,UAAU,CAACM,QAAQ,CAACD,QAAQ,CAAC,EAAE;MACvC,IAAI,CAACL,UAAU,CAACO,IAAI,CAACF,QAAQ,CAAC;IAChC;IACA,OAAO,MAAM;MACX,IAAI,CAACG,cAAc,CAACH,QAAQ,CAAC;IAC/B,CAAC;EACH;;EAEA;AACF;AACA;AACA;EACEI,IAAIA,CAAA,EAAmB;IACrB,MAAMN,SAAS,GAAG,IAAI,CAACH,UAAU,CAACU,KAAK,CAAC,CAAC;IACzC,KAAK,MAAML,QAAQ,IAAIF,SAAS,EAAEE,QAAQ,CAAC,GAAAM,SAAO,CAAC;EACrD;;EAEA;AACF;AACA;EACEC,kBAAkBA,CAAA,EAAS;IACzB,IAAI,CAACZ,UAAU,GAAG,EAAE;EACtB;;EAEA;AACF;AACA;AACA;EACEQ,cAAcA,CAACH,QAAqB,EAAQ;IAC1C,MAAMQ,GAAG,GAAG,IAAI,CAACb,UAAU,CAACc,OAAO,CAACT,QAAQ,CAAC;IAC7C,IAAIQ,GAAG,IAAI,CAAC,EAAE,IAAI,CAACb,UAAU,CAACe,MAAM,CAACF,GAAG,EAAE,CAAC,CAAC;EAC9C;AACF","ignoreList":[]}
1
+ {"version":3,"file":"Emitter.js","names":["Emitter","pListeners","hasListeners","length","listeners","addListener","listener","includes","push","removeListener","emit","args","slice","removeAllListeners","idx","indexOf","splice"],"sources":["../../src/Emitter.ts"],"sourcesContent":["export type Listener<T extends unknown[] = unknown[]> = (...args: T) => void;\n\n/**\n * Simple listeneable data Emitter.\n */\nexport class Emitter<T extends unknown[] = unknown[]> {\n private pListeners: Array<Listener<T>> = [];\n\n /**\n * Returns \"true\" if any listener is connected; \"false\" otherwise.\n * @return {boolean}\n */\n get hasListeners(): boolean {\n return !!this.pListeners.length;\n }\n\n get listeners(): ReadonlyArray<Listener<T>> {\n return this.pListeners;\n }\n\n /**\n * Adds `listener` if it is not already connected.\n * @param {function} listener\n * @return {function} Unsubscribe function.\n */\n addListener(listener: Listener<T>): () => void {\n if (!this.pListeners.includes(listener)) {\n this.pListeners.push(listener);\n }\n return () => {\n this.removeListener(listener);\n };\n }\n\n /**\n * Calls every connected listener with the given arguments.\n * @param args\n */\n emit(...args: T): void {\n const listeners = this.pListeners.slice();\n for (const listener of listeners) listener(...args);\n }\n\n /**\n * Removes all connected listeners.\n */\n removeAllListeners(): void {\n this.pListeners = [];\n }\n\n /**\n * Removes specified `listener`, if connected.\n * @param listener\n */\n removeListener(listener: Listener<T>): void {\n const idx = this.pListeners.indexOf(listener);\n if (idx >= 0) this.pListeners.splice(idx, 1);\n }\n}\n"],"mappings":"AAEA;AACA;AACA;AACA,OAAO,MAAMA,OAAO,CAAkC;EAC5CC,UAAU,GAAuB,EAAE;;EAE3C;AACF;AACA;AACA;EACE,IAAIC,YAAYA,CAAA,EAAY;IAC1B,OAAO,CAAC,CAAC,IAAI,CAACD,UAAU,CAACE,MAAM;EACjC;EAEA,IAAIC,SAASA,CAAA,EAA+B;IAC1C,OAAO,IAAI,CAACH,UAAU;EACxB;;EAEA;AACF;AACA;AACA;AACA;EACEI,WAAWA,CAACC,QAAqB,EAAc;IAC7C,IAAI,CAAC,IAAI,CAACL,UAAU,CAACM,QAAQ,CAACD,QAAQ,CAAC,EAAE;MACvC,IAAI,CAACL,UAAU,CAACO,IAAI,CAACF,QAAQ,CAAC;IAChC;IACA,OAAO,MAAM;MACX,IAAI,CAACG,cAAc,CAACH,QAAQ,CAAC;IAC/B,CAAC;EACH;;EAEA;AACF;AACA;AACA;EACEI,IAAIA,CAAC,GAAGC,IAAO,EAAQ;IACrB,MAAMP,SAAS,GAAG,IAAI,CAACH,UAAU,CAACW,KAAK,CAAC,CAAC;IACzC,KAAK,MAAMN,QAAQ,IAAIF,SAAS,EAAEE,QAAQ,CAAC,GAAGK,IAAI,CAAC;EACrD;;EAEA;AACF;AACA;EACEE,kBAAkBA,CAAA,EAAS;IACzB,IAAI,CAACZ,UAAU,GAAG,EAAE;EACtB;;EAEA;AACF;AACA;AACA;EACEQ,cAAcA,CAACH,QAAqB,EAAQ;IAC1C,MAAMQ,GAAG,GAAG,IAAI,CAACb,UAAU,CAACc,OAAO,CAACT,QAAQ,CAAC;IAC7C,IAAIQ,GAAG,IAAI,CAAC,EAAE,IAAI,CAACb,UAAU,CAACe,MAAM,CAACF,GAAG,EAAE,CAAC,CAAC;EAC9C;AACF","ignoreList":[]}
@@ -4,14 +4,19 @@ import Barrier from './Barrier';
4
4
  * Implements a simple semaphore for async code logic.
5
5
  */
6
6
  export default class Semaphore {
7
- constructor() {
8
- let ready = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
7
+ constructor(ready = false) {
8
+ // TODO: Boolean conversion is performed for backward compatibility with
9
+ // plain JS projects. Drop it in future.
10
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
9
11
  this.pReady = !!ready;
10
12
  }
11
13
  get ready() {
12
14
  return this.pReady;
13
15
  }
14
16
  setReady(ready) {
17
+ // TODO: Boolean conversion is performed for backward compatibility with
18
+ // plain JS projects. Drop it in future.
19
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
15
20
  const bool = !!ready;
16
21
  if (this.pReady !== bool) {
17
22
  this.pReady = bool;
@@ -27,8 +32,7 @@ export default class Semaphore {
27
32
  async seize() {
28
33
  return this.waitReady(true);
29
34
  }
30
- async waitReady() {
31
- let seize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
35
+ async waitReady(seize = false) {
32
36
  if (!this.pReady || this.pQueue.length) {
33
37
  const barrier = new Barrier();
34
38
  this.pQueue.push(barrier);
@@ -1 +1 @@
1
- {"version":3,"file":"Semaphore.js","names":["Barrier","Semaphore","constructor","ready","arguments","length","undefined","pReady","setReady","bool","pDraining","pQueue","pDrainQueue","seize","waitReady","barrier","push","pDrainLock","resolve","shift"],"sources":["../../src/Semaphore.ts"],"sourcesContent":["import Barrier from './Barrier';\n\n/**\n * Implements a simple semaphore for async code logic.\n */\nexport default class Semaphore {\n constructor(ready = false) {\n this.pReady = !!ready;\n }\n\n get ready(): boolean {\n return this.pReady;\n }\n\n setReady(ready: boolean): void {\n const bool = !!ready;\n if (this.pReady !== bool) {\n this.pReady = bool;\n if (bool && !this.pDraining && this.pQueue.length) {\n void this.pDrainQueue();\n }\n }\n }\n\n /**\n * Waits until the semaphore is ready, and marks it as non-ready (seizes it).\n */\n async seize(): Promise<void> {\n return this.waitReady(true);\n }\n\n async waitReady(seize = false): Promise<void> {\n if (!this.pReady || this.pQueue.length) {\n const barrier = new Barrier<void>();\n this.pQueue.push(barrier);\n await barrier;\n if (seize) this.pReady = false;\n void this.pDrainLock!.resolve();\n } else if (seize) this.pReady = false;\n }\n\n // Private members below this point.\n\n /**\n * If semaphore is ready, it releases the next barrier in the queue, if any,\n * and reschedules itself for a call in the next event loop iteration.\n * Otherwise, it breaks the queue draining loop, which will be restarted\n * the next time the semaphore is set ready.\n */\n async pDrainQueue(): Promise<void> {\n this.pDraining = true;\n while (this.pReady && this.pQueue.length) {\n this.pDrainLock = new Barrier();\n void this.pQueue[0]!.resolve();\n await this.pDrainLock;\n void this.pQueue.shift();\n }\n this.pDraining = false;\n this.pDrainLock = null;\n }\n\n // \"true\" when the drain queue process is running (and thus no need to start\n // a new one).\n private pDraining = false;\n\n // Each time a Promise from drain queue is resolved this drainLock is set\n // to block further queue draining until the promise resolution handler\n // (.seize() or .waitReady()) unlocks it, thus confirming it is fine\n // to continue the draining. This is specifically important for .seize(),\n // which should have a chance to switch semaphore state to non-ready prior\n // to next Promise in the queue being unlocked.\n private pDrainLock: Barrier<void> | null = null;\n\n // The array of barriers set for each async code flow awaiting for\n // the Semaphore to become ready.\n private pQueue: Array<Barrier<void>> = [];\n\n private pReady: boolean;\n}\n"],"mappings":"AAAA,OAAOA,OAAO,MAAM,WAAW;;AAE/B;AACA;AACA;AACA,eAAe,MAAMC,SAAS,CAAC;EAC7BC,WAAWA,CAAA,EAAgB;IAAA,IAAfC,KAAK,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,KAAK;IACvB,IAAI,CAACG,MAAM,GAAG,CAAC,CAACJ,KAAK;EACvB;EAEA,IAAIA,KAAKA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACI,MAAM;EACpB;EAEAC,QAAQA,CAACL,KAAc,EAAQ;IAC7B,MAAMM,IAAI,GAAG,CAAC,CAACN,KAAK;IACpB,IAAI,IAAI,CAACI,MAAM,KAAKE,IAAI,EAAE;MACxB,IAAI,CAACF,MAAM,GAAGE,IAAI;MAClB,IAAIA,IAAI,IAAI,CAAC,IAAI,CAACC,SAAS,IAAI,IAAI,CAACC,MAAM,CAACN,MAAM,EAAE;QACjD,KAAK,IAAI,CAACO,WAAW,CAAC,CAAC;MACzB;IACF;EACF;;EAEA;AACF;AACA;EACE,MAAMC,KAAKA,CAAA,EAAkB;IAC3B,OAAO,IAAI,CAACC,SAAS,CAAC,IAAI,CAAC;EAC7B;EAEA,MAAMA,SAASA,CAAA,EAA+B;IAAA,IAA9BD,KAAK,GAAAT,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,KAAK;IAC3B,IAAI,CAAC,IAAI,CAACG,MAAM,IAAI,IAAI,CAACI,MAAM,CAACN,MAAM,EAAE;MACtC,MAAMU,OAAO,GAAG,IAAIf,OAAO,CAAO,CAAC;MACnC,IAAI,CAACW,MAAM,CAACK,IAAI,CAACD,OAAO,CAAC;MACzB,MAAMA,OAAO;MACb,IAAIF,KAAK,EAAE,IAAI,CAACN,MAAM,GAAG,KAAK;MAC9B,KAAK,IAAI,CAACU,UAAU,CAAEC,OAAO,CAAC,CAAC;IACjC,CAAC,MAAM,IAAIL,KAAK,EAAE,IAAI,CAACN,MAAM,GAAG,KAAK;EACvC;;EAEA;;EAEA;AACF;AACA;AACA;AACA;AACA;EACE,MAAMK,WAAWA,CAAA,EAAkB;IACjC,IAAI,CAACF,SAAS,GAAG,IAAI;IACrB,OAAO,IAAI,CAACH,MAAM,IAAI,IAAI,CAACI,MAAM,CAACN,MAAM,EAAE;MACxC,IAAI,CAACY,UAAU,GAAG,IAAIjB,OAAO,CAAC,CAAC;MAC/B,KAAK,IAAI,CAACW,MAAM,CAAC,CAAC,CAAC,CAAEO,OAAO,CAAC,CAAC;MAC9B,MAAM,IAAI,CAACD,UAAU;MACrB,KAAK,IAAI,CAACN,MAAM,CAACQ,KAAK,CAAC,CAAC;IAC1B;IACA,IAAI,CAACT,SAAS,GAAG,KAAK;IACtB,IAAI,CAACO,UAAU,GAAG,IAAI;EACxB;;EAEA;EACA;EACQP,SAAS,GAAG,KAAK;;EAEzB;EACA;EACA;EACA;EACA;EACA;EACQO,UAAU,GAAyB,IAAI;;EAE/C;EACA;EACQN,MAAM,GAAyB,EAAE;AAG3C","ignoreList":[]}
1
+ {"version":3,"file":"Semaphore.js","names":["Barrier","Semaphore","constructor","ready","pReady","setReady","bool","pDraining","pQueue","length","pDrainQueue","seize","waitReady","barrier","push","pDrainLock","resolve","shift"],"sources":["../../src/Semaphore.ts"],"sourcesContent":["import Barrier from './Barrier';\n\n/**\n * Implements a simple semaphore for async code logic.\n */\nexport default class Semaphore {\n constructor(ready = false) {\n // TODO: Boolean conversion is performed for backward compatibility with\n // plain JS projects. Drop it in future.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n this.pReady = !!ready;\n }\n\n get ready(): boolean {\n return this.pReady;\n }\n\n setReady(ready: boolean): void {\n // TODO: Boolean conversion is performed for backward compatibility with\n // plain JS projects. Drop it in future.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n const bool = !!ready;\n if (this.pReady !== bool) {\n this.pReady = bool;\n if (bool && !this.pDraining && this.pQueue.length) {\n void this.pDrainQueue();\n }\n }\n }\n\n /**\n * Waits until the semaphore is ready, and marks it as non-ready (seizes it).\n */\n async seize(): Promise<void> {\n return this.waitReady(true);\n }\n\n async waitReady(seize = false): Promise<void> {\n if (!this.pReady || this.pQueue.length) {\n const barrier = new Barrier<void>();\n this.pQueue.push(barrier);\n await barrier;\n if (seize) this.pReady = false;\n void this.pDrainLock!.resolve();\n } else if (seize) this.pReady = false;\n }\n\n // Private members below this point.\n\n /**\n * If semaphore is ready, it releases the next barrier in the queue, if any,\n * and reschedules itself for a call in the next event loop iteration.\n * Otherwise, it breaks the queue draining loop, which will be restarted\n * the next time the semaphore is set ready.\n */\n async pDrainQueue(): Promise<void> {\n this.pDraining = true;\n while (this.pReady && this.pQueue.length) {\n this.pDrainLock = new Barrier();\n void this.pQueue[0]!.resolve();\n await this.pDrainLock;\n void this.pQueue.shift();\n }\n this.pDraining = false;\n this.pDrainLock = null;\n }\n\n // \"true\" when the drain queue process is running (and thus no need to start\n // a new one).\n private pDraining = false;\n\n // Each time a Promise from drain queue is resolved this drainLock is set\n // to block further queue draining until the promise resolution handler\n // (.seize() or .waitReady()) unlocks it, thus confirming it is fine\n // to continue the draining. This is specifically important for .seize(),\n // which should have a chance to switch semaphore state to non-ready prior\n // to next Promise in the queue being unlocked.\n private pDrainLock: Barrier<void> | null = null;\n\n // The array of barriers set for each async code flow awaiting for\n // the Semaphore to become ready.\n private pQueue: Array<Barrier<void>> = [];\n\n private pReady: boolean;\n}\n"],"mappings":"AAAA,OAAOA,OAAO,MAAM,WAAW;;AAE/B;AACA;AACA;AACA,eAAe,MAAMC,SAAS,CAAC;EAC7BC,WAAWA,CAACC,KAAK,GAAG,KAAK,EAAE;IACzB;IACA;IACA;IACA,IAAI,CAACC,MAAM,GAAG,CAAC,CAACD,KAAK;EACvB;EAEA,IAAIA,KAAKA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACC,MAAM;EACpB;EAEAC,QAAQA,CAACF,KAAc,EAAQ;IAC7B;IACA;IACA;IACA,MAAMG,IAAI,GAAG,CAAC,CAACH,KAAK;IACpB,IAAI,IAAI,CAACC,MAAM,KAAKE,IAAI,EAAE;MACxB,IAAI,CAACF,MAAM,GAAGE,IAAI;MAClB,IAAIA,IAAI,IAAI,CAAC,IAAI,CAACC,SAAS,IAAI,IAAI,CAACC,MAAM,CAACC,MAAM,EAAE;QACjD,KAAK,IAAI,CAACC,WAAW,CAAC,CAAC;MACzB;IACF;EACF;;EAEA;AACF;AACA;EACE,MAAMC,KAAKA,CAAA,EAAkB;IAC3B,OAAO,IAAI,CAACC,SAAS,CAAC,IAAI,CAAC;EAC7B;EAEA,MAAMA,SAASA,CAACD,KAAK,GAAG,KAAK,EAAiB;IAC5C,IAAI,CAAC,IAAI,CAACP,MAAM,IAAI,IAAI,CAACI,MAAM,CAACC,MAAM,EAAE;MACtC,MAAMI,OAAO,GAAG,IAAIb,OAAO,CAAO,CAAC;MACnC,IAAI,CAACQ,MAAM,CAACM,IAAI,CAACD,OAAO,CAAC;MACzB,MAAMA,OAAO;MACb,IAAIF,KAAK,EAAE,IAAI,CAACP,MAAM,GAAG,KAAK;MAC9B,KAAK,IAAI,CAACW,UAAU,CAAEC,OAAO,CAAC,CAAC;IACjC,CAAC,MAAM,IAAIL,KAAK,EAAE,IAAI,CAACP,MAAM,GAAG,KAAK;EACvC;;EAEA;;EAEA;AACF;AACA;AACA;AACA;AACA;EACE,MAAMM,WAAWA,CAAA,EAAkB;IACjC,IAAI,CAACH,SAAS,GAAG,IAAI;IACrB,OAAO,IAAI,CAACH,MAAM,IAAI,IAAI,CAACI,MAAM,CAACC,MAAM,EAAE;MACxC,IAAI,CAACM,UAAU,GAAG,IAAIf,OAAO,CAAC,CAAC;MAC/B,KAAK,IAAI,CAACQ,MAAM,CAAC,CAAC,CAAC,CAAEQ,OAAO,CAAC,CAAC;MAC9B,MAAM,IAAI,CAACD,UAAU;MACrB,KAAK,IAAI,CAACP,MAAM,CAACS,KAAK,CAAC,CAAC;IAC1B;IACA,IAAI,CAACV,SAAS,GAAG,KAAK;IACtB,IAAI,CAACQ,UAAU,GAAG,IAAI;EACxB;;EAEA;EACA;EACQR,SAAS,GAAG,KAAK;;EAEzB;EACA;EACA;EACA;EACA;EACA;EACQQ,UAAU,GAAyB,IAAI;;EAE/C;EACA;EACQP,MAAM,GAAyB,EAAE;AAG3C","ignoreList":[]}
@@ -1,4 +1,5 @@
1
1
  export { default as Barrier } from './Barrier';
2
+ export * from './Cached';
2
3
  export * from './Emitter';
3
4
  export { default as Semaphore } from './Semaphore';
4
5
  export * from './time';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["default","Barrier","Semaphore","withRetries"],"sources":["../../src/index.ts"],"sourcesContent":["export { default as Barrier } from './Barrier';\nexport * from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport * from './time';\nexport { default as withRetries } from './withRetries';\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,OAAO,QAAQ,WAAW;AAC9C,cAAc,WAAW;AACzB,SAASD,OAAO,IAAIE,SAAS,QAAQ,aAAa;AAClD,cAAc,QAAQ;AACtB,SAASF,OAAO,IAAIG,WAAW,QAAQ,eAAe","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["default","Barrier","Semaphore","withRetries"],"sources":["../../src/index.ts"],"sourcesContent":["export { default as Barrier } from './Barrier';\nexport * from './Cached';\nexport * from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport * from './time';\nexport { default as withRetries } from './withRetries';\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,OAAO,QAAQ,WAAW;AAC9C,cAAc,UAAU;AACxB,cAAc,WAAW;AACzB,SAASD,OAAO,IAAIE,SAAS,QAAQ,aAAa;AAClD,cAAc,QAAQ;AACtB,SAASF,OAAO,IAAIG,WAAW,QAAQ,eAAe","ignoreList":[]}
@@ -11,9 +11,7 @@ import { timer } from './time';
11
11
  * @returns Resolves to the result of the successful `action` execution;
12
12
  * or rejects with the error from the last faileda attempt.
13
13
  */
14
- export default async function withRetries(action) {
15
- let maxRetries = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
16
- let interval = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 300;
14
+ export default async function withRetries(action, maxRetries = 3, interval = 300) {
17
15
  for (let n = 1;; ++n) {
18
16
  try {
19
17
  const res = action();
@@ -1 +1 @@
1
- {"version":3,"file":"withRetries.js","names":["timer","withRetries","action","maxRetries","arguments","length","undefined","interval","n","res","Promise","error"],"sources":["../../src/withRetries.ts"],"sourcesContent":["import { timer } from './time';\n\n/**\n * Attempts to perform the given async `action` up to `maxRetries` times with\n * the specified `interval`, stopping at the first successful (non-throwing)\n * execution.\n * @param action\n * @param maxRetries Optional. The maximum number of re-tries. Defaults 3.\n * @param interval Optional. The interval between re-tries (in milliseconds).\n * Defaults to 300ms.\n * @returns Resolves to the result of the successful `action` execution;\n * or rejects with the error from the last faileda attempt.\n */\nexport default async function withRetries<T>(\n action: () => T,\n maxRetries = 3,\n interval = 300,\n): Promise<Awaited<T>> {\n for (let n = 1; ; ++n) {\n try {\n const res = action();\n return res instanceof Promise ? await res : (res as Awaited<T>);\n } catch (error) {\n if (n < maxRetries) await timer(interval);\n else throw error;\n }\n }\n}\n"],"mappings":"AAAA,SAASA,KAAK,QAAQ,QAAQ;;AAE9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,eAAeC,WAAWA,CACvCC,MAAe,EAGM;EAAA,IAFrBC,UAAU,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC;EAAA,IACdG,QAAQ,GAAAH,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,GAAG;EAEd,KAAK,IAAII,CAAC,GAAG,CAAC,GAAI,EAAEA,CAAC,EAAE;IACrB,IAAI;MACF,MAAMC,GAAG,GAAGP,MAAM,CAAC,CAAC;MACpB,OAAOO,GAAG,YAAYC,OAAO,GAAG,MAAMD,GAAG,GAAIA,GAAkB;IACjE,CAAC,CAAC,OAAOE,KAAK,EAAE;MACd,IAAIH,CAAC,GAAGL,UAAU,EAAE,MAAMH,KAAK,CAACO,QAAQ,CAAC,CAAC,KACrC,MAAMI,KAAK;IAClB;EACF;AACF","ignoreList":[]}
1
+ {"version":3,"file":"withRetries.js","names":["timer","withRetries","action","maxRetries","interval","n","res","Promise","error"],"sources":["../../src/withRetries.ts"],"sourcesContent":["import { timer } from './time';\n\n/**\n * Attempts to perform the given async `action` up to `maxRetries` times with\n * the specified `interval`, stopping at the first successful (non-throwing)\n * execution.\n * @param action\n * @param maxRetries Optional. The maximum number of re-tries. Defaults 3.\n * @param interval Optional. The interval between re-tries (in milliseconds).\n * Defaults to 300ms.\n * @returns Resolves to the result of the successful `action` execution;\n * or rejects with the error from the last faileda attempt.\n */\nexport default async function withRetries<T>(\n action: () => T,\n maxRetries = 3,\n interval = 300,\n): Promise<Awaited<T>> {\n for (let n = 1; ; ++n) {\n try {\n const res = action();\n return res instanceof Promise ? await res : (res as Awaited<T>);\n } catch (error) {\n if (n < maxRetries) await timer(interval);\n else throw error;\n }\n }\n}\n"],"mappings":"AAAA,SAASA,KAAK,QAAQ,QAAQ;;AAE9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,eAAeC,WAAWA,CACvCC,MAAe,EACfC,UAAU,GAAG,CAAC,EACdC,QAAQ,GAAG,GAAG,EACO;EACrB,KAAK,IAAIC,CAAC,GAAG,CAAC,GAAI,EAAEA,CAAC,EAAE;IACrB,IAAI;MACF,MAAMC,GAAG,GAAGJ,MAAM,CAAC,CAAC;MACpB,OAAOI,GAAG,YAAYC,OAAO,GAAG,MAAMD,GAAG,GAAIA,GAAkB;IACjE,CAAC,CAAC,OAAOE,KAAK,EAAE;MACd,IAAIH,CAAC,GAAGF,UAAU,EAAE,MAAMH,KAAK,CAACI,QAAQ,CAAC,CAAC,KACrC,MAAMI,KAAK;IAClB;EACF;AACF","ignoreList":[]}
@@ -0,0 +1,26 @@
1
+ type CachedT<T> = [T, number];
2
+ type TimestampedPromise<T> = Promise<T> & {
3
+ timestamp: number;
4
+ };
5
+ type EntryT<T> = CachedT<T> | TimestampedPromise<CachedT<T>>;
6
+ export declare class Cached<T> {
7
+ readonly maxage: number;
8
+ private getter;
9
+ private data;
10
+ private oldestTimestamp;
11
+ /** For test use only. */
12
+ get _data(): Readonly<Record<string, EntryT<T>>>;
13
+ /** For test use only. */
14
+ get _oldestTimestamp(): number;
15
+ constructor(maxage: number, getter: (id: string) => T | Promise<T>);
16
+ /** Removes stale items from the cache, and updates .oldestTimestamp. */
17
+ private cleanCache;
18
+ /** Adds `datum` to the cache, and removes stale items from the cache. */
19
+ private set;
20
+ /** Retrieves envelope of the specified datum, either read from the cache,
21
+ * or retrieved using the getter provided at construction time. */
22
+ private getEntry;
23
+ /** Gets item. */
24
+ get(id: string): T | Promise<T>;
25
+ }
26
+ export {};
@@ -1,4 +1,5 @@
1
1
  export { default as Barrier } from './Barrier';
2
+ export * from './Cached';
2
3
  export * from './Emitter';
3
4
  export { default as Semaphore } from './Semaphore';
4
5
  export * from './time';
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@dr.pogodin/js-utils",
3
- "version": "0.0.18",
3
+ "version": "0.1.0",
4
4
  "description": "Collection of JavaScript (TypeScript) utilities.",
5
- "main": "build/common/index.js",
6
- "module": "build/module/index.js",
5
+ "main": "./build/module/index.js",
6
+ "module": "./build/module/index.js",
7
7
  "types": "./build/types/index.d.ts",
8
8
  "exports": {
9
+ "require": "./build/common/index.js",
9
10
  "types": "./build/types/index.d.ts",
10
- "import": "./build/module/index.js",
11
- "default": "./build/common/index.js"
11
+ "default": "./build/module/index.js"
12
12
  },
13
13
  "scripts": {
14
14
  "build": "rimraf build && npm run build:common && npm run build:module && npm run build:types",
@@ -38,21 +38,22 @@
38
38
  },
39
39
  "homepage": "https://github.com/birdofpreyru/js-utils#readme",
40
40
  "devDependencies": {
41
- "@babel/cli": "^7.27.1",
42
- "@babel/core": "^7.27.1",
43
- "@babel/plugin-transform-runtime": "^7.27.1",
44
- "@babel/preset-env": "^7.27.1",
41
+ "@babel/cli": "^7.28.0",
42
+ "@babel/core": "^7.28.0",
43
+ "@babel/plugin-transform-runtime": "^7.28.0",
44
+ "@babel/preset-env": "^7.28.0",
45
45
  "@babel/preset-typescript": "^7.27.1",
46
- "@dr.pogodin/eslint-configs": "^0.0.5",
47
- "@tsconfig/recommended": "^1.0.8",
48
- "@types/jest": "^29.5.14",
49
- "babel-jest": "^29.7.0",
50
- "jest": "^29.7.0",
46
+ "@dr.pogodin/eslint-configs": "^0.0.8",
47
+ "@tsconfig/recommended": "^1.0.10",
48
+ "@types/jest": "^30.0.0",
49
+ "babel-jest": "^30.0.4",
50
+ "jest": "^30.0.4",
51
+ "mockdate": "^3.0.5",
51
52
  "rimraf": "^6.0.1",
52
- "tstyche": "^3.5.0",
53
+ "tstyche": "^4.3.0",
53
54
  "typescript": "^5.8.3"
54
55
  },
55
56
  "dependencies": {
56
- "@babel/runtime": "^7.27.1"
57
+ "@babel/runtime": "^7.27.6"
57
58
  }
58
59
  }
@@ -1,6 +1,8 @@
1
1
  {
2
+ "$schema": "https://tstyche.org/schemas/config.json",
3
+ "checkSuppressedErrors": true,
4
+ "checkSourceFiles": false,
2
5
  "testFileMatch": [
3
- "__tests__/**/*.ts",
4
- "__tests__/**/*.tsx"
6
+ "__tests__/**/*.{ts, tsx}"
5
7
  ]
6
8
  }