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

29 lines
1.5 KiB
TypeScript

import type { Json } from './types.ts';
import { fault } from './values.ts';
/** Own JSON fields only. A * segment enumerates an array, never object keys. */
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});
}
}
}
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;
}
}
}