56 lines
1.4 KiB
TypeScript
56 lines
1.4 KiB
TypeScript
import { AsyncLocalStorage } from "node:async_hooks";
|
|
import type { ComposeSpecification } from "../schema/docker.d";
|
|
import { getProject, throwWhen } from "./shared";
|
|
import { readCompose, resolveComposeFile } from "./yaml";
|
|
|
|
type AppContext = {
|
|
project: string;
|
|
cwd: string;
|
|
path(): Promise<string | undefined>;
|
|
compose(): Promise<ComposeSpecification>;
|
|
};
|
|
|
|
const appContext = new AsyncLocalStorage<AppContext>();
|
|
|
|
export function provideContext<T>(fn: () => T): T {
|
|
const cwd = process.cwd();
|
|
const path = createCachedGetter("composeFile", () => resolveComposeFile(cwd));
|
|
return appContext.run(
|
|
{
|
|
project: getProject(),
|
|
cwd,
|
|
path,
|
|
compose: createCachedGetter("compose", () =>
|
|
path()
|
|
.then(
|
|
throwWhen(
|
|
(path): path is undefined => path === undefined,
|
|
"Compose file cannot be found",
|
|
),
|
|
)
|
|
.then(readCompose),
|
|
),
|
|
},
|
|
fn,
|
|
);
|
|
}
|
|
|
|
export function ctx() {
|
|
const store = appContext.getStore();
|
|
if (!store) throw new Error("Not in context!");
|
|
return store;
|
|
}
|
|
|
|
const cache: Record<string, unknown> = {};
|
|
export function createCachedGetter<T>(
|
|
key: string,
|
|
fn: () => Promise<T>,
|
|
): () => Promise<T> {
|
|
return async () => {
|
|
if (key in cache) return cache[key] as T;
|
|
const result = await fn();
|
|
cache[key] = result;
|
|
return result;
|
|
};
|
|
}
|