@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.
Files changed (258) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +182 -172
  3. package/dist/craiIndex.d.ts +37 -0
  4. package/dist/craiIndex.js +196 -301
  5. package/dist/craiIndex.js.map +1 -0
  6. package/dist/cram-bundle.js +6 -15
  7. package/dist/cramFile/codecs/_base.d.ts +6 -0
  8. package/dist/cramFile/codecs/_base.js +44 -53
  9. package/dist/cramFile/codecs/_base.js.map +1 -0
  10. package/dist/cramFile/codecs/beta.d.ts +4 -0
  11. package/dist/cramFile/codecs/beta.js +38 -48
  12. package/dist/cramFile/codecs/beta.js.map +1 -0
  13. package/dist/cramFile/codecs/byteArrayLength.d.ts +8 -0
  14. package/dist/cramFile/codecs/byteArrayLength.js +58 -78
  15. package/dist/cramFile/codecs/byteArrayLength.js.map +1 -0
  16. package/dist/cramFile/codecs/byteArrayStop.d.ts +6 -0
  17. package/dist/cramFile/codecs/byteArrayStop.js +62 -76
  18. package/dist/cramFile/codecs/byteArrayStop.js.map +1 -0
  19. package/dist/cramFile/codecs/external.d.ts +7 -0
  20. package/dist/cramFile/codecs/external.js +63 -81
  21. package/dist/cramFile/codecs/external.js.map +1 -0
  22. package/dist/cramFile/codecs/gamma.d.ts +4 -0
  23. package/dist/cramFile/codecs/gamma.js +43 -56
  24. package/dist/cramFile/codecs/gamma.js.map +1 -0
  25. package/dist/cramFile/codecs/huffman.d.ts +17 -0
  26. package/dist/cramFile/codecs/huffman.js +126 -199
  27. package/dist/cramFile/codecs/huffman.js.map +1 -0
  28. package/dist/cramFile/codecs/index.d.ts +2 -0
  29. package/dist/cramFile/codecs/index.js +31 -38
  30. package/dist/cramFile/codecs/index.js.map +1 -0
  31. package/dist/cramFile/codecs/subexp.d.ts +4 -0
  32. package/dist/cramFile/codecs/subexp.js +51 -64
  33. package/dist/cramFile/codecs/subexp.js.map +1 -0
  34. package/dist/cramFile/constants.d.ts +36 -0
  35. package/dist/cramFile/constants.js +52 -50
  36. package/dist/cramFile/constants.js.map +1 -0
  37. package/dist/cramFile/container/compressionScheme.d.ts +23 -0
  38. package/dist/cramFile/container/compressionScheme.js +115 -153
  39. package/dist/cramFile/container/compressionScheme.js.map +1 -0
  40. package/dist/cramFile/container/index.d.ts +13 -0
  41. package/dist/cramFile/container/index.js +169 -283
  42. package/dist/cramFile/container/index.js.map +1 -0
  43. package/dist/cramFile/file.d.ts +63 -0
  44. package/dist/cramFile/file.js +440 -766
  45. package/dist/cramFile/file.js.map +1 -0
  46. package/dist/cramFile/index.d.ts +2 -0
  47. package/dist/cramFile/index.js +7 -4
  48. package/dist/cramFile/index.js.map +1 -0
  49. package/dist/cramFile/record.d.ts +79 -0
  50. package/dist/cramFile/record.js +253 -308
  51. package/dist/cramFile/record.js.map +1 -0
  52. package/dist/cramFile/sectionParsers.d.ts +18 -0
  53. package/dist/cramFile/sectionParsers.js +324 -362
  54. package/dist/cramFile/sectionParsers.js.map +1 -0
  55. package/dist/cramFile/slice/decodeRecord.d.ts +2 -0
  56. package/dist/cramFile/slice/decodeRecord.js +278 -298
  57. package/dist/cramFile/slice/decodeRecord.js.map +1 -0
  58. package/dist/cramFile/slice/index.d.ts +20 -0
  59. package/dist/cramFile/slice/index.js +488 -789
  60. package/dist/cramFile/slice/index.js.map +1 -0
  61. package/dist/cramFile/util.d.ts +5 -0
  62. package/dist/cramFile/util.js +158 -144
  63. package/dist/cramFile/util.js.map +1 -0
  64. package/dist/errors.d.ts +23 -0
  65. package/dist/errors.js +66 -103
  66. package/dist/errors.js.map +1 -0
  67. package/dist/index.d.ts +4 -0
  68. package/dist/index.js +12 -12
  69. package/dist/index.js.map +1 -0
  70. package/dist/indexedCramFile.d.ts +39 -0
  71. package/dist/indexedCramFile.js +213 -315
  72. package/dist/indexedCramFile.js.map +1 -0
  73. package/dist/io/bufferCache.d.ts +12 -0
  74. package/dist/io/bufferCache.js +108 -128
  75. package/dist/io/bufferCache.js.map +1 -0
  76. package/dist/io/index.d.ts +5 -0
  77. package/dist/io/index.js +29 -27
  78. package/dist/io/index.js.map +1 -0
  79. package/dist/io/localFile.d.ts +10 -0
  80. package/dist/io/localFile.js +105 -162
  81. package/dist/io/localFile.js.map +1 -0
  82. package/dist/io/remoteFile.d.ts +16 -0
  83. package/dist/io/remoteFile.js +137 -206
  84. package/dist/io/remoteFile.js.map +1 -0
  85. package/dist/rans/constants.d.ts +3 -0
  86. package/dist/rans/constants.js +6 -6
  87. package/dist/rans/constants.js.map +1 -0
  88. package/dist/rans/d04.d.ts +1 -0
  89. package/dist/rans/d04.js +70 -99
  90. package/dist/rans/d04.js.map +1 -0
  91. package/dist/rans/d14.d.ts +1 -0
  92. package/dist/rans/d14.js +55 -93
  93. package/dist/rans/d14.js.map +1 -0
  94. package/dist/rans/decoding.d.ts +30 -0
  95. package/dist/rans/decoding.js +112 -159
  96. package/dist/rans/decoding.js.map +1 -0
  97. package/dist/rans/frequencies.d.ts +2 -0
  98. package/dist/rans/frequencies.js +110 -119
  99. package/dist/rans/frequencies.js.map +1 -0
  100. package/dist/rans/index.d.ts +1 -0
  101. package/dist/rans/index.js +111 -174
  102. package/dist/rans/index.js.map +1 -0
  103. package/dist/sam.d.ts +1 -0
  104. package/dist/sam.js +16 -41
  105. package/dist/sam.js.map +1 -0
  106. package/dist/unzip-pako.d.ts +2 -0
  107. package/dist/unzip-pako.js +9 -0
  108. package/dist/unzip-pako.js.map +1 -0
  109. package/dist/unzip.d.ts +2 -0
  110. package/dist/unzip.js +6 -0
  111. package/dist/unzip.js.map +1 -0
  112. package/errors.js +66 -103
  113. package/esm/craiIndex.d.ts +37 -0
  114. package/esm/craiIndex.js +158 -0
  115. package/esm/craiIndex.js.map +1 -0
  116. package/esm/cramFile/codecs/_base.d.ts +6 -0
  117. package/esm/cramFile/codecs/_base.js +42 -0
  118. package/esm/cramFile/codecs/_base.js.map +1 -0
  119. package/esm/cramFile/codecs/beta.d.ts +4 -0
  120. package/esm/cramFile/codecs/beta.js +15 -0
  121. package/esm/cramFile/codecs/beta.js.map +1 -0
  122. package/esm/cramFile/codecs/byteArrayLength.d.ts +8 -0
  123. package/esm/cramFile/codecs/byteArrayLength.js +35 -0
  124. package/esm/cramFile/codecs/byteArrayLength.js.map +1 -0
  125. package/esm/cramFile/codecs/byteArrayStop.d.ts +6 -0
  126. package/esm/cramFile/codecs/byteArrayStop.js +40 -0
  127. package/esm/cramFile/codecs/byteArrayStop.js.map +1 -0
  128. package/esm/cramFile/codecs/external.d.ts +7 -0
  129. package/esm/cramFile/codecs/external.js +40 -0
  130. package/esm/cramFile/codecs/external.js.map +1 -0
  131. package/esm/cramFile/codecs/gamma.d.ts +4 -0
  132. package/esm/cramFile/codecs/gamma.js +20 -0
  133. package/esm/cramFile/codecs/gamma.js.map +1 -0
  134. package/esm/cramFile/codecs/huffman.d.ts +17 -0
  135. package/esm/cramFile/codecs/huffman.js +107 -0
  136. package/esm/cramFile/codecs/huffman.js.map +1 -0
  137. package/esm/cramFile/codecs/index.d.ts +2 -0
  138. package/esm/cramFile/codecs/index.js +30 -0
  139. package/esm/cramFile/codecs/index.js.map +1 -0
  140. package/esm/cramFile/codecs/subexp.d.ts +4 -0
  141. package/esm/cramFile/codecs/subexp.js +28 -0
  142. package/esm/cramFile/codecs/subexp.js.map +1 -0
  143. package/esm/cramFile/constants.d.ts +36 -0
  144. package/esm/cramFile/constants.js +51 -0
  145. package/esm/cramFile/constants.js.map +1 -0
  146. package/esm/cramFile/container/compressionScheme.d.ts +23 -0
  147. package/esm/cramFile/container/compressionScheme.js +123 -0
  148. package/esm/cramFile/container/compressionScheme.js.map +1 -0
  149. package/esm/cramFile/container/index.d.ts +13 -0
  150. package/esm/cramFile/container/index.js +84 -0
  151. package/esm/cramFile/container/index.js.map +1 -0
  152. package/esm/cramFile/file.d.ts +63 -0
  153. package/esm/cramFile/file.js +281 -0
  154. package/esm/cramFile/file.js.map +1 -0
  155. package/esm/cramFile/index.d.ts +2 -0
  156. package/esm/cramFile/index.js +3 -0
  157. package/esm/cramFile/index.js.map +1 -0
  158. package/esm/cramFile/record.d.ts +79 -0
  159. package/esm/cramFile/record.js +297 -0
  160. package/esm/cramFile/record.js.map +1 -0
  161. package/esm/cramFile/sectionParsers.d.ts +18 -0
  162. package/esm/cramFile/sectionParsers.js +347 -0
  163. package/esm/cramFile/sectionParsers.js.map +1 -0
  164. package/esm/cramFile/slice/decodeRecord.d.ts +2 -0
  165. package/esm/cramFile/slice/decodeRecord.js +299 -0
  166. package/esm/cramFile/slice/decodeRecord.js.map +1 -0
  167. package/esm/cramFile/slice/index.d.ts +20 -0
  168. package/esm/cramFile/slice/index.js +364 -0
  169. package/esm/cramFile/slice/index.js.map +1 -0
  170. package/esm/cramFile/util.d.ts +5 -0
  171. package/esm/cramFile/util.js +161 -0
  172. package/esm/cramFile/util.js.map +1 -0
  173. package/esm/errors.d.ts +23 -0
  174. package/esm/errors.js +24 -0
  175. package/esm/errors.js.map +1 -0
  176. package/esm/index.d.ts +4 -0
  177. package/esm/index.js +5 -0
  178. package/esm/index.js.map +1 -0
  179. package/esm/indexedCramFile.d.ts +39 -0
  180. package/esm/indexedCramFile.js +155 -0
  181. package/esm/indexedCramFile.js.map +1 -0
  182. package/esm/io/bufferCache.d.ts +12 -0
  183. package/esm/io/bufferCache.js +54 -0
  184. package/esm/io/bufferCache.js.map +1 -0
  185. package/esm/io/index.d.ts +5 -0
  186. package/esm/io/index.js +24 -0
  187. package/esm/io/index.js.map +1 -0
  188. package/esm/io/localFile.d.ts +10 -0
  189. package/esm/io/localFile.js +31 -0
  190. package/esm/io/localFile.js.map +1 -0
  191. package/esm/io/remoteFile.d.ts +16 -0
  192. package/esm/io/remoteFile.js +64 -0
  193. package/esm/io/remoteFile.js.map +1 -0
  194. package/esm/rans/constants.d.ts +3 -0
  195. package/esm/rans/constants.js +5 -0
  196. package/esm/rans/constants.js.map +1 -0
  197. package/esm/rans/d04.d.ts +1 -0
  198. package/esm/rans/d04.js +67 -0
  199. package/esm/rans/d04.js.map +1 -0
  200. package/esm/rans/d14.d.ts +1 -0
  201. package/esm/rans/d14.js +52 -0
  202. package/esm/rans/d14.js.map +1 -0
  203. package/esm/rans/decoding.d.ts +30 -0
  204. package/esm/rans/decoding.js +118 -0
  205. package/esm/rans/decoding.js.map +1 -0
  206. package/esm/rans/frequencies.d.ts +2 -0
  207. package/esm/rans/frequencies.js +110 -0
  208. package/esm/rans/frequencies.js.map +1 -0
  209. package/esm/rans/index.d.ts +1 -0
  210. package/esm/rans/index.js +195 -0
  211. package/esm/rans/index.js.map +1 -0
  212. package/esm/sam.d.ts +1 -0
  213. package/esm/sam.js +16 -0
  214. package/esm/sam.js.map +1 -0
  215. package/esm/unzip-pako.d.ts +2 -0
  216. package/esm/unzip-pako.js +5 -0
  217. package/esm/unzip-pako.js.map +1 -0
  218. package/esm/unzip.d.ts +2 -0
  219. package/esm/unzip.js +3 -0
  220. package/esm/unzip.js.map +1 -0
  221. package/package.json +38 -35
  222. package/src/craiIndex.js +180 -0
  223. package/src/cramFile/codecs/_base.js +49 -0
  224. package/src/cramFile/codecs/beta.js +23 -0
  225. package/src/cramFile/codecs/byteArrayLength.js +55 -0
  226. package/src/cramFile/codecs/byteArrayStop.js +50 -0
  227. package/src/cramFile/codecs/external.js +54 -0
  228. package/src/cramFile/codecs/gamma.js +30 -0
  229. package/src/cramFile/codecs/huffman.js +137 -0
  230. package/src/cramFile/codecs/index.js +38 -0
  231. package/src/cramFile/codecs/subexp.js +32 -0
  232. package/src/cramFile/constants.js +55 -0
  233. package/src/cramFile/container/compressionScheme.js +144 -0
  234. package/src/cramFile/container/index.js +119 -0
  235. package/src/cramFile/file.js +347 -0
  236. package/src/cramFile/index.js +3 -0
  237. package/src/cramFile/record.js +337 -0
  238. package/src/cramFile/sectionParsers.js +379 -0
  239. package/src/cramFile/slice/decodeRecord.js +362 -0
  240. package/src/cramFile/slice/index.js +497 -0
  241. package/src/cramFile/util.js +169 -0
  242. package/src/errors.js +22 -0
  243. package/src/index.js +5 -0
  244. package/src/indexedCramFile.js +191 -0
  245. package/src/io/bufferCache.js +66 -0
  246. package/src/io/index.js +26 -0
  247. package/src/io/localFile.js +35 -0
  248. package/src/io/remoteFile.js +71 -0
  249. package/src/rans/README.md +1 -0
  250. package/src/rans/constants.js +5 -0
  251. package/src/rans/d04.js +83 -0
  252. package/src/rans/d14.js +59 -0
  253. package/src/rans/decoding.js +141 -0
  254. package/src/rans/frequencies.js +121 -0
  255. package/src/rans/index.js +249 -0
  256. package/src/sam.js +15 -0
  257. package/src/unzip-pako.ts +5 -0
  258. 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
+ }