UNPKG

@react-awesome-query-builder/core

Version:
1,157 lines (1,141 loc) 53.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.loadFromJsonLogic = exports._loadFromJsonLogic = void 0; var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); 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 _configExtend = require("../utils/configExtend"); var _tree = require("./tree"); var _defaultUtils = require("../utils/defaultUtils"); var _immutable = _interopRequireDefault(require("immutable")); 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(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, 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 o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } // http://jsonlogic.com/ // helpers var arrayUniq = function arrayUniq(arr) { return Array.from(new Set(arr)); }; // constants var jlFieldMarker = "jlField"; var jlRawFieldMarker = "jlRawField"; var jlHavingMarker = "jlHavingMarker"; var jlArgsMarker = new Proxy({ __name: "jlArgs", __test: function __test(v) { var _v$match; var m = v === null || v === void 0 || (_v$match = v.match) === null || _v$match === void 0 ? void 0 : _v$match.call(v, /jlArgs\[(\d+)\]/); if (m) { return parseInt(m[1]); } } }, { get: function get(target, k) { if (!isNaN(parseInt(k))) { return "jlArgs[" + k + "]"; } else { return target[k]; } } }); var jlEqOps = ["==", "!=", "datetime==", "datetime!=", "date==", "date!="]; var jlRangeOps = ["<", "<=", ">", ">="]; var jlDualMeaningOps = ["in", "!in"]; // can be mapped to "select_any_in" or "like" 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, _configExtend.extendConfig)(config, undefined, false); var conv = buildConv(extendedConfig); var jsTree = logicTree ? _convertFromLogic(logicTree, conv, extendedConfig, ["rule", "group", "switch", "case_val"], meta) : undefined; var immTree = jsTree ? (0, _tree.loadTree)(jsTree) : undefined; meta.errors = Array.from(new Set(meta.errors)); 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 = {}; var _loop = function _loop(opKey) { var opConfig = config.operators[opKey]; var cardinality = (0, _stuff.getOpCardinality)(opConfig); if (typeof opConfig.jsonLogic == "string") { // example: "</2", "#in/1" var opk = opConfig.jsonLogic + "/" + cardinality; if (!operators[opk]) operators[opk] = []; operators[opk].push(opKey); } else if (typeof opConfig.jsonLogic === "function") { var _opConfig$jsonLogic, _opConfig$jsonLogic2$, _opConfig$jsonLogic2, _opConfig$jsonLogicOp; var template; try { template = opConfig.jsonLogic(jlFieldMarker, opKey, jlArgsMarker, opConfig, new _immutable["default"].Map({ having: jlHavingMarker, groupField: jlRawFieldMarker // reduce: undefined, // groupFieldFormatted: undefined, })); } catch (e) { console.warn("Error while running JsonLogic template for op ".concat(opKey), e); return 1; // continue } var opInTemplate = Object.keys(template)[0]; var isRevArgs = (_opConfig$jsonLogic = opConfig.jsonLogic2) === null || _opConfig$jsonLogic === void 0 ? void 0 : _opConfig$jsonLogic.startsWith("#"); // example: "all-in/1" var newOp = (_opConfig$jsonLogic2$ = (_opConfig$jsonLogic2 = opConfig.jsonLogic2) === null || _opConfig$jsonLogic2 === void 0 ? void 0 : _opConfig$jsonLogic2.replace(/^#/, "")) !== null && _opConfig$jsonLogic2$ !== void 0 ? _opConfig$jsonLogic2$ : opInTemplate; var ops = (_opConfig$jsonLogicOp = opConfig.jsonLogicOps) !== null && _opConfig$jsonLogicOp !== void 0 ? _opConfig$jsonLogicOp : [newOp]; ops.map(function (op) { var opk = op + "/" + cardinality; if (!operators[opk]) operators[opk] = []; operators[opk].push(opKey); }); if (!combinationOperators[opKey]) combinationOperators[opKey] = {}; combinationOperators[opKey] = { "template": template, "newOp": newOp, "_jsonLogicIsExclamationOp": !!opConfig._jsonLogicIsExclamationOp, "isRevArgs": isRevArgs }; } }; for (var opKey in config.operators) { if (_loop(opKey)) continue; } 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.newOp; } } } } // 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": [], "jlHaving": null }; 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; } response.vals = []; for (var index = 0; index < tKeys.length; index++) { var key = tKeys[index]; var value = template[key]; response.vals.push(jsonlogic[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; } var maybeArgIndex = jlArgsMarker.__test(value); if (maybeArgIndex !== undefined) { response.jlArgs[maybeArgIndex] = jsonlogic[key]; } 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 === jlRawFieldMarker) { response.jlField = { "var": 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 (value === jlHavingMarker) { response.jlHaving = 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 `newOp` value (usually taken from jsonLogic2) var match = matchAgainstTemplates(logic, conv, meta); if (match) { // We reset vals if match found vals = []; vals[0] = match.jlField; if (match.jlHaving) { vals.push(match.jlHaving); } match.jlArgs.forEach(function (arg) { return vals.push(arg); }); // We reset op to new op that represents multiple jsonlogic operators op = match.newOp; if (jlDualMeaningOps.includes(op)) { // use original order of args vals = match.vals; } } 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 { var errorsBefore = (0, _toConsumableArray2["default"])(meta.errors); if (expectedTypes.includes("switch")) { ret = convertSwitch(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); } var errorsAfter = (0, _toConsumableArray2["default"])(meta.errors); if (ret == undefined && expectedTypes.includes("case_val")) { // last resort meta.errors = errorsBefore; ret = convertCaseVal(op, vals, conv, config, not, meta, parentField); if (ret == undefined) { meta.errors = errorsAfter; } } 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$fieldSet2; 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; } if (widgetConfig !== null && widgetConfig !== void 0 && widgetConfig.jsonLogicImport) { try { var _fieldConfig$fieldSet; val = widgetConfig.jsonLogicImport.call(config.ctx, val, _objectSpread(_objectSpread({}, widgetConfig), (_fieldConfig$fieldSet = fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.fieldSettings) !== null && _fieldConfig$fieldSet !== void 0 ? _fieldConfig$fieldSet : {})); } 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; } } else { // 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 isEpoch = typeof val === "number" || typeof val === "string" && !isNaN(val); // Note: can import only from ms timestamp, not seconds timestamp var epoch = isEpoch && typeof val === "string" ? parseInt(val) : val; var _dateVal = new Date(isEpoch ? epoch : val); if (_dateVal instanceof Date) { val = _dateVal; } if (isNaN(_dateVal)) { throw new Error("Invalid date"); } } 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$fieldSet2 = fieldConfig.fieldSettings) !== null && _fieldConfig$fieldSet2 !== void 0 && _fieldConfig$fieldSet2.asyncFetch) { var vals = Array.isArray(val) ? val : [val]; asyncListValues = vals; } 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(groupOp, 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 groupOpConfig = config.operators[groupOp]; var isGroup = !!groupOpConfig; // const isGroup0 = groupOpConfig?.cardinality == 0; 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; var parsed = _parse(k, v); if (parsed) { field = parsed.field; fieldSrc = parsed.fieldSrc; } if (isGroup) { // If current op is in `config.groupOperators`, first arg is having query (see `match.jlHaving`) having = args[0]; args = args.splice(1); } // 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.call(config.ctx, 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, groupField, groupFieldConfig, 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, groupFieldConfig), not: not, field: groupField } }; }; 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.defaultGroupConjunction)(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(Array.from(new Set(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 _groupOpConfig$cardin; // 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 groupOp = config.settings.groupOperators.find(function (groupOp) { var groupOpConfig = config.operators[groupOp]; return [groupOp, typeof groupOpConfig.jsonLogic === "string" && groupOpConfig.jsonLogic, groupOpConfig.jsonLogic2].includes(op); }); var groupOpConfig = config.operators[groupOp]; var isGroup0 = groupOp && (groupOpConfig === null || groupOpConfig === void 0 ? void 0 : groupOpConfig.cardinality) == 0 && !isAllOrSomeInForMultiselect; var cardinality = (_groupOpConfig$cardin = groupOpConfig === null || groupOpConfig === void 0 ? void 0 : groupOpConfig.cardinality) !== null && _groupOpConfig$cardin !== void 0 ? _groupOpConfig$cardin : arity - 1; if (!isGroup0 && 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 returnVariants = []; var _iterator3 = _createForOfIteratorHelper(opKeys), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var _conv$combinationOper, _meta$settings2; var opKey = _step3.value; var jlField = void 0, 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 ((_conv$combinationOper = conv.combinationOperators[opKey]) !== null && _conv$combinationOper !== void 0 && _conv$combinationOper.isRevArgs) { jlField = vals[vals.length - 1]; jlArgs = vals.slice(0, vals.length - 1); } if (!(0, _stuff.isJsonLogic)(jlField)) { continue; // try another operator } var lhs = convertLhs(groupOp, jlField, jlArgs, conv, config, null, null, meta, parentField); if (!lhs) { continue; // try another operator } 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 isValidOp = (fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.operators) && fieldConfig.operators.includes(opKey); returnVariants.push({ field: field, fieldSrc: fieldSrc, fieldConfig: fieldConfig, opKey: opKey, args: args, having: having, isValidOp: isValidOp }); } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } returnVariants.sort(function (_ref7) { var isValidOp = _ref7.isValidOp; return isValidOp ? -1 : +1; }); return returnVariants[0]; }; 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 (_ref8) { var jsonLogicConj = _ref8.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; if (jlDualMeaningOps.includes(match.newOp)) { // use original order of args havingVals = match.vals; } } } // Use reversed op if (needRev) { not = !not; opKey = opConfig.reversedOp; opConfig = config.operators[opKey]; } var widget = (0, _configUtils.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 convertCaseVal = function convertCaseVal(op, vals, conv, config, not, meta) { var parentField = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null; var val = (0, _defineProperty2["default"])({}, op, vals); var defaultCaseVal = buildCaseValProperties(config, meta, conv, val); if (defaultCaseVal === undefined) { return undefined; } var defaultCase = wrapInCase(null, defaultCaseVal, config, meta); var children1 = [defaultCase]; var switchI = { type: "switch_group", id: (0, _uuid["default"])(), children1: children1, properties: {} }; return switchI