SPB Git forge

spb/uqo-chat

Public
14commits 1branches 0releases
1.4 MBsize
maindefault branch
17 days agolast push
Python 64.6% TypeScript 33.7% CSS 0.8%
2.3 KB · 82 lines typescript
Raw Blame History
1/**2 * French prose is full of « 185 000 $ ». remark-math would treat those dollars as inline-math3 * delimiters. We apply Pandoc's rule before parsing: a single `$` opens math only if followed by4 * a non-space, closes only if preceded by a non-space and not followed by a digit. Every `$`5 * that cannot play either role is escaped (`\$`). `$$` blocks and code fences are left untouched.6 */7export function guardCurrency(md: string): string {8  let out = '';9  let i = 0;10  let inFence = false;11  let openIdx = -1; // index in `out` of the current unmatched opener12  const n = md.length;13  while (i < n) {14    const ch = md[i];15    // code fences16    if ((ch === '`' && md.startsWith('```', i)) || (ch === '~' && md.startsWith('~~~', i))) {17      inFence = !inFence;18      out += md.slice(i, i + 3);19      i += 3;20      continue;21    }22    if (inFence) {23      out += ch;24      i++;25      continue;26    }27    if (ch === '`') {28      // inline code: copy through the closing backtick29      const j = md.indexOf('`', i + 1);30      if (j > 0) {31        out += md.slice(i, j + 1);32        i = j + 1;33        continue;34      }35    }36    if (ch === '\\' && md[i + 1] === '$') {37      out += '\\$';38      i += 2;39      continue;40    }41    if (ch === '$' && md[i + 1] === '$') {42      // display math: copy through the closing $$43      const j = md.indexOf('$$', i + 2);44      if (j > 0) {45        out += md.slice(i, j + 2);46        i = j + 2;47        continue;48      }49    }50    if (ch === '$') {51      const prev = i > 0 ? md[i - 1] : ' ';52      const next = i + 1 < n ? md[i + 1] : ' ';53      const canOpen = !/\s/.test(next) && next !== '$';54      const canClose = !/\s/.test(prev) && !/\d/.test(next);55      if (openIdx < 0) {56        if (canOpen) {57          openIdx = out.length;58          out += '$';59        } else {60          out += '\\$';61        }62      } else if (canClose) {63        out += '$';64        openIdx = -1;65      } else {66        out += '\\$';67      }68      i++;69      continue;70    }71    if (ch === '\n' && openIdx >= 0 && md[i + 1] === '\n') {72      // paragraph break with an unmatched opener: it was a currency sign73      out = out.slice(0, openIdx) + '\\$' + out.slice(openIdx + 1);74      openIdx = -1;75    }76    out += ch;77    i++;78  }79  if (openIdx >= 0) out = out.slice(0, openIdx) + '\\$' + out.slice(openIdx + 1);80  return out;81}82