{
  "version": 3,
  "sources": ["../../src/traverser/traverse.ts"],
  "sourcesContent": ["import type {AlternativeElementNode, AlternativeNode, CharacterClassElementNode, Node, ParentNode, RegexNode} from '../parser/parse.js';\nimport {throwIfNullish} from '../utils.js';\n\ntype ContainerElementNode =\n  // Used within the `body` container of any `AlternativeContainerNode`\n  AlternativeNode |\n  // Any node type used within the `body` container of an `AlternativeNode`\n  AlternativeElementNode |\n  // Any node type used within the `body` container of a `CharacterClassNode`\n  CharacterClassElementNode;\n\ntype Path<N = Node, Root = RegexNode> = {\n  // The current node being traversed\n  node: N;\n  // Parent node of the current node\n  parent: N extends RegexNode ? null : ParentNode;\n  // String property where the current node in held by the parent node, or numeric index in the\n  // parent's `container` array\n  key: N extends RegexNode ? null : number | string;\n  // Container array holding the current node in the parent node; `null` if the parent isn't a type\n  // that contains a list of nodes\n  container: N extends RegexNode ? null : Array<ContainerElementNode> | null;\n  // Starting node of the AST being traversed; usually a `RegexNode` but can be any node type if\n  // traversing from a midpoint\n  root: Root;\n  // Removes the current node; its kids won't be traversed\n  remove: () => void;\n  // Removes all siblings to the right of the current node, without traversing them; returns the\n  // removed nodes\n  removeAllNextSiblings: () => Array<Node>;\n  // Removes all siblings to the left of the current node, which have already been traversed;\n  // returns the removed nodes\n  removeAllPrevSiblings: () => Array<Node>;\n  // Replaces the current node with a new node; kids of the replaced node won't be traversed;\n  // optionally traverses the new node\n  replaceWith: (newNode: Node, options?: {traverse?: boolean}) => void;\n  // Replaces the current node with multiple new nodes; kids of the replaced node won't be\n  // traversed; optionally traverses the new nodes\n  replaceWithMultiple: (newNodes: Array<Node>, options?: {traverse?: boolean}) => void;\n  // Skips traversing kids of the current node\n  skip: () => void;\n};\n\n// `VisitorNodeFn() {\u2026}` is shorthand for `VisitorNodeFn: {enter() {\u2026}}`.\ntype Visitor<State extends object | null = null, Root extends Node = RegexNode> = {\n  [N in Node as N['type']]?: VisitorNodeFn<Path<N, Root>, State> | {\n    enter?: VisitorNodeFn<Path<N, Root>, State>;\n    exit?: VisitorNodeFn<Path<N, Root>, State>;\n  };\n} & {\n  '*'?: VisitorNodeFn<Path<Node, Root>, State> | {\n    enter?: VisitorNodeFn<Path<Node, Root>, State>;\n    exit?: VisitorNodeFn<Path<Node, Root>, State>;\n  };\n};\n\ntype VisitorNodeFn<P, State> = (path: P, state: State) => void;\n\n/**\nTraverses an AST and calls the provided `visitor`'s node function for each node. Returns the same\nobject, possibly modified.\n\nVisitor node functions can modify the AST in place and use methods on the `path` (provided as their\nfirst argument) to help modify the AST. Provided `state` is passed through to all visitor node\nfunctions as their second argument.\n\nVisitor node functions are called in the following order:\n1. `enter` function of the `'*'` node type (if any)\n2. `enter` function of the given node's type (if any)\n3. [The node's kids (if any) are traversed recursively, unless `skip` is called]\n4. `exit` function of the given node's type (if any)\n5. `exit` function of the `'*'` node type (if any)\n*/\nfunction traverse<State extends object | null = null, Root extends Node = RegexNode>(\n  root: Root,\n  visitor: Visitor<State, Root>,\n  state: State | null = null\n): Root {\n  function traverseArray(array: NonNullable<Path['container']>, parent: Path['parent']) {\n    for (let i = 0; i < array.length; i++) {\n      const keyShift = traverseNode(array[i], parent, i, array);\n      i = Math.max(-1, i + keyShift);\n    }\n  }\n  function traverseNode(\n    node: Path['node'],\n    parent: Path['parent'] = null,\n    key: Path['key'] = null,\n    container: Path['container'] = null\n  ): number {\n    let keyShift = 0;\n    let skipTraversingKidsOfPath = false;\n    const path: Path = {\n      node,\n      parent,\n      key,\n      container,\n      root: root as RegexNode,\n      remove() {\n        arrayContainer(container).splice(Math.max(0, numericKey(key) + keyShift), 1);\n        keyShift--;\n        skipTraversingKidsOfPath = true;\n      },\n      removeAllNextSiblings() {\n        return arrayContainer(container).splice(numericKey(key) + 1);\n      },\n      removeAllPrevSiblings() {\n        const shifted = numericKey(key) + keyShift;\n        keyShift -= shifted;\n        return arrayContainer(container).splice(0, Math.max(0, shifted));\n      },\n      replaceWith(newNode, options = {}) {\n        const traverseNew = !!options.traverse;\n        if (container) {\n          container[Math.max(0, numericKey(key) + keyShift)] = newNode as ContainerElementNode;\n        } else {\n          // `key` will be one of:\n          // - For `CharacterClassRangeNode`: 'min', 'max'\n          // - For `QuantifierNode`: 'body'\n          // - For `RegexNode`: 'flags'\n          // @ts-expect-error\n          throwIfNullish(parent, `Can't replace root node`)[key as string] = newNode;\n        }\n        if (traverseNew) {\n          traverseNode(newNode, parent, key, container);\n        }\n        skipTraversingKidsOfPath = true;\n      },\n      replaceWithMultiple(newNodes, options = {}) {\n        const traverseNew = !!options.traverse;\n        arrayContainer(container).splice(Math.max(0, numericKey(key) + keyShift), 1, ...newNodes);\n        keyShift += newNodes.length - 1;\n        if (traverseNew) {\n          let keyShiftInLoop = 0;\n          for (let i = 0; i < newNodes.length; i++) {\n            keyShiftInLoop += traverseNode(newNodes[i], parent, numericKey(key) + i + keyShiftInLoop, container);\n          }\n        }\n        skipTraversingKidsOfPath = true;\n      },\n      skip() {\n        skipTraversingKidsOfPath = true;\n      },\n    };\n\n    const {type} = node;\n    const anyTypeVisitor = visitor['*'];\n    const thisTypeVisitor = visitor[type];\n    const enterAllFn = typeof anyTypeVisitor === 'function' ? anyTypeVisitor : anyTypeVisitor?.enter;\n    const enterThisFn = typeof thisTypeVisitor === 'function' ? thisTypeVisitor : thisTypeVisitor?.enter;\n    // Type args are too complex to avoid TS errors here, but `VisitorNodeFn`s get correct types\n    // @ts-expect-error\n    enterAllFn?.(path, state);\n    // @ts-expect-error\n    enterThisFn?.(path, state);\n\n    if (!skipTraversingKidsOfPath) {\n      switch (type) {\n        case 'AbsenceFunction':\n        case 'CapturingGroup':\n        case 'Group':\n          traverseArray(node.body, node);\n          break;\n        case 'Alternative':\n        case 'CharacterClass':\n          traverseArray(node.body, node);\n          break;\n        case 'Assertion':\n        case 'Backreference':\n        case 'Character':\n        case 'CharacterSet':\n        case 'Directive':\n        case 'Flags':\n        case 'NamedCallout':\n        case 'Subroutine':\n          break;\n        case 'CharacterClassRange':\n          traverseNode(node.min, node, 'min');\n          traverseNode(node.max, node, 'max');\n          break;\n        case 'LookaroundAssertion':\n          traverseArray(node.body, node);\n          break;\n        case 'Quantifier':\n          traverseNode(node.body, node, 'body');\n          break;\n        case 'Regex':\n          traverseArray(node.body, node);\n          traverseNode(node.flags, node, 'flags');\n          break;\n        default:\n          throw new Error(`Unexpected node type \"${type}\"`);\n      }\n    }\n\n    // @ts-expect-error\n    (thisTypeVisitor as Exclude<typeof thisTypeVisitor, Function>)?.exit?.(path, state);\n    // @ts-expect-error\n    (anyTypeVisitor as Exclude<typeof anyTypeVisitor, Function>)?.exit?.(path, state);\n    return keyShift;\n  }\n  traverseNode(root);\n  return root;\n}\n\nfunction arrayContainer(value: unknown): Array<Node> {\n  if (!Array.isArray(value)) {\n    throw new Error('Container expected');\n  }\n  return value;\n}\n\nfunction numericKey(value: unknown): number {\n  if (typeof value !== 'number') {\n    throw new Error('Numeric key expected');\n  }\n  return value;\n}\n\nexport {\n  type Path,\n  type Visitor,\n  traverse,\n};\n"],
  "mappings": "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",
  "names": ["throwIfNullish", "traverse", "root", "visitor", "state", "traverseArray", "array", "parent", "i", "keyShift", "traverseNode", "node", "key", "container", "skipTraversingKidsOfPath", "path", "arrayContainer", "numericKey", "shifted", "newNode", "options", "traverseNew", "newNodes", "keyShiftInLoop", "type", "anyTypeVisitor", "thisTypeVisitor", "enterAllFn", "enterThisFn", "value"]
}
