init project
This commit is contained in:
+162
@@ -0,0 +1,162 @@
|
||||
// src/jsx/context.ts
|
||||
import { raw } from "../helper/html/index.js";
|
||||
import { JSXFragmentNode } from "./base.js";
|
||||
import { DOM_RENDERER } from "./constants.js";
|
||||
import { createContextProviderFunction } from "./dom/context.js";
|
||||
var globalContexts = [];
|
||||
var alsProbed = false;
|
||||
var asyncLocalStorage;
|
||||
var fallbackStore;
|
||||
var fallbackRendersInFlight = 0;
|
||||
var warnedFallbackDefault = false;
|
||||
var loadAsyncLocalStorage = () => {
|
||||
if (alsProbed) {
|
||||
return asyncLocalStorage;
|
||||
}
|
||||
alsProbed = true;
|
||||
const global = globalThis;
|
||||
let AsyncLocalStorage;
|
||||
for (const probe of [
|
||||
// Node.js >= 20.16, Deno, Bun, Cloudflare Workers (nodejs_compat). Property
|
||||
// access only, so bundlers don't statically resolve `node:async_hooks`.
|
||||
() => global.process?.getBuiltinModule?.("node:async_hooks")?.AsyncLocalStorage,
|
||||
// Node.js < 20.16 has no `process.getBuiltinModule`, but a CJS entrypoint
|
||||
// exposes the main module's `require` here.
|
||||
() => global.process?.mainModule?.require?.("node:async_hooks")?.AsyncLocalStorage
|
||||
]) {
|
||||
try {
|
||||
AsyncLocalStorage = probe();
|
||||
} catch {
|
||||
}
|
||||
if (AsyncLocalStorage) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (AsyncLocalStorage) {
|
||||
asyncLocalStorage = new AsyncLocalStorage();
|
||||
}
|
||||
return asyncLocalStorage;
|
||||
};
|
||||
var getCurrentStore = () => {
|
||||
return loadAsyncLocalStorage()?.getStore() || fallbackStore;
|
||||
};
|
||||
var warnIfStorelessAccess = () => {
|
||||
if (fallbackRendersInFlight > 0 && !warnedFallbackDefault) {
|
||||
warnedFallbackDefault = true;
|
||||
console.warn(
|
||||
"hono/jsx: AsyncLocalStorage is unavailable in this runtime, so useContext() after an await in an async component falls back to the context default value during server-side rendering. To get provided values across await boundaries, use a runtime with AsyncLocalStorage (Node.js >= 20.16, Deno, Bun, or Cloudflare Workers with the nodejs_compat flag)."
|
||||
);
|
||||
}
|
||||
};
|
||||
var getContextValuesIn = (store, context) => {
|
||||
if (!store) {
|
||||
warnIfStorelessAccess();
|
||||
return context.values;
|
||||
}
|
||||
let values = store.get(context);
|
||||
if (!values) {
|
||||
values = [context.values[0]];
|
||||
store.set(context, values);
|
||||
}
|
||||
return values;
|
||||
};
|
||||
var readContextValueIn = (store, context) => {
|
||||
if (!store) {
|
||||
warnIfStorelessAccess();
|
||||
return context.values.at(-1);
|
||||
}
|
||||
const values = store.get(context);
|
||||
return values?.length ? values.at(-1) : context.values[0];
|
||||
};
|
||||
var captureContextValues = (store) => (store ? globalContexts.filter((c) => store.has(c)) : globalContexts).map((c) => [
|
||||
c,
|
||||
readContextValueIn(store, c)
|
||||
]);
|
||||
var resumeWithContextValues = (callback, store, contexts) => runWithRenderContext(() => {
|
||||
const currentStore = getCurrentStore();
|
||||
const valuesPerContext = contexts.map(([context, value]) => {
|
||||
const values = getContextValuesIn(currentStore, context);
|
||||
values.push(value);
|
||||
return values;
|
||||
});
|
||||
const popContextValues = () => {
|
||||
valuesPerContext.forEach((values) => {
|
||||
values.pop();
|
||||
});
|
||||
};
|
||||
try {
|
||||
const result = callback();
|
||||
if (result instanceof Promise) {
|
||||
return result.finally(popContextValues);
|
||||
}
|
||||
popContextValues();
|
||||
return result;
|
||||
} catch (e) {
|
||||
popContextValues();
|
||||
throw e;
|
||||
}
|
||||
}, store);
|
||||
var runWithRenderContext = (callback, resumeStore) => {
|
||||
if (getCurrentStore()) {
|
||||
return callback();
|
||||
}
|
||||
const store = resumeStore ?? /* @__PURE__ */ new WeakMap();
|
||||
const storage = loadAsyncLocalStorage();
|
||||
if (storage) {
|
||||
return storage.run(store, callback);
|
||||
}
|
||||
fallbackStore = store;
|
||||
let result;
|
||||
try {
|
||||
result = callback();
|
||||
} finally {
|
||||
fallbackStore = void 0;
|
||||
}
|
||||
if (!warnedFallbackDefault && result instanceof Promise) {
|
||||
fallbackRendersInFlight++;
|
||||
result = result.finally(() => {
|
||||
fallbackRendersInFlight--;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
var captureRenderContext = () => {
|
||||
const store = getCurrentStore();
|
||||
const contexts = captureContextValues(store);
|
||||
return (callback) => resumeWithContextValues(callback, store, contexts);
|
||||
};
|
||||
var createContext = (defaultValue) => {
|
||||
const values = [defaultValue];
|
||||
const context = ((props) => {
|
||||
const contextValues = getContextValuesIn(getCurrentStore(), context);
|
||||
contextValues.push(props.value);
|
||||
let string;
|
||||
try {
|
||||
string = props.children ? (Array.isArray(props.children) ? new JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
|
||||
} catch (e) {
|
||||
contextValues.pop();
|
||||
throw e;
|
||||
}
|
||||
if (string instanceof Promise) {
|
||||
return string.finally(() => contextValues.pop()).then((resString) => raw(resString, resString.callbacks));
|
||||
} else {
|
||||
contextValues.pop();
|
||||
return raw(string);
|
||||
}
|
||||
});
|
||||
context.values = values;
|
||||
context.Provider = context;
|
||||
context[DOM_RENDERER] = createContextProviderFunction(values);
|
||||
globalContexts.push(context);
|
||||
return context;
|
||||
};
|
||||
var useContext = (context) => {
|
||||
return readContextValueIn(getCurrentStore(), context);
|
||||
};
|
||||
export {
|
||||
captureRenderContext,
|
||||
createContext,
|
||||
globalContexts,
|
||||
runWithRenderContext,
|
||||
useContext
|
||||
};
|
||||
Reference in New Issue
Block a user