shelving
Version:
Toolkit for using data in JavaScript.
62 lines (61 loc) • 1.77 kB
JavaScript
import { logError } from "./error.js";
import { isObject } from "./object.js";
/**
* Temporary polyfill for `Symbol.dipose` value.
* @todo Remove this once browsers support `Symbol.dispose`
*/
Symbol.dispose ??= Symbol("Symbol.dispose");
/** Safely dispose a disposable. */
export function dispose(value) {
try {
value[Symbol.dispose]();
}
catch (thrown) {
logError(thrown);
}
}
/** Is an unknown value a disposable object? */
export function isDisposable(v) {
return isObject(v) && typeof v[Symbol.dispose] === "function";
}
/**
* Version of `Map` that is disposable.
* - If items are `Disposable` they are disposed when they're deleted from the map.
* - Set itself is `Disposable` to delete (and dispose) all items when the map itself is disposed.
*/
export class DisposableMap extends Map {
delete(key) {
if (this.has(key)) {
const value = this.get(key);
super.delete(key);
if (isDisposable(value))
dispose(value);
return true;
}
return false;
}
[Symbol.dispose]() {
for (const key of this.keys())
this.delete(key);
}
}
/**
* Version of `Set` that is disposable.
* - If items are `Disposable` they are disposed when they're deleted from the set.
* - Set itself is `Disposable` to delete (and dispose) all items when the set itself is disposed.
*/
export class DisposableSet extends Set {
delete(item) {
if (this.has(item)) {
super.delete(item);
if (isDisposable(item))
dispose(item);
return true;
}
return false;
}
[Symbol.dispose]() {
for (const item of this)
this.delete(item);
}
}