context
Version:
Lightweight context propagation for JavaScript and TypeScript. Create a scoped storage object, run code inside it, and read the active value anywhere down the call stack - without depending on React.
64 lines (62 loc) • 1.73 kB
JavaScript
let vest_utils = require("vest-utils");
//#region src/context.ts
const USEX_DEFAULT_ERROR_MESSAGE = "Not inside of a running context.";
const EMPTY_CONTEXT = Symbol();
/**
* Base context interface.
*/
function createContext(defaultContextValue) {
let contextValue = EMPTY_CONTEXT;
return {
run,
use,
useX
};
function use() {
return isInsideContext() ? contextValue : defaultContextValue;
}
function useX(errorMessage) {
(0, vest_utils.invariant)(isInsideContext(), (0, vest_utils.defaultTo)(errorMessage, USEX_DEFAULT_ERROR_MESSAGE));
return contextValue;
}
function run(value, cb) {
const parentContext = isInsideContext() ? use() : EMPTY_CONTEXT;
contextValue = value;
const res = cb();
contextValue = parentContext;
return res;
}
function isInsideContext() {
return contextValue !== EMPTY_CONTEXT;
}
}
/**
* Cascading context - another implementation of context, that assumes the context value is an object.
* When nesting context runs, the the values of the current layer merges with the layers above it.
*/
function createCascade(init) {
const ctx = createContext();
return {
bind,
run,
use: ctx.use,
useX: ctx.useX
};
function run(value, fn) {
const parentContext = ctx.use();
const initResult = (0, vest_utils.dynamicValue)(init, value, parentContext) ?? value;
const out = (0, vest_utils.assign)({}, parentContext ? parentContext : {}, initResult);
return ctx.run(Object.freeze(out), fn);
}
function bind(value, fn) {
return function(...runTimeArgs) {
return run(value, function() {
return fn(...runTimeArgs);
});
};
}
}
//#endregion
exports.createCascade = createCascade;
exports.createContext = createContext;
//# sourceMappingURL=context.cjs.map