'use strict'; const v8Util = process.electronBinding('v8_util'); class CallbacksRegistry { constructor() { this.nextId = 0; this.callbacks = {}; } add(callback) { // The callback is already added. let id = v8Util.getHiddenValue(callback, 'callbackId'); if (id != null) return id; id = this.nextId += 1; // Capture the location of the function and put it in the ID string, // so that release errors can be tracked down easily. const regexp = /at (.*)/gi; const stackString = (new Error()).stack; let filenameAndLine; let match; while ((match = regexp.exec(stackString)) !== null) { const location = match[1]; if (location.includes('(native)')) continue; if (location.includes('()')) continue; if (location.includes('electron.asar')) continue; const ref = /([^/^)]*)\)?$/gi.exec(location); filenameAndLine = ref[1]; break; } this.callbacks[id] = callback; v8Util.setHiddenValue(callback, 'callbackId', id); v8Util.setHiddenValue(callback, 'location', filenameAndLine); return id; } get(id) { return this.callbacks[id] || function () { }; } apply(id, ...args) { return this.get(id).apply(global, ...args); } remove(id) { const callback = this.callbacks[id]; if (callback) { v8Util.deleteHiddenValue(callback, 'callbackId'); delete this.callbacks[id]; } } } module.exports = CallbacksRegistry;