UNPKG

@sanity/migrate

Version:

Tooling for running data migrations on Sanity.io projects

74 lines (64 loc) 2.09 kB
import {type Path, type PathSegment} from '@sanity/types' import {type JsonArray, type JsonObject, type JsonValue} from '../../json.js' import {getValueType} from './getValueType.js' type SkipMarker = {_: 'SKIP_MARKER'} export const SKIP_MARKER: SkipMarker = {_: 'SKIP_MARKER'} function callMap<T>(mapFn: MapFn<T>, value: JsonValue, path: Path): T[] { const res = mapFn(value, path) return Array.isArray(res) ? res : [res] } function getPathWithKey( item: unknown, index: number | string, container: JsonArray | JsonObject, ): PathSegment { if ( item && Array.isArray(container) && typeof item === 'object' && '_key' in item && typeof item._key === 'string' ) { return {_key: item._key} } return index } type MapFn<T> = (value: JsonValue, path: Path) => T | T[] // Reduce depth first function mapObject<T>(reducerFn: MapFn<T>, object: JsonObject, path: Path): T[] { return [ ...callMap(reducerFn, object, path), ...Object.keys(object).flatMap((key) => { const value = object[key] if (value === undefined) return [] return flatMapAny(reducerFn, value, [...path, getPathWithKey(value, key, object)]) }), ] } // Reduce depth first function mapArray<T>(mapFn: MapFn<T>, array: JsonArray, path: Path): T[] { return [ ...callMap(mapFn, array, path), ...array.flatMap((item: JsonValue, index) => flatMapAny(mapFn, item, [...path, getPathWithKey(item, index, array)]), ), ] } function flatMapAny<T>(mapFn: MapFn<T>, val: JsonValue, path: Path) { const type = getValueType(val) if (type === 'object') { return mapObject(mapFn, val as JsonObject, path) } if (type === 'array') { return mapArray(mapFn, val as JsonArray, path) } return callMap(mapFn, val, path) } /** * Iterating depth first over the JSON tree, calling the mapFn for parents before children * @param value - the value to map deeply over * @param mapFn - the mapFn to call for each value */ export function flatMapDeep<T>(value: JsonValue, mapFn: MapFn<T>): T[] { return flatMapAny(mapFn, value, []) }