@gmod/bam 6.1.1 → 7.0.1
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 +6 -2
- package/dist/bamFile.d.ts +5 -6
- package/dist/bamFile.js +38 -74
- package/dist/bamFile.js.map +1 -1
- package/dist/package.json +1 -0
- package/dist/record.d.ts +4 -2
- package/dist/record.js +151 -181
- package/dist/record.js.map +1 -1
- package/dist/util.d.ts +0 -22
- package/dist/util.js +9 -56
- package/dist/util.js.map +1 -1
- package/esm/bamFile.d.ts +5 -6
- package/esm/bamFile.js +39 -75
- package/esm/bamFile.js.map +1 -1
- package/esm/record.d.ts +4 -2
- package/esm/record.js +152 -183
- package/esm/record.js.map +1 -1
- package/esm/util.d.ts +0 -22
- package/esm/util.js +9 -52
- package/esm/util.js.map +1 -1
- package/package.json +11 -10
- package/src/bamFile.ts +71 -89
- package/src/record.ts +169 -161
- package/src/util.ts +9 -55
package/esm/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AAGnD,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gmod/bam",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.1",
|
|
4
4
|
"description": "Parser for BAM and BAM index (bai) files",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "GMOD/bam-js",
|
|
@@ -29,15 +29,17 @@
|
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
31
|
"test": "vitest",
|
|
32
|
+
"benchonly": "vitest bench",
|
|
33
|
+
"bench": "./scripts/build-both-branches.sh \"$BRANCH1\" \"$BRANCH2\" && vitest bench",
|
|
32
34
|
"lint": "eslint --report-unused-disable-directives --max-warnings 0",
|
|
33
35
|
"clean": "rimraf dist esm",
|
|
34
36
|
"format": "prettier --write .",
|
|
35
37
|
"build:esm": "tsc --outDir esm",
|
|
36
38
|
"build:es5": "tsc --module commonjs --outDir dist",
|
|
37
|
-
"build": "
|
|
38
|
-
"prebuild": "
|
|
39
|
+
"build": "yarn build:esm && yarn build:es5",
|
|
40
|
+
"prebuild": "yarn clean",
|
|
39
41
|
"postbuild:es5": "echo '{\"type\": \"commonjs\"}' > dist/package.json",
|
|
40
|
-
"preversion": "
|
|
42
|
+
"preversion": "yarn lint && yarn test --run && yarn build",
|
|
41
43
|
"version": "standard-changelog && git add CHANGELOG.md",
|
|
42
44
|
"postversion": "git push --follow-tags"
|
|
43
45
|
},
|
|
@@ -48,24 +50,23 @@
|
|
|
48
50
|
"genomics"
|
|
49
51
|
],
|
|
50
52
|
"dependencies": {
|
|
51
|
-
"@gmod/
|
|
52
|
-
"@gmod/bgzf-filehandle": "^4.0.0",
|
|
53
|
+
"@gmod/bgzf-filehandle": "^4.2.1",
|
|
53
54
|
"crc": "^4.3.2",
|
|
54
55
|
"generic-filehandle2": "^2.0.1",
|
|
55
56
|
"quick-lru": "^4.0.0"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
|
-
"@types/node": "^
|
|
59
|
-
"@vitest/coverage-v8": "^
|
|
59
|
+
"@types/node": "^24.10.0",
|
|
60
|
+
"@vitest/coverage-v8": "^4.0.3",
|
|
60
61
|
"eslint": "^9.9.0",
|
|
61
62
|
"eslint-plugin-import": "^2.31.0",
|
|
62
|
-
"eslint-plugin-unicorn": "^
|
|
63
|
+
"eslint-plugin-unicorn": "^62.0.0",
|
|
63
64
|
"prettier": "^3.3.3",
|
|
64
65
|
"rimraf": "^6.0.1",
|
|
65
66
|
"standard-changelog": "^7.0.1",
|
|
66
67
|
"typescript": "^5.0.4",
|
|
67
68
|
"typescript-eslint": "^8.27.0",
|
|
68
|
-
"vitest": "^
|
|
69
|
+
"vitest": "^4.0.3"
|
|
69
70
|
},
|
|
70
71
|
"publishConfig": {
|
|
71
72
|
"access": "public"
|
package/src/bamFile.ts
CHANGED
|
@@ -9,7 +9,7 @@ import CSI from './csi.ts'
|
|
|
9
9
|
import NullFilehandle from './nullFilehandle.ts'
|
|
10
10
|
import BAMFeature from './record.ts'
|
|
11
11
|
import { parseHeaderText } from './sam.ts'
|
|
12
|
-
import {
|
|
12
|
+
import { gen2array, makeOpts } from './util.ts'
|
|
13
13
|
|
|
14
14
|
import type { BamOpts, BaseOpts } from './util.ts'
|
|
15
15
|
import type { GenericFilehandle } from 'generic-filehandle2'
|
|
@@ -24,7 +24,6 @@ export default class BamFile {
|
|
|
24
24
|
public header?: string
|
|
25
25
|
public chrToIndex?: Record<string, number>
|
|
26
26
|
public indexToChr?: { refName: string; length: number }[]
|
|
27
|
-
public yieldThreadTime: number
|
|
28
27
|
public index?: BAI | CSI
|
|
29
28
|
public htsget = false
|
|
30
29
|
public headerP?: ReturnType<BamFile['getHeaderPre']>
|
|
@@ -43,7 +42,6 @@ export default class BamFile {
|
|
|
43
42
|
csiFilehandle,
|
|
44
43
|
csiUrl,
|
|
45
44
|
htsget,
|
|
46
|
-
yieldThreadTime = 100,
|
|
47
45
|
renameRefSeqs = n => n,
|
|
48
46
|
}: {
|
|
49
47
|
bamFilehandle?: GenericFilehandle
|
|
@@ -56,7 +54,6 @@ export default class BamFile {
|
|
|
56
54
|
csiFilehandle?: GenericFilehandle
|
|
57
55
|
csiUrl?: string
|
|
58
56
|
renameRefSeqs?: (a: string) => string
|
|
59
|
-
yieldThreadTime?: number
|
|
60
57
|
htsget?: boolean
|
|
61
58
|
}) {
|
|
62
59
|
this.renameRefSeq = renameRefSeqs
|
|
@@ -94,26 +91,24 @@ export default class BamFile {
|
|
|
94
91
|
} else {
|
|
95
92
|
throw new Error('unable to infer index format')
|
|
96
93
|
}
|
|
97
|
-
this.yieldThreadTime = yieldThreadTime
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
async getHeaderPre(origOpts?: BaseOpts) {
|
|
101
97
|
const opts = makeOpts(origOpts)
|
|
102
98
|
if (!this.index) {
|
|
103
|
-
return
|
|
99
|
+
return undefined
|
|
104
100
|
}
|
|
105
101
|
const indexData = await this.index.parse(opts)
|
|
106
|
-
const ret = indexData.firstDataLine
|
|
107
|
-
? indexData.firstDataLine.blockPosition + 65535
|
|
108
|
-
: undefined
|
|
109
|
-
let buffer
|
|
110
|
-
if (ret) {
|
|
111
|
-
const s = ret + blockLen
|
|
112
|
-
buffer = await this.bam.read(s, 0)
|
|
113
|
-
} else {
|
|
114
|
-
buffer = await this.bam.readFile(opts)
|
|
115
|
-
}
|
|
116
102
|
|
|
103
|
+
// firstDataLine is not defined in cases where there is no data in the file
|
|
104
|
+
// (just bam header and nothing else)
|
|
105
|
+
const buffer =
|
|
106
|
+
indexData.firstDataLine === undefined
|
|
107
|
+
? await this.bam.readFile()
|
|
108
|
+
: await this.bam.read(
|
|
109
|
+
indexData.firstDataLine.blockPosition + blockLen,
|
|
110
|
+
0,
|
|
111
|
+
)
|
|
117
112
|
const uncba = await unzip(buffer)
|
|
118
113
|
const dataView = new DataView(uncba.buffer)
|
|
119
114
|
|
|
@@ -121,14 +116,10 @@ export default class BamFile {
|
|
|
121
116
|
throw new Error('Not a BAM file')
|
|
122
117
|
}
|
|
123
118
|
const headLen = dataView.getInt32(4, true)
|
|
124
|
-
|
|
125
119
|
const decoder = new TextDecoder('utf8')
|
|
126
120
|
this.header = decoder.decode(uncba.subarray(8, 8 + headLen))
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
65535,
|
|
130
|
-
opts,
|
|
131
|
-
)
|
|
121
|
+
|
|
122
|
+
const { chrToIndex, indexToChr } = this._parseRefSeqs(uncba, headLen + 8)
|
|
132
123
|
this.chrToIndex = chrToIndex
|
|
133
124
|
this.indexToChr = indexToChr
|
|
134
125
|
|
|
@@ -150,29 +141,28 @@ export default class BamFile {
|
|
|
150
141
|
return this.header
|
|
151
142
|
}
|
|
152
143
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
async _readRefSeqs(
|
|
144
|
+
_parseRefSeqs(
|
|
145
|
+
uncba: Uint8Array,
|
|
156
146
|
start: number,
|
|
157
|
-
|
|
158
|
-
opts?: BaseOpts,
|
|
159
|
-
): Promise<{
|
|
147
|
+
): {
|
|
160
148
|
chrToIndex: Record<string, number>
|
|
161
149
|
indexToChr: { refName: string; length: number }[]
|
|
162
|
-
}
|
|
163
|
-
if (start > refSeqBytes) {
|
|
164
|
-
return this._readRefSeqs(start, refSeqBytes * 2, opts)
|
|
165
|
-
}
|
|
166
|
-
// const size = refSeqBytes + blockLen <-- use this?
|
|
167
|
-
const buffer = await this.bam.read(refSeqBytes, 0, opts)
|
|
168
|
-
const uncba = await unzip(buffer)
|
|
150
|
+
} {
|
|
169
151
|
const dataView = new DataView(uncba.buffer)
|
|
170
152
|
const nRef = dataView.getInt32(start, true)
|
|
171
153
|
let p = start + 4
|
|
154
|
+
|
|
172
155
|
const chrToIndex: Record<string, number> = {}
|
|
173
156
|
const indexToChr: { refName: string; length: number }[] = []
|
|
174
157
|
const decoder = new TextDecoder('utf8')
|
|
158
|
+
|
|
175
159
|
for (let i = 0; i < nRef; i += 1) {
|
|
160
|
+
if (p + 8 > uncba.length) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Insufficient data for reference sequences: need more than ${uncba.length} bytes`,
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
176
166
|
const lName = dataView.getInt32(p, true)
|
|
177
167
|
const refName = this.renameRefSeq(
|
|
178
168
|
decoder.decode(uncba.subarray(p + 4, p + 4 + lName - 1)),
|
|
@@ -183,13 +173,8 @@ export default class BamFile {
|
|
|
183
173
|
indexToChr.push({ refName, length: lRef })
|
|
184
174
|
|
|
185
175
|
p = p + 8 + lName
|
|
186
|
-
if (p > uncba.length) {
|
|
187
|
-
console.warn(
|
|
188
|
-
`BAM header is very big. Re-fetching ${refSeqBytes} bytes.`,
|
|
189
|
-
)
|
|
190
|
-
return this._readRefSeqs(start, refSeqBytes * 2, opts)
|
|
191
|
-
}
|
|
192
176
|
}
|
|
177
|
+
|
|
193
178
|
return { chrToIndex, indexToChr }
|
|
194
179
|
}
|
|
195
180
|
|
|
@@ -211,11 +196,10 @@ export default class BamFile {
|
|
|
211
196
|
await this.getHeader(opts)
|
|
212
197
|
const chrId = this.chrToIndex?.[chr]
|
|
213
198
|
if (chrId === undefined || !this.index) {
|
|
214
|
-
|
|
215
|
-
} else {
|
|
216
|
-
const chunks = await this.index.blocksForRange(chrId, min - 1, max, opts)
|
|
217
|
-
yield* this._fetchChunkFeatures(chunks, chrId, min, max, opts)
|
|
199
|
+
return
|
|
218
200
|
}
|
|
201
|
+
const chunks = await this.index.blocksForRange(chrId, min - 1, max, opts)
|
|
202
|
+
yield* this._fetchChunkFeatures(chunks, chrId, min, max, opts)
|
|
219
203
|
}
|
|
220
204
|
|
|
221
205
|
async *_fetchChunkFeatures(
|
|
@@ -239,6 +223,9 @@ export default class BamFile {
|
|
|
239
223
|
cpositions,
|
|
240
224
|
dpositions,
|
|
241
225
|
chunk,
|
|
226
|
+
chrId,
|
|
227
|
+
min,
|
|
228
|
+
max,
|
|
242
229
|
)
|
|
243
230
|
|
|
244
231
|
const recs = [] as BAMFeature[]
|
|
@@ -261,7 +248,6 @@ export default class BamFile {
|
|
|
261
248
|
}
|
|
262
249
|
}
|
|
263
250
|
|
|
264
|
-
checkAbortSignal(opts.signal)
|
|
265
251
|
if (viewAsPairs) {
|
|
266
252
|
yield this.fetchPairs(chrId, feats, opts)
|
|
267
253
|
}
|
|
@@ -271,7 +257,7 @@ export default class BamFile {
|
|
|
271
257
|
const { pairAcrossChr, maxInsertSize = 200000 } = opts
|
|
272
258
|
const unmatedPairs: Record<string, boolean> = {}
|
|
273
259
|
const readIds: Record<string, number> = {}
|
|
274
|
-
|
|
260
|
+
for (const ret of feats) {
|
|
275
261
|
const readNames: Record<string, number> = {}
|
|
276
262
|
for (const element of ret) {
|
|
277
263
|
const name = element.name
|
|
@@ -287,10 +273,10 @@ export default class BamFile {
|
|
|
287
273
|
unmatedPairs[k] = true
|
|
288
274
|
}
|
|
289
275
|
}
|
|
290
|
-
}
|
|
276
|
+
}
|
|
291
277
|
|
|
292
278
|
const matePromises: Promise<Chunk[]>[] = []
|
|
293
|
-
|
|
279
|
+
for (const ret of feats) {
|
|
294
280
|
for (const f of ret) {
|
|
295
281
|
const name = f.name
|
|
296
282
|
const start = f.start
|
|
@@ -307,7 +293,7 @@ export default class BamFile {
|
|
|
307
293
|
)
|
|
308
294
|
}
|
|
309
295
|
}
|
|
310
|
-
}
|
|
296
|
+
}
|
|
311
297
|
|
|
312
298
|
// filter out duplicate chunks (the blocks are lists of chunks, blocks are
|
|
313
299
|
// concatenated, then filter dup chunks)
|
|
@@ -362,69 +348,54 @@ export default class BamFile {
|
|
|
362
348
|
cpositions: number[],
|
|
363
349
|
dpositions: number[],
|
|
364
350
|
chunk: Chunk,
|
|
351
|
+
chrId?: number,
|
|
352
|
+
min?: number,
|
|
353
|
+
max?: number,
|
|
365
354
|
) {
|
|
366
355
|
let blockStart = 0
|
|
367
356
|
const sink = [] as BAMFeature[]
|
|
368
357
|
let pos = 0
|
|
369
|
-
let last = Date.now()
|
|
370
358
|
|
|
371
359
|
const dataView = new DataView(ba.buffer)
|
|
360
|
+
const hasDpositions = dpositions.length > 0
|
|
361
|
+
const hasCpositions = cpositions.length > 0
|
|
362
|
+
const hasFilter =
|
|
363
|
+
chrId !== undefined && min !== undefined && max !== undefined
|
|
364
|
+
|
|
372
365
|
while (blockStart + 4 < ba.length) {
|
|
373
366
|
const blockSize = dataView.getInt32(blockStart, true)
|
|
374
367
|
const blockEnd = blockStart + 4 + blockSize - 1
|
|
375
368
|
|
|
376
|
-
|
|
377
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
378
|
-
if (dpositions) {
|
|
369
|
+
if (hasDpositions) {
|
|
379
370
|
while (blockStart + chunk.minv.dataPosition >= dpositions[pos++]!) {}
|
|
380
371
|
pos--
|
|
381
372
|
}
|
|
382
373
|
|
|
383
|
-
// only try to read the feature if we have all the bytes for it
|
|
384
374
|
if (blockEnd < ba.length) {
|
|
375
|
+
if (
|
|
376
|
+
hasFilter &&
|
|
377
|
+
blockStart + 12 < ba.length &&
|
|
378
|
+
!this._shouldIncludeFeature(dataView, blockStart, chrId, max)
|
|
379
|
+
) {
|
|
380
|
+
blockStart = blockEnd + 1
|
|
381
|
+
continue
|
|
382
|
+
}
|
|
383
|
+
|
|
385
384
|
const feature = new BAMFeature({
|
|
386
385
|
bytes: {
|
|
387
386
|
byteArray: ba,
|
|
388
387
|
start: blockStart,
|
|
389
388
|
end: blockEnd,
|
|
390
389
|
},
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
//
|
|
398
|
-
// we multiply by (1 <<8) in order to make sure each block has a
|
|
399
|
-
// "unique" address space so that data in that block could never
|
|
400
|
-
// overlap
|
|
401
|
-
//
|
|
402
|
-
// then the blockStart-dpositions is an uncompressed file offset from
|
|
403
|
-
// that bgzip block boundary, and since the cpositions are multiplied
|
|
404
|
-
// by (1 << 8) these uncompressed offsets get a unique space
|
|
405
|
-
//
|
|
406
|
-
// this has an extra chunk.minv.dataPosition added on because it
|
|
407
|
-
// blockStart starts at 0 instead of chunk.minv.dataPosition
|
|
408
|
-
//
|
|
409
|
-
// the +1 is just to avoid any possible uniqueId 0 but this does not
|
|
410
|
-
// realistically happen
|
|
411
|
-
fileOffset:
|
|
412
|
-
cpositions.length > 0
|
|
413
|
-
? cpositions[pos]! * (1 << 8) +
|
|
414
|
-
(blockStart - dpositions[pos]!) +
|
|
415
|
-
chunk.minv.dataPosition +
|
|
416
|
-
1
|
|
417
|
-
: // this shift >>> 0 is equivalent to crc32(b).unsigned but uses the
|
|
418
|
-
// internal calculator of crc32 to avoid accidentally importing buffer
|
|
419
|
-
// https://github.com/alexgorbatchev/crc/blob/31fc3853e417b5fb5ec83335428805842575f699/src/define_crc.ts#L5
|
|
420
|
-
crc32(ba.subarray(blockStart, blockEnd)) >>> 0,
|
|
390
|
+
fileOffset: hasCpositions
|
|
391
|
+
? cpositions[pos]! * (1 << 8) +
|
|
392
|
+
(blockStart - dpositions[pos]!) +
|
|
393
|
+
chunk.minv.dataPosition +
|
|
394
|
+
1
|
|
395
|
+
: crc32(ba.subarray(blockStart, blockEnd)) >>> 0,
|
|
421
396
|
})
|
|
422
397
|
|
|
423
398
|
sink.push(feature)
|
|
424
|
-
if (this.yieldThreadTime && Date.now() - last > this.yieldThreadTime) {
|
|
425
|
-
await timeout(1)
|
|
426
|
-
last = Date.now()
|
|
427
|
-
}
|
|
428
399
|
}
|
|
429
400
|
|
|
430
401
|
blockStart = blockEnd + 1
|
|
@@ -432,6 +403,17 @@ export default class BamFile {
|
|
|
432
403
|
return sink
|
|
433
404
|
}
|
|
434
405
|
|
|
406
|
+
_shouldIncludeFeature(
|
|
407
|
+
dataView: DataView,
|
|
408
|
+
blockStart: number,
|
|
409
|
+
chrId: number,
|
|
410
|
+
max: number,
|
|
411
|
+
) {
|
|
412
|
+
const ref_id = dataView.getInt32(blockStart + 4, true)
|
|
413
|
+
const start = dataView.getInt32(blockStart + 8, true)
|
|
414
|
+
return ref_id === chrId && start < max
|
|
415
|
+
}
|
|
416
|
+
|
|
435
417
|
async hasRefSeq(seqName: string) {
|
|
436
418
|
const seqId = this.chrToIndex?.[seqName]
|
|
437
419
|
return seqId === undefined ? false : this.index?.hasRefSeq(seqId)
|