fix(schema-form): extract the clone-spine walk and drop the unused ui-primitives dependency

This commit is contained in:
Yichen Jiang
2026-07-30 10:40:43 +08:00
parent 0d96676f35
commit ebff7db11e
4 changed files with 31 additions and 35 deletions

View File

@@ -20,7 +20,6 @@
}, },
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"@deepseek-ai/dsh-client-ui-primitives": "workspace:^",
"react": "^18.2.0", "react": "^18.2.0",
"schemastery": "^3.18.0" "schemastery": "^3.18.0"
}, },

View File

@@ -117,7 +117,13 @@ export function getPath(value: unknown, path: readonly string[]): unknown {
return current return current
} }
/** Whether a draft explicitly carries the path (its presence marks a user override). */ /**
* Whether a draft explicitly carries the path (its presence marks a user
* override, independent of the value stored there).
* @param value - root value (draft or fallback layer).
* @param path - key path from the root; array indexes as strings.
* @returns whether the path's final key exists on its parent.
*/
export function hasPath(value: unknown, path: readonly string[]): boolean { export function hasPath(value: unknown, path: readonly string[]): boolean {
if (path.length === 0) return value !== undefined if (path.length === 0) return value !== undefined
const parent = getPath(value, path.slice(0, -1)) const parent = getPath(value, path.slice(0, -1))
@@ -134,15 +140,12 @@ function cloneContainer(container: unknown, key: string): Record<string, unknown
return /^\d+$/.test(key) ? [] : {} return /^\d+$/.test(key) ? [] : {}
} }
/** /** Clone the container spine down to the leaf's parent, materializing missing intermediates. */
* Immutably set a nested value, materializing missing intermediate containers. function cloneSpine(root: Record<string, unknown>, path: readonly string[]): {
* @param root - draft root (never mutated). result: Record<string, unknown>
* @param path - non-empty key path. parent: Record<string, unknown> | unknown[]
* @param value - value to store at the path. leaf: string
* @returns the new draft root. } {
*/
export function setPath(root: Record<string, unknown>, path: readonly string[], value: unknown): Record<string, unknown> {
if (path.length === 0) throw new Error('schema-form: setPath needs a non-empty path')
const result = { ...root } const result = { ...root }
let target: Record<string, unknown> | unknown[] = result let target: Record<string, unknown> | unknown[] = result
for (let i = 0; i < path.length - 1; i++) { for (let i = 0; i < path.length - 1; i++) {
@@ -155,9 +158,21 @@ export function setPath(root: Record<string, unknown>, path: readonly string[],
else (target)[key] = child else (target)[key] = child
target = child target = child
} }
const leaf = path[path.length - 1] as string return { result, parent: target, leaf: path[path.length - 1] as string }
if (Array.isArray(target)) target[Number(leaf)] = value }
else (target)[leaf] = value
/**
* Immutably set a nested value, materializing missing intermediate containers.
* @param root - draft root (never mutated).
* @param path - non-empty key path.
* @param value - value to store at the path.
* @returns the new draft root.
*/
export function setPath(root: Record<string, unknown>, path: readonly string[], value: unknown): Record<string, unknown> {
if (path.length === 0) throw new Error('schema-form: setPath needs a non-empty path')
const { result, parent, leaf } = cloneSpine(root, path)
if (Array.isArray(parent)) parent[Number(leaf)] = value
else parent[leaf] = value
return result return result
} }
@@ -172,20 +187,8 @@ export function setPath(root: Record<string, unknown>, path: readonly string[],
export function deletePath(root: Record<string, unknown>, path: readonly string[]): Record<string, unknown> { export function deletePath(root: Record<string, unknown>, path: readonly string[]): Record<string, unknown> {
if (path.length === 0) throw new Error('schema-form: deletePath needs a non-empty path') if (path.length === 0) throw new Error('schema-form: deletePath needs a non-empty path')
if (!hasPath(root, path)) return root if (!hasPath(root, path)) return root
const result = { ...root } const { result, parent, leaf } = cloneSpine(root, path)
let target: Record<string, unknown> | unknown[] = result if (Array.isArray(parent)) parent.splice(Number(leaf), 1)
for (let i = 0; i < path.length - 1; i++) { else Reflect.deleteProperty(parent, leaf)
const key = path[i] as string
const child = cloneContainer(
Array.isArray(target) ? target[Number(key)] : (target)[key],
path[i + 1] as string,
)
if (Array.isArray(target)) target[Number(key)] = child
else (target)[key] = child
target = child
}
const leaf = path[path.length - 1] as string
if (Array.isArray(target)) target.splice(Number(leaf), 1)
else Reflect.deleteProperty(target, leaf)
return result return result
} }

View File

@@ -8,9 +8,6 @@
"src" "src"
], ],
"references": [ "references": [
{
"path": "../ui-primitives"
},
{ {
"path": "../../../vendor/schemastery" "path": "../../../vendor/schemastery"
}, },

3
pnpm-lock.yaml generated
View File

@@ -956,9 +956,6 @@ importers:
packages/client/schema-form: packages/client/schema-form:
dependencies: dependencies:
'@deepseek-ai/dsh-client-ui-primitives':
specifier: workspace:^
version: link:../ui-primitives
react: react:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.3.1 version: 18.3.1