@gmod/tabix 3.0.5 → 3.1.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 +4 -10
- package/README.md +0 -1
- package/dist/chunk.d.ts +1 -1
- package/dist/chunk.js +1 -1
- package/dist/chunk.js.map +1 -1
- package/dist/csi.d.ts +3 -7
- package/dist/csi.js +2 -25
- package/dist/csi.js.map +1 -1
- package/dist/indexFile.d.ts +6 -2
- package/dist/indexFile.js +24 -2
- package/dist/indexFile.js.map +1 -1
- package/dist/tabix-bundle.js +1 -1
- package/dist/tabixIndexedFile.d.ts +7 -1
- package/dist/tabixIndexedFile.js +83 -75
- package/dist/tabixIndexedFile.js.map +1 -1
- package/dist/tbi.d.ts +1 -5
- package/dist/tbi.js +5 -29
- package/dist/tbi.js.map +1 -1
- package/dist/util.js +9 -9
- package/dist/util.js.map +1 -1
- package/esm/chunk.d.ts +1 -1
- package/esm/chunk.js +1 -1
- package/esm/chunk.js.map +1 -1
- package/esm/csi.d.ts +3 -7
- package/esm/csi.js +2 -25
- package/esm/csi.js.map +1 -1
- package/esm/indexFile.d.ts +6 -2
- package/esm/indexFile.js +24 -2
- package/esm/indexFile.js.map +1 -1
- package/esm/tabixIndexedFile.d.ts +7 -1
- package/esm/tabixIndexedFile.js +83 -75
- package/esm/tabixIndexedFile.js.map +1 -1
- package/esm/tbi.d.ts +1 -5
- package/esm/tbi.js +5 -29
- package/esm/tbi.js.map +1 -1
- package/esm/util.js +9 -9
- package/esm/util.js.map +1 -1
- package/package.json +8 -8
- package/src/chunk.ts +1 -1
- package/src/csi.ts +2 -29
- package/src/indexFile.ts +28 -3
- package/src/tabixIndexedFile.ts +127 -81
- package/src/tbi.ts +12 -38
- package/src/util.ts +8 -8
package/src/chunk.ts
CHANGED
package/src/csi.ts
CHANGED
|
@@ -68,7 +68,7 @@ export default class CSI extends IndexFile {
|
|
|
68
68
|
end: dataView.getInt32(offset + 12, true),
|
|
69
69
|
}
|
|
70
70
|
const metaValue = dataView.getInt32(offset + 16, true)
|
|
71
|
-
const metaChar = metaValue ? String.fromCharCode(metaValue) :
|
|
71
|
+
const metaChar = metaValue ? String.fromCharCode(metaValue) : undefined
|
|
72
72
|
const skipLines = dataView.getInt32(offset + 20, true)
|
|
73
73
|
const nameSectionLength = dataView.getInt32(offset + 24, true)
|
|
74
74
|
|
|
@@ -87,33 +87,6 @@ export default class CSI extends IndexFile {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
_parseNameBytes(namesBytes: Uint8Array) {
|
|
91
|
-
let currRefId = 0
|
|
92
|
-
let currNameStart = 0
|
|
93
|
-
const refIdToName = []
|
|
94
|
-
const refNameToId: Record<string, number> = {}
|
|
95
|
-
const decoder = new TextDecoder('utf8')
|
|
96
|
-
for (let i = 0; i < namesBytes.length; i += 1) {
|
|
97
|
-
if (!namesBytes[i]) {
|
|
98
|
-
if (currNameStart < i) {
|
|
99
|
-
const refName = this.renameRefSeq(
|
|
100
|
-
decoder.decode(namesBytes.subarray(currNameStart, i)),
|
|
101
|
-
)
|
|
102
|
-
refIdToName[currRefId] = refName
|
|
103
|
-
refNameToId[refName] = currRefId
|
|
104
|
-
}
|
|
105
|
-
currNameStart = i + 1
|
|
106
|
-
currRefId += 1
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
refNameToId,
|
|
111
|
-
refIdToName,
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// fetch and parse the index
|
|
116
|
-
|
|
117
90
|
async _parse(opts: Options = {}) {
|
|
118
91
|
const bytes = await unzip(await this.filehandle.readFile(opts))
|
|
119
92
|
const dataView = new DataView(bytes.buffer)
|
|
@@ -139,7 +112,7 @@ export default class CSI extends IndexFile {
|
|
|
139
112
|
: {
|
|
140
113
|
refIdToName: [],
|
|
141
114
|
refNameToId: {},
|
|
142
|
-
metaChar:
|
|
115
|
+
metaChar: undefined,
|
|
143
116
|
columnNumbers: { ref: 0, start: 1, end: 2 },
|
|
144
117
|
coordinateType: 'zero-based-half-open',
|
|
145
118
|
format: 'generic',
|
package/src/indexFile.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface Options {
|
|
|
10
10
|
export interface IndexData {
|
|
11
11
|
refNameToId: Record<string, number>
|
|
12
12
|
refIdToName: string[]
|
|
13
|
-
metaChar: string |
|
|
13
|
+
metaChar: string | undefined
|
|
14
14
|
columnNumbers: { ref: number; start: number; end: number }
|
|
15
15
|
coordinateType: string
|
|
16
16
|
format: string
|
|
@@ -64,9 +64,9 @@ export default abstract class IndexFile {
|
|
|
64
64
|
|
|
65
65
|
async parse(opts: Options = {}) {
|
|
66
66
|
if (!this.parseP) {
|
|
67
|
-
this.parseP = this._parse(opts).catch((
|
|
67
|
+
this.parseP = this._parse(opts).catch((error: unknown) => {
|
|
68
68
|
this.parseP = undefined
|
|
69
|
-
throw
|
|
69
|
+
throw error
|
|
70
70
|
})
|
|
71
71
|
}
|
|
72
72
|
return this.parseP
|
|
@@ -76,4 +76,29 @@ export default abstract class IndexFile {
|
|
|
76
76
|
const idx = await this.parse(opts)
|
|
77
77
|
return !!idx.indices[seqId]?.binIndex
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
_parseNameBytes(namesBytes: Uint8Array) {
|
|
81
|
+
let currRefId = 0
|
|
82
|
+
let currNameStart = 0
|
|
83
|
+
const refIdToName: string[] = []
|
|
84
|
+
const refNameToId: Record<string, number> = {}
|
|
85
|
+
const decoder = new TextDecoder('utf8')
|
|
86
|
+
for (let i = 0; i < namesBytes.length; i += 1) {
|
|
87
|
+
if (!namesBytes[i]) {
|
|
88
|
+
if (currNameStart < i) {
|
|
89
|
+
const refName = this.renameRefSeq(
|
|
90
|
+
decoder.decode(namesBytes.subarray(currNameStart, i)),
|
|
91
|
+
)
|
|
92
|
+
refIdToName[currRefId] = refName
|
|
93
|
+
refNameToId[refName] = currRefId
|
|
94
|
+
}
|
|
95
|
+
currNameStart = i + 1
|
|
96
|
+
currRefId += 1
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
refNameToId,
|
|
101
|
+
refIdToName,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
79
104
|
}
|
package/src/tabixIndexedFile.ts
CHANGED
|
@@ -11,11 +11,6 @@ import { checkAbortSignal } from './util.ts'
|
|
|
11
11
|
|
|
12
12
|
import type { GenericFilehandle } from 'generic-filehandle2'
|
|
13
13
|
|
|
14
|
-
function isASCII(str: string) {
|
|
15
|
-
// eslint-disable-next-line no-control-regex
|
|
16
|
-
return /^[\u0000-\u007F]*$/.test(str)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
14
|
type GetLinesCallback = (line: string, fileOffset: number) => void
|
|
20
15
|
|
|
21
16
|
interface GetLinesOpts {
|
|
@@ -35,6 +30,9 @@ export default class TabixIndexedFile {
|
|
|
35
30
|
private index: IndexFile
|
|
36
31
|
private renameRefSeq: (n: string) => string
|
|
37
32
|
private chunkCache: AbortablePromiseCache<Chunk, ReadChunk>
|
|
33
|
+
public cache = new LRU<string, { buffer: Uint8Array; nextIn: number }>({
|
|
34
|
+
maxSize: 1000,
|
|
35
|
+
})
|
|
38
36
|
|
|
39
37
|
/**
|
|
40
38
|
* @param {object} args
|
|
@@ -161,6 +159,21 @@ export default class TabixIndexedFile {
|
|
|
161
159
|
* @returns promise that is resolved when the whole read is finished,
|
|
162
160
|
* rejected on error
|
|
163
161
|
*/
|
|
162
|
+
private calculateFileOffset(
|
|
163
|
+
cpositions: number[],
|
|
164
|
+
dpositions: number[],
|
|
165
|
+
pos: number,
|
|
166
|
+
blockStart: number,
|
|
167
|
+
minvDataPosition: number,
|
|
168
|
+
) {
|
|
169
|
+
return (
|
|
170
|
+
cpositions[pos]! * (1 << 8) +
|
|
171
|
+
(blockStart - dpositions[pos]!) +
|
|
172
|
+
minvDataPosition +
|
|
173
|
+
1
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
164
177
|
async getLines(
|
|
165
178
|
refName: string,
|
|
166
179
|
s: number | undefined,
|
|
@@ -209,69 +222,104 @@ export default class TabixIndexedFile {
|
|
|
209
222
|
let pos = 0
|
|
210
223
|
|
|
211
224
|
// fast path, Buffer is just ASCII chars and not gigantor, can be
|
|
212
|
-
// converted to string and processed directly.
|
|
213
|
-
//
|
|
225
|
+
// converted to string and processed directly.
|
|
226
|
+
//
|
|
227
|
+
// if it is not ASCII or, we have to decode line by line, as it is
|
|
228
|
+
// otherwise hard to get the right 'fileOffset' based feature IDs
|
|
229
|
+
//
|
|
230
|
+
// we use a basic check for isASCII: string length equals buffer length
|
|
231
|
+
// if it is ASCII...no multi-byte decodings
|
|
214
232
|
const str = decoder.decode(buffer)
|
|
215
|
-
const strIsASCII =
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (strIsASCII) {
|
|
220
|
-
n = str.indexOf('\n', blockStart)
|
|
233
|
+
const strIsASCII = buffer.length == str.length
|
|
234
|
+
if (strIsASCII) {
|
|
235
|
+
while (blockStart < str.length) {
|
|
236
|
+
const n = str.indexOf('\n', blockStart)
|
|
221
237
|
if (n === -1) {
|
|
222
238
|
break
|
|
223
239
|
}
|
|
224
|
-
line = str.slice(blockStart, n)
|
|
225
|
-
|
|
226
|
-
|
|
240
|
+
const line = str.slice(blockStart, n)
|
|
241
|
+
|
|
242
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
243
|
+
if (dpositions) {
|
|
244
|
+
const target = blockStart + c.minv.dataPosition
|
|
245
|
+
while (pos < dpositions.length && target >= dpositions[pos]!) {
|
|
246
|
+
pos++
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// filter the line for whether it is within the requested range
|
|
251
|
+
const { startCoordinate, overlaps } = this.checkLine(
|
|
252
|
+
metadata,
|
|
253
|
+
refName,
|
|
254
|
+
start,
|
|
255
|
+
end,
|
|
256
|
+
line,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
if (overlaps) {
|
|
260
|
+
callback(
|
|
261
|
+
line,
|
|
262
|
+
this.calculateFileOffset(
|
|
263
|
+
cpositions,
|
|
264
|
+
dpositions,
|
|
265
|
+
pos,
|
|
266
|
+
blockStart,
|
|
267
|
+
c.minv.dataPosition,
|
|
268
|
+
),
|
|
269
|
+
)
|
|
270
|
+
} else if (startCoordinate !== undefined && startCoordinate >= end) {
|
|
271
|
+
// the lines were overlapping the region, but now have stopped, so we
|
|
272
|
+
// must be at the end of the relevant data and we can stop processing
|
|
273
|
+
// data now
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
blockStart = n + 1
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
while (blockStart < buffer.length) {
|
|
280
|
+
const n = buffer.indexOf('\n'.charCodeAt(0), blockStart)
|
|
227
281
|
if (n === -1) {
|
|
228
282
|
break
|
|
229
283
|
}
|
|
230
284
|
const b = buffer.slice(blockStart, n)
|
|
231
|
-
line = decoder.decode(b)
|
|
232
|
-
}
|
|
285
|
+
const line = decoder.decode(b)
|
|
233
286
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
287
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
288
|
+
if (dpositions) {
|
|
289
|
+
const target = blockStart + c.minv.dataPosition
|
|
290
|
+
while (pos < dpositions.length && target >= dpositions[pos]!) {
|
|
291
|
+
pos++
|
|
292
|
+
}
|
|
293
|
+
}
|
|
239
294
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
line,
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
if (overlaps) {
|
|
250
|
-
callback(
|
|
295
|
+
// filter the line for whether it is within the requested range
|
|
296
|
+
const { startCoordinate, overlaps } = this.checkLine(
|
|
297
|
+
metadata,
|
|
298
|
+
refName,
|
|
299
|
+
start,
|
|
300
|
+
end,
|
|
251
301
|
line,
|
|
252
|
-
// cpositions[pos] refers to actual file offset of a bgzip block
|
|
253
|
-
// boundaries
|
|
254
|
-
//
|
|
255
|
-
// we multiply by (1 <<8) in order to make sure each block has a
|
|
256
|
-
// "unique" address space so that data in that block could never
|
|
257
|
-
// overlap
|
|
258
|
-
//
|
|
259
|
-
// then the blockStart-dpositions is an uncompressed file offset
|
|
260
|
-
// from that bgzip block boundary, and since the cpositions are
|
|
261
|
-
// multiplied by (1 << 8) these uncompressed offsets get a unique
|
|
262
|
-
// space
|
|
263
|
-
cpositions[pos]! * (1 << 8) +
|
|
264
|
-
(blockStart - dpositions[pos]!) +
|
|
265
|
-
c.minv.dataPosition +
|
|
266
|
-
1,
|
|
267
302
|
)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
303
|
+
|
|
304
|
+
if (overlaps) {
|
|
305
|
+
callback(
|
|
306
|
+
line,
|
|
307
|
+
this.calculateFileOffset(
|
|
308
|
+
cpositions,
|
|
309
|
+
dpositions,
|
|
310
|
+
pos,
|
|
311
|
+
blockStart,
|
|
312
|
+
c.minv.dataPosition,
|
|
313
|
+
),
|
|
314
|
+
)
|
|
315
|
+
} else if (startCoordinate !== undefined && startCoordinate >= end) {
|
|
316
|
+
// the lines were overlapping the region, but now have stopped, so we
|
|
317
|
+
// must be at the end of the relevant data and we can stop processing
|
|
318
|
+
// data now
|
|
319
|
+
return
|
|
320
|
+
}
|
|
321
|
+
blockStart = n + 1
|
|
273
322
|
}
|
|
274
|
-
blockStart = n + 1
|
|
275
323
|
}
|
|
276
324
|
}
|
|
277
325
|
}
|
|
@@ -303,11 +351,13 @@ export default class TabixIndexedFile {
|
|
|
303
351
|
let lastNewline = -1
|
|
304
352
|
const newlineByte = '\n'.charCodeAt(0)
|
|
305
353
|
const metaByte = metaChar.charCodeAt(0)
|
|
306
|
-
|
|
307
|
-
|
|
354
|
+
|
|
355
|
+
for (let i = 0, l = bytes.length; i < l; i++) {
|
|
356
|
+
const byte = bytes[i]
|
|
357
|
+
if (i === lastNewline + 1 && byte !== metaByte) {
|
|
308
358
|
break
|
|
309
359
|
}
|
|
310
|
-
if (
|
|
360
|
+
if (byte === newlineByte) {
|
|
311
361
|
lastNewline = i
|
|
312
362
|
}
|
|
313
363
|
}
|
|
@@ -402,7 +452,10 @@ export default class TabixIndexedFile {
|
|
|
402
452
|
}
|
|
403
453
|
}
|
|
404
454
|
} else if (currentColumnNumber === start) {
|
|
405
|
-
startCoordinate = parseInt(
|
|
455
|
+
startCoordinate = Number.parseInt(
|
|
456
|
+
line.slice(currentColumnStart, i),
|
|
457
|
+
10,
|
|
458
|
+
)
|
|
406
459
|
// we convert to 0-based-half-open
|
|
407
460
|
if (coordinateType === '1-based-closed') {
|
|
408
461
|
startCoordinate -= 1
|
|
@@ -413,13 +466,13 @@ export default class TabixIndexedFile {
|
|
|
413
466
|
overlaps: false,
|
|
414
467
|
}
|
|
415
468
|
}
|
|
416
|
-
if (
|
|
417
|
-
// if we have no end, we assume the feature is 1 bp long
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
469
|
+
if (
|
|
470
|
+
(end === 0 || end === start) && // if we have no end, we assume the feature is 1 bp long
|
|
471
|
+
startCoordinate + 1 <= regionStart
|
|
472
|
+
) {
|
|
473
|
+
return {
|
|
474
|
+
startCoordinate,
|
|
475
|
+
overlaps: false,
|
|
423
476
|
}
|
|
424
477
|
}
|
|
425
478
|
} else if (format === 'VCF' && currentColumnNumber === 4) {
|
|
@@ -440,11 +493,11 @@ export default class TabixIndexedFile {
|
|
|
440
493
|
}
|
|
441
494
|
}
|
|
442
495
|
}
|
|
443
|
-
|
|
444
|
-
currentColumnNumber += 1
|
|
445
|
-
if (currentColumnNumber > maxColumn) {
|
|
496
|
+
if (currentColumnNumber === maxColumn) {
|
|
446
497
|
break
|
|
447
498
|
}
|
|
499
|
+
currentColumnStart = i + 1
|
|
500
|
+
currentColumnNumber += 1
|
|
448
501
|
}
|
|
449
502
|
}
|
|
450
503
|
return {
|
|
@@ -462,17 +515,10 @@ export default class TabixIndexedFile {
|
|
|
462
515
|
// be another pairwise feature at the end of this one
|
|
463
516
|
const isTRA = info.includes('SVTYPE=TRA')
|
|
464
517
|
if (info[0] !== '.' && !isTRA) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
if (valueEnd === -1) {
|
|
470
|
-
valueEnd = info.length
|
|
471
|
-
}
|
|
472
|
-
endCoordinate = parseInt(info.slice(j + 4, valueEnd), 10)
|
|
473
|
-
break
|
|
474
|
-
}
|
|
475
|
-
prevChar = info[j]
|
|
518
|
+
const endRegex = /(?:^|;)END=([^;]+)/
|
|
519
|
+
const match = endRegex.exec(info)
|
|
520
|
+
if (match) {
|
|
521
|
+
endCoordinate = Number.parseInt(match[1]!, 10)
|
|
476
522
|
}
|
|
477
523
|
} else if (isTRA) {
|
|
478
524
|
return startCoordinate + 1
|
|
@@ -502,6 +548,6 @@ export default class TabixIndexedFile {
|
|
|
502
548
|
c.minv.blockPosition,
|
|
503
549
|
opts,
|
|
504
550
|
)
|
|
505
|
-
return unzipChunkSlice(ret, c)
|
|
551
|
+
return unzipChunkSlice(ret, c, this.cache)
|
|
506
552
|
}
|
|
507
553
|
}
|
package/src/tbi.ts
CHANGED
|
@@ -75,7 +75,7 @@ export default class TabixIndex extends IndexFile {
|
|
|
75
75
|
const depth = 5
|
|
76
76
|
const maxBinNumber = ((1 << ((depth + 1) * 3)) - 1) / 7
|
|
77
77
|
const maxRefLength = 2 ** (14 + depth * 3)
|
|
78
|
-
const metaChar = metaValue ? String.fromCharCode(metaValue) :
|
|
78
|
+
const metaChar = metaValue ? String.fromCharCode(metaValue) : undefined
|
|
79
79
|
const skipLines = dataView.getInt32(28, true)
|
|
80
80
|
|
|
81
81
|
// read sequence dictionary
|
|
@@ -160,31 +160,6 @@ export default class TabixIndex extends IndexFile {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
_parseNameBytes(namesBytes: Uint8Array) {
|
|
164
|
-
let currRefId = 0
|
|
165
|
-
let currNameStart = 0
|
|
166
|
-
const refIdToName: string[] = []
|
|
167
|
-
const refNameToId: Record<string, number> = {}
|
|
168
|
-
const decoder = new TextDecoder('utf8')
|
|
169
|
-
for (let i = 0; i < namesBytes.length; i += 1) {
|
|
170
|
-
if (!namesBytes[i]) {
|
|
171
|
-
if (currNameStart < i) {
|
|
172
|
-
const refName = this.renameRefSeq(
|
|
173
|
-
decoder.decode(namesBytes.subarray(currNameStart, i)),
|
|
174
|
-
)
|
|
175
|
-
refIdToName[currRefId] = refName
|
|
176
|
-
refNameToId[refName] = currRefId
|
|
177
|
-
}
|
|
178
|
-
currNameStart = i + 1
|
|
179
|
-
currRefId += 1
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return {
|
|
183
|
-
refNameToId,
|
|
184
|
-
refIdToName,
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
163
|
async blocksForRange(
|
|
189
164
|
refName: string,
|
|
190
165
|
min: number,
|
|
@@ -205,13 +180,14 @@ export default class TabixIndex extends IndexFile {
|
|
|
205
180
|
return []
|
|
206
181
|
}
|
|
207
182
|
|
|
208
|
-
const minOffset =
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
183
|
+
const minOffset =
|
|
184
|
+
ba.linearIndex.length > 0
|
|
185
|
+
? ba.linearIndex[
|
|
186
|
+
min >> TAD_LIDX_SHIFT >= ba.linearIndex.length
|
|
187
|
+
? ba.linearIndex.length - 1
|
|
188
|
+
: min >> TAD_LIDX_SHIFT
|
|
189
|
+
]
|
|
190
|
+
: new VirtualOffset(0, 0)
|
|
215
191
|
if (!minOffset) {
|
|
216
192
|
console.warn('querying outside of possible tabix range')
|
|
217
193
|
}
|
|
@@ -235,15 +211,13 @@ export default class TabixIndex extends IndexFile {
|
|
|
235
211
|
// Use the linear index to find minimum file position of chunks that could
|
|
236
212
|
// contain alignments in the region
|
|
237
213
|
const nintv = ba.linearIndex.length
|
|
238
|
-
let lowest
|
|
214
|
+
let lowest: VirtualOffset | undefined
|
|
239
215
|
const minLin = Math.min(min >> 14, nintv - 1)
|
|
240
216
|
const maxLin = Math.min(max >> 14, nintv - 1)
|
|
241
217
|
for (let i = minLin; i <= maxLin; ++i) {
|
|
242
218
|
const vp = ba.linearIndex[i]
|
|
243
|
-
if (vp) {
|
|
244
|
-
|
|
245
|
-
lowest = vp
|
|
246
|
-
}
|
|
219
|
+
if (vp && (!lowest || vp.compareTo(lowest) < 0)) {
|
|
220
|
+
lowest = vp
|
|
247
221
|
}
|
|
248
222
|
}
|
|
249
223
|
|
package/src/util.ts
CHANGED
|
@@ -22,12 +22,12 @@ export function checkAbortSignal(signal?: AbortSignal) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
if (signal.aborted) {
|
|
25
|
-
if (typeof DOMException
|
|
26
|
-
throw new DOMException('aborted', 'AbortError')
|
|
27
|
-
} else {
|
|
25
|
+
if (typeof DOMException === 'undefined') {
|
|
28
26
|
const e = new AbortError('aborted')
|
|
29
27
|
e.code = 'ERR_ABORTED'
|
|
30
28
|
throw e
|
|
29
|
+
} else {
|
|
30
|
+
throw new DOMException('aborted', 'AbortError')
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -52,7 +52,7 @@ export function canMergeBlocks(chunk1: Chunk, chunk2: Chunk) {
|
|
|
52
52
|
|
|
53
53
|
export function optimizeChunks(chunks: Chunk[], lowest?: VirtualOffset) {
|
|
54
54
|
const mergedChunks: Chunk[] = []
|
|
55
|
-
let lastChunk: Chunk |
|
|
55
|
+
let lastChunk: Chunk | undefined
|
|
56
56
|
|
|
57
57
|
if (chunks.length === 0) {
|
|
58
58
|
return chunks
|
|
@@ -60,12 +60,12 @@ export function optimizeChunks(chunks: Chunk[], lowest?: VirtualOffset) {
|
|
|
60
60
|
|
|
61
61
|
chunks.sort(function (c0, c1) {
|
|
62
62
|
const dif = c0.minv.blockPosition - c1.minv.blockPosition
|
|
63
|
-
return dif
|
|
63
|
+
return dif === 0 ? c0.minv.dataPosition - c1.minv.dataPosition : dif
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
for (const chunk of chunks) {
|
|
67
67
|
if (!lowest || chunk.maxv.compareTo(lowest) > 0) {
|
|
68
|
-
if (lastChunk ===
|
|
68
|
+
if (lastChunk === undefined) {
|
|
69
69
|
mergedChunks.push(chunk)
|
|
70
70
|
lastChunk = chunk
|
|
71
71
|
} else {
|
|
@@ -79,7 +79,7 @@ export function optimizeChunks(chunks: Chunk[], lowest?: VirtualOffset) {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
}
|
|
82
|
+
}
|
|
83
83
|
|
|
84
84
|
return mergedChunks
|
|
85
85
|
}
|