ElectronicBabylonianLiterature/ebl-frontend

View on GitHub
src/signs/domain/Sign.ts

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
import produce, { immerable } from 'immer'
import { compareCleanedAkkadianString } from 'dictionary/domain/compareAkkadianStrings'
import { subscriptNumbers } from 'transliteration/application/SubIndex'
import MuseumNumber from 'fragmentarium/domain/MuseumNumber'

export interface Logogram {
  logogram: string
  atf: string
  wordId: readonly string[]
  schrammLogogramme: string
  unicode: string
}
export interface OrderedSign {
  readonly name: string
  readonly unicode: readonly number[]
  readonly mzl: string | null
}
export interface UnicodeAtf {
  readonly unicode: number[]
}
export interface Fossey {
  page: number
  number: number
  reference: string
  newEdition: string
  secondaryLiterature: string
  cdliNumber: string
  museumNumber: MuseumNumber | null
  externalProject: string
  notes: string
  date: string
  transliteration: string
  sign: string
}

export interface SignListRecord {
  name: string
  number: string
}

export interface SignQuery {
  value?: string | null
  subIndex?: number | null
  listsName?: string | null
  listsNumber?: string | null
  isIncludeHomophones?: boolean | null
  isComposite?: boolean | null
  wordId?: string | null
}
export interface SignDto {
  name: string
  lists: readonly SignListRecord[]
  values: readonly { value: string; subIndex?: number | undefined }[]
  fossey: readonly Fossey[]
  logograms: readonly Logogram[]
  mesZl: string
  LaBaSi: string
  unicode: readonly number[]
}
export class Value {
  readonly value: string
  readonly subIndex: number | undefined

  constructor(value: string, subIndex: number | undefined = undefined) {
    this.value = value
    this.subIndex = subIndex
  }
  get displaySubIndex(): string {
    if (this.subIndex === undefined) {
      return '~x~'
    } else if (this.subIndex === 1) {
      return ''
    } else {
      return this.subIndex
        .toString()
        .split('')
        .map((digit) => subscriptNumbers.get(digit))
        .join('')
    }
  }
}

export default class Sign {
  [immerable] = true
  readonly name: string
  readonly lists: readonly SignListRecord[]
  readonly values: readonly Value[]
  readonly logograms: readonly Logogram[]
  readonly fossey: readonly Fossey[]
  readonly mesZl: string
  readonly LaBaSi: string
  readonly unicode: readonly number[]

  constructor({
    name,
    lists,
    values,
    logograms,
    fossey,
    mesZl,
    LaBaSi,
    unicode,
  }: {
    name: string
    lists: readonly SignListRecord[]
    values: readonly Value[]
    logograms: readonly Logogram[]
    fossey: readonly Fossey[]
    mesZl: string
    LaBaSi: string
    unicode: readonly number[]
  }) {
    this.name = name
    this.lists = lists
    this.values = values
    this.logograms = logograms
    this.fossey = fossey
    this.mesZl = mesZl
    this.LaBaSi = LaBaSi
    this.unicode = unicode
  }

  private sortedValues(): readonly Value[] {
    return produce(this.values, (draftValues) => {
      draftValues.sort((value1, value2) =>
        compareCleanedAkkadianString(value1.value, value2.value)
      )
    })
  }
  get displayValuesMarkdown(): string {
    return this.sortedValues()
      .map((value) => `*${value.value}*${value.displaySubIndex}`)
      .join(', ')
  }

  get displayCuneiformSigns(): string {
    return this.unicode.map((unicode) => String.fromCodePoint(unicode)).join('')
  }
  get displaySignName(): string {
    return this.name.replace(/\|/g, '')
  }

  static fromDto(signDto: SignDto): Sign {
    const sign = produce(signDto, (draftSignDto) => {
      draftSignDto.values = draftSignDto.values.map(
        (value) => new Value(value.value, value.subIndex)
      )
    }) as SignDtoWithValues
    return new Sign(sign)
  }
}

interface SignDtoWithValues extends Omit<SignDto, 'values'> {
  values: readonly Value[]
}