All files / src/utils utf8-to-jis-table.js

100% Statements 93/93
100% Branches 26/26
100% Functions 7/7
100% Lines 93/93

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 941x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 99x 99x 99x 6747x 2x 2x 6747x 210x 210x 210x 853x 853x 6745x 6535x 6535x 6747x 99x 1x 1x 1x 1x 1x 1x 1x 1x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 99x 24759x 24759x 1226x 1226x 24759x 1226x 1226x 24759x 6648x 6648x 6648x 24759x 15659x 24759x 24759x 99x 99x 99x 1x 1x 1x 2x 2x 2x 10x 10x 10x 2x 2x 1x 1x  
import { base64ToHex } from './text-decode-encode.util.js'
import UTF8_TO_JIS_TABLE from './utf8-to-jis-table.constants.js'
 
/** @param {string} x - hex string */
const xInt = x => parseInt(x, 16)
/** @param {string} x - base64 string */
const b64Int = x => xInt(base64ToHex(x))
 
/** @typedef {{[key: string]: string}} CompressedTable */
/** @typedef {{[utf8Value: number]: number}} Utf8ToJisTable */
 
/**
 * @param {CompressedTable} compressedTable - target table
 * @returns {Utf8ToJisTable} decompressed table
 */
function decompressUtf8ToJisTable (compressedTable) {
  /** @type {Record<number, number>} */
  const result = {}
  for (const [jisChar, compressedUtf8ValsStr] of Object.entries(compressedTable)) {
    const utf8Vals = decompressUtf8ValsStr(compressedUtf8ValsStr).split(',')
    let charIterator = xInt(jisChar)
    for (const utf8Value of utf8Vals) {
      if (utf8Value.includes('|')) {
        utf8Value.split('|').map(b64Int).forEach(key => { result[key] = charIterator })
        charIterator++
      } else if (utf8Value.includes('>')) {
        const kv = utf8Value.split('>')
        const init = b64Int(kv[0])
        for (let i = 0, e = xInt(kv[1]); i <= e; ++i) {
          result[init + i] = charIterator++
        }
      } else {
        result[b64Int(utf8Value)] = charIterator++
      }
    }
  }
  return result
}
 
/**
 * decompress each value in utf8-to-jis-table.constants.js object (e.g "4[p[S[A,C,M,Q,Y,U,c,s,k,0,8,B,D,P,T,b,X,j,z,r,7],WL,S[g,v,o,3,/,d,w,l,4],WC]]" to
 * "4pSA,4pSC,4pSM,4pSQ,4pSY,4pSU,4pSc,4pSs,4pSk,4pS0,4pS8,4pSB,4pSD,4pSP,4pST,4pSb,4pSX,4pSj,4pSz,4pSr,4pS7,4pWL,4pSg,4pSv,4pSo,4pS3,4pS/,4pSd,4pSw,4pSl,4pS4,4pWC")
 * @param {string} compressedVals - compressed utf8-to-jis-table.constants.js field value
 */
function decompressUtf8ValsStr (compressedVals) {
  /** @type {(amount: number) => (str: string) => string} */
  const join = amount => str => str.slice(1, -1).split('').reduce((val, ch, i) => val + (i % amount ? '' : ',') + ch)
 
  const commaSeparatedVals = [
    [/{/g, '[;'],
    [/}/g, ';]'],
    [/]([^\]])/g, '],$1'], // @ts-ignore
    [/[a-zA-z0-9+/]{2,3}\[/g, match => match.split('').join('[').slice(0, -1)], // @ts-ignore
    [/_[^_]+_/g, join(3)], // @ts-ignore
    [/#[^#]+#/g, join(2)], // @ts-ignore
    [/;[^;]+;/g, join(1)],    // @ts-ignore
  ].reduce((acc, args) => acc.replace(...args), compressedVals)
 
  let result = ''
  let prefix = ''
  let initPrefix = ''
  for (const char of commaSeparatedVals) {
    switch (char) {
      case '[':
        initPrefix = prefix
        break
      case ']':
        initPrefix = initPrefix.slice(0, -1)
        break
      case ',':
        result += prefix + ','
        prefix = initPrefix
        break
      default:
        prefix += char
    }
  }
  result += prefix
  return result
}
 
/** @type {(x:CompressedTable) => {Utf8ToJisTable: () => Utf8ToJisTable}} x  */
export const usingTable = (compressedTable) => {
  let generatedTable = null
  return {
    Utf8ToJisTable () {
      generatedTable ??= decompressUtf8ToJisTable(compressedTable)
      return generatedTable
    },
  }
}
 
export const getUtf8ToJisTable = usingTable(UTF8_TO_JIS_TABLE).Utf8ToJisTable