mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-21 20:21:02 +03:00
56 lines
2.5 KiB
JavaScript
56 lines
2.5 KiB
JavaScript
// web-test cli/test-runner/suite-root v1.0 — locate the suite root above a given test path
|
|
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
|
import { existsSync, statSync } from 'fs';
|
|
import { resolve, dirname } from 'path';
|
|
|
|
// Files that MARK a suite root. Both count, not just the config: `webtest.config.mjs` is
|
|
// optional (a single-URL suite may pass --url= instead), and a suite that ships only
|
|
// `_hooks.mjs` must still be found — otherwise its stand preparation is silently skipped,
|
|
// which is worse than any URL error.
|
|
const MARKERS = ['webtest.config.mjs', '_hooks.mjs'];
|
|
|
|
// Files that BOUND the climb. A boundary never selects a root — it only stops the search,
|
|
// so a wrong boundary degrades to "root not found" (= the pre-v1.9 behaviour plus a clear
|
|
// message) and can never produce a wrong root. `package.json` is deliberately absent: it
|
|
// occurs nested and would stop the climb below a legitimate suite root.
|
|
const BOUNDARIES = ['.git', '.v8-project.json'];
|
|
|
|
const isDir = (p) => { try { return statSync(p).isDirectory(); } catch { return false; } };
|
|
|
|
/**
|
|
* Walk up from `startPath` looking for a suite root.
|
|
*
|
|
* @param {string} startPath A test file or directory (absolute or cwd-relative).
|
|
* @param {{cwd?: string}} [opts]
|
|
* @returns {{root: string, marker: string} | null} null when no marker was found within bounds.
|
|
*
|
|
* Stops after examining the first directory that contains `.git` / `.v8-project.json`
|
|
* (that directory IS examined for markers), or — when neither is met — after examining `cwd`.
|
|
* A path outside `cwd` degenerates to the filesystem root; the marker requirement still
|
|
* makes a wrong hit unlikely, and the resolved root is printed in the run banner.
|
|
*/
|
|
export function findSuiteRoot(startPath, { cwd = process.cwd() } = {}) {
|
|
const full = resolve(startPath);
|
|
let dir = isDir(full) ? full : dirname(full);
|
|
const cwdAbs = resolve(cwd);
|
|
|
|
while (true) {
|
|
for (const m of MARKERS) {
|
|
if (existsSync(resolve(dir, m))) return { root: dir, marker: m };
|
|
}
|
|
const atBoundary = BOUNDARIES.some(b => existsSync(resolve(dir, b))) || dir === cwdAbs;
|
|
const parent = dirname(dir);
|
|
if (atBoundary || parent === dir) return null;
|
|
dir = parent;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The directory a path contributes to root resolution — its own dir for a file, itself for
|
|
* a directory. Also the fallback root when no marker is found (pre-v1.9 behaviour).
|
|
*/
|
|
export function startDirOf(testPath) {
|
|
const full = resolve(testPath);
|
|
return isDir(full) ? full : dirname(full);
|
|
}
|