UNPKG

map-transform-cjs

Version:
1,449 lines (1,416 loc) 54.6 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, value3) => ({ ...state, context: [...state.context, value3] }); 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 }, value3, shouldPushContext = false) => shouldPushContext ? { ...pushContext(state, state.value), value: value3 } : { ...state, value: value3 }; var getStateValue = (state) => state.value; var setValueFromState = (state, { value: value3 }, shouldPushContext = false) => setStateValue(state, value3, shouldPushContext); var isNonvalue = (value3, nonvalues = [void 0]) => nonvalues.includes(value3); 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 populateState = (data, { rev: rev2 = false, noDefaults = false, target = void 0 }) => ({ context: [], value: data, target, rev: rev2, noDefaults }); 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 = (value3) => Object.prototype.toString.call(value3) === "[object Object]"; var isString = (value3) => typeof value3 === "string"; var isNullOrUndefined = (value3) => value3 === null || value3 === void 0; var isNotNullOrUndefined = (value3) => !isNullOrUndefined(value3); var isNonEmptyArray = (value3) => Array.isArray(value3) && value3.length > 0; // src/operations/getSet.ts import mapAny from "map-any-cjs"; // 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 value3 = getStateValue(thisState); return setStateValue( nextState, isObject(target) && isObject(value3) ? { ...value3, ...target } : isObject(value3) ? value3 : target ); }; }; } // src/utils/array.ts var ensureArray = (value3, nonvalues) => Array.isArray(value3) ? value3 : isNonvalue(value3, nonvalues) ? [] : [value3]; var indexOfIfArray = (arr, index2) => Array.isArray(arr) && typeof index2 === "number" ? arr[index2] : arr; // src/operations/getSet.ts var adjustIsSet = (isSet, state) => revFromState(state, isSet); function flatMapAny(fn) { return (value3, target) => Array.isArray(value3) ? value3.flatMap((value4) => fn(value4, target)) : fn(value3, 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 (value3) => value3; } const getFn = flatMapAny( (value3) => isObject(value3) ? value3[path] : void 0 ); const setFn = (value3, target) => isObject(target) ? { ...target, [path]: value3 } : { [path]: value3 }; return (value3, isSet, target) => { if (isSet) { return setFn(value3, target); } else { return getFn(value3); } }; } var calculateIndex = (index2, arr) => index2 >= 0 ? index2 : arr.length + index2; function getSetIndex(index2) { return (value3, isSet, target) => { if (isSet) { const arr = Array.isArray(target) ? [...target] : []; arr[calculateIndex(index2, arr)] = value3; return arr; } else { return Array.isArray(value3) ? value3[calculateIndex(index2, value3)] : 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(value3, state, options) { const { modifyGetValue } = options; return typeof modifyGetValue === "function" ? modifyGetValue(value3, state, options) : value3; } 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 = (value4, index2) => getSetFn(value4, true, indexOfIfArray(target, index2)); const nextValue = getStateValue(nextState); if (state.noDefaults && isNonvalue(nextValue, options.nonvalues)) { return setStateValue(state, target); } const value3 = isArr2 ? ensureArray(nextValue, options.nonvalues) : nextValue; const thisValue = nextState.iterate && !isArr2 && !isIndexProp ? mapAny(setIt, value3) : setIt(value3); return setStateValue(state, thisValue); } else { const nextState = await next(state); const thisValue = getSetFn(getStateValue(nextState), false); const modifiedValue = doModifyGetValue(thisValue, nextState, options); const value3 = state.noDefaults && isNonvalue(modifiedValue, options.nonvalues) ? void 0 : isArr2 ? ensureArray(modifiedValue, options.nonvalues) : modifiedValue; return setStateValue( nextState, value3, true // Push to context ); } }; }; } function resolveArrayNotation(path, pos) { const index2 = Number.parseInt(path.slice(pos + 1), 10); if (!Number.isNaN(index2)) { const basePath = path.slice(0, pos).trim(); return basePath ? [`${basePath}][`, index2] : [index2]; } 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) => (value3) => { if (typeof part === "string") { if (isObject(value3)) { const nextValue = value3[part]; return isArr2 ? ensureArray(nextValue) : nextValue; } } else if (typeof part === "number" && Array.isArray(value3)) { return value3[calculateIndex(part, value3)]; } 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 (value3) => [fn(value3), void 0]; } else { const fn = flatMapAny(getByPart(part, isArr2)); return (value3) => [fn(value3), void 0]; } } var setOnObject = (part) => (value3) => part ? { [part]: value3 } : value3; var setByPart = (part, isArr2, doIterate) => (value3) => { const data = isArr2 ? ensureArray(value3) : value3; if (typeof part === "number") { const arr = []; const index2 = part < 0 ? 0 : part; arr[index2] = data; return arr; } else { return doIterate ? mapAny(setOnObject(part), data) : setOnObject(part)(data); } }; function getDoIterateFromLastPart(parts) { if (parts.length === 0) { return false; } const lastPart = parts[parts.length - 1]; return lastPart[1] || lastPart[2]; } var setDoIterateOnParts = (parts, [part, isArr2]) => [ ...parts, [part, isArr2, isArr2 ? false : getDoIterateFromLastPart(parts)] ]; function pathGetter(path, _options = {}) { if (!path || path === ".") { return (value3) => value3; } const parts = path.split(".").flatMap(splitUpArrayAndParentNotation).map(preparePath).map(prepareGetFn); return function getFromPath(value3, startState) { let data = value3; let state = startState; for (const partOrGetFn of parts) { ; [data, state = state] = partOrGetFn(data, state); } return data; }; } function pathSetter(path, options = {}) { if (typeof path !== "string" || path === "" || path === ".") { return (value3) => value3; } else if (path[0] === "^") { return () => void 0; } const setFns = path.split(".").flatMap(splitUpArrayAndParentNotation).map(preparePath).reduce(setDoIterateOnParts, []).map(([part, isArr2, doIterate]) => setByPart(part, isArr2, doIterate)); return function setToPath(value3, state) { if (state.noDefaults && isNonvalue(value3, options.nonvalues)) { return void 0; } else { return setFns.reduceRight((value4, setFn) => setFn(value4), value3); } }; } var get = (path) => pathToNextOperations(path, false); var set = (path) => pathToNextOperations(path, true); // src/operations/iterate.ts var runIterationStep = async (fn, state, value3, index2, target) => getStateValue( await fn( setTargetOnState( { ...state, index: index2, value: value3 }, indexOfIfArray(target, index2) ) ) ); 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 [index2, value3] of values.entries()) { nextValue.push( await runIterationStep(fn, nextState, value3, index2, 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 value3 = await fn2(getStateValue(nextState), nextState); return setStateValue(nextState, value3); }; }; } // 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 [index2, 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(index2 + 1)]), [ step.slice(pos + 3), ...defs.slice(index2 + 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 index2 = path.indexOf("$modify"); return index2 > -1 && // We have a $modify (index2 === 0 || path[index2 - 1] === ".") && // It's either the first char, or preceded by a dot (path.length === index2 + 7 || path[index2 + 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 value3 = getStateValue(nextState); return isObject(target) && isObject(value3) ? setStateValue(nextState, { ...target, ...value3 }) : nextState; }; function runOperationWithOriginalValue({ value: value3 }) { return async (state, fn) => { const nextState = await fn(setStateValue(state, value3)); 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 = (value3) => !Number.isNaN(Number.parseInt(value3, 10)); function removeSlash(prop) { const index2 = prop.indexOf("/"); if (index2 > -1 && prop[index2 - 1] !== "\\" && isNumeric(prop.slice(index2 + 1))) { return prop.slice(0, index2); } 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 value3 of values) { if (await filterFn(value3, state)) { results.push(value3); } } 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, index2, hasOnlyOneAlt) { return (options) => { const pipeline = pipeIfArray(defToOperations(def, options))(options)( noopNext ); const isFirst = !hasOnlyOneAlt && index2 === 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, index2) => createOneAltPipeline(def, index2, hasOnlyOneAlt) ); } // src/operations/merge.ts import deepmerge from "deepmerge"; function mergeExisting(target, source) { if (Array.isArray(target)) { const arr = source.slice(); target.forEach((value3, index2) => { arr[index2] = deepmerge(source[index2], value3, { arrayMerge: mergeExisting }); }); return arr; } return target; } function mergeStates(state, thisState) { const target = getStateValue(state); const source = getStateValue(thisState); const value3 = !isObject(source) ? target : !isObject(target) ? source : deepmerge(target, source, { arrayMerge: mergeExisting }); return setStateValue(state, value3); } function merge(...defs) { return (options) => (next) => { if (defs.length === 0) { return async (state) => setStateValue(await next(state), void 0); } const pipelines = defs.map( (def) => defToOperation(def, options)(options)(next) ); return async function(state) { const nextState = await next(state); if (isNonvalueState(nextState, options.nonvalues)) { return setStateValue(nextState, void 0); } else { const states = []; for (const pipeline of pipelines) { states.push(await pipeline(nextState)); } return states.reduce(mergeStates); } }; }; } // src/operations/concat.ts var merge2 = (left, right) => Array.isArray(right) ? [...left, ...right] : [...left, right]; async function getAndMergeArrays(state, fns) { let nextValue = []; for (const fn of fns) { const value3 = getStateValue(await fn(state)); nextValue = merge2(nextValue, value3); } 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 = (value3, state, arr, getProp) => arr.filter((val) => getProp(val, state) === value3); var findOneMatch = (value3, state, arr, getProp) => arr.find((val) => getProp(val, state) === value3); var matchInArray = (getArray, match, getProp) => (state) => { const getFn = getArray({})(noopNext); return async (value3) => { const { value: arr } = await getFn(goForward(state)); if (Array.isArray(arr)) { return match(value3, state, arr, getProp); } else if (isObject(arr)) { return match(value3, 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 (value3) => getter(value3, state); return (next) => async function doLookup(state) { const nextState = await next(state); const value3 = getStateValue(nextState); const rev2 = revFromState(state, flip); const matcher = rev2 ? extractProp : matchFn; const matches = await mapAny2(matcher(nextState), value3); return setStateValue(nextState, flattenIfArray(matches)); }; }; } function lookdown(props2) { return lookup({ ...props2, flip: !props2.flip }); } // src/utils/escape.ts var escapeValue = (value3) => value3 === void 0 ? "**undefined**" : value3; var unescapeValue = (value3) => value3 === "**undefined**" ? void 0 : value3; // 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 (value3) => value3; } } 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 (value3) => value3; function defToOperation(def, options) { const operations = isPipeline(def) ? def : defToOperations(def, options); return pipeIfArray2(operations); } function operationToDataMapper(operation, options) { const fn = operation(options)(noopNext); return async (value3, state) => getStateValue(await fn(setStateValue(state, value3))); } function defToDataMapper(def, options = {}) { return operationToDataMapper(defToOperation(def, options), options); } // src/transformers/value.ts var extractValue = (value3) => { const val = isObject(value3) ? value3.value : value3; return unescapeValue(typeof val === "function" ? val() : val); }; var value = function value2(props2) { const value3 = extractValue(props2); return () => (_data, state) => state.noDefaults ? void 0 : value3; }; var fixed = function fixed2(props2) { const value3 = extractValue(props2); return () => () => value3; }; // src/transformers/bucket.ts function addToBucket(value3, buckets, key) { const bucket3 = buckets.get(key); if (bucket3) { bucket3.push(value3); } else { buckets.set(key, [value3]); } } async function sortIntoBuckets(getFn, pipelines, getGroupFn, data, state, nonvalues) { const arr = ensureArray(getFn(data, state)); const retBucket = /* @__PURE__ */ new Map(); if (pipelines.length > 0) { for (const value3 of arr) { for (const [pipeline, key] of pipelines) { const result = await pipeline(value3, state); if (result) { addToBucket(value3, retBucket, key); break; } } } } else if (getGroupFn) { for (const value3 of arr) { const key = await getGroupFn(value3, state); if (!isNonvalue(key, nonvalues)) { addToBucket(value3, retBucket, String(key)); } } } return Object.fromEntries(retBucket.entries()); } function shouldGoInBucket(options, condition, size) { let inBucket = 0; const mapper = condition ? defToDataMapper(condition, options) : void 0; return async function considerItemForBucket(item, state) { if (size === void 0 || inBucket < size) { if (!mapper || await mapper(item, state)) { inBucket++; return true; } } return false; }; } var extractArrayFromBuckets = (buckets, keys, nonvalues) => isObject(buckets) ? (keys || Object.keys(buckets)).flatMap((key) => buckets[key]).filter((key) => !isNonvalue(key, nonvalues)) : []; var prepareGroupByPathFn = (pipeline, options) => typeof pipeline === "string" ? pathGetter(pipeline) : pipeline === void 0 ? void 0 : defToDataMapper(pipeline, options); var extractBucketKeys = (buckets, hasGroupFn) => buckets.length === 0 && hasGroupFn ? void 0 : buckets.map(({ key }) => key); var transformer2 = function bucket({ path = ".", buckets = [], groupByPath }) { return (options) => { const getFn = pathGetter(path); const setFn = pathSetter(path, options); const getGroupByPathFn = prepareGroupByPathFn(groupByPath, options); const pipelines = buckets.filter(({ key }) => typeof key === "string").map((bucket3) => [ shouldGoInBucket( options, bucket3.condition ?? bucket3.pipeline, // Keep `pipeline` as an alias of `condition` for backwards compatibility. TODO: Remove in v2 bucket3.size ), bucket3.key ]); const keys = extractBucketKeys(buckets, !!getGroupByPathFn); return async (data, state) => { if (revFromState(state)) { return setFn( extractArrayFromBuckets(data, keys, options.nonvalues), state ); } else { return sortIntoBuckets( getFn, pipelines, getGroupByPathFn, data, state, options.nonvalues ); } }; }; }; var bucket_default = transformer2; // src/transformers/compare.ts import mapAny3 from "map-any-cjs"; var not = (comparer) => (value3, match) => !comparer(value3, match); var compareArrayOrValue = (comparer) => (value3, match) => Array.isArray(value3) ? value3.some((value4) => comparer(value4, match)) : comparer(value3, match); var isNumeric2 = (value3) => typeof value3 === "number"; var compareArrayOrValueNumeric = (comparer) => compareArrayOrValue( (value3, match) => isNumeric2(value3) && isNumeric2(match) && comparer(value3, match) ); var compareEqual = compareArrayOrValue( (value3, match) => value3 === match ); var compareIn = (value3, match) => Array.isArray(match) ? match.some((item) => compareEqual(value3, item)) : compareEqual(value3, match); var exists = (value3) => value3 !== void 0; function getGtLtComparer(operator) { switch (operator) { case ">": return (value3, match) => value3 > match; case ">=": return (value3, match) => value3 >= match; case "<": return (value3, match) => value3 < match; case "<=": return (value3, match) => value3 <= match; } } function createComparer(operator) { switch (operator) { case "=": return compareEqual; case "!=": return not(compareEqual); case "in": return compareIn; case "exists": return exists; case ">": case ">=": case "<": case "<=": return compareArrayOrValueNumeric(getGtLtComparer(operator)); default: return (_value, _match) => false; } } var transformer3 = function compare({ path = ".", operator = "=", match, value: value3, matchPath, valuePath, not: not3 = false }) { match = match === void 0 ? value3 : match; matchPath = matchPath ?? valuePath; return (options) => { const realMatchValue = mapAny3(unescapeValue, match); const comparer = createComparer(operator); const getMatch = typeof matchPath === "string" ? pathGetter(matchPath) : () => realMatchValue; if (typeof path === "string" || !path) { const getValue = pathGetter(path); return (data, state) => { const value4 = getValue(data, state); const match2 = getMatch(data, state); return xor(comparer(value4, match2), not3); }; } else { const getValue = defToDataMapper(path, options); return async (data, state) => { const value4 = await getValue(data, goForward(state)); const match2 = getMatch(data, state); return xor(comparer(value4, match2), not3); }; } }; }; var compare_default = transformer3; // src/transformers/explode.ts var isExplodedArray = (data) => data.length > 0 && data.every((item) => isObject(item) && typeof item.key === "number"); var setValueOnKey = (target, keyValue) => { if (isObject(keyValue)) { const { key, value: value3 } = keyValue; if (Array.isArray(target)) { target[key] = value3; } else { target[String(key)] = value3; } } return target; }; function doImplode(data) { if (Array.isArray(data)) { return data.reduce( setValueOnKey, isExplodedArray(data) ? [] : {} ); } else { return void 0; } } function doExplode(data) { if (isObject(data)) { return Object.entries(data).filter(([, value3]) => value3 !== void 0).map(([key, value3]) => ({ key, value: value3 })); } else if (Array.isArray(data)) { return data.map((value3, key) => ({ key, value: value3 })); } else { return void 0; } } function explodeOrImplode(isImplode) { return () => () => async (data, state) => revFromState(state, isImplode) ? doImplode(data) : doExplode(data); } var explode = explodeOrImplode(false); var implode = explodeOrImplode(true); // src/transformers/get.ts var extractPath = (path) => typeof path === "string" ? path : path.path; var transformer4 = function get2(props2) { return () => { const path = extractPath(props2) || "."; if (typeof path !== "string" && path !== void 0) { throw new TypeError( "The 'get' transformer does not allow `path` to be a pipeline" ); } const mapper = pathGetter(path); return (data, state) => mapper(data, state); }; }; var get_default = transformer4; // src/transformers/indexFn.ts var transformer5 = function index() { return () => (_data, state) => { return state.index || 0; }; }; var indexFn_default = transformer5; // src/transformers/logical.ts var getLogicalFn = (operator) => operator === "OR" ? (a, b) => Boolean(a) || Boolean(b) : (a, b) => Boolean(a) && Boolean(b); var transformer6 = function logical({ path = ".", operator = "AND" }) { return (options) => { const pathArr = ensureArray(path); const getFns = pathArr.map((path2) => defToDataMapper(path2, options)); const setFns = pathArr.map((path2) => defToDataMapper(`>${path2}`, options)); const logicalOp = getLogicalFn(operator); return async (data, state) => { if (state.rev) { const value3 = Boolean(data); let obj; for (const setFn of setFns) { obj = await setFn(value3, setTargetOnState(goForward(state), obj)); } return obj; } else { const values = []; for (const getFn of getFns) { values.push(await getFn(data, state)); } return values.reduce(logicalOp); } }; }; }; var logical_default = transformer6; // src/transformers/map.ts import mapAny4 from "map-any-cjs"; var isSupportedValue = (data) => ["string", "number", "boolean"].includes(typeof data) || data === null || data === void 0; function findFirstMatch(value3, dictionary, direction) { const match = dictionary.find((dict) => dict[direction] === value3); return match ? match[1 - direction] : void 0; } function translate(data, dictionary, rev2) { const direction = Number(rev2); return mapAny4((data2) => { const value3 = isSupportedValue(data2) ? data2 : void 0; const match = findFirstMatch(value3, dictionary, direction); if (match === void 0 || match === "*") { const starMatch = findFirstMatch("*", dictionary, direction); return starMatch === void 0 ? match : starMatch; } return match; }, data); } function extractDictionary(dictionary, dictionaries) { if (typeof dictionary === "string") { return dictionaries && dictionaries[dictionary]; } else { return dictionary; } } var escapeDictionary = (dictionary) => dictionary ? dictionary.map(([from, to]) => [escapeValue(from), escapeValue(to)]) : void 0; var transformer7 = function map(props2) { return (options) => { const dictionary = escapeDictionary( extractDictionary(props2.dictionary, options && options.dictionaries) ); if (!dictionary) { return () => void 0; } return (data, state) => { const { rev: rev2 = false } = state; const match = translate(escapeValue(data), dictionary, rev2); return match === "*" ? data : unescapeValue(match); }; }; }; var map_default = transformer7; // src/transformers/merge.ts var undefinedFirst = ([_a, a], [_b, b]) => b === void 0 && a !== void 0 ? 1 : a === void 0 ? -1 : 0; function mergeTransformer({ path }, flip) { return (options) => { const getFns = ensureArray(path).map( (path2) => defToDataMapper(path2, options) ); return async function mergePipelines(data, state) { const values = []; for (const fn of getFns) { values.push(await fn(data, flipState(state, flip))); } return Object.fromEntries( values.flat().filter(isObject).flatMap(Object.entries).sort(undefinedFirst) ); }; }; } var merge3 = function merge4(props2) { return mergeTransformer(props2, false); }; var mergeRev = function mergeRev2(props2) { return mergeTransformer(props2, true); }; // src/transformers/not.ts function dataMapperFromProps(props2, options) { if (typeof props2 === "function") { return props2(options); } else if (isObject(props2)) { return defToDataMapper(props2.path, options); } else { return (value3) => value3; } } v