* override jsonLogic operators on string operands to allow for case insensitive comparisons. Affected Operators: "==", "===", "!=", "!==", "in" * disable no-explicit-any on jsonLogicOverrides file since most of the code there will be from jsonLogic and may not meet our coding style. Majority of overrides require us to copy over functions and their signatures from jsonLogic and then modify their implementation. The signature of functions implementing most operators take the operands typed as "any", which is intended, but doesn't adhere to our coding style. Hence the need to override the eslint rule * run linter to fix issues * Fix bug in in operator when second arg is an array * remove redundant indexOf check on overriden jsonLogic "in" operator. Note: this deviates from the original implementation in the jsonLogic library because our current useage ensures that the second operand is always a string or string[] and will therefore always have .index function. Whenever our invariants change in the future, make sure to modify this implementation to prevent any unexpected --------- Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import type { App_RoutingForms_Form } from "@prisma/client";
|
|
import { Utils as QbUtils } from "react-awesome-query-builder";
|
|
import type { z } from "zod";
|
|
|
|
import type { Response, Route, SerializableForm } from "../types/types";
|
|
import type { zodNonRouterRoute } from "../zod";
|
|
import { getQueryBuilderConfig } from "./getQueryBuilderConfig";
|
|
import { isFallbackRoute } from "./isFallbackRoute";
|
|
import isRouter from "./isRouter";
|
|
import jsonLogic from "./jsonLogicOverrides";
|
|
|
|
export function processRoute({
|
|
form,
|
|
response,
|
|
}: {
|
|
form: SerializableForm<App_RoutingForms_Form>;
|
|
response: Record<string, Pick<Response[string], "value">>;
|
|
}) {
|
|
const queryBuilderConfig = getQueryBuilderConfig(form);
|
|
|
|
const routes = form.routes || [];
|
|
|
|
let decidedAction: Route["action"] | null = null;
|
|
|
|
const fallbackRoute = routes.find(isFallbackRoute);
|
|
|
|
if (!fallbackRoute) {
|
|
throw new Error("Fallback route is missing");
|
|
}
|
|
|
|
const routesWithFallbackInEnd = routes
|
|
.flatMap((r) => {
|
|
// For a router, use it's routes instead.
|
|
if (isRouter(r)) return r.routes;
|
|
return r;
|
|
})
|
|
// Use only non fallback routes
|
|
.filter((route) => route && !isFallbackRoute(route))
|
|
// After above flat map, all routes are non router routes.
|
|
.concat([fallbackRoute]) as z.infer<typeof zodNonRouterRoute>[];
|
|
|
|
routesWithFallbackInEnd.some((route) => {
|
|
if (!route) {
|
|
return false;
|
|
}
|
|
const state = {
|
|
tree: QbUtils.checkTree(QbUtils.loadTree(route.queryValue), queryBuilderConfig),
|
|
config: queryBuilderConfig,
|
|
};
|
|
const jsonLogicQuery = QbUtils.jsonLogicFormat(state.tree, state.config);
|
|
const logic = jsonLogicQuery.logic;
|
|
let result = false;
|
|
const responseValues: Record<string, string | string[]> = {};
|
|
for (const [uuid, { value }] of Object.entries(response)) {
|
|
responseValues[uuid] = value;
|
|
}
|
|
|
|
if (logic) {
|
|
// Leave the logs for easy debugging of routing form logic test.
|
|
console.log("Checking logic with response", logic, responseValues);
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
result = jsonLogic.apply(logic as any, responseValues);
|
|
} else {
|
|
// If no logic is provided, then consider it a match
|
|
result = true;
|
|
}
|
|
if (result) {
|
|
decidedAction = route.action;
|
|
return true;
|
|
}
|
|
});
|
|
|
|
if (!decidedAction) {
|
|
return null;
|
|
}
|
|
|
|
// Without type assertion, it is never. See why https://github.com/microsoft/TypeScript/issues/16928
|
|
return decidedAction as Route["action"];
|
|
}
|