Merge pull request #3348 from code-yeongyu/refactor/ulw-repo-cleanup-20260411

refactor: simplify nullish guards and remove dead no-op paths
This commit is contained in:
YeonGyu-Kim
2026-04-12 18:04:43 +09:00
committed by GitHub
15 changed files with 156 additions and 46 deletions
@@ -112,6 +112,20 @@ describe("loop-detector", () => {
expect(result).toBe("read")
})
test("#given nullish inputs #when signatures are created #then null and undefined behave the same", () => {
// given
const undefinedInput = undefined
const nullInput = null
// when
const undefinedResult = createToolCallSignature("read", undefinedInput)
const nullResult = createToolCallSignature("read", nullInput)
// then
expect(undefinedResult).toBe("read")
expect(nullResult).toBe(undefinedResult)
})
test("#given tool with empty object input #when signature created #then returns bare tool name", () => {
const result = createToolCallSignature("read", {})
@@ -259,5 +273,24 @@ describe("loop-detector", () => {
expect(result).toEqual({ triggered: false })
})
})
describe("#given nullish tool inputs", () => {
test("#when recorded #then null and undefined produce the same unknown-input window", () => {
// given
const settings = resolveCircuitBreakerSettings()
// when
const undefinedWindow = recordToolCall(undefined, "read", settings, undefined)
const nullWindow = recordToolCall(undefined, "read", settings, null)
// then
expect(undefinedWindow).toEqual(nullWindow)
expect(undefinedWindow).toEqual({
lastSignature: "read::__unknown-input__",
consecutiveCount: 1,
threshold: settings.consecutiveThreshold,
})
})
})
})
})
@@ -36,7 +36,7 @@ export function recordToolCall(
settings: CircuitBreakerSettings,
toolInput?: Record<string, unknown> | null
): ToolCallWindow {
if (toolInput === undefined || toolInput === null) {
if (toolInput == null) {
return {
lastSignature: `${toolName}::__unknown-input__`,
consecutiveCount: 1,
@@ -62,7 +62,7 @@ export function recordToolCall(
}
function sortObject(obj: unknown): unknown {
if (obj === null || obj === undefined) return obj
if (obj == null) return obj
if (typeof obj !== "object") return obj
if (Array.isArray(obj)) return obj.map(sortObject)
@@ -78,7 +78,7 @@ export function createToolCallSignature(
toolName: string,
toolInput?: Record<string, unknown> | null
): string {
if (toolInput === undefined || toolInput === null) {
if (toolInput == null) {
return toolName
}
if (Object.keys(toolInput).length === 0) {
@@ -35,7 +35,7 @@ export function expandEnvVars(value: string, options: ExpandEnvVarsOptions = {})
}
export function expandEnvVarsInObject<T>(obj: T, options: ExpandEnvVarsOptions = {}): T {
if (obj === null || obj === undefined) return obj
if (obj == null) return obj
if (typeof obj === "string") return expandEnvVars(obj, options) as T
if (Array.isArray(obj)) {
return obj.map((item) => expandEnvVarsInObject(item, options)) as T
@@ -0,0 +1,55 @@
import { describe, expect, test } from "bun:test"
import { resolvePluginPath, resolvePluginPaths } from "./plugin-path-resolver"
describe("resolvePluginPath", () => {
test("#given a plugin root placeholder #when resolving the path #then it replaces the placeholder", () => {
// given
const path = "${CLAUDE_PLUGIN_ROOT}/dist/index.js"
// when
const result = resolvePluginPath(path, "/tmp/plugin-root")
// then
expect(result).toBe("/tmp/plugin-root/dist/index.js")
})
})
describe("resolvePluginPaths", () => {
test("#given a nested object #when resolving paths #then it rewrites every nested string path", () => {
// given
const value = {
command: "node",
args: ["${CLAUDE_PLUGIN_ROOT}/server.js"],
nested: {
config: "${CLAUDE_PLUGIN_ROOT}/config.json",
},
}
// when
const result = resolvePluginPaths(value, "/tmp/plugin-root")
// then
expect(result).toEqual({
command: "node",
args: ["/tmp/plugin-root/server.js"],
nested: {
config: "/tmp/plugin-root/config.json",
},
})
})
test("#given nullish input #when resolving paths #then it returns the same nullish value", () => {
// given
const nullValue = null
const undefinedValue = undefined
// when
const nullResult = resolvePluginPaths(nullValue, "/tmp/plugin-root")
const undefinedResult = resolvePluginPaths(undefinedValue, "/tmp/plugin-root")
// then
expect(nullResult).toBeNull()
expect(undefinedResult).toBeUndefined()
})
})
@@ -5,7 +5,7 @@ export function resolvePluginPath(path: string, pluginRoot: string): string {
}
export function resolvePluginPaths<T>(obj: T, pluginRoot: string): T {
if (obj === null || obj === undefined) return obj
if (obj == null) return obj
if (typeof obj === "string") {
return resolvePluginPath(obj, pluginRoot) as T
}