81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
import { dirname, isAbsolute, resolve } from "node:path";
|
|
|
|
/** Root directory of the framework package. */
|
|
export const frameworkRoot = resolve(import.meta.dir, "..");
|
|
|
|
const INTERNAL_MARKERS = ["/bun:", "node:internal", "node_modules"];
|
|
|
|
export const frameworkSources = [
|
|
"adapters",
|
|
"contracts",
|
|
"core",
|
|
"decorators",
|
|
"integrations",
|
|
"orm",
|
|
"views",
|
|
].map((folder) => resolve(frameworkRoot, folder));
|
|
|
|
/** Extracts the file path of a stack frame. */
|
|
function frameFile(frame: string): string | undefined {
|
|
let text = frame.trim();
|
|
text = text.replace(/^at\s+/, "");
|
|
|
|
const parenthesised = /\((.*)\)$/.exec(text);
|
|
if (parenthesised) text = parenthesised[1] as string;
|
|
|
|
text = text.replace(/:\d+(?::\d+)?$/, "");
|
|
if (text.length === 0) return undefined;
|
|
if (text.startsWith("file://")) return text.slice(7);
|
|
if (!text.startsWith("/")) return undefined;
|
|
return text;
|
|
}
|
|
|
|
/** Returns the file that called the caller of this function. */
|
|
export function callerFile(
|
|
skipDirs: string[] = frameworkSources,
|
|
skip = 0,
|
|
): string | undefined {
|
|
const stack = new Error("caller").stack;
|
|
if (!stack) return undefined;
|
|
const frames = stack.split("\n").slice(1);
|
|
let seen = 0;
|
|
for (const frame of frames) {
|
|
const file = frameFile(frame);
|
|
if (!file) continue;
|
|
if (INTERNAL_MARKERS.some((marker) => file.startsWith(marker))) continue;
|
|
if (skipDirs.some((dir) => file.startsWith(dir))) continue;
|
|
if (seen < skip) {
|
|
seen += 1;
|
|
continue;
|
|
}
|
|
return file;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
/** Directory of the file that called the caller of this function. */
|
|
export function callerDirectory(
|
|
skipDirs: string[] = frameworkSources,
|
|
skip = 0,
|
|
): string | undefined {
|
|
const file = callerFile(skipDirs, skip + 1);
|
|
return file ? dirname(file) : undefined;
|
|
}
|
|
|
|
/** Resolves a path relative to the project root. */
|
|
export function fromRoot(root: string, path: string): string {
|
|
return isAbsolute(path) ? path : resolve(root, path);
|
|
}
|
|
|
|
/** Normalises a path to posix separators, relative to the project root. */
|
|
export function relativeTo(root: string, path: string): string {
|
|
const resolvedRoot = resolve(root);
|
|
const resolvedPath = resolve(path);
|
|
if (!resolvedPath.startsWith(resolvedRoot)) return resolvedPath;
|
|
return resolvedPath.slice(resolvedRoot.length + 1).replace(/\\/g, "/");
|
|
}
|
|
|
|
/** Removes the extension of a path. */
|
|
export function stripExtension(path: string): string {
|
|
return path.replace(/\.[^./]+$/, "");
|
|
}
|