indisposed 0.0.7 → 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 +106 -1
- package/dist/explicit-resource-management-BSyjFgS-.js +837 -0
- package/dist/{explicit-resource-management-0TNUBRTo.js.map → explicit-resource-management-BSyjFgS-.js.map} +1 -1
- package/dist/functions/channel.d.ts +82 -0
- package/dist/functions/channel.d.ts.map +1 -0
- package/dist/functions/handlers.d.ts +7 -4
- package/dist/functions/handlers.d.ts.map +1 -1
- package/dist/functions/timing.d.ts +91 -0
- package/dist/functions/timing.d.ts.map +1 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +17 -12
- package/dist/index.js.map +1 -1
- package/dist/no-polyfill.d.ts +5 -3
- package/dist/no-polyfill.d.ts.map +1 -1
- package/dist/no-polyfill.js +139 -58
- package/dist/no-polyfill.js.map +1 -1
- package/dist/path-DtH12Oyl.js +1398 -0
- package/dist/{path-CAJHNV4f.js.map → path-DtH12Oyl.js.map} +1 -1
- package/dist/with-resolvers-0tPpPN4C.js +1243 -0
- package/dist/{with-resolvers-DDdeEz5R.js.map → with-resolvers-0tPpPN4C.js.map} +1 -1
- package/package.json +8 -9
- package/dist/explicit-resource-management-0TNUBRTo.js +0 -448
- package/dist/path-CAJHNV4f.js +0 -918
- package/dist/with-resolvers-DDdeEz5R.js +0 -715
package/dist/no-polyfill.js
CHANGED
|
@@ -1,85 +1,166 @@
|
|
|
1
|
-
function
|
|
2
|
-
return
|
|
1
|
+
function hasDisposable(value) {
|
|
2
|
+
return value != null && typeof value === "object" && typeof value[Symbol.dispose] === "function";
|
|
3
3
|
}
|
|
4
|
-
function
|
|
5
|
-
return
|
|
4
|
+
function hasAsyncDisposable(value) {
|
|
5
|
+
return value != null && typeof value === "object" && typeof value[Symbol.asyncDispose] === "function";
|
|
6
6
|
}
|
|
7
|
-
function
|
|
8
|
-
let
|
|
9
|
-
const
|
|
10
|
-
return Object.assign(
|
|
7
|
+
function toDisposable(value, disposeFn) {
|
|
8
|
+
let disposed = false;
|
|
9
|
+
const originalDispose = hasDisposable(value) ? value[Symbol.dispose] : void 0;
|
|
10
|
+
return Object.assign(value, {
|
|
11
11
|
[Symbol.dispose]: () => {
|
|
12
|
-
|
|
12
|
+
if (disposed) return;
|
|
13
|
+
disposeFn(value);
|
|
14
|
+
originalDispose?.call(value);
|
|
15
|
+
disposed = true;
|
|
13
16
|
}
|
|
14
17
|
});
|
|
15
18
|
}
|
|
16
|
-
function
|
|
17
|
-
let
|
|
18
|
-
const
|
|
19
|
-
return Object.assign(
|
|
19
|
+
function toAsyncDisposable(value, disposeFn) {
|
|
20
|
+
let disposingPromise;
|
|
21
|
+
const originalDispose = hasAsyncDisposable(value) ? value[Symbol.asyncDispose] : void 0;
|
|
22
|
+
return Object.assign(value, {
|
|
20
23
|
[Symbol.asyncDispose]: async () => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
if (disposingPromise == null) {
|
|
25
|
+
disposingPromise = (async () => {
|
|
26
|
+
await disposeFn(value);
|
|
27
|
+
await originalDispose?.call(value);
|
|
28
|
+
})();
|
|
29
|
+
}
|
|
30
|
+
await disposingPromise;
|
|
24
31
|
}
|
|
25
32
|
});
|
|
26
33
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
const DEFAULT_OPTIONS = {
|
|
35
|
+
maxBuffer: 100,
|
|
36
|
+
drain: false
|
|
37
|
+
};
|
|
38
|
+
function channel(options) {
|
|
39
|
+
const { maxBuffer, drain: shouldDrain } = { ...DEFAULT_OPTIONS, ...options };
|
|
40
|
+
let closed = false;
|
|
41
|
+
const events = [];
|
|
42
|
+
const waiters = [];
|
|
43
|
+
const doneResult = () => ({
|
|
44
|
+
value: void 0,
|
|
45
|
+
done: true
|
|
46
|
+
});
|
|
47
|
+
const drainQueue = () => {
|
|
48
|
+
while (!closed && events.length && waiters.length) {
|
|
49
|
+
const value = events.shift();
|
|
50
|
+
const resolve = waiters.shift();
|
|
51
|
+
resolve({ value, done: false });
|
|
38
52
|
}
|
|
39
|
-
e(p(r));
|
|
40
53
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}), r = () => {
|
|
49
|
-
for (; !t && e.length && i.length; ) {
|
|
50
|
-
const l = e.shift();
|
|
51
|
-
i.shift()({ value: l, done: !1 });
|
|
54
|
+
const push = (value) => {
|
|
55
|
+
if (closed) return;
|
|
56
|
+
if (maxBuffer <= 0) {
|
|
57
|
+
if (waiters.length) events.push(value);
|
|
58
|
+
} else {
|
|
59
|
+
events.push(value);
|
|
60
|
+
if (events.length > maxBuffer) events.shift();
|
|
52
61
|
}
|
|
53
|
-
|
|
54
|
-
if (t) return;
|
|
55
|
-
const f = p(l);
|
|
56
|
-
o <= 0 ? i.length && e.push(f) : (e.push(f), e.length > o && e.shift()), r();
|
|
62
|
+
drainQueue();
|
|
57
63
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
const dispose = () => {
|
|
65
|
+
if (closed) return;
|
|
66
|
+
closed = true;
|
|
67
|
+
if (shouldDrain) {
|
|
68
|
+
while (events.length && waiters.length) {
|
|
69
|
+
const value = events.shift();
|
|
70
|
+
const resolve = waiters.shift();
|
|
71
|
+
resolve({ value, done: false });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
while (waiters.length > 0) {
|
|
75
|
+
const waiter = waiters.shift();
|
|
76
|
+
waiter?.(doneResult());
|
|
77
|
+
}
|
|
63
78
|
};
|
|
64
|
-
|
|
79
|
+
const iterator = {
|
|
65
80
|
async next() {
|
|
66
|
-
|
|
67
|
-
|
|
81
|
+
if (shouldDrain && events.length) {
|
|
82
|
+
return { value: events.shift(), done: false };
|
|
83
|
+
}
|
|
84
|
+
if (closed) {
|
|
85
|
+
return doneResult();
|
|
86
|
+
}
|
|
87
|
+
if (events.length) {
|
|
88
|
+
return { value: events.shift(), done: false };
|
|
89
|
+
}
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
waiters.push(resolve);
|
|
92
|
+
drainQueue();
|
|
68
93
|
});
|
|
69
94
|
},
|
|
70
95
|
return() {
|
|
71
|
-
|
|
96
|
+
dispose();
|
|
97
|
+
return Promise.resolve(doneResult());
|
|
72
98
|
},
|
|
73
99
|
[Symbol.asyncIterator]() {
|
|
74
100
|
return this;
|
|
101
|
+
},
|
|
102
|
+
[Symbol.dispose]: dispose
|
|
103
|
+
};
|
|
104
|
+
return {
|
|
105
|
+
push,
|
|
106
|
+
get closed() {
|
|
107
|
+
return closed;
|
|
108
|
+
},
|
|
109
|
+
iterator
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function unpackArray(values) {
|
|
113
|
+
return values.length === 0 ? void 0 : values.length === 1 ? values[0] : values;
|
|
114
|
+
}
|
|
115
|
+
function invoke(fn) {
|
|
116
|
+
return fn();
|
|
117
|
+
}
|
|
118
|
+
function once(emitter, event, rejects) {
|
|
119
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
120
|
+
const handler = (...args) => {
|
|
121
|
+
if (rejects) {
|
|
122
|
+
reject(args.length === 1 ? args[0] : args);
|
|
123
|
+
return;
|
|
75
124
|
}
|
|
76
|
-
|
|
125
|
+
resolve(unpackArray(args));
|
|
126
|
+
};
|
|
127
|
+
emitter.once(event, handler);
|
|
128
|
+
return toDisposable(promise, () => emitter.off(event, handler));
|
|
129
|
+
}
|
|
130
|
+
function on(emitter, event, options) {
|
|
131
|
+
const ch = channel(options);
|
|
132
|
+
const handler = (...args) => {
|
|
133
|
+
ch.push(unpackArray(args));
|
|
134
|
+
};
|
|
135
|
+
emitter.on(event, handler);
|
|
136
|
+
return toDisposable(ch.iterator, () => {
|
|
137
|
+
emitter.off(event, handler);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function timeout(ms) {
|
|
141
|
+
const timingPromise = Promise.withResolvers();
|
|
142
|
+
const timeoutId = setTimeout(timingPromise.resolve, ms);
|
|
143
|
+
return toDisposable(timingPromise.promise, () => clearTimeout(timeoutId));
|
|
144
|
+
}
|
|
145
|
+
function interval(ms, options) {
|
|
146
|
+
const ch = channel(options);
|
|
147
|
+
let currentValue = 0;
|
|
148
|
+
const intervalId = setInterval(() => {
|
|
149
|
+
if (ch.closed) return;
|
|
150
|
+
ch.push(currentValue++);
|
|
151
|
+
}, ms);
|
|
152
|
+
return toDisposable(ch.iterator, () => {
|
|
153
|
+
clearInterval(intervalId);
|
|
154
|
+
});
|
|
77
155
|
}
|
|
78
156
|
export {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
157
|
+
channel,
|
|
158
|
+
interval,
|
|
159
|
+
invoke,
|
|
160
|
+
on,
|
|
161
|
+
once,
|
|
162
|
+
timeout,
|
|
163
|
+
toAsyncDisposable,
|
|
164
|
+
toDisposable
|
|
84
165
|
};
|
|
85
166
|
//# sourceMappingURL=no-polyfill.js.map
|
package/dist/no-polyfill.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-polyfill.js","sources":["../src/functions/disposable.ts","../src/functions/fn.ts","../src/functions/handlers.ts"],"sourcesContent":["/** Function that performs cleanup for a disposable resource */\nexport type DisposeFn<T> = (value: T) => unknown;\n\n/**\n * Object with a Symbol.dispose method for automatic cleanup\n * @see {@link toDisposable}\n */\nexport type Disposable<T extends object> = ReturnType<typeof toDisposable<T>>;\n\nfunction hasDisposable(\n\tvalue: unknown,\n): value is { [Symbol.dispose]: () => unknown } {\n\treturn (\n\t\tvalue != null &&\n\t\ttypeof value === \"object\" &&\n\t\ttypeof (value as any)[Symbol.dispose] === \"function\"\n\t);\n}\n\nfunction hasAsyncDisposable(\n\tvalue: unknown,\n): value is { [Symbol.asyncDispose]: () => PromiseLike<unknown> } {\n\treturn (\n\t\tvalue != null &&\n\t\ttypeof value === \"object\" &&\n\t\ttypeof (value as any)[Symbol.asyncDispose] === \"function\"\n\t);\n}\n\n/**\n * Make a value disposable by adding a Symbol.dispose method\n * @param value item to make disposable (must be an extensible object)\n * @param disposeFn function that will cleanup the item\n * @returns value that's disposable\n * @example\n * ```ts\n * // Direct usage with extensible objects\n * const resource = toDisposable({ handle: 123 }, (r) => closeHandle(r.handle));\n * using handle = resource; // automatically disposed at end of scope\n *\n * // For non-extensible values (primitives, sealed objects, class instances), wrap them:\n * const connection = new WebSocket('ws://localhost');\n * const disposableConnection = toDisposable(\n * { socket: connection },\n * (wrapped) => wrapped.socket.close()\n * );\n * using conn = disposableConnection;\n * ```\n */\nexport function toDisposable<T extends object>(\n\tvalue: T,\n\tdisposeFn: DisposeFn<T>,\n) {\n\tlet disposed = false;\n\n\tconst originalDispose = hasDisposable(value)\n\t\t? value[Symbol.dispose]\n\t\t: undefined;\n\n\treturn Object.assign(value, {\n\t\t[Symbol.dispose]: () => {\n\t\t\tif (disposed) return;\n\n\t\t\tdisposeFn(value);\n\t\t\toriginalDispose?.call(value);\n\t\t\tdisposed = true;\n\t\t},\n\t});\n}\n\n/** Async function that performs cleanup for a disposable resource */\nexport type AsyncDispose<T> = (value: T) => PromiseLike<unknown>;\n\n/**\n * Object with a Symbol.asyncDispose method for automatic async cleanup\n * @see {@link toAsyncDisposable}\n */\nexport type AsyncDisposable<T extends object> = ReturnType<\n\ttypeof toAsyncDisposable<T>\n>;\n\n/**\n * Make a value async disposable by adding a Symbol.asyncDispose method\n * @param value item to make disposable (must be an extensible object)\n * @param disposeFn async function that will cleanup the item\n * @returns value that's async disposable\n * @example\n * ```ts\n * // Direct usage with extensible objects\n * const resource = toAsyncDisposable({ stream: fs.createReadStream('file.txt') }, async (r) => {\n * await r.stream.close();\n * });\n * await using file = resource; // automatically disposed at end of scope\n *\n * // For non-extensible values (sealed objects, class instances), wrap them:\n * const database = new DatabaseConnection();\n * const disposableDb = toAsyncDisposable(\n * { connection: database },\n * async (wrapped) => {\n * await wrapped.connection.close();\n * }\n * );\n * await using db = disposableDb;\n * ```\n */\nexport function toAsyncDisposable<T extends object>(\n\tvalue: T,\n\tdisposeFn: AsyncDispose<T>,\n) {\n\tlet disposingPromise: PromiseLike<unknown> | undefined;\n\tconst originalDispose = hasAsyncDisposable(value)\n\t\t? value[Symbol.asyncDispose]\n\t\t: undefined;\n\n\treturn Object.assign(value, {\n\t\t[Symbol.asyncDispose]: async () => {\n\t\t\tif (disposingPromise == null) {\n\t\t\t\tdisposingPromise = (async () => {\n\t\t\t\t\tawait disposeFn(value);\n\t\t\t\t\tawait originalDispose?.call(value);\n\t\t\t\t})();\n\t\t\t}\n\t\t\tawait disposingPromise;\n\t\t},\n\t});\n}\n","export type UnpackArray<T extends unknown[]> = T[\"length\"] extends 0\n\t? undefined\n\t: T[\"length\"] extends 1\n\t\t? T[0]\n\t\t: T;\n\nexport function unpackArray<T extends unknown[]>(values: T) {\n\treturn (\n\t\tvalues.length === 0 ? undefined : values.length === 1 ? values[0] : values\n\t) as UnpackArray<T>;\n}\n\n/**\n * Utility just invokes the method being called immediately.\n * Useful to scope resources to calling body.\n * @param fn Function to invoke\n * @returns Result of fn\n * @example\n * ```ts\n * import {invoke, once, toAsyncDisposable} from \"indisposed\";\n * import {WebSocketServer} from \"ws\";\n *\n * {\n * \tawait using wss = await invoke(async () => {\n * \t\tconst wss = toAsyncDisposable(\n * \t\t\tnew WebSocketServer({ host: \"127.0.0.1\", port: 0 }),\n * \t\t\t(wss) =>\n * \t\t\t\tnew Promise((resolve, reject) => {\n * \t\t\t\t\twss.close((err) => {\n * \t\t\t\t\t\tif (err) return reject(err);\n * \t\t\t\t\t\tresolve(undefined);\n * \t\t\t\t\t});\n * \t\t\t\t}),\n * \t\t);\n * \t\tusing listening = once(wss, \"listening\");\n * \t\tusing error = once(wss, \"error\", true);\n *\n * \t\tawait Promise.race([listening, error]);\n *\n * \t\treturn wss;\n * \t});\n *\n * \tconsole.log(\"Server ready at\", wss.address());\n * \t// ... handle connections ...\n * }\n * // wss is automatically closed once the scope ends\n * ```\n */\nexport function invoke<TResult>(fn: () => TResult) {\n\treturn fn();\n}\n","import type { EventHandlerParams, EventNames, Fn } from \"~/types\";\nimport { toDisposable } from \"./disposable\";\nimport { type UnpackArray, unpackArray } from \"./fn\";\n\nexport type Subscription = (event: any, handler: Fn) => any;\n\n/**\n * Represents an event emitter with an `off` method for removing listeners.\n */\nexport type HasOff = {\n\toff: Subscription;\n};\n\n/**\n * Represents an event emitter with an `on` method for registering listeners.\n */\nexport type HasOn = {\n\ton: Subscription;\n} & HasOff;\n\n/**\n * Represents an event emitter with a `once` method for one-time listeners.\n */\nexport type HasOnce = {\n\tonce: Subscription;\n} & HasOff;\n\nexport type OnceResult<\n\tEventEmitter extends HasOnce,\n\tEvent extends EventNames<EventEmitter[\"once\"]>,\n\tRejects extends boolean,\n> = Rejects extends true\n\t? never\n\t: UnpackArray<EventHandlerParams<EventEmitter[\"once\"], Event>>;\n\n/**\n * Type-safe wrapper for event emitter's `once` method that preserves overload signatures.\n *\n * The return value is automatically unpacked:\n * - Handlers with 0 parameters resolve to `undefined`\n * - Handlers with 1 parameter resolve to that single value\n * - Handlers with 2+ parameters resolve to an array of values\n *\n * @param emitter - Event emitter with `once` and `off` methods\n * @param event - Event name (must match one of the emitter's overloads)\n * @param rejects - When true, the promise rejects with the handler arguments instead of resolving\n * @returns Disposable promise with the handler arguments and automatic cleanup via `off`\n *\n * @example\n * ```ts\n * type MyEmitter = {\n * once(event: 'data', handler: (value: string) => void): void;\n * once(event: 'error', handler: (error: Error) => void): number;\n * once(event: 'multi', handler: (x: number, y: number) => void): void;\n * off(event: string, handler: Fn): void;\n * };\n *\n * declare const emitter: MyEmitter;\n *\n * // Single parameter: returns the value directly\n * using result = once(emitter, 'data');\n * console.log((await result).toUpperCase()); // string\n *\n * // Multiple parameters: returns as array\n * using coords = once(emitter, 'multi');\n * const [x, y] = await coords; // [number, number]\n * ```\n */\nexport function once<\n\tEventEmitter extends HasOnce,\n\tconst Event extends EventNames<EventEmitter[\"once\"]>,\n\tconst Rejects extends boolean = false,\n>(emitter: EventEmitter, event: Event, rejects?: Rejects) {\n\tconst { promise, resolve, reject } =\n\t\tPromise.withResolvers<OnceResult<EventEmitter, Event, Rejects>>();\n\n\tconst handler: Fn = (...args: unknown[]) => {\n\t\tif (rejects) {\n\t\t\treject(args.length === 1 ? args[0] : args);\n\t\t\treturn;\n\t\t}\n\t\tresolve(unpackArray(args) as OnceResult<EventEmitter, Event, Rejects>);\n\t};\n\temitter.once(event, handler);\n\treturn toDisposable(promise, () => emitter.off(event, handler));\n}\n\nexport type OnResult<\n\tEventEmitter extends HasOn,\n\tEvent extends EventNames<EventEmitter[\"on\"]>,\n> = UnpackArray<EventHandlerParams<EventEmitter[\"on\"], Event>>;\n\n/**\n * Type-safe wrapper for event emitter's `on` method that returns an async iterator.\n *\n * The yielded values are automatically unpacked:\n * - Handlers with 0 parameters yield `undefined`\n * - Handlers with 1 parameter yield that single value\n * - Handlers with 2+ parameters yield an array of values\n *\n * @param emitter - Event emitter with `on` and `off` methods\n * @param event - Event name (must match one of the emitter's overloads)\n * @param maxBuffer - Maximum number of events to buffer (default: 100)\n * @returns Disposable async iterator that yields handler arguments\n *\n * @example\n * ```ts\n * type MyEmitter = {\n * on(event: 'data', handler: (value: string) => void): void;\n * on(event: 'position', handler: (x: number, y: number) => void): void;\n * off(event: string, handler: Fn): void;\n * };\n *\n * declare const emitter: MyEmitter;\n *\n * // Single parameter: yields values directly\n * using iterator = on(emitter, 'data');\n * for await (const value of iterator) {\n * console.log(value.toUpperCase()); // string\n * }\n *\n * // Multiple parameters: yields as array\n * using positions = on(emitter, 'position');\n * for await (const [x, y] of positions) {\n * console.log(`Position: ${x}, ${y}`);\n * }\n * ```\n */\nexport function on<\n\tEventEmitter extends HasOn,\n\tconst Event extends EventNames<EventEmitter[\"on\"]>,\n>(emitter: EventEmitter, event: Event, maxBuffer = 100) {\n\ttype Item = OnResult<EventEmitter, Event>;\n\ttype IterationResult = IteratorResult<Item, undefined>;\n\n\tlet done = false;\n\tconst events: Item[] = [];\n\tconst waiters: ((value: IterationResult) => void)[] = [];\n\n\tconst doneResult = () => ({\n\t\tvalue: undefined,\n\t\tdone: true as const,\n\t});\n\n\tconst drain = () => {\n\t\t// Pair off as many as possible, FIFO ↔ FIFO\n\t\twhile (!done && events.length && waiters.length) {\n\t\t\tconst value = events.shift()!;\n\t\t\tconst resolve = waiters.shift()!;\n\t\t\tresolve({ value, done: false });\n\t\t}\n\t};\n\n\tconst handler = (...args: unknown[]) => {\n\t\tif (done) return;\n\t\tconst value = unpackArray(args) as Item;\n\n\t\tif (maxBuffer <= 0) {\n\t\t\tif (waiters.length) events.push(value); // only deliver to waiters\n\t\t} else {\n\t\t\tevents.push(value);\n\t\t\tif (events.length > maxBuffer) events.shift();\n\t\t}\n\t\tdrain();\n\t};\n\n\temitter.on(event, handler);\n\n\tconst dispose = () => {\n\t\tif (done) return;\n\t\temitter.off(event, handler);\n\t\tdone = true;\n\n\t\twhile (waiters.length > 0) {\n\t\t\tconst waiter = waiters.shift();\n\t\t\twaiter?.(doneResult());\n\t\t}\n\t};\n\n\tconst iterator: AsyncIterableIterator<Item, undefined, void> = {\n\t\tasync next() {\n\t\t\t// If already disposed, return done\n\t\t\tif (done) {\n\t\t\t\treturn doneResult();\n\t\t\t}\n\n\t\t\tif (events.length)\n\t\t\t\treturn { value: events.shift()!, done: false } as const;\n\n\t\t\t// Wait for the next event\n\t\t\treturn new Promise<IterationResult>((resolve) => {\n\t\t\t\twaiters.push(resolve);\n\t\t\t\tdrain();\n\t\t\t});\n\t\t},\n\t\treturn() {\n\t\t\tdispose();\n\t\t\treturn Promise.resolve(doneResult());\n\t\t},\n\t\t[Symbol.asyncIterator]() {\n\t\t\treturn this;\n\t\t},\n\t};\n\n\treturn toDisposable(iterator, dispose);\n}\n"],"names":["hasDisposable","value","hasAsyncDisposable","toDisposable","disposeFn","disposed","originalDispose","toAsyncDisposable","disposingPromise","unpackArray","values","invoke","fn","once","emitter","event","rejects","promise","resolve","reject","handler","args","on","maxBuffer","done","events","waiters","doneResult","drain","dispose"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"no-polyfill.js","sources":["../src/functions/disposable.ts","../src/functions/channel.ts","../src/functions/fn.ts","../src/functions/handlers.ts","../src/functions/timing.ts"],"sourcesContent":["/** Function that performs cleanup for a disposable resource */\nexport type DisposeFn<T> = (value: T) => unknown;\n\n/**\n * Object with a Symbol.dispose method for automatic cleanup\n * @see {@link toDisposable}\n */\nexport type Disposable<T extends object> = ReturnType<typeof toDisposable<T>>;\n\nfunction hasDisposable(\n\tvalue: unknown,\n): value is { [Symbol.dispose]: () => unknown } {\n\treturn (\n\t\tvalue != null &&\n\t\ttypeof value === \"object\" &&\n\t\ttypeof (value as any)[Symbol.dispose] === \"function\"\n\t);\n}\n\nfunction hasAsyncDisposable(\n\tvalue: unknown,\n): value is { [Symbol.asyncDispose]: () => PromiseLike<unknown> } {\n\treturn (\n\t\tvalue != null &&\n\t\ttypeof value === \"object\" &&\n\t\ttypeof (value as any)[Symbol.asyncDispose] === \"function\"\n\t);\n}\n\n/**\n * Make a value disposable by adding a Symbol.dispose method\n * @param value item to make disposable (must be an extensible object)\n * @param disposeFn function that will cleanup the item\n * @returns value that's disposable\n * @example\n * ```ts\n * // Direct usage with extensible objects\n * const resource = toDisposable({ handle: 123 }, (r) => closeHandle(r.handle));\n * using handle = resource; // automatically disposed at end of scope\n *\n * // For non-extensible values (primitives, sealed objects, class instances), wrap them:\n * const connection = new WebSocket('ws://localhost');\n * const disposableConnection = toDisposable(\n * { socket: connection },\n * (wrapped) => wrapped.socket.close()\n * );\n * using conn = disposableConnection;\n * ```\n */\nexport function toDisposable<T extends object>(\n\tvalue: T,\n\tdisposeFn: DisposeFn<T>,\n) {\n\tlet disposed = false;\n\n\tconst originalDispose = hasDisposable(value)\n\t\t? value[Symbol.dispose]\n\t\t: undefined;\n\n\treturn Object.assign(value, {\n\t\t[Symbol.dispose]: () => {\n\t\t\tif (disposed) return;\n\n\t\t\tdisposeFn(value);\n\t\t\toriginalDispose?.call(value);\n\t\t\tdisposed = true;\n\t\t},\n\t});\n}\n\n/** Async function that performs cleanup for a disposable resource */\nexport type AsyncDispose<T> = (value: T) => PromiseLike<unknown>;\n\n/**\n * Object with a Symbol.asyncDispose method for automatic async cleanup\n * @see {@link toAsyncDisposable}\n */\nexport type AsyncDisposable<T extends object> = ReturnType<\n\ttypeof toAsyncDisposable<T>\n>;\n\n/**\n * Make a value async disposable by adding a Symbol.asyncDispose method\n * @param value item to make disposable (must be an extensible object)\n * @param disposeFn async function that will cleanup the item\n * @returns value that's async disposable\n * @example\n * ```ts\n * // Direct usage with extensible objects\n * const resource = toAsyncDisposable({ stream: fs.createReadStream('file.txt') }, async (r) => {\n * await r.stream.close();\n * });\n * await using file = resource; // automatically disposed at end of scope\n *\n * // For non-extensible values (sealed objects, class instances), wrap them:\n * const database = new DatabaseConnection();\n * const disposableDb = toAsyncDisposable(\n * { connection: database },\n * async (wrapped) => {\n * await wrapped.connection.close();\n * }\n * );\n * await using db = disposableDb;\n * ```\n */\nexport function toAsyncDisposable<T extends object>(\n\tvalue: T,\n\tdisposeFn: AsyncDispose<T>,\n) {\n\tlet disposingPromise: PromiseLike<unknown> | undefined;\n\tconst originalDispose = hasAsyncDisposable(value)\n\t\t? value[Symbol.asyncDispose]\n\t\t: undefined;\n\n\treturn Object.assign(value, {\n\t\t[Symbol.asyncDispose]: async () => {\n\t\t\tif (disposingPromise == null) {\n\t\t\t\tdisposingPromise = (async () => {\n\t\t\t\t\tawait disposeFn(value);\n\t\t\t\t\tawait originalDispose?.call(value);\n\t\t\t\t})();\n\t\t\t}\n\t\t\tawait disposingPromise;\n\t\t},\n\t});\n}\n","export type ChannelOptions = {\n\t/**\n\t * Maximum amount of events to be buffered.\n\t * When buffer is full, oldest events are dropped.\n\t * Set to 0 to disable buffering (only deliver to waiting consumers).\n\t * @default 100\n\t */\n\tmaxBuffer?: number;\n\n\t/**\n\t * Whether to drain buffered events before ending iteration on dispose.\n\t * When true, buffered events will still be yielded after dispose is called.\n\t * When false, dispose immediately ends iteration and discards buffered events.\n\t * @default false\n\t */\n\tdrain?: boolean;\n};\n\nconst DEFAULT_OPTIONS = {\n\tmaxBuffer: 100,\n\tdrain: false,\n} satisfies ChannelOptions;\n\n/**\n * The iterator portion of a channel - this is what consumers see.\n */\nexport type ChannelIterator<T> = AsyncIterableIterator<T, undefined, void> & {\n\t[Symbol.dispose]: () => void;\n};\n\n/**\n * The full channel handle with push capability - for internal/producer use.\n */\nexport type Channel<T> = {\n\t/**\n\t * Push a value into the channel.\n\t * If there are waiting consumers, the value is delivered immediately.\n\t * Otherwise, it's buffered (subject to maxBuffer).\n\t */\n\tpush: (value: T) => void;\n\t/**\n\t * Whether the channel is closed.\n\t */\n\treadonly closed: boolean;\n\t/**\n\t * The async iterator for consuming values.\n\t * This is what should be exposed to downstream consumers.\n\t */\n\titerator: ChannelIterator<T>;\n};\n\n/**\n * Creates a buffered async channel for pushing values and consuming them via async iteration.\n *\n * This is a low-level primitive for building async iterators from push-based sources\n * like event emitters, intervals, or any producer that pushes values over time.\n *\n * The returned channel has a `push` method for producers and an `iterator` property\n * for consumers. Only expose the `iterator` to downstream code.\n *\n * @param options - Channel configuration\n * @returns A channel with push capability and a disposable async iterator\n *\n * @example\n * ```ts\n * // Basic usage - producer keeps the channel, consumer gets the iterator\n * const ch = channel<string>();\n *\n * // Producer side\n * ch.push(\"hello\");\n * ch.push(\"world\");\n *\n * // Consumer side - only sees the iterator\n * for await (const value of ch.iterator) {\n * console.log(value);\n * if (shouldStop) break;\n * }\n * ```\n *\n * @example\n * ```ts\n * // Building a custom async iterator\n * function myAsyncSource() {\n * const ch = channel<number>();\n * // ... set up producer that calls ch.push()\n * return ch.iterator; // Only expose the iterator\n * }\n * ```\n */\nexport function channel<T>(options?: ChannelOptions): Channel<T> {\n\tconst { maxBuffer, drain: shouldDrain } = { ...DEFAULT_OPTIONS, ...options };\n\ttype IterationResult = IteratorResult<T, undefined>;\n\n\tlet closed = false;\n\tconst events: T[] = [];\n\tconst waiters: ((value: IterationResult) => void)[] = [];\n\n\tconst doneResult = (): IterationResult => ({\n\t\tvalue: undefined,\n\t\tdone: true as const,\n\t});\n\n\tconst drainQueue = () => {\n\t\t// Pair off as many as possible, FIFO ↔ FIFO\n\t\twhile (!closed && events.length && waiters.length) {\n\t\t\tconst value = events.shift()!;\n\t\t\tconst resolve = waiters.shift()!;\n\t\t\tresolve({ value, done: false });\n\t\t}\n\t};\n\n\tconst push = (value: T) => {\n\t\tif (closed) return;\n\n\t\tif (maxBuffer <= 0) {\n\t\t\t// Only deliver to waiting consumers\n\t\t\tif (waiters.length) events.push(value);\n\t\t} else {\n\t\t\tevents.push(value);\n\t\t\tif (events.length > maxBuffer) events.shift();\n\t\t}\n\t\tdrainQueue();\n\t};\n\n\tconst dispose = () => {\n\t\tif (closed) return;\n\t\tclosed = true;\n\n\t\tif (shouldDrain) {\n\t\t\t// Drain buffered events to waiting consumers before signaling done\n\t\t\twhile (events.length && waiters.length) {\n\t\t\t\tconst value = events.shift()!;\n\t\t\t\tconst resolve = waiters.shift()!;\n\t\t\t\tresolve({ value, done: false });\n\t\t\t}\n\t\t}\n\n\t\t// Signal done to remaining waiters\n\t\twhile (waiters.length > 0) {\n\t\t\tconst waiter = waiters.shift();\n\t\t\twaiter?.(doneResult());\n\t\t}\n\t};\n\n\tconst iterator: ChannelIterator<T> = {\n\t\tasync next() {\n\t\t\t// If drain mode, return buffered events even after close\n\t\t\tif (shouldDrain && events.length) {\n\t\t\t\treturn { value: events.shift()!, done: false } as const;\n\t\t\t}\n\n\t\t\tif (closed) {\n\t\t\t\treturn doneResult();\n\t\t\t}\n\n\t\t\tif (events.length) {\n\t\t\t\treturn { value: events.shift()!, done: false } as const;\n\t\t\t}\n\n\t\t\t// Wait for the next event\n\t\t\treturn new Promise<IterationResult>((resolve) => {\n\t\t\t\twaiters.push(resolve);\n\t\t\t\tdrainQueue();\n\t\t\t});\n\t\t},\n\t\treturn() {\n\t\t\tdispose();\n\t\t\treturn Promise.resolve(doneResult());\n\t\t},\n\t\t[Symbol.asyncIterator]() {\n\t\t\treturn this;\n\t\t},\n\t\t[Symbol.dispose]: dispose,\n\t};\n\n\treturn {\n\t\tpush,\n\t\tget closed() {\n\t\t\treturn closed;\n\t\t},\n\t\titerator,\n\t};\n}\n","export type UnpackArray<T extends unknown[]> = T[\"length\"] extends 0\n\t? undefined\n\t: T[\"length\"] extends 1\n\t\t? T[0]\n\t\t: T;\n\nexport function unpackArray<T extends unknown[]>(values: T) {\n\treturn (\n\t\tvalues.length === 0 ? undefined : values.length === 1 ? values[0] : values\n\t) as UnpackArray<T>;\n}\n\n/**\n * Utility just invokes the method being called immediately.\n * Useful to scope resources to calling body.\n * @param fn Function to invoke\n * @returns Result of fn\n * @example\n * ```ts\n * import {invoke, once, toAsyncDisposable} from \"indisposed\";\n * import {WebSocketServer} from \"ws\";\n *\n * {\n * \tawait using wss = await invoke(async () => {\n * \t\tconst wss = toAsyncDisposable(\n * \t\t\tnew WebSocketServer({ host: \"127.0.0.1\", port: 0 }),\n * \t\t\t(wss) =>\n * \t\t\t\tnew Promise((resolve, reject) => {\n * \t\t\t\t\twss.close((err) => {\n * \t\t\t\t\t\tif (err) return reject(err);\n * \t\t\t\t\t\tresolve(undefined);\n * \t\t\t\t\t});\n * \t\t\t\t}),\n * \t\t);\n * \t\tusing listening = once(wss, \"listening\");\n * \t\tusing error = once(wss, \"error\", true);\n *\n * \t\tawait Promise.race([listening, error]);\n *\n * \t\treturn wss;\n * \t});\n *\n * \tconsole.log(\"Server ready at\", wss.address());\n * \t// ... handle connections ...\n * }\n * // wss is automatically closed once the scope ends\n * ```\n */\nexport function invoke<TResult>(fn: () => TResult) {\n\treturn fn();\n}\n","import type { EventHandlerParams, EventNames, Fn } from \"~/types\";\nimport { toDisposable } from \"./disposable\";\nimport { channel, type ChannelOptions } from \"./channel\";\nimport { type UnpackArray, unpackArray } from \"./fn\";\n\nexport type Subscription = (event: any, handler: Fn) => any;\n\n/**\n * Represents an event emitter with an `off` method for removing listeners.\n */\nexport type HasOff = {\n\toff: Subscription;\n};\n\n/**\n * Represents an event emitter with an `on` method for registering listeners.\n */\nexport type HasOn = {\n\ton: Subscription;\n} & HasOff;\n\n/**\n * Represents an event emitter with a `once` method for one-time listeners.\n */\nexport type HasOnce = {\n\tonce: Subscription;\n} & HasOff;\n\nexport type OnceResult<\n\tEventEmitter extends HasOnce,\n\tEvent extends EventNames<EventEmitter[\"once\"]>,\n\tRejects extends boolean,\n> = Rejects extends true\n\t? never\n\t: UnpackArray<EventHandlerParams<EventEmitter[\"once\"], Event>>;\n\n/**\n * Type-safe wrapper for event emitter's `once` method that preserves overload signatures.\n *\n * The return value is automatically unpacked:\n * - Handlers with 0 parameters resolve to `undefined`\n * - Handlers with 1 parameter resolve to that single value\n * - Handlers with 2+ parameters resolve to an array of values\n *\n * @param emitter - Event emitter with `once` and `off` methods\n * @param event - Event name (must match one of the emitter's overloads)\n * @param rejects - When true, the promise rejects with the handler arguments instead of resolving\n * @returns Disposable promise with the handler arguments and automatic cleanup via `off`\n *\n * @example\n * ```ts\n * type MyEmitter = {\n * once(event: 'data', handler: (value: string) => void): void;\n * once(event: 'error', handler: (error: Error) => void): number;\n * once(event: 'multi', handler: (x: number, y: number) => void): void;\n * off(event: string, handler: Fn): void;\n * };\n *\n * declare const emitter: MyEmitter;\n *\n * // Single parameter: returns the value directly\n * using result = once(emitter, 'data');\n * console.log((await result).toUpperCase()); // string\n *\n * // Multiple parameters: returns as array\n * using coords = once(emitter, 'multi');\n * const [x, y] = await coords; // [number, number]\n * ```\n */\nexport function once<\n\tEventEmitter extends HasOnce,\n\tconst Event extends EventNames<EventEmitter[\"once\"]>,\n\tconst Rejects extends boolean = false,\n>(emitter: EventEmitter, event: Event, rejects?: Rejects) {\n\tconst { promise, resolve, reject } =\n\t\tPromise.withResolvers<OnceResult<EventEmitter, Event, Rejects>>();\n\n\tconst handler: Fn = (...args: unknown[]) => {\n\t\tif (rejects) {\n\t\t\treject(args.length === 1 ? args[0] : args);\n\t\t\treturn;\n\t\t}\n\t\tresolve(unpackArray(args) as OnceResult<EventEmitter, Event, Rejects>);\n\t};\n\temitter.once(event, handler);\n\treturn toDisposable(promise, () => emitter.off(event, handler));\n}\n\nexport type OnResult<\n\tEventEmitter extends HasOn,\n\tEvent extends EventNames<EventEmitter[\"on\"]>,\n> = UnpackArray<EventHandlerParams<EventEmitter[\"on\"], Event>>;\n\n/**\n * Type-safe wrapper for event emitter's `on` method that returns an async iterator.\n *\n * The yielded values are automatically unpacked:\n * - Handlers with 0 parameters yield `undefined`\n * - Handlers with 1 parameter yield that single value\n * - Handlers with 2+ parameters yield an array of values\n *\n * @param emitter - Event emitter with `on` and `off` methods\n * @param event - Event name (must match one of the emitter's overloads)\n * @param options - Channel options (maxBuffer, etc.)\n * @returns Disposable async iterator that yields handler arguments\n *\n * @example\n * ```ts\n * type MyEmitter = {\n * on(event: 'data', handler: (value: string) => void): void;\n * on(event: 'position', handler: (x: number, y: number) => void): void;\n * off(event: string, handler: Fn): void;\n * };\n *\n * declare const emitter: MyEmitter;\n *\n * // Single parameter: yields values directly\n * using iterator = on(emitter, 'data');\n * for await (const value of iterator) {\n * console.log(value.toUpperCase()); // string\n * }\n *\n * // Multiple parameters: yields as array\n * using positions = on(emitter, 'position');\n * for await (const [x, y] of positions) {\n * console.log(`Position: ${x}, ${y}`);\n * }\n * ```\n */\nexport function on<\n\tEventEmitter extends HasOn,\n\tconst Event extends EventNames<EventEmitter[\"on\"]>,\n>(emitter: EventEmitter, event: Event, options?: ChannelOptions) {\n\ttype Item = OnResult<EventEmitter, Event>;\n\n\tconst ch = channel<Item>(options);\n\n\tconst handler = (...args: unknown[]) => {\n\t\tch.push(unpackArray(args) as Item);\n\t};\n\n\temitter.on(event, handler);\n\n\treturn toDisposable(ch.iterator, () => {\n\t\temitter.off(event, handler);\n\t});\n}\n","import { toDisposable } from \"./disposable\";\nimport { channel, type ChannelOptions } from \"./channel\";\n\n/**\n * Creates a disposable promise that resolves after a specified delay.\n *\n * The timeout is automatically cleared when disposed, preventing\n * memory leaks and unnecessary timer execution.\n *\n * @param ms - Delay in milliseconds before the promise resolves\n * @returns A disposable promise that resolves to `void` after the delay\n *\n * @example\n * ```ts\n * // Basic usage - wait for 1 second\n * await timeout(1000);\n * console.log(\"1 second passed\");\n * ```\n *\n * @example\n * ```ts\n * // With using - automatically clears timeout when scope exits\n * {\n * using timer = timeout(5000);\n * await timer;\n * } // timeout cleared if scope exits early\n * ```\n *\n * @example\n * ```ts\n * // Racing with other promises - losing timeout is cleaned up\n * {\n * using timer = timeout(10000);\n * using data = once(socket, \"data\");\n *\n * await Promise.race([timer, data]);\n * } // both cleaned up regardless of which wins\n * ```\n */\nexport function timeout(ms: number) {\n\tconst timingPromise = Promise.withResolvers<void>();\n\tconst timeoutId = setTimeout(timingPromise.resolve, ms);\n\n\treturn toDisposable(timingPromise.promise, () => clearTimeout(timeoutId));\n}\n\nexport type IntervalOptions = ChannelOptions;\n\n/**\n * Creates a disposable async iterator that yields incrementing numbers at a fixed interval.\n *\n * Values start at 0 and increment by 1 for each interval tick. The interval\n * is automatically cleared when the iterator is disposed or iteration ends.\n *\n * @param ms - Interval duration in milliseconds between each tick\n * @param options - Channel options for buffering behavior\n * @param options.maxBuffer - Maximum events to buffer (default: 100). Set to 0 for no buffering.\n * @param options.drain - Whether to drain buffer on close (default: false)\n * @returns A disposable async iterator yielding incrementing numbers\n *\n * @example\n * ```ts\n * // Basic usage - tick every second\n * {\n * using ticks = interval(1000);\n *\n * for await (const tick of ticks) {\n * console.log(`Tick ${tick}`); // 0, 1, 2, ...\n * if (tick >= 5) break;\n * }\n * } // interval automatically cleared\n * ```\n *\n * @example\n * ```ts\n * // Polling pattern\n * {\n * using poll = interval(5000);\n *\n * for await (const _ of poll) {\n * const status = await checkStatus();\n * if (status === \"complete\") break;\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // With no buffering - only deliver to waiting consumers\n * const ticks = interval(100, { maxBuffer: 0 });\n * ```\n */\nexport function interval(ms: number, options?: IntervalOptions) {\n\tconst ch = channel<number>(options);\n\tlet currentValue = 0;\n\n\tconst intervalId = setInterval(() => {\n\t\tif (ch.closed) return;\n\t\tch.push(currentValue++);\n\t}, ms);\n\n\treturn toDisposable(ch.iterator, () => {\n\t\tclearInterval(intervalId);\n\t});\n}\n"],"names":[],"mappings":"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"}
|