mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 22:44:16 +00:00
refactor(cli): remove configurable option inheritance depth (openclaw#18725, thanks @gumadeiras)
This commit is contained in:
@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { inheritOptionFromParent } from "./command-options.js";
|
||||
|
||||
describe("inheritOptionFromParent", () => {
|
||||
it("inherits only from direct parent by default", async () => {
|
||||
it("inherits from grandparent when parent does not define the option", async () => {
|
||||
const program = new Command().option("--token <token>", "Root token");
|
||||
const gateway = program.command("gateway");
|
||||
let inherited: string | undefined;
|
||||
@@ -15,22 +15,6 @@ describe("inheritOptionFromParent", () => {
|
||||
inherited = inheritOptionFromParent<string>(command, "token");
|
||||
});
|
||||
|
||||
await program.parseAsync(["--token", "root-token", "gateway", "run"], { from: "user" });
|
||||
expect(inherited).toBeUndefined();
|
||||
});
|
||||
|
||||
it("walks ancestor chain when explicitly configured", async () => {
|
||||
const program = new Command().option("--token <token>", "Root token");
|
||||
const gateway = program.command("gateway");
|
||||
let inherited: string | undefined;
|
||||
|
||||
gateway
|
||||
.command("run")
|
||||
.option("--token <token>", "Run token")
|
||||
.action((_opts, command) => {
|
||||
inherited = inheritOptionFromParent<string>(command, "token", { maxDepth: 3 });
|
||||
});
|
||||
|
||||
await program.parseAsync(["--token", "root-token", "gateway", "run"], { from: "user" });
|
||||
expect(inherited).toBe("root-token");
|
||||
});
|
||||
@@ -44,7 +28,7 @@ describe("inheritOptionFromParent", () => {
|
||||
.command("run")
|
||||
.option("--token <token>", "Run token")
|
||||
.action((_opts, command) => {
|
||||
inherited = inheritOptionFromParent<string>(command, "token", { maxDepth: 3 });
|
||||
inherited = inheritOptionFromParent<string>(command, "token");
|
||||
});
|
||||
|
||||
await program.parseAsync(
|
||||
@@ -65,4 +49,23 @@ describe("inheritOptionFromParent", () => {
|
||||
|
||||
expect(inheritOptionFromParent<string>(run, "token")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not inherit from ancestors beyond the bounded traversal depth", async () => {
|
||||
const program = new Command().option("--token <token>", "Root token");
|
||||
const level1 = program.command("level1");
|
||||
const level2 = level1.command("level2");
|
||||
let inherited: string | undefined;
|
||||
|
||||
level2
|
||||
.command("run")
|
||||
.option("--token <token>", "Run token")
|
||||
.action((_opts, command) => {
|
||||
inherited = inheritOptionFromParent<string>(command, "token");
|
||||
});
|
||||
|
||||
await program.parseAsync(["--token", "root-token", "level1", "level2", "run"], {
|
||||
from: "user",
|
||||
});
|
||||
expect(inherited).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,15 +14,12 @@ function getOptionSource(command: Command, name: string): string | undefined {
|
||||
return command.getOptionValueSource(name);
|
||||
}
|
||||
|
||||
type InheritOptionConfig = {
|
||||
// Defensive default: only direct-parent inheritance unless callers opt into deeper traversal.
|
||||
maxDepth?: number;
|
||||
};
|
||||
// Defensive guardrail: allow expected parent/grandparent inheritance without unbounded deep traversal.
|
||||
const MAX_INHERIT_DEPTH = 2;
|
||||
|
||||
export function inheritOptionFromParent<T = unknown>(
|
||||
command: Command | undefined,
|
||||
name: string,
|
||||
config?: InheritOptionConfig,
|
||||
): T | undefined {
|
||||
if (!command) {
|
||||
return undefined;
|
||||
@@ -33,15 +30,9 @@ export function inheritOptionFromParent<T = unknown>(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const rawMaxDepth = config?.maxDepth;
|
||||
const maxDepth =
|
||||
typeof rawMaxDepth === "number" && Number.isFinite(rawMaxDepth)
|
||||
? Math.max(1, Math.floor(rawMaxDepth))
|
||||
: 1;
|
||||
|
||||
let depth = 0;
|
||||
let ancestor = command.parent;
|
||||
while (ancestor && depth < maxDepth) {
|
||||
while (ancestor && depth < MAX_INHERIT_DEPTH) {
|
||||
const source = getOptionSource(ancestor, name);
|
||||
if (source && source !== "default") {
|
||||
return ancestor.opts<Record<string, unknown>>()[name] as T | undefined;
|
||||
|
||||
Reference in New Issue
Block a user