UNPKG

map-transform-cjs

Version:
1,019 lines (996 loc) 35.8 kB
// src/utils/xor.ts function xor(a = false, b = false) { return a ? !b : b; } // src/utils/stateHelpers.ts var getLastContext = (state) => state.context[state.context.length - 1]; var pushContext = (state, value) => ({ ...state, context: [...state.context, value] }); var popContext = (state) => ({ ...state, context: state.context.slice(0, -1), value: state.context[state.context.length - 1] }); var getRootFromState = (state) => state.context.length === 0 ? state.value : state.context[0]; var getTargetFromState = (state) => state.target; function setTargetOnState(state, target) { return { ...state, target }; } var setStateValue = ({ untouched, ...state }, value, shouldPushContext = false) => shouldPushContext ? { ...pushContext(state, state.value), value } : { ...state, value }; var getStateValue = (state) => state.value; var setValueFromState = (state, { value }, shouldPushContext = false) => setStateValue(state, value, shouldPushContext); var isNonvalue = (value, nonvalues = [void 0]) => nonvalues.includes(value); var isNonvalueState = (state, nonvalues = [void 0]) => isNonvalue(state.value, nonvalues); var markAsUntouched = (state) => ({ ...state, untouched: true }); var clearUntouched = ({ untouched, ...state }) => state; var isUntouched = ({ untouched }) => !!untouched; var goForward = (state) => state.rev || state.flip ? { ...state, rev: false, flip: false } : state; var flipState = (state, flip = true) => ({ ...state, flip: xor(state.flip, flip) }); var stopIteration = (state) => ({ ...state, iterate: false }); var noopNext = async (state) => state; var revFromState = (state, flip = false) => flip ? xor(state.rev, !state.flip) : xor(state.rev, state.flip); // src/utils/modifyOperationObject.ts var createTransformWithPath = ($transform, path, operator) => ({ $transform, path, ...operator && { operator } }); var createValueTransform = ({ $value, ...rest }) => ({ ...rest, $transform: "value", value: $value }); var createAndTransform = ({ $and, ...rest }) => ({ ...rest, ...createTransformWithPath("logical", $and, "AND") }); var createOrTransform = ({ $or, ...rest }) => ({ ...rest, ...createTransformWithPath("logical", $or, "OR") }); var createNotTransform = ({ $not, ...rest }) => ({ ...rest, ...createTransformWithPath("not", $not) }); var createMergeTransform = ({ $merge, ...rest }) => ({ ...rest, ...createTransformWithPath("merge", $merge) }); function modifyOperationObject(rawOperation, modify2) { const operation = typeof modify2 === "function" ? modify2(rawOperation) : rawOperation; if (operation.hasOwnProperty("$value")) { return createValueTransform(operation); } else if (operation.hasOwnProperty("$and")) { return createAndTransform(operation); } else if (operation.hasOwnProperty("$or")) { return createOrTransform(operation); } else if (operation.hasOwnProperty("$not")) { return createNotTransform(operation); } else if (operation.hasOwnProperty("$merge")) { return createMergeTransform(operation); } return operation; } // src/utils/is.ts var isObject = (value) => Object.prototype.toString.call(value) === "[object Object]"; var isNullOrUndefined = (value) => value === null || value === void 0; var isNotNullOrUndefined = (value) => !isNullOrUndefined(value); // src/operations/getSet.ts import mapAny from "map-any-cjs"; // src/utils/array.ts var ensureArray = (value, nonvalues) => Array.isArray(value) ? value : isNonvalue(value, nonvalues) ? [] : [value]; var indexOfIfArray = (arr, index) => Array.isArray(arr) && typeof index === "number" ? arr[index] : arr; // src/operations/getSet.ts var adjustIsSet = (isSet, state) => revFromState(state, isSet); function flatMapAny(fn) { return (value, target) => Array.isArray(value) ? value.flatMap((value2) => fn(value2, target)) : fn(value, target); } function handleArrayPath(path) { if (path.endsWith("][")) { return [ path.slice(0, path.length - 2), false, true /* isIndexProp */ ]; } const pos = path.indexOf("["); if (path[pos - 1] === "\\") { return [path.replace("\\[", "["), false, false]; } else { const isArr2 = path[pos + 1] === "]"; return [path.slice(0, pos), isArr2, false]; } } function preparePath(path) { if (typeof path === "string") { if (path.includes("[")) { return handleArrayPath(path); } else if (path.startsWith("\\$")) { return [path.slice(1), false, false]; } } return [path, false, false]; } function getSetProp(path) { if (path === "") { return (value) => value; } const getFn = flatMapAny( (value) => isObject(value) ? value[path] : void 0 ); const setFn = (value, target) => isObject(target) ? { ...target, [path]: value } : { [path]: value }; return (value, isSet, target) => { if (isSet) { return setFn(value, target); } else { return getFn(value); } }; } var calculateIndex = (index, arr) => index >= 0 ? index : arr.length + index; function getSetIndex(index) { return (value, isSet, target) => { if (isSet) { const arr = Array.isArray(target) ? [...target] : []; arr[calculateIndex(index, arr)] = value; return arr; } else { return Array.isArray(value) ? value[calculateIndex(index, value)] : void 0; } }; } function getParent(state) { const nextValue = getLastContext(state); const nextContext = state.context.slice(0, -1); return { ...state, context: nextContext, value: nextValue }; } function getRoot(state) { const nextValue = getRootFromState(state); return { ...state, context: [], value: nextValue }; } function getSetParentOrRoot(path, isSet) { const getFn = path[1] === "^" ? getRoot : getParent; return () => (next) => async (state) => { const nextState = await next(state); if (adjustIsSet(isSet, state)) { return setStateValue(nextState, state.target); } else { return getFn(nextState); } }; } var modifyOnSet = (isSet) => (options) => function modifyOnSet2(next) { const modifyFn = modify(".")(options)(next); return async (state) => { return adjustIsSet(isSet, state) ? await modifyFn(state) : setStateValue(await next(state), void 0); }; }; function doModifyGetValue(value, state, options) { const { modifyGetValue } = options; return typeof modifyGetValue === "function" ? modifyGetValue(value, state, options) : value; } function getSet(isSet = false) { return (path) => { if (typeof path === "string") { if (path === "$modify") { return modifyOnSet(isSet); } else if (path[0] === "^") { return getSetParentOrRoot(path, isSet); } } const [basePath, isArr2, isIndexProp] = preparePath(path); const isIndex = typeof basePath === "number"; const getSetFn = isIndex ? getSetIndex(basePath) : getSetProp(basePath); return (options) => (next) => async function doGetSet(state) { if (adjustIsSet(isSet, state)) { const target = getTargetFromState(state); const nextTarget = getSetFn(target, false); const nextState = await next( setTargetOnState( { ...state, iterate: state.iterate || isArr2 }, nextTarget ) ); const setIt = (value2, index) => getSetFn(value2, true, indexOfIfArray(target, index)); const nextValue = getStateValue(nextState); if (state.noDefaults && isNonvalue(nextValue, options.nonvalues)) { return setStateValue(state, target); } const value = isArr2 ? ensureArray(nextValue, options.nonvalues) : nextValue; const thisValue = nextState.iterate && !isArr2 && !isIndexProp ? mapAny(setIt, value) : setIt(value); return setStateValue(state, thisValue); } else { const nextState = await next(state); const thisValue = getSetFn(getStateValue(nextState), false); const modifiedValue = doModifyGetValue(thisValue, nextState, options); const value = state.noDefaults && isNonvalue(modifiedValue, options.nonvalues) ? void 0 : isArr2 ? ensureArray(modifiedValue, options.nonvalues) : modifiedValue; return setStateValue( nextState, value, true // Push to context ); } }; }; } function resolveArrayNotation(path, pos) { const index = Number.parseInt(path.slice(pos + 1), 10); if (!Number.isNaN(index)) { const basePath = path.slice(0, pos).trim(); return basePath ? [`${basePath}][`, index] : [index]; } else { return path.trim(); } } function resolveParentNotation(path) { if (path.startsWith("^^") && path.length > 2) { return ["^^", path.slice(2).trim()]; } else if (path.length > 1 && path !== "^^") { return ["^^", path.slice(1).trim()]; } else { return path.trim(); } } function splitUpArrayAndParentNotation(path) { const pos = path.indexOf("["); if (pos > -1 && path[pos - 1] !== "\\") { return resolveArrayNotation(path, pos); } else if (path.startsWith("^")) { return resolveParentNotation(path); } else { return path.trim(); } } function pathToNextOperations(path, isSet = false) { if (!path || path === ".") { return [ () => (next) => async (state) => clearUntouched(await next(state)) // We don't change the value, but we still need to clear untouched ]; } if (path[0] === ">") { path = path.slice(1); isSet = true; } const parts = path.split(".").flatMap(splitUpArrayAndParentNotation); const operations = parts.map(getSet(isSet)); if (isSet) { operations.reverse(); } return operations; } var getByPart = (part, isArr2) => (value) => { if (typeof part === "string") { if (isObject(value)) { const nextValue = value[part]; return isArr2 ? ensureArray(nextValue) : nextValue; } } else if (typeof part === "number" && Array.isArray(value)) { return value[calculateIndex(part, value)]; } return isArr2 ? [] : void 0; }; function prepareGetFn([part, isArr2]) { if (typeof part === "string" && part[0] === "^") { const isRoot = part[1] === "^"; return (_value, state) => { const nextState = isRoot ? getRoot(state) : getParent(state); return [nextState.value, nextState]; }; } else if (typeof part === "number") { const fn = getByPart(part, isArr2); return (value) => [fn(value), void 0]; } else { const fn = flatMapAny(getByPart(part, isArr2)); return (value) => [fn(value), void 0]; } } function pathGetter(path, _options = {}) { if (!path || path === ".") { return (value) => value; } const parts = path.split(".").flatMap(splitUpArrayAndParentNotation).map(preparePath).map(prepareGetFn); return function getFromPath(value, startState) { let data = value; let state = startState; for (const partOrGetFn of parts) { ; [data, state = state] = partOrGetFn(data, state); } return data; }; } var get = (path) => pathToNextOperations(path, false); var set = (path) => pathToNextOperations(path, true); // src/operations/iterate.ts var runIterationStep = async (fn, state, value, index, target) => getStateValue( await fn( setTargetOnState( { ...state, index, value }, indexOfIfArray(target, index) ) ) ); var iterateState = (fn) => async (state, target) => { const values = getStateValue(state); if (!Array.isArray(values)) { return await runIterationStep(fn, state, values, 0, target); } const nextState = pushContext(state, values); const nextValue = []; for (const [index, value] of values.entries()) { nextValue.push( await runIterationStep(fn, nextState, value, index, target) ); } return nextValue; }; function iterate(def) { if (!def || typeof def === "object" && Object.keys(def).length === 0) { return (_options) => (next) => async (state) => setStateValue(await next(state), void 0); } return (options) => { const fn = defToOperation(def, options)(options); return (next) => { const runIteration = iterateState(fn(noopNext)); return async function doIterate(state) { const nextState = await next(state); return setStateValue( nextState, await runIteration(nextState, getTargetFromState(nextState)) ); }; }; }; } // src/operations/directionals.ts var applyInDirection = (def, shouldRunRev) => (options) => (next) => { const fn = defToOperation(def, options)(options)(next); return async function applyFwdOrRev(state) { return !!state.rev === shouldRunRev ? await fn(state) : await next(state); }; }; function fwd(def) { return applyInDirection(def, false); } function rev(def) { return applyInDirection(def, true); } function divide(fwdDef, revDef, honorFlip = false) { return (options) => (next) => { const fwdFn = defToOperation(fwdDef, options)(options)(next); const revFn = defToOperation(revDef, options)(options)(next); return async function applyDivide(state) { const isRev = honorFlip ? revFromState(state) : !!state.rev; return isRev ? await revFn(state) : await fwdFn(state); }; }; } // src/operations/transform.ts function transform(fn, revFn) { return (options) => { if (typeof fn !== "function") { throw new Error( "Transform operation was called without a valid transformer function" ); } const fwdPipeline = fn(options); const revPipeline = typeof revFn === "function" ? revFn(options) : fwdPipeline; return (next) => async (state) => { const nextState = await next(state); const fn2 = revFromState(nextState) ? revPipeline : fwdPipeline; const value = await fn2(getStateValue(nextState), nextState); return setStateValue(nextState, value); }; }; } // src/transformers/flatten.ts var transformer = function flatten({ depth = 1 }) { return () => (data) => Array.isArray(data) ? data.flat(depth) : data; }; var flatten_default = transformer; // src/operations/pipe.ts function createRun(fns, next) { let fn = next; for (const f of fns) { fn = f(fn); } return fn; } function splitArrayPaths(defs) { const pipeline = []; for (const [index, step] of defs.entries()) { if (typeof step === "string" && step.includes("[].")) { const pos = step.indexOf("[]."); pipeline.push(step.slice(0, pos + 2)); pipeline.push( divide(iterate([step.slice(pos + 3), ...defs.slice(index + 1)]), [ step.slice(pos + 3), ...defs.slice(index + 1) ]) ); pipeline.push(fwd(transform(flatten_default({ depth: 1 })))); break; } else { pipeline.push(step); } } return pipeline; } function pipe(defs, doReturnContext = false) { return (options) => { if (!Array.isArray(defs) || defs.length === 0) { return () => async (state) => state; } const fns = splitArrayPaths(defs).flat().flatMap((def) => defToOperations(def, options)).map((fn) => fn(options)); return (next) => { const runFwd = createRun(fns, next); const runRev = createRun(Array.from(fns).reverse(), next); return async function doPipe(state) { const thisState = revFromState(state) ? await runRev(state) : await runFwd(state); return doReturnContext ? thisState : setValueFromState(state, thisState); }; }; }; } // src/operations/plug.ts function plug() { return () => (_next) => async (state) => setStateValue(state, getTargetFromState(state)); } // src/operations/props.ts function pathHasModify(path) { const index = path.indexOf("$modify"); return index > -1 && // We have a $modify (index === 0 || path[index - 1] === ".") && // It's either the first char, or preceded by a dot (path.length === index + 7 || path[index + 7] === "."); } function isPathWithModify(pipeline) { if (Array.isArray(pipeline)) { return pipeline.some(isPathWithModify); } else if (typeof pipeline !== "string") { return false; } else { return pathHasModify(pipeline); } } function isRegularProp(entry) { const [prop, pipeline] = entry; return (prop[0] !== "$" || isPathWithModify(prop) && !isPathWithModify(pipeline)) && isTransformDefinition(pipeline); } function sortProps([aProp, aPipeline], [bProp, bPipeline]) { const aIsModify = isPathWithModify(aProp) || isPathWithModify(aPipeline); const bIsModify = isPathWithModify(bProp) || isPathWithModify(bPipeline); return Number(aIsModify) - Number(bIsModify); } var checkDirection = (requiredDirection, directionKeyword, directionAlias) => requiredDirection === directionKeyword || directionAlias && requiredDirection === directionAlias; var resolveDirection = (direction, options) => checkDirection(direction, "rev", options.revAlias) ? true : checkDirection(direction, "fwd", options.fwdAlias) ? false : void 0; function wrapInDirectional(operation, direction) { return (options) => { const isRev = resolveDirection(direction, options); if (isRev === void 0) { return operation(options); } else { const wrapOp = isRev ? rev : fwd; return wrapOp(operation)(options); } }; } var mergeTargetAndValueOperation = () => (next) => async function mergeTargetAndValue(state) { const nextState = await next(state); const target = getTargetFromState(nextState); const value = getStateValue(nextState); return isObject(target) && isObject(value) ? setStateValue(nextState, { ...target, ...value }) : nextState; }; function runOperationWithOriginalValue({ value }) { return async (state, fn) => { const nextState = await fn(setStateValue(state, value)); const target = getTargetFromState(state); const nextValue = getStateValue(nextState); const thisState = setTargetOnState(nextState, nextValue); if (isObject(target) && !isObject(nextValue)) { return setStateValue(thisState, target); } else { return thisState; } }; } var isArr = (prop) => prop.endsWith("[]") && prop[prop.length - 3] !== "\\"; var isNumeric = (value) => !Number.isNaN(Number.parseInt(value, 10)); function removeSlash(prop) { const index = prop.indexOf("/"); if (index > -1 && prop[index - 1] !== "\\" && isNumeric(prop.slice(index + 1))) { return prop.slice(0, index); } return prop; } function createDirectionalOperation(pipeline, onlyFwd, onlyRev) { if (onlyRev && onlyFwd) { return void 0; } else if (onlyRev) { return divide(plug(), pipeline, true); } else if (onlyFwd) { return divide(pipeline, plug(), true); } else { return pipe(pipeline); } } var createSetPipeline = (options) => function createSetPipeline2([prop, pipeline]) { if (isTransformObject(pipeline)) { pipeline = [ rev(mergeTargetAndValueOperation), // This will make sure the result of this pipeline is merged with the target in reverse { ...pipeline, $iterate: pipeline.$iterate || isArr(prop) } ]; } const unslashedProp = removeSlash(prop); const isSlashed = prop !== unslashedProp; const onlyFwd = isPathWithModify(unslashedProp); const onlyRev = isSlashed || isPathWithModify(pipeline); const operations = [defToOperation(pipeline, options), set(unslashedProp)]; return createDirectionalOperation(operations, onlyFwd, onlyRev); }; var runOperations = (stateMappers, options) => async (state) => { if (isNonvalueState(state, options.nonvalues)) { return state; } else { const run = runOperationWithOriginalValue(state); let nextState = state; for (const stateMapper of stateMappers) { nextState = await run(nextState, stateMapper(noopNext)); } return nextState; } }; var setStateProps = (state, noDefaults, flip) => ({ ...state, noDefaults: noDefaults || state.noDefaults || false, flip: flip || state.flip || false, target: void 0 }); var fixModifyPath = (def) => def.$modify === true ? { ...def, $modify: "." } : def; var createStateMappers = (def, options) => Object.entries(def).filter(isRegularProp).sort(sortProps).map(createSetPipeline(options)).filter(isNotNullOrUndefined).map((fn) => fn(options)); function prepareOperation(def) { return (options) => { const nextStateMappers = createStateMappers(fixModifyPath(def), options); if (nextStateMappers.length === 0) { return (next) => async (state) => setStateValue(await next(state), {}); } const run = runOperations(nextStateMappers, options); const runWithIterateWhenNeeded = def.$iterate === true ? iterate(() => () => run)(options)(noopNext) : run; return (next) => { return async function doMutate(state) { const nextState = await next(state); if (isNonvalueState(nextState, options.nonvalues)) { return nextState; } const propsState = stopIteration( setStateProps(nextState, def.$noDefaults, def.$flip) ); const thisState = await runWithIterateWhenNeeded(propsState); return setValueFromState(nextState, thisState); }; }; }; } function props(def) { const operation = prepareOperation(def); return wrapInDirectional(operation, def.$direction); } // src/operations/filter.ts async function filterValue(values, filterFn, state) { if (Array.isArray(values)) { const results = []; for (const value of values) { if (await filterFn(value, state)) { results.push(value); } } return results; } else { const result = await filterFn(values, state); return result ? values : void 0; } } function filter(fn) { return (options) => (next) => { if (typeof fn !== "function") { return async (state) => await next(state); } const fnWithOptions = fn(options); return async (state) => { const nextState = await next(state); return setStateValue( nextState, await filterValue(getStateValue(nextState), fnWithOptions, nextState) ); }; }; } // src/operations/ifelse.ts function runCondition(conditionDef) { return () => (next) => async (state) => { const nextState = await next(state); return setStateValue( nextState, await conditionDef(getStateValue(nextState), nextState) ); }; } function ifelse_default(conditionDef, trueDef, falseDef) { return (options) => { const falseFn = defToOperation(falseDef, options); if (!conditionDef) { return falseFn(options); } const conditionFn = typeof conditionDef === "function" ? runCondition(conditionDef) : defToOperation(conditionDef, options); const trueFn = defToOperation(trueDef, options); return (next) => { const runCondition2 = conditionFn(options)(noopNext); const runTrue = trueFn(options)(noopNext); const runFalse = falseFn(options)(noopNext); return async (state) => { const nextState = await next(state); const bool = getStateValue(await runCondition2(goForward(nextState))); return bool ? await runTrue(nextState) : await runFalse(nextState); }; }; }; } // src/operations/apply.ts var getPipeline = (pipelineId, { pipelines }) => (typeof pipelineId === "string" || typeof pipelineId === "symbol") && pipelines ? pipelines[pipelineId] : void 0; function setPipeline(id, operation, options) { if (options.pipelines) { options.pipelines[id] = operation; } } var removeFlip = ({ flip, ...state }) => state; function prepareAndSetPipeline(pipelineId, pipeline, options) { if (typeof pipeline !== "function" && pipeline) { setPipeline(pipelineId, () => () => noopNext, options); const operation = defToOperation(pipeline, options)(options); setPipeline(pipelineId, () => operation, options); } } function apply(pipelineId) { return (options) => { const pipeline = getPipeline(pipelineId, options); if (!pipeline) { const message = pipelineId ? `Failed to apply pipeline '${String(pipelineId)}'. Unknown pipeline` : "Failed to apply pipeline. No id provided"; throw new Error(message); } prepareAndSetPipeline(pipelineId, pipeline, options); return (next) => { const operation = getPipeline(pipelineId, options); const fn = typeof operation === "function" ? operation(options)(noopNext) : void 0; if (fn) { setPipeline(pipelineId, () => () => fn, options); } return async (state) => { const nextState = await next(state); return fn ? fn(removeFlip(nextState)) : nextState; }; }; }; } // src/operations/alt.ts var pipeIfArray = (def) => Array.isArray(def) ? pipe(def, true) : def; async function runAltPipeline(pipeline, state) { const afterState = await pipeline(markAsUntouched(state)); return isUntouched(afterState) ? setStateValue(afterState, void 0) : afterState; } function createOneAltPipeline(def, index, hasOnlyOneAlt) { return (options) => { const pipeline = pipeIfArray(defToOperations(def, options))(options)( noopNext ); const isFirst = !hasOnlyOneAlt && index === 0; const { nonvalues } = options; return (next) => async (state) => { const nextState = await next(state); if (!isFirst && !isNonvalueState(nextState, nonvalues)) { return nextState; } const beforeState = isFirst ? nextState : popContext(nextState); const afterState = await runAltPipeline(pipeline, beforeState); return isNonvalueState(afterState, nonvalues) ? setValueFromState(nextState, afterState, isFirst) : afterState; }; }; } function alt(...defs) { const hasOnlyOneAlt = defs.length === 1; return defs.map( (def, index) => createOneAltPipeline(def, index, hasOnlyOneAlt) ); } // src/operations/merge.ts import deepmerge from "deepmerge"; function mergeExisting(target, source) { if (Array.isArray(target)) { const arr = source.slice(); target.forEach((value, index) => { arr[index] = deepmerge(source[index], value, { arrayMerge: mergeExisting }); }); return arr; } return target; } function mergeStates(state, thisState) { const target = getStateValue(state); const source = getStateValue(thisState); const value = !isObject(source) ? target : !isObject(target) ? source : deepmerge(target, source, { arrayMerge: mergeExisting }); return setStateValue(state, value); } // src/operations/concat.ts var merge = (left, right) => Array.isArray(right) ? [...left, ...right] : [...left, right]; async function getAndMergeArrays(state, fns) { let nextValue = []; for (const fn of fns) { const value = getStateValue(await fn(state)); nextValue = merge(nextValue, value); } return setStateValue( state, nextValue.filter((val) => val !== void 0) ); } async function setArrayOnFirstOperation(state, fns) { let valueState = await fns[0](state); for (const fn of fns.slice(1)) { const thisState = await fn(setStateValue(state, [])); valueState = mergeStates(valueState, thisState); } return valueState; } function concatPipelines(defs, flip) { return (options) => { const fns = defs.map( (def) => defToOperation(def, options)(options)(noopNext) ); if (fns.length === 0) { return (next) => async (state) => setStateValue(await next(state), revFromState(state, flip) ? {} : []); } return (next) => async function doConcat(state) { const nextState = flipState(await next(state), flip); return revFromState(nextState) ? setArrayOnFirstOperation(nextState, fns) : getAndMergeArrays(nextState, fns); }; }; } function concat(...defs) { return concatPipelines(defs, false); } function concatRev(...defs) { return concatPipelines(defs, true); } // src/operations/lookup.ts import mapAny2 from "map-any-cjs/async.js"; var FLATTEN_DEPTH = 1; var flattenIfArray = (data) => Array.isArray(data) ? data.flat(FLATTEN_DEPTH) : data; var findAllMatches = (value, state, arr, getProp) => arr.filter((val) => getProp(val, state) === value); var findOneMatch = (value, state, arr, getProp) => arr.find((val) => getProp(val, state) === value); var matchInArray = (getArray, match, getProp) => (state) => { const getFn = getArray({})(noopNext); return async (value) => { const { value: arr } = await getFn(goForward(state)); if (Array.isArray(arr)) { return match(value, state, arr, getProp); } else if (isObject(arr)) { return match(value, state, [arr], getProp); } else { return void 0; } }; }; function lookup({ arrayPath, propPath, matchSeveral = false, flip = false }) { return (options) => { if (typeof propPath !== "string" && propPath !== void 0) { throw new TypeError( "The 'lookup' operation does not allow `path` (the prop path) to be a pipeline" ); } const getter = pathGetter(propPath); const matchFn = matchInArray( defToOperation(arrayPath, options), matchSeveral ? findAllMatches : findOneMatch, getter ); const extractProp = (state) => async (value) => getter(value, state); return (next) => async function doLookup(state) { const nextState = await next(state); const value = getStateValue(nextState); const rev2 = revFromState(state, flip); const matcher = rev2 ? extractProp : matchFn; const matches = await mapAny2(matcher(nextState), value); return setStateValue(nextState, flattenIfArray(matches)); }; }; } function lookdown(props2) { return lookup({ ...props2, flip: !props2.flip }); } // src/utils/escape.ts var unescapeValue = (value) => value === "**undefined**" ? void 0 : value; // src/utils/definitionHelpers.ts var passStateThroughNext = (next) => async (state) => next(state); var nonOperatorKeys = [ "$iterate", "$modify", "$noDefaults", "$flip", "$direction" ]; var isOperatorKey = (key) => key[0] === "$" && !nonOperatorKeys.includes(key); var isOperationObject = (def) => isObject(def) && Object.keys(def).filter(isOperatorKey).length > 0; var isOperationType = (def, prop) => def.hasOwnProperty(prop); var pipeIfArray2 = (operations) => Array.isArray(operations) ? pipe(operations) : operations; var isPath = (def) => typeof def === "string"; var isTransformObject = (def) => isObject(def) && !isOperationObject(def); var isPipeline = (def) => Array.isArray(def); var isOperation = (def) => typeof def === "function"; var isTransformDefinition = (def) => isPath(def) || isObject(def) || isPipeline(def) || isOperation(def); var wrapInNoDefaults = (fn) => (options) => (next) => { const stateMapper = fn(options)(next); return async (state) => { const stateWithNoDefaults = { ...state, noDefaults: true }; return stateMapper(stateWithNoDefaults); }; }; function wrapFromDefinition(ops, def) { const opsWithNoDefaults = def.$noDefaults === true ? wrapInNoDefaults(pipeIfArray2(ops)) : ops; const fn = def.$iterate === true ? iterate(opsWithNoDefaults) : opsWithNoDefaults; return (options) => { const dir = def.$direction; if (typeof dir === "string") { if (dir === "rev" || dir === options.revAlias) { return rev(fn)(options); } else if (dir === "fwd" || dir === options.fwdAlias) { return fwd(fn)(options); } } return Array.isArray(fn) ? pipe(fn, true)(options) : fn(options); }; } var humanizeOperatorName = (operatorProp) => `${operatorProp[1].toUpperCase()}${operatorProp.slice(2)}`; var createOperation = (operationFn, fnProp, def) => (options) => { const { [fnProp]: fnId, ...props2 } = def; let transformFn; if (typeof fnId === "function") { transformFn = fnId; } else { if (typeof fnId !== "string" && typeof fnId !== "symbol") { throw new Error( `${humanizeOperatorName( fnProp )} operator was given no transformer id or an invalid transformer id` ); } const fn = options.transformers && options.transformers[fnId]; if (typeof fn !== "function") { throw new Error( `${humanizeOperatorName( fnProp )} operator was given the unknown transformer id '${String(fnId)}'` ); } transformFn = fn(props2); } return typeof transformFn === "function" ? wrapFromDefinition(operationFn(transformFn), def)(options) : passStateThroughNext; }; var createTransformOperation = (def) => createOperation(transform, "$transform", def); var createFilterOperation = (def) => createOperation(filter, "$filter", def); var setNoneValuesOnOptions = (options, nonvalues) => Array.isArray(nonvalues) ? { ...options, nonvalues: nonvalues.map(unescapeValue) } : options; var createAltOperation = (operationFn, def) => (options) => { const { $alt: defs, $undefined: nonvalues } = def; return Array.isArray(defs) ? wrapFromDefinition( operationFn(...defs), def )(setNoneValuesOnOptions(options, nonvalues)) : passStateThroughNext; }; var createIfOperation = (def) => (options) => { const { $if: conditionPipeline, then: thenPipeline, else: elsePipeline } = def; return wrapFromDefinition( ifelse_default(conditionPipeline, thenPipeline, elsePipeline), def )(options); }; function createApplyOperation(operationFn, def) { const pipelineId = def.$apply; return wrapFromDefinition(operationFn(pipelineId), def); } function createConcatOperation(operationFn, pipeline) { const pipelines = ensureArray(pipeline); return operationFn(...pipelines); } function createLookupOperation(operationFn, def, arrayPath) { const { path: propPath, ...props2 } = def; return wrapFromDefinition(operationFn({ ...props2, arrayPath, propPath }), def); } function operationFromObject(defRaw, options) { const def = modifyOperationObject(defRaw, options.modifyOperationObject); if (isOperationObject(def)) { if (isOperationType(def, "$transform")) { return createTransformOperation(def); } else if (isOperationType(def, "$filter")) { return createFilterOperation(def); } else if (isOperationType(def, "$if")) { return createIfOperation(def); } else if (isOperationType(def, "$apply")) { return createApplyOperation(apply, def); } else if (isOperationType(def, "$alt")) { return createAltOperation(alt, def); } else if (isOperationType(def, "$concat")) { return createConcatOperation(concat, def.$concat); } else if (isOperationType(def, "$concatRev")) { return createConcatOperation(concatRev, def.$concatRev); } else if (isOperationType(def, "$lookup")) { return createLookupOperation(lookup, def, def.$lookup); } else if (isOperationType(def, "$lookdown")) { return createLookupOperation(lookdown, def, def.$lookdown); } else { return () => () => async (value) => value; } } else { return props(def); } } var defToOperations = (def, options) => isPipeline(def) ? def.flatMap((def2) => defToOperations(def2, options)) : isObject(def) ? operationFromObject(def, options) : isPath(def) ? get(def) : isOperation(def) ? def : () => () => async (value) => value; function defToOperation(def, options) { const operations = isPipeline(def) ? def : defToOperations(def, options); return pipeIfArray2(operations); } // src/operations/modify.ts function modify(def) { return (options) => { const runFn = defToOperation(def, options); return (next) => async (state) => { const nextState = await next(state); const thisState = await runFn(options)(noopNext)(goForward(nextState)); const target = getTargetFromState(nextState); const value = getStateValue(thisState); return setStateValue( nextState, isObject(target) && isObject(value) ? { ...value, ...target } : isObject(value) ? value : target ); }; }; } export { modify as default }; //# sourceMappingURL=modify.js.map