Floppy/dataslate

View on GitHub
src/FileLoader.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { parseBattlescribeXML as parseKillTeam2018 } from './parsers/KillTeam2018/BattlescribeParser'
import { parseBattlescribeXML as parseKillTeam2021 } from './parsers/KillTeam2021/BattlescribeParser'
import { parseBattlescribeXML as parse40k9e } from './parsers/WH40k9e/BattlescribeParser'
import JSZip from 'jszip'
import { DOMParserImpl } from 'xmldom-ts'
import * as XPath from 'xpath-ts'
import { Roster as Roster2018 } from './types/KillTeam2018'
import { Roster as Roster2021 } from './types/KillTeam2021'
import { Roster as Roster40k9e } from './types/WH40k9e'

// useNamespaces is NOT a React hook, so:
// eslint-disable-next-line
const xpSelect = XPath.useNamespaces({ bs: 'http://www.battlescribe.net/schema/rosterSchema' })

const unzip = async (file: string): Promise<string> => {
  if (file.charAt(0) !== 'P') {
    return file
  } else {
    const jszip = new JSZip()
    const zip = await jszip.loadAsync(file)
    return await zip.file(/[^/]+\.ros/)[0].async('string') // Get roster files that are in the root
  }
}

const parseFile = (file: string): Roster2018 | Roster2021 | Roster40k9e => {
  const doc = new DOMParserImpl().parseFromString(file)
  const gameSystemId = (xpSelect('/bs:roster/@gameSystemId', doc, true) as Node).nodeValue
  switch (gameSystemId) {
    case 'a467-5f42-d24c-6e5b':
      return parseKillTeam2018(doc) as Roster2018
    case '3b7e-7dab-f79f-2e74':
      return parseKillTeam2021(doc)
    case '28ec-711c-d87f-3aeb':
      return parse40k9e(doc)
    default:
      throw new Error('Unsupported game system!')
  }
}

export const loadFile = async (file: File): Promise<Roster2018 | Roster2021 | Roster40k9e> => {
  const reader = new FileReader()
  return await new Promise((resolve, reject) => {
    reader.onerror = () => {
      reader.abort()
      reject(new DOMException('Problem parsing input file.'))
    }
    reader.onloadend = async () => {
      const content = reader.result as string
      const file = await unzip(content)
      resolve(parseFile(file))
    }
    reader.readAsBinaryString(file)
  })
}

export const loadFiles = async (files: File[]): Promise<Roster2018 | Roster2021 | Roster40k9e> => {
  return await loadFile(files[0])
}