ElectronicBabylonianLiterature/ebl-frontend

View on GitHub
src/corpus/application/dtos.ts

Summary

Maintainability
B
4 hrs
Test Coverage
B
87%
import _ from 'lodash'

import createReference from 'bibliography/application/createReference'
import serializeReference from 'bibliography/application/serializeReference'
import { AlignmentToken, ChapterAlignment } from 'corpus/domain/alignment'
import {
  Chapter,
  ChapterDisplay,
  DictionaryLineDisplay,
  LineDisplay,
  LineVariantDisplay,
} from 'corpus/domain/chapter'
import { ChapterLemmatization } from 'corpus/domain/lemmatization'
import {
  createLine,
  createManuscriptLine,
  createVariant,
  EditStatus,
  Line,
  LineVariant,
} from 'corpus/domain/line'
import { LineDetails, ManuscriptLineDisplay } from 'corpus/domain/line-details'
import {
  Manuscript,
  ManuscriptTypes,
  OldSiglum,
} from 'corpus/domain/manuscript'
import { ReferenceDto } from 'bibliography/domain/referenceDto'
import { PeriodModifiers, Periods } from 'common/period'
import { Provenances } from 'corpus/domain/provenance'
import SiglumAndTransliteration from 'corpus/domain/SiglumAndTransliteration'
import {
  ChapterListing,
  createChapter,
  createText,
  Text,
} from 'corpus/domain/text'
import { museumNumberToString } from 'fragmentarium/domain/MuseumNumber'
import { createJoins } from 'fragmentarium/infrastructure/FragmentRepository'
import {
  createTransliteration,
  fromTransliterationLineDto,
} from 'transliteration/application/dtos'
import { EmptyLine } from 'transliteration/domain/line'
import { TextLine } from 'transliteration/domain/text-line'
import TranslationLine, {
  Extent,
} from 'transliteration/domain/translation-line'
import { MarkupPart } from 'transliteration/domain/markup'
import { Token } from 'transliteration/domain/token'
import { NoteLine, NoteLineDto } from 'transliteration/domain/note-line'
import { ParallelLineDto } from 'transliteration/domain/parallel-line'
import Reference from 'bibliography/domain/Reference'
import { ChapterInfoLine } from 'corpus/domain/ChapterInfo'
import { createResearchProject } from 'research-projects/researchProject'

export type LineVariantDisplayDto = Pick<
  LineVariantDisplay,
  'originalIndex' | 'reconstruction' | 'manuscripts' | 'intertext'
> & {
  note: Omit<NoteLineDto, 'type'> | null
  parallelLines: ParallelLineDto[]
}

export type OldLineNumberDto = {
  number: string
  reference: ReferenceDto
}

export type LineDisplayDto = Pick<
  LineDisplay,
  | 'number'
  | 'isSecondLineOfParallelism'
  | 'isBeginningOfSection'
  | 'originalIndex'
> & {
  translation: {
    language: string
    extent: Extent | null
    parts: MarkupPart[]
    content: Token[]
  }[]
  variants: LineVariantDisplayDto[]
  oldLineNumbers: OldLineNumberDto[]
}

export type ChapterDisplayDto = Pick<
  ChapterDisplay,
  | 'id'
  | 'textHasDoi'
  | 'textName'
  | 'isSingleStage'
  | 'title'
  | 'record'
  | 'atf'
> & { lines: LineDisplayDto[] }

export function fromSiglumAndTransliterationDto(
  dto
): SiglumAndTransliteration[] {
  return dto.map(({ siglum, text }) => ({
    siglum,
    text: createTransliteration(text),
  }))
}

export function fromChapterListingDto(chapterListingDto): ChapterListing {
  return {
    ...chapterListingDto,
    uncertainFragments: chapterListingDto.uncertainFragments.map(
      ({ museumNumber }) => ({
        museumNumber: museumNumberToString(museumNumber),
      })
    ),
  }
}

