react-querybuilder
Version:
React Query Builder component for constructing queries and filters, with utilities for executing them in various database and evaluation contexts
1 lines • 568 kB
Source Map (JSON)
{"version":3,"file":"QueryBuilderInternal-CrUkpBSt.mjs","names":["QueryBuilderContext: Context<QueryBuilderContextType>","DragHandle: React.ForwardRefExoticComponent<\n DragHandleProps & React.RefAttributes<HTMLSpanElement>\n>","defaultPlaceholderFieldName: typeof defaultPlaceholderName","defaultPlaceholderFieldLabel: typeof defaultPlaceholderLabel","defaultPlaceholderFieldGroupLabel: typeof defaultPlaceholderLabel","defaultPlaceholderOperatorName: typeof defaultPlaceholderName","defaultPlaceholderOperatorLabel: typeof defaultPlaceholderLabel","defaultPlaceholderOperatorGroupLabel: typeof defaultPlaceholderLabel","defaultPlaceholderValueName: typeof defaultPlaceholderName","defaultPlaceholderValueLabel: typeof defaultPlaceholderLabel","defaultPlaceholderValueGroupLabel: typeof defaultPlaceholderLabel","defaultOperatorLabelMap: Record<DefaultOperatorName, string>","defaultCombinatorLabelMap: Record<DefaultCombinatorNameExtended, string>","defaultOperators: DefaultOperators","defaultOperatorNegationMap: Record<DefaultOperatorName, DefaultOperatorName>","defaultCombinators: DefaultCombinators","defaultCombinatorsExtended: DefaultCombinatorsExtended","defaultMatchModes: DefaultMatchModes","defaultControlClassnames: Classnames","rootPath: Path","v","numericRegex: RegExp","numericQuantityRegex","rules: (RuleGroupTypeIC | RuleType | string)[]","defaultValidator: QueryValidator","result: ValidationMap","reasons: any[]","recipe: (o: Opt | string) => ToFullOption<Opt>","idObj: { name?: string; value?: string }","recipe: (ol: FlexibleOptionList<Opt>) => FullOptionList<Opt>","newArray: T[]","newArray: OptionGroup<ToFullOption<T>>[]","optionsForThisGroup: WithUnknownIndex<ToFullOption<T>>[]","valAsNum: number | bigint","celCombinatorMap: {\n and: '&&';\n or: '||';\n}","jsonLogicAdditionalOperators: Record<\n 'startsWith' | 'endsWith',\n (a: string, b: string) => boolean\n>","numericRegex","result: string[]","defaultNLTranslations: NLTranslations","defaultRuleGroupProcessorCEL: RuleGroupProcessor<string>","expression: string","shouldNegate","defaultRuleProcessorCEL: RuleProcessor","negate","defaultRuleGroupProcessorMongoDBQuery: RuleGroupProcessor","expressions: Record<string, unknown>[]","processNumber","defaultRuleProcessorMongoDBQuery: RuleProcessor","defaultRuleProcessorMongoDB: RuleProcessor","defaultRuleGroupProcessorSpEL: RuleGroupProcessor<string>","expression: string","shouldNegate","negate","defaultRuleProcessorSpEL: RuleProcessor","escapeStringValueQuotes","defaultValueProcessorByRule: ValueProcessorByRule","defaultRuleProcessorDrizzle: RuleProcessor","defaultRuleGroupProcessorDrizzle: RuleGroupProcessor<\n (columns: Record<string, Column> | Table, drizzleOperators: Operators) => SQL | undefined\n>","ruleGroupSQL: SQL | undefined","defaultRuleGroupProcessorElasticSearch: RuleGroupProcessor<Record<string, unknown>>","defaultRuleGroupProcessorJSONata: RuleGroupProcessor","expression: string","defaultRuleGroupProcessorJsonLogic: RuleGroupProcessor<RQBJsonLogic>","jsonRuleGroup: RQBJsonLogic","defaultRuleGroupProcessorLDAP: RuleGroupProcessor<string>","rules: string[]","defaultRuleGroupProcessorMongoDB: RuleGroupProcessor<string>","expressions: string[]","defaultRuleGroupProcessorNL: RuleGroupProcessor<string>","defaultRuleGroupProcessorParameterized: RuleGroupProcessor<\n ParameterizedSQL | ParameterizedNamedSQL\n>","params: any[]","paramsNamed: Record<string, any>","fieldParams: Map<string, Set<string>>","defaultRuleGroupProcessorPrisma: RuleGroupProcessor<\n Record<string, unknown> | undefined\n>","expressions: Record<string, unknown>[]","defaultRuleGroupProcessorSequelize: RuleGroupProcessor<WhereOptions | undefined>","expressions: Record<string, unknown>[]","defaultRuleGroupProcessorSQL: RuleGroupProcessor<string>","negateIfNotOp","textFunctionMap: Partial<Record<Lowercase<DefaultOperatorName>, string>>","defaultRuleProcessorElasticSearch: RuleProcessor","negate","defaultRuleProcessorJSONata: RuleProcessor","defaultRuleProcessorJsonLogic: RuleProcessor","fieldObject: JsonLogicVar","jsonRule: RQBJsonLogic","negate","defaultRuleProcessorLDAP: RuleProcessor","defaultValueProcessorNL: ValueProcessorByRule","defaultExportOperatorMap: ExportOperatorMap","defaultOperatorProcessorNL: RuleProcessor","defaultRuleProcessorNL: RuleProcessor","defaultOperatorProcessorSQL: RuleProcessor","defaultRuleProcessorSQL: RuleProcessor","defaultRuleProcessorParameterized: RuleProcessor","params: any[]","paramsNamed: Record<string, any>","inParams: string[]","defaultRuleProcessorPrisma: RuleProcessor","defaultRuleProcessorSequelize: RuleProcessor","sqlDialectPresets: Record<SQLPreset, FormatQueryOptions>","formatQueryOptionPresets: Record<string, FormatQueryOptions>","defaultOperatorProcessor: RuleProcessor","defaultFallbackExpressions: Partial<Record<ExportFormat, string>>","optObj: MostFormatQueryOptions","valueProcessor: ValueProcessorByRule","getOperators: FormatQueryOptions['getOperators']","validationMap: ValidationMap","validatorMap: Record<string, RuleValidator>","validationResult: boolean | ValidationResult | undefined","fieldValidator: RuleValidator | undefined","finalOptions: FormatQueryFinalOptions","defaultValueProcessor: ValueProcessorLegacy","defaultMongoDBValueProcessor: ValueProcessorLegacy","defaultCELValueProcessor: ValueProcessorLegacy","defaultSpELValueProcessor: ValueProcessorLegacy","defaultValueProcessorCELByRule: RuleProcessor","defaultValueProcessorMongoDBByRule: RuleProcessor","defaultValueProcessorSpELByRule: RuleProcessor","target: FindPathReturnType","t: RuleGroupTypeAny | RuleType | string","commonAncestorPath: Path","target: RuleType | RuleGroupTypeAny","generateAccessibleDescription: ADG","nullFwdComp: ForwardRefExoticComponent<DragHandleProps & RefAttributes<HTMLElement>>","rqbContext: QueryBuilderContextProps<F, O>","contextCE: ControlElementsProp<F, O>","propsCE: ControlElementsProp<F, O>","propsT: Partial<Translations>","contextT: Partial<Translations>","dummyFD","matchModes: boolean | MatchMode[] | FlexibleOption<MatchMode>[]","defaultValueSourcesArray: ValueSourceFullOptions","valueSourcesNEW:\n | false\n | ValueSources\n | ValueSourceFlexibleOptions\n | ((operator: string) => ValueSources | ValueSourceFlexibleOptions)","rules","dummyFieldData: FullField","dummyPath: Path","initialState: QueriesSliceState","queriesSlice: Slice<\n QueriesSliceState,\n {\n setQueryState: (\n state: QueriesSliceState,\n {\n payload: { qbId, query },\n }: PayloadAction<SetQueryStateParams>\n ) => void;\n },\n 'queries',\n 'queries',\n { getQuerySelectorById: (state: QueriesSliceState, qbId: string) => RuleGroupTypeAny }\n>","QueryBuilderStateContext: React.Context<ReactReduxContextValue<\n RqbState,\n UnknownAction\n> | null>","initialState: WarningsSliceState","warningsSlice: Slice<\n {\n [messages.errorInvalidIndependentCombinatorsProp]: boolean;\n [messages.errorUnnecessaryIndependentCombinatorsProp]: boolean;\n [messages.errorDeprecatedRuleGroupProps]: boolean;\n [messages.errorDeprecatedRuleProps]: boolean;\n [messages.errorBothQueryDefaultQuery]: boolean;\n [messages.errorUncontrolledToControlled]: boolean;\n [messages.errorControlledToUncontrolled]: boolean;\n [messages.errorEnabledDndWithoutReactDnD]: boolean;\n },\n {\n // oxlint-disable-next-line typescript/no-explicit-any\n rqbWarn: (state: any, { payload }: PayloadAction<Messages>) => void;\n },\n 'warnings'\n>","useRQB_INTERNAL_QueryBuilderDispatch: UseQueryBuilderDispatch","useRQB_INTERNAL_QueryBuilderStore: UseStore<Store<RqbState, UnknownAction>>","storeCommon: ConfigureStoreOptions","om: Partial<FullOptionRecord<FullOption>>","useRQB_INTERNAL_QueryBuilderSelector: TypedUseSelectorHook<RqbState>","useQueryBuilderSelector: TypedUseSelectorHook<RqbState>","defaultValidationResult: ReturnType<QueryValidator>","defaultValidationMap: ValidationMap","defaultDisabledPaths: Path[]","validationResult","validationMap","combinatorPropObject: Pick<RuleGroupProps, 'combinator'>","valsFinal: FullOptionList<BaseOption>","value: string | (string | null)[] | boolean | null","RuleGroup: React.MemoExoticComponent<(props: RuleGroupProps) => React.JSX.Element>","RuleGroup","RuleGroupHeaderComponents: React.MemoExoticComponent<\n (rg: UseRuleGroup) => React.JSX.Element\n>","RuleGroupHeaderComponents","RuleGroupBodyComponents: React.MemoExoticComponent<\n (rg: UseRuleGroup) => React.JSX.Element\n>","RuleGroupBodyComponents","onCombinatorChange: ValueChangeEventHandler","addRule: ActionElementEventHandler","addGroup: ActionElementEventHandler","cloneGroup: ActionElementEventHandler","toggleLockGroup: ActionElementEventHandler","removeGroup: ActionElementEventHandler","paths: { path: Path; disabled: boolean }[]","defaultSubproperties: FullOption[]","Rule: React.MemoExoticComponent<(r: RuleProps) => React.JSX.Element>","Rule","RuleComponents: React.MemoExoticComponent<\n (r: RuleComponentsProps) => React.JSX.Element\n>","RuleComponents","RuleComponentsWithSubQuery: React.MemoExoticComponent<\n (r: RuleComponentsProps) => React.JSX.Element\n>","RuleComponentsWithSubQuery","cloneRule: ActionElementEventHandler","toggleLockRule: ActionElementEventHandler","removeRule: ActionElementEventHandler","shiftRuleUp: ActionElementEventHandler","shiftRuleDown: ActionElementEventHandler","fieldData: FullField","bi: bigint","clsx","defaultTranslations: TranslationsFull","defaultControlElements: {\n actionElement: typeof ActionElement;\n addGroupAction: typeof ActionElement;\n addRuleAction: typeof ActionElement;\n cloneGroupAction: typeof ActionElement;\n cloneRuleAction: typeof ActionElement;\n combinatorSelector: typeof ValueSelector;\n dragHandle: typeof DragHandle;\n fieldSelector: typeof ValueSelector;\n inlineCombinator: typeof InlineCombinator;\n lockGroupAction: typeof ActionElement;\n lockRuleAction: typeof ActionElement;\n matchModeEditor: typeof MatchModeEditor;\n notToggle: typeof NotToggle;\n operatorSelector: typeof ValueSelector;\n removeGroupAction: typeof ActionElement;\n removeRuleAction: typeof ActionElement;\n rule: typeof Rule;\n ruleGroup: typeof RuleGroup;\n ruleGroupBodyElements: typeof RuleGroupBodyComponents;\n ruleGroupHeaderElements: typeof RuleGroupHeaderComponents;\n shiftActions: typeof ShiftActions;\n valueEditor: typeof ValueEditor;\n valueSelector: typeof ValueSelector;\n valueSourceSelector: typeof ValueSelector;\n}","QueryBuilderContext","_QBC"],"sources":["../src/context/QueryBuilderContext.ts","../src/components/ActionElement.tsx","../src/components/DragHandle.tsx","../src/defaults.ts","../src/utils/clsx.ts","../src/components/InlineCombinator.tsx","../src/utils/arrayUtils.ts","../src/utils/misc.ts","../src/utils/isRuleGroup.ts","../src/utils/convertQuery.ts","../src/utils/defaultValidator.ts","../src/utils/optGroupUtils.ts","../src/utils/filterFieldsByComparator.ts","../src/utils/parseNumber.ts","../src/utils/transformQuery.ts","../src/utils/isRuleOrGroupValid.ts","../src/utils/getParseNumberMethod.ts","../src/utils/formatQuery/utils.ts","../src/utils/formatQuery/defaultRuleGroupProcessorCEL.ts","../src/utils/formatQuery/defaultRuleProcessorCEL.ts","../src/utils/formatQuery/defaultRuleGroupProcessorMongoDBQuery.ts","../src/utils/formatQuery/defaultRuleProcessorMongoDBQuery.ts","../src/utils/formatQuery/defaultRuleProcessorMongoDB.ts","../src/utils/formatQuery/defaultRuleGroupProcessorSpEL.ts","../src/utils/formatQuery/defaultRuleProcessorSpEL.ts","../src/utils/formatQuery/defaultValueProcessorByRule.ts","../src/utils/formatQuery/defaultRuleProcessorDrizzle.ts","../src/utils/formatQuery/defaultRuleGroupProcessorDrizzle.ts","../src/utils/formatQuery/defaultRuleGroupProcessorElasticSearch.ts","../src/utils/formatQuery/defaultRuleGroupProcessorJSONata.ts","../src/utils/formatQuery/defaultRuleGroupProcessorJsonLogic.ts","../src/utils/formatQuery/defaultRuleGroupProcessorLDAP.ts","../src/utils/formatQuery/defaultRuleGroupProcessorMongoDB.ts","../src/utils/formatQuery/defaultRuleGroupProcessorNL.ts","../src/utils/formatQuery/defaultRuleGroupProcessorParameterized.ts","../src/utils/formatQuery/defaultRuleGroupProcessorPrisma.ts","../src/utils/formatQuery/defaultRuleGroupProcessorSequelize.ts","../src/utils/formatQuery/defaultRuleGroupProcessorSQL.ts","../src/utils/formatQuery/defaultRuleProcessorElasticSearch.ts","../src/utils/formatQuery/defaultRuleProcessorJSONata.ts","../src/utils/formatQuery/defaultRuleProcessorJsonLogic.ts","../src/utils/formatQuery/defaultRuleProcessorLDAP.ts","../src/utils/formatQuery/defaultValueProcessorNL.ts","../src/utils/formatQuery/defaultRuleProcessorNL.ts","../src/utils/formatQuery/defaultRuleProcessorSQL.ts","../src/utils/formatQuery/defaultRuleProcessorParameterized.ts","../src/utils/formatQuery/defaultRuleProcessorPrisma.ts","../src/utils/formatQuery/defaultRuleProcessorSequelize.ts","../src/utils/formatQuery/formatQuery.ts","../src/utils/formatQuery/index.ts","../src/utils/pathUtils.ts","../src/utils/generateAccessibleDescription.ts","../src/utils/generateID.ts","../src/hooks/usePreferProp.ts","../src/hooks/useMergedContext.ts","../src/utils/getCompatContextProvider.tsx","../src/utils/getMatchModesUtil.ts","../src/utils/getValidationClassNames.ts","../src/utils/getValueSourcesUtil.ts","../src/utils/mergeClassnames.ts","../src/utils/objectUtils.ts","../src/utils/mergeTranslations.ts","../src/utils/prepareQueryObjects.ts","../src/utils/regenerateIDs.ts","../src/utils/queryTools.ts","../src/utils/toOptions.tsx","../src/components/MatchModeEditor.tsx","../src/components/NotToggle.tsx","../src/messages.ts","../src/redux/queriesSlice.ts","../src/redux/QueryBuilderStateContext.ts","../src/redux/warningsSlice.ts","../src/redux/_internal.ts","../src/hooks/usePrevious.ts","../src/hooks/useControlledOrUncontrolled.ts","../src/hooks/useDeprecatedProps.ts","../src/hooks/useOptionListProp.ts","../src/hooks/useFields.ts","../src/hooks/useReactDndWarning.ts","../src/hooks/useSelectElementChangeHandler.ts","../src/hooks/useStopEventPropagation.ts","../src/redux/selectors.ts","../src/redux/hooks.ts","../src/components/QueryBuilder.useQueryBuilderSchema.ts","../src/components/QueryBuilder.useQueryBuilderSetup.ts","../src/components/QueryBuilder.useQueryBuilder.ts","../src/components/RuleGroup.tsx","../src/components/Rule.tsx","../src/components/ShiftActions.tsx","../src/components/ValueEditor.tsx","../src/components/ValueSelector.tsx","../src/defaultControlElements.ts","../src/components/QueryBuilderInternal.tsx"],"sourcesContent":["import type { Context } from 'react';\nimport { createContext } from 'react';\nimport type { QueryBuilderContextProps, RuleGroupTypeAny } from '../types';\n\ninterface QueryBuilderContextInternals {\n initialQuery?: RuleGroupTypeAny;\n qbId?: string;\n}\n\ninterface QueryBuilderContextType\n // oxlint-disable-next-line typescript/no-explicit-any\n extends QueryBuilderContextProps<any, any>,\n QueryBuilderContextInternals {}\n\n/**\n * Context provider for {@link QueryBuilder}. Any descendant query builders\n * will inherit the props from a context provider.\n */\nexport const QueryBuilderContext: Context<QueryBuilderContextType> = createContext({});\n","import * as React from 'react';\nimport type { ActionProps } from '../types';\n\n/**\n * Default `<button>` component used by {@link QueryBuilder}.\n *\n * @group Components\n */\nexport const ActionElement = (props: ActionProps): React.JSX.Element => (\n <button\n type=\"button\"\n data-testid={props.testID}\n disabled={props.disabled && !props.disabledTranslation}\n className={props.className}\n title={\n props.disabledTranslation && props.disabled ? props.disabledTranslation.title : props.title\n }\n onClick={e => props.handleOnClick(e)}>\n {props.disabledTranslation && props.disabled ? props.disabledTranslation.label : props.label}\n </button>\n);\n","import * as React from 'react';\nimport { forwardRef } from 'react';\nimport type { DragHandleProps } from '../types';\n\n/**\n * Default drag handle component used by {@link QueryBuilder} when `enableDragAndDrop` is `true`.\n *\n * @group Components\n */\nexport const DragHandle: React.ForwardRefExoticComponent<\n DragHandleProps & React.RefAttributes<HTMLSpanElement>\n> = forwardRef<HTMLSpanElement, DragHandleProps>((props, dragRef) => (\n <span data-testid={props.testID} ref={dragRef} className={props.className} title={props.title}>\n {props.label}\n </span>\n));\n","import type {\n Classnames,\n DefaultCombinatorName,\n DefaultCombinatorNameExtended,\n DefaultOperatorName,\n MatchMode,\n Path,\n StringUnionToFullOptionArray,\n} from './types/index.noReact';\n\n// DO NOT ALTER OR REMOVE REGION NAMES. Some of them are used\n// to generate code snippets in the documentation.\n\n/**\n * @group Defaults\n */\nexport const defaultPlaceholderName = '~';\n/**\n * @group Defaults\n */\nexport const defaultPlaceholderLabel = '------';\n/**\n * Default `name` for placeholder option in the `fields` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderFieldName: typeof defaultPlaceholderName = defaultPlaceholderName;\n/**\n * Default `label` for placeholder option in the `fields` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderFieldLabel: typeof defaultPlaceholderLabel = defaultPlaceholderLabel;\n/**\n * Default `label` for placeholder option group in the `fields` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderFieldGroupLabel: typeof defaultPlaceholderLabel =\n defaultPlaceholderLabel;\n/**\n * Default `name` for placeholder option in the `operators` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderOperatorName: typeof defaultPlaceholderName = defaultPlaceholderName;\n/**\n * Default `label` for placeholder option in the `operators` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderOperatorLabel: typeof defaultPlaceholderLabel =\n defaultPlaceholderLabel;\n/**\n * Default `label` for placeholder option group in the `operators` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderOperatorGroupLabel: typeof defaultPlaceholderLabel =\n defaultPlaceholderLabel;\n/**\n * Default `name` for placeholder option in the `values` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderValueName: typeof defaultPlaceholderName = defaultPlaceholderName;\n/**\n * Default `label` for placeholder option in the `values` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderValueLabel: typeof defaultPlaceholderLabel = defaultPlaceholderLabel;\n/**\n * Default `label` for placeholder option group in the `values` array.\n *\n * @group Defaults\n */\nexport const defaultPlaceholderValueGroupLabel: typeof defaultPlaceholderLabel =\n defaultPlaceholderLabel;\n\n/**\n * Default character used to `.join` and `.split` arrays.\n *\n * @group Defaults\n */\nexport const defaultJoinChar = ',';\n\nexport type DefaultOperators = StringUnionToFullOptionArray<DefaultOperatorName>;\n\nexport const defaultOperatorLabelMap: Record<DefaultOperatorName, string> = {\n '=': '=',\n '!=': '!=',\n '<': '<',\n '>': '>',\n '<=': '<=',\n '>=': '>=',\n contains: 'contains',\n beginsWith: 'begins with',\n endsWith: 'ends with',\n doesNotContain: 'does not contain',\n doesNotBeginWith: 'does not begin with',\n doesNotEndWith: 'does not end with',\n null: 'is null',\n notNull: 'is not null',\n in: 'in',\n notIn: 'not in',\n between: 'between',\n notBetween: 'not between',\n};\n\nexport const defaultCombinatorLabelMap: Record<DefaultCombinatorNameExtended, string> = {\n and: 'AND',\n or: 'OR',\n xor: 'XOR',\n};\n\n/**\n * Default operator list.\n *\n * @group Defaults\n */\n// #region docs-operators\nexport const defaultOperators: DefaultOperators = [\n { name: '=', value: '=', label: '=' },\n { name: '!=', value: '!=', label: '!=' },\n { name: '<', value: '<', label: '<' },\n { name: '>', value: '>', label: '>' },\n { name: '<=', value: '<=', label: '<=' },\n { name: '>=', value: '>=', label: '>=' },\n { name: 'contains', value: 'contains', label: 'contains' },\n { name: 'beginsWith', value: 'beginsWith', label: 'begins with' },\n { name: 'endsWith', value: 'endsWith', label: 'ends with' },\n { name: 'doesNotContain', value: 'doesNotContain', label: 'does not contain' },\n { name: 'doesNotBeginWith', value: 'doesNotBeginWith', label: 'does not begin with' },\n { name: 'doesNotEndWith', value: 'doesNotEndWith', label: 'does not end with' },\n { name: 'null', value: 'null', label: 'is null' },\n { name: 'notNull', value: 'notNull', label: 'is not null' },\n { name: 'in', value: 'in', label: 'in' },\n { name: 'notIn', value: 'notIn', label: 'not in' },\n { name: 'between', value: 'between', label: 'between' },\n { name: 'notBetween', value: 'notBetween', label: 'not between' },\n];\n// #endregion\n\n/**\n * Map of default operators to their respective opposite/negating operators.\n *\n * @group Defaults\n */\nexport const defaultOperatorNegationMap: Record<DefaultOperatorName, DefaultOperatorName> = {\n '=': '!=',\n '!=': '=',\n '<': '>=',\n '<=': '>',\n '>': '<=',\n '>=': '<',\n beginsWith: 'doesNotBeginWith',\n doesNotBeginWith: 'beginsWith',\n endsWith: 'doesNotEndWith',\n doesNotEndWith: 'endsWith',\n contains: 'doesNotContain',\n doesNotContain: 'contains',\n between: 'notBetween',\n notBetween: 'between',\n in: 'notIn',\n notIn: 'in',\n notNull: 'null',\n null: 'notNull',\n} satisfies Record<DefaultOperatorName, DefaultOperatorName>;\n\nexport type DefaultCombinators = StringUnionToFullOptionArray<DefaultCombinatorName>;\n\n/**\n * Default combinator list.\n *\n * @group Defaults\n */\n// #region docs-combinators\nexport const defaultCombinators: DefaultCombinators = [\n { name: 'and', value: 'and', label: 'AND' } as const,\n { name: 'or', value: 'or', label: 'OR' } as const,\n];\n// #endregion\n\nexport type DefaultCombinatorsExtended =\n StringUnionToFullOptionArray<DefaultCombinatorNameExtended>;\n\n/**\n * Default combinator list, with `XOR` added.\n *\n * @group Defaults\n */\nexport const defaultCombinatorsExtended: DefaultCombinatorsExtended = [\n ...defaultCombinators,\n { name: 'xor', value: 'xor', label: 'XOR' } as const,\n];\n\nexport type DefaultMatchModes = StringUnionToFullOptionArray<MatchMode>;\n\n/**\n * Default match modes.\n *\n * @group Defaults\n */\n// #region docs-matchmodes\nexport const defaultMatchModes: DefaultMatchModes = [\n { name: 'all', value: 'all', label: 'all' },\n { name: 'some', value: 'some', label: 'some' },\n { name: 'none', value: 'none', label: 'none' },\n { name: 'atLeast', value: 'atLeast', label: 'at least' },\n { name: 'atMost', value: 'atMost', label: 'at most' },\n { name: 'exactly', value: 'exactly', label: 'exactly' },\n];\n// #endregion\n\n/**\n * Standard classnames applied to each component.\n *\n * @group Defaults\n */\n// #region docs-standardclassnames\nexport const standardClassnames = {\n queryBuilder: 'queryBuilder',\n ruleGroup: 'ruleGroup',\n header: 'ruleGroup-header',\n body: 'ruleGroup-body',\n combinators: 'ruleGroup-combinators',\n addRule: 'ruleGroup-addRule',\n addGroup: 'ruleGroup-addGroup',\n cloneRule: 'rule-cloneRule',\n cloneGroup: 'ruleGroup-cloneGroup',\n removeGroup: 'ruleGroup-remove',\n notToggle: 'ruleGroup-notToggle',\n rule: 'rule',\n fields: 'rule-fields',\n matchMode: 'rule-matchMode',\n matchThreshold: 'rule-matchThreshold',\n operators: 'rule-operators',\n value: 'rule-value',\n removeRule: 'rule-remove',\n betweenRules: 'betweenRules',\n valid: 'queryBuilder-valid',\n invalid: 'queryBuilder-invalid',\n shiftActions: 'shiftActions',\n dndDragging: 'dndDragging',\n dndOver: 'dndOver',\n dndCopy: 'dndCopy',\n dndGroup: 'dndGroup',\n dragHandle: 'queryBuilder-dragHandle',\n disabled: 'queryBuilder-disabled',\n lockRule: 'rule-lock',\n lockGroup: 'ruleGroup-lock',\n valueSource: 'rule-valueSource',\n valueListItem: 'rule-value-list-item',\n branches: 'queryBuilder-branches',\n justified: 'queryBuilder-justified',\n hasSubQuery: 'rule-hasSubQuery',\n} as const;\n// #endregion\n\n/**\n * Default classnames for each component.\n *\n * @group Defaults\n */\nexport const defaultControlClassnames: Classnames = {\n queryBuilder: '',\n ruleGroup: '',\n header: '',\n body: '',\n combinators: '',\n addRule: '',\n addGroup: '',\n cloneRule: '',\n cloneGroup: '',\n removeGroup: '',\n notToggle: '',\n rule: '',\n fields: '',\n matchMode: '',\n matchThreshold: '',\n operators: '',\n value: '',\n removeRule: '',\n shiftActions: '',\n dragHandle: '',\n lockRule: '',\n lockGroup: '',\n valueSource: '',\n actionElement: '',\n valueSelector: '',\n betweenRules: '',\n valid: '',\n invalid: '',\n dndDragging: '',\n dndOver: '',\n dndGroup: '',\n dndCopy: '',\n disabled: '',\n valueListItem: '',\n branches: '',\n hasSubQuery: '',\n} satisfies Classnames;\n\n/**\n * Default reason codes for a group being invalid.\n *\n * @group Defaults\n */\nexport const groupInvalidReasons = {\n empty: 'empty',\n invalidCombinator: 'invalid combinator',\n invalidIndependentCombinators: 'invalid independent combinators',\n} as const;\n\n/**\n * Component identifiers for testing.\n *\n * @group Defaults\n */\nexport const TestID = {\n rule: 'rule',\n ruleGroup: 'rule-group',\n inlineCombinator: 'inline-combinator',\n addGroup: 'add-group',\n removeGroup: 'remove-group',\n cloneGroup: 'clone-group',\n cloneRule: 'clone-rule',\n addRule: 'add-rule',\n removeRule: 'remove-rule',\n combinators: 'combinators',\n fields: 'fields',\n operators: 'operators',\n valueEditor: 'value-editor',\n notToggle: 'not-toggle',\n shiftActions: 'shift-actions',\n dragHandle: 'drag-handle',\n lockRule: 'lock-rule',\n lockGroup: 'lock-group',\n valueSourceSelector: 'value-source-selector',\n matchModeEditor: 'match-mode-editor',\n} as const;\n\nexport const LogType = {\n parentPathDisabled: 'action aborted: parent path disabled',\n pathDisabled: 'action aborted: path is disabled',\n queryUpdate: 'query updated',\n onAddRuleFalse: 'onAddRule callback returned false',\n onAddGroupFalse: 'onAddGroup callback returned false',\n onGroupRuleFalse: 'onGroupRule callback returned false',\n onGroupGroupFalse: 'onGroupGroup callback returned false',\n onMoveRuleFalse: 'onMoveRule callback returned false',\n onMoveGroupFalse: 'onMoveGroup callback returned false',\n onRemoveFalse: 'onRemove callback returned false',\n add: 'rule or group added',\n remove: 'rule or group removed',\n update: 'rule or group updated',\n move: 'rule or group moved',\n group: 'rule or group grouped with another',\n} as const;\n\n/**\n * The {@link Path} of the root group.\n *\n * @group Defaults\n */\nexport const rootPath: Path = [] satisfies Path;\n","// Adapted from https://github.com/lukeed/clsx/tree/925494cf31bcd97d3337aacd34e659e80cae7fe2\n\n// oxlint-disable-next-line typescript/no-explicit-any\ntype ClassDictionary = Record<string, any>;\ntype ClassValue =\n | ClassArray\n | ClassDictionary\n | string\n | number\n | bigint\n | null\n | boolean\n | undefined;\ntype ClassArray = ClassValue[];\n\n// istanbul ignore next\n// oxlint-disable-next-line typescript/no-explicit-any\nfunction toVal(mix: any) {\n let k;\n let y;\n let str = '';\n\n if (typeof mix === 'string' || typeof mix === 'number') {\n str += mix;\n } else if (typeof mix === 'object') {\n if (Array.isArray(mix)) {\n const len = mix.length;\n for (k = 0; k < len; k++) {\n if (mix[k] && (y = toVal(mix[k]))) {\n str && (str += ' ');\n str += y;\n }\n }\n } else {\n for (y in mix) {\n if (mix[y]) {\n str && (str += ' ');\n str += y;\n }\n }\n }\n }\n\n return str;\n}\n\n// istanbul ignore next\nexport function clsx(...args: ClassValue[]): string {\n let i = 0;\n let tmp;\n let x;\n let str = '';\n const len = args.length;\n for (; i < len; i++) {\n if ((tmp = args[i]) && (x = toVal(tmp))) {\n str && (str += ' ');\n str += x;\n }\n }\n return str;\n}\n\nexport default clsx;\n","import * as React from 'react';\nimport { standardClassnames, TestID } from '../defaults';\nimport type { InlineCombinatorProps } from '../types';\nimport { clsx } from '../utils/clsx';\n\n/**\n * Default `inlineCombinator` component used by {@link QueryBuilder}. A small `<div>`\n * wrapper around the `combinatorSelector` component, used when either\n * `showCombinatorsBetweenRules` or `independentCombinators` are `true`.\n *\n * @group Components\n */\nexport const InlineCombinator = (allProps: InlineCombinatorProps): React.JSX.Element => {\n const { component: CombinatorSelectorComponent, ...props } = allProps;\n\n const className = clsx(\n props.schema.suppressStandardClassnames || standardClassnames.betweenRules,\n props.schema.classNames.betweenRules\n );\n\n return (\n <div className={className} data-testid={TestID.inlineCombinator}>\n <CombinatorSelectorComponent {...props} testID={TestID.combinators} />\n </div>\n );\n};\n","import { defaultJoinChar } from '../defaults';\n\n/**\n * Splits a string by a given character (see {@link defaultJoinChar}). Escaped characters\n * (characters preceded by a backslash) will not apply to the split, and the backslash will\n * be removed in the array element. Inverse of {@link joinWith}.\n *\n * @example\n * splitBy('this\\\\,\\\\,that,,the other,,,\\\\,')\n * // or\n * splitBy('this\\\\,\\\\,that,,the other,,,\\\\,', ',')\n * // would return\n * ['this,,that', '', 'the other', '', '', ',']\n */\nexport const splitBy = (str?: string, splitChar: string = defaultJoinChar): string[] =>\n typeof str === 'string'\n ? str\n .split(`\\\\${splitChar}`)\n .map(c => c.split(splitChar))\n .reduce((prev, curr, idx) => {\n if (idx === 0) {\n return curr;\n }\n return [...prev.slice(0, -1), `${prev.at(-1)}${splitChar}${curr[0]}`, ...curr.slice(1)];\n }, [])\n : [];\n\n/**\n * Joins an array of strings using the given character (see {@link defaultJoinChar}). When\n * the given character appears in an array element, a backslash will be added just before it\n * to distinguish it from the join character. Effectively the inverse of {@link splitBy}.\n *\n * TIP: The join character can actually be a string of any length. Only the first character\n * will be searched for in the array elements and preceded by a backslash.\n *\n * @example\n * joinWith(['this,,that', '', 'the other', '', '', ','], ', ')\n * // would return\n * 'this\\\\,\\\\,that, , the other, , , \\\\,'\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const joinWith = (strArr: any[], joinChar: string = defaultJoinChar): string =>\n strArr.map(str => `${str ?? ''}`.replaceAll(joinChar[0], `\\\\${joinChar[0]}`)).join(joinChar);\n\n/**\n * Trims the value if it is a string. Otherwise returns the value as is.\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const trimIfString = (val: any): any => (typeof val === 'string' ? val.trim() : val);\n\n/**\n * Splits a string by comma then trims each element. Arrays are returned as is except\n * any string elements are trimmed.\n */\nexport const toArray = (\n // oxlint-disable-next-line typescript/no-explicit-any\n v: any,\n { retainEmptyStrings }: { retainEmptyStrings?: boolean } = {}\n // oxlint-disable-next-line typescript/no-explicit-any\n): any[] =>\n Array.isArray(v)\n ? v.map(v => trimIfString(v))\n : typeof v === 'string'\n ? splitBy(v, defaultJoinChar)\n .filter(retainEmptyStrings ? () => true : s => !/^\\s*$/.test(s))\n .map(s => s.trim())\n : typeof v === 'number'\n ? [v]\n : [];\n\n/**\n * Determines if an array is free of `null`/`undefined`.\n */\nexport const nullFreeArray = <T>(arr: T[]): arr is Exclude<T, null>[] =>\n arr.every(el => el === false || (el ?? false) !== false);\n","import { numericRegex as numericQuantityRegex } from 'numeric-quantity';\n\n/**\n * Converts a value to lowercase if it's a string, otherwise returns the value as is.\n */\n// istanbul ignore next\nexport const lc = <T>(v: T): T => (typeof v === 'string' ? (v.toLowerCase() as T) : v);\n\n/**\n * Regex matching numeric strings. Passes for positive/negative integers, decimals,\n * and E notation, with optional surrounding whitespace.\n */\nexport const numericRegex: RegExp = new RegExp(\n numericQuantityRegex.source.replace(/^\\^/, String.raw`^\\s*`).replace(/\\$$/, String.raw`\\s*$`)\n);\n\n/**\n * Determines if a variable is a plain old JavaScript object, aka POJO.\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const isPojo = (obj: any): obj is Record<string, any> =>\n obj === null || typeof obj !== 'object' ? false : Object.getPrototypeOf(obj) === Object.prototype;\n\n/**\n * Simple helper to determine whether a value is null, undefined, or an empty string.\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const nullOrUndefinedOrEmpty = (value: any): value is null | undefined | '' =>\n value === null || value === undefined || value === '';\n","import type { RuleGroupType, RuleGroupTypeAny, RuleGroupTypeIC } from '../types/index.noReact';\nimport { isPojo } from './misc';\n\n/**\n * Determines if an object is a {@link RuleGroupType} or {@link RuleGroupTypeIC}.\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const isRuleGroup = (rg: any): rg is RuleGroupTypeAny =>\n isPojo(rg) && Array.isArray(rg.rules);\n\n/**\n * Determines if an object is a {@link RuleGroupType}.\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const isRuleGroupType = (rg: any): rg is RuleGroupType =>\n isRuleGroup(rg) && typeof rg.combinator === 'string';\n\n/**\n * Determines if an object is a {@link RuleGroupTypeIC}.\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const isRuleGroupTypeIC = (rg: any): rg is RuleGroupTypeIC =>\n isRuleGroup(rg) && rg.combinator === undefined;\n","import { produce } from 'immer';\nimport type {\n RuleGroupArray,\n RuleGroupType,\n RuleGroupTypeAny,\n RuleGroupTypeIC,\n RuleType,\n} from '../types/index.noReact';\nimport { isRuleGroup, isRuleGroupType, isRuleGroupTypeIC } from './isRuleGroup';\nimport { lc } from './misc';\n\nconst combinatorLevels = ['or', 'xor', 'and'] as const;\n\nconst isSameString = (a: unknown, b: string) => lc(a) === b;\n\nconst generateRuleGroupICWithConsistentCombinators = (\n rg: RuleGroupTypeIC,\n baseCombinatorLevel: number = 0\n): RuleGroupTypeIC => {\n const baseCombinator = combinatorLevels[baseCombinatorLevel];\n\n // oxlint-disable-next-line typescript/no-explicit-any\n if (!rg.rules.includes(baseCombinator as any)) {\n // No instances of this combinator, so group based on the next\n // combinator level if at least two levels remain\n return baseCombinatorLevel < combinatorLevels.length - 2\n ? generateRuleGroupICWithConsistentCombinators(rg, baseCombinatorLevel + 1)\n : rg;\n }\n\n return produce(rg, draft => {\n let cursor = 0;\n\n // Group all chains of combinators in the rule array that are not the base combinator\n while (cursor < draft.rules.length - 2) {\n if (isSameString(draft.rules[cursor + 1], baseCombinator)) {\n cursor += 2;\n continue;\n }\n\n const nextBaseCombinatorIndex = draft.rules.findIndex(\n (r, i) => i > cursor && typeof r === 'string' && lc(r) === baseCombinator\n );\n\n if (nextBaseCombinatorIndex === -1) {\n // No more instances of this combinator, so group all remaining rules and exit the loop\n draft.rules.splice(\n cursor,\n draft.rules.length,\n generateRuleGroupICWithConsistentCombinators(\n // oxlint-disable-next-line typescript/no-explicit-any\n { rules: draft.rules.slice(cursor) as any },\n baseCombinatorLevel + 1\n )\n );\n break;\n } else {\n // Group all rules between the current cursor and the next instance of the base combinator\n draft.rules.splice(\n cursor,\n nextBaseCombinatorIndex - cursor,\n generateRuleGroupICWithConsistentCombinators(\n // oxlint-disable-next-line typescript/no-explicit-any\n { rules: draft.rules.slice(cursor, nextBaseCombinatorIndex) as any },\n baseCombinatorLevel + 1\n )\n );\n }\n }\n });\n};\n\n/**\n * Converts a {@link RuleGroupTypeIC} to {@link RuleGroupType}.\n *\n * This function is idempotent: {@link RuleGroupType} queries will be\n * returned as-is.\n *\n * @group Query Tools\n */\nexport const convertFromIC = <RG extends RuleGroupType = RuleGroupType>(\n rg: RuleGroupTypeAny\n): RG => {\n if (isRuleGroupType(rg)) {\n return rg as RG;\n }\n const processedRG = generateRuleGroupICWithConsistentCombinators(rg);\n const rulesAsMixedList = processedRG.rules.map(r =>\n typeof r === 'string' || !isRuleGroup(r) ? r : convertFromIC(r)\n );\n const combinator = rulesAsMixedList.length < 2 ? 'and' : (rulesAsMixedList[1] as string);\n const rules = rulesAsMixedList.filter(r => typeof r !== 'string') as RuleGroupArray;\n return { ...processedRG, combinator, rules } as RG;\n};\n\n/**\n * Converts a {@link RuleGroupType} to {@link RuleGroupTypeIC}.\n *\n * This function is idempotent: {@link RuleGroupTypeIC} queries will be\n * returned as-is.\n *\n * @group Query Tools\n */\nexport const convertToIC = <RGIC extends RuleGroupTypeIC = RuleGroupTypeIC>(\n rg: RuleGroupTypeAny\n): RGIC => {\n if (isRuleGroupTypeIC(rg)) {\n return rg as RGIC;\n }\n const { combinator, ...queryWithoutCombinator } = rg;\n const rules: (RuleGroupTypeIC | RuleType | string)[] = [];\n const { length } = rg.rules;\n for (const [idx, r] of rg.rules.entries()) {\n if (isRuleGroup(r)) {\n rules.push(convertToIC(r));\n } else {\n rules.push(r);\n }\n if (combinator && idx < length - 1) {\n rules.push(combinator);\n }\n }\n return { ...queryWithoutCombinator, rules } as RGIC;\n};\n\n/**\n * Converts a {@link RuleGroupType} to {@link RuleGroupTypeIC}. For a more explicit\n * operation, use {@link convertToIC}.\n *\n * @group Query Tools\n */\nfunction convertQuery(query: RuleGroupType): RuleGroupTypeIC;\n/**\n * Converts a {@link RuleGroupTypeIC} to {@link RuleGroupType}. For a more explicit\n * operation, use {@link convertFromIC}.\n *\n * @group Query Tools\n */\nfunction convertQuery(query: RuleGroupTypeIC): RuleGroupType;\nfunction convertQuery(query: RuleGroupType | RuleGroupTypeIC): RuleGroupType | RuleGroupTypeIC {\n return isRuleGroupTypeIC(query) ? convertFromIC(query) : convertToIC(query);\n}\n\nexport { convertQuery };\n","import { defaultCombinators, groupInvalidReasons } from '../defaults';\nimport type {\n QueryValidator,\n RuleGroupTypeAny,\n RuleType,\n ValidationMap,\n} from '../types/index.noReact';\nimport { isRuleGroup, isRuleGroupType } from './isRuleGroup';\n\n/**\n * This is an example validation function you can pass to {@link QueryBuilder} in the\n * `validator` prop. It assumes that you want to validate groups, and has a no-op\n * for validating rules which you can replace with your own implementation.\n */\n// oxlint-disable-next-line consistent-function-scoping\nexport const defaultValidator: QueryValidator = query => {\n const result: ValidationMap = {};\n\n const validateRule = (_rule: RuleType) => {\n // Replace this with your custom implementation.\n // Inside this function, set `result[_rule.id] = true` for a valid\n // rule, or `{ valid: false, reasons: ['your', 'reasons', 'here'] }`\n // for an invalid rule.\n };\n\n const validateGroup = (rg: RuleGroupTypeAny) => {\n // oxlint-disable-next-line typescript/no-explicit-any\n const reasons: any[] = [];\n if (rg.rules.length === 0) {\n reasons.push(groupInvalidReasons.empty);\n } else if (!isRuleGroupType(rg)) {\n // Odd indexes should be valid combinators and even indexes should be rules or groups\n let invalidICs = false;\n for (let i = 0; i < rg.rules.length && !invalidICs; i++) {\n if (\n (i % 2 === 0 && typeof rg.rules[i] === 'string') ||\n (i % 2 === 1 && typeof rg.rules[i] !== 'string') ||\n (i % 2 === 1 &&\n typeof rg.rules[i] === 'string' &&\n !defaultCombinators.map(c => c.name as string).includes(rg.rules[i] as string))\n ) {\n invalidICs = true;\n }\n }\n if (invalidICs) {\n reasons.push(groupInvalidReasons.invalidIndependentCombinators);\n }\n }\n // Non-independent combinators should be valid, but only checked if there are multiple rules\n // since combinators don't really apply to groups with only one rule/group\n if (\n isRuleGroupType(rg) &&\n !defaultCombinators.map(c => c.name as string).includes(rg.combinator) &&\n rg.rules.length > 1\n ) {\n reasons.push(groupInvalidReasons.invalidCombinator);\n }\n /* istanbul ignore else */\n if (rg.id) {\n result[rg.id] = reasons.length > 0 ? { valid: false, reasons } : true;\n }\n for (const r of rg.rules) {\n if (typeof r === 'string') {\n // Validation for this case was done earlier\n } else if (isRuleGroup(r)) {\n validateGroup(r);\n } else {\n validateRule(r);\n }\n }\n };\n\n validateGroup(query);\n\n return result;\n // You can return the result object itself like above, or if you just\n // want the entire query to be marked invalid if _any_ rules/groups are\n // invalid, return a boolean like this:\n // return Object.values(result).map(rv => (typeof rv !== 'boolean')).includes(true);\n // That will return `true` if no errors were found.\n};\n","import type { Draft } from 'immer';\nimport { produce } from 'immer';\nimport type {\n BaseOption,\n BaseOptionMap,\n FlexibleOption,\n FlexibleOptionGroup,\n FlexibleOptionList,\n FullOption,\n FullOptionList,\n GetOptionIdentifierType,\n Option,\n OptionGroup,\n RequireAtLeastOne,\n ToFullOption,\n ValueOption,\n WithUnknownIndex,\n} from '../types/index.noReact';\nimport { isPojo } from './misc';\n\nconst isOptionWithName = (opt: BaseOption): opt is Option =>\n isPojo(opt) && 'name' in opt && typeof opt.name === 'string';\nconst isOptionWithValue = (opt: BaseOption): opt is ValueOption =>\n isPojo(opt) && 'value' in opt && typeof opt.value === 'string';\n\n/**\n * Converts an {@link Option} or {@link ValueOption} (i.e., {@link BaseOption})\n * into a {@link FullOption}. Full options are left unchanged.\n *\n * @group Option Lists\n */\nexport function toFullOption<Opt extends BaseOption>(\n opt: Opt | string,\n baseProperties?: Record<string, unknown>,\n labelMap?: Record<string, unknown>\n): ToFullOption<Opt> {\n const recipe: (o: Opt | string) => ToFullOption<Opt> = produce(draft => {\n const idObj: { name?: string; value?: string } = {};\n let needsUpdating = !!baseProperties;\n\n if (typeof draft === 'string') {\n return {\n ...baseProperties,\n name: draft,\n value: draft,\n label: labelMap?.[draft] ?? draft,\n } as Draft<Opt>;\n }\n\n if (isOptionWithName(draft) && !isOptionWithValue(draft)) {\n idObj.value = draft.name;\n needsUpdating = true;\n } else if (!isOptionWithName(draft) && isOptionWithValue(draft)) {\n idObj.name = draft.value;\n needsUpdating = true;\n }\n\n if (needsUpdating) {\n return Object.assign({}, baseProperties, draft, idObj);\n }\n });\n return recipe(opt);\n}\n\n/**\n * Converts an {@link OptionList} or {@link FlexibleOptionList} into a {@link FullOptionList}.\n * Lists of full options are left unchanged.\n *\n * @group Option Lists\n */\nexport function toFullOptionList<Opt extends BaseOption>(\n optList: unknown[],\n baseProperties?: Record<string, unknown>,\n labelMap?: Record<string, unknown>\n): FullOptionList<Opt> {\n if (!Array.isArray(optList)) {\n return [] as unknown as FullOptionList<Opt>;\n }\n\n const recipe: (ol: FlexibleOptionList<Opt>) => FullOptionList<Opt> = produce(draft => {\n if (isFlexibleOptionGroupArray(draft)) {\n for (const optGroup of draft) {\n for (const [idx, opt] of optGroup.options.entries())\n optGroup.options[idx] = toFullOption(opt, baseProperties, labelMap);\n }\n } else {\n for (const [idx, opt] of (draft as Opt[]).entries())\n draft[idx] = toFullOption(opt, baseProperties, labelMap);\n }\n });\n\n return recipe(optList as FlexibleOptionList<Opt>);\n}\n\n/**\n * Converts a {@link FlexibleOptionList} into a {@link FullOptionList}.\n * Lists of full options are left unchanged.\n *\n * @group Option Lists\n */\nexport function toFullOptionMap<OptMap extends BaseOptionMap>(\n optMap: OptMap,\n baseProperties?: Record<string, unknown>\n): OptMap extends BaseOptionMap<infer V, infer K> ? Partial<Record<K, ToFullOption<V>>> : never {\n type FullOptMapType =\n OptMap extends BaseOptionMap<infer VT, infer KT>\n ? Partial<Record<KT, ToFullOption<VT>>>\n : never;\n\n return Object.fromEntries(\n (Object.entries(optMap) as [string, FlexibleOption][]).map(([k, v]) => [\n k,\n toFullOption(v, baseProperties),\n ])\n ) as FullOptMapType;\n}\n\n/**\n * @deprecated Renamed to {@link uniqByIdentifier}.\n *\n * @group Option Lists\n */\nexport const uniqByName = <\n T extends { name: string; value?: string } | { name?: string; value: string },\n>(\n originalArray: T[]\n): T[] => uniqByIdentifier(originalArray);\n\n/**\n * Generates a new array of objects with duplicates removed based\n * on the identifying property (`value` or `name`)\n *\n * @group Option Lists\n */\nexport const uniqByIdentifier = <\n T extends RequireAtLeastOne<{ name: string; value: string }, 'name' | 'value'>,\n>(\n originalArray: T[]\n): T[] => {\n const names = new Set<string>();\n const newArray: T[] = [];\n for (const el of originalArray) {\n if (!names.has((el.value ?? el.name)!)) {\n names.add((el.value ?? el.name)!);\n newArray.push(el);\n }\n }\n return originalArray.length === newArray.length ? originalArray : newArray;\n};\n\n/**\n * Determines if an {@link OptionList} is an {@link OptionGroup} array.\n *\n * @group Option Lists\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const isOptionGroupArray = (arr: any): arr is OptionGroup<BaseOption>[] =>\n Array.isArray(arr) &&\n arr.length > 0 &&\n isPojo(arr[0]) &&\n 'options' in arr[0] &&\n Array.isArray(arr[0].options);\n\n/**\n * Determines if an array is a flat array of {@link FlexibleOption}.\n *\n * @group Option Lists\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const isFlexibleOptionArray = (arr: any): arr is FlexibleOption[] => {\n let isFOA = false;\n if (Array.isArray(arr)) {\n for (const o of arr) {\n if (isOptionWithName(o) || isOptionWithValue(o)) {\n isFOA = true;\n } else {\n return false;\n }\n }\n }\n return isFOA;\n};\n\n/**\n * Determines if an array is a flat array of {@link FullOption}.\n *\n * @group Option Lists\n */\n// oxlint-disable-next-line typescript/no-explicit-any\nexport const isFullOptionArray = (arr: any): arr is FullOption[] => {\n let isFOA = false;\n if (Array.isArray(arr)) {\n for (const o of arr) {\n if (isOptionWithName(o) && isOptionWithValue(o)) {\n isFOA = true;\n } else {\n return false;\n }\n }\n }\n return isFOA;\n};\n\n/**\n * Determines if a {@link FlexibleOptionList} is a {@link FlexibleOptionGroup} array.\n *\n * @group Option Lists\n */\nexport const isFlexibleOptionGroupArray = (\n // oxlint-disable-next-line typescript/no-explicit-any\n arr: any,\n { allowEmpty = false }: { allowEmpty?: boolean } = {}\n): arr is FlexibleOptionGroup[] => {\n let isFOGA = false;\n if (Array.isArray(arr)) {\n for (const og of arr) {\n if (\n isPojo(og) &&\n 'options' in og &&\n (isFlexibleOptionArray(og.options) ||\n (allowEmpty && Array.isArray(og.options) && og.options.length === 0))\n ) {\n isFOGA = true;\n } else {\n return false;\n }\n }\n }\n return isFOGA;\n};\n\n/**\n * Determines if a {@link FlexibleOptionList} is a {@link OptionGroup} array of {@link FullOption}.\n *\n * @group Option Lists\n */\nexport const isFullOptionGroupArray = (\n // oxlint-disable-next-line typescript/no-explicit-any\n arr: any,\n { allowEmpty = false }: { allowEmpty?: boolean } = {}\n): arr is OptionGroup<FullOption>[] => {\n let isFOGA = false;\n if (Array.isArray(arr)) {\n for (const og of arr) {\n if (\n isPojo(og) &&\n 'options' in og &&\n (isFullOptionArray(og.options) ||\n (allowEmpty && Array.isArray(og.options) && og.options.length === 0))\n ) {\n isFOGA = true;\n } else {\n return false;\n }\n }\n }\n return isFOGA;\n};\n\n/**\n * Gets the option from an {@link OptionList} with the given `name`. Handles\n * {@link Option} arrays as well as {@link OptionGroup} arrays.\n *\n * @group Option Lists\n */\nexport function getOption<OptType extends FullOption>(\n arr: FullOptionList<OptType>,\n name: string\n): OptType | undefined;\nexport function getOption<OptType extends ValueOption>(\n arr: FlexibleOptionList<OptType>,\n name: string\n): OptType | undefined;\nexport function getOption<OptType extends Option>(\n arr: FlexibleOptionList<OptType>,\n name: string\n): OptType | undefined;\nexport