'use strict'; // This currentContext variable will only be used if the makeSlotClass // function is called, which happens only if this is the first copy of the // @wry/context package to be imported. var currentContext = null; // This unique internal object is used to denote the absence of a value // for a given Slot, and is never exposed to outside code. var MISSING_VALUE = {}; var idCounter = 1; // Although we can't do anything about the cost of duplicated code from // accidentally bundling multiple copies of the @wry/context package, we can // avoid creating the Slot class more than once using makeSlotClass. var makeSlotClass = function () { return /** @class */ (function () { function Slot() { // If you have a Slot object, you can find out its slot.id, but you cannot // guess the slot.id of a Slot you don't have access to, thanks to the // randomized suffix. this.id = [ "slot", idCounter++, Date.now(), Math.random().toString(36).slice(2), ].join(":"); } Slot.prototype.hasValue = function () { for (var context_1 = currentContext; context_1; context_1 = context_1.parent) { // We use the Slot object iself as a key to its value, which means the // value cannot be obtained without a reference to the Slot object. if (this.id in context_1.slots) { var value = context_1.slots[this.id]; if (value === MISSING_VALUE) break; if (context_1 !== currentContext) { // Cache the value in currentContext.slots so the next lookup will // be faster. This caching is safe because the tree of contexts and // the values of the slots are logically immutable. currentContext.slots[this.id] = value; } return true; } } if (currentContext) { // If a value was not found for this Slot, it's never going to be found // no matter how many times we look it up, so we might as well cache // the absence of the value, too. currentContext.slots[this.id] = MISSING_VALUE; } return false; }; Slot.prototype.getValue = function () { if (this.hasValue()) { return currentContext.slots[this.id]; } }; Slot.prototype.withValue = function (value, callback, // Given the prevalence of arrow functions, specifying arguments is likely // to be much more common than specifying `this`, hence this ordering: args, thisArg) { var _a; var slots = (_a = { __proto__: null }, _a[this.id] = value, _a); var parent = currentContext; currentContext = { parent: parent, slots: slots }; try { // Function.prototype.apply allows the arguments array argument to be // omitted or undefined, so args! is fine here. return callback.apply(thisArg, args); } finally { currentContext = parent; } }; // Capture the current context and wrap a callback function so that it // reestablishes the captured context when called. Slot.bind = function (callback) { var context = currentContext; return function () { var saved = currentContext; try { currentContext = context; return callback.apply(this, arguments); } finally { currentContext = saved; } }; }; // Immediately run a callback function without any captured context. Slot.noContext = function (callback, // Given the prevalence of arrow functions, specifying arguments is likely // to be much more common than specifying `this`, hence this ordering: args, thisArg) { if (currentContext) { var saved = currentContext; try { currentContext = null; // Function.prototype.apply allows the arguments array argument to be // omitted or undefined, so args! is fine here. return callback.apply(thisArg, args); } finally { currentContext = saved; } } else { return callback.apply(thisArg, args); } }; return Slot; }()); }; function maybe(fn) { try { return fn(); } catch (ignored) { } } // We store a single global implementation of the Slot class as a permanent // non-enumerable property of the globalThis object. This obfuscation does // nothing to prevent access to the Slot class, but at least it ensures the // implementation (i.e. currentContext) cannot be tampered with, and all copies // of the @wry/context package (hopefully just one) will share the same Slot // implementation. Since the first copy of the @wry/context package to be // imported wins, this technique imposes a steep cost for any future breaking // changes to the Slot class. var globalKey = "@wry/context:Slot"; var host = // Prefer globalThis when available. // https://github.com/benjamn/wryware/issues/347 maybe(function () { return globalThis; }) || // Fall back to global, which works in Node.js and may be converted by some // bundlers to the appropriate identifier (window, self, ...) depending on the // bundling target. https://github.com/endojs/endo/issues/576#issuecomment-1178515224 maybe(function () { return global; }) || // Otherwise, use a dummy host that's local to this module. We used to fall // back to using the Array constructor as a namespace, but that was flagged in // https://github.com/benjamn/wryware/issues/347, and can be avoided. Object.create(null); // Whichever globalHost we're using, make TypeScript happy about the additional // globalKey property. var globalHost = host; var Slot = globalHost[globalKey] || // Earlier versions of this package stored the globalKey property on the Array // constructor, so we check there as well, to prevent Slot class duplication. Array[globalKey] || (function (Slot) { try { Object.defineProperty(globalHost, globalKey, { value: Slot, enumerable: false, writable: false, // When it was possible for globalHost to be the Array constructor (a // legacy Slot dedup strategy), it was important for the property to be // configurable:true so it could be deleted. That does not seem to be as // important when globalHost is the global object, but I don't want to // cause similar problems again, and configurable:true seems safest. // https://github.com/endojs/endo/issues/576#issuecomment-1178274008 configurable: true }); } finally { return Slot; } })(makeSlotClass()); var bind = Slot.bind, noContext = Slot.noContext; function setTimeoutWithContext(callback, delay) { return setTimeout(bind(callback), delay); } // Turn any generator function into an async function (using yield instead // of await), with context automatically preserved across yields. function asyncFromGen(genFn) { return function () { var gen = genFn.apply(this, arguments); var boundNext = bind(gen.next); var boundThrow = bind(gen.throw); return new Promise(function (resolve, reject) { function invoke(method, argument) { try { var result = method.call(gen, argument); } catch (error) { return reject(error); } var next = result.done ? resolve : invokeNext; if (isPromiseLike(result.value)) { result.value.then(next, result.done ? reject : invokeThrow); } else { next(result.value); } } var invokeNext = function (value) { return invoke(boundNext, value); }; var invokeThrow = function (error) { return invoke(boundThrow, error); }; invokeNext(); }); }; } function isPromiseLike(value) { return value && typeof value.then === "function"; } // If you use the fibers npm package to implement coroutines in Node.js, // you should call this function at least once to ensure context management // remains coherent across any yields. var wrappedFibers = []; function wrapYieldingFiberMethods(Fiber) { // There can be only one implementation of Fiber per process, so this array // should never grow longer than one element. if (wrappedFibers.indexOf(Fiber) < 0) { var wrap = function (obj, method) { var fn = obj[method]; obj[method] = function () { return noContext(fn, arguments, this); }; }; // These methods can yield, according to // https://github.com/laverdet/node-fibers/blob/ddebed9b8ae3883e57f822e2108e6943e5c8d2a8/fibers.js#L97-L100 wrap(Fiber, "yield"); wrap(Fiber.prototype, "run"); wrap(Fiber.prototype, "throwInto"); wrappedFibers.push(Fiber); } return Fiber; } exports.Slot = Slot; exports.asyncFromGen = asyncFromGen; exports.bind = bind; exports.noContext = noContext; exports.setTimeout = setTimeoutWithContext; exports.wrapYieldingFiberMethods = wrapYieldingFiberMethods; //# sourceMappingURL=bundle.cjs.map