UNPKG

tc39-weakrefs-shim

Version:
140 lines 5.48 kB
import makePrivates from "../utils/privates.js"; import isObject from "../utils/lodash/isObject.js"; // Note: agent will hold FinalizationGroup instance until all registered targets have been collected class FinalizationGroupCell { constructor(info, holdings, unregisterTokenSiblings) { this.info = info; this.holdings = holdings; this.unregisterTokenSiblings = unregisterTokenSiblings; } } class FinalizationGroupSlots { constructor(cleanupCallback) { this.cleanupCallback = cleanupCallback; this.cellsForTarget = new Map(); this.cellsForToken = new WeakMap(); this.isCleanupJobActive = false; } } export function createFinalizationGroupClassShim(jobs, getInfo, isAlive) { const privates = makePrivates(); function* getEmptyCells(context) { for (const info of context.finalized) { const cells = context.cellsForInfo.get(info); if (!cells) continue; for (const cell of cells) { if (!context.finalized) throw new TypeError(); yield cell; } } } const CleanupIterator = function* CleanupIterator(context) { for (const cell of context.cells) { if (isAlive(cell.info)) continue; const holding = cell.holdings; unregisterCell(context.group, cell); yield holding; } }; Object.defineProperty(Object.getPrototypeOf(CleanupIterator.prototype), Symbol.toStringTag, { value: "FinalizationGroup Cleanup Iterator", configurable: true, }); function unregisterCell(group, cell) { const slots = privates(group); if (cell.unregisterTokenSiblings) { cell.unregisterTokenSiblings.delete(cell); } const cellsForTarget = slots.cellsForTarget.get(cell.info); cellsForTarget.delete(cell); if (cellsForTarget.size == 0) { slots.cellsForTarget.delete(cell.info); jobs.unregisterFinalizationGroup(group, cell.info); } } class FinalizationGroup { constructor(cleanupCallback) { if (typeof cleanupCallback != "function") throw new TypeError(); privates.init(this, new FinalizationGroupSlots(cleanupCallback)); } register(target, holdings, unregisterToken = undefined) { if (!isObject(target) || target === holdings) throw new TypeError(); if (unregisterToken !== undefined && !isObject(unregisterToken)) throw TypeError(); const slots = privates(this); const objectInfo = getInfo(target); let cellsForToken; if (unregisterToken) { cellsForToken = slots.cellsForToken.get(unregisterToken); if (!cellsForToken) { cellsForToken = new Set(); slots.cellsForToken.set(unregisterToken, cellsForToken); } } const cell = new FinalizationGroupCell(objectInfo, holdings, cellsForToken); let cellsForTarget = slots.cellsForTarget.get(objectInfo); if (!cellsForTarget) { jobs.registerFinalizationGroup(this, objectInfo); cellsForTarget = new Set(); slots.cellsForTarget.set(objectInfo, cellsForTarget); } cellsForTarget.add(cell); if (cellsForToken) cellsForToken.add(cell); } unregister(unregisterToken) { if (!isObject(unregisterToken)) throw new TypeError(); const slots = privates(this); let removed = false; const cellsForToken = slots.cellsForToken.get(unregisterToken); if (!cellsForToken) return removed; for (const cell of cellsForToken) { unregisterCell(this, cell); removed = true; } return removed; } cleanupSome(cleanupCallback = undefined) { let slots = privates(this); if (slots.isCleanupJobActive) { throw new TypeError(); } if (cleanupCallback === undefined) { cleanupCallback = slots.cleanupCallback; } else if (typeof cleanupCallback != "function") { throw new TypeError(); } const getEmptyCellsContext = { finalized: jobs.getFinalizedInFinalizationGroup(this), cellsForInfo: slots.cellsForTarget, }; if (getEmptyCellsContext.finalized.size == 0) return; const cleanupIteratorContext = { group: this, cells: getEmptyCells(getEmptyCellsContext), }; const iterator = CleanupIterator(cleanupIteratorContext); try { slots.isCleanupJobActive = true; cleanupCallback(iterator); } finally { slots.isCleanupJobActive = false; cleanupIteratorContext.group = undefined; getEmptyCellsContext.finalized = undefined; getEmptyCellsContext.cellsForInfo = undefined; } } } return FinalizationGroup; } //# sourceMappingURL=FinalizationGroup.js.map