{
  "version": 3,
  "sources": ["../../../src/optimizer/transforms/merge-ranges.ts"],
  "sourcesContent": ["import type {CharacterClassElementNode, CharacterClassRangeNode, CharacterNode} from '../../parser/parse.js';\nimport type {Visitor} from '../../traverser/traverse.js';\nimport {createCharacter, createCharacterClassRange} from '../../parser/parse.js';\n\n/**\nMerge, dedupe, and sort ranges and characters in character classes.\n*/\nconst mergeRanges: Visitor = {\n  CharacterClass({node}) {\n    if (node.kind !== 'union' || !node.body.length) {\n      return;\n    }\n\n    // ## Since characters and ranges will be deduped by merging, might as well dedupe sets too\n    const withoutDupeSets: Array<CharacterClassElementNode> = [];\n    for (const el of node.body) {\n      if (\n        el.type === 'CharacterSet' &&\n        withoutDupeSets.some(k => (\n          k.type === el.type &&\n          k.kind === el.kind &&\n          k.negate === el.negate &&\n          k.value === el.value\n        ))\n      ) {\n        continue;\n      }\n      // Keep non-duplicate sets (first instance) and any non-set nodes\n      withoutDupeSets.push(el);\n    }\n    node.body = withoutDupeSets;\n\n    // ## Now merge characters and ranges\n    const keep: Array<Exclude<CharacterClassElementNode, HandledNode>> = [];\n    const candidates: Array<HandledNode> = [];\n    for (const el of node.body) {\n      if (el.type === 'Character' || el.type === 'CharacterClassRange') {\n        candidates.push(el);\n      } else {\n        keep.push(el);\n      }\n    }\n    if (!candidates.length) {\n      return;\n    }\n    candidates.sort((a, b) => {\n      const aValue = a.type === 'Character' ? a.value : a.min.value;\n      const bValue = b.type === 'Character' ? b.value : b.min.value;\n      return aValue - bValue;\n    });\n    const merged: Array<HandledNode> = [candidates[0]];\n    for (let i = 1; i < candidates.length; i++) {\n      const el = candidates[i];\n      const last = merged.at(-1)!;\n      const elMin = el.type === 'Character' ? el.value : el.min.value;\n      const lastMax = last.type === 'Character' ? last.value : last.max.value;\n      if (elMin <= lastMax + 1) {\n        if (last.type === 'Character' && el.type === 'Character') {\n          if (last.value !== el.value) {\n            merged[merged.length - 1] = createCharacterClassRange(last, el);\n          }\n        } else if (last.type === 'Character' && el.type === 'CharacterClassRange') {\n          merged[merged.length - 1] = createCharacterClassRange(createCharacter(last.value), el.max);\n        } else if (last.type === 'CharacterClassRange' && el.type === 'Character') {\n          last.max.value = Math.max(el.value, last.max.value);\n        } else if (last.type === 'CharacterClassRange' && el.type === 'CharacterClassRange') {\n          last.max.value = Math.max(el.max.value, last.max.value);\n        } else {\n          throw new Error('Unexpected merge case');\n        }\n      } else {\n        merged.push(el);\n      }\n    }\n    // Replace any ranges with fewer than four (sometimes three) chars with character nodes\n    const final = merged.flatMap(el => {\n      if (el.type === 'CharacterClassRange') {\n        const diff = el.max.value - el.min.value;\n        // More aggressively use ranges for U+40000+, since they're rendered in long form like\n        // `\\x{40000}` rather than as single-length characters\n        if (el.min.value > 0x3FFFF && diff > 1) {\n          return el;\n        } else if (!diff) {\n          return el.min;\n        } else if (diff === 1) {\n          return [el.min, el.max];\n        } else if (diff === 2) {\n          // Ex: `a-c` -> `abc`\n          return [el.min, createCharacter(el.min.value + 1), el.max];\n        }\n        // `diff > 2`\n      }\n      return el;\n    });\n    // Always replace `body` to avoid skipping things like `[a-a]` -> `[a]` where both classes\n    // contain the same number of nodes; means we always sort characters/ranges by their values\n    node.body = [\n      // Pull chars to the front that don't need to be escaped in first position\n      ...final.filter(el => firstPosChar(el)),\n      ...final.filter(el => !firstPosChar(el)),\n      ...keep\n    ];\n  },\n};\n\ntype HandledNode = CharacterNode | CharacterClassRangeNode;\n\nfunction firstPosChar(node: HandledNode): boolean {\n  // Is `-` or `]`\n  return node.type === 'Character' && (node.value === 45 || node.value === 93);\n}\n\nexport {\n  mergeRanges,\n};\n"],
  "mappings": "aAEA,OAAQ,mBAAAA,EAAiB,6BAAAC,MAAgC,wBAKzD,MAAMC,EAAuB,CAC3B,eAAe,CAAC,KAAAC,CAAI,EAAG,CACrB,GAAIA,EAAK,OAAS,SAAW,CAACA,EAAK,KAAK,OACtC,OAIF,MAAMC,EAAoD,CAAC,EAC3D,UAAWC,KAAMF,EAAK,KAElBE,EAAG,OAAS,gBACZD,EAAgB,KAAKE,GACnBA,EAAE,OAASD,EAAG,MACdC,EAAE,OAASD,EAAG,MACdC,EAAE,SAAWD,EAAG,QAChBC,EAAE,QAAUD,EAAG,KAChB,GAKHD,EAAgB,KAAKC,CAAE,EAEzBF,EAAK,KAAOC,EAGZ,MAAMG,EAA+D,CAAC,EAChEC,EAAiC,CAAC,EACxC,UAAWH,KAAMF,EAAK,KAChBE,EAAG,OAAS,aAAeA,EAAG,OAAS,sBACzCG,EAAW,KAAKH,CAAE,EAElBE,EAAK,KAAKF,CAAE,EAGhB,GAAI,CAACG,EAAW,OACd,OAEFA,EAAW,KAAK,CAACC,EAAGC,IAAM,CACxB,MAAMC,EAASF,EAAE,OAAS,YAAcA,EAAE,MAAQA,EAAE,IAAI,MAClDG,EAASF,EAAE,OAAS,YAAcA,EAAE,MAAQA,EAAE,IAAI,MACxD,OAAOC,EAASC,CAClB,CAAC,EACD,MAAMC,EAA6B,CAACL,EAAW,CAAC,CAAC,EACjD,QAASM,EAAI,EAAGA,EAAIN,EAAW,OAAQM,IAAK,CAC1C,MAAMT,EAAKG,EAAWM,CAAC,EACjBC,EAAOF,EAAO,GAAG,EAAE,EACnBG,EAAQX,EAAG,OAAS,YAAcA,EAAG,MAAQA,EAAG,IAAI,MACpDY,EAAUF,EAAK,OAAS,YAAcA,EAAK,MAAQA,EAAK,IAAI,MAClE,GAAIC,GAASC,EAAU,EACrB,GAAIF,EAAK,OAAS,aAAeV,EAAG,OAAS,YACvCU,EAAK,QAAUV,EAAG,QACpBQ,EAAOA,EAAO,OAAS,CAAC,EAAIZ,EAA0Bc,EAAMV,CAAE,WAEvDU,EAAK,OAAS,aAAeV,EAAG,OAAS,sBAClDQ,EAAOA,EAAO,OAAS,CAAC,EAAIZ,EAA0BD,EAAgBe,EAAK,KAAK,EAAGV,EAAG,GAAG,UAChFU,EAAK,OAAS,uBAAyBV,EAAG,OAAS,YAC5DU,EAAK,IAAI,MAAQ,KAAK,IAAIV,EAAG,MAAOU,EAAK,IAAI,KAAK,UACzCA,EAAK,OAAS,uBAAyBV,EAAG,OAAS,sBAC5DU,EAAK,IAAI,MAAQ,KAAK,IAAIV,EAAG,IAAI,MAAOU,EAAK,IAAI,KAAK,MAEtD,OAAM,IAAI,MAAM,uBAAuB,OAGzCF,EAAO,KAAKR,CAAE,CAElB,CAEA,MAAMa,EAAQL,EAAO,QAAQR,GAAM,CACjC,GAAIA,EAAG,OAAS,sBAAuB,CACrC,MAAMc,EAAOd,EAAG,IAAI,MAAQA,EAAG,IAAI,MAGnC,GAAIA,EAAG,IAAI,MAAQ,QAAWc,EAAO,EACnC,OAAOd,EACF,GAAKc,EAEL,IAAIA,IAAS,EAClB,MAAO,CAACd,EAAG,IAAKA,EAAG,GAAG,EACjB,GAAIc,IAAS,EAElB,MAAO,CAACd,EAAG,IAAKL,EAAgBK,EAAG,IAAI,MAAQ,CAAC,EAAGA,EAAG,GAAG,MALzD,QAAOA,EAAG,GAQd,CACA,OAAOA,CACT,CAAC,EAGDF,EAAK,KAAO,CAEV,GAAGe,EAAM,OAAOb,GAAMe,EAAaf,CAAE,CAAC,EACtC,GAAGa,EAAM,OAAOb,GAAM,CAACe,EAAaf,CAAE,CAAC,EACvC,GAAGE,CACL,CACF,CACF,EAIA,SAASa,EAAajB,EAA4B,CAEhD,OAAOA,EAAK,OAAS,cAAgBA,EAAK,QAAU,IAAMA,EAAK,QAAU,GAC3E,CAEA,OACED,KAAA",
  "names": ["createCharacter", "createCharacterClassRange", "mergeRanges", "node", "withoutDupeSets", "el", "k", "keep", "candidates", "a", "b", "aValue", "bValue", "merged", "i", "last", "elMin", "lastMax", "final", "diff", "firstPosChar"]
}
