UNPKG

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