UNPKG

@react-query-builder-express/core

Version:
1,125 lines (1,108 loc) 47.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.loadFromJsonLogic = exports._loadFromJsonLogic = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _uuid = _interopRequireDefault(require("../utils/uuid")); var _stuff = require("../utils/stuff"); var _configUtils = require("../utils/configUtils"); var _ruleUtils = require("../utils/ruleUtils"); var _tree = require("./tree"); var _defaultUtils = require("../utils/defaultUtils"); var _moment = _interopRequireDefault(require("moment")); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } // http://jsonlogic.com/ // helpers var arrayUniq = function arrayUniq(arr) { return Array.from(new Set(arr)); }; // constants var jlFieldMarker = "jlField"; var jlArgsMarker = "jlArgs"; var jlEqOps = ["==", "!="]; var jlRangeOps = ["<", "<=", ">", ">="]; var multiselectOps = ["multiselect_equals", "multiselect_not_equals", "multiselect_contains", "multiselect_not_contains"]; var createMeta = function createMeta(parentMeta) { return { errors: [], settings: parentMeta === null || parentMeta === void 0 ? void 0 : parentMeta.settings }; }; var loadFromJsonLogic = exports.loadFromJsonLogic = function loadFromJsonLogic(logicTree, config) { return _loadFromJsonLogic(logicTree, config, false); }; var _loadFromJsonLogic = exports._loadFromJsonLogic = function _loadFromJsonLogic(logicTree, config) { var returnErrors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; //meta is mutable var meta = createMeta(); meta.settings = { allowUnknownFields: false, returnErrors: returnErrors }; var extendedConfig = (0, _configUtils.extendConfig)(config, undefined, false); var conv = buildConv(extendedConfig); var jsTree = logicTree ? convertFromLogic(logicTree, conv, extendedConfig, ["rule", "group", "switch"], meta) : undefined; var immTree = jsTree ? (0, _tree.loadTree)(jsTree) : undefined; if (returnErrors) { return [immTree, meta.errors]; } else { if (meta.errors.length) console.warn("Errors while importing from JsonLogic:", meta.errors); return immTree; } }; var buildConv = function buildConv(config) { var operators = {}; var combinationOperators = {}; for (var opKey in config.operators) { var opConfig = config.operators[opKey]; if (typeof opConfig.jsonLogic == "string") { // example: "</2", "#in/1" var opk = opConfig.jsonLogic + "/" + (0, _stuff.getOpCardinality)(opConfig); if (!operators[opk]) operators[opk] = []; operators[opk].push(opKey); } else if (typeof opConfig.jsonLogic2 == "string") { // example: all-in/1" var _opk = opConfig.jsonLogic2 + "/" + (0, _stuff.getOpCardinality)(opConfig); if (!operators[_opk]) operators[_opk] = []; operators[_opk].push(opKey); if (!combinationOperators[opKey]) combinationOperators[opKey] = {}; combinationOperators[opKey] = { "template": opConfig.jsonLogic(jlFieldMarker, opKey, jlArgsMarker), "jsonLogic2": opConfig.jsonLogic2, "_jsonLogicIsExclamationOp": !!opConfig._jsonLogicIsExclamationOp }; } } var conjunctions = {}; for (var conjKey in config.conjunctions) { var conjunctionDefinition = config.conjunctions[conjKey]; var ck = conjunctionDefinition.jsonLogicConj || conjKey.toLowerCase(); conjunctions[ck] = conjKey; } var funcs = {}; var _iterator = _createForOfIteratorHelper((0, _configUtils.iterateFuncs)(config)), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var _step$value = (0, _slicedToArray2["default"])(_step.value, 2), funcPath = _step$value[0], funcConfig = _step$value[1]; var fk = void 0; if (funcConfig.jsonLogicIsMethod) { fk = "#" + funcConfig.jsonLogic; } else if (typeof funcConfig.jsonLogic == "string") { fk = funcConfig.jsonLogic; } if (fk) { if (!funcs[fk]) funcs[fk] = []; funcs[fk].push(funcPath); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var _config$settings$json = config.settings.jsonLogic, groupVarKey = _config$settings$json.groupVarKey, altVarKey = _config$settings$json.altVarKey; return { operators: operators, conjunctions: conjunctions, funcs: funcs, varKeys: ["var", groupVarKey, altVarKey], combinationOperators: combinationOperators }; }; /** * This function checks a given jsonlogic object against a set of templates defined in 'conv'. * It determines if the jsonlogic object matches any of the specified templates. * * @param {*} jsonlogic The jsonlogic object to be matched against the templates. * @param {*} conv The object containing all potential templates and their associated logic for matching. * It is expected to have a 'combinationOperators' property that houses the templates. * @param {*} meta An object where any errors or metadata during the processing are stored. It's modified by reference. * @param {*} operatorsToCheck An optional array of operator keys that limits which operators in 'conv' are checked. * If null, all operators in 'conv' are considered. * @returns {Object|null} The response object containing the match result, and any relevant matched fields and * arguments if a match is found. Returns null if no match is found. */ var matchAgainstTemplates = function matchAgainstTemplates(jsonlogic, conv, meta) { var operatorsToCheck = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; var response; if (conv !== null && conv !== void 0 && conv.combinationOperators) { for (var _i = 0, _Object$entries = Object.entries(conv.combinationOperators); _i < _Object$entries.length; _i++) { var _Object$entries$_i = (0, _slicedToArray2["default"])(_Object$entries[_i], 2), key = _Object$entries$_i[0], value = _Object$entries$_i[1]; if (operatorsToCheck == null || operatorsToCheck.includes(key)) { var tempResponse = isTemplateMatch(value.template, jsonlogic); // Found a match if (tempResponse.match) { if (!response) response = tempResponse; // Templates should be spesific enough that only one match can be found. This should not happen else meta.errors.push("Operator matched against 2 templates: ".concat(response.newOp, " and ").concat(key)); // New op that is used to represent operator that is combosed of multiple operators response["newOp"] = value.jsonLogic2; } } } } // Returns undefined if no matches found return response; }; /** * This function recursively compares a jsonlogic object against a template to determine if they match structurally and content-wise. * It is used to support complex template matching where the template can include special markers indicating variable fields and arguments. * * @param {*} template The template object to match against, which can include special markers to denote fields and arguments. * @param {*} jsonlogic The jsonlogic object to test against the template. * @param {*} response An object to accumulate results such as whether a match is found, and to collect any fields or arguments identified * by the template markers. Default is initialized to a match state with empty fields and arguments. * @returns {Object} The updated response object after checking the current template level. It includes whether the current level * matches (match: true/false), any identified fields (jlField), and any arguments (jlArgs). */ var isTemplateMatch = function isTemplateMatch(template, jsonlogic) { var response = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { "match": true, "jlField": null, "jlArgs": [] }; if (template == undefined || jsonlogic == undefined) { response.match = false; return response; } // This lets us compare order easily var tKeys = Object.keys(template); var jKeys = Object.keys(jsonlogic); if (tKeys.length !== jKeys.length) { // Both have same length response.match = false; return response; } for (var index = 0; index < tKeys.length; index++) { var key = tKeys[index]; var value = template[key]; if (key !== jKeys[index]) { // Checks that both have exact same key at exact same place. Kind of pointless for arrays but whatever response.match = false; return response; } else if (value === jlFieldMarker && (0, _stuff.isJsonLogic)(jsonlogic[key])) { // If jlFieldMarker is found in template AND it's field or func we take the value from corresponding place in jsonlogic response.jlField = jsonlogic[key]; } else if (value === jlArgsMarker) { // If jlArgsMarker is found in template we take the value from corresponding place in jsonlogic response.jlArgs.push(jsonlogic[key]); } else if ((0, _typeof2["default"])(value) === "object" && value !== null || Array.isArray(value)) { // Here we recurse thru objects and arrays of template until we have gone thru it completely response = isTemplateMatch(value, jsonlogic[key], response); } else if (value !== jsonlogic[key]) { // This is for cases of {var: ""}, which should be only case in default config that leads here response.match = false; return response; } } return response; }; // expectedTypes - "val", "rule", "group", "switch", "case_val" var convertFromLogic = function convertFromLogic(logic, conv, config, expectedTypes, meta) { var not = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; var fieldConfig = arguments.length > 6 ? arguments[6] : undefined; var widget = arguments.length > 7 ? arguments[7] : undefined; var parentField = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : null; var _isLockedLogic = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false; var op, vals; if ((0, _stuff.isJsonLogic)(logic)) { op = Object.keys(logic)[0]; vals = logic[op]; if (!Array.isArray(vals)) vals = [vals]; } var ret; var beforeErrorsCnt = meta.errors.length; var lockedOp = config.settings.jsonLogic.lockedOp; var isEmptyOp = op == "!" && vals.length == 1 && vals[0] && (0, _stuff.isJsonLogic)(vals[0]) && conv.varKeys.includes(Object.keys(vals[0])[0]); // If matchAgainstTemplates returns match then op is replaced with special jsonlogic2 value var match = matchAgainstTemplates(logic, conv, meta); if (match) { // We reset vals if match found vals = []; vals[0] = match.jlField; match.jlArgs.forEach(function (arg) { return vals.push(arg); }); // We reset op to new op that represents multiple jsonlogic operators op = match.newOp; } var isNot = op == "!" && !isEmptyOp; var isLocked = lockedOp && op == lockedOp; var isSwitch = expectedTypes.includes("switch"); var isRoot = isSwitch; if (isLocked) { ret = convertFromLogic(vals[0], conv, config, expectedTypes, meta, not, fieldConfig, widget, parentField, true); } else if (isNot) { // apply not ret = convertFromLogic(vals[0], conv, config, expectedTypes, meta, !not, fieldConfig, widget, parentField); } else if (expectedTypes.includes("val")) { // not is not used here ret = convertFieldRhs(op, vals, conv, config, not, meta, parentField) || convertFuncRhs(op, vals, conv, config, not, fieldConfig, meta, parentField) || convertValRhs(logic, fieldConfig, widget, config, meta); } else { if (expectedTypes.includes("switch")) { ret = convertIf(op, vals, conv, config, not, meta, parentField); } if (ret == undefined && expectedTypes.includes("group")) { ret = convertConj(op, vals, conv, config, not, meta, parentField, false); } if (ret == undefined && expectedTypes.includes("rule")) { ret = convertOp(op, vals, conv, config, not, meta, parentField); } if (ret) { if (isRoot && !["group", "switch_group"].includes(ret.type)) { ret = wrapInDefaultConj(ret, config); } } } var afterErrorsCnt = meta.errors.length; if (op != "!" && ret === undefined && afterErrorsCnt == beforeErrorsCnt) { meta.errors.push("Can't parse logic ".concat(JSON.stringify(logic))); } if (isLocked) { ret.properties.isLocked = true; } return ret; }; var convertValRhs = function convertValRhs(val, fieldConfig, widget, config, meta) { var _fieldConfig$fieldSet; if (val === undefined) val = fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.defaultValue; if (val === undefined) return undefined; widget = widget || (fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.mainWidget); var widgetConfig = config.widgets[widget]; var fieldType = fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type; if (fieldType && !widgetConfig) { meta.errors.push("No widget for type ".concat(fieldType)); return undefined; } if ((0, _stuff.isJsonLogic)(val)) { meta.errors.push("Unexpected logic in value: ".concat(JSON.stringify(val))); return undefined; } // number of seconds -> time string if (fieldType === "time" && typeof val === "number") { var h = Math.floor(val / 60 / 60) % 24, m = Math.floor(val / 60) % 60, s = val % 60; var valueFormat = widgetConfig.valueFormat; if (valueFormat) { var dateVal = new Date(val); dateVal.setMilliseconds(0); dateVal.setHours(h); dateVal.setMinutes(m); dateVal.setSeconds(s); val = (0, _moment["default"])(dateVal).format(valueFormat); } else { val = "".concat(h, ":").concat(m, ":").concat(s); } } // "2020-01-08T22:00:00.000Z" -> Date object if (["date", "datetime"].includes(fieldType) && val && !(val instanceof Date)) { try { var _dateVal = new Date(val); if (_dateVal instanceof Date && _dateVal.toISOString() === val) { val = _dateVal; } } catch (e) { meta.errors.push("Can't convert value ".concat(val, " as Date")); val = undefined; } } // Date object -> formatted string if (val instanceof Date && fieldConfig) { var _valueFormat = widgetConfig.valueFormat; if (_valueFormat) { val = (0, _moment["default"])(val).format(_valueFormat); } } var asyncListValues; if (val && fieldConfig !== null && fieldConfig !== void 0 && (_fieldConfig$fieldSet = fieldConfig.fieldSettings) !== null && _fieldConfig$fieldSet !== void 0 && _fieldConfig$fieldSet.asyncFetch) { var vals = Array.isArray(val) ? val : [val]; asyncListValues = vals; } if (widgetConfig !== null && widgetConfig !== void 0 && widgetConfig.jsonLogicImport) { try { val = widgetConfig.jsonLogicImport.call(config.ctx, val); } catch (e) { var _e$message; meta.errors.push("Can't import value ".concat(val, " using import func of widget ").concat(widget, ": ").concat((_e$message = e === null || e === void 0 ? void 0 : e.message) !== null && _e$message !== void 0 ? _e$message : e)); val = undefined; } } return { valueSrc: "value", value: val, valueType: widgetConfig === null || widgetConfig === void 0 ? void 0 : widgetConfig.type, asyncListValues: asyncListValues }; }; var convertFieldRhs = function convertFieldRhs(op, vals, conv, config, not, meta) { var parentField = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null; if (conv.varKeys.includes(op) && typeof vals[0] == "string") { var _meta$settings; var field = (0, _configUtils.normalizeField)(config, vals[0], parentField); var fieldConfig = (0, _configUtils.getFieldConfig)(config, field); if (!fieldConfig && !((_meta$settings = meta.settings) !== null && _meta$settings !== void 0 && _meta$settings.allowUnknownFields)) { meta.errors.push("No config for field ".concat(field)); return undefined; } return { valueSrc: "field", value: field, valueType: fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type }; } return undefined; }; var convertLhs = function convertLhs(isGroup0, jlField, args, conv, config) { var not = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null; var fieldConfig = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null; var meta = arguments.length > 7 ? arguments[7] : undefined; var parentField = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : null; var k = Object.keys(jlField)[0]; var v = Object.values(jlField)[0]; var _parse = function _parse(k, v) { return convertFieldLhs(k, v, conv, config, not, meta, parentField) || convertFuncLhs(k, v, conv, config, not, fieldConfig, meta, parentField); }; var beforeErrorsCnt = meta.errors.length; var field, fieldSrc, having, isGroup; var parsed = _parse(k, v); if (parsed) { field = parsed.field; fieldSrc = parsed.fieldSrc; } if (isGroup0) { isGroup = true; having = args[0]; args = []; } // reduce/filter for group ext if (k == "reduce" && Array.isArray(v) && v.length == 3) { var _v = v, _v2 = (0, _slicedToArray2["default"])(_v, 3), filter = _v2[0], acc = _v2[1], init = _v2[2]; if ((0, _stuff.isJsonLogic)(filter) && init == 0 && (0, _stuff.isJsonLogic)(acc) && Array.isArray(acc["+"]) && acc["+"][0] == 1 && (0, _stuff.isJsonLogic)(acc["+"][1]) && acc["+"][1]["var"] == "accumulator") { k = Object.keys(filter)[0]; v = Object.values(filter)[0]; if (k == "filter") { var _v3 = v, _v4 = (0, _slicedToArray2["default"])(_v3, 2), group = _v4[0], _filter = _v4[1]; if ((0, _stuff.isJsonLogic)(group)) { k = Object.keys(group)[0]; v = Object.values(group)[0]; var parsedGroup = _parse(k, v); if (parsedGroup) { field = parsedGroup.field; fieldSrc = parsedGroup.fieldSrc; having = _filter; isGroup = true; } } } else { var _parsedGroup = _parse(k, v); if (_parsedGroup) { field = _parsedGroup.field; fieldSrc = _parsedGroup.fieldSrc; isGroup = true; } } } } var afterErrorsCnt = meta.errors.length; if (!field && afterErrorsCnt == beforeErrorsCnt) { meta.errors.push("Unknown LHS ".concat(JSON.stringify(jlField))); } if (!field) return; return { field: field, fieldSrc: fieldSrc, having: having, isGroup: isGroup, args: args }; }; var convertFieldLhs = function convertFieldLhs(op, vals, conv, config, not, meta) { var parentField = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null; if (!Array.isArray(vals)) vals = [vals]; var parsed = convertFieldRhs(op, vals, conv, config, not, meta, parentField); if (parsed) { return { fieldSrc: "field", field: parsed.value }; } return undefined; }; var convertFuncLhs = function convertFuncLhs(op, vals, conv, config, not) { var fieldConfig = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null; var meta = arguments.length > 6 ? arguments[6] : undefined; var parentField = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null; var parsed = convertFuncRhs(op, vals, conv, config, not, fieldConfig, meta, parentField); if (parsed) { return { fieldSrc: "func", field: parsed.value }; } return undefined; }; var convertFuncRhs = function convertFuncRhs(op, vals, conv, config, not) { var fieldConfig = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null; var meta = arguments.length > 6 ? arguments[6] : undefined; var parentField = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null; if (!op) return undefined; var func, argsArr, funcKey; var jsonLogicIsMethod = op == "method"; if (jsonLogicIsMethod) { var obj, opts; var _vals = (0, _toArray2["default"])(vals); obj = _vals[0]; func = _vals[1]; opts = _vals.slice(2); argsArr = [obj].concat((0, _toConsumableArray2["default"])(opts)); } else { func = op; argsArr = vals; } var fk = (jsonLogicIsMethod ? "#" : "") + func; var returnType = (fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type) || (fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.returnType); var funcKeys = (conv.funcs[fk] || []).filter(function (k) { return fieldConfig ? (0, _configUtils.getFuncConfig)(config, k).returnType == returnType : true; }); if (funcKeys.length) { funcKey = funcKeys[0]; } else { var v = (0, _defineProperty2["default"])({}, op, vals); var _iterator2 = _createForOfIteratorHelper((0, _configUtils.iterateFuncs)(config)), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var _step2$value = (0, _slicedToArray2["default"])(_step2.value, 2), f = _step2$value[0], fc = _step2$value[1]; if (fc.jsonLogicImport && (returnType ? fc.returnType == returnType : true)) { var parsed = void 0; try { parsed = fc.jsonLogicImport(v); } catch (_e) { // given expression `v` can't be parsed into function } if (parsed) { funcKey = f; argsArr = parsed; } } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } if (!funcKey) return undefined; if (funcKey) { var funcConfig = (0, _configUtils.getFuncConfig)(config, funcKey); var argKeys = Object.keys(funcConfig.args || {}); var argsObj = argsArr.reduce(function (acc, val, ind) { var argKey = argKeys[ind]; var argConfig = funcConfig.args[argKey]; var argVal; if (argConfig) { argVal = convertFromLogic(val, conv, config, ["val"], meta, false, argConfig, null, parentField); } return argVal !== undefined ? _objectSpread(_objectSpread({}, acc), {}, (0, _defineProperty2["default"])({}, argKey, argVal)) : acc; }, {}); for (var argKey in funcConfig.args) { var argConfig = funcConfig.args[argKey]; var argVal = argsObj[argKey]; if (argVal === undefined) { argVal = argConfig === null || argConfig === void 0 ? void 0 : argConfig.defaultValue; if (argVal !== undefined) { var _argVal; argVal = { value: argVal, valueSrc: (_argVal = argVal) !== null && _argVal !== void 0 && _argVal.func ? "func" : "value", valueType: argConfig.type }; } if (argVal === undefined) { if (argConfig !== null && argConfig !== void 0 && argConfig.isOptional) { //ignore } else { meta.errors.push("No value for arg ".concat(argKey, " of func ").concat(funcKey)); return undefined; } } else { argsObj[argKey] = argVal; } } } return { valueSrc: "func", value: { func: funcKey, args: argsObj }, valueType: funcConfig.returnType }; } return undefined; }; var convertConj = function convertConj(op, vals, conv, config, not, meta) { var parentField = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null; var isRuleGroup = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false; var conjKey = conv.conjunctions[op]; var fieldSeparator = config.settings.fieldSeparator; // const parentFieldConfig = parentField ? getFieldConfig(config, parentField) : null; // const isParentGroup = parentFieldConfig?.type == "!group"; if (conjKey) { var type = "group"; var children = vals.map(function (v) { return convertFromLogic(v, conv, config, ["rule", "group"], meta, false, null, null, parentField); }).filter(function (r) { return r !== undefined; }).reduce(function (acc, r) { return _objectSpread(_objectSpread({}, acc), {}, (0, _defineProperty2["default"])({}, r.id, r)); }, {}); var complexFields = Object.values(children).map(function (v) { var _v$properties, _v$properties2; return (v === null || v === void 0 || (_v$properties = v.properties) === null || _v$properties === void 0 ? void 0 : _v$properties.fieldSrc) == "field" && (v === null || v === void 0 || (_v$properties2 = v.properties) === null || _v$properties2 === void 0 ? void 0 : _v$properties2.field); }).filter(function (f) { var _f$includes; return f === null || f === void 0 || (_f$includes = f.includes) === null || _f$includes === void 0 ? void 0 : _f$includes.call(f, fieldSeparator); }); var complexFieldsGroupAncestors = Object.fromEntries(arrayUniq(complexFields).map(function (f) { var parts = f.split(fieldSeparator); var ancs = Object.fromEntries(parts.slice(0, -1).map(function (f, i, parts) { return [].concat((0, _toConsumableArray2["default"])(parts.slice(0, i)), [f]); }).map(function (fp) { return [fp.join(fieldSeparator), (0, _configUtils.getFieldConfig)(config, fp)]; }).filter(function (_ref) { var _ref2 = (0, _slicedToArray2["default"])(_ref, 2), _f = _ref2[0], fc = _ref2[1]; return (fc === null || fc === void 0 ? void 0 : fc.type) == "!group"; })); return [f, Object.keys(ancs)]; })); // const childrenInRuleGroup = Object.values(children) // .map(v => v?.properties?.fieldSrc == "field" && v?.properties?.field) // .map(f => complexFieldsGroupAncestors[f]) // .filter(ancs => ancs && ancs.length); // const usedRuleGroups = arrayUniq(Object.values(complexFieldsGroupAncestors).flat()); // const usedTopRuleGroups = topLevelFieldsFilter(usedRuleGroups); var properties = { conjunction: conjKey, not: not }; var id = (0, _uuid["default"])(); var children1 = {}; var groupToId = {}; Object.entries(children).map(function (_ref3) { var _ref4 = (0, _slicedToArray2["default"])(_ref3, 2), k = _ref4[0], v = _ref4[1]; if ((v === null || v === void 0 ? void 0 : v.type) == "group" || (v === null || v === void 0 ? void 0 : v.type) == "rule_group") { // put as-is children1[k] = v; } else { var _v$properties3; var field = v === null || v === void 0 || (_v$properties3 = v.properties) === null || _v$properties3 === void 0 ? void 0 : _v$properties3.field; var groupAncestors = complexFieldsGroupAncestors[field] || []; var groupField = groupAncestors[groupAncestors.length - 1]; if (!groupField) { // not in rule_group (can be simple field or in struct) - put as-is if (v) { children1[k] = v; } } else { // wrap field in rule_group (with creating hierarchy if need) var ch = children1; var parentFieldParts = (0, _configUtils.getFieldParts)(parentField, config); var groupPath = (0, _configUtils.getFieldParts)(groupField, config); var isInParent = (0, _stuff.shallowEqual)(parentFieldParts, groupPath.slice(0, parentFieldParts.length)); if (!isInParent) parentFieldParts = []; // should not be var traverseGroupFields = groupField.split(fieldSeparator).slice(parentFieldParts.length).map(function (f, i, parts) { return [].concat((0, _toConsumableArray2["default"])(parentFieldParts), (0, _toConsumableArray2["default"])(parts.slice(0, i)), [f]).join(fieldSeparator); }).map(function (f) { return { f: f, fc: (0, _configUtils.getFieldConfig)(config, f) || {} }; }).filter(function (_ref5) { var fc = _ref5.fc; return fc.type != "!struct"; }); traverseGroupFields.map(function (_ref6, i) { var gf = _ref6.f, gfc = _ref6.fc; var groupId = groupToId[gf]; if (!groupId) { groupId = (0, _uuid["default"])(); groupToId[gf] = groupId; ch[groupId] = { type: "rule_group", id: groupId, children1: {}, properties: { conjunction: conjKey, not: false, field: gf, fieldSrc: "field", mode: gfc.mode } }; } ch = ch[groupId].children1; }); ch[k] = v; } } }); // tip: for isRuleGroup=true correct type and properties will be set out of this func return { type: type, id: id, children1: children1, properties: properties }; } return undefined; }; // const topLevelFieldsFilter = (fields) => { // let arr = [...fields].sort((a, b) => (a.length - b.length)); // for (let i = 0 ; i < arr.length ; i++) { // for (let j = i + 1 ; j < arr.length ; j++) { // if (arr[j].indexOf(arr[i]) == 0) { // // arr[j] is inside arr[i] (eg. "a.b" inside "a") // arr.splice(j, 1); // j--; // } // } // } // return arr; // }; var wrapInDefaultConjRuleGroup = function wrapInDefaultConjRuleGroup(rule, parentField, parentFieldConfig, config) { var conj = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : undefined; var not = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; if (!rule) return undefined; return { type: "rule_group", id: (0, _uuid["default"])(), children1: (0, _defineProperty2["default"])({}, rule.id, rule), properties: { conjunction: conj || (0, _defaultUtils.defaultGroupConjunction)(config, parentFieldConfig), not: not, field: parentField } }; }; var wrapInDefaultConj = function wrapInDefaultConj(rule, config) { var not = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; return { type: "group", id: (0, _uuid["default"])(), children1: (0, _defineProperty2["default"])({}, rule.id, rule), properties: { conjunction: (0, _defaultUtils.defaultConjunction)(config), not: not } }; }; var parseRule = function parseRule(op, arity, vals, parentField, conv, config, meta) { var submeta = createMeta(meta); var res = _parseRule(op, arity, vals, parentField, conv, config, submeta); if (!res) { meta.errors.push(submeta.errors.join("; ") || "Unknown op ".concat(op, "/").concat(arity)); return undefined; } return res; }; var _parseRule = function _parseRule(op, arity, vals, parentField, conv, config, meta) { var _meta$settings2; // config.settings.groupOperators are used for group count (cardinality = 0 is exception) // but don't confuse with "all-in" or "some-in" for multiselect var isAllOrSomeInForMultiselect = multiselectOps.map(function (opName) { var _config$operators$opN; return (_config$operators$opN = config.operators[opName]) === null || _config$operators$opN === void 0 ? void 0 : _config$operators$opN.jsonLogic2; }).includes(op); var isGroup0 = config.settings.groupOperators.includes(op) && !isAllOrSomeInForMultiselect; var cardinality = isGroup0 ? 0 : arity - 1; if (isGroup0) cardinality = 0;else if (jlEqOps.includes(op) && cardinality == 1 && vals[1] === null) { arity = 1; cardinality = 0; vals = [vals[0]]; } var opk = op + "/" + cardinality; var opKeys = conv.operators[opk]; if (!opKeys) return; var jlField, jlArgs = []; if (jlRangeOps.includes(op) && arity == 3) { jlField = vals[1]; jlArgs = [vals[0], vals[2]]; } else { var _vals2 = vals; var _vals3 = (0, _toArray2["default"])(_vals2); jlField = _vals3[0]; jlArgs = _vals3.slice(1); } if (!(0, _stuff.isJsonLogic)(jlField)) { meta.errors.push("Incorrect operands for ".concat(op, ": ").concat(JSON.stringify(vals))); return; } var lhs = convertLhs(isGroup0, jlField, jlArgs, conv, config, null, null, meta, parentField); if (!lhs) return; var field = lhs.field, fieldSrc = lhs.fieldSrc, having = lhs.having, isGroup = lhs.isGroup, args = lhs.args; var fieldConfig = (0, _configUtils.getFieldConfig)(config, field); if (!fieldConfig && !((_meta$settings2 = meta.settings) !== null && _meta$settings2 !== void 0 && _meta$settings2.allowUnknownFields)) { meta.errors.push("No config for LHS ".concat(field)); return; } var opKey = opKeys[0]; if (opKeys.length > 1 && fieldConfig && fieldConfig.operators) { // eg. for "equal" and "select_equals" opKeys = opKeys.filter(function (k) { return fieldConfig.operators.includes(k); }); if (opKeys.length == 0) { meta.errors.push("No corresponding ops for LHS ".concat(field)); return; } opKey = opKeys[0]; } return { field: field, fieldSrc: fieldSrc, fieldConfig: fieldConfig, opKey: opKey, args: args, having: having }; }; var convertOp = function convertOp(op, vals, conv, config, not, meta) { var _opConfig; var parentField = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null; var _isOneRuleInRuleGroup = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false; if (!op) return undefined; var jlConjs = Object.values(config.conjunctions).map(function (_ref7) { var jsonLogicConj = _ref7.jsonLogicConj; return jsonLogicConj; }); var arity = vals.length; var parseRes = parseRule(op, arity, vals, parentField, conv, config, meta); if (!parseRes) return undefined; var field = parseRes.field, fieldSrc = parseRes.fieldSrc, fieldConfig = parseRes.fieldConfig, opKey = parseRes.opKey, args = parseRes.args, having = parseRes.having; var parentFieldConfig = (0, _configUtils.getFieldConfig)(config, parentField); var opConfig = config.operators[opKey]; var reversedOpConfig = config.operators[(_opConfig = opConfig) === null || _opConfig === void 0 ? void 0 : _opConfig.reversedOp]; var opNeedsReverse = false; var opCanReverse = !!reversedOpConfig; // Group component in array mode can show NOT checkbox, so do nothing in this case // Otherwise try to reverse // const showNot = fieldConfig?.showNot !== undefined ? fieldConfig.showNot : config.settings.showNot; var isRuleGroup = fieldConfig.type == "!group"; // const isGroupArray = isRuleGroup && fieldConfig.mode == "array"; var isInRuleGroup = (parentFieldConfig === null || parentFieldConfig === void 0 ? void 0 : parentFieldConfig.type) == "!group"; var canRev = opCanReverse && (!!config.settings.reverseOperatorsForNot || opNeedsReverse || isRuleGroup && !having // !(count == 2) -> count != 2 // because "NOT" is not visible inside rule_group if there are no children || !isRuleGroup && isInRuleGroup && !_isOneRuleInRuleGroup // 2+ rules in rule-group should be flat. see inits.with_not_and_in_some in test ); // if (isGroupArray && showNot) // canRev = false; var needRev = not && canRev || opNeedsReverse; var conj; var havingVals; var havingNot = false; var canRevHaving = !!config.settings.reverseOperatorsForNot; if ((fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type) == "!group" && having) { conj = Object.keys(having)[0]; havingVals = having[conj]; if (!Array.isArray(havingVals)) havingVals = [havingVals]; // Preprocess "!": Try to reverse op in single rule in having // Eg. use `not_equal` instead of `not` `equal` // We look for template matches here to make sure we dont reverse when "!" is // part of operator var match = matchAgainstTemplates(having, conv, meta); while (conj == "!" && !match) { var isEmptyOp = conj == "!" && havingVals.length == 1 && havingVals[0] && (0, _stuff.isJsonLogic)(havingVals[0]) && conv.varKeys.includes(Object.keys(havingVals[0])[0]); if (isEmptyOp) { break; } havingNot = !havingNot; having = having["!"]; conj = Object.keys(having)[0]; havingVals = having[conj]; // Negation group with single rule is to be treated the same as ! if (canRevHaving && jlConjs.includes(conj) && havingVals.length == 1) { having = having[conj][0]; conj = Object.keys(having)[0]; havingVals = having[conj]; } // Another template matching var matchTemp = matchAgainstTemplates(having, conv, meta); match = matchTemp ? matchTemp : match; } if (!Array.isArray(havingVals)) { havingVals = [havingVals]; } // If template match found we act accordingly if (match) { // We reset vals if match found havingVals = []; havingVals[0] = match.jlField; match.jlArgs.forEach(function (arg) { return havingVals.push(arg); }); // We reset op to new op that represents multiple jsonlogic operators conj = match.newOp; } } // Use reversed op if (needRev) { not = !not; opKey = opConfig.reversedOp; opConfig = config.operators[opKey]; } var widget = (0, _ruleUtils.getWidgetForFieldOp)(config, field, opKey, null); var convertedArgs = args.map(function (v) { return convertFromLogic(v, conv, config, ["val"], meta, false, fieldConfig, widget, parentField); }); if (convertedArgs.filter(function (v) { return v === undefined; }).length) { //meta.errors.push(`Undefined arg for field ${field} and op ${opKey}`); return undefined; } var res; var fieldType = fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type; if (fieldType === "!group" || fieldType === "!struct") { fieldType = null; } if ((fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type) == "!group" && having) { if (conv.conjunctions[conj] !== undefined) { // group res = convertConj(conj, havingVals, conv, config, havingNot, meta, field, true); } else { // rule, need to be wrapped in `rule_group` res = convertOp(conj, havingVals, conv, config, havingNot, meta, field, true); if (res) { var _res$properties; if (res.type === "rule_group" && ((_res$properties = res.properties) === null || _res$properties === void 0 ? void 0 : _res$properties.field) !== field) { res = wrapInDefaultConjRuleGroup(res, field, fieldConfig, config); } Object.assign(res.properties, { conjunction: (0, _defaultUtils.defaultGroupConjunction)(config, fieldConfig) }); } } if (!res) return undefined; res.type = "rule_group"; Object.assign(res.properties, { field: field, mode: fieldConfig.mode, operator: opKey }); if (fieldConfig.mode == "array") { Object.assign(res.properties, { value: convertedArgs.map(function (v) { return v.value; }), valueSrc: convertedArgs.map(function (v) { return v.valueSrc; }), valueType: convertedArgs.map(function (v) { return v.valueType; }) }); } if (not) { // tip: don't set not to properties, only havingNot should affect it res = wrapInDefaultConj(res, config, not); } } else if ((fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type) == "!group" && !having) { res = { type: "rule_group", id: (0, _uuid["default"])(), children1: {}, properties: { conjunction: (0, _defaultUtils.defaultGroupConjunction)(config, fieldConfig), // tip: `not: true` have no effect if there are no children! "NOT" is hidden in UI and is ignored during export // So it's better to reverse group op (see `canRev =`), or wrap in conj with NOT as a last resort not: false, mode: fieldConfig.mode, field: field, operator: opKey } }; if (fieldConfig.mode === "array") { Object.assign(res.properties, { value: convertedArgs.map(function (v) { return v.value; }), valueSrc: convertedArgs.map(function (v) { return v.valueSrc; }), valueType: convertedArgs.map(function (v) { return v.valueType; }) }); } if (not) { res = wrapInDefaultConj(res, config, not); } } else { var asyncListValuesArr = convertedArgs.map(function (v) { return v.asyncListValues; }).filter(function (v) { return v != undefined; }); var asyncListValues = asyncListValuesArr.length ? asyncListValuesArr[0] : undefined; res = { type: "rule", id: (0, _uuid["default"])(), properties: _objectSpread({ field: field, fieldSrc: fieldSrc, operator: opKey, value: convertedArgs.map(function (v) { return v.value; }), valueSrc: convertedArgs.map(function (v) { return v.valueSrc; }), valueType: convertedArgs.map(function (v) { return v.valueType; }) }, asyncListValues ? { asyncListValues: asyncListValues } : {}) }; if (not || _isOneRuleInRuleGroup) { res = wrapInDefaultConj(res, config, not); } } return res; }; var convertIf = function convertIf(op, vals, conv, config, not, meta) { var parentField = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null; if ((op === null || op === void 0 ? void 0 : op.toLowerCase()) !== "if") return undefined; var flat = flatizeTernary(vals); var cases = flat.map(function (_ref8) { var _ref9 = (0, _slicedToArray2["default"])(_ref8, 2), cond = _ref9[0], val = _ref9[1]; return [cond ? convertFromLogic(cond, conv, config, ["rule", "group"], meta, false, null, null, parentField) : null, buildCaseValProperties(config, meta, conv, val)]; }); var children1 = cases.map(function (_ref10) { var _ref11 = (0, _slicedToArray2["default"])(_ref10, 2), cond = _ref11[0], val = _ref11[1]; return wrapInCase(cond, val, config, meta); }); var switchI = { type: "switch_group", id: (0, _uuid["default"])(), children1: children1, properties: {} }; return switchI; }; var flatizeTernary = function flatizeTernary(children) { var flat = []; function _processTernaryChildren(tern) { var _tern = (0, _slicedToArray2["default"])(tern, 3), cond = _tern[0], if_val = _tern[1], else_val = _tern[2]; flat.push([cond, if_val]); var else_op = (0, _stuff.isJsonLogic)(else_val) ? Object.keys(else_val)[0] : null; if ((else_op === null || else_op === void 0 ? void 0 : else_op.toLowerCase()) === "if") { _processTernaryChildren(else_val[else_op]); } else { flat.push([undefined, else_val]); } } _processTernaryChildren(children); return flat; }; var wrapInCase = function wrapInCase(cond, valProperties, config, meta) { var caseI; if (cond) { caseI = _objectSpread({}, cond); if (caseI.type) { if (caseI.type != "group") { caseI = wrapInDefaultConj(caseI, config); } caseI.type = "case_group"; } else { meta.errors.push("Unexpected case: ".concat(JSON.stringify(caseI))); caseI = undefined; } } else { caseI = { id: (0, _uuid["default"])(), type: "case_group", properties: {} }; } if (caseI) { caseI.properties = _objectSpread(_objectSpread({}, caseI.properties), valProperties); } return caseI; }; var buildCaseValProperties = function buildCaseValProperties(config, meta, conv, val) { var caseValueFieldConfig = (0, _configUtils.getFieldConfig)(config, "!case_value"); if (!caseValueFieldConfig) { meta.errors.push("Missing caseValueField in settings"); return undefined; } var widget = caseValueFieldConfig.mainWidget; var widgetDef = config.widgets[widget]; if (!widgetDef) { meta.errors.push("No widget ".concat(widget, " for case value")); return undefined; } var convVal = convertFromLogic(val, conv, config, ["val", "case_val"], meta, false, caseValueFieldConfig, widget); if (convVal == undefined) { return undefined; } var value = convVal.value, valueSrc = convVal.valueSrc, valueType = convVal.valueType; var valProperties = { value: [value], valueSrc: [valueSrc !== null && valueSrc !== void 0 ? valueSrc : "value"], valueType: [valueType !== null && valueType !== void 0 ? valueType : widgetDef === null || widgetDef === void 0 ? void 0 : widgetDef.type], field: "!case_value" }; return valProperties; };