import util from 'util'; const promiseDebugging = util.debuglog('promises').enabled; const danglingPromise = new FinalizationRegistry((stack) => { danglingStacks.delete(stack); console.log(stack); }); const danglingStacks = new Set(); const stackCache = new WeakMap(); /** * @template T * @param {TemplateStringsArray} uniqLocation * @param {Promise} promise * @returns {Promise} */ function mustAwait(uniqLocation, promise) { if (!promiseDebugging) return promise; let stack = stackCache.get(uniqLocation); if (!stack) { stack = new Error('dangling promise').stack; stackCache.set(uniqLocation, stack); } try { danglingPromise.register(promise, stack); danglingStacks.add(stack); } catch { return promise; } const proxy = new Proxy(promise, { get(target, prop, receiver) { if (prop === 'then' || prop === 'catch' || prop === 'finally') { const real = Reflect.get(target, prop, receiver); return function () { let recv = this; if (this === proxy) { danglingPromise.unregister(promise); danglingStacks.delete(stack); recv = promise; } return Reflect.apply(real, recv, arguments); }; } else { console.log(new Error('attempted to do something prior to awaiting Promise').stack); } return Reflect.get(target, prop, receiver); } }); return proxy; } process.on('exit', () => { for (const stack of danglingStacks) { console.log(stack); } }) let one = Promise.resolve(1); let tracker = mustAwait`${one}`; let { x } = tracker;