Files
Endoleap/src/lib/canvas-core/copy-paths.ts
T

37 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 组件声明式引用路径的遍历器,供复制/解散等纯规划复用。
* 只访问自有字段,不用字符串相似度猜 ID;这里 yield 可写 slot,调用者必须先复制数据再改。
*/
import type { Json } from './types.ts';
import { fault } from './values.ts';
/** Own JSON fields only. A * segment enumerates an array, never object keys. */
/** 用显式 stack 遍历 path,返回终端字段的 parent/key;缺失普通字段直接跳过。
* * 只允许数组,非数组抛错;反向压栈使最终输出仍按原数组顺序。 */
export function* copySlots(data: Json, path: readonly string[]): Generator<{parent: Record<string, Json>; key: string}> {
const work: {value: Json; depth: number}[] = [{value: data, depth: 0}];
while (work.length) {
const {value, depth} = work.pop()!, key = path[depth];
if (key === '*') {
if (!Array.isArray(value)) throw fault('invalid_copy_reference');
// 终端 * 直接枚举数组项位置;非终端 * 继续匹配下一路径段。
if (depth === path.length - 1) { for (let i = 0; i < value.length; i++) yield {parent: value as unknown as Record<string, Json>, key: String(i)}; }
else for (let i = value.length - 1; i >= 0; i--) work.push({value: value[i], depth: depth + 1});
} else if (value && typeof value === 'object' && Object.hasOwn(value, key)) {
if (depth === path.length - 1) yield {parent: value as Record<string, Json>, key};
else work.push({value: (value as Record<string, Json>)[key], depth: depth + 1});
}
}
}
/** 在 slot 上读取引用 ID;null 代表无引用,many 要求数组,每个 ID 必须非空字符串。 */
export function* copyReferenceIds(data: Json, ref: {path: readonly string[]; many?: boolean}): Generator<string> {
for (const {parent, key} of copySlots(data, ref.path)) {
const value = parent[key]; if (value === null) continue;
if (ref.many && !Array.isArray(value)) throw fault('invalid_copy_reference');
for (const id of ref.many ? value as Json[] : [value]) {
if (typeof id !== 'string' || !id) throw fault('invalid_copy_reference');
yield id;
}
}
}