@react-querybuilder/core 8.14.4 → 8.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/cjs/react-querybuilder_core.cjs.development.d.ts +201 -8
  2. package/dist/cjs/react-querybuilder_core.cjs.development.js +394 -58
  3. package/dist/cjs/react-querybuilder_core.cjs.development.js.map +1 -1
  4. package/dist/cjs/react-querybuilder_core.cjs.production.d.ts +201 -8
  5. package/dist/cjs/react-querybuilder_core.cjs.production.js +1 -1
  6. package/dist/cjs/react-querybuilder_core.cjs.production.js.map +1 -1
  7. package/dist/{convertQuery-CeJSNn37.mjs → convertQuery-BeJJH9BI.mjs} +2 -2
  8. package/dist/convertQuery-BeJJH9BI.mjs.map +1 -0
  9. package/dist/{convertQuery-J8LpTG-7.js → convertQuery-Lx2HQa0m.js} +2 -2
  10. package/dist/convertQuery-Lx2HQa0m.js.map +1 -0
  11. package/dist/formatQuery.d.mts +24 -2
  12. package/dist/formatQuery.d.ts +24 -2
  13. package/dist/formatQuery.js +373 -47
  14. package/dist/formatQuery.js.map +1 -1
  15. package/dist/formatQuery.mjs +373 -48
  16. package/dist/formatQuery.mjs.map +1 -1
  17. package/dist/{import-BwQqExpO.d.mts → import-0wp72lLT.d.mts} +2 -2
  18. package/dist/{import-CrJf23Nf.d.ts → import-yRVJh7E1.d.ts} +2 -2
  19. package/dist/{index-CYT4Saz-.d.mts → index-D5TXNIzF.d.ts} +149 -5
  20. package/dist/{index-DBlQeLax.d.ts → index-Lht_Wq3V.d.mts} +149 -5
  21. package/dist/{objectUtils-ButT0Mng.js → objectUtils-Bzug_QfX.js} +2 -2
  22. package/dist/objectUtils-Bzug_QfX.js.map +1 -0
  23. package/dist/{objectUtils-C0WB-8ex.mjs → objectUtils-D96eEEzL.mjs} +2 -2
  24. package/dist/objectUtils-D96eEEzL.mjs.map +1 -0
  25. package/dist/parseCEL.d.mts +2 -2
  26. package/dist/parseCEL.d.ts +2 -2
  27. package/dist/parseCEL.js +35 -35
  28. package/dist/parseCEL.js.map +1 -1
  29. package/dist/parseCEL.mjs +35 -35
  30. package/dist/parseCEL.mjs.map +1 -1
  31. package/dist/parseJSONata.d.mts +2 -2
  32. package/dist/parseJSONata.d.ts +2 -2
  33. package/dist/parseJSONata.js +11 -11
  34. package/dist/parseJSONata.js.map +1 -1
  35. package/dist/parseJSONata.mjs +11 -11
  36. package/dist/parseJSONata.mjs.map +1 -1
  37. package/dist/parseJsonLogic.d.mts +2 -2
  38. package/dist/parseJsonLogic.d.ts +2 -2
  39. package/dist/parseJsonLogic.js +6 -6
  40. package/dist/parseJsonLogic.js.map +1 -1
  41. package/dist/parseJsonLogic.mjs +6 -6
  42. package/dist/parseJsonLogic.mjs.map +1 -1
  43. package/dist/parseMongoDB.d.mts +2 -2
  44. package/dist/parseMongoDB.d.ts +2 -2
  45. package/dist/parseMongoDB.js +6 -6
  46. package/dist/parseMongoDB.js.map +1 -1
  47. package/dist/parseMongoDB.mjs +6 -6
  48. package/dist/parseMongoDB.mjs.map +1 -1
  49. package/dist/parseSQL.d.mts +2 -2
  50. package/dist/parseSQL.d.ts +2 -2
  51. package/dist/parseSQL.js +16 -16
  52. package/dist/parseSQL.js.map +1 -1
  53. package/dist/parseSQL.mjs +16 -16
  54. package/dist/parseSQL.mjs.map +1 -1
  55. package/dist/parseSpEL.d.mts +2 -2
  56. package/dist/parseSpEL.d.ts +2 -2
  57. package/dist/parseSpEL.js +10 -10
  58. package/dist/parseSpEL.js.map +1 -1
  59. package/dist/parseSpEL.mjs +10 -10
  60. package/dist/parseSpEL.mjs.map +1 -1
  61. package/dist/{prepareQueryObjects-DO3qXriW.js → prepareQueryObjects-BoG5Rt8z.js} +6 -6
  62. package/dist/prepareQueryObjects-BoG5Rt8z.js.map +1 -0
  63. package/dist/{prepareQueryObjects-BfMlS4ql.mjs → prepareQueryObjects-uA10ZpZX.mjs} +6 -6
  64. package/dist/prepareQueryObjects-uA10ZpZX.mjs.map +1 -0
  65. package/dist/query-builder.css +1 -1
  66. package/dist/query-builder.css.map +1 -1
  67. package/dist/react-querybuilder_core.d.mts +201 -8
  68. package/dist/react-querybuilder_core.legacy-esm.d.ts +201 -8
  69. package/dist/react-querybuilder_core.legacy-esm.js +433 -89
  70. package/dist/react-querybuilder_core.legacy-esm.js.map +1 -1
  71. package/dist/react-querybuilder_core.mjs +393 -59
  72. package/dist/react-querybuilder_core.mjs.map +1 -1
  73. package/dist/react-querybuilder_core.production.d.mts +201 -8
  74. package/dist/react-querybuilder_core.production.mjs +1 -1
  75. package/dist/react-querybuilder_core.production.mjs.map +1 -1
  76. package/dist/styles/_main.scss +4 -0
  77. package/dist/transformQuery.d.mts +1 -1
  78. package/dist/transformQuery.d.ts +1 -1
  79. package/dist/transformQuery.js +1 -1
  80. package/dist/transformQuery.mjs +1 -1
  81. package/dist/{utils-BlMGIhvx.mjs → utils-ChLG90DP.mjs} +3 -3
  82. package/dist/utils-ChLG90DP.mjs.map +1 -0
  83. package/dist/{utils-CZRhzje-.js → utils-Qwkq2Q0F.js} +3 -3
  84. package/dist/utils-Qwkq2Q0F.js.map +1 -0
  85. package/package.json +9 -14
  86. package/dist/convertQuery-CeJSNn37.mjs.map +0 -1
  87. package/dist/convertQuery-J8LpTG-7.js.map +0 -1
  88. package/dist/objectUtils-ButT0Mng.js.map +0 -1
  89. package/dist/objectUtils-C0WB-8ex.mjs.map +0 -1
  90. package/dist/prepareQueryObjects-BfMlS4ql.mjs.map +0 -1
  91. package/dist/prepareQueryObjects-DO3qXriW.js.map +0 -1
  92. package/dist/utils-BlMGIhvx.mjs.map +0 -1
  93. package/dist/utils-CZRhzje-.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_utils = require("./utils-CZRhzje-.js");
3
- const require_objectUtils = require("./objectUtils-ButT0Mng.js");
2
+ const require_utils = require("./utils-Qwkq2Q0F.js");
3
+ const require_objectUtils = require("./objectUtils-Bzug_QfX.js");
4
4
  const require_transformQuery = require("./transformQuery.js");
5
- const require_convertQuery = require("./convertQuery-J8LpTG-7.js");
5
+ const require_convertQuery = require("./convertQuery-Lx2HQa0m.js");
6
6
  //#region src/utils/isRuleOrGroupValid.ts
7
7
  /**
8
8
  * Determines if an object is useful as a validation result.
@@ -20,7 +20,7 @@ const isRuleOrGroupValid = (rg, validationResult, validator) => {
20
20
  if (typeof validator === "function" && !require_objectUtils.isRuleGroup(rg)) {
21
21
  const vr = validator(rg);
22
22
  if (typeof vr === "boolean") return vr;
23
- // istanbul ignore else
23
+ // v8 ignore else
24
24
  if (isValidationResult(vr)) return vr.valid;
25
25
  }
26
26
  return true;
@@ -544,22 +544,22 @@ const defaultValueProcessorByRule = ({ operator, value, valueSource }, { escapeQ
544
544
  * @group Export
545
545
  */
546
546
  const defaultRuleProcessorDrizzle = (rule, _options) => {
547
- const opts = _options ?? ( /* istanbul ignore next */ {});
548
- // istanbul ignore next
547
+ const opts = _options ?? ( /* v8 ignore start -- @preserve */ {});
548
+ // v8 ignore next
549
549
  const { parseNumbers, preserveValueOrder, context = {} } = opts;
550
550
  const { columns, drizzleOperators, useRawFields } = context;
551
- if (!columns || !drizzleOperators) return;
551
+ if (!columns || !drizzleOperators) return void 0;
552
552
  const { between, eq, gt, gte, inArray, isNotNull, isNull, like, lt, lte, ne, notBetween, notInArray, notLike, sql } = drizzleOperators;
553
553
  const { field, operator, value, valueSource } = rule;
554
554
  const column = useRawFields && /[a-z][a-z0-9]*/i.test(field) ? sql.raw(field) : columns[field];
555
555
  const operatorLC = require_objectUtils.lc(operator);
556
556
  const valueIsField = valueSource === "field";
557
557
  const asFieldOrValue = (v) => valueIsField ? columns[v] : v;
558
- if (!column) return;
558
+ if (!column) return void 0;
559
559
  const matchEval = require_utils.processMatchMode(rule);
560
560
  if (matchEval === false) return;
561
561
  else if (matchEval) {
562
- if (opts.preset !== "postgresql") return;
562
+ if (opts.preset !== "postgresql") return void 0;
563
563
  const { mode, threshold } = matchEval;
564
564
  const arrayElementAlias = "elem_alias";
565
565
  const nestedArrayFilter = defaultRuleGroupProcessorDrizzle(require_transformQuery.transformQuery(rule.value, { ruleProcessor: (r) => ({
@@ -648,7 +648,7 @@ const defaultRuleProcessorDrizzle = (rule, _options) => {
648
648
  */
649
649
  const defaultRuleGroupProcessorDrizzle = (ruleGroup, options, _meta) => (columns, drizzleOperators) => {
650
650
  const { fields, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, validateRule, validationMap } = options;
651
- if (!columns || !drizzleOperators) return;
651
+ if (!columns || !drizzleOperators) return void 0;
652
652
  const { and, not, or } = drizzleOperators;
653
653
  const ruleProcessor = defaultRuleProcessorDrizzle;
654
654
  const processRuleGroup = (rg, _outermost) => {
@@ -867,7 +867,7 @@ const defaultRuleGroupProcessorMongoDB = (ruleGroup, options, meta) => {
867
867
  const defaultRuleGroupProcessorNL = (ruleGroup, options) => {
868
868
  const { fields, fallbackExpression, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, translations, validateRule, validationMap } = options;
869
869
  const processRuleGroup = (rg, outermostOrLonelyInGroup) => {
870
- if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermostOrLonelyInGroup ? fallbackExpression : "";
870
+ if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermostOrLonelyInGroup ? fallbackExpression : /* v8 ignore next -- @preserve */ "";
871
871
  const rg2 = require_objectUtils.isRuleGroupTypeIC(rg) && rg.rules.some((r) => typeof r === "string" && require_objectUtils.lc(r) === "xor") ? require_convertQuery.convertFromIC(rg) : rg;
872
872
  const processedRules = [];
873
873
  let precedingCombinator = "";
@@ -879,7 +879,7 @@ const defaultRuleGroupProcessorNL = (ruleGroup, options) => {
879
879
  }
880
880
  if (require_objectUtils.isRuleGroup(rule)) {
881
881
  const processedGroup = processRuleGroup(rule, rg2.rules.length === 1 && !(rg2.not || /^xor$/i.test(rg2.combinator ?? "")));
882
- // istanbul ignore else
882
+ // v8 ignore else
883
883
  if (processedGroup) {
884
884
  if (!firstRule && precedingCombinator) {
885
885
  processedRules.push(precedingCombinator);
@@ -955,7 +955,7 @@ const defaultRuleGroupProcessorParameterized = (ruleGroup, options) => {
955
955
  if (!require_objectUtils.isPojo(processedRule)) return "";
956
956
  const { sql, params: customParams } = processedRule;
957
957
  if (typeof sql !== "string" || !sql) return "";
958
- // istanbul ignore else
958
+ // v8 ignore else
959
959
  if (format === "parameterized" && Array.isArray(customParams)) params.push(...customParams);
960
960
  else if (format === "parameterized_named" && require_objectUtils.isPojo(customParams)) {
961
961
  Object.assign(paramsNamed, customParams);
@@ -964,7 +964,7 @@ const defaultRuleGroupProcessorParameterized = (ruleGroup, options) => {
964
964
  return sql;
965
965
  };
966
966
  const processRuleGroup = (rg, outermostOrLonelyInGroup) => {
967
- if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermostOrLonelyInGroup ? fallbackExpression : "";
967
+ if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermostOrLonelyInGroup ? fallbackExpression : /* v8 ignore next -- @preserve */ "";
968
968
  const processedRules = [];
969
969
  let precedingCombinator = "";
970
970
  let firstRule = true;
@@ -975,7 +975,7 @@ const defaultRuleGroupProcessorParameterized = (ruleGroup, options) => {
975
975
  }
976
976
  if (require_objectUtils.isRuleGroup(rule)) {
977
977
  const processedGroup = processRuleGroup(rule, rg.rules.length === 1);
978
- // istanbul ignore else
978
+ // v8 ignore else
979
979
  if (processedGroup) {
980
980
  if (!firstRule && precedingCombinator) {
981
981
  processedRules.push(precedingCombinator);
@@ -1058,10 +1058,10 @@ const defaultRuleGroupProcessorPrisma = (ruleGroup, options) => {
1058
1058
  * @group Export
1059
1059
  */
1060
1060
  const defaultRuleGroupProcessorSequelize = (ruleGroup, options) => {
1061
- // istanbul ignore next
1061
+ // v8 ignore next
1062
1062
  const { fields, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap, context = {} } = options;
1063
1063
  const { sequelizeOperators: Op } = context;
1064
- if (!Op) return;
1064
+ if (!Op) return void 0;
1065
1065
  const processRuleGroup = (rg, _outermost) => {
1066
1066
  if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return;
1067
1067
  const combinator = rg.combinator.toUpperCase();
@@ -1084,7 +1084,7 @@ const defaultRuleGroupProcessorSequelize = (ruleGroup, options) => {
1084
1084
  fieldData
1085
1085
  });
1086
1086
  }).filter(Boolean);
1087
- if (expressions.length === 0) return;
1087
+ if (expressions.length === 0) return void 0;
1088
1088
  const result = expressions.length === 1 && !hasChildRules ? expressions[0] : { [require_objectUtils.lc(combinator) === "or" ? Op.or : Op.and]: expressions };
1089
1089
  return rg.not ? { [Op.not]: result } : result;
1090
1090
  };
@@ -1100,7 +1100,7 @@ const defaultRuleGroupProcessorSequelize = (ruleGroup, options) => {
1100
1100
  const defaultRuleGroupProcessorSQL = (ruleGroup, options) => {
1101
1101
  const { fields, fallbackExpression, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap } = options;
1102
1102
  const processRuleGroup = (rg, outermostOrLonelyInGroup) => {
1103
- if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermostOrLonelyInGroup ? fallbackExpression : "";
1103
+ if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermostOrLonelyInGroup ? fallbackExpression : /* v8 ignore next -- @preserve */ "";
1104
1104
  const processedRules = [];
1105
1105
  let precedingCombinator = "";
1106
1106
  let firstRule = true;
@@ -1111,7 +1111,7 @@ const defaultRuleGroupProcessorSQL = (ruleGroup, options) => {
1111
1111
  }
1112
1112
  if (require_objectUtils.isRuleGroup(rule)) {
1113
1113
  const processedGroup = processRuleGroup(rule, rg.rules.length === 1);
1114
- // istanbul ignore else
1114
+ // v8 ignore else
1115
1115
  if (processedGroup) {
1116
1116
  if (!firstRule && precedingCombinator) {
1117
1117
  processedRules.push(precedingCombinator);
@@ -1147,6 +1147,325 @@ const defaultRuleGroupProcessorSQL = (ruleGroup, options) => {
1147
1147
  return processRuleGroup(ruleGroup, true);
1148
1148
  };
1149
1149
  //#endregion
1150
+ //#region src/utils/formatQuery/defaultRuleGroupProcessorDiagnostics.ts
1151
+ const numericInputTypes = new Set([
1152
+ "number",
1153
+ "range",
1154
+ "bigint"
1155
+ ]);
1156
+ const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
1157
+ const timeRegex = /^\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/;
1158
+ const monthRegex = /^\d{4}-\d{2}$/;
1159
+ const weekRegex = /^\d{4}-W\d{2}$/;
1160
+ const colorRegex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
1161
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1162
+ const isValidDateComponents = (y, m, d) => {
1163
+ const date = new Date(Date.UTC(y, m - 1, d));
1164
+ return date.getUTCFullYear() === y && date.getUTCMonth() === m - 1 && date.getUTCDate() === d;
1165
+ };
1166
+ const isValidTimeComponents = (s) => {
1167
+ const parts = s.split(":");
1168
+ const h = Number(parts[0]);
1169
+ const m = Number(parts[1]);
1170
+ const sec = parts[2] ? Number.parseFloat(parts[2]) : 0;
1171
+ return h >= 0 && h <= 23 && m >= 0 && m <= 59 && sec >= 0 && sec < 60;
1172
+ };
1173
+ /**
1174
+ * Checks whether a value is compatible with the given {@link FullField.inputType}.
1175
+ * Returns a diagnostic code string if there is a mismatch, or `undefined` if OK.
1176
+ */
1177
+ const checkValueTypeMismatch = (value, inputType) => {
1178
+ if (value === null || value === void 0 || value === "") return void 0;
1179
+ if (numericInputTypes.has(inputType)) {
1180
+ const v = typeof value === "string" ? value.trim() : value;
1181
+ if (typeof v === "number" || typeof v === "bigint") return void 0;
1182
+ if (typeof v === "string" && require_objectUtils.numericRegex.test(v)) return void 0;
1183
+ return "VALUE_TYPE_MISMATCH";
1184
+ }
1185
+ if (inputType === "date") {
1186
+ if (typeof value !== "string") return "VALUE_TYPE_MISMATCH";
1187
+ const v = value.trim();
1188
+ if (!dateRegex.test(v)) return "VALUE_TYPE_MISMATCH";
1189
+ const [y, m, d] = v.split("-").map(Number);
1190
+ return isValidDateComponents(y, m, d) ? void 0 : "VALUE_TYPE_MISMATCH";
1191
+ }
1192
+ if (inputType === "datetime-local") {
1193
+ if (typeof value !== "string") return "VALUE_TYPE_MISMATCH";
1194
+ const base = value.trim().replace(/(Z|[+-]\d{2}:?\d{2}|[+-]\d{2})$/, "");
1195
+ const tIndex = base.indexOf("T");
1196
+ if (tIndex === -1) return "VALUE_TYPE_MISMATCH";
1197
+ const datePart = base.slice(0, tIndex);
1198
+ const timePart = base.slice(tIndex + 1);
1199
+ if (!dateRegex.test(datePart) || !timeRegex.test(timePart)) return "VALUE_TYPE_MISMATCH";
1200
+ const [y, m, d] = datePart.split("-").map(Number);
1201
+ if (!isValidDateComponents(y, m, d)) return "VALUE_TYPE_MISMATCH";
1202
+ return isValidTimeComponents(timePart) ? void 0 : "VALUE_TYPE_MISMATCH";
1203
+ }
1204
+ if (inputType === "time") {
1205
+ if (typeof value !== "string") return "VALUE_TYPE_MISMATCH";
1206
+ const v = value.trim();
1207
+ if (!timeRegex.test(v)) return "VALUE_TYPE_MISMATCH";
1208
+ return isValidTimeComponents(v) ? void 0 : "VALUE_TYPE_MISMATCH";
1209
+ }
1210
+ if (inputType === "month") {
1211
+ if (typeof value !== "string") return "VALUE_TYPE_MISMATCH";
1212
+ const v = value.trim();
1213
+ if (!monthRegex.test(v)) return "VALUE_TYPE_MISMATCH";
1214
+ const m = Number(v.slice(5));
1215
+ return m >= 1 && m <= 12 ? void 0 : "VALUE_TYPE_MISMATCH";
1216
+ }
1217
+ if (inputType === "week") {
1218
+ if (typeof value !== "string") return "VALUE_TYPE_MISMATCH";
1219
+ const v = value.trim();
1220
+ if (!weekRegex.test(v)) return "VALUE_TYPE_MISMATCH";
1221
+ const w = Number(v.slice(6));
1222
+ return w >= 1 && w <= 53 ? void 0 : "VALUE_TYPE_MISMATCH";
1223
+ }
1224
+ if (inputType === "color") {
1225
+ if (typeof value !== "string") return "VALUE_TYPE_MISMATCH";
1226
+ return colorRegex.test(value.trim()) ? void 0 : "VALUE_TYPE_MISMATCH";
1227
+ }
1228
+ if (inputType === "url") {
1229
+ if (typeof value !== "string") return "VALUE_TYPE_MISMATCH";
1230
+ try {
1231
+ new URL(value.trim());
1232
+ return;
1233
+ } catch {
1234
+ return "VALUE_TYPE_MISMATCH";
1235
+ }
1236
+ }
1237
+ if (inputType === "email") {
1238
+ if (typeof value !== "string") return "VALUE_TYPE_MISMATCH";
1239
+ return emailRegex.test(value.trim()) ? void 0 : "VALUE_TYPE_MISMATCH";
1240
+ }
1241
+ };
1242
+ /**
1243
+ * Rule group processor used by {@link formatQuery} for "diagnostics" format.
1244
+ *
1245
+ * Produces a {@link DiagnosticsResult} containing an annotated copy of the query
1246
+ * tree (`query`) with `valid`, `reasons`, `path`, and `level` properties on every
1247
+ * rule and group; a flat `diagnostics` array; aggregate `stats`; and a per-field
1248
+ * `fieldSummary`.
1249
+ *
1250
+ * @group Export
1251
+ */
1252
+ const defaultRuleGroupProcessorDiagnostics = (ruleGroup, options) => {
1253
+ const { fields: fieldsOption, placeholderFieldName, placeholderOperatorName, placeholderValueName, validateRule, validationMap } = options;
1254
+ const diagnostics = [];
1255
+ const stats = {
1256
+ totalRules: 0,
1257
+ totalGroups: 0,
1258
+ validRules: 0,
1259
+ invalidRules: 0,
1260
+ validGroups: 0,
1261
+ invalidGroups: 0
1262
+ };
1263
+ const fieldSummary = {};
1264
+ const uniqueFields = require_utils.toFlatOptionArray(fieldsOption);
1265
+ const fieldsByName = /* @__PURE__ */ new Map();
1266
+ for (const f of uniqueFields) fieldsByName.set(f.name, f);
1267
+ const hasFieldsConfig = fieldsByName.size > 0;
1268
+ const processRuleGroup = (rg, path) => {
1269
+ stats.totalGroups++;
1270
+ const level = path.length;
1271
+ const groupValidationEntry = validationMap[rg.id ?? ""];
1272
+ const groupSelfValid = isRuleOrGroupValid(rg, groupValidationEntry);
1273
+ const groupReasons = getReasons(groupValidationEntry);
1274
+ if (rg.muted) diagnostics.push({
1275
+ id: rg.id ?? "",
1276
+ path,
1277
+ code: "MUTED",
1278
+ message: "Group is muted",
1279
+ source: "muted"
1280
+ });
1281
+ else if (!groupSelfValid && groupValidationEntry !== void 0) diagnostics.push({
1282
+ id: rg.id ?? "",
1283
+ path,
1284
+ code: "CUSTOM_VALIDATOR",
1285
+ message: groupReasons ? `Invalid: ${groupReasons.join(", ")}` : "Group failed validation",
1286
+ source: "query-validator"
1287
+ });
1288
+ let allChildrenValid = true;
1289
+ let ruleIndex = 0;
1290
+ const annotatedRules = [];
1291
+ for (const rule of rg.rules) {
1292
+ if (typeof rule === "string") {
1293
+ annotatedRules.push(rule);
1294
+ ruleIndex++;
1295
+ continue;
1296
+ }
1297
+ const childPath = [...path, ruleIndex];
1298
+ if (require_objectUtils.isRuleGroup(rule)) {
1299
+ const annotatedGroup = processRuleGroup(rule, childPath);
1300
+ if (!annotatedGroup.valid) allChildrenValid = false;
1301
+ annotatedRules.push(annotatedGroup);
1302
+ ruleIndex++;
1303
+ continue;
1304
+ }
1305
+ stats.totalRules++;
1306
+ const childLevel = childPath.length;
1307
+ const [validationResult, fieldValidator] = validateRule(rule);
1308
+ const ruleValid = isRuleOrGroupValid(rule, validationResult, fieldValidator) && rule.field !== placeholderFieldName && rule.operator !== placeholderOperatorName && !(placeholderValueName !== void 0 && rule.value === placeholderValueName);
1309
+ collectRuleDiagnostics(rule, childPath, validationResult, fieldValidator, ruleValid, diagnostics, placeholderFieldName, placeholderOperatorName, placeholderValueName, hasFieldsConfig, fieldsByName);
1310
+ if (!ruleValid) {
1311
+ allChildrenValid = false;
1312
+ stats.invalidRules++;
1313
+ } else stats.validRules++;
1314
+ const fieldName = rule.field;
1315
+ if (!fieldSummary[fieldName]) fieldSummary[fieldName] = {
1316
+ ruleCount: 0,
1317
+ invalidCount: 0
1318
+ };
1319
+ fieldSummary[fieldName].ruleCount++;
1320
+ if (!ruleValid) fieldSummary[fieldName].invalidCount++;
1321
+ const ruleReasons = getReasons(validationResult) ?? getFieldValidatorReasons(rule, fieldValidator);
1322
+ const annotatedRule = {
1323
+ ...rule,
1324
+ valid: ruleValid,
1325
+ ...ruleReasons ? { reasons: ruleReasons } : null,
1326
+ path: childPath,
1327
+ level: childLevel
1328
+ };
1329
+ annotatedRules.push(annotatedRule);
1330
+ ruleIndex++;
1331
+ }
1332
+ const groupValid = groupSelfValid && allChildrenValid;
1333
+ if (groupValid) stats.validGroups++;
1334
+ else stats.invalidGroups++;
1335
+ if (require_objectUtils.isRuleGroupType(rg)) return {
1336
+ ...rg,
1337
+ valid: groupValid,
1338
+ ...groupReasons ? { reasons: groupReasons } : null,
1339
+ path,
1340
+ level,
1341
+ rules: annotatedRules
1342
+ };
1343
+ return {
1344
+ ...rg,
1345
+ valid: groupValid,
1346
+ ...groupReasons ? { reasons: groupReasons } : null,
1347
+ path,
1348
+ level,
1349
+ rules: annotatedRules
1350
+ };
1351
+ };
1352
+ const query = processRuleGroup(ruleGroup, []);
1353
+ if (hasFieldsConfig) {
1354
+ const referencedFields = new Set(Object.keys(fieldSummary));
1355
+ for (const [fieldName] of fieldsByName) if (!referencedFields.has(fieldName)) diagnostics.push({
1356
+ id: "",
1357
+ path: [],
1358
+ code: "UNREFERENCED_FIELD",
1359
+ message: `Field "${fieldName}" is defined in the fields config but not used in the query`,
1360
+ source: "field-check"
1361
+ });
1362
+ }
1363
+ return {
1364
+ query,
1365
+ diagnostics,
1366
+ stats,
1367
+ fieldSummary
1368
+ };
1369
+ };
1370
+ /**
1371
+ * Collects diagnostic entries for a single rule.
1372
+ */
1373
+ const collectRuleDiagnostics = (rule, path, validationResult, fieldValidator, ruleValid, diagnostics, placeholderFieldName, placeholderOperatorName, placeholderValueName, hasFieldsConfig, fieldsByName) => {
1374
+ const id = rule.id ?? "";
1375
+ if (rule.muted) diagnostics.push({
1376
+ id,
1377
+ path,
1378
+ code: "MUTED",
1379
+ message: "Rule is muted",
1380
+ source: "muted"
1381
+ });
1382
+ if (rule.field === placeholderFieldName) diagnostics.push({
1383
+ id,
1384
+ path,
1385
+ code: "PLACEHOLDER_FIELD",
1386
+ message: "Rule has a placeholder field",
1387
+ source: "placeholder"
1388
+ });
1389
+ if (rule.operator === placeholderOperatorName) diagnostics.push({
1390
+ id,
1391
+ path,
1392
+ code: "PLACEHOLDER_OPERATOR",
1393
+ message: "Rule has a placeholder operator",
1394
+ source: "placeholder"
1395
+ });
1396
+ if (placeholderValueName !== void 0 && rule.value === placeholderValueName) diagnostics.push({
1397
+ id,
1398
+ path,
1399
+ code: "PLACEHOLDER_VALUE",
1400
+ message: "Rule has a placeholder value",
1401
+ source: "placeholder"
1402
+ });
1403
+ if (!rule.muted && rule.field !== placeholderFieldName && rule.operator !== placeholderOperatorName && !(placeholderValueName !== void 0 && rule.value === placeholderValueName)) {
1404
+ if (typeof validationResult === "boolean" && !validationResult) diagnostics.push({
1405
+ id,
1406
+ path,
1407
+ code: "CUSTOM_VALIDATOR",
1408
+ message: "Rule failed validation",
1409
+ source: "query-validator"
1410
+ });
1411
+ else if (typeof validationResult !== "boolean" && isValidationResult(validationResult) && !validationResult.valid) {
1412
+ const reasons = validationResult.reasons;
1413
+ diagnostics.push({
1414
+ id,
1415
+ path,
1416
+ code: "CUSTOM_VALIDATOR",
1417
+ message: reasons ? `Invalid: ${reasons.join(", ")}` : "Rule failed validation",
1418
+ source: "query-validator"
1419
+ });
1420
+ } else if (!ruleValid && typeof fieldValidator === "function") {
1421
+ const vr = fieldValidator(rule);
1422
+ const reasons = typeof vr !== "boolean" && isValidationResult(vr) && !vr.valid ? vr.reasons : void 0;
1423
+ diagnostics.push({
1424
+ id,
1425
+ path,
1426
+ code: "CUSTOM_VALIDATOR",
1427
+ message: reasons ? `Invalid: ${reasons.join(", ")}` : "Rule failed field validation",
1428
+ source: "field-validator"
1429
+ });
1430
+ }
1431
+ }
1432
+ if (hasFieldsConfig && !fieldsByName.has(rule.field) && rule.field !== placeholderFieldName) diagnostics.push({
1433
+ id,
1434
+ path,
1435
+ code: "UNDEFINED_FIELD",
1436
+ message: `Field "${rule.field}" is not defined in the fields config`,
1437
+ source: "field-check"
1438
+ });
1439
+ if (hasFieldsConfig) {
1440
+ const fieldDef = fieldsByName.get(rule.field);
1441
+ if (fieldDef?.inputType) {
1442
+ const mismatchCode = checkValueTypeMismatch(rule.value, fieldDef.inputType);
1443
+ if (mismatchCode) diagnostics.push({
1444
+ id,
1445
+ path,
1446
+ code: mismatchCode,
1447
+ message: `Value "${rule.value}" is not compatible with input type "${fieldDef.inputType}"`,
1448
+ source: "type-check"
1449
+ });
1450
+ }
1451
+ }
1452
+ };
1453
+ /**
1454
+ * Extracts `reasons` from a validation result, if present.
1455
+ */
1456
+ const getReasons = (validationResult) => {
1457
+ if (typeof validationResult !== "boolean" && isValidationResult(validationResult) && !validationResult.valid && validationResult.reasons) return validationResult.reasons;
1458
+ };
1459
+ /**
1460
+ * Runs a field-level validator and extracts `reasons` if present.
1461
+ */
1462
+ const getFieldValidatorReasons = (rule, fieldValidator) => {
1463
+ if (typeof fieldValidator === "function") {
1464
+ const vr = fieldValidator(rule);
1465
+ if (typeof vr !== "boolean" && isValidationResult(vr) && !vr.valid && vr.reasons) return vr.reasons;
1466
+ }
1467
+ };
1468
+ //#endregion
1150
1469
  //#region src/utils/formatQuery/defaultRuleProcessorElasticSearch.ts
1151
1470
  const rangeOperatorMap = {
1152
1471
  "<": "lt",
@@ -1525,12 +1844,12 @@ const defaultRuleProcessorLDAP = (rule, options = {}) => {
1525
1844
  return negateIf(`(&(${field}>=${ldapEscape(firstValue)})(${field}<=${ldapEscape(secondValue)}))`, operatorLC === "notbetween");
1526
1845
  }
1527
1846
  }
1528
- // istanbul ignore next
1847
+ // v8 ignore next
1529
1848
  return "";
1530
1849
  };
1531
1850
  //#endregion
1532
1851
  //#region src/utils/formatQuery/defaultValueProcessorNL.ts
1533
- const escapeStringValueQuotes = (v, quoteChar, escapeQuotes) => escapeQuotes && typeof v === "string" ? v.replaceAll(`${quoteChar}`, `${quoteChar}${quoteChar}`) : v;
1852
+ const escapeStringValueQuotes = (v, quoteChar, escapeQuotes) => escapeQuotes && typeof v === "string" ? v.replaceAll(`${quoteChar}`, `${quoteChar}${quoteChar}`) : /* v8 ignore next -- @preserve */ v;
1534
1853
  /**
1535
1854
  * Default value processor used by {@link formatQuery} for "natural_language" format.
1536
1855
  *
@@ -1548,7 +1867,7 @@ const defaultValueProcessorNL = (rule, opts = {}) => {
1548
1867
  quoteFieldNamesWith,
1549
1868
  fieldIdentifierSeparator
1550
1869
  });
1551
- const t = translations ?? ( /* istanbul ignore next */ {});
1870
+ const t = translations ?? ( /* v8 ignore start -- @preserve */ {});
1552
1871
  const orTL = t.or ?? "or";
1553
1872
  const trueTL = t.true ?? "true";
1554
1873
  const falseTL = t.false ?? "false";
@@ -1604,7 +1923,7 @@ const defaultExportOperatorMap = {
1604
1923
  between: ["is between", "is between the values in"],
1605
1924
  notbetween: ["is not between", "is not between the values in"]
1606
1925
  };
1607
- /* istanbul ignore next */
1926
+ /* v8 ignore next -- @preserve */
1608
1927
  const defaultGetOperators = () => [];
1609
1928
  /**
1610
1929
  * Default operator processor used by {@link formatQuery} for "natural_language" format.
@@ -1613,7 +1932,7 @@ const defaultGetOperators = () => [];
1613
1932
  */
1614
1933
  const defaultOperatorProcessorNL = (rule, opts = {}) => {
1615
1934
  const { field, operator, valueSource = "value" } = rule;
1616
- // istanbul ignore next
1935
+ // v8 ignore next
1617
1936
  const { getOperators = defaultGetOperators, operatorMap: operatorMapParam = defaultExportOperatorMap } = opts;
1618
1937
  const mergedOperatorMap = new Map(Object.entries(defaultExportOperatorMap));
1619
1938
  for (const [key, value] of Object.entries(operatorMapParam)) mergedOperatorMap.set(require_objectUtils.lc(key), value);
@@ -1642,8 +1961,8 @@ const defaultOperatorProcessorNL = (rule, opts = {}) => {
1642
1961
  */
1643
1962
  const defaultRuleProcessorNL = (rule, opts) => {
1644
1963
  const { field, operator } = rule;
1645
- // istanbul ignore next
1646
- const { fieldData, quoteFieldNamesWith = ["", ""], fieldIdentifierSeparator = "", quoteValuesWith = `'`, operatorProcessor = defaultOperatorProcessorNL, valueProcessor = defaultValueProcessorNL, concatOperator = "||", wordOrder = "SVO" } = opts ?? ( /* istanbul ignore next */ {});
1964
+ // v8 ignore next
1965
+ const { fieldData, quoteFieldNamesWith = ["", ""], fieldIdentifierSeparator = "", quoteValuesWith = `'`, operatorProcessor = defaultOperatorProcessorNL, valueProcessor = defaultValueProcessorNL, concatOperator = "||", wordOrder = "SVO" } = opts ?? ( /* v8 ignore start -- @preserve */ {});
1647
1966
  const processedField = require_utils.getQuotedFieldName(fieldData?.label ?? field, {
1648
1967
  quoteFieldNamesWith,
1649
1968
  fieldIdentifierSeparator
@@ -1749,7 +2068,7 @@ const defaultRuleProcessorSQL = (rule, opts = {}) => {
1749
2068
  * @group Export
1750
2069
  */
1751
2070
  const defaultRuleProcessorParameterized = (rule, opts, meta) => {
1752
- // istanbul ignore next
2071
+ // v8 ignore next
1753
2072
  const { fieldData, format, getNextNamedParam, parseNumbers, paramPrefix, paramsKeepPrefix, numberedParams, quoteFieldNamesWith = ["", ""], fieldIdentifierSeparator, concatOperator, operatorProcessor = defaultOperatorProcessorSQL, valueProcessor = defaultValueProcessorByRule } = opts ?? {};
1754
2073
  const { processedParams = [] } = meta ?? {};
1755
2074
  const parameterized = format === "parameterized";
@@ -1768,6 +2087,7 @@ const defaultRuleProcessorParameterized = (rule, opts, meta) => {
1768
2087
  });
1769
2088
  const ruleField = wrapFieldName(rule.field);
1770
2089
  const matchEval = require_utils.processMatchMode(rule);
2090
+ /* v8 ignore start -- @preserve */
1771
2091
  if (matchEval === false) return;
1772
2092
  else if (matchEval) {
1773
2093
  if (opts?.preset !== "postgresql") return finalize("");
@@ -1780,7 +2100,6 @@ const defaultRuleProcessorParameterized = (rule, opts, meta) => {
1780
2100
  ...opts,
1781
2101
  fields: []
1782
2102
  });
1783
- // istanbul ignore else
1784
2103
  if (Array.isArray(nestedParams)) params.push(...nestedParams);
1785
2104
  else Object.assign(paramsNamed, nestedParams);
1786
2105
  switch (mode) {
@@ -1795,6 +2114,7 @@ const defaultRuleProcessorParameterized = (rule, opts, meta) => {
1795
2114
  }
1796
2115
  }
1797
2116
  }
2117
+ /* v8 ignore stop -- @preserve */
1798
2118
  const value = valueProcessor(rule, {
1799
2119
  parseNumbers,
1800
2120
  quoteFieldNamesWith,
@@ -1835,7 +2155,7 @@ const defaultRuleProcessorParameterized = (rule, opts, meta) => {
1835
2155
  }
1836
2156
  let paramValue = rule.value;
1837
2157
  if (typeof rule.value === "string") if (require_utils.shouldRenderAsNumber(rule.value, parseNumbers)) paramValue = require_utils.parseNumber(rule.value, { parseNumbers });
1838
- else paramValue = /^'.*'$/g.test(value) ? value.replaceAll(/(^'|'$)/g, "") : value;
2158
+ else paramValue = /^'.*'$/g.test(value) ? value.replaceAll(/(^'|'$)/g, "") : /* v8 ignore next -- @preserve */ value;
1839
2159
  let paramName = "";
1840
2160
  if (parameterized) params.push(paramValue);
1841
2161
  else {
@@ -1854,9 +2174,9 @@ const processNumber = (value, fallback, parseNumbers) => require_utils.shouldRen
1854
2174
  */
1855
2175
  const defaultRuleProcessorPrisma = (rule, options = {}) => {
1856
2176
  const { field, operator, value, valueSource } = rule;
1857
- // istanbul ignore next
2177
+ // v8 ignore next
1858
2178
  const { parseNumbers, preserveValueOrder } = options;
1859
- if (valueSource === "field" || require_utils.processMatchMode(rule)) return;
2179
+ if (valueSource === "field" || require_utils.processMatchMode(rule)) return void 0;
1860
2180
  const operatorLC = require_objectUtils.lc(operator);
1861
2181
  switch (operatorLC) {
1862
2182
  case "=": return { [field]: processNumber(value, value, parseNumbers) };
@@ -1914,7 +2234,7 @@ const defaultRuleProcessorPrisma = (rule, options = {}) => {
1914
2234
  */
1915
2235
  const defaultRuleProcessorSequelize = (rule, { parseNumbers, preserveValueOrder, context = {} } = {}) => {
1916
2236
  const { sequelizeOperators: Op, sequelizeCol: col, sequelizeFn: fn } = context;
1917
- if (require_utils.processMatchMode(rule)) return;
2237
+ if (require_utils.processMatchMode(rule)) return void 0;
1918
2238
  const { field, operator, value, valueSource } = rule;
1919
2239
  const valueIsField = valueSource === "field";
1920
2240
  const operatorLC = require_objectUtils.lc(operator);
@@ -2018,9 +2338,10 @@ const defaultRuleProcessors = {
2018
2338
  prisma: defaultRuleProcessorPrisma,
2019
2339
  sequelize: defaultRuleProcessorSequelize,
2020
2340
  spel: defaultRuleProcessorSpEL,
2021
- sql: defaultRuleProcessorSQL
2341
+ sql: defaultRuleProcessorSQL,
2342
+ diagnostics: defaultRuleProcessorSQL
2022
2343
  };
2023
- /* istanbul ignore next */
2344
+ /* v8 ignore next -- @preserve */
2024
2345
  const defaultOperatorProcessor = (r) => r.operator;
2025
2346
  const defaultOperatorProcessors = {
2026
2347
  cel: defaultOperatorProcessor,
@@ -2039,7 +2360,8 @@ const defaultOperatorProcessors = {
2039
2360
  prisma: defaultOperatorProcessor,
2040
2361
  sequelize: defaultOperatorProcessor,
2041
2362
  spel: defaultOperatorProcessor,
2042
- sql: defaultOperatorProcessorSQL
2363
+ sql: defaultOperatorProcessorSQL,
2364
+ diagnostics: defaultOperatorProcessor
2043
2365
  };
2044
2366
  const defaultFallbackExpressions = {
2045
2367
  cel: "1 == 1",
@@ -2113,24 +2435,26 @@ function formatQuery(ruleGroup, optionParam = {}) {
2113
2435
  const getOperators = (f, m) => require_utils.toFullOptionList(getOperators_option(f, m) ?? []);
2114
2436
  const fallbackExpression = fallbackExpression_option ?? defaultFallbackExpressions[format] ?? defaultFallbackExpressions.sql;
2115
2437
  let validationMap = {};
2116
- // istanbul ignore else
2438
+ // v8 ignore else
2117
2439
  if (typeof validator === "function") {
2118
2440
  const validationResult = validator(ruleGroup);
2119
2441
  if (typeof validationResult === "boolean") {
2120
- // istanbul ignore else
2121
- if (!validationResult) return format === "parameterized" ? {
2122
- sql: fallbackExpression,
2123
- params: []
2124
- } : format === "parameterized_named" ? {
2125
- sql: fallbackExpression,
2126
- params: {}
2127
- } : format === "mongodb" ? `{${fallbackExpression}}` : format === "mongodb_query" ? mongoDbFallback : format === "prisma" ? prismaFallback : format === "jsonlogic" ? false : format === "elasticsearch" ? {} : format === "drizzle" || format === "sequelize" ? void 0 : fallbackExpression;
2442
+ // v8 ignore else
2443
+ if (!validationResult) {
2444
+ if (format !== "diagnostics") return format === "parameterized" ? {
2445
+ sql: fallbackExpression,
2446
+ params: []
2447
+ } : format === "parameterized_named" ? {
2448
+ sql: fallbackExpression,
2449
+ params: {}
2450
+ } : format === "mongodb" ? `{${fallbackExpression}}` : format === "mongodb_query" ? mongoDbFallback : format === "prisma" ? prismaFallback : format === "jsonlogic" ? false : format === "elasticsearch" ? {} : format === "drizzle" || format === "sequelize" ? void 0 : fallbackExpression;
2451
+ }
2128
2452
  } else validationMap = validationResult;
2129
2453
  }
2130
2454
  const validatorMap = {};
2131
2455
  const uniqueFields = require_utils.toFlatOptionArray(fields);
2132
2456
  for (const f of uniqueFields)
2133
- // istanbul ignore else
2457
+ // v8 ignore else
2134
2458
  if (typeof f.validator === "function") validatorMap[f.value ?? f.name] = f.validator;
2135
2459
  const validateRule = (rule) => {
2136
2460
  let validationResult;
@@ -2140,7 +2464,7 @@ function formatQuery(ruleGroup, optionParam = {}) {
2140
2464
  const fieldArr = uniqueFields.filter((f) => f.name === rule.field);
2141
2465
  if (fieldArr.length > 0) {
2142
2466
  const field = fieldArr[0];
2143
- // istanbul ignore else
2467
+ // v8 ignore else
2144
2468
  if (typeof field.validator === "function") fieldValidator = field.validator;
2145
2469
  }
2146
2470
  }
@@ -2184,6 +2508,7 @@ function formatQuery(ruleGroup, optionParam = {}) {
2184
2508
  case "prisma": return defaultRuleGroupProcessorPrisma(ruleGroup, finalOptions);
2185
2509
  case "drizzle": return defaultRuleGroupProcessorDrizzle(ruleGroup, finalOptions);
2186
2510
  case "sequelize": return defaultRuleGroupProcessorSequelize(ruleGroup, finalOptions);
2511
+ case "diagnostics": return defaultRuleGroupProcessorDiagnostics(ruleGroup, finalOptions);
2187
2512
  default: return "";
2188
2513
  }
2189
2514
  }
@@ -2248,6 +2573,7 @@ exports.defaultNLTranslations = require_utils.defaultNLTranslations;
2248
2573
  exports.defaultOperatorProcessorNL = defaultOperatorProcessorNL;
2249
2574
  exports.defaultOperatorProcessorSQL = defaultOperatorProcessorSQL;
2250
2575
  exports.defaultRuleGroupProcessorCEL = defaultRuleGroupProcessorCEL;
2576
+ exports.defaultRuleGroupProcessorDiagnostics = defaultRuleGroupProcessorDiagnostics;
2251
2577
  exports.defaultRuleGroupProcessorDrizzle = defaultRuleGroupProcessorDrizzle;
2252
2578
  exports.defaultRuleGroupProcessorElasticSearch = defaultRuleGroupProcessorElasticSearch;
2253
2579
  exports.defaultRuleGroupProcessorJSONata = defaultRuleGroupProcessorJSONata;