66 lines
1.7 KiB
TypeScript
66 lines
1.7 KiB
TypeScript
import { readdir, stat } from "node:fs/promises";
|
|
import { join, dirname } from "node:path";
|
|
import { createRequire } from "node:module";
|
|
|
|
async function find(path: string, name: string): Promise<string | null> {
|
|
for (const file of await readdir(path, { withFileTypes: true })) {
|
|
if (file.isDirectory()) {
|
|
const found = await find(join(file.parentPath, file.name), name);
|
|
if (found) return found;
|
|
} else if (file.isFile()) {
|
|
if (file.name === name) return join(file.parentPath, file.name);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async function isFile(path: string): Promise<boolean> {
|
|
try {
|
|
const st = await stat(path);
|
|
return st.isFile();
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function getPackageJsonDir(path: string): Promise<string | null> {
|
|
if (await isFile(join(path, "package.json"))) return path;
|
|
const next = dirname(path);
|
|
if (next === path) return null;
|
|
return getPackageJsonDir(next);
|
|
}
|
|
|
|
export async function findNative(
|
|
module: string,
|
|
native: string
|
|
): Promise<string> {
|
|
const path = await getPackageJsonDir(
|
|
createRequire(import.meta.url).resolve(module)
|
|
);
|
|
if (!path) throw new Error(`Cannot find module directory for ${module}`);
|
|
const file = await find(path, native);
|
|
if (!file)
|
|
throw new Error(
|
|
`Cannot find native ${native} of package ${module} in ${path}`
|
|
);
|
|
return file;
|
|
}
|
|
|
|
export async function tryFindNative(
|
|
module: string,
|
|
native: string
|
|
): Promise<string | null> {
|
|
try {
|
|
return await findNative(module, native);
|
|
} catch (e) {
|
|
console.warn(e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function findNatives(): Promise<typeof natives> {
|
|
return {
|
|
sqlite: await tryFindNative("better-sqlite3", "better_sqlite3.node"),
|
|
};
|
|
}
|