import { isDeepStrictEqual } from "node:util"; import type { OpenClawConfig } from "../config/config.js"; import { isRecord } from "./shared.js"; function isArrayIndexSegment(segment: string): boolean { return /^\d+$/.test(segment); } function expectedContainer(nextSegment: string): "array" | "object" { return isArrayIndexSegment(nextSegment) ? "array" : "object"; } function parseArrayLeafTarget( cursor: unknown, leaf: string, segments: string[], ): { array: unknown[]; index: number } | null { if (!Array.isArray(cursor)) { return null; } if (!isArrayIndexSegment(leaf)) { throw new Error(`Invalid array index segment "${leaf}" at ${segments.join(".")}.`); } return { array: cursor, index: Number.parseInt(leaf, 10) }; } function traverseToLeafParent(params: { root: unknown; segments: string[]; requireExistingSegment: boolean; }): unknown { if (params.segments.length === 0) { throw new Error("Target path is empty."); } let cursor: unknown = params.root; for (let index = 0; index < params.segments.length - 1; index += 1) { const segment = params.segments[index] ?? ""; if (Array.isArray(cursor)) { if (!isArrayIndexSegment(segment)) { throw new Error( `Invalid array index segment "${segment}" at ${params.segments.join(".")}.`, ); } const arrayIndex = Number.parseInt(segment, 10); if (params.requireExistingSegment && (arrayIndex < 0 || arrayIndex >= cursor.length)) { throw new Error( `Path segment does not exist at ${params.segments.slice(0, index + 1).join(".")}.`, ); } cursor = cursor[arrayIndex]; continue; } if (!isRecord(cursor)) { throw new Error( `Invalid path shape at ${params.segments.slice(0, index).join(".") || ""}.`, ); } if (params.requireExistingSegment && !Object.prototype.hasOwnProperty.call(cursor, segment)) { throw new Error( `Path segment does not exist at ${params.segments.slice(0, index + 1).join(".")}.`, ); } cursor = cursor[segment]; } return cursor; } export function getPath(root: unknown, segments: string[]): unknown { if (segments.length === 0) { return undefined; } let cursor: unknown = root; for (const segment of segments) { if (Array.isArray(cursor)) { if (!isArrayIndexSegment(segment)) { return undefined; } cursor = cursor[Number.parseInt(segment, 10)]; continue; } if (!isRecord(cursor)) { return undefined; } cursor = cursor[segment]; } return cursor; } export function setPathCreateStrict( root: OpenClawConfig, segments: string[], value: unknown, ): boolean { if (segments.length === 0) { throw new Error("Target path is empty."); } let cursor: unknown = root; let changed = false; for (let index = 0; index < segments.length - 1; index += 1) { const segment = segments[index] ?? ""; const nextSegment = segments[index + 1] ?? ""; const needs = expectedContainer(nextSegment); if (Array.isArray(cursor)) { if (!isArrayIndexSegment(segment)) { throw new Error(`Invalid array index segment "${segment}" at ${segments.join(".")}.`); } const arrayIndex = Number.parseInt(segment, 10); const existing = cursor[arrayIndex]; if (existing === undefined || existing === null) { cursor[arrayIndex] = needs === "array" ? [] : {}; changed = true; } else if (needs === "array" ? !Array.isArray(existing) : !isRecord(existing)) { throw new Error(`Invalid path shape at ${segments.slice(0, index + 1).join(".")}.`); } cursor = cursor[arrayIndex]; continue; } if (!isRecord(cursor)) { throw new Error(`Invalid path shape at ${segments.slice(0, index).join(".") || ""}.`); } const existing = cursor[segment]; if (existing === undefined || existing === null) { cursor[segment] = needs === "array" ? [] : {}; changed = true; } else if (needs === "array" ? !Array.isArray(existing) : !isRecord(existing)) { throw new Error(`Invalid path shape at ${segments.slice(0, index + 1).join(".")}.`); } cursor = cursor[segment]; } const leaf = segments[segments.length - 1] ?? ""; const arrayTarget = parseArrayLeafTarget(cursor, leaf, segments); if (arrayTarget) { if (!isDeepStrictEqual(arrayTarget.array[arrayTarget.index], value)) { arrayTarget.array[arrayTarget.index] = value; changed = true; } return changed; } if (!isRecord(cursor)) { throw new Error(`Invalid path shape at ${segments.slice(0, -1).join(".") || ""}.`); } if (!isDeepStrictEqual(cursor[leaf], value)) { cursor[leaf] = value; changed = true; } return changed; } export function setPathExistingStrict( root: OpenClawConfig, segments: string[], value: unknown, ): boolean { const cursor = traverseToLeafParent({ root, segments, requireExistingSegment: true }); const leaf = segments[segments.length - 1] ?? ""; const arrayTarget = parseArrayLeafTarget(cursor, leaf, segments); if (arrayTarget) { if (arrayTarget.index < 0 || arrayTarget.index >= arrayTarget.array.length) { throw new Error(`Path segment does not exist at ${segments.join(".")}.`); } if (!isDeepStrictEqual(arrayTarget.array[arrayTarget.index], value)) { arrayTarget.array[arrayTarget.index] = value; return true; } return false; } if (!isRecord(cursor)) { throw new Error(`Invalid path shape at ${segments.slice(0, -1).join(".") || ""}.`); } if (!Object.prototype.hasOwnProperty.call(cursor, leaf)) { throw new Error(`Path segment does not exist at ${segments.join(".")}.`); } if (!isDeepStrictEqual(cursor[leaf], value)) { cursor[leaf] = value; return true; } return false; } export function deletePathStrict(root: OpenClawConfig, segments: string[]): boolean { const cursor = traverseToLeafParent({ root, segments, requireExistingSegment: false }); const leaf = segments[segments.length - 1] ?? ""; const arrayTarget = parseArrayLeafTarget(cursor, leaf, segments); if (arrayTarget) { if (arrayTarget.index < 0 || arrayTarget.index >= arrayTarget.array.length) { return false; } // Arrays are compacted to preserve predictable index semantics. arrayTarget.array.splice(arrayTarget.index, 1); return true; } if (!isRecord(cursor)) { throw new Error(`Invalid path shape at ${segments.slice(0, -1).join(".") || ""}.`); } if (!Object.prototype.hasOwnProperty.call(cursor, leaf)) { return false; } delete cursor[leaf]; return true; }