{"version":3,"file":"parseGremlin.mjs","names":[],"sources":["../src/utils/parseGremlin/parseGremlin.ts"],"sourcesContent":["import type {\n  DefaultRuleGroupType,\n  DefaultRuleGroupTypeAny,\n  DefaultRuleGroupTypeIC,\n  DefaultRuleType,\n} from '../../types';\n\n/**\n * Options for {@link parseGremlin}.\n */\nexport interface ParseGremlinOptions {\n  independentCombinators?: boolean;\n}\n\n/**\n * Parses a Gremlin traversal string into a {@link DefaultRuleGroupType}.\n *\n * Accepts a full Gremlin traversal or a chain of `.has()` steps.\n * Pattern steps (`.hasLabel()`, `.out()`, `.in()`, `.both()`, `.as()`) are\n * consumed but discarded — only `.has()` filter predicates are returned.\n *\n * @example\n * ```ts\n * // Full traversal — extracts .has() conditions only\n * parseGremlin(\"g.V().hasLabel('Person').has('age', gt(30))\");\n *\n * // Bare .has() chain\n * parseGremlin(\".has('age', gt(30)).has('name', 'Alice')\");\n * ```\n */\nexport function parseGremlin(gremlin: string): DefaultRuleGroupType;\nexport function parseGremlin(\n  gremlin: string,\n  options: Omit<ParseGremlinOptions, 'independentCombinators'> & {\n    independentCombinators?: false;\n  }\n): DefaultRuleGroupType;\nexport function parseGremlin(\n  gremlin: string,\n  options: Omit<ParseGremlinOptions, 'independentCombinators'> & {\n    independentCombinators: true;\n  }\n): DefaultRuleGroupTypeIC;\nexport function parseGremlin(\n  gremlin: string,\n  _options?: ParseGremlinOptions\n): DefaultRuleGroupTypeAny {\n  const trimmed = gremlin.trim();\n  if (!trimmed) return { combinator: 'and', rules: [] };\n\n  const rules: (DefaultRuleType | DefaultRuleGroupType)[] = [];\n  const steps = tokenizeGremlinSteps(trimmed);\n\n  for (const step of steps) {\n    // Skip pattern steps — only extract filter predicates\n    // .hasLabel('Label') — pattern step, skip\n    if (step.startsWith('hasLabel(')) continue;\n    // .as('alias') — pattern step, skip\n    if (step.startsWith('as(')) continue;\n    // .out('edge'), .in('edge'), .both('edge') — pattern step, skip\n    if (/^(out|in|both)\\(/.test(step)) continue;\n    // .V(), .E() — traversal source, skip\n    if (/^[VE]\\(/.test(step)) continue;\n\n    // .hasNot('prop') — null check\n    const hasNotMatch = step.match(/^hasNot\\('([^']+)'\\)$/);\n    if (hasNotMatch) {\n      rules.push({ field: hasNotMatch[1], operator: 'null', value: null } as DefaultRuleType);\n      continue;\n    }\n\n    // .has('prop') — property exists\n    const hasExistsMatch = step.match(/^has\\('([^']+)'\\)$/);\n    if (hasExistsMatch) {\n      rules.push({ field: hasExistsMatch[1], operator: 'notNull', value: null } as DefaultRuleType);\n      continue;\n    }\n\n    // .has('prop', value) — equality or predicate\n    const hasEqMatch = step.match(/^has\\('([^']+)',\\s*(.+)\\)$/);\n    if (hasEqMatch) {\n      const [, prop, rawValue] = hasEqMatch;\n      const parsed = parseGremlinPredicate(prop, rawValue.trim());\n      if (parsed) {\n        rules.push(parsed);\n      }\n      continue;\n    }\n  }\n\n  return { combinator: 'and', rules };\n}\n\n/** Tokenizes a Gremlin traversal string into individual step strings. */\nconst tokenizeGremlinSteps = (gremlin: string): string[] => {\n  const steps: string[] = [];\n\n  // Remove leading source (e.g., \"g.V().\")\n  let str = gremlin.trim();\n  const sourceMatch = str.match(/^\\w+\\.V\\(\\)\\./);\n  if (sourceMatch) {\n    str = str.slice(sourceMatch[0].length);\n  } else if (str.startsWith('.')) {\n    // Bare step chain starting with a dot\n    str = str.slice(1);\n  }\n\n  // Split on top-level dots\n  let depth = 0;\n  let current = '';\n\n  for (let i = 0; i < str.length; i++) {\n    const ch = str[i];\n    if (ch === '(') depth++;\n    else if (ch === ')') depth--;\n\n    if (ch === '.' && depth === 0) {\n      if (current.trim()) steps.push(current.trim());\n      current = '';\n      continue;\n    }\n    current += ch;\n  }\n  if (current.trim()) steps.push(current.trim());\n\n  return steps;\n};\n\n/** Parses a Gremlin predicate (the second argument of `.has()`). */\nconst parseGremlinPredicate = (prop: string, rawValue: string): DefaultRuleType | null => {\n  // Predicate functions: gt(), lt(), gte(), lte(), neq(), within(), without(), between(), outside()\n  const predicateMatch = rawValue.match(/^(\\w+)\\((.+)\\)$/);\n  if (predicateMatch) {\n    const [, predName, args] = predicateMatch;\n    const parsedArgs = parseGremlinArgs(args);\n\n    switch (predName) {\n      case 'gt':\n        return { field: prop, operator: '>', value: parsedArgs[0] } as DefaultRuleType;\n      case 'lt':\n        return { field: prop, operator: '<', value: parsedArgs[0] } as DefaultRuleType;\n      case 'gte':\n        return { field: prop, operator: '>=', value: parsedArgs[0] } as DefaultRuleType;\n      case 'lte':\n        return { field: prop, operator: '<=', value: parsedArgs[0] } as DefaultRuleType;\n      case 'neq':\n        return { field: prop, operator: '!=', value: parsedArgs[0] } as DefaultRuleType;\n      case 'within':\n        return { field: prop, operator: 'in', value: parsedArgs } as DefaultRuleType;\n      case 'without':\n        return { field: prop, operator: 'notIn', value: parsedArgs } as DefaultRuleType;\n      case 'between':\n        return {\n          field: prop,\n          operator: 'between',\n          value: parsedArgs.slice(0, 2),\n        } as DefaultRuleType;\n      case 'outside':\n        return {\n          field: prop,\n          operator: 'notBetween',\n          value: parsedArgs.slice(0, 2),\n        } as DefaultRuleType;\n      case 'containing':\n        return { field: prop, operator: 'contains', value: parsedArgs[0] } as DefaultRuleType;\n      case 'notContaining':\n        return { field: prop, operator: 'doesNotContain', value: parsedArgs[0] } as DefaultRuleType;\n      case 'startingWith':\n        return { field: prop, operator: 'beginsWith', value: parsedArgs[0] } as DefaultRuleType;\n      case 'notStartingWith':\n        return {\n          field: prop,\n          operator: 'doesNotBeginWith',\n          value: parsedArgs[0],\n        } as DefaultRuleType;\n      case 'endingWith':\n        return { field: prop, operator: 'endsWith', value: parsedArgs[0] } as DefaultRuleType;\n      case 'notEndingWith':\n        return { field: prop, operator: 'doesNotEndWith', value: parsedArgs[0] } as DefaultRuleType;\n      default:\n        return null;\n    }\n  }\n\n  // Plain value — equality\n  return { field: prop, operator: '=', value: parseGremlinLiteral(rawValue) } as DefaultRuleType;\n};\n\n/** Parses a comma-separated argument list. */\nconst parseGremlinArgs = (args: string): unknown[] => {\n  const result: unknown[] = [];\n  let depth = 0;\n  let current = '';\n\n  for (const ch of args) {\n    if (ch === '(') depth++;\n    else if (ch === ')') depth--;\n    if (ch === ',' && depth === 0) {\n      result.push(parseGremlinLiteral(current.trim()));\n      current = '';\n      continue;\n    }\n    current += ch;\n  }\n  if (current.trim()) result.push(parseGremlinLiteral(current.trim()));\n  return result;\n};\n\n/** Parses a Gremlin literal value. */\nconst parseGremlinLiteral = (raw: string): unknown => {\n  if (raw.startsWith(\"'\") && raw.endsWith(\"'\")) {\n    return raw.slice(1, -1).replace(/\\\\'/g, \"'\");\n  }\n  if (raw === 'null') return null;\n  if (raw === 'true') return true;\n  if (raw === 'false') return false;\n  const num = Number(raw);\n  if (!Number.isNaN(num)) return num;\n  return raw;\n};\n"],"mappings":"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"}