{"version":3,"file":"filter-v3.mjs","sources":["../../../src/tools/filter-v3.ts"],"sourcesContent":["import { SdkError } from '../core/sdk-error'\n\n/**\n * The eight — and only eight — comparison operators the Bitrix24 REST API v3\n * filter grammar accepts. Anything else is rejected server-side with\n * `UNKNOWNFILTEROPERATOREXCEPTION`.\n */\nexport type FilterV3Operator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'in' | 'between'\n\nconst FILTER_V3_OPERATORS: readonly FilterV3Operator[] = ['=', '!=', '>', '>=', '<', '<=', 'in', 'between']\n\n/**\n * A single condition in short-form: `[field, operator, value]`.\n */\nexport type FilterV3Condition = [string, FilterV3Operator, unknown]\n\n/**\n * A logical group of conditions / nested groups. `logic` defaults to `'and'`;\n * `negative: true` wraps the whole group in a NOT.\n */\nexport interface FilterV3Group {\n  logic?: 'and' | 'or'\n  negative?: boolean\n  conditions: FilterV3Node[]\n}\n\nexport type FilterV3Node = FilterV3Condition | FilterV3Group\n\nfunction condition(field: string, operator: FilterV3Operator, value: unknown): FilterV3Condition {\n  if (typeof field !== 'string' || field.length === 0) {\n    throw new SdkError({\n      code: 'JSSDK_FILTER_V3_INVALID_FIELD',\n      description: `FilterV3: field name must be a non-empty string, got ${JSON.stringify(field)}.`,\n      status: 400\n    })\n  }\n  if (!FILTER_V3_OPERATORS.includes(operator)) {\n    throw new SdkError({\n      code: 'JSSDK_FILTER_V3_INVALID_OPERATOR',\n      description: `FilterV3: operator \"${operator}\" is not one of ${FILTER_V3_OPERATORS.join(' ')}.`,\n      status: 400\n    })\n  }\n  return [field, operator, value]\n}\n\n/**\n * Typed builder for Bitrix24 REST API **v3** filters (the array-of-triples\n * dialect with AND/OR/NOT groups — see the v3 reference §3). Produces exactly\n * the structures the server accepts, so a bad operator or a malformed\n * `in` / `between` value fails fast on the client instead of as a server 400.\n *\n * @example\n * import { FilterV3 as F } from '@bitrix24/b24jssdk'\n *\n * // status = NEW  AND  (id in [1,2]  OR  id > 100)\n * const filter = F.build(\n *   F.eq('status', 'NEW'),\n *   F.or(\n *     F.in('id', [1, 2]),\n *     F.gt('id', 100)\n *   )\n * )\n * await b24.actions.v3.call.make({ method: 'tasks.task.list', params: { filter } })\n */\nexport const FilterV3 = Object.freeze({\n  /** `field = value` */\n  eq(field: string, value: unknown): FilterV3Condition {\n    return condition(field, '=', value)\n  },\n  /** `field != value` */\n  ne(field: string, value: unknown): FilterV3Condition {\n    return condition(field, '!=', value)\n  },\n  /** `field > value` */\n  gt(field: string, value: unknown): FilterV3Condition {\n    return condition(field, '>', value)\n  },\n  /** `field >= value` */\n  ge(field: string, value: unknown): FilterV3Condition {\n    return condition(field, '>=', value)\n  },\n  /** `field < value` */\n  lt(field: string, value: unknown): FilterV3Condition {\n    return condition(field, '<', value)\n  },\n  /** `field <= value` */\n  le(field: string, value: unknown): FilterV3Condition {\n    return condition(field, '<=', value)\n  },\n  /** `field in [values]` — `values` must be a non-empty array. */\n  in(field: string, values: unknown[]): FilterV3Condition {\n    if (!Array.isArray(values) || values.length === 0) {\n      throw new SdkError({\n        code: 'JSSDK_FILTER_V3_INVALID_IN',\n        description: `FilterV3.in(\"${field}\"): value must be a non-empty array.`,\n        status: 400\n      })\n    }\n    return condition(field, 'in', values)\n  },\n  /** `field between [from, to]` — inclusive range of exactly two defined operands. */\n  between(field: string, from: unknown, to: unknown): FilterV3Condition {\n    if (from === undefined || from === null || to === undefined || to === null) {\n      throw new SdkError({\n        code: 'JSSDK_FILTER_V3_INVALID_BETWEEN',\n        description: `FilterV3.between(\"${field}\"): both range operands must be defined (got [${String(from)}, ${String(to)}]).`,\n        status: 400\n      })\n    }\n    return condition(field, 'between', [from, to])\n  },\n\n  /** Combine nodes with AND (for nesting inside an OR; the top level is already AND). */\n  and(...conditions: FilterV3Node[]): FilterV3Group {\n    return { logic: 'and', conditions }\n  },\n  /** Combine nodes with OR. */\n  or(...conditions: FilterV3Node[]): FilterV3Group {\n    return { logic: 'or', conditions }\n  },\n  /**\n   * Negate a condition or group (wraps it in a NOT). A bare condition is wrapped\n   * in a single-item AND group so the `negative` flag has somewhere to live.\n   * Returns a fresh group (the input's `conditions` array is copied, not shared).\n   */\n  not(node: FilterV3Node): FilterV3Group {\n    if (isGroup(node)) {\n      return { ...node, conditions: [...node.conditions], negative: true }\n    }\n    return { logic: 'and', negative: true, conditions: [node] }\n  },\n\n  /**\n   * Assemble the top-level filter array (its elements are AND-joined) ready to\n   * pass as `params.filter`. Falsy nodes are skipped, so you can inline\n   * conditionals: `F.build(F.eq('a', 1), flag && F.gt('b', 2))`.\n   *\n   * Always wrap with `build` (or an array) even for a single condition —\n   * `params.filter` must be an array, so pass `build(F.eq('a', 1))`, not the bare\n   * `F.eq('a', 1)`. Each surviving node is shape-checked, so a forgotten spread\n   * (`build([F.eq(...)])`) or a hand-rolled malformed triple fails fast here\n   * instead of as an opaque server error.\n   */\n  build(...nodes: Array<FilterV3Node | false | null | undefined>): FilterV3Node[] {\n    const result = nodes.filter(Boolean) as FilterV3Node[]\n    for (const node of result) {\n      assertNode(node)\n    }\n    return result\n  }\n})\n\nfunction isGroup(node: unknown): node is FilterV3Group {\n  return !Array.isArray(node) && typeof node === 'object' && node !== null && 'conditions' in node\n}\n\nfunction assertNode(node: FilterV3Node): void {\n  if (isGroup(node)) {\n    return\n  }\n  const ok = Array.isArray(node)\n    && node.length === 3\n    && typeof node[0] === 'string'\n    && FILTER_V3_OPERATORS.includes(node[1] as FilterV3Operator)\n  if (!ok) {\n    throw new SdkError({\n      code: 'JSSDK_FILTER_V3_INVALID_NODE',\n      description: `FilterV3.build: each node must be a [field, operator, value] condition or a group — got ${JSON.stringify(node)}. Did you forget to spread (build(...nodes)) or build a condition with FilterV3 helpers?`,\n      status: 400\n    })\n  }\n}\n"],"names":[],"mappings":"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"}