{
  "version": 3,
  "sources": ["../../../src/optimizer/transforms/extract-prefix.ts"],
  "sourcesContent": ["import type {AssertionNode, CharacterNode, CharacterSetNode, Node} from '../../parser/parse.js';\nimport type {Visitor} from '../../traverser/traverse.js';\nimport {isAlternativeContainer} from '../../parser/node-utils.js';\nimport {createAlternative, createGroup} from '../../parser/parse.js';\n\n/**\nExtract nodes at the start of every alternative into a prefix.\nEx: `^aa|^abb|^ac` -> `^a(?:a|bb|c)`.\nAlso works within groups.\n*/\nconst extractPrefix: Visitor = {\n  '*'({node}) {\n    if (!isAlternativeContainer(node) || node.body.length < 2) {\n      return;\n    }\n    const prefixNodes = [];\n    let passedSharedPrefix = false;\n    let i = 0;\n    while (!passedSharedPrefix) {\n      prefixNodes.push(node.body[0].body[i]);\n      for (const alt of node.body) {\n        const kid = alt.body[i];\n        if (!kid || !isAllowedSimpleNode(kid) || !isNodeEqual(kid, prefixNodes[i])) {\n          passedSharedPrefix = true;\n          break;\n        }\n      }\n      i++;\n    }\n    prefixNodes.pop();\n    if (!prefixNodes.length) {\n      return;\n    }\n\n    for (const alt of node.body) {\n      alt.body = alt.body.slice(prefixNodes.length);\n    }\n    const newContentsAlt = createAlternative({body: prefixNodes});\n    const suffixGroup = createGroup({body: node.body});\n    if (!suffixGroup.body.every(alt => !alt.body.length)) {\n      newContentsAlt.body.push(suffixGroup);\n    }\n    node.body = [newContentsAlt];\n  },\n};\n\nfunction isAllowedSimpleNode(node: Node) {\n  return (\n    node.type === 'Assertion' ||\n    node.type === 'Character' ||\n    node.type === 'CharacterSet'\n  );\n}\n\n// TODO: Add support for more node types and move to `src/parser/node-utils.ts`\nfunction isNodeEqual(a: Node, b: Node): boolean {\n  if (a.type !== b.type) {\n    // TS doesn't understand that this makes `a` and `b` always have the same type, so we'll still\n    // need to cast, later\n    return false;\n  }\n  if (a.type === 'Assertion' || a.type === 'CharacterSet') {\n    return (\n      a.kind === (b as AssertionNode | CharacterSetNode).kind &&\n      a.negate === (b as AssertionNode | CharacterSetNode).negate\n    );\n  }\n  if (a.type === 'Character') {\n    return a.value === (b as CharacterNode).value;\n  }\n  // Only supports types from `isAllowedSimpleNode`\n  throw new Error(`Unexpected node type \"${a.type}\"`);\n}\n\nexport {\n  extractPrefix,\n  isAllowedSimpleNode,\n  isNodeEqual,\n};\n"],
  "mappings": "aAEA,OAAQ,0BAAAA,MAA6B,6BACrC,OAAQ,qBAAAC,EAAmB,eAAAC,MAAkB,wBAO7C,MAAMC,EAAyB,CAC7B,IAAI,CAAC,KAAAC,CAAI,EAAG,CACV,GAAI,CAACJ,EAAuBI,CAAI,GAAKA,EAAK,KAAK,OAAS,EACtD,OAEF,MAAMC,EAAc,CAAC,EACrB,IAAIC,EAAqB,GACrBC,EAAI,EACR,KAAO,CAACD,GAAoB,CAC1BD,EAAY,KAAKD,EAAK,KAAK,CAAC,EAAE,KAAKG,CAAC,CAAC,EACrC,UAAWC,KAAOJ,EAAK,KAAM,CAC3B,MAAMK,EAAMD,EAAI,KAAKD,CAAC,EACtB,GAAI,CAACE,GAAO,CAACC,EAAoBD,CAAG,GAAK,CAACE,EAAYF,EAAKJ,EAAYE,CAAC,CAAC,EAAG,CAC1ED,EAAqB,GACrB,KACF,CACF,CACAC,GACF,CAEA,GADAF,EAAY,IAAI,EACZ,CAACA,EAAY,OACf,OAGF,UAAWG,KAAOJ,EAAK,KACrBI,EAAI,KAAOA,EAAI,KAAK,MAAMH,EAAY,MAAM,EAE9C,MAAMO,EAAiBX,EAAkB,CAAC,KAAMI,CAAW,CAAC,EACtDQ,EAAcX,EAAY,CAAC,KAAME,EAAK,IAAI,CAAC,EAC5CS,EAAY,KAAK,MAAML,GAAO,CAACA,EAAI,KAAK,MAAM,GACjDI,EAAe,KAAK,KAAKC,CAAW,EAEtCT,EAAK,KAAO,CAACQ,CAAc,CAC7B,CACF,EAEA,SAASF,EAAoBN,EAAY,CACvC,OACEA,EAAK,OAAS,aACdA,EAAK,OAAS,aACdA,EAAK,OAAS,cAElB,CAGA,SAASO,EAAYG,EAASC,EAAkB,CAC9C,GAAID,EAAE,OAASC,EAAE,KAGf,MAAO,GAET,GAAID,EAAE,OAAS,aAAeA,EAAE,OAAS,eACvC,OACEA,EAAE,OAAUC,EAAuC,MACnDD,EAAE,SAAYC,EAAuC,OAGzD,GAAID,EAAE,OAAS,YACb,OAAOA,EAAE,QAAWC,EAAoB,MAG1C,MAAM,IAAI,MAAM,yBAAyBD,EAAE,IAAI,GAAG,CACpD,CAEA,OACEX,KAAA,cACAO,KAAA,oBACAC,KAAA",
  "names": ["isAlternativeContainer", "createAlternative", "createGroup", "extractPrefix", "node", "prefixNodes", "passedSharedPrefix", "i", "alt", "kid", "isAllowedSimpleNode", "isNodeEqual", "newContentsAlt", "suffixGroup", "a", "b"]
}
