UNPKG

@gmod/cram

Version:

read CRAM files with pure Javascript

78 lines 3.6 kB
import { CramMalformedError } from "../../errors.js"; import CramSlice from "../slice/index.js"; import { itf8Size, parseItem, tinyMemoize } from "../util.js"; import CramContainerCompressionScheme from "./compressionScheme.js"; import { getSectionParsers } from "../sectionParsers.js"; export default class CramContainer { constructor(file, filePosition) { this.file = file; this.filePosition = filePosition; } getHeader() { return this._readContainerHeader(this.filePosition); } async getCompressionHeaderBlock() { const containerHeader = await this.getHeader(); // if there are no records in the container, there will be no compression // header if (!containerHeader.numRecords) { return null; } const { majorVersion } = await this.file.getDefinition(); const sectionParsers = getSectionParsers(majorVersion); const block = await this.getFirstBlock(); if (block.contentType !== 'COMPRESSION_HEADER') { throw new CramMalformedError(`invalid content type ${block.contentType} in compression header block`); } const content = parseItem(block.content, sectionParsers.cramCompressionHeader.parser, 0, block.contentPosition); return { ...block, parsedContent: content, }; } async getFirstBlock() { const containerHeader = await this.getHeader(); return this.file.readBlock(containerHeader._endPosition); } // parses the compression header data into a CramContainerCompressionScheme // object async getCompressionScheme() { const header = await this.getCompressionHeaderBlock(); if (!header) { return undefined; } return new CramContainerCompressionScheme(header.parsedContent); } getSlice(slicePosition, sliceSize) { // note: slicePosition is relative to the end of the container header // TODO: perhaps we should cache slices? return new CramSlice(this, slicePosition, sliceSize); } async _readContainerHeader(position) { const { majorVersion } = await this.file.getDefinition(); const sectionParsers = getSectionParsers(majorVersion); const { cramContainerHeader1, cramContainerHeader2 } = sectionParsers; // parse the container header. do it in 2 pieces because you cannot tell // how much to buffer until you read numLandmarks const bytes1 = await this.file.read(cramContainerHeader1.maxLength, position); const header1 = parseItem(bytes1, cramContainerHeader1.parser); const numLandmarksSize = itf8Size(header1.numLandmarks); const bytes2 = await this.file.read(cramContainerHeader2.maxLength(header1.numLandmarks), position + header1._size - numLandmarksSize); const header2 = parseItem(bytes2, cramContainerHeader2.parser); if (this.file.validateChecksums && header2.crc32 !== undefined) { await this.file.checkCrc32(position, header1._size + header2._size - numLandmarksSize - 4, header2.crc32, `container header beginning at position ${position}`); } return { ...header1, ...header2, _size: header1._size + header2._size - numLandmarksSize, _endPosition: header1._size + header2._size - numLandmarksSize + position, }; } } 'getHeader getCompressionHeaderBlock getCompressionScheme' .split(' ') .forEach(method => { tinyMemoize(CramContainer, method); }); //# sourceMappingURL=index.js.map