UNPKG

taxonium-component

Version:

React component for exploring large phylogenetic trees in the browser

1,224 lines (1,223 loc) 39.1 kB
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