@gmod/bbi 5.0.1 → 6.0.0
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 +8 -0
- package/README.md +5 -5
- package/dist/bbi.d.ts +15 -16
- package/dist/bbi.js +195 -220
- package/dist/bbi.js.map +1 -1
- package/dist/bigbed.js +138 -159
- package/dist/bigbed.js.map +1 -1
- package/dist/bigwig.js +11 -21
- package/dist/bigwig.js.map +1 -1
- package/dist/block-view.d.ts +2 -3
- package/dist/block-view.js +190 -205
- package/dist/block-view.js.map +1 -1
- package/dist/unzip-pako.d.ts +1 -2
- package/dist/unzip-pako.js.map +1 -1
- package/dist/util.js +3 -14
- package/dist/util.js.map +1 -1
- package/esm/bbi.d.ts +15 -16
- package/esm/bbi.js +66 -70
- package/esm/bbi.js.map +1 -1
- package/esm/bigbed.js +47 -40
- package/esm/bigbed.js.map +1 -1
- package/esm/bigwig.js +3 -2
- package/esm/bigwig.js.map +1 -1
- package/esm/block-view.d.ts +2 -3
- package/esm/block-view.js +36 -41
- package/esm/block-view.js.map +1 -1
- package/esm/unzip-pako.d.ts +1 -2
- package/esm/unzip-pako.js.map +1 -1
- package/package.json +14 -18
- package/src/bbi.ts +78 -99
- package/src/bigbed.ts +47 -62
- package/src/bigwig.ts +2 -2
- package/src/block-view.ts +46 -57
- package/src/unzip-pako.ts +1 -2
package/src/block-view.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Buffer } from 'buffer'
|
|
2
1
|
import { Observer } from 'rxjs'
|
|
3
2
|
import AbortablePromiseCache from '@gmod/abortable-promise-cache'
|
|
4
|
-
import { GenericFilehandle } from 'generic-
|
|
3
|
+
import { GenericFilehandle } from 'generic-filehandle2'
|
|
5
4
|
import QuickLRU from 'quick-lru'
|
|
6
5
|
|
|
7
6
|
// locals
|
|
@@ -10,6 +9,9 @@ import { unzip } from './unzip'
|
|
|
10
9
|
import { Feature } from './bbi'
|
|
11
10
|
import { groupBlocks, checkAbortSignal } from './util'
|
|
12
11
|
|
|
12
|
+
const decoder =
|
|
13
|
+
typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined
|
|
14
|
+
|
|
13
15
|
interface CoordRequest {
|
|
14
16
|
chrId: number
|
|
15
17
|
start: number
|
|
@@ -39,18 +41,15 @@ function coordFilter(s1: number, e1: number, s2: number, e2: number): boolean {
|
|
|
39
41
|
*/
|
|
40
42
|
|
|
41
43
|
export class BlockView {
|
|
42
|
-
private cirTreePromise?: Promise<
|
|
44
|
+
private cirTreePromise?: Promise<Uint8Array>
|
|
43
45
|
|
|
44
|
-
private featureCache = new AbortablePromiseCache<ReadData,
|
|
46
|
+
private featureCache = new AbortablePromiseCache<ReadData, Uint8Array>({
|
|
45
47
|
cache: new QuickLRU({ maxSize: 1000 }),
|
|
46
48
|
|
|
47
49
|
fill: async (requestData, signal) => {
|
|
48
|
-
|
|
49
|
-
const off = requestData.offset
|
|
50
|
-
const { buffer } = await this.bbi.read(Buffer.alloc(len), 0, len, off, {
|
|
50
|
+
return this.bbi.read(requestData.length, requestData.offset, {
|
|
51
51
|
signal,
|
|
52
52
|
})
|
|
53
|
-
return buffer
|
|
54
53
|
},
|
|
55
54
|
})
|
|
56
55
|
|
|
@@ -58,7 +57,6 @@ export class BlockView {
|
|
|
58
57
|
private bbi: GenericFilehandle,
|
|
59
58
|
private refsByName: any,
|
|
60
59
|
private cirTreeOffset: number,
|
|
61
|
-
private isBigEndian: boolean,
|
|
62
60
|
private isCompressed: boolean,
|
|
63
61
|
private blockType: string,
|
|
64
62
|
) {
|
|
@@ -75,31 +73,23 @@ export class BlockView {
|
|
|
75
73
|
opts?: Options,
|
|
76
74
|
) {
|
|
77
75
|
try {
|
|
78
|
-
const { refsByName, bbi, cirTreeOffset
|
|
76
|
+
const { refsByName, bbi, cirTreeOffset } = this
|
|
79
77
|
const chrId = refsByName[chrName]
|
|
80
78
|
if (chrId === undefined) {
|
|
81
79
|
observer.complete()
|
|
82
80
|
}
|
|
83
81
|
const request = { chrId, start, end }
|
|
84
82
|
if (!this.cirTreePromise) {
|
|
85
|
-
this.cirTreePromise = bbi.read(
|
|
86
|
-
Buffer.alloc(48),
|
|
87
|
-
0,
|
|
88
|
-
48,
|
|
89
|
-
cirTreeOffset,
|
|
90
|
-
opts,
|
|
91
|
-
)
|
|
83
|
+
this.cirTreePromise = bbi.read(48, cirTreeOffset, opts)
|
|
92
84
|
}
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
: buffer.readUInt32LE(4)
|
|
85
|
+
const buffer = await this.cirTreePromise
|
|
86
|
+
const dataView = new DataView(buffer.buffer)
|
|
87
|
+
const cirBlockSize = dataView.getUint32(4, true)
|
|
97
88
|
let blocksToFetch: any[] = []
|
|
98
89
|
let outstanding = 0
|
|
99
|
-
const le = true
|
|
100
90
|
|
|
101
91
|
const cirFobRecur2 = (
|
|
102
|
-
cirBlockData:
|
|
92
|
+
cirBlockData: Uint8Array,
|
|
103
93
|
offset2: number,
|
|
104
94
|
level: number,
|
|
105
95
|
) => {
|
|
@@ -112,22 +102,22 @@ export class BlockView {
|
|
|
112
102
|
|
|
113
103
|
const isLeaf = dataView.getUint8(offset)
|
|
114
104
|
offset += 2 // 1 skip
|
|
115
|
-
const cnt = dataView.getUint16(offset,
|
|
105
|
+
const cnt = dataView.getUint16(offset, true)
|
|
116
106
|
offset += 2
|
|
117
107
|
if (isLeaf === 1) {
|
|
118
108
|
const blocksToFetch2 = []
|
|
119
109
|
for (let i = 0; i < cnt; i++) {
|
|
120
|
-
const startChrom = dataView.getUint32(offset,
|
|
110
|
+
const startChrom = dataView.getUint32(offset, true)
|
|
121
111
|
offset += 4
|
|
122
|
-
const startBase = dataView.getUint32(offset,
|
|
112
|
+
const startBase = dataView.getUint32(offset, true)
|
|
123
113
|
offset += 4
|
|
124
|
-
const endChrom = dataView.getUint32(offset,
|
|
114
|
+
const endChrom = dataView.getUint32(offset, true)
|
|
125
115
|
offset += 4
|
|
126
|
-
const endBase = dataView.getUint32(offset,
|
|
116
|
+
const endBase = dataView.getUint32(offset, true)
|
|
127
117
|
offset += 4
|
|
128
|
-
const blockOffset = Number(dataView.getBigUint64(offset,
|
|
118
|
+
const blockOffset = Number(dataView.getBigUint64(offset, true))
|
|
129
119
|
offset += 8
|
|
130
|
-
const blockSize = Number(dataView.getBigUint64(offset,
|
|
120
|
+
const blockSize = Number(dataView.getBigUint64(offset, true))
|
|
131
121
|
offset += 8
|
|
132
122
|
blocksToFetch2.push({
|
|
133
123
|
startChrom,
|
|
@@ -150,15 +140,15 @@ export class BlockView {
|
|
|
150
140
|
} else if (isLeaf === 0) {
|
|
151
141
|
const recurOffsets = []
|
|
152
142
|
for (let i = 0; i < cnt; i++) {
|
|
153
|
-
const startChrom = dataView.getUint32(offset,
|
|
143
|
+
const startChrom = dataView.getUint32(offset, true)
|
|
154
144
|
offset += 4
|
|
155
|
-
const startBase = dataView.getUint32(offset,
|
|
145
|
+
const startBase = dataView.getUint32(offset, true)
|
|
156
146
|
offset += 4
|
|
157
|
-
const endChrom = dataView.getUint32(offset,
|
|
147
|
+
const endChrom = dataView.getUint32(offset, true)
|
|
158
148
|
offset += 4
|
|
159
|
-
const endBase = dataView.getUint32(offset,
|
|
149
|
+
const endBase = dataView.getUint32(offset, true)
|
|
160
150
|
offset += 4
|
|
161
|
-
const blockOffset = Number(dataView.getBigUint64(offset,
|
|
151
|
+
const blockOffset = Number(dataView.getBigUint64(offset, true))
|
|
162
152
|
offset += 8
|
|
163
153
|
recurOffsets.push({
|
|
164
154
|
startChrom,
|
|
@@ -202,7 +192,7 @@ export class BlockView {
|
|
|
202
192
|
try {
|
|
203
193
|
const length = fr.max - fr.min
|
|
204
194
|
const offset = fr.min
|
|
205
|
-
const resultBuffer
|
|
195
|
+
const resultBuffer = await this.featureCache.get(
|
|
206
196
|
`${length}_${offset}`,
|
|
207
197
|
{ length, offset },
|
|
208
198
|
opts?.signal,
|
|
@@ -215,7 +205,9 @@ export class BlockView {
|
|
|
215
205
|
this.readFeatures(observer, blocksToFetch, {
|
|
216
206
|
...opts,
|
|
217
207
|
request,
|
|
218
|
-
}).catch(e =>
|
|
208
|
+
}).catch((e: unknown) => {
|
|
209
|
+
observer.error(e)
|
|
210
|
+
})
|
|
219
211
|
}
|
|
220
212
|
}
|
|
221
213
|
}
|
|
@@ -251,14 +243,15 @@ export class BlockView {
|
|
|
251
243
|
}
|
|
252
244
|
}
|
|
253
245
|
|
|
254
|
-
|
|
246
|
+
cirFobRecur([Number(cirTreeOffset) + 48], 1)
|
|
247
|
+
return
|
|
255
248
|
} catch (e) {
|
|
256
249
|
observer.error(e)
|
|
257
250
|
}
|
|
258
251
|
}
|
|
259
252
|
|
|
260
253
|
private parseSummaryBlock(
|
|
261
|
-
b:
|
|
254
|
+
b: Uint8Array,
|
|
262
255
|
startOffset: number,
|
|
263
256
|
request?: CoordRequest,
|
|
264
257
|
) {
|
|
@@ -308,23 +301,22 @@ export class BlockView {
|
|
|
308
301
|
}
|
|
309
302
|
|
|
310
303
|
private parseBigBedBlock(
|
|
311
|
-
data:
|
|
304
|
+
data: Uint8Array,
|
|
312
305
|
startOffset: number,
|
|
313
306
|
offset: number,
|
|
314
307
|
request?: CoordRequest,
|
|
315
308
|
) {
|
|
316
309
|
const items = [] as Feature[]
|
|
317
310
|
let currOffset = startOffset
|
|
318
|
-
const le = true
|
|
319
311
|
const b = data
|
|
320
312
|
const dataView = new DataView(b.buffer, b.byteOffset, b.length)
|
|
321
313
|
while (currOffset < data.byteLength) {
|
|
322
314
|
const c2 = currOffset
|
|
323
|
-
const chromId = dataView.getUint32(currOffset,
|
|
315
|
+
const chromId = dataView.getUint32(currOffset, true)
|
|
324
316
|
currOffset += 4
|
|
325
|
-
const start = dataView.getInt32(currOffset,
|
|
317
|
+
const start = dataView.getInt32(currOffset, true)
|
|
326
318
|
currOffset += 4
|
|
327
|
-
const end = dataView.getInt32(currOffset,
|
|
319
|
+
const end = dataView.getInt32(currOffset, true)
|
|
328
320
|
currOffset += 4
|
|
329
321
|
let i = currOffset
|
|
330
322
|
for (; i < data.length; i++) {
|
|
@@ -332,7 +324,8 @@ export class BlockView {
|
|
|
332
324
|
break
|
|
333
325
|
}
|
|
334
326
|
}
|
|
335
|
-
const
|
|
327
|
+
const b = data.subarray(currOffset, i)
|
|
328
|
+
const rest = decoder?.decode(b) ?? b.toString()
|
|
336
329
|
currOffset = i + 1
|
|
337
330
|
items.push({
|
|
338
331
|
chromId,
|
|
@@ -351,7 +344,7 @@ export class BlockView {
|
|
|
351
344
|
}
|
|
352
345
|
|
|
353
346
|
private parseBigWigBlock(
|
|
354
|
-
buffer:
|
|
347
|
+
buffer: Uint8Array,
|
|
355
348
|
startOffset: number,
|
|
356
349
|
req?: CoordRequest,
|
|
357
350
|
) {
|
|
@@ -443,32 +436,28 @@ export class BlockView {
|
|
|
443
436
|
)
|
|
444
437
|
for (const block of blockGroup.blocks) {
|
|
445
438
|
checkAbortSignal(signal)
|
|
446
|
-
let
|
|
447
|
-
|
|
439
|
+
let resultData = data.subarray(
|
|
440
|
+
Number(block.offset) - Number(blockGroup.offset),
|
|
441
|
+
)
|
|
448
442
|
if (isCompressed) {
|
|
449
|
-
resultData = unzip(
|
|
450
|
-
blockOffset = 0
|
|
443
|
+
resultData = unzip(resultData)
|
|
451
444
|
}
|
|
452
445
|
checkAbortSignal(signal)
|
|
453
446
|
|
|
454
447
|
switch (blockType) {
|
|
455
448
|
case 'summary': {
|
|
456
|
-
observer.next(
|
|
457
|
-
this.parseSummaryBlock(resultData, blockOffset, request),
|
|
458
|
-
)
|
|
449
|
+
observer.next(this.parseSummaryBlock(resultData, 0, request))
|
|
459
450
|
break
|
|
460
451
|
}
|
|
461
452
|
case 'bigwig': {
|
|
462
|
-
observer.next(
|
|
463
|
-
this.parseBigWigBlock(resultData, blockOffset, request),
|
|
464
|
-
)
|
|
453
|
+
observer.next(this.parseBigWigBlock(resultData, 0, request))
|
|
465
454
|
break
|
|
466
455
|
}
|
|
467
456
|
case 'bigbed': {
|
|
468
457
|
observer.next(
|
|
469
458
|
this.parseBigBedBlock(
|
|
470
459
|
resultData,
|
|
471
|
-
|
|
460
|
+
0,
|
|
472
461
|
Number(block.offset) * (1 << 8),
|
|
473
462
|
request,
|
|
474
463
|
),
|