60 lines
1.5 KiB
JavaScript
60 lines
1.5 KiB
JavaScript
|
|
"use strict";
|
||
|
|
|
||
|
|
const path = require("path");
|
||
|
|
|
||
|
|
function existsSync(p) {
|
||
|
|
try {
|
||
|
|
// eslint-disable-next-line n/no-sync
|
||
|
|
return require("fs").existsSync(p);
|
||
|
|
} catch (_) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function isDirectorySync(p) {
|
||
|
|
try {
|
||
|
|
// eslint-disable-next-line n/no-sync
|
||
|
|
return require("fs").statSync(p).isDirectory();
|
||
|
|
} catch (_) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function findRoot(startPath) {
|
||
|
|
if (!startPath || typeof startPath !== "string") return null;
|
||
|
|
|
||
|
|
// Handle URIs (atom://...) and file:// style strings conservatively.
|
||
|
|
if (startPath.startsWith("atom://")) return null;
|
||
|
|
let current = startPath;
|
||
|
|
if (current.startsWith("file://")) current = current.replace(/^file:\/\//, "");
|
||
|
|
|
||
|
|
// If it's a file, walk from its directory.
|
||
|
|
try {
|
||
|
|
if (existsSync(current) && !current.endsWith(path.sep)) {
|
||
|
|
const stat = require("fs").statSync(current);
|
||
|
|
if (stat && stat.isFile()) current = path.dirname(current);
|
||
|
|
}
|
||
|
|
} catch (_) {
|
||
|
|
current = path.dirname(current);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Prefer `find-root` if available (it is in the SDK dependency tree).
|
||
|
|
try {
|
||
|
|
const findRootPkg = require("find-root");
|
||
|
|
return findRootPkg(current);
|
||
|
|
} catch (_) {
|
||
|
|
// Fall back to a simple package.json search.
|
||
|
|
}
|
||
|
|
|
||
|
|
let dir = current;
|
||
|
|
while (dir && dir !== path.dirname(dir)) {
|
||
|
|
if (existsSync(path.join(dir, "package.json"))) return dir;
|
||
|
|
// Jibo SDK projects also commonly have a top-level `src/`.
|
||
|
|
if (isDirectorySync(path.join(dir, "src"))) return dir;
|
||
|
|
dir = path.dirname(dir);
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = { findRoot };
|