{"version":3,"file":"templates.cjs","sources":["../src/Util.ts","../src/Slicer.ts","../src/templates/SimpleTemplate.ts"],"sourcesContent":["export function multiKeySet<A, B, V>(\n  m: Map<A, Map<B, V>>,\n  a: A,\n  b: B,\n  v: V\n): void {\n  const bMap = m.get(a) || new Map();\n  m.set(a, bMap);\n  bMap.set(b, v);\n}\n\nconst tokenRegex = /\\b(\\w+)\\b/gi;\n/** replace strings in a text according to a relacement map\n * replaced strings must be 'tokens', surrounded by spaces or punctuation\n */\nexport function replaceWords(\n  text: string,\n  replace: Record<string, string>\n): string {\n  return text.replaceAll(tokenRegex, (s) => (s in replace ? replace[s] : s));\n}\n\n/** return an array partitioned into possibly overlapping groups */\nexport function grouped<T>(a: T[], size: number, stride = size): T[][] {\n  const groups = [];\n  for (let i = 0; i < a.length; i += stride) {\n    groups.push(a.slice(i, i + size));\n  }\n  return groups;\n}\n\n/** group an array into subarrays by a key function */\nexport function groupBy<T, K>(a: T[], key: (t: T) => K): Map<K, T[]> {\n  const groups = new Map<K, T[]>();\n  for (const t of a) {\n    const k = key(t);\n    const group = groups.get(k) || [];\n    group.push(t);\n    groups.set(k, group);\n  }\n  return groups;\n}\n\n/** partition an array into two parts by a discriminator function */\nexport function partition<T>(a: T[], partFn: (t: T) => boolean): [T[], T[]] {\n  const yesPart: T[] = [];\n  const noPart: T[] = [];\n  for (const t of a) {\n    partFn(t) ? yesPart.push(t) : noPart.push(t);\n  }\n  return [yesPart, noPart];\n}\n\n/** run an carrying function over every element in an array,\n * i.e. an inclusive prefix scan */\nexport function scan<T, U>(array: T[], fn: (a: T, b: U) => U, zero: U): U[] {\n  const result = [zero];\n\n  let current = zero;\n  for (let i = 0; i < array.length; i++) {\n    current = fn(array[i], current);\n    result.push(current);\n  }\n  return result;\n}\n\n/** return a new record by replacing values in 'a' with 'b' as a map.\n * values in 'a' that are not in 'b' are unchanged.\n * e.g. {a: \"b\", x: 9}, {b: 1} yields {a: 1, x: 9}\n */\nexport function mapForward(\n  a: Record<string, string>,\n  b: Record<string, any>\n): Record<string, any> {\n  const combined = Object.entries(a).map(([key, value]) => {\n    const mappedValue = value in b ? b[value] : value;\n    return [key, mappedValue];\n  });\n  return Object.fromEntries(combined);\n}\n\n/** return the last element of an array or undefined */\nexport function last<T>(a: T[]): T | undefined {\n  return a[a.length - 1];\n}\n\n/**\n * Overlap two arrays, returning the tail of b if a is a prefix of b.\n * Otherwise, return undefined.\n */\nexport function overlapTail<T>(a: T[], b: T[]): T[] | undefined {\n  let overlapSize = Math.min(a.length, b.length);\n\n  while (overlapSize > 0) {\n    const suffix = a.slice(-overlapSize);\n    const prefix = b.slice(0, overlapSize);\n    if (arrayEquals(suffix, prefix)) {\n      break;\n    } else {\n      overlapSize--;\n    }\n  }\n\n  if (overlapSize) {\n    return b.slice(overlapSize);\n  }\n}\n\nfunction arrayEquals(a: any[], b: any[]): boolean {\n  return a.length === b.length && a.every((val, index) => val === b[index]);\n}\n","import { SrcMap, SrcMapEntry } from \"mini-parse\";\nimport { last, scan } from \"./Util.js\";\n\n/** specify a start,end portion of a string to be replaced */\nexport interface SliceReplace {\n  start: number;\n  end: number;\n  replacement: string;\n}\n\ninterface SlicingProgress {\n  srcPos: number;\n  destPos: number;\n  results: string[];\n  entries: SrcMapEntry[];\n}\n\n/**\n * Rewrite a string by replacing segments them with provided texts.\n *\n * example:\n * src:\n *  aaabbbbbc\n *     ^    ^\n *     St   End Repl='XXX'\n *\n * returns a srcMap with the new text and mappings from the original text to the new text\n *  aaaXXXc\n */\nexport function sliceReplace(\n  src: string,\n  slices: SliceReplace[],\n  start = 0,\n  end = src.length\n): SrcMap {\n  const sorted = [...slices].sort((a, b) => a.start - b.start);\n  const initProgress = { srcPos: start, destPos: 0, results: [], entries: [] };\n  const slicePogress = scan(sorted, oneSlice, initProgress);\n  const lastProgress = finalProgress2(slicePogress);\n\n  const { results, entries } = lastProgress;\n  const text = results.join(\"\");\n  const srcMap = new SrcMap(text, entries);\n  return srcMap;\n\n  /** visit one slice, return progress */\n  function oneSlice(\n    slice: SliceReplace,\n    progress: SlicingProgress\n  ): SlicingProgress {\n    // dlog({ slice });\n    // update text with copy and replacement\n    const copyText = src.slice(progress.srcPos, slice.start);\n    const copied = replaceOne(copyText, slice.start, progress);\n    const replaced = replaceOne(slice.replacement, slice.end, copied);\n\n    return replaced;\n  }\n\n  /** add provided text to the result, advance src position, and add a srcMap entry\n   * @return the accumulated progress */\n  function replaceOne(\n    replacement: string,\n    newSrcPos: number,\n    progress: SlicingProgress\n  ): SlicingProgress {\n    const { destPos, entries } = progress;\n    const newDestPos = destPos + replacement.length;\n\n    // new srcMap entry if there is a replacement text (otherwise there's nothing to map dest to src)\n    let newEntries = entries;\n    if (replacement) {\n      const { srcPos } = progress;\n      newEntries = entries.concat({\n        src,\n        srcStart: srcPos,\n        srcEnd: newSrcPos,\n        destStart: destPos,\n        destEnd: newDestPos,\n      });\n    }\n\n    // update results text and progress\n    const { results } = progress;\n    const newResults = replacement ? results.concat(replacement) : results;\n    return {\n      srcPos: newSrcPos,\n      destPos: newDestPos,\n      results: newResults,\n      entries: newEntries,\n    };\n  }\n\n  /**\n   * If there's any trailing text uncovered by the slices before the end,\n   * add a result and srcMap entry\n   *\n   * @return the accumulated progress\n   */\n  function finalProgress2(progress: SlicingProgress[]): SlicingProgress {\n    const lastProgress = last(progress) ?? initProgress;\n    const { srcPos } = lastProgress;\n    return replaceOne(src.slice(srcPos, end), end, lastProgress);\n  }\n}\n\nconst tokenRegex = /\\b(\\w+)\\b/gi;\n/** find strings in a text -\n * found strings must be 'tokens', surrounded by spaces or punctuation\n *\n * @return SliceReplace elements\n */\nexport function sliceWords(\n  text: string,\n  replace: Record<string, string>\n): SliceReplace[] {\n  const tokens = [...text.matchAll(tokenRegex)];\n  const find = Object.keys(replace);\n  const matches = tokens.filter((m) => find.includes(m[0]));\n  const slices = matches.map((m) => {\n    const start = m.index;\n    const end = start + m[0].length;\n    const replacement = replace[m[0]];\n    return { start, end, replacement };\n  });\n  return slices;\n}\n","import { Template } from \"../ModuleRegistry.js\";\nimport { sliceReplace, sliceWords } from \"../Slicer.js\";\n\nexport const simpleTemplate: Template = {\n  name: \"simple\",\n  apply: (src, extParams) => {\n    const slices = sliceWords(src, extParams);\n    return sliceReplace(src, slices);\n  },\n};\n"],"names":["SrcMap","entries","results","lastProgress"],"mappings":";;;AAuDgB,SAAA,KAAW,OAAY,IAAuB,MAAc;AACpE,QAAA,SAAS,CAAC,IAAI;AAEpB,MAAI,UAAU;AACd,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAU,GAAG,MAAM,CAAC,GAAG,OAAO;AAC9B,WAAO,KAAK,OAAO;AAAA,EACrB;AACO,SAAA;AACT;AAkBO,SAAS,KAAQ,GAAuB;AACtC,SAAA,EAAE,EAAE,SAAS,CAAC;AACvB;ACvDO,SAAS,aACd,KACA,QACA,QAAQ,GACR,MAAM,IAAI,QACF;AACR,QAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACrD,QAAA,eAAe,EAAE,QAAQ,OAAO,SAAS,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;AACxE,QAAM,eAAe,KAAK,QAAQ,UAAU,YAAY;AAClD,QAAA,eAAe,eAAe,YAAY;AAE1C,QAAA,EAAE,SAAS,QAAY,IAAA;AACvB,QAAA,OAAO,QAAQ,KAAK,EAAE;AAC5B,QAAM,SAAS,IAAIA,UAAAA,OAAO,MAAM,OAAO;AAChC,SAAA;AAGE,WAAA,SACP,OACA,UACiB;AAGjB,UAAM,WAAW,IAAI,MAAM,SAAS,QAAQ,MAAM,KAAK;AACvD,UAAM,SAAS,WAAW,UAAU,MAAM,OAAO,QAAQ;AACzD,UAAM,WAAW,WAAW,MAAM,aAAa,MAAM,KAAK,MAAM;AAEzD,WAAA;AAAA,EACT;AAIS,WAAA,WACP,aACA,WACA,UACiB;AACjB,UAAM,EAAE,SAAS,SAAAC,SAAAA,IAAY;AACvB,UAAA,aAAa,UAAU,YAAY;AAGzC,QAAI,aAAaA;AACjB,QAAI,aAAa;AACT,YAAA,EAAE,OAAW,IAAA;AACnB,mBAAaA,SAAQ,OAAO;AAAA,QAC1B;AAAA,QACA,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS;AAAA,MAAA,CACV;AAAA,IACH;AAGM,UAAA,EAAE,SAAAC,SAAY,IAAA;AACpB,UAAM,aAAa,cAAcA,SAAQ,OAAO,WAAW,IAAIA;AACxD,WAAA;AAAA,MACL,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,IAAA;AAAA,EAEb;AAQA,WAAS,eAAe,UAA8C;AAC9DC,UAAAA,gBAAe,KAAK,QAAQ,KAAK;AACjC,UAAA,EAAE,OAAWA,IAAAA;AACnB,WAAO,WAAW,IAAI,MAAM,QAAQ,GAAG,GAAG,KAAKA,aAAY;AAAA,EAC7D;AACF;AAEA,MAAM,aAAa;AAMH,SAAA,WACd,MACA,SACgB;AAChB,QAAM,SAAS,CAAC,GAAG,KAAK,SAAS,UAAU,CAAC;AACtC,QAAA,OAAO,OAAO,KAAK,OAAO;AAC1B,QAAA,UAAU,OAAO,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC,CAAC;AACxD,QAAM,SAAS,QAAQ,IAAI,CAAC,MAAM;AAChC,UAAM,QAAQ,EAAE;AAChB,UAAM,MAAM,QAAQ,EAAE,CAAC,EAAE;AACzB,UAAM,cAAc,QAAQ,EAAE,CAAC,CAAC;AACzB,WAAA,EAAE,OAAO,KAAK;EAAY,CAClC;AACM,SAAA;AACT;AC3HO,MAAM,iBAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO,CAAC,KAAK,cAAc;AACnB,UAAA,SAAS,WAAW,KAAK,SAAS;AACjC,WAAA,aAAa,KAAK,MAAM;AAAA,EACjC;AACF;;"}