MessagesForMacintosh/JS/node_modules/@wry/context/lib/context.esm.js

200 lines
8.0 KiB
JavaScript

// 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;
}()); };
// We store a single global implementation of the Slot class as a permanent
// non-enumerable symbol property of the Array constructor. 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 very high cost for any
// future breaking changes to the Slot class.
var globalKey = "@wry/context:Slot";
var host = Array;
var Slot = host[globalKey] || function () {
var Slot = makeSlotClass();
try {
Object.defineProperty(host, globalKey, {
value: host[globalKey] = Slot,
enumerable: false,
writable: false,
configurable: false,
});
}
finally {
return Slot;
}
}();
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;
}
export { Slot, asyncFromGen, bind, noContext, setTimeoutWithContext as setTimeout, wrapYieldingFiberMethods };
//# sourceMappingURL=context.esm.js.map