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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user