@gmod/tabix 3.5.4 → 3.5.7
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/dist/indexFile.d.ts +35 -2
- package/dist/indexFile.js +79 -7
- package/dist/indexFile.js.map +1 -1
- package/dist/tabix-bundle.js +1 -1
- package/dist/util.d.ts +18 -0
- package/dist/util.js +71 -1
- package/dist/util.js.map +1 -1
- package/esm/indexFile.d.ts +35 -2
- package/esm/indexFile.js +80 -8
- package/esm/indexFile.js.map +1 -1
- package/esm/util.d.ts +18 -0
- package/esm/util.js +70 -1
- package/esm/util.js.map +1 -1
- package/package.json +1 -2
- package/src/indexFile.ts +80 -8
- package/src/util.ts +74 -1
package/src/util.ts
CHANGED
|
@@ -5,6 +5,37 @@ import { longFromBytesToUnsigned } from './long.ts'
|
|
|
5
5
|
import VirtualOffset from './virtualOffset.ts'
|
|
6
6
|
|
|
7
7
|
// SYNC: ~/src/gmod/bam-js/src/util.ts optimizeChunks
|
|
8
|
+
/**
|
|
9
|
+
* `signal.throwIfAborted()`, without requiring either that method or `reason`.
|
|
10
|
+
*
|
|
11
|
+
* Two reasons not to call the built-in directly. It assumes a *real*
|
|
12
|
+
* `AbortSignal`, and callers pass duck-typed ones, where calling a missing
|
|
13
|
+
* method is a `TypeError` rather than the cancellation the caller asked for —
|
|
14
|
+
* a strictly worse failure.
|
|
15
|
+
*
|
|
16
|
+
* And it sets a browser floor. `AbortSignal.prototype.throwIfAborted` and
|
|
17
|
+
* `AbortSignal.reason` are Safari 15.4 / Chrome 100 / Firefox 97 (March 2022),
|
|
18
|
+
* higher than anything else here needs: this package otherwise touches only
|
|
19
|
+
* `.aborted`, and `generic-filehandle2` only forwards a signal to `fetch`.
|
|
20
|
+
*
|
|
21
|
+
* Faithful to the spec otherwise: an aborted signal throws its `reason`
|
|
22
|
+
* whatever that is, and only synthesizes an `AbortError` when there is none.
|
|
23
|
+
* Kept in sync with the copy in `@gmod/bam`'s `src/util.ts`.
|
|
24
|
+
*/
|
|
25
|
+
export function throwIfAborted(signal?: AbortSignal) {
|
|
26
|
+
if (signal?.aborted) {
|
|
27
|
+
const reason: unknown = signal.reason
|
|
28
|
+
// Spec-faithful: throwIfAborted throws `reason` verbatim, and `reason` is
|
|
29
|
+
// whatever the caller passed to abort() — `controller.abort('too slow')`
|
|
30
|
+
// makes it a string. Coercing it to an Error here would hide that from a
|
|
31
|
+
// consumer who set it deliberately.
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
|
33
|
+
throw reason === undefined
|
|
34
|
+
? new DOMException('This operation was aborted', 'AbortError')
|
|
35
|
+
: reason
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
8
39
|
export function optimizeChunks(chunks: Chunk[], lowest?: VirtualOffset) {
|
|
9
40
|
const n = chunks.length
|
|
10
41
|
if (n === 0) {
|
|
@@ -75,7 +106,49 @@ export function optimizeChunks(chunks: Chunk[], lowest?: VirtualOffset) {
|
|
|
75
106
|
}
|
|
76
107
|
}
|
|
77
108
|
|
|
78
|
-
return mergedChunks
|
|
109
|
+
return makeDisjoint(mergedChunks)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// SYNC: ~/src/gmod/bam-js/src/util.ts makeDisjoint
|
|
113
|
+
/**
|
|
114
|
+
* Trim any chunk that starts before its predecessor ends, so the spans a query
|
|
115
|
+
* reads never overlap.
|
|
116
|
+
*
|
|
117
|
+
* Merging alone does not guarantee this. Two chunks from different bins can
|
|
118
|
+
* overlap inside a single BGZF block while the merge above still declines to
|
|
119
|
+
* join them, because the combined span would exceed its 5MB cap. The shared
|
|
120
|
+
* bytes are then fetched, decompressed and decoded by both chunks, and every
|
|
121
|
+
* line in the overlap is returned TWICE from getLines — a duplicated VCF
|
|
122
|
+
* record or GFF feature, with a duplicated fileOffset.
|
|
123
|
+
*
|
|
124
|
+
* Safe because a chunk's `maxv` is the virtual offset just past its last
|
|
125
|
+
* record — a record boundary — so no record begins inside the trimmed span and
|
|
126
|
+
* the union of the chunks is unchanged.
|
|
127
|
+
*
|
|
128
|
+
* No fixture here reproduces it (@gmod/bam found it on an 18MB BAM, where
|
|
129
|
+
* out.bam returned 5 of its 6551 records twice); this keeps the two copies of
|
|
130
|
+
* optimizeChunks in step and pins the invariant.
|
|
131
|
+
*/
|
|
132
|
+
function makeDisjoint(chunks: Chunk[]) {
|
|
133
|
+
const out: Chunk[] = [chunks[0]!]
|
|
134
|
+
for (let i = 1; i < chunks.length; i++) {
|
|
135
|
+
const chunk = chunks[i]!
|
|
136
|
+
const prevMax = out.at(-1)!.maxv
|
|
137
|
+
const cmp =
|
|
138
|
+
chunk.minv.blockPosition - prevMax.blockPosition ||
|
|
139
|
+
chunk.minv.dataPosition - prevMax.dataPosition
|
|
140
|
+
if (cmp >= 0) {
|
|
141
|
+
out.push(chunk)
|
|
142
|
+
continue
|
|
143
|
+
}
|
|
144
|
+
const stillHasData =
|
|
145
|
+
chunk.maxv.blockPosition - prevMax.blockPosition ||
|
|
146
|
+
chunk.maxv.dataPosition - prevMax.dataPosition
|
|
147
|
+
if (stillHasData > 0) {
|
|
148
|
+
out.push(new Chunk(prevMax, chunk.maxv, chunk.bin, chunk.endPosition))
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return out
|
|
79
152
|
}
|
|
80
153
|
|
|
81
154
|
// Tighten each chunk's endPosition (default: a full max-size BGZF block past
|