@gmod/bam 7.1.18 → 7.1.20
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/README.md +5 -4
- package/dist/bai.js +1 -0
- package/dist/bai.js.map +1 -1
- package/dist/bamFile.d.ts +1 -0
- package/dist/bamFile.js +55 -23
- package/dist/bamFile.js.map +1 -1
- package/dist/chunk.js +5 -0
- package/dist/chunk.js.map +1 -1
- package/dist/csi.js +4 -6
- package/dist/csi.js.map +1 -1
- package/dist/htsget.js +2 -0
- package/dist/htsget.js.map +1 -1
- package/dist/indexFile.js +2 -0
- package/dist/indexFile.js.map +1 -1
- package/dist/nullFilehandle.d.ts +4 -4
- package/dist/nullIndex.d.ts +4 -4
- package/dist/record.d.ts +1 -1
- package/dist/record.js +17 -2
- package/dist/record.js.map +1 -1
- package/dist/virtualOffset.js +2 -0
- package/dist/virtualOffset.js.map +1 -1
- package/esm/bai.js +1 -0
- package/esm/bai.js.map +1 -1
- package/esm/bamFile.d.ts +1 -0
- package/esm/bamFile.js +55 -23
- package/esm/bamFile.js.map +1 -1
- package/esm/chunk.js +5 -0
- package/esm/chunk.js.map +1 -1
- package/esm/csi.js +4 -6
- package/esm/csi.js.map +1 -1
- package/esm/htsget.js +2 -0
- package/esm/htsget.js.map +1 -1
- package/esm/indexFile.js +2 -0
- package/esm/indexFile.js.map +1 -1
- package/esm/nullFilehandle.d.ts +4 -4
- package/esm/nullIndex.d.ts +4 -4
- package/esm/record.d.ts +1 -1
- package/esm/record.js +17 -2
- package/esm/record.js.map +1 -1
- package/esm/virtualOffset.js +2 -0
- package/esm/virtualOffset.js.map +1 -1
- package/package.json +22 -21
- package/src/bamFile.ts +52 -24
- package/src/nullFilehandle.ts +4 -4
- package/src/nullIndex.ts +4 -4
- package/src/record.ts +7 -3
- package/CHANGELOG.md +0 -532
package/package.json
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gmod/bam",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.20",
|
|
4
4
|
"description": "Parser for BAM and BAM index (bai) files",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"repository":
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/GMOD/bam-js.git"
|
|
9
|
+
},
|
|
7
10
|
"type": "module",
|
|
8
|
-
"types": "./
|
|
11
|
+
"types": "./esm/index.d.ts",
|
|
9
12
|
"exports": {
|
|
10
|
-
"
|
|
11
|
-
"import": "./esm/index.js"
|
|
12
|
-
},
|
|
13
|
-
"require": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./esm/index.js",
|
|
14
15
|
"require": "./dist/index.js"
|
|
15
16
|
}
|
|
16
17
|
},
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
"url": "https://github.com/cmdcolin"
|
|
21
22
|
},
|
|
22
23
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
24
|
+
"node": ">=20"
|
|
24
25
|
},
|
|
25
26
|
"files": [
|
|
26
27
|
"dist",
|
|
@@ -35,11 +36,11 @@
|
|
|
35
36
|
"clean": "rimraf dist esm",
|
|
36
37
|
"format": "prettier --write .",
|
|
37
38
|
"build:esm": "tsc --outDir esm",
|
|
38
|
-
"build:es5": "tsc --module commonjs --outDir dist",
|
|
39
|
-
"build": "
|
|
40
|
-
"prebuild": "
|
|
39
|
+
"build:es5": "tsc --module commonjs --moduleResolution bundler --outDir dist",
|
|
40
|
+
"build": "pnpm build:esm && pnpm build:es5",
|
|
41
|
+
"prebuild": "pnpm clean",
|
|
41
42
|
"postbuild:es5": "echo '{\"type\": \"commonjs\"}' > dist/package.json",
|
|
42
|
-
"preversion": "
|
|
43
|
+
"preversion": "pnpm lint && pnpm test --run && pnpm build",
|
|
43
44
|
"version": "standard-changelog && git add CHANGELOG.md",
|
|
44
45
|
"postversion": "git push --follow-tags"
|
|
45
46
|
},
|
|
@@ -53,21 +54,21 @@
|
|
|
53
54
|
"@gmod/bgzf-filehandle": "^6.0.12",
|
|
54
55
|
"@jbrowse/quick-lru": "^7.3.5",
|
|
55
56
|
"crc": "^4.3.2",
|
|
56
|
-
"generic-filehandle2": "^2.
|
|
57
|
+
"generic-filehandle2": "^2.1.4"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
60
|
"@eslint/js": "^10.0.1",
|
|
60
|
-
"@types/node": "^25.
|
|
61
|
-
"@vitest/coverage-v8": "^4.
|
|
62
|
-
"eslint": "^
|
|
63
|
-
"eslint-plugin-import": "^2.
|
|
64
|
-
"eslint-plugin-unicorn": "^
|
|
61
|
+
"@types/node": "^25.5.0",
|
|
62
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
63
|
+
"eslint": "^9.39.4",
|
|
64
|
+
"eslint-plugin-import": "^2.32.0",
|
|
65
|
+
"eslint-plugin-unicorn": "^64.0.0",
|
|
65
66
|
"prettier": "^3.8.1",
|
|
66
67
|
"rimraf": "^6.1.3",
|
|
67
68
|
"standard-changelog": "^7.0.1",
|
|
68
|
-
"typescript": "^
|
|
69
|
-
"typescript-eslint": "^8.
|
|
70
|
-
"vitest": "^4.
|
|
69
|
+
"typescript": "^6.0.2",
|
|
70
|
+
"typescript-eslint": "^8.57.2",
|
|
71
|
+
"vitest": "^4.1.2"
|
|
71
72
|
},
|
|
72
73
|
"publishConfig": {
|
|
73
74
|
"access": "public"
|
package/src/bamFile.ts
CHANGED
|
@@ -139,32 +139,49 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
139
139
|
|
|
140
140
|
// firstDataLine is not defined in cases where there is no data in the file
|
|
141
141
|
// (just bam header and nothing else)
|
|
142
|
-
|
|
142
|
+
let readLen =
|
|
143
143
|
indexData.firstDataLine === undefined
|
|
144
|
+
? undefined
|
|
145
|
+
: indexData.firstDataLine.blockPosition + blockLen
|
|
146
|
+
|
|
147
|
+
const buffer =
|
|
148
|
+
readLen === undefined
|
|
144
149
|
? await this.bam.readFile()
|
|
145
|
-
:
|
|
146
|
-
|
|
147
|
-
// (provided by the bgzip block offset at blockPosition + the
|
|
148
|
-
// virtualOffset dataPosition, so we add one extra blockLen to make
|
|
149
|
-
// sure we consume the full header)
|
|
150
|
-
await this.bam.read(
|
|
151
|
-
indexData.firstDataLine.blockPosition + blockLen,
|
|
152
|
-
0,
|
|
153
|
-
)
|
|
154
|
-
const uncba = await unzip(buffer)
|
|
150
|
+
: await this.bam.read(readLen, 0)
|
|
151
|
+
let uncba = await unzip(buffer)
|
|
155
152
|
const dataView = new DataView(uncba.buffer)
|
|
156
153
|
|
|
157
154
|
if (dataView.getInt32(0, true) !== BAM_MAGIC) {
|
|
158
155
|
throw new Error('Not a BAM file')
|
|
159
156
|
}
|
|
160
157
|
const headLen = dataView.getInt32(4, true)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
158
|
+
this.header = new TextDecoder('utf8').decode(uncba.subarray(8, 8 + headLen))
|
|
159
|
+
|
|
160
|
+
// BAM files with many reference sequences may need more data than the
|
|
161
|
+
// initial read provides, so re-fetch with doubled size until it fits
|
|
162
|
+
const refSeqStart = headLen + 8
|
|
163
|
+
const maxRetries = 5
|
|
164
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
165
|
+
if (this._hasEnoughRefSeqData(uncba, refSeqStart)) {
|
|
166
|
+
const { chrToIndex, indexToChr } = this._parseRefSeqs(
|
|
167
|
+
uncba,
|
|
168
|
+
refSeqStart,
|
|
169
|
+
)
|
|
170
|
+
this.chrToIndex = chrToIndex
|
|
171
|
+
this.indexToChr = indexToChr
|
|
172
|
+
return parseHeaderText(this.header)
|
|
173
|
+
}
|
|
174
|
+
if (readLen === undefined) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`Insufficient data for reference sequences in ${uncba.length} bytes`,
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
readLen *= 2
|
|
180
|
+
uncba = await unzip(await this.bam.read(readLen, 0))
|
|
181
|
+
}
|
|
182
|
+
throw new Error(
|
|
183
|
+
`Insufficient data for reference sequences after ${maxRetries} retries`,
|
|
184
|
+
)
|
|
168
185
|
}
|
|
169
186
|
|
|
170
187
|
getHeader(opts?: BaseOpts) {
|
|
@@ -182,6 +199,23 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
182
199
|
return this.header
|
|
183
200
|
}
|
|
184
201
|
|
|
202
|
+
_hasEnoughRefSeqData(uncba: Uint8Array, start: number) {
|
|
203
|
+
if (start + 4 > uncba.length) {
|
|
204
|
+
return false
|
|
205
|
+
}
|
|
206
|
+
const dataView = new DataView(uncba.buffer)
|
|
207
|
+
const nRef = dataView.getInt32(start, true)
|
|
208
|
+
let p = start + 4
|
|
209
|
+
for (let i = 0; i < nRef; i += 1) {
|
|
210
|
+
if (p + 8 > uncba.length) {
|
|
211
|
+
return false
|
|
212
|
+
}
|
|
213
|
+
const lName = dataView.getInt32(p, true)
|
|
214
|
+
p = p + 8 + lName
|
|
215
|
+
}
|
|
216
|
+
return true
|
|
217
|
+
}
|
|
218
|
+
|
|
185
219
|
_parseRefSeqs(
|
|
186
220
|
uncba: Uint8Array,
|
|
187
221
|
start: number,
|
|
@@ -198,12 +232,6 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
198
232
|
const decoder = new TextDecoder('utf8')
|
|
199
233
|
|
|
200
234
|
for (let i = 0; i < nRef; i += 1) {
|
|
201
|
-
if (p + 8 > uncba.length) {
|
|
202
|
-
throw new Error(
|
|
203
|
-
`Insufficient data for reference sequences: need more than ${uncba.length} bytes`,
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
235
|
const lName = dataView.getInt32(p, true)
|
|
208
236
|
const refName = this.renameRefSeq(
|
|
209
237
|
decoder.decode(uncba.subarray(p + 4, p + 4 + lName - 1)),
|
package/src/nullFilehandle.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
export default class NullFilehandle {
|
|
2
|
-
public read(): Promise<
|
|
2
|
+
public read(): Promise<never> {
|
|
3
3
|
throw new Error('never called')
|
|
4
4
|
}
|
|
5
|
-
public stat(): Promise<
|
|
5
|
+
public stat(): Promise<never> {
|
|
6
6
|
throw new Error('never called')
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
public readFile(): Promise<
|
|
9
|
+
public readFile(): Promise<never> {
|
|
10
10
|
throw new Error('never called')
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
public close(): Promise<
|
|
13
|
+
public close(): Promise<never> {
|
|
14
14
|
throw new Error('never called')
|
|
15
15
|
}
|
|
16
16
|
}
|
package/src/nullIndex.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import IndexFile from './indexFile.ts'
|
|
2
2
|
|
|
3
3
|
export default class NullIndex extends IndexFile {
|
|
4
|
-
public lineCount(): Promise<
|
|
4
|
+
public lineCount(): Promise<never> {
|
|
5
5
|
throw new Error('never called')
|
|
6
6
|
}
|
|
7
|
-
protected _parse(): Promise<
|
|
7
|
+
protected _parse(): Promise<never> {
|
|
8
8
|
throw new Error('never called')
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
public async indexCov(): Promise<
|
|
11
|
+
public async indexCov(): Promise<never> {
|
|
12
12
|
throw new Error('never called')
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
public blocksForRange(): Promise<
|
|
15
|
+
public blocksForRange(): Promise<never> {
|
|
16
16
|
throw new Error('never called')
|
|
17
17
|
}
|
|
18
18
|
}
|
package/src/record.ts
CHANGED
|
@@ -674,10 +674,14 @@ export default class BamRecord {
|
|
|
674
674
|
}
|
|
675
675
|
|
|
676
676
|
// adapted from igv.js
|
|
677
|
-
// uses precomputed lookup table indexed by flag bits + isize sign
|
|
677
|
+
// uses precomputed lookup table indexed by flag bits + isize sign.
|
|
678
|
+
// the BAM spec defines tlen as positive for the leftmost segment and
|
|
679
|
+
// negative for the rightmost, so tlen > 0 reliably indicates which
|
|
680
|
+
// read comes first without needing position-based correction
|
|
681
|
+
// (see also: gmod/cram-js src/cramFile/record.ts getPairOrientation)
|
|
678
682
|
get pair_orientation() {
|
|
679
683
|
const f = this.flags
|
|
680
|
-
//
|
|
684
|
+
// unmapped (0x4) or mate unmapped (0x8) -> undefined
|
|
681
685
|
if (f & 0xc || this.ref_id !== this.next_refid) {
|
|
682
686
|
return undefined
|
|
683
687
|
}
|
|
@@ -727,7 +731,7 @@ export default class BamRecord {
|
|
|
727
731
|
}
|
|
728
732
|
|
|
729
733
|
toJSON() {
|
|
730
|
-
const data: Record<string,
|
|
734
|
+
const data: Record<string, unknown> = {}
|
|
731
735
|
for (const k of Object.keys(this)) {
|
|
732
736
|
if (k.startsWith('_') || k === 'bytes') {
|
|
733
737
|
continue
|