react-querybuilder
Version:
React Query Builder component for constructing queries and filters, with utilities for executing them in various database and evaluation contexts
172 lines (166 loc) • 7.12 kB
JavaScript
const require_isRuleGroup = require('./isRuleGroup-Bf2BUwdE.js');
const require_optGroupUtils = require('./optGroupUtils-BVZSodaD.js');
const immer = require_isRuleGroup.__toESM(require("immer"));
//#region src/utils/filterFieldsByComparator.ts
const filterByComparator = (field, operator, fieldToCompare) => {
const fullField = require_optGroupUtils.toFullOption(field);
const fullFieldToCompare = require_optGroupUtils.toFullOption(fieldToCompare);
if (fullField.value === fullFieldToCompare.value) return false;
if (typeof fullField.comparator === "string") return fullField[fullField.comparator] === fullFieldToCompare[fullField.comparator];
return fullField.comparator?.(fullFieldToCompare, operator) ?? false;
};
/**
* For a given {@link FullField}, returns the `fields` list filtered for
* other fields that match by `comparator`. Only fields *other than the
* one in question* will ever be included, even if `comparator` is `null`
* or `undefined`. If `comparator` is a string, fields with the same value
* for that property will be included. If `comparator` is a function, each
* field will be passed to the function along with the `operator` and fields
* for which the function returns `true` will be included.
*
* @group Option Lists
*/
const filterFieldsByComparator = (field, fields, operator) => {
if (!field.comparator) {
const filterOutSameField = (f) => (f.value ?? f.name) !== (field.value ?? field.name);
if (require_optGroupUtils.isFlexibleOptionGroupArray(fields)) return fields.map((og) => ({
...og,
options: og.options.filter((v) => filterOutSameField(v))
}));
return fields.filter((v) => filterOutSameField(v));
}
if (require_optGroupUtils.isFlexibleOptionGroupArray(fields)) return fields.map((og) => ({
...og,
options: og.options.filter((f) => filterByComparator(field, operator, f))
})).filter((og) => og.options.length > 0);
return fields.filter((f) => filterByComparator(field, operator, f));
};
//#endregion
//#region src/utils/getValueSourcesUtil.ts
const defaultValueSourcesArray = [{
name: "value",
value: "value",
label: "value"
}];
const dummyFD = {
name: "name",
value: "name",
valueSources: null,
label: "label"
};
/**
* Utility function to get the value sources array for the given
* field and operator. If the field definition does not define a
* `valueSources` property, the `getValueSources` prop is used.
* Returns `[FullOption<"value">]` by default.
*/
const getValueSourcesUtil = (fieldData, operator, getValueSources) => {
const fd = fieldData ? require_optGroupUtils.toFullOption(fieldData) : dummyFD;
let valueSourcesNEW = fd.valueSources ?? false;
if (typeof valueSourcesNEW === "function") valueSourcesNEW = valueSourcesNEW(operator);
if (!valueSourcesNEW && getValueSources) valueSourcesNEW = getValueSources(fd.value, operator, { fieldData: fd });
if (!valueSourcesNEW) return defaultValueSourcesArray;
if (require_optGroupUtils.isFlexibleOptionArray(valueSourcesNEW)) return require_optGroupUtils.toFullOptionList(valueSourcesNEW);
return valueSourcesNEW.map((vs) => defaultValueSourcesArray.find((dmm) => dmm.value === require_isRuleGroup.lc(vs)) ?? {
name: vs,
value: vs,
label: vs
});
};
//#endregion
//#region src/utils/parserUtils.ts
const getFieldsArray = (fields) => {
const fieldsArray = fields ? Array.isArray(fields) ? fields : Object.keys(fields).map((fld) => ({
...fields[fld],
name: fld
})).sort((a, b) => a.label.localeCompare(b.label)) : [];
return require_optGroupUtils.toFlatOptionArray(fieldsArray);
};
function fieldIsValidUtil(params) {
const { fieldsFlat, fieldName, operator, subordinateFieldName, getValueSources } = params;
const vsIncludes = (vs) => {
const vss = getValueSourcesUtil(primaryField, operator, getValueSources);
return require_optGroupUtils.isFlexibleOptionArray(vss) && vss.some((vso) => vso.value === vs || vso.name === vs);
};
if (fieldsFlat.length === 0) return true;
let valid = false;
const primaryField = require_optGroupUtils.toFullOption(fieldsFlat.find((ff) => ff.name === fieldName));
if (primaryField) {
valid = !(!subordinateFieldName && operator !== "notNull" && operator !== "null" && !vsIncludes("value"));
if (valid && !!subordinateFieldName) if (vsIncludes("field") && fieldName !== subordinateFieldName) {
const validSubordinateFields = filterFieldsByComparator(primaryField, fieldsFlat, operator);
if (!validSubordinateFields.some((vsf) => vsf.name === subordinateFieldName)) valid = false;
} else valid = false;
}
return valid;
}
//#endregion
//#region src/utils/generateID.ts
const cryptoModule = globalThis.crypto;
/**
* Default `id` generator. Generates a valid v4 UUID. Uses `crypto.randomUUID()`
* when available, otherwise uses an alternate method based on `getRandomValues`.
* The returned string is guaranteed to match this regex:
* ```
* /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
* ```
* @returns Valid v4 UUID
*/
// istanbul ignore next
let generateID = () => "00-0-4-2-000".replaceAll(/[^-]/g, (s) => ((Math.random() + Math.trunc(s)) * 65536 >> Number.parseInt(s)).toString(16).padStart(4, "0"));
// istanbul ignore else
if (cryptoModule) {
// istanbul ignore else
if (typeof cryptoModule.randomUUID === "function") generateID = () => cryptoModule.randomUUID();
else if (typeof cryptoModule.getRandomValues === "function") {
const position19vals = "89ab";
const container = new Uint32Array(32);
generateID = () => {
cryptoModule.getRandomValues(container);
let id = (container[0] % 16).toString(16);
for (let i = 1; i < 32; i++) {
if (i === 12) id = `${id}4`;
else if (i === 16) id = `${id}${position19vals[container[17] % 4]}`;
else id = `${id}${(container[i] % 16).toString(16)}`;
if (i === 7 || i === 11 || i === 15 || i === 19) id = `${id}-`;
}
return id;
};
}
}
//#endregion
//#region src/utils/prepareQueryObjects.ts
/**
* Ensures that a rule is valid by adding an `id` property if it does not already exist.
*/
const prepareRule = (rule, { idGenerator = generateID } = {}) => (0, immer.produce)(rule, (draft) => {
if (!draft.id) draft.id = idGenerator();
});
/**
* Ensures that a rule group is valid by recursively adding an `id` property to the group itself
* and all its rules and subgroups where one does not already exist.
*/
const prepareRuleGroup = (queryObject, { idGenerator = generateID } = {}) => (0, immer.produce)(queryObject, (draft) => {
if (!draft.id) draft.id = idGenerator();
draft.rules = draft.rules.map((r) => typeof r === "string" ? r : require_isRuleGroup.isRuleGroup(r) ? prepareRuleGroup(r, { idGenerator }) : prepareRule(r, { idGenerator }));
});
//#endregion
Object.defineProperty(exports, 'fieldIsValidUtil', {
enumerable: true,
get: function () {
return fieldIsValidUtil;
}
});
Object.defineProperty(exports, 'getFieldsArray', {
enumerable: true,
get: function () {
return getFieldsArray;
}
});
Object.defineProperty(exports, 'prepareRuleGroup', {
enumerable: true,
get: function () {
return prepareRuleGroup;
}
});
//# sourceMappingURL=prepareQueryObjects-D-xu06SF.js.map