@gmod/cram 1.5.9 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/README.md +182 -172
- package/dist/craiIndex.d.ts +37 -0
- package/dist/craiIndex.js +196 -301
- package/dist/craiIndex.js.map +1 -0
- package/dist/cram-bundle.js +6 -15
- package/dist/cramFile/codecs/_base.d.ts +6 -0
- package/dist/cramFile/codecs/_base.js +44 -53
- package/dist/cramFile/codecs/_base.js.map +1 -0
- package/dist/cramFile/codecs/beta.d.ts +4 -0
- package/dist/cramFile/codecs/beta.js +38 -48
- package/dist/cramFile/codecs/beta.js.map +1 -0
- package/dist/cramFile/codecs/byteArrayLength.d.ts +8 -0
- package/dist/cramFile/codecs/byteArrayLength.js +58 -78
- package/dist/cramFile/codecs/byteArrayLength.js.map +1 -0
- package/dist/cramFile/codecs/byteArrayStop.d.ts +6 -0
- package/dist/cramFile/codecs/byteArrayStop.js +62 -76
- package/dist/cramFile/codecs/byteArrayStop.js.map +1 -0
- package/dist/cramFile/codecs/external.d.ts +7 -0
- package/dist/cramFile/codecs/external.js +63 -81
- package/dist/cramFile/codecs/external.js.map +1 -0
- package/dist/cramFile/codecs/gamma.d.ts +4 -0
- package/dist/cramFile/codecs/gamma.js +43 -56
- package/dist/cramFile/codecs/gamma.js.map +1 -0
- package/dist/cramFile/codecs/huffman.d.ts +17 -0
- package/dist/cramFile/codecs/huffman.js +126 -199
- package/dist/cramFile/codecs/huffman.js.map +1 -0
- package/dist/cramFile/codecs/index.d.ts +2 -0
- package/dist/cramFile/codecs/index.js +31 -38
- package/dist/cramFile/codecs/index.js.map +1 -0
- package/dist/cramFile/codecs/subexp.d.ts +4 -0
- package/dist/cramFile/codecs/subexp.js +51 -64
- package/dist/cramFile/codecs/subexp.js.map +1 -0
- package/dist/cramFile/constants.d.ts +36 -0
- package/dist/cramFile/constants.js +52 -50
- package/dist/cramFile/constants.js.map +1 -0
- package/dist/cramFile/container/compressionScheme.d.ts +23 -0
- package/dist/cramFile/container/compressionScheme.js +115 -153
- package/dist/cramFile/container/compressionScheme.js.map +1 -0
- package/dist/cramFile/container/index.d.ts +13 -0
- package/dist/cramFile/container/index.js +169 -283
- package/dist/cramFile/container/index.js.map +1 -0
- package/dist/cramFile/file.d.ts +63 -0
- package/dist/cramFile/file.js +440 -766
- package/dist/cramFile/file.js.map +1 -0
- package/dist/cramFile/index.d.ts +2 -0
- package/dist/cramFile/index.js +7 -4
- package/dist/cramFile/index.js.map +1 -0
- package/dist/cramFile/record.d.ts +79 -0
- package/dist/cramFile/record.js +253 -308
- package/dist/cramFile/record.js.map +1 -0
- package/dist/cramFile/sectionParsers.d.ts +18 -0
- package/dist/cramFile/sectionParsers.js +324 -362
- package/dist/cramFile/sectionParsers.js.map +1 -0
- package/dist/cramFile/slice/decodeRecord.d.ts +2 -0
- package/dist/cramFile/slice/decodeRecord.js +278 -298
- package/dist/cramFile/slice/decodeRecord.js.map +1 -0
- package/dist/cramFile/slice/index.d.ts +20 -0
- package/dist/cramFile/slice/index.js +488 -789
- package/dist/cramFile/slice/index.js.map +1 -0
- package/dist/cramFile/util.d.ts +5 -0
- package/dist/cramFile/util.js +158 -144
- package/dist/cramFile/util.js.map +1 -0
- package/dist/errors.d.ts +23 -0
- package/dist/errors.js +66 -103
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -0
- package/dist/indexedCramFile.d.ts +39 -0
- package/dist/indexedCramFile.js +213 -315
- package/dist/indexedCramFile.js.map +1 -0
- package/dist/io/bufferCache.d.ts +12 -0
- package/dist/io/bufferCache.js +108 -128
- package/dist/io/bufferCache.js.map +1 -0
- package/dist/io/index.d.ts +5 -0
- package/dist/io/index.js +29 -27
- package/dist/io/index.js.map +1 -0
- package/dist/io/localFile.d.ts +10 -0
- package/dist/io/localFile.js +105 -162
- package/dist/io/localFile.js.map +1 -0
- package/dist/io/remoteFile.d.ts +16 -0
- package/dist/io/remoteFile.js +137 -206
- package/dist/io/remoteFile.js.map +1 -0
- package/dist/rans/constants.d.ts +3 -0
- package/dist/rans/constants.js +6 -6
- package/dist/rans/constants.js.map +1 -0
- package/dist/rans/d04.d.ts +1 -0
- package/dist/rans/d04.js +70 -99
- package/dist/rans/d04.js.map +1 -0
- package/dist/rans/d14.d.ts +1 -0
- package/dist/rans/d14.js +55 -93
- package/dist/rans/d14.js.map +1 -0
- package/dist/rans/decoding.d.ts +30 -0
- package/dist/rans/decoding.js +112 -159
- package/dist/rans/decoding.js.map +1 -0
- package/dist/rans/frequencies.d.ts +2 -0
- package/dist/rans/frequencies.js +110 -119
- package/dist/rans/frequencies.js.map +1 -0
- package/dist/rans/index.d.ts +1 -0
- package/dist/rans/index.js +111 -174
- package/dist/rans/index.js.map +1 -0
- package/dist/sam.d.ts +1 -0
- package/dist/sam.js +16 -41
- package/dist/sam.js.map +1 -0
- package/dist/unzip-pako.d.ts +2 -0
- package/dist/unzip-pako.js +9 -0
- package/dist/unzip-pako.js.map +1 -0
- package/dist/unzip.d.ts +2 -0
- package/dist/unzip.js +6 -0
- package/dist/unzip.js.map +1 -0
- package/errors.js +66 -103
- package/esm/craiIndex.d.ts +37 -0
- package/esm/craiIndex.js +158 -0
- package/esm/craiIndex.js.map +1 -0
- package/esm/cramFile/codecs/_base.d.ts +6 -0
- package/esm/cramFile/codecs/_base.js +42 -0
- package/esm/cramFile/codecs/_base.js.map +1 -0
- package/esm/cramFile/codecs/beta.d.ts +4 -0
- package/esm/cramFile/codecs/beta.js +15 -0
- package/esm/cramFile/codecs/beta.js.map +1 -0
- package/esm/cramFile/codecs/byteArrayLength.d.ts +8 -0
- package/esm/cramFile/codecs/byteArrayLength.js +35 -0
- package/esm/cramFile/codecs/byteArrayLength.js.map +1 -0
- package/esm/cramFile/codecs/byteArrayStop.d.ts +6 -0
- package/esm/cramFile/codecs/byteArrayStop.js +40 -0
- package/esm/cramFile/codecs/byteArrayStop.js.map +1 -0
- package/esm/cramFile/codecs/external.d.ts +7 -0
- package/esm/cramFile/codecs/external.js +40 -0
- package/esm/cramFile/codecs/external.js.map +1 -0
- package/esm/cramFile/codecs/gamma.d.ts +4 -0
- package/esm/cramFile/codecs/gamma.js +20 -0
- package/esm/cramFile/codecs/gamma.js.map +1 -0
- package/esm/cramFile/codecs/huffman.d.ts +17 -0
- package/esm/cramFile/codecs/huffman.js +107 -0
- package/esm/cramFile/codecs/huffman.js.map +1 -0
- package/esm/cramFile/codecs/index.d.ts +2 -0
- package/esm/cramFile/codecs/index.js +30 -0
- package/esm/cramFile/codecs/index.js.map +1 -0
- package/esm/cramFile/codecs/subexp.d.ts +4 -0
- package/esm/cramFile/codecs/subexp.js +28 -0
- package/esm/cramFile/codecs/subexp.js.map +1 -0
- package/esm/cramFile/constants.d.ts +36 -0
- package/esm/cramFile/constants.js +51 -0
- package/esm/cramFile/constants.js.map +1 -0
- package/esm/cramFile/container/compressionScheme.d.ts +23 -0
- package/esm/cramFile/container/compressionScheme.js +123 -0
- package/esm/cramFile/container/compressionScheme.js.map +1 -0
- package/esm/cramFile/container/index.d.ts +13 -0
- package/esm/cramFile/container/index.js +84 -0
- package/esm/cramFile/container/index.js.map +1 -0
- package/esm/cramFile/file.d.ts +63 -0
- package/esm/cramFile/file.js +281 -0
- package/esm/cramFile/file.js.map +1 -0
- package/esm/cramFile/index.d.ts +2 -0
- package/esm/cramFile/index.js +3 -0
- package/esm/cramFile/index.js.map +1 -0
- package/esm/cramFile/record.d.ts +79 -0
- package/esm/cramFile/record.js +297 -0
- package/esm/cramFile/record.js.map +1 -0
- package/esm/cramFile/sectionParsers.d.ts +18 -0
- package/esm/cramFile/sectionParsers.js +347 -0
- package/esm/cramFile/sectionParsers.js.map +1 -0
- package/esm/cramFile/slice/decodeRecord.d.ts +2 -0
- package/esm/cramFile/slice/decodeRecord.js +299 -0
- package/esm/cramFile/slice/decodeRecord.js.map +1 -0
- package/esm/cramFile/slice/index.d.ts +20 -0
- package/esm/cramFile/slice/index.js +364 -0
- package/esm/cramFile/slice/index.js.map +1 -0
- package/esm/cramFile/util.d.ts +5 -0
- package/esm/cramFile/util.js +161 -0
- package/esm/cramFile/util.js.map +1 -0
- package/esm/errors.d.ts +23 -0
- package/esm/errors.js +24 -0
- package/esm/errors.js.map +1 -0
- package/esm/index.d.ts +4 -0
- package/esm/index.js +5 -0
- package/esm/index.js.map +1 -0
- package/esm/indexedCramFile.d.ts +39 -0
- package/esm/indexedCramFile.js +155 -0
- package/esm/indexedCramFile.js.map +1 -0
- package/esm/io/bufferCache.d.ts +12 -0
- package/esm/io/bufferCache.js +54 -0
- package/esm/io/bufferCache.js.map +1 -0
- package/esm/io/index.d.ts +5 -0
- package/esm/io/index.js +24 -0
- package/esm/io/index.js.map +1 -0
- package/esm/io/localFile.d.ts +10 -0
- package/esm/io/localFile.js +31 -0
- package/esm/io/localFile.js.map +1 -0
- package/esm/io/remoteFile.d.ts +16 -0
- package/esm/io/remoteFile.js +64 -0
- package/esm/io/remoteFile.js.map +1 -0
- package/esm/rans/constants.d.ts +3 -0
- package/esm/rans/constants.js +5 -0
- package/esm/rans/constants.js.map +1 -0
- package/esm/rans/d04.d.ts +1 -0
- package/esm/rans/d04.js +67 -0
- package/esm/rans/d04.js.map +1 -0
- package/esm/rans/d14.d.ts +1 -0
- package/esm/rans/d14.js +52 -0
- package/esm/rans/d14.js.map +1 -0
- package/esm/rans/decoding.d.ts +30 -0
- package/esm/rans/decoding.js +118 -0
- package/esm/rans/decoding.js.map +1 -0
- package/esm/rans/frequencies.d.ts +2 -0
- package/esm/rans/frequencies.js +110 -0
- package/esm/rans/frequencies.js.map +1 -0
- package/esm/rans/index.d.ts +1 -0
- package/esm/rans/index.js +195 -0
- package/esm/rans/index.js.map +1 -0
- package/esm/sam.d.ts +1 -0
- package/esm/sam.js +16 -0
- package/esm/sam.js.map +1 -0
- package/esm/unzip-pako.d.ts +2 -0
- package/esm/unzip-pako.js +5 -0
- package/esm/unzip-pako.js.map +1 -0
- package/esm/unzip.d.ts +2 -0
- package/esm/unzip.js +3 -0
- package/esm/unzip.js.map +1 -0
- package/package.json +38 -35
- package/src/craiIndex.js +180 -0
- package/src/cramFile/codecs/_base.js +49 -0
- package/src/cramFile/codecs/beta.js +23 -0
- package/src/cramFile/codecs/byteArrayLength.js +55 -0
- package/src/cramFile/codecs/byteArrayStop.js +50 -0
- package/src/cramFile/codecs/external.js +54 -0
- package/src/cramFile/codecs/gamma.js +30 -0
- package/src/cramFile/codecs/huffman.js +137 -0
- package/src/cramFile/codecs/index.js +38 -0
- package/src/cramFile/codecs/subexp.js +32 -0
- package/src/cramFile/constants.js +55 -0
- package/src/cramFile/container/compressionScheme.js +144 -0
- package/src/cramFile/container/index.js +119 -0
- package/src/cramFile/file.js +347 -0
- package/src/cramFile/index.js +3 -0
- package/src/cramFile/record.js +337 -0
- package/src/cramFile/sectionParsers.js +379 -0
- package/src/cramFile/slice/decodeRecord.js +362 -0
- package/src/cramFile/slice/index.js +497 -0
- package/src/cramFile/util.js +169 -0
- package/src/errors.js +22 -0
- package/src/index.js +5 -0
- package/src/indexedCramFile.js +191 -0
- package/src/io/bufferCache.js +66 -0
- package/src/io/index.js +26 -0
- package/src/io/localFile.js +35 -0
- package/src/io/remoteFile.js +71 -0
- package/src/rans/README.md +1 -0
- package/src/rans/constants.js +5 -0
- package/src/rans/d04.js +83 -0
- package/src/rans/d14.js +59 -0
- package/src/rans/decoding.js +141 -0
- package/src/rans/frequencies.js +121 -0
- package/src/rans/index.js +249 -0
- package/src/sam.js +15 -0
- package/src/unzip-pako.ts +5 -0
- package/src/unzip.ts +2 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import Long from 'long'
|
|
2
|
+
import { CramMalformedError, CramUnimplementedError } from '../../errors'
|
|
3
|
+
import CramRecord from '../record'
|
|
4
|
+
import Constants from '../constants'
|
|
5
|
+
/**
|
|
6
|
+
* given a Buffer, read a string up to the first null character
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
function readNullTerminatedStringFromBuffer(buffer) {
|
|
10
|
+
const zeroOffset = buffer.indexOf(0)
|
|
11
|
+
if (zeroOffset === -1) {
|
|
12
|
+
return buffer.toString('utf8')
|
|
13
|
+
}
|
|
14
|
+
return buffer.toString('utf8', 0, zeroOffset)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* parse a BAM tag's array value from a binary buffer
|
|
19
|
+
* @private
|
|
20
|
+
*/
|
|
21
|
+
function parseTagValueArray(buffer) {
|
|
22
|
+
const arrayType = String.fromCharCode(buffer[0])
|
|
23
|
+
const length = buffer.readInt32LE(1)
|
|
24
|
+
|
|
25
|
+
const schema = {
|
|
26
|
+
c: ['readInt8', 1],
|
|
27
|
+
C: ['readUInt8', 1],
|
|
28
|
+
s: ['readInt16LE', 2],
|
|
29
|
+
S: ['readUInt16LE', 2],
|
|
30
|
+
i: ['readInt32LE', 4],
|
|
31
|
+
I: ['readUInt32LE', 4],
|
|
32
|
+
f: ['readFloatLE', 4],
|
|
33
|
+
}[arrayType]
|
|
34
|
+
if (!schema) {
|
|
35
|
+
throw new CramMalformedError(`invalid tag value array type '${arrayType}'`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const [getMethod, itemSize] = schema
|
|
39
|
+
const array = new Array(length)
|
|
40
|
+
let offset = 5
|
|
41
|
+
for (let i = 0; i < length; i += 1) {
|
|
42
|
+
array[i] = buffer[getMethod](offset)
|
|
43
|
+
offset += itemSize
|
|
44
|
+
}
|
|
45
|
+
return array
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parseTagData(tagType, buffer) {
|
|
49
|
+
if (!buffer.readInt32LE) {
|
|
50
|
+
buffer = Buffer.from(buffer)
|
|
51
|
+
}
|
|
52
|
+
if (tagType === 'Z') {
|
|
53
|
+
return readNullTerminatedStringFromBuffer(buffer)
|
|
54
|
+
}
|
|
55
|
+
if (tagType === 'A') {
|
|
56
|
+
return String.fromCharCode(buffer[0])
|
|
57
|
+
}
|
|
58
|
+
if (tagType === 'I') {
|
|
59
|
+
const val = Long.fromBytesLE(buffer)
|
|
60
|
+
if (
|
|
61
|
+
val.greaterThan(Number.MAX_SAFE_INTEGER) ||
|
|
62
|
+
val.lessThan(Number.MIN_SAFE_INTEGER)
|
|
63
|
+
) {
|
|
64
|
+
throw new CramUnimplementedError('integer overflow')
|
|
65
|
+
}
|
|
66
|
+
return val.toNumber()
|
|
67
|
+
}
|
|
68
|
+
if (tagType === 'i') {
|
|
69
|
+
return buffer.readInt32LE(0)
|
|
70
|
+
}
|
|
71
|
+
if (tagType === 's') {
|
|
72
|
+
return buffer.readInt16LE(0)
|
|
73
|
+
}
|
|
74
|
+
if (tagType === 'S') {
|
|
75
|
+
return buffer.readUInt16LE(0)
|
|
76
|
+
}
|
|
77
|
+
if (tagType === 'c') {
|
|
78
|
+
return buffer.readInt8(0)
|
|
79
|
+
}
|
|
80
|
+
if (tagType === 'C') {
|
|
81
|
+
return buffer.readUInt8(0)
|
|
82
|
+
}
|
|
83
|
+
if (tagType === 'f') {
|
|
84
|
+
return buffer.readFloatLE(0)
|
|
85
|
+
}
|
|
86
|
+
if (tagType === 'H') {
|
|
87
|
+
const hex = readNullTerminatedStringFromBuffer(buffer)
|
|
88
|
+
return Number.parseInt(hex.replace(/^0x/, ''), 16)
|
|
89
|
+
}
|
|
90
|
+
if (tagType === 'B') {
|
|
91
|
+
return parseTagValueArray(buffer)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
throw new CramMalformedError(`Unrecognized tag type ${tagType}`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function decodeReadFeatures(
|
|
98
|
+
cramRecord,
|
|
99
|
+
readFeatureCount,
|
|
100
|
+
decodeDataSeries,
|
|
101
|
+
compressionScheme,
|
|
102
|
+
majorVersion,
|
|
103
|
+
) {
|
|
104
|
+
let currentReadPos = 0
|
|
105
|
+
let currentRefPos = cramRecord.alignmentStart - 1
|
|
106
|
+
const readFeatures = new Array(readFeatureCount)
|
|
107
|
+
|
|
108
|
+
function decodeRFData([type, dataSeriesName]) {
|
|
109
|
+
const data = decodeDataSeries(dataSeriesName)
|
|
110
|
+
if (type === 'character') {
|
|
111
|
+
return String.fromCharCode(data)
|
|
112
|
+
}
|
|
113
|
+
if (type === 'string') {
|
|
114
|
+
return data.toString('utf8')
|
|
115
|
+
}
|
|
116
|
+
if (type === 'numArray') {
|
|
117
|
+
return data.toArray()
|
|
118
|
+
}
|
|
119
|
+
// else if (type === 'number') {
|
|
120
|
+
// return data[0]
|
|
121
|
+
// }
|
|
122
|
+
return data
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (let i = 0; i < readFeatureCount; i += 1) {
|
|
126
|
+
const code = String.fromCharCode(decodeDataSeries('FC'))
|
|
127
|
+
|
|
128
|
+
const readPosDelta = decodeDataSeries('FP')
|
|
129
|
+
|
|
130
|
+
const readFeature = { code }
|
|
131
|
+
// map of operator name -> data series name
|
|
132
|
+
const data1Schema = {
|
|
133
|
+
B: ['character', 'BA'],
|
|
134
|
+
S: ['string', majorVersion > 1 ? 'SC' : 'IN'], // IN if cram v1, SC otherwise
|
|
135
|
+
X: ['number', 'BS'],
|
|
136
|
+
D: ['number', 'DL'],
|
|
137
|
+
I: ['string', 'IN'],
|
|
138
|
+
i: ['character', 'BA'],
|
|
139
|
+
b: ['string', 'BB'],
|
|
140
|
+
q: ['numArray', 'QQ'],
|
|
141
|
+
Q: ['number', 'QS'],
|
|
142
|
+
H: ['number', 'HC'],
|
|
143
|
+
P: ['number', 'PD'],
|
|
144
|
+
N: ['number', 'RS'],
|
|
145
|
+
}[code]
|
|
146
|
+
|
|
147
|
+
if (!data1Schema) {
|
|
148
|
+
throw new CramMalformedError(`invalid read feature code "${code}"`)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
readFeature.data = decodeRFData(data1Schema)
|
|
152
|
+
|
|
153
|
+
// if this is a tag with two data items, make the data an array and add the second item
|
|
154
|
+
const data2Schema = { B: ['number', 'QS'] }[code]
|
|
155
|
+
if (data2Schema) {
|
|
156
|
+
readFeature.data = [readFeature.data, decodeRFData(data2Schema)]
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
currentReadPos += readPosDelta
|
|
160
|
+
readFeature.pos = currentReadPos
|
|
161
|
+
|
|
162
|
+
currentRefPos += readPosDelta
|
|
163
|
+
readFeature.refPos = currentRefPos
|
|
164
|
+
|
|
165
|
+
// for gapping features, adjust the reference position for read features that follow
|
|
166
|
+
if (code === 'D' || code === 'N') {
|
|
167
|
+
currentRefPos += readFeature.data
|
|
168
|
+
} else if (code === 'I' || code === 'S') {
|
|
169
|
+
currentRefPos -= readFeature.data.length
|
|
170
|
+
} else if (code === 'i') {
|
|
171
|
+
currentRefPos -= 1
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
readFeatures[i] = readFeature
|
|
175
|
+
}
|
|
176
|
+
return readFeatures
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function thingToString(thing) {
|
|
180
|
+
if (thing instanceof Buffer) {
|
|
181
|
+
return readNullTerminatedStringFromBuffer(thing)
|
|
182
|
+
}
|
|
183
|
+
if (thing.length && thing.indexOf) {
|
|
184
|
+
// array-like
|
|
185
|
+
if (!thing[thing.length - 1]) {
|
|
186
|
+
// trim zeroes off the end if necessary
|
|
187
|
+
const termIndex = thing.indexOf(0)
|
|
188
|
+
return String.fromCharCode(...thing.slice(0, termIndex))
|
|
189
|
+
}
|
|
190
|
+
return String.fromCharCode(...thing)
|
|
191
|
+
}
|
|
192
|
+
return String(thing)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export default function decodeRecord(
|
|
196
|
+
slice,
|
|
197
|
+
decodeDataSeries,
|
|
198
|
+
compressionScheme,
|
|
199
|
+
sliceHeader,
|
|
200
|
+
coreDataBlock,
|
|
201
|
+
blocksByContentId,
|
|
202
|
+
cursors,
|
|
203
|
+
majorVersion,
|
|
204
|
+
recordNumber,
|
|
205
|
+
) {
|
|
206
|
+
const cramRecord = new CramRecord()
|
|
207
|
+
|
|
208
|
+
cramRecord.flags = decodeDataSeries('BF')
|
|
209
|
+
|
|
210
|
+
// note: the C data type of compressionFlags is byte in cram v1
|
|
211
|
+
// and int32 in cram v2+, but that does not matter for us here
|
|
212
|
+
// in javascript land.
|
|
213
|
+
cramRecord.cramFlags = decodeDataSeries('CF')
|
|
214
|
+
|
|
215
|
+
if (majorVersion > 1 && sliceHeader.content.refSeqId === -2) {
|
|
216
|
+
cramRecord.sequenceId = decodeDataSeries('RI')
|
|
217
|
+
} else {
|
|
218
|
+
cramRecord.sequenceId = sliceHeader.content.refSeqId
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
cramRecord.readLength = decodeDataSeries('RL')
|
|
222
|
+
// if APDelta, will calculate the true start in a second pass
|
|
223
|
+
cramRecord.alignmentStart = decodeDataSeries('AP')
|
|
224
|
+
if (compressionScheme.APdelta) {
|
|
225
|
+
cramRecord.alignmentStart += cursors.lastAlignmentStart
|
|
226
|
+
}
|
|
227
|
+
cursors.lastAlignmentStart = cramRecord.alignmentStart
|
|
228
|
+
cramRecord.readGroupId = decodeDataSeries('RG')
|
|
229
|
+
|
|
230
|
+
if (compressionScheme.readNamesIncluded) {
|
|
231
|
+
cramRecord.readName = thingToString(decodeDataSeries('RN'))
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// mate record
|
|
235
|
+
if (cramRecord.isDetached()) {
|
|
236
|
+
// note: the MF is a byte in 1.0, int32 in 2+, but once again this doesn't matter for javascript
|
|
237
|
+
const mate = {}
|
|
238
|
+
mate.flags = decodeDataSeries('MF')
|
|
239
|
+
if (!compressionScheme.readNamesIncluded) {
|
|
240
|
+
mate.readName = thingToString(decodeDataSeries('RN'))
|
|
241
|
+
cramRecord.readName = mate.readName
|
|
242
|
+
}
|
|
243
|
+
mate.sequenceId = decodeDataSeries('NS')
|
|
244
|
+
mate.alignmentStart = decodeDataSeries('NP')
|
|
245
|
+
if (mate.flags || mate.sequenceId > -1) {
|
|
246
|
+
cramRecord.mate = mate
|
|
247
|
+
}
|
|
248
|
+
cramRecord.templateSize = decodeDataSeries('TS')
|
|
249
|
+
|
|
250
|
+
// set mate unmapped if needed
|
|
251
|
+
if (mate.flags & Constants.CRAM_M_UNMAP) {
|
|
252
|
+
cramRecord.flags |= Constants.BAM_FMUNMAP
|
|
253
|
+
}
|
|
254
|
+
// set mate reversed if needed
|
|
255
|
+
if (mate.flags & Constants.CRAM_M_REVERSE) {
|
|
256
|
+
cramRecord.flags |= Constants.BAM_FMREVERSE
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// detachedCount++
|
|
260
|
+
} else if (cramRecord.hasMateDownStream()) {
|
|
261
|
+
cramRecord.mateRecordNumber = decodeDataSeries('NF') + recordNumber + 1
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// TODO: the aux tag parsing will have to be refactored if we want to support
|
|
265
|
+
// cram v1
|
|
266
|
+
const TLindex = decodeDataSeries('TL')
|
|
267
|
+
if (TLindex < 0) {
|
|
268
|
+
/* TODO: check nTL: TLindex >= compressionHeader.tagEncoding.size */
|
|
269
|
+
throw new CramMalformedError('invalid TL index')
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// TN = tag names
|
|
273
|
+
const TN = compressionScheme.getTagNames(TLindex)
|
|
274
|
+
const ntags = TN.length
|
|
275
|
+
|
|
276
|
+
for (let i = 0; i < ntags; i += 1) {
|
|
277
|
+
const tagId = TN[i]
|
|
278
|
+
const tagName = tagId.substr(0, 2)
|
|
279
|
+
const tagType = tagId.substr(2, 1)
|
|
280
|
+
|
|
281
|
+
const tagCodec = compressionScheme.getCodecForTag(tagId)
|
|
282
|
+
if (!tagCodec) {
|
|
283
|
+
throw new CramMalformedError(
|
|
284
|
+
`no codec defined for auxiliary tag ${tagId}`,
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
const tagData = tagCodec.decode(
|
|
288
|
+
slice,
|
|
289
|
+
coreDataBlock,
|
|
290
|
+
blocksByContentId,
|
|
291
|
+
cursors,
|
|
292
|
+
)
|
|
293
|
+
cramRecord.tags[tagName] = parseTagData(tagType, tagData)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!cramRecord.isSegmentUnmapped()) {
|
|
297
|
+
// reading read features
|
|
298
|
+
const /* int */ readFeatureCount = decodeDataSeries('FN')
|
|
299
|
+
if (readFeatureCount) {
|
|
300
|
+
cramRecord.readFeatures = decodeReadFeatures(
|
|
301
|
+
cramRecord,
|
|
302
|
+
readFeatureCount,
|
|
303
|
+
decodeDataSeries,
|
|
304
|
+
compressionScheme,
|
|
305
|
+
majorVersion,
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// compute the read's true span on the reference sequence, and the end coordinate of the alignment on the reference
|
|
310
|
+
let lengthOnRef = cramRecord.readLength
|
|
311
|
+
if (cramRecord.readFeatures) {
|
|
312
|
+
cramRecord.readFeatures.forEach(({ code, data }) => {
|
|
313
|
+
if (code === 'D' || code === 'N') {
|
|
314
|
+
lengthOnRef += data
|
|
315
|
+
} else if (code === 'I' || code === 'S') {
|
|
316
|
+
lengthOnRef -= data.length
|
|
317
|
+
} else if (code === 'i') {
|
|
318
|
+
lengthOnRef -= 1
|
|
319
|
+
}
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
if (Number.isNaN(lengthOnRef)) {
|
|
323
|
+
console.warn(
|
|
324
|
+
`${
|
|
325
|
+
cramRecord.readName ||
|
|
326
|
+
`${cramRecord.sequenceId}:${cramRecord.alignmentStart}`
|
|
327
|
+
} record has invalid read features`,
|
|
328
|
+
)
|
|
329
|
+
lengthOnRef = cramRecord.readLength
|
|
330
|
+
}
|
|
331
|
+
cramRecord.lengthOnRef = lengthOnRef
|
|
332
|
+
|
|
333
|
+
// mapping quality
|
|
334
|
+
cramRecord.mappingQuality = decodeDataSeries('MQ')
|
|
335
|
+
if (cramRecord.isPreservingQualityScores()) {
|
|
336
|
+
const bases = new Array(cramRecord.readLength)
|
|
337
|
+
for (let i = 0; i < bases.length; i += 1) {
|
|
338
|
+
bases[i] = decodeDataSeries('QS')
|
|
339
|
+
}
|
|
340
|
+
cramRecord.qualityScores = bases
|
|
341
|
+
}
|
|
342
|
+
} else if (cramRecord.isUnknownBases()) {
|
|
343
|
+
cramRecord.readBases = null
|
|
344
|
+
cramRecord.qualityScores = null
|
|
345
|
+
} else {
|
|
346
|
+
const bases = new Array(cramRecord.readLength)
|
|
347
|
+
for (let i = 0; i < bases.length; i += 1) {
|
|
348
|
+
bases[i] = decodeDataSeries('BA')
|
|
349
|
+
}
|
|
350
|
+
cramRecord.readBases = String.fromCharCode(...bases)
|
|
351
|
+
|
|
352
|
+
if (cramRecord.isPreservingQualityScores()) {
|
|
353
|
+
for (let i = 0; i < bases.length; i += 1) {
|
|
354
|
+
bases[i] = decodeDataSeries('QS')
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
cramRecord.qualityScores = bases
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return cramRecord
|
|
362
|
+
}
|