mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-03 03:03:24 -04:00
refactor(shared): dedupe requirements evaluation
This commit is contained in:
63
src/shared/requirements.test.ts
Normal file
63
src/shared/requirements.test.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildConfigChecks,
|
||||
resolveMissingAnyBins,
|
||||
resolveMissingBins,
|
||||
resolveMissingEnv,
|
||||
resolveMissingOs,
|
||||
} from "./requirements.js";
|
||||
|
||||
describe("requirements helpers", () => {
|
||||
it("resolveMissingBins respects local+remote", () => {
|
||||
expect(
|
||||
resolveMissingBins({
|
||||
required: ["a", "b", "c"],
|
||||
hasLocalBin: (bin) => bin === "a",
|
||||
hasRemoteBin: (bin) => bin === "b",
|
||||
}),
|
||||
).toEqual(["c"]);
|
||||
});
|
||||
|
||||
it("resolveMissingAnyBins requires at least one", () => {
|
||||
expect(
|
||||
resolveMissingAnyBins({
|
||||
required: ["a", "b"],
|
||||
hasLocalBin: () => false,
|
||||
hasRemoteAnyBin: () => false,
|
||||
}),
|
||||
).toEqual(["a", "b"]);
|
||||
expect(
|
||||
resolveMissingAnyBins({
|
||||
required: ["a", "b"],
|
||||
hasLocalBin: (bin) => bin === "b",
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("resolveMissingOs allows remote platform", () => {
|
||||
expect(
|
||||
resolveMissingOs({
|
||||
required: ["darwin"],
|
||||
localPlatform: "linux",
|
||||
remotePlatforms: ["darwin"],
|
||||
}),
|
||||
).toEqual([]);
|
||||
expect(resolveMissingOs({ required: ["darwin"], localPlatform: "linux" })).toEqual(["darwin"]);
|
||||
});
|
||||
|
||||
it("resolveMissingEnv uses predicate", () => {
|
||||
expect(
|
||||
resolveMissingEnv({ required: ["A", "B"], isSatisfied: (name) => name === "B" }),
|
||||
).toEqual(["A"]);
|
||||
});
|
||||
|
||||
it("buildConfigChecks includes value+status", () => {
|
||||
expect(
|
||||
buildConfigChecks({
|
||||
required: ["a.b"],
|
||||
resolveValue: (p) => (p === "a.b" ? 1 : null),
|
||||
isSatisfied: (p) => p === "a.b",
|
||||
}),
|
||||
).toEqual([{ path: "a.b", value: 1, satisfied: true }]);
|
||||
});
|
||||
});
|
||||
90
src/shared/requirements.ts
Normal file
90
src/shared/requirements.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
export type Requirements = {
|
||||
bins: string[];
|
||||
anyBins: string[];
|
||||
env: string[];
|
||||
config: string[];
|
||||
os: string[];
|
||||
};
|
||||
|
||||
export type RequirementConfigCheck = {
|
||||
path: string;
|
||||
value: unknown;
|
||||
satisfied: boolean;
|
||||
};
|
||||
|
||||
export function resolveMissingBins(params: {
|
||||
required: string[];
|
||||
hasLocalBin: (bin: string) => boolean;
|
||||
hasRemoteBin?: (bin: string) => boolean;
|
||||
}): string[] {
|
||||
const remote = params.hasRemoteBin;
|
||||
return params.required.filter((bin) => {
|
||||
if (params.hasLocalBin(bin)) {
|
||||
return false;
|
||||
}
|
||||
if (remote?.(bin)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveMissingAnyBins(params: {
|
||||
required: string[];
|
||||
hasLocalBin: (bin: string) => boolean;
|
||||
hasRemoteAnyBin?: (bins: string[]) => boolean;
|
||||
}): string[] {
|
||||
if (params.required.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (params.required.some((bin) => params.hasLocalBin(bin))) {
|
||||
return [];
|
||||
}
|
||||
if (params.hasRemoteAnyBin?.(params.required)) {
|
||||
return [];
|
||||
}
|
||||
return params.required;
|
||||
}
|
||||
|
||||
export function resolveMissingOs(params: {
|
||||
required: string[];
|
||||
localPlatform: string;
|
||||
remotePlatforms?: string[];
|
||||
}): string[] {
|
||||
if (params.required.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (params.required.includes(params.localPlatform)) {
|
||||
return [];
|
||||
}
|
||||
if (params.remotePlatforms?.some((platform) => params.required.includes(platform))) {
|
||||
return [];
|
||||
}
|
||||
return params.required;
|
||||
}
|
||||
|
||||
export function resolveMissingEnv(params: {
|
||||
required: string[];
|
||||
isSatisfied: (envName: string) => boolean;
|
||||
}): string[] {
|
||||
const missing: string[] = [];
|
||||
for (const envName of params.required) {
|
||||
if (params.isSatisfied(envName)) {
|
||||
continue;
|
||||
}
|
||||
missing.push(envName);
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
export function buildConfigChecks(params: {
|
||||
required: string[];
|
||||
resolveValue: (pathStr: string) => unknown;
|
||||
isSatisfied: (pathStr: string) => boolean;
|
||||
}): RequirementConfigCheck[] {
|
||||
return params.required.map((pathStr) => {
|
||||
const value = params.resolveValue(pathStr);
|
||||
const satisfied = params.isSatisfied(pathStr);
|
||||
return { path: pathStr, value, satisfied };
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user