map-transform-cjs
Version:
MapTransform with CJS support
1,027 lines (1,003 loc) • 36 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, 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/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
);
};
};
}
// 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/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/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/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/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/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/root.ts
function root_default(def) {
return (options) => {
const pipeline = [get("^^"), defToOperations(def, options)].flat();
return pipe(pipeline)(options);
};
}
export {
root_default as default
};
//# sourceMappingURL=root.js.map