117 lines
3.2 KiB
JavaScript
117 lines
3.2 KiB
JavaScript
'use strict';
|
|
|
|
function createContext() {
|
|
let currentInstance;
|
|
let isSingleton = false;
|
|
const checkConflict = (instance) => {
|
|
if (currentInstance && currentInstance !== instance) {
|
|
throw new Error("Context conflict");
|
|
}
|
|
};
|
|
return {
|
|
use: () => {
|
|
if (currentInstance === void 0) {
|
|
throw new Error("Context is not available");
|
|
}
|
|
return currentInstance;
|
|
},
|
|
tryUse: () => {
|
|
return currentInstance;
|
|
},
|
|
set: (instance, replace) => {
|
|
if (!replace) {
|
|
checkConflict(instance);
|
|
}
|
|
currentInstance = instance;
|
|
isSingleton = true;
|
|
},
|
|
unset: () => {
|
|
currentInstance = void 0;
|
|
isSingleton = false;
|
|
},
|
|
call: (instance, callback) => {
|
|
checkConflict(instance);
|
|
currentInstance = instance;
|
|
try {
|
|
return callback();
|
|
} finally {
|
|
if (!isSingleton) {
|
|
currentInstance = void 0;
|
|
}
|
|
}
|
|
},
|
|
async callAsync(instance, callback) {
|
|
currentInstance = instance;
|
|
const onRestore = () => {
|
|
currentInstance = instance;
|
|
};
|
|
const onLeave = () => currentInstance === instance ? onRestore : void 0;
|
|
asyncHandlers.add(onLeave);
|
|
try {
|
|
const r = callback();
|
|
if (!isSingleton) {
|
|
currentInstance = void 0;
|
|
}
|
|
return await r;
|
|
} finally {
|
|
asyncHandlers.delete(onLeave);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
function createNamespace() {
|
|
const contexts = {};
|
|
return {
|
|
get(key) {
|
|
if (!contexts[key]) {
|
|
contexts[key] = createContext();
|
|
}
|
|
contexts[key];
|
|
return contexts[key];
|
|
}
|
|
};
|
|
}
|
|
const _globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {};
|
|
const globalKey = "__unctx__";
|
|
const defaultNamespace = _globalThis[globalKey] || (_globalThis[globalKey] = createNamespace());
|
|
const getContext = (key) => defaultNamespace.get(key);
|
|
const useContext = (key) => getContext(key).use;
|
|
const asyncHandlersKey = "__unctx_async_handlers__";
|
|
const asyncHandlers = _globalThis[asyncHandlersKey] || (_globalThis[asyncHandlersKey] = /* @__PURE__ */ new Set());
|
|
function executeAsync(function_) {
|
|
const restores = [];
|
|
for (const leaveHandler of asyncHandlers) {
|
|
const restore2 = leaveHandler();
|
|
if (restore2) {
|
|
restores.push(restore2);
|
|
}
|
|
}
|
|
const restore = () => {
|
|
for (const restore2 of restores) {
|
|
restore2();
|
|
}
|
|
};
|
|
let awaitable = function_();
|
|
if (awaitable && typeof awaitable === "object" && "catch" in awaitable) {
|
|
awaitable = awaitable.catch((error) => {
|
|
restore();
|
|
throw error;
|
|
});
|
|
}
|
|
return [awaitable, restore];
|
|
}
|
|
function withAsyncContext(function_, transformed) {
|
|
if (!transformed) {
|
|
console.warn("[unctx] `withAsyncContext` needs transformation for async context support in", function_, "\n", function_.toString());
|
|
}
|
|
return function_;
|
|
}
|
|
|
|
exports.createContext = createContext;
|
|
exports.createNamespace = createNamespace;
|
|
exports.defaultNamespace = defaultNamespace;
|
|
exports.executeAsync = executeAsync;
|
|
exports.getContext = getContext;
|
|
exports.useContext = useContext;
|
|
exports.withAsyncContext = withAsyncContext;
|