@gmod/bbi 5.0.2 → 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/src/bigbed.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { Buffer } from 'buffer'
2
1
  import { Observable, merge, firstValueFrom } from 'rxjs'
3
2
  import { map, reduce } from 'rxjs/operators'
4
3
  import AbortablePromiseCache from '@gmod/abortable-promise-cache'
@@ -52,23 +51,16 @@ export class BigBed extends BBI {
52
51
  * multiple extraIndexes in a bigbed, see bedToBigBed documentation
53
52
  */
54
53
  private async _readIndices(opts: RequestOptions) {
55
- const { extHeaderOffset, isBigEndian } = await this.getHeader(opts)
56
- const { buffer: data } = await this.bbi.read(
57
- Buffer.alloc(64),
58
- 0,
59
- 64,
60
- Number(extHeaderOffset),
61
- )
62
- const le = !isBigEndian
63
-
64
- const b = data
54
+ const { extHeaderOffset } = await this.getHeader(opts)
55
+ const b = await this.bbi.read(64, Number(extHeaderOffset))
56
+
65
57
  const dataView = new DataView(b.buffer, b.byteOffset, b.length)
66
58
  let offset = 0
67
- // const _size = dataView.getUint16(offset, le)
59
+ // const _size = dataView.getUint16(offset, true)
68
60
  offset += 2
69
- const count = dataView.getUint16(offset, le)
61
+ const count = dataView.getUint16(offset, true)
70
62
  offset += 2
71
- const dataOffset = Number(dataView.getBigUint64(offset, le))
63
+ const dataOffset = Number(dataView.getBigUint64(offset, true))
72
64
  offset += 8
73
65
 
74
66
  // no extra index is defined if count==0
@@ -78,12 +70,7 @@ export class BigBed extends BBI {
78
70
 
79
71
  const blocklen = 20
80
72
  const len = blocklen * count
81
- const { buffer } = await this.bbi.read(
82
- Buffer.alloc(len),
83
- 0,
84
- len,
85
- Number(dataOffset),
86
- )
73
+ const buffer = await this.bbi.read(len, Number(dataOffset))
87
74
 
88
75
  const indices = [] as Index[]
89
76
 
@@ -91,13 +78,13 @@ export class BigBed extends BBI {
91
78
  const b = buffer.subarray(i * blocklen)
92
79
  const dataView = new DataView(b.buffer, b.byteOffset, b.length)
93
80
  let offset = 0
94
- const type = dataView.getInt16(offset, le)
81
+ const type = dataView.getInt16(offset, true)
95
82
  offset += 2
96
- const fieldcount = dataView.getInt16(offset, le)
83
+ const fieldcount = dataView.getInt16(offset, true)
97
84
  offset += 2
98
- const dataOffset = Number(dataView.getBigUint64(offset, le))
85
+ const dataOffset = Number(dataView.getBigUint64(offset, true))
99
86
  offset += 8 + 4 //4 skip
100
- const field = dataView.getInt16(offset, le)
87
+ const field = dataView.getInt16(offset, true)
101
88
  indices.push({ type, fieldcount, offset: Number(dataOffset), field })
102
89
  }
103
90
  return indices
@@ -108,72 +95,62 @@ export class BigBed extends BBI {
108
95
  * bigbed data to look for the actual feature data
109
96
  *
110
97
  * @param name - the name to search for
98
+ *
111
99
  * @param opts - a SearchOptions argument with optional signal
100
+ *
112
101
  * @return a Promise for an array of bigbed block Loc entries
113
102
  */
114
103
  private async searchExtraIndexBlocks(
115
104
  name: string,
116
105
  opts: RequestOptions = {},
117
106
  ): Promise<Loc[]> {
118
- const { isBigEndian } = await this.getHeader(opts)
119
107
  const indices = await this.readIndices(opts)
120
108
  if (indices.length === 0) {
121
109
  return []
122
110
  }
111
+ const decoder = new TextDecoder('utf8')
123
112
  const locs = indices.map(async (index): Promise<Loc | undefined> => {
124
113
  const { offset: offset2, field } = index
125
- const { buffer: data } = await this.bbi.read(
126
- Buffer.alloc(32),
127
- 0,
128
- 32,
129
- offset2,
130
- opts,
131
- )
132
- const le = !isBigEndian
133
- const b = data
114
+ const b = await this.bbi.read(32, offset2, opts)
134
115
 
135
116
  const dataView = new DataView(b.buffer, b.byteOffset, b.length)
136
117
  let offset = 0
137
- // const _magic = dataView.getInt32(offset, le)
118
+ // const _magic = dataView.getInt32(offset, true)
138
119
  offset += 4
139
- const blockSize = dataView.getInt32(offset, le)
120
+ const blockSize = dataView.getInt32(offset, true)
140
121
  offset += 4
141
- const keySize = dataView.getInt32(offset, le)
122
+ const keySize = dataView.getInt32(offset, true)
142
123
  offset += 4
143
- const valSize = dataView.getInt32(offset, le)
124
+ const valSize = dataView.getInt32(offset, true)
144
125
  offset += 4
145
- // const _itemCount = Number(dataView.getBigUint64(offset, le))
126
+ // const _itemCount = Number(dataView.getBigUint64(offset, true))
146
127
  offset += 8
147
128
 
148
129
  const bptReadNode = async (nodeOffset: number) => {
149
130
  const val = Number(nodeOffset)
150
131
  const len = 4 + blockSize * (keySize + valSize)
151
- const { buffer } = await this.bbi.read(
152
- Buffer.alloc(len),
153
- 0,
154
- len,
155
- val,
156
- opts,
157
- )
132
+ const buffer = await this.bbi.read(len, val, opts)
158
133
  const b = buffer
159
134
  const dataView = new DataView(b.buffer, b.byteOffset, b.length)
160
135
  let offset = 0
161
136
  const nodeType = dataView.getInt8(offset)
162
137
  offset += 2 //skip 1
163
- const cnt = dataView.getInt16(offset, le)
138
+ const cnt = dataView.getInt16(offset, true)
164
139
  offset += 2
165
140
  const keys = []
166
141
  if (nodeType === 0) {
167
142
  const leafkeys = []
168
143
  for (let i = 0; i < cnt; i++) {
169
- const key = b
170
- .subarray(offset, offset + keySize)
171
- .toString()
144
+ const key = decoder
145
+ .decode(b.subarray(offset, offset + keySize))
172
146
  .replaceAll('\0', '')
173
147
  offset += keySize
174
- const dataOffset = Number(dataView.getBigUint64(offset, le))
148
+ const dataOffset = Number(dataView.getBigUint64(offset, true))
175
149
  offset += 8
176
- leafkeys.push({ key, offset: dataOffset })
150
+ leafkeys.push({
151
+ key,
152
+ offset: dataOffset,
153
+ })
177
154
  }
178
155
 
179
156
  let lastOffset = 0
@@ -186,18 +163,22 @@ export class BigBed extends BBI {
186
163
  return bptReadNode(lastOffset)
187
164
  } else if (nodeType === 1) {
188
165
  for (let i = 0; i < cnt; i++) {
189
- const key = b
190
- .subarray(offset, offset + keySize)
191
- .toString()
166
+ const key = decoder
167
+ .decode(b.subarray(offset, offset + keySize))
192
168
  .replaceAll('\0', '')
193
169
  offset += keySize
194
- const dataOffset = Number(dataView.getBigUint64(offset, le))
170
+ const dataOffset = Number(dataView.getBigUint64(offset, true))
195
171
  offset += 8
196
- const length = dataView.getUint32(offset, le)
172
+ const length = dataView.getUint32(offset, true)
197
173
  offset += 4
198
- const reserved = dataView.getUint32(offset, le)
174
+ const reserved = dataView.getUint32(offset, true)
199
175
  offset += 4
200
- keys.push({ key, offset: dataOffset, length, reserved })
176
+ keys.push({
177
+ key,
178
+ offset: dataOffset,
179
+ length,
180
+ reserved,
181
+ })
201
182
  }
202
183
 
203
184
  for (const n of keys) {
@@ -221,8 +202,10 @@ export class BigBed extends BBI {
221
202
  * the BigBed specification and the -extraIndex argument to bedToBigBed
222
203
  *
223
204
  * @param name - the name to search for
224
- * @param opts - a SearchOptions argument with optional signal
225
- * @return a Promise for an array of Feature
205
+ *
206
+ * @param opts - options object with optional AboutSignal
207
+ *
208
+ * @return array of Feature
226
209
  */
227
210
  public async searchExtraIndex(name: string, opts: RequestOptions = {}) {
228
211
  const blocks = await this.searchExtraIndexBlocks(name, opts)
package/src/bigwig.ts CHANGED
@@ -11,7 +11,7 @@ export class BigWig extends BBI {
11
11
  * or scale used to infer the zoomLevel to use
12
12
  */
13
13
  protected async getView(scale: number, opts: RequestOptions) {
14
- const { zoomLevels, refsByName, isBigEndian, uncompressBufSize } =
14
+ const { zoomLevels, refsByName, uncompressBufSize } =
15
15
  await this.getHeader(opts)
16
16
  const basesPerPx = 1 / scale
17
17
  const maxLevel = zoomLevels.length - 1
@@ -24,7 +24,6 @@ export class BigWig extends BBI {
24
24
  this.bbi,
25
25
  refsByName,
26
26
  zh.indexOffset,
27
- isBigEndian,
28
27
  uncompressBufSize > 0,
29
28
  'summary',
30
29
  )
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-filehandle'
3
+ import { GenericFilehandle } from 'generic-filehandle2'
5
4
  import QuickLRU from 'quick-lru'
6
5
 
7
6
  // locals
@@ -42,18 +41,15 @@ function coordFilter(s1: number, e1: number, s2: number, e2: number): boolean {
42
41
  */
43
42
 
44
43
  export class BlockView {
45
- private cirTreePromise?: Promise<{ bytesRead: number; buffer: Buffer }>
44
+ private cirTreePromise?: Promise<Uint8Array>
46
45
 
47
- private featureCache = new AbortablePromiseCache<ReadData, Buffer>({
46
+ private featureCache = new AbortablePromiseCache<ReadData, Uint8Array>({
48
47
  cache: new QuickLRU({ maxSize: 1000 }),
49
48
 
50
49
  fill: async (requestData, signal) => {
51
- const len = requestData.length
52
- const off = requestData.offset
53
- const { buffer } = await this.bbi.read(Buffer.alloc(len), 0, len, off, {
50
+ return this.bbi.read(requestData.length, requestData.offset, {
54
51
  signal,
55
52
  })
56
- return buffer
57
53
  },
58
54
  })
59
55
 
@@ -61,7 +57,6 @@ export class BlockView {
61
57
  private bbi: GenericFilehandle,
62
58
  private refsByName: any,
63
59
  private cirTreeOffset: number,
64
- private isBigEndian: boolean,
65
60
  private isCompressed: boolean,
66
61
  private blockType: string,
67
62
  ) {
@@ -78,31 +73,23 @@ export class BlockView {
78
73
  opts?: Options,
79
74
  ) {
80
75
  try {
81
- const { refsByName, bbi, cirTreeOffset, isBigEndian } = this
76
+ const { refsByName, bbi, cirTreeOffset } = this
82
77
  const chrId = refsByName[chrName]
83
78
  if (chrId === undefined) {
84
79
  observer.complete()
85
80
  }
86
81
  const request = { chrId, start, end }
87
82
  if (!this.cirTreePromise) {
88
- this.cirTreePromise = bbi.read(
89
- Buffer.alloc(48),
90
- 0,
91
- 48,
92
- cirTreeOffset,
93
- opts,
94
- )
83
+ this.cirTreePromise = bbi.read(48, cirTreeOffset, opts)
95
84
  }
96
- const { buffer } = await this.cirTreePromise
97
- const cirBlockSize = isBigEndian
98
- ? buffer.readUInt32BE(4)
99
- : buffer.readUInt32LE(4)
85
+ const buffer = await this.cirTreePromise
86
+ const dataView = new DataView(buffer.buffer)
87
+ const cirBlockSize = dataView.getUint32(4, true)
100
88
  let blocksToFetch: any[] = []
101
89
  let outstanding = 0
102
- const le = true
103
90
 
104
91
  const cirFobRecur2 = (
105
- cirBlockData: Buffer,
92
+ cirBlockData: Uint8Array,
106
93
  offset2: number,
107
94
  level: number,
108
95
  ) => {
@@ -115,22 +102,22 @@ export class BlockView {
115
102
 
116
103
  const isLeaf = dataView.getUint8(offset)
117
104
  offset += 2 // 1 skip
118
- const cnt = dataView.getUint16(offset, le)
105
+ const cnt = dataView.getUint16(offset, true)
119
106
  offset += 2
120
107
  if (isLeaf === 1) {
121
108
  const blocksToFetch2 = []
122
109
  for (let i = 0; i < cnt; i++) {
123
- const startChrom = dataView.getUint32(offset, le)
110
+ const startChrom = dataView.getUint32(offset, true)
124
111
  offset += 4
125
- const startBase = dataView.getUint32(offset, le)
112
+ const startBase = dataView.getUint32(offset, true)
126
113
  offset += 4
127
- const endChrom = dataView.getUint32(offset, le)
114
+ const endChrom = dataView.getUint32(offset, true)
128
115
  offset += 4
129
- const endBase = dataView.getUint32(offset, le)
116
+ const endBase = dataView.getUint32(offset, true)
130
117
  offset += 4
131
- const blockOffset = Number(dataView.getBigUint64(offset, le))
118
+ const blockOffset = Number(dataView.getBigUint64(offset, true))
132
119
  offset += 8
133
- const blockSize = Number(dataView.getBigUint64(offset, le))
120
+ const blockSize = Number(dataView.getBigUint64(offset, true))
134
121
  offset += 8
135
122
  blocksToFetch2.push({
136
123
  startChrom,
@@ -153,15 +140,15 @@ export class BlockView {
153
140
  } else if (isLeaf === 0) {
154
141
  const recurOffsets = []
155
142
  for (let i = 0; i < cnt; i++) {
156
- const startChrom = dataView.getUint32(offset, le)
143
+ const startChrom = dataView.getUint32(offset, true)
157
144
  offset += 4
158
- const startBase = dataView.getUint32(offset, le)
145
+ const startBase = dataView.getUint32(offset, true)
159
146
  offset += 4
160
- const endChrom = dataView.getUint32(offset, le)
147
+ const endChrom = dataView.getUint32(offset, true)
161
148
  offset += 4
162
- const endBase = dataView.getUint32(offset, le)
149
+ const endBase = dataView.getUint32(offset, true)
163
150
  offset += 4
164
- const blockOffset = Number(dataView.getBigUint64(offset, le))
151
+ const blockOffset = Number(dataView.getBigUint64(offset, true))
165
152
  offset += 8
166
153
  recurOffsets.push({
167
154
  startChrom,
@@ -205,7 +192,7 @@ export class BlockView {
205
192
  try {
206
193
  const length = fr.max - fr.min
207
194
  const offset = fr.min
208
- const resultBuffer: Buffer = await this.featureCache.get(
195
+ const resultBuffer = await this.featureCache.get(
209
196
  `${length}_${offset}`,
210
197
  { length, offset },
211
198
  opts?.signal,
@@ -264,7 +251,7 @@ export class BlockView {
264
251
  }
265
252
 
266
253
  private parseSummaryBlock(
267
- b: Buffer,
254
+ b: Uint8Array,
268
255
  startOffset: number,
269
256
  request?: CoordRequest,
270
257
  ) {
@@ -314,23 +301,22 @@ export class BlockView {
314
301
  }
315
302
 
316
303
  private parseBigBedBlock(
317
- data: Buffer,
304
+ data: Uint8Array,
318
305
  startOffset: number,
319
306
  offset: number,
320
307
  request?: CoordRequest,
321
308
  ) {
322
309
  const items = [] as Feature[]
323
310
  let currOffset = startOffset
324
- const le = true
325
311
  const b = data
326
312
  const dataView = new DataView(b.buffer, b.byteOffset, b.length)
327
313
  while (currOffset < data.byteLength) {
328
314
  const c2 = currOffset
329
- const chromId = dataView.getUint32(currOffset, le)
315
+ const chromId = dataView.getUint32(currOffset, true)
330
316
  currOffset += 4
331
- const start = dataView.getInt32(currOffset, le)
317
+ const start = dataView.getInt32(currOffset, true)
332
318
  currOffset += 4
333
- const end = dataView.getInt32(currOffset, le)
319
+ const end = dataView.getInt32(currOffset, true)
334
320
  currOffset += 4
335
321
  let i = currOffset
336
322
  for (; i < data.length; i++) {
@@ -358,7 +344,7 @@ export class BlockView {
358
344
  }
359
345
 
360
346
  private parseBigWigBlock(
361
- buffer: Buffer,
347
+ buffer: Uint8Array,
362
348
  startOffset: number,
363
349
  req?: CoordRequest,
364
350
  ) {
@@ -450,32 +436,28 @@ export class BlockView {
450
436
  )
451
437
  for (const block of blockGroup.blocks) {
452
438
  checkAbortSignal(signal)
453
- let blockOffset = Number(block.offset) - Number(blockGroup.offset)
454
- let resultData = data
439
+ let resultData = data.subarray(
440
+ Number(block.offset) - Number(blockGroup.offset),
441
+ )
455
442
  if (isCompressed) {
456
- resultData = unzip(data.subarray(blockOffset))
457
- blockOffset = 0
443
+ resultData = unzip(resultData)
458
444
  }
459
445
  checkAbortSignal(signal)
460
446
 
461
447
  switch (blockType) {
462
448
  case 'summary': {
463
- observer.next(
464
- this.parseSummaryBlock(resultData, blockOffset, request),
465
- )
449
+ observer.next(this.parseSummaryBlock(resultData, 0, request))
466
450
  break
467
451
  }
468
452
  case 'bigwig': {
469
- observer.next(
470
- this.parseBigWigBlock(resultData, blockOffset, request),
471
- )
453
+ observer.next(this.parseBigWigBlock(resultData, 0, request))
472
454
  break
473
455
  }
474
456
  case 'bigbed': {
475
457
  observer.next(
476
458
  this.parseBigBedBlock(
477
459
  resultData,
478
- blockOffset,
460
+ 0,
479
461
  Number(block.offset) * (1 << 8),
480
462
  request,
481
463
  ),
package/src/unzip-pako.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { Buffer } from 'buffer'
2
1
  import { inflateRaw } from 'pako'
3
2
 
4
- export function unzip(input: Buffer) {
3
+ export function unzip(input: Uint8Array) {
5
4
  return inflateRaw(input.subarray(2))
6
5
  }