UNPKG

@gmod/cram

Version:

read CRAM files with pure Javascript

111 lines 5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const errors_ts_1 = require("../../errors.js"); const index_ts_1 = __importDefault(require("../slice/index.js")); const util_ts_1 = require("../util.js"); const compressionScheme_ts_1 = __importDefault(require("./compressionScheme.js")); const sectionParsers_ts_1 = require("../sectionParsers.js"); class CramContainer { file; filePosition; _headerResult; _compressionHeaderBlockResult; _compressionSchemeResult; constructor(file, filePosition) { this.file = file; this.filePosition = filePosition; } getHeader() { if (this._headerResult === undefined) { this._headerResult = this._fetchHeader(); this._headerResult.catch(() => { this._headerResult = undefined; }); } return this._headerResult; } _fetchHeader() { return this._readContainerHeader(this.filePosition); } async getCompressionHeaderBlock() { if (this._compressionHeaderBlockResult === undefined) { this._compressionHeaderBlockResult = this._fetchCompressionHeaderBlock(); this._compressionHeaderBlockResult.catch(() => { this._compressionHeaderBlockResult = undefined; }); } return this._compressionHeaderBlockResult; } async _fetchCompressionHeaderBlock() { 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 = (0, sectionParsers_ts_1.getSectionParsers)(majorVersion); const block = await this.getFirstBlock(); if (block.contentType !== 'COMPRESSION_HEADER') { throw new errors_ts_1.CramMalformedError(`invalid content type ${block.contentType} in compression header block`); } const content = (0, util_ts_1.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() { if (this._compressionSchemeResult === undefined) { this._compressionSchemeResult = this._fetchCompressionScheme(); this._compressionSchemeResult.catch(() => { this._compressionSchemeResult = undefined; }); } return this._compressionSchemeResult; } async _fetchCompressionScheme() { const header = await this.getCompressionHeaderBlock(); if (!header) { return undefined; } return new compressionScheme_ts_1.default(header.parsedContent); } getSlice(slicePosition, sliceSize) { // note: slicePosition is relative to the end of the container header // TODO: perhaps we should cache slices? return new index_ts_1.default(this, slicePosition, sliceSize); } async _readContainerHeader(position) { const { majorVersion } = await this.file.getDefinition(); const sectionParsers = (0, sectionParsers_ts_1.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 = (0, util_ts_1.parseItem)(bytes1, cramContainerHeader1.parser); const numLandmarksSize = (0, util_ts_1.itf8Size)(header1.numLandmarks); const bytes2 = await this.file.read(cramContainerHeader2.maxLength(header1.numLandmarks), position + header1._size - numLandmarksSize); const header2 = (0, util_ts_1.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, }; } } exports.default = CramContainer; //# sourceMappingURL=index.js.map