export function fromDto(textDto): Text {
  return createText({
    ...textDto,
    references: textDto.references.map(createReference),
    chapters: textDto.chapters.map(fromChapterListingDto),
    projects: textDto.projects?.map(createResearchProject) || [],
  })
}

export function fromChapterDto(chapterDto): Chapter {
  return createChapter({
    ...chapterDto,
    manuscripts: chapterDto.manuscripts.map(fromManuscriptDto),
    lines: chapterDto.lines.map(fromLineDto),
  })
}

export interface OldSiglumDto {
  readonly siglum: string
  readonly reference: ReferenceDto
}

export function createOldSiglum(oldSiglumDto: OldSiglumDto): OldSiglum {
  return new OldSiglum(
    oldSiglumDto.siglum,
    createReference(oldSiglumDto.reference)
  )
}

export function fromManuscriptDto(manuscriptDto): Manuscript {
  return new Manuscript(
    manuscriptDto.id,
    manuscriptDto.siglumDisambiguator,
    manuscriptDto.oldSigla.map(createOldSiglum),
    manuscriptDto.museumNumber,
    manuscriptDto.accession,
    PeriodModifiers[manuscriptDto.periodModifier],
    Periods[manuscriptDto.period],
    Provenances[manuscriptDto.provenance],
    ManuscriptTypes[manuscriptDto.type],
    manuscriptDto.notes,
    manuscriptDto.colophon,
    manuscriptDto.unplacedLines,
    manuscriptDto.references.map(createReference),
    createJoins(manuscriptDto.joins),
    manuscriptDto.isInFragmentarium
  )
}

function fromLineVariantDto(variantDto): LineVariant {
  return createVariant({
    ...variantDto,
    manuscripts: variantDto.manuscripts.map((manuscriptLineDto) =>
      createManuscriptLine({
        manuscriptId: manuscriptLineDto['manuscriptId'],
        labels: manuscriptLineDto['labels'],
        number: manuscriptLineDto['number'],
        atf: manuscriptLineDto['atf'],
        atfTokens: manuscriptLineDto['atfTokens'],
        omittedWords: manuscriptLineDto['omittedWords'],
      })
    ),
  })
}

export function fromMatchingColophonLinesDto(
  matchingColophonLinesDto: Record<string, unknown>
): Record<string, readonly TextLine[]> {
  return Object.entries(matchingColophonLinesDto).reduce(
    (previousValue, colophon: any) => ({
      ...previousValue,
      [colophon[0]]: colophon[1].map((textLine) => new TextLine(textLine)),
    }),
    {}
  )
}

export function fromLineDto(lineDto): Line {
  return createLine({
    ...lineDto,
    variants: lineDto.variants?.map(fromLineVariantDto) ?? [],
    status: EditStatus.CLEAN,
  })
}
export function fromMatchingLineDto(lineDto): ChapterInfoLine {
  return {
    ...createLine({
      ...lineDto,
      variants: lineDto.variants?.map(fromLineVariantDto) ?? [],
      status: EditStatus.CLEAN,
    }),
    translation: lineDto.translation.map(
      (translation) => new TranslationLine(translation)
    ),
  }
}

function fromManuscriptLineDisplay(manuscript): ManuscriptLineDisplay {
  return new ManuscriptLineDisplay(
    Provenances[manuscript.provenance],
    PeriodModifiers[manuscript.periodModifier],
    Periods[manuscript.period],
    ManuscriptTypes[manuscript.type],
    manuscript.siglumDisambiguator,
    manuscript.oldSigla.map(createOldSiglum),
    manuscript.labels,
    (fromTransliterationLineDto(manuscript.line) as unknown) as
      | TextLine
      | EmptyLine,
    manuscript.paratext.map(fromTransliterationLineDto),
    manuscript.references.map(createReference),
    createJoins(manuscript.joins),
    manuscript.museumNumber,
    manuscript.isInFragmentarium,
    manuscript.accession,
    manuscript.omittedWords
  )
}

function fromLineVariantDisplay(variant): LineVariantDisplay {
  return {
    ...variant,
    note: variant.note && new NoteLine(variant.note),
    manuscripts: variant.manuscripts.map((manuscript) =>
      fromManuscriptLineDisplay(manuscript)
    ),
  }
}

export function fromLineDetailsDto(line, activeVariant: number): LineDetails {
  return new LineDetails(
    line.variants.map((variant) => fromLineVariantDisplay(variant)),
    activeVariant
  )
}

function toName(record: { name: string }): string {
  return record.name
}

function serializeOldSiglum(
  oldSiglum: OldSiglum
): {
  siglum: string
  reference: Pick<Reference, 'type' | 'pages' | 'notes' | 'linesCited'> & {
    id: string
  }
} {
  return {
    siglum: oldSiglum.siglum,
    reference: serializeReference(oldSiglum.reference),
  }
}

function toManuscriptDto(manuscript: Manuscript) {
  return {
    id: manuscript.id,
    siglumDisambiguator: manuscript.siglumDisambiguator,
    oldSigla: manuscript.oldSigla.map(serializeOldSiglum),
    museumNumber: manuscript.museumNumber,
    accession: manuscript.accession,
    provenance: toName(manuscript.provenance),
    periodModifier: toName(manuscript.periodModifier),
    period: toName(manuscript.period),
    type: toName(manuscript.type),
    notes: manuscript.notes,
    colophon: manuscript.colophon,
    unplacedLines: manuscript.unplacedLines,
    references: manuscript.references.map(serializeReference),
  } as const
}

function toLineDto(line: Line) {
  return {
    ..._.omit(line, 'status'),
    variants: line.variants.map((variant) => ({
      reconstruction: variant.reconstruction,
      intertext: variant.intertext,
      manuscripts: variant.manuscripts.map((manuscript) => ({
        manuscriptId: manuscript.manuscriptId,
        labels: manuscript.labels,
        number: manuscript.number,
        atf: manuscript.atf,
        omittedWords: manuscript.omittedWords,
      })),
    })),
  } as const
}

function toAlignmentTokenDto(token: AlignmentToken) {
  return token.isAlignable
    ? ({
        value: token.value,
        alignment: token.alignment,
        variant: token.variant?.value ?? '',
        type: token.variant?.type ?? '',
        language: token.variant?.language ?? '',
      } as const)
    : ({
        value: token.value,
      } as const)
}

export function toAlignmentDto(
  alignment: ChapterAlignment
): Record<string, unknown> {
  return {
    alignment: alignment.lines.map((line) =>
      line.map((variant) =>
        variant.map((manuscript) => ({
          alignment: manuscript.alignment.map(toAlignmentTokenDto),
          omittedWords: manuscript.omittedWords,
        }))
      )
    ),
  } as const
}

export function toLemmatizationDto(lemmatization: ChapterLemmatization) {
  return {
    lemmatization: lemmatization.map((line) =>
      line.map((variant) => ({
        reconstruction: variant[0].map((token) => token.toDto()),
        manuscripts: variant[1].map((line) =>
          line.map((token) => token.toDto())
        ),
      }))
    ),
  } as const
}

export function toManuscriptsDto(
  manuscripts: readonly Manuscript[],
  uncertainChapters: readonly string[]
): Record<string, unknown> {
  return {
    manuscripts: manuscripts.map(toManuscriptDto),
    uncertainFragments: uncertainChapters,
  } as const
}

export const toLinesDto = (lines: readonly Line[]) =>
  ({
    edited: _(lines)
      .map((line, index) =>
        line.status === EditStatus.EDITED
          ? { line: toLineDto(line), index: index }
          : null
      )
      .reject(_.isNil)
      .value(),
    deleted: _(lines)
      .map((line, index) => (line.status === EditStatus.DELETED ? index : null))
      .reject(_.isNil)
      .value(),
    new: _(lines)
      .filter((line) => line.status === EditStatus.NEW)
      .map(toLineDto)
      .value(),
  } as const)

export function fromDictionaryLineDto(dto): DictionaryLineDisplay[] {
  return { ...dto, lineDetails: fromLineDetailsDto(dto.lineDetails, 0) }
}