mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 17:53:39 +00:00
93 lines
4.1 KiB
JavaScript
93 lines
4.1 KiB
JavaScript
import { posix } from "node:path";
|
|
|
|
/**
|
|
* @typedef {"docs" | "source" | "package" | "ui" | "extension" | "app" | "rootTest" | "testFixture" | "rootTooling" | "rootGlobal" | "legacyRootAsset" | "unknown"} ChangedPathSurface
|
|
*/
|
|
|
|
/** @type {readonly (readonly [ChangedPathSurface, RegExp])[]} */
|
|
const SURFACE_PATTERNS = [
|
|
["docs", /^(?:docs\/|README\.md$|AGENTS\.md$|.*\.mdx?$)/u],
|
|
[
|
|
"rootGlobal",
|
|
/^(?:package\.json$|pnpm-lock\.yaml$|pnpm-workspace\.yaml$|tsdown\.config\.ts$|vitest\.config\.ts$)/u,
|
|
],
|
|
["extension", /^extensions\/[^/]+(?:\/|$)/u],
|
|
["source", /^src\//u],
|
|
["package", /^packages\//u],
|
|
["ui", /^(?:ui\/|tsconfig\.ui\.json$)/u],
|
|
["app", /^(?:apps\/|Swabble\/|appcast(?:-(?:arm64|x86_64))?\.xml$)/u],
|
|
["rootTest", /^test\//u],
|
|
["testFixture", /^test-fixtures\//u],
|
|
// These hidden helpers own maintainer reports and release artifact validation.
|
|
// Match the reviewed leaf exactly so unreviewed skill executables still fail safe.
|
|
[
|
|
"rootTooling",
|
|
/^\.agents\/skills\/(?:openclaw-pr-maintainer\/scripts\/github-activity\.sh|openclaw-changelog-update\/scripts\/verify-release-notes\.mjs)$/u,
|
|
],
|
|
[
|
|
"rootTooling",
|
|
/^(?:scripts\/|test\/vitest\/|\.github\/|\.vscode\/|config\/|deploy\/|git-hooks\/|Dockerfile\.sandbox(?:-(?:browser|common))?$|Makefile$|docker-setup\.sh$|setup-podman\.sh$|openclaw\.podman\.env$|skills\/pyproject\.toml$|vitest(?:\..+)?\.config\.ts$|tsconfig.*\.json$|\.dockerignore$|\.gitignore$|\.jscpd\.json$|\.npmignore$|\.pre-commit-config\.yaml$|\.swiftformat$|\.swiftlint\.yml$|\.oxlint.*|\.oxfmt.*)/u,
|
|
],
|
|
["legacyRootAsset", /^assets\//u],
|
|
];
|
|
const CHANGED_LANE_TEST_PATH_RE =
|
|
/(?:^|\/)(?:test|__tests__)\/|(?:\.|\/)(?:test|spec|suite|e2e|browser\.test)\.[cm]?[jt]sx?$|(?:^|\/)[^/]+\.test-(?:helpers|support)\.[cm]?[jt]sx?$/u;
|
|
const TEST_ONLY_PATH_RE =
|
|
/(^test\/|\/test\/|\/tests\/|(?:^|\/)[^/]+\.(?:test|spec|suite|test-utils|test-(?:helpers|support|harness)|e2e-harness)\.[cm]?[jt]sx?$)/u;
|
|
const NATIVE_ONLY_PATH_RE =
|
|
/^(?:apps\/android\/|apps\/ios\/|apps\/macos\/|apps\/macos-mlx-tts\/|apps\/shared\/|apps\/swabble\/|Swabble\/|appcast(?:-(?:arm64|x86_64))?\.xml$)/u;
|
|
const ROOT_TEST_SOURCE_PATH_RE = /^test\/(?!fixtures\/).*\.[cm]?tsx?$/u;
|
|
|
|
/**
|
|
* Normalizes a changed file path into repo-relative POSIX form.
|
|
* @param {unknown} inputPath
|
|
* @param {NodeJS.Platform} [platform]
|
|
* @returns {string}
|
|
*/
|
|
export function normalizeChangedPath(inputPath, platform = process.platform) {
|
|
const path = (typeof inputPath === "string" ? inputPath : "").trim();
|
|
return (platform === "win32" ? path.replaceAll("\\", "/") : path).replace(/^\.\/+/u, "");
|
|
}
|
|
|
|
/**
|
|
* Returns shared path facts without imposing a caller's lane-selection policy.
|
|
* @param {unknown} inputPath
|
|
* @returns {{ path: string; surface: ChangedPathSurface; isChangedLaneTest: boolean; isRootTestSource: boolean; isTestOnly: boolean; isNativeOnly: boolean }}
|
|
*/
|
|
export function getChangedPathFacts(inputPath) {
|
|
const path = typeof inputPath === "string" ? inputPath : "";
|
|
const surface = SURFACE_PATTERNS.find(([, pattern]) => pattern.test(path))?.[0] ?? "unknown";
|
|
|
|
return {
|
|
path,
|
|
surface,
|
|
isChangedLaneTest: CHANGED_LANE_TEST_PATH_RE.test(path),
|
|
isRootTestSource: ROOT_TEST_SOURCE_PATH_RE.test(path),
|
|
isTestOnly: TEST_ONLY_PATH_RE.test(path),
|
|
isNativeOnly: NATIVE_ONLY_PATH_RE.test(path),
|
|
};
|
|
}
|
|
|
|
/** @param {string} arg */
|
|
export function isTestFileTarget(arg) {
|
|
return /\.(?:test|spec)\.[cm]?[jt]sx?$/u.test(arg);
|
|
}
|
|
|
|
/** @param {string} arg */
|
|
export function isTestSupportFileTarget(arg) {
|
|
if (/(?:^|\/)(?:test-helpers|test-support)(?:\/|$)/u.test(arg)) {
|
|
return true;
|
|
}
|
|
const basename = posix.basename(arg).replace(/\.[cm]?[jt]sx?$/u, "");
|
|
return /(?:^|[._-])(?:suite|test-(?:helpers|support))(?:[._-]|$)/u.test(basename);
|
|
}
|
|
|
|
// Artifact and Docker gates retain narrower target-ownership rules than the isTestOnly fact.
|
|
/** @param {string} changedPath */
|
|
export function isTestOnlyPath(changedPath) {
|
|
return (
|
|
isTestFileTarget(changedPath) ||
|
|
isTestSupportFileTarget(changedPath) ||
|
|
changedPath.startsWith("test/")
|
|
);
|
|
}
|