map-transform-cjs
Version:
MapTransform with CJS support
1,449 lines (1,416 loc) • 54.6 kB
JavaScript
// 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