taxonium-component
Version:
React component for exploring large phylogenetic trees in the browser
1,224 lines (1,223 loc) • 39.1 kB
JavaScript
import { Q } from "./index-BOYufR2k.js";
import { aX as q, bT as B, c1 as et, c2 as W, a4 as L, u as D, a2 as nt, a3 as st, R as V, c3 as it, c4 as rt } from "./JBrowsePanel-uJIA-L6s.js";
import { u as U, a as at } from "./unzip-ASAuJ12U.js";
import { c as ot } from "./crc32-CxoSWZf_.js";
import { B as ct } from "./index-BnQfM3Nw.js";
import { Q as ht } from "./QuickLRU-DcNaxluI.js";
import { r as ut } from "./rxjs-BnZkaVAs.js";
class $ {
constructor(t, e, n, s) {
this.minv = t, this.maxv = e, this.bin = n, this._fetchedSize = s;
}
toUniqueString() {
return `${this.minv.toString()}..${this.maxv.toString()} (bin ${this.bin}, fetchedSize ${this.fetchedSize()})`;
}
toString() {
return this.toUniqueString();
}
compareTo(t) {
return this.minv.compareTo(t.minv) || this.maxv.compareTo(t.maxv) || this.bin - t.bin;
}
fetchedSize() {
return this._fetchedSize !== void 0 ? this._fetchedSize : this.maxv.blockPosition + 65536 - this.minv.blockPosition;
}
}
class Y {
constructor({ filehandle: t, renameRefSeq: e = (n) => n }) {
this.filehandle = t, this.renameRefSeq = e;
}
}
const j = 65536, ft = j * j;
function lt(a, t = 0) {
const e = a[t] | a[t + 1] << 8 | a[t + 2] << 16 | a[t + 3] << 24;
return ((a[t + 4] | a[t + 5] << 8 | a[t + 6] << 16 | a[t + 7] << 24) >>> 0) * ft + (e >>> 0);
}
function dt(a) {
return new Promise((t) => setTimeout(t, a));
}
function gt(a) {
if (a && a.aborted)
if (typeof DOMException > "u") {
const t = new Error("aborted");
throw t.code = "ERR_ABORTED", t;
} else
throw new DOMException("aborted", "AbortError");
}
function mt(a, t) {
return t.minv.blockPosition - a.maxv.blockPosition < 65e3 && t.maxv.blockPosition - a.minv.blockPosition < 5e6;
}
function pt(a = {}) {
return "aborted" in a ? { signal: a } : a;
}
function J(a, t) {
const e = [];
let n;
if (a.length === 0)
return a;
a.sort((s, i) => {
const r = s.minv.blockPosition - i.minv.blockPosition;
return r === 0 ? s.minv.dataPosition - i.minv.dataPosition : r;
});
for (const s of a)
(!t || s.maxv.compareTo(t) > 0) && (n === void 0 ? (e.push(s), n = s) : mt(n, s) ? s.maxv.compareTo(n.maxv) > 0 && (n.maxv = s.maxv) : (e.push(s), n = s));
return e;
}
function X(a, t) {
return {
lineCount: lt(a, t)
};
}
function T(a, t) {
return a ? a.compareTo(t) > 0 ? t : a : t;
}
function wt(a, t = (e) => e) {
let e = 0, n = 0;
const s = [], i = {};
for (let r = 0; r < a.length; r += 1)
if (!a[r]) {
if (n < r) {
let o = "";
for (let c = n; c < r; c++)
o += String.fromCharCode(a[c]);
o = t(o), s[e] = o, i[o] = e;
}
n = r + 1, e += 1;
}
return { refNameToId: i, refIdToName: s };
}
function bt(a) {
let t = 0;
for (const e of a)
t += e.length;
return t;
}
function $t(a) {
const t = new Uint8Array(bt(a));
let e = 0;
for (const n of a)
t.set(n, e), e += n.length;
return t;
}
async function xt(a) {
let t = [];
for await (const e of a)
t = t.concat(e);
return t;
}
class K {
constructor(t, e) {
this.blockPosition = t, this.dataPosition = e;
}
toString() {
return `${this.blockPosition}:${this.dataPosition}`;
}
compareTo(t) {
return this.blockPosition - t.blockPosition || this.dataPosition - t.dataPosition;
}
}
function P(a, t = 0, e = !1) {
if (e)
throw new Error("big-endian virtual file offsets not implemented");
return new K(a[t + 7] * 1099511627776 + a[t + 6] * 4294967296 + a[t + 5] * 16777216 + a[t + 4] * 65536 + a[t + 3] * 256 + a[t + 2], a[t + 1] << 8 | a[t]);
}
const _t = 21578050;
function yt(a, t) {
return a - a % t;
}
function It(a, t) {
return a - a % t + t;
}
function Ct(a, t) {
return t -= 1, [
[0, 0],
[1 + (a >> 26), 1 + (t >> 26)],
[9 + (a >> 23), 9 + (t >> 23)],
[73 + (a >> 20), 73 + (t >> 20)],
[585 + (a >> 17), 585 + (t >> 17)],
[4681 + (a >> 14), 4681 + (t >> 14)]
];
}
class F extends Y {
async lineCount(t, e) {
var s, i;
return ((i = (s = (await this.parse(e)).indices(t)) == null ? void 0 : s.stats) == null ? void 0 : i.lineCount) || 0;
}
async _parse(t) {
const e = await this.filehandle.readFile(), n = new DataView(e.buffer);
if (n.getUint32(0, !0) !== _t)
throw new Error("Not a BAI file");
const s = n.getInt32(4, !0), r = ((1 << (5 + 1) * 3) - 1) / 7;
let o = 8, c;
const h = [];
for (let l = 0; l < s; l++) {
h.push(o);
const f = n.getInt32(o, !0);
o += 4;
for (let m = 0; m < f; m += 1) {
const g = n.getUint32(o, !0);
if (o += 4, g === r + 1)
o += 4, o += 32;
else {
if (g > r + 1)
throw new Error("bai index contains too many bins, please use CSI");
{
const y = n.getInt32(o, !0);
o += 4;
for (let _ = 0; _ < y; _++)
o += 8, o += 8;
}
}
}
const w = n.getInt32(o, !0);
o += 4;
const p = new Array(w);
for (let m = 0; m < w; m++) {
const g = P(e, o);
o += 8, c = T(c, g), p[m] = g;
}
}
const u = new Q({
maxSize: 5
});
function d(l) {
let f = h[l];
if (f === void 0)
return;
const w = n.getInt32(f, !0);
let p;
f += 4;
const m = {};
for (let _ = 0; _ < w; _ += 1) {
const I = n.getUint32(f, !0);
if (f += 4, I === r + 1)
f += 4, p = X(e, f + 16), f += 32;
else {
if (I > r + 1)
throw new Error("bai index contains too many bins, please use CSI");
{
const A = n.getInt32(f, !0);
f += 4;
const S = new Array(A);
for (let R = 0; R < A; R++) {
const v = P(e, f);
f += 8;
const k = P(e, f);
f += 8, c = T(c, v), S[R] = new $(v, k, I);
}
m[I] = S;
}
}
}
const g = n.getInt32(f, !0);
f += 4;
const y = new Array(g);
for (let _ = 0; _ < g; _++) {
const I = P(e, f);
f += 8, c = T(c, I), y[_] = I;
}
return {
binIndex: m,
linearIndex: y,
stats: p
};
}
return {
bai: !0,
firstDataLine: c,
maxBlockSize: 65536,
indices: (l) => {
if (!u.has(l)) {
const f = d(l);
return f && u.set(l, f), f;
}
return u.get(l);
},
refCount: s
};
}
async indexCov(t, e, n, s) {
const r = e !== void 0, c = (await this.parse(s)).indices(t);
if (!c)
return [];
const { linearIndex: h = [], stats: u } = c;
if (h.length === 0)
return [];
const d = n === void 0 ? (h.length - 1) * 16384 : It(n, 16384), l = e === void 0 ? 0 : yt(e, 16384), f = r ? new Array((d - l) / 16384) : new Array(h.length - 1), w = h[h.length - 1].blockPosition;
if (d > (h.length - 1) * 16384)
throw new Error("query outside of range of linear index");
let p = h[l / 16384].blockPosition;
for (let m = l / 16384, g = 0; m < d / 16384; m++, g++)
f[g] = {
score: h[m + 1].blockPosition - p,
start: m * 16384,
end: m * 16384 + 16384
}, p = h[m + 1].blockPosition;
return f.map((m) => ({
...m,
score: m.score * ((u == null ? void 0 : u.lineCount) || 0) / w
}));
}
async blocksForRange(t, e, n, s = {}) {
e < 0 && (e = 0);
const i = await this.parse(s);
if (!i)
return [];
const r = i.indices(t);
if (!r)
return [];
const o = Ct(e, n), c = [];
for (const [f, w] of o)
for (let p = f; p <= w; p++)
if (r.binIndex[p]) {
const m = r.binIndex[p];
for (const g of m)
c.push(new $(g.minv, g.maxv, p));
}
const h = r.linearIndex.length;
let u;
const d = Math.min(e >> 14, h - 1), l = Math.min(n >> 14, h - 1);
for (let f = d; f <= l; ++f) {
const w = r.linearIndex[f];
w && (!u || w.compareTo(u) < 0) && (u = w);
}
return J(c, u);
}
async parse(t = {}) {
return this.setupP || (this.setupP = this._parse(t).catch((e) => {
throw this.setupP = void 0, e;
})), this.setupP;
}
async hasRefSeq(t, e = {}) {
var s;
return !!((s = (await this.parse(e)).indices(t)) != null && s.binIndex);
}
}
const At = 21582659, St = 38359875;
function Pt(a, t) {
return a * 2 ** t;
}
function G(a, t) {
return Math.floor(a / 2 ** t);
}
class O extends Y {
constructor() {
super(...arguments), this.maxBinNumber = 0, this.depth = 0, this.minShift = 0;
}
async lineCount(t, e) {
var s, i;
return ((i = (s = (await this.parse(e)).indices(t)) == null ? void 0 : s.stats) == null ? void 0 : i.lineCount) || 0;
}
async indexCov() {
return [];
}
parseAuxData(t, e) {
const n = new DataView(t.buffer), s = n.getUint32(e, !0), i = s & 65536 ? "zero-based-half-open" : "1-based-closed", r = { 0: "generic", 1: "SAM", 2: "VCF" }[s & 15];
if (!r)
throw new Error(`invalid Tabix preset format flags ${s}`);
const o = {
ref: n.getInt32(e + 4, !0),
start: n.getInt32(e + 8, !0),
end: n.getInt32(e + 12, !0)
}, c = n.getInt32(e + 16, !0), h = c ? String.fromCharCode(c) : "", u = n.getInt32(e + 20, !0), d = n.getInt32(e + 24, !0);
return {
columnNumbers: o,
coordinateType: i,
metaValue: c,
metaChar: h,
skipLines: u,
format: r,
formatFlags: s,
...wt(t.subarray(e + 28, e + 28 + d), this.renameRefSeq)
};
}
// fetch and parse the index
async _parse(t) {
const e = await this.filehandle.readFile(t), n = await U(e), s = new DataView(n.buffer);
let i;
const r = s.getUint32(0, !0);
if (r === At)
i = 1;
else if (r === St)
i = 2;
else
throw new Error(`Not a CSI file ${r}`);
this.minShift = s.getInt32(4, !0), this.depth = s.getInt32(8, !0), this.maxBinNumber = ((1 << (this.depth + 1) * 3) - 1) / 7;
const o = this.maxBinNumber, c = s.getInt32(12, !0), h = c >= 30 ? this.parseAuxData(n, 16) : void 0, u = s.getInt32(16 + c, !0);
let d = 16 + c + 4, l;
const f = [];
for (let m = 0; m < u; m++) {
f.push(d);
const g = s.getInt32(d, !0);
d += 4;
for (let y = 0; y < g; y++) {
const _ = s.getUint32(d, !0);
if (d += 4, _ > this.maxBinNumber)
d += 44;
else {
d += 8;
const I = s.getInt32(d, !0);
d += 4;
for (let A = 0; A < I; A += 1) {
const S = P(n, d);
d += 8, d += 8, l = T(l, S);
}
}
}
}
const w = new Q({
maxSize: 5
});
function p(m) {
let g = f[m];
if (g === void 0)
return;
const y = s.getInt32(g, !0);
g += 4;
const _ = {};
let I;
for (let A = 0; A < y; A++) {
const S = s.getUint32(g, !0);
if (g += 4, S > o)
I = X(n, g + 28), g += 44;
else {
l = T(l, P(n, g)), g += 8;
const R = s.getInt32(g, !0);
g += 4;
const v = new Array(R);
for (let k = 0; k < R; k += 1) {
const Z = P(n, g);
g += 8;
const tt = P(n, g);
g += 8, v[k] = new $(Z, tt, S);
}
_[S] = v;
}
}
return {
binIndex: _,
stats: I
};
}
return {
csiVersion: i,
firstDataLine: l,
indices: (m) => {
if (!w.has(m)) {
const g = p(m);
return g && w.set(m, g), g;
}
return w.get(m);
},
refCount: u,
csi: !0,
maxBlockSize: 65536,
...h
};
}
async blocksForRange(t, e, n, s = {}) {
e < 0 && (e = 0);
const r = (await this.parse(s)).indices(t);
if (!r)
return [];
const o = this.reg2bins(e, n);
if (o.length === 0)
return [];
const c = [];
for (const [h, u] of o)
for (let d = h; d <= u; d++)
if (r.binIndex[d]) {
const l = r.binIndex[d];
for (const f of l)
c.push(f);
}
return J(c, new K(0, 0));
}
/**
* calculate the list of bins that may overlap with region [beg,end)
* (zero-based half-open)
*/
reg2bins(t, e) {
t -= 1, t < 1 && (t = 1), e > 2 ** 50 && (e = 2 ** 34), e -= 1;
let n = 0, s = 0, i = this.minShift + this.depth * 3;
const r = [];
for (; n <= this.depth; i -= 3, s += Pt(1, n * 3), n += 1) {
const o = s + G(t, i), c = s + G(e, i);
if (c - o + r.length > this.maxBinNumber)
throw new Error(`query ${t}-${e} is too large for current binning scheme (shift ${this.minShift}, depth ${this.depth}), try a smaller query or a coarser index binning scheme`);
r.push([o, c]);
}
return r;
}
async parse(t = {}) {
return this.setupP || (this.setupP = this._parse(t).catch((e) => {
throw this.setupP = void 0, e;
})), this.setupP;
}
async hasRefSeq(t, e = {}) {
var s;
return !!((s = (await this.parse(e)).indices(t)) != null && s.binIndex);
}
}
class Rt {
read() {
throw new Error("never called");
}
stat() {
throw new Error("never called");
}
readFile() {
throw new Error("never called");
}
close() {
throw new Error("never called");
}
}
const C = {
// the read is paired in sequencing, no matter whether it is mapped in a pair
BAM_FPAIRED: 1,
// the read is mapped in a proper pair
BAM_FPROPER_PAIR: 2,
// the read itself is unmapped; conflictive with BAM_FPROPER_PAIR
BAM_FUNMAP: 4,
// the mate is unmapped
BAM_FMUNMAP: 8,
// the read is mapped to the reverse strand
BAM_FREVERSE: 16,
// the mate is mapped to the reverse strand
BAM_FMREVERSE: 32,
// this is read1
BAM_FREAD1: 64,
// this is read2
BAM_FREAD2: 128,
// not primary alignment
BAM_FSECONDARY: 256,
// QC failure
BAM_FQCFAIL: 512,
// optical or PCR duplicate
BAM_FDUP: 1024,
// supplementary alignment
BAM_FSUPPLEMENTARY: 2048
};
var vt = function(a, t, e, n, s) {
if (n === "m") throw new TypeError("Private method is not writable");
if (n === "a" && !s) throw new TypeError("Private accessor was defined without a setter");
if (typeof t == "function" ? a !== t || !s : !t.has(a)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return n === "a" ? s.call(a, e) : s ? s.value = e : t.set(a, e), e;
}, x = function(a, t, e, n) {
if (e === "a" && !n) throw new TypeError("Private accessor was defined without a getter");
if (typeof t == "function" ? a !== t || !n : !t.has(a)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return e === "m" ? n : e === "a" ? n.call(a) : n ? n.value : t.get(a);
}, b;
const H = "=ACMGRSVTWYHKDBN".split(""), E = "MIDNSHP=X???????".split("");
class M {
constructor(t) {
b.set(this, void 0), this.bytes = t.bytes, this.fileOffset = t.fileOffset, vt(this, b, new DataView(this.bytes.byteArray.buffer), "f");
}
get byteArray() {
return this.bytes.byteArray;
}
get flags() {
return (x(this, b, "f").getInt32(this.bytes.start + 16, !0) & 4294901760) >> 16;
}
get ref_id() {
return x(this, b, "f").getInt32(this.bytes.start + 4, !0);
}
get start() {
return x(this, b, "f").getInt32(this.bytes.start + 8, !0);
}
get end() {
return this.start + this.length_on_ref;
}
get id() {
return this.fileOffset;
}
get mq() {
const t = (this.bin_mq_nl & 65280) >> 8;
return t === 255 ? void 0 : t;
}
get score() {
return this.mq;
}
get qual() {
if (this.isSegmentUnmapped())
return;
const t = this.b0 + this.read_name_length + this.num_cigar_ops * 4 + this.num_seq_bytes;
return this.byteArray.subarray(t, t + this.seq_length);
}
get strand() {
return this.isReverseComplemented() ? -1 : 1;
}
get b0() {
return this.bytes.start + 36;
}
get name() {
let t = "";
for (let e = 0; e < this.read_name_length - 1; e++)
t += String.fromCharCode(this.byteArray[this.b0 + e]);
return t;
}
get tags() {
let t = this.b0 + this.read_name_length + this.num_cigar_ops * 4 + this.num_seq_bytes + this.seq_length;
const e = this.bytes.end, n = {};
for (; t < e; ) {
const s = String.fromCharCode(this.byteArray[t], this.byteArray[t + 1]), i = String.fromCharCode(this.byteArray[t + 2]);
if (t += 3, i === "A")
n[s] = String.fromCharCode(this.byteArray[t]), t += 1;
else if (i === "i")
n[s] = x(this, b, "f").getInt32(t, !0), t += 4;
else if (i === "I")
n[s] = x(this, b, "f").getUint32(t, !0), t += 4;
else if (i === "c")
n[s] = x(this, b, "f").getInt8(t), t += 1;
else if (i === "C")
n[s] = x(this, b, "f").getUint8(t), t += 1;
else if (i === "s")
n[s] = x(this, b, "f").getInt16(t, !0), t += 2;
else if (i === "S")
n[s] = x(this, b, "f").getUint16(t, !0), t += 2;
else if (i === "f")
n[s] = x(this, b, "f").getFloat32(t, !0), t += 4;
else if (i === "Z" || i === "H") {
const r = [];
for (; t <= e; ) {
const o = this.byteArray[t++];
if (o !== 0)
r.push(String.fromCharCode(o));
else
break;
}
n[s] = r.join("");
} else if (i === "B") {
const r = this.byteArray[t++], o = String.fromCharCode(r), c = x(this, b, "f").getInt32(t, !0);
if (t += 4, o === "i")
if (s === "CG") {
const h = [];
for (let u = 0; u < c; u++) {
const d = x(this, b, "f").getInt32(t, !0), l = d >> 4, f = E[d & 15];
h.push(l + f), t += 4;
}
n[s] = h.join("");
} else {
const h = [];
for (let u = 0; u < c; u++)
h.push(x(this, b, "f").getInt32(t, !0)), t += 4;
n[s] = h;
}
else if (o === "I")
if (s === "CG") {
const h = [];
for (let u = 0; u < c; u++) {
const d = x(this, b, "f").getUint32(t, !0), l = d >> 4, f = E[d & 15];
h.push(l + f), t += 4;
}
n[s] = h.join("");
} else {
const h = [];
for (let u = 0; u < c; u++)
h.push(x(this, b, "f").getUint32(t, !0)), t += 4;
n[s] = h;
}
else if (o === "s") {
const h = [];
for (let u = 0; u < c; u++)
h.push(x(this, b, "f").getInt16(t, !0)), t += 2;
n[s] = h;
} else if (o === "S") {
const h = [];
for (let u = 0; u < c; u++)
h.push(x(this, b, "f").getUint16(t, !0)), t += 2;
n[s] = h;
} else if (o === "c") {
const h = [];
for (let u = 0; u < c; u++)
h.push(x(this, b, "f").getInt8(t)), t += 1;
n[s] = h;
} else if (o === "C") {
const h = [];
for (let u = 0; u < c; u++)
h.push(x(this, b, "f").getUint8(t)), t += 1;
n[s] = h;
} else if (o === "f") {
const h = [];
for (let u = 0; u < c; u++)
h.push(x(this, b, "f").getFloat32(t, !0)), t += 4;
n[s] = h;
}
} else {
console.error("Unknown BAM tag type", i);
break;
}
}
return n;
}
/**
* @returns {boolean} true if the read is paired, regardless of whether both
* segments are mapped
*/
isPaired() {
return !!(this.flags & C.BAM_FPAIRED);
}
/** @returns {boolean} true if the read is paired, and both segments are mapped */
isProperlyPaired() {
return !!(this.flags & C.BAM_FPROPER_PAIR);
}
/** @returns {boolean} true if the read itself is unmapped; conflictive with isProperlyPaired */
isSegmentUnmapped() {
return !!(this.flags & C.BAM_FUNMAP);
}
/** @returns {boolean} true if the read itself is unmapped; conflictive with isProperlyPaired */
isMateUnmapped() {
return !!(this.flags & C.BAM_FMUNMAP);
}
/** @returns {boolean} true if the read is mapped to the reverse strand */
isReverseComplemented() {
return !!(this.flags & C.BAM_FREVERSE);
}
/** @returns {boolean} true if the mate is mapped to the reverse strand */
isMateReverseComplemented() {
return !!(this.flags & C.BAM_FMREVERSE);
}
/** @returns {boolean} true if this is read number 1 in a pair */
isRead1() {
return !!(this.flags & C.BAM_FREAD1);
}
/** @returns {boolean} true if this is read number 2 in a pair */
isRead2() {
return !!(this.flags & C.BAM_FREAD2);
}
/** @returns {boolean} true if this is a secondary alignment */
isSecondary() {
return !!(this.flags & C.BAM_FSECONDARY);
}
/** @returns {boolean} true if this read has failed QC checks */
isFailedQc() {
return !!(this.flags & C.BAM_FQCFAIL);
}
/** @returns {boolean} true if the read is an optical or PCR duplicate */
isDuplicate() {
return !!(this.flags & C.BAM_FDUP);
}
/** @returns {boolean} true if this is a supplementary alignment */
isSupplementary() {
return !!(this.flags & C.BAM_FSUPPLEMENTARY);
}
get cigarAndLength() {
if (this.isSegmentUnmapped())
return {
length_on_ref: 0,
CIGAR: ""
};
const t = this.num_cigar_ops;
let e = this.b0 + this.read_name_length;
const n = [];
let s = x(this, b, "f").getInt32(e, !0), i = s >> 4, r = E[s & 15];
if (r === "S" && i === this.seq_length)
return e += 4, s = x(this, b, "f").getInt32(e, !0), i = s >> 4, r = E[s & 15], r !== "N" && console.warn("CG tag with no N tag"), {
CIGAR: this.tags.CG,
length_on_ref: i
};
{
let o = 0;
for (let c = 0; c < t; ++c)
s = x(this, b, "f").getInt32(e, !0), i = s >> 4, r = E[s & 15], n.push(i + r), r !== "H" && r !== "S" && r !== "I" && (o += i), e += 4;
return {
CIGAR: n.join(""),
length_on_ref: o
};
}
}
get length_on_ref() {
return this.cigarAndLength.length_on_ref;
}
get CIGAR() {
return this.cigarAndLength.CIGAR;
}
get num_cigar_ops() {
return this.flag_nc & 65535;
}
get read_name_length() {
return this.bin_mq_nl & 255;
}
get num_seq_bytes() {
return this.seq_length + 1 >> 1;
}
get seq() {
const t = this.b0 + this.read_name_length + this.num_cigar_ops * 4, e = this.num_seq_bytes, n = this.seq_length, s = [];
let i = 0;
for (let r = 0; r < e; ++r) {
const o = this.byteArray[t + r];
s.push(H[(o & 240) >> 4]), i++, i < n && (s.push(H[o & 15]), i++);
}
return s.join("");
}
// adapted from igv.js
get pair_orientation() {
if (!this.isSegmentUnmapped() && !this.isMateUnmapped() && this.ref_id === this.next_refid) {
const t = this.isReverseComplemented() ? "R" : "F", e = this.isMateReverseComplemented() ? "R" : "F";
let n = " ", s = " ";
this.isRead1() ? (n = "1", s = "2") : this.isRead2() && (n = "2", s = "1");
const i = [];
return this.template_length > 0 ? (i[0] = t, i[1] = n, i[2] = e, i[3] = s) : (i[2] = t, i[3] = n, i[0] = e, i[1] = s), i.join("");
}
}
get bin_mq_nl() {
return x(this, b, "f").getInt32(this.bytes.start + 12, !0);
}
get flag_nc() {
return x(this, b, "f").getInt32(this.bytes.start + 16, !0);
}
get seq_length() {
return x(this, b, "f").getInt32(this.bytes.start + 20, !0);
}
get next_refid() {
return x(this, b, "f").getInt32(this.bytes.start + 24, !0);
}
get next_pos() {
return x(this, b, "f").getInt32(this.bytes.start + 28, !0);
}
get template_length() {
return x(this, b, "f").getInt32(this.bytes.start + 32, !0);
}
toJSON() {
const t = {};
for (const e of Object.keys(this))
e.startsWith("_") || e === "bytes" || (t[e] = this[e]);
return t;
}
}
b = /* @__PURE__ */ new WeakMap();
function N(a, t) {
const e = Object.getOwnPropertyDescriptor(a.prototype, t);
if (!e)
throw new Error("OH NO, NO PROPERTY DESCRIPTOR");
const n = e.get;
if (!n)
throw new Error("OH NO, NOT A GETTER");
Object.defineProperty(a.prototype, t, {
get() {
const s = n.call(this);
return Object.defineProperty(this, t, { value: s }), s;
}
});
}
N(M, "tags");
N(M, "cigarAndLength");
N(M, "seq");
N(M, "qual");
function kt(a) {
const t = a.split(/\r?\n/), e = [];
for (const n of t) {
const [s, ...i] = n.split(/\t/);
s && e.push({
tag: s.slice(1),
data: i.map((r) => {
const o = r.indexOf(":"), c = r.slice(0, o), h = r.slice(o + 1);
return { tag: c, value: h };
})
});
}
return e;
}
const Ft = 21840194, Et = 65536;
class Tt {
constructor({ bamFilehandle: t, bamPath: e, bamUrl: n, baiPath: s, baiFilehandle: i, baiUrl: r, csiPath: o, csiFilehandle: c, csiUrl: h, htsget: u, yieldThreadTime: d = 100, renameRefSeqs: l = (f) => f }) {
if (this.htsget = !1, this.renameRefSeq = l, t)
this.bam = t;
else if (e)
this.bam = new q(e);
else if (n)
this.bam = new B(n);
else if (u)
this.htsget = !0, this.bam = new Rt();
else
throw new Error("unable to initialize bam");
if (c)
this.index = new O({ filehandle: c });
else if (o)
this.index = new O({ filehandle: new q(o) });
else if (h)
this.index = new O({ filehandle: new B(h) });
else if (i)
this.index = new F({ filehandle: i });
else if (s)
this.index = new F({ filehandle: new q(s) });
else if (r)
this.index = new F({ filehandle: new B(r) });
else if (e)
this.index = new F({ filehandle: new q(`${e}.bai`) });
else if (n)
this.index = new F({ filehandle: new B(`${n}.bai`) });
else if (u)
this.htsget = !0;
else
throw new Error("unable to infer index format");
this.yieldThreadTime = d;
}
async getHeaderPre(t) {
const e = pt(t);
if (!this.index)
return;
const n = await this.index.parse(e), s = n.firstDataLine ? n.firstDataLine.blockPosition + 65535 : void 0;
let i;
if (s) {
const l = s + Et;
i = await this.bam.read(l, 0);
} else
i = await this.bam.readFile(e);
const r = await U(i), o = new DataView(r.buffer);
if (o.getInt32(0, !0) !== Ft)
throw new Error("Not a BAM file");
const c = o.getInt32(4, !0), h = new TextDecoder("utf8");
this.header = h.decode(r.subarray(8, 8 + c));
const { chrToIndex: u, indexToChr: d } = await this._readRefSeqs(c + 8, 65535, e);
return this.chrToIndex = u, this.indexToChr = d, kt(this.header);
}
getHeader(t) {
return this.headerP || (this.headerP = this.getHeaderPre(t).catch((e) => {
throw this.headerP = void 0, e;
})), this.headerP;
}
async getHeaderText(t = {}) {
return await this.getHeader(t), this.header;
}
// the full length of the refseq block is not given in advance so this grabs
// a chunk and doubles it if all refseqs haven't been processed
async _readRefSeqs(t, e, n) {
if (t > e)
return this._readRefSeqs(t, e * 2, n);
const s = await this.bam.read(e, 0, n), i = await U(s), r = new DataView(i.buffer), o = r.getInt32(t, !0);
let c = t + 4;
const h = {}, u = [], d = new TextDecoder("utf8");
for (let l = 0; l < o; l += 1) {
const f = r.getInt32(c, !0), w = this.renameRefSeq(d.decode(i.subarray(c + 4, c + 4 + f - 1))), p = r.getInt32(c + f + 4, !0);
if (h[w] = l, u.push({ refName: w, length: p }), c = c + 8 + f, c > i.length)
return console.warn(`BAM header is very big. Re-fetching ${e} bytes.`), this._readRefSeqs(t, e * 2, n);
}
return { chrToIndex: h, indexToChr: u };
}
async getRecordsForRange(t, e, n, s) {
return xt(this.streamRecordsForRange(t, e, n, s));
}
async *streamRecordsForRange(t, e, n, s) {
var r;
await this.getHeader(s);
const i = (r = this.chrToIndex) == null ? void 0 : r[t];
if (i === void 0 || !this.index)
yield [];
else {
const o = await this.index.blocksForRange(i, e - 1, n, s);
yield* this._fetchChunkFeatures(o, i, e, n, s);
}
}
async *_fetchChunkFeatures(t, e, n, s, i = {}) {
const { viewAsPairs: r } = i, o = [];
let c = !1;
for (const h of t) {
const { data: u, cpositions: d, dpositions: l } = await this._readChunk({
chunk: h,
opts: i
}), f = await this.readBamFeatures(u, d, l, h), w = [];
for (const p of f)
if (p.ref_id === e)
if (p.start >= s) {
c = !0;
break;
} else p.end >= n && w.push(p);
if (o.push(w), yield w, c)
break;
}
gt(i.signal), r && (yield this.fetchPairs(e, o, i));
}
async fetchPairs(t, e, n) {
const { pairAcrossChr: s, maxInsertSize: i = 2e5 } = n, r = {}, o = {};
e.map((l) => {
const f = {};
for (const w of l) {
const p = w.name, m = w.id;
f[p] || (f[p] = 0), f[p]++, o[m] = 1;
}
for (const [w, p] of Object.entries(f))
p === 1 && (r[w] = !0);
});
const c = [];
e.map((l) => {
for (const f of l) {
const w = f.name, p = f.start, m = f.next_pos, g = f.next_refid;
this.index && r[w] && (s || g === t && Math.abs(p - m) < i) && c.push(this.index.blocksForRange(g, m, m + 1, n));
}
});
const h = /* @__PURE__ */ new Map(), u = await Promise.all(c);
for (const l of u.flat())
h.has(l.toString()) || h.set(l.toString(), l);
return (await Promise.all([...h.values()].map(async (l) => {
const { data: f, cpositions: w, dpositions: p, chunk: m } = await this._readChunk({
chunk: l,
opts: n
}), g = [];
for (const y of await this.readBamFeatures(f, w, p, m))
r[y.name] && !o[y.id] && g.push(y);
return g;
}))).flat();
}
async _readChunk({ chunk: t, opts: e }) {
const n = await this.bam.read(t.fetchedSize(), t.minv.blockPosition, e), { buffer: s, cpositions: i, dpositions: r } = await at(n, t);
return { data: s, cpositions: i, dpositions: r, chunk: t };
}
async readBamFeatures(t, e, n, s) {
let i = 0;
const r = [];
let o = 0, c = +Date.now();
const h = new DataView(t.buffer);
for (; i + 4 < t.length; ) {
const u = h.getInt32(i, !0), d = i + 4 + u - 1;
if (n) {
for (; i + s.minv.dataPosition >= n[o++]; )
;
o--;
}
if (d < t.length) {
const l = new M({
bytes: {
byteArray: t,
start: i,
end: d
},
// the below results in an automatically calculated file-offset based
// ID if the info for that is available, otherwise crc32 of the
// features
//
// cpositions[pos] refers to actual file offset of a bgzip block
// boundaries
//
// we multiply by (1 <<8) in order to make sure each block has a
// "unique" address space so that data in that block could never
// overlap
//
// then the blockStart-dpositions is an uncompressed file offset from
// that bgzip block boundary, and since the cpositions are multiplied
// by (1 << 8) these uncompressed offsets get a unique space
//
// this has an extra chunk.minv.dataPosition added on because it
// blockStart starts at 0 instead of chunk.minv.dataPosition
//
// the +1 is just to avoid any possible uniqueId 0 but this does not
// realistically happen
fileOffset: e.length > 0 ? e[o] * 256 + (i - n[o]) + s.minv.dataPosition + 1 : (
// this shift >>> 0 is equivalent to crc32(b).unsigned but uses the
// internal calculator of crc32 to avoid accidentally importing buffer
// https://github.com/alexgorbatchev/crc/blob/31fc3853e417b5fb5ec83335428805842575f699/src/define_crc.ts#L5
ot(t.subarray(i, d)) >>> 0
)
});
r.push(l), this.yieldThreadTime && +Date.now() - c > this.yieldThreadTime && (await dt(1), c = +Date.now());
}
i = d + 1;
}
return r;
}
async hasRefSeq(t) {
var n, s;
const e = (n = this.chrToIndex) == null ? void 0 : n[t];
return e === void 0 ? !1 : (s = this.index) == null ? void 0 : s.hasRefSeq(e);
}
async lineCount(t) {
var n;
const e = (n = this.chrToIndex) == null ? void 0 : n[t];
return e === void 0 || !this.index ? 0 : this.index.lineCount(e);
}
async indexCov(t, e, n) {
var i;
if (!this.index)
return [];
await this.index.parse();
const s = (i = this.chrToIndex) == null ? void 0 : i[t];
return s === void 0 ? [] : this.index.indexCov(s, e, n);
}
async blocksForRange(t, e, n, s) {
var r;
if (!this.index)
return [];
await this.index.parse();
const i = (r = this.chrToIndex) == null ? void 0 : r[t];
return i === void 0 ? [] : this.index.blocksForRange(i, e, n, s);
}
}
class z {
constructor(t, e, n) {
this.record = t, this.adapter = e, this.ref = n;
}
id() {
return `${this.adapter.id}-${this.record.id}`;
}
get mismatches() {
return et(this.record.CIGAR, this.record.tags.MD, this.record.seq, this.ref, this.record.qual);
}
get qual() {
var t;
return (t = this.record.qual) === null || t === void 0 ? void 0 : t.join(" ");
}
get(t) {
return t === "mismatches" ? this.mismatches : t === "qual" ? this.qual : this.fields[t];
}
parent() {
}
children() {
}
get fields() {
const t = this.record, e = this.adapter, n = t.isPaired();
return {
start: t.start,
name: t.name,
end: t.end,
score: t.score,
strand: t.strand,
template_length: t.template_length,
flags: t.flags,
tags: t.tags,
refName: e.refIdToName(t.ref_id),
CIGAR: t.CIGAR,
seq: t.seq,
type: "match",
pair_orientation: t.pair_orientation,
next_ref: n ? e.refIdToName(t.next_refid) : void 0,
next_pos: n ? t.next_pos : void 0,
next_segment_position: n ? `${e.refIdToName(t.next_refid)}:${t.next_pos + 1}` : void 0,
uniqueId: this.id()
};
}
toJSON() {
return {
...this.fields,
qual: this.qual
};
}
}
W(z, "fields");
W(z, "mismatches");
class Mt extends ct.BaseFeatureDataAdapter {
constructor() {
super(...arguments), this.ultraLongFeatureCache = new ht({
maxSize: 500
});
}
async configurePre() {
const t = this.getConf("bamLocation"), e = this.getConf(["index", "location"]), n = this.getConf(["index", "indexType"]), s = this.pluginManager, i = n === "CSI", r = new Tt({
bamFilehandle: L.openLocation(t, s),
csiFilehandle: i ? L.openLocation(e, s) : void 0,
baiFilehandle: i ? void 0 : L.openLocation(e, s),
yieldThreadTime: Number.POSITIVE_INFINITY
}), o = this.getConf("sequenceAdapter");
if (o && this.getSubAdapter) {
const { dataAdapter: c } = await this.getSubAdapter(o);
return {
bam: r,
sequenceAdapter: c
};
}
return { bam: r };
}
async configure() {
return this.configureP || (this.configureP = this.configurePre().catch((t) => {
throw this.configureP = void 0, t;
})), this.configureP;
}
async getHeader(t) {
const { bam: e } = await this.configure();
return e.getHeaderText();
}
async setupPre(t) {
const { bam: e } = await this.configure(), n = await e.getHeader(), s = [], i = {};
if (n)
for (const [r, o] of n.filter((c) => c.tag === "SQ").entries()) {
const c = o.data.find((h) => h.tag === "SN");
if (c) {
const h = c.value;
i[h] = r, s[r] = h;
}
}
return this.samHeader = { idToName: s, nameToId: i }, this.samHeader;
}
async setupPre2(t) {
return this.setupP || (this.setupP = this.setupPre(t).catch((e) => {
throw this.setupP = void 0, e;
})), this.setupP;
}
async setup(t) {
const { statusCallback: e = () => {
} } = t || {};
return D.updateStatus("Downloading index", e, () => this.setupPre2(t));
}
async getRefNames(t) {
const { idToName: e } = await this.setup(t);
return e;
}
async seqFetch(t, e, n) {
const { sequenceAdapter: s } = await this.configure(), i = s;
if (!i || !t)
return;
const r = i.getFeatures({
refName: t,
start: e,
end: n,
assemblyName: ""
}), o = await nt(r.pipe(st()));
let c = "";
for (const h of o.sort((u, d) => u.get("start") - d.get("start"))) {
const u = h.get("start"), d = h.get("end"), l = Math.max(e - u, 0), w = Math.min(n - u, d - u) - l, p = h.get("seq") || h.get("residues");
c += p.slice(l, l + w);
}
if (c.length !== n - e)
throw new Error(`sequence fetch failed: fetching ${t}:${(e - 1).toLocaleString()}-${n.toLocaleString()} returned ${c.length.toLocaleString()} bases, but should have returned ${(n - e).toLocaleString()}`);
return c;
}
getFeatures(t, e) {
const { refName: n, start: s, end: i, originalRefName: r } = t, { stopToken: o, filterBy: c, statusCallback: h = () => {
} } = e || {};
return ut.ObservableCreate(async (u) => {
const { bam: d } = await this.configure();
await this.setup(e), V.checkStopToken(o);
const l = await D.updateStatus("Downloading alignments", h, () => d.getRecordsForRange(n, s, i));
V.checkStopToken(o), await D.updateStatus("Processing alignments", h, async () => {
const { flagInclude: f = 0, flagExclude: w = 0, tagFilter: p, readName: m } = c || {};
for (const g of l) {
let y;
if (g.tags.MD || (y = await this.seqFetch(r || n, g.start, g.end)), it(g.flags, f, w) || p && rt(g.tags[p.tag], p.value) || m && g.name !== m)
continue;
const _ = this.ultraLongFeatureCache.get(`${g.id}`);
if (_)
u.next(_);
else {
const I = new z(g, this, y);
this.ultraLongFeatureCache.set(`${g.id}`, I), u.next(I);
}
}
u.complete();
});
});
}
async getMultiRegionFeatureDensityStats(t, e) {
const { bam: n } = await this.configure();
if (n.index) {
const s = await D.bytesForRegions(t, n), i = this.getConf("fetchSizeLimit");
return { bytes: s, fetchSizeLimit: i };
}
return super.getMultiRegionFeatureDensityStats(t, e);
}
refIdToName(t) {
var e;
return (e = this.samHeader) === null || e === void 0 ? void 0 : e.idToName[t];
}
}
const zt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: Mt
}, Symbol.toStringTag, { value: "Module" }));
export {
Tt as B,
Ft as a,
Mt as b,
$t as c,
zt as d,
kt as p
};
//# sourceMappingURL=BamAdapter-eGpVgvvP.js.map