taxonium-component
Version:
React component for exploring large phylogenetic trees in the browser
197 lines (196 loc) • 6.05 kB
JavaScript
import { A as L } from "./AbortablePromiseCache-CcuMrnn7.js";
import "./unzip-NIBF0hze.js";
import { L as d } from "./browser-BpRiKmO-.js";
import { B as F } from "./index-CpJXUZUB.js";
import { a1 as h, u as x, O as I } from "./JBrowsePanel-BNE3gNW1.js";
import { Q as k } from "./QuickLRU-BaqKky94.js";
import { r as A } from "./rxjs-L4bS73F7.js";
function q(r, e) {
return r.offset + r.lineBytes * Math.floor(e / r.lineLength) + e % r.lineLength;
}
async function E(r, e = {}) {
const s = new TextDecoder("utf8");
return Object.fromEntries(s.decode(await r.readFile(e)).split(/\r?\n/).map((t) => t.trim()).filter((t) => !!t).map((t) => t.split(" ")).map((t) => {
var n;
if ((n = t[0]) != null && n.startsWith(">"))
throw new Error("found > in sequence name, might have supplied FASTA file for the FASTA index");
return [
t[0],
{
name: t[0],
length: +t[1],
start: 0,
end: +t[1],
offset: +t[2],
lineLength: +t[3],
lineBytes: +t[4]
}
];
}));
}
class O {
constructor({ fasta: e, fai: s, path: t, faiPath: n }) {
if (e)
this.fasta = e;
else if (t)
this.fasta = new d(t);
else
throw new Error("Need to pass filehandle for fasta or path to localfile");
if (s)
this.fai = s;
else if (n)
this.fai = new d(n);
else if (t)
this.fai = new d(`${t}.fai`);
else
throw new Error("Need to pass filehandle for or path to localfile");
}
async _getIndexes(e) {
return this.indexes || (this.indexes = E(this.fai, e).catch((s) => {
throw this.indexes = void 0, s;
})), this.indexes;
}
/**
* @returns array of string sequence names that are present in the index, in
* which the array index indicates the sequence ID, and the value is the
* sequence name
*/
async getSequenceNames(e) {
return Object.keys(await this._getIndexes(e));
}
/**
* @returns array of string sequence names that are present in the index, in
* which the array index indicates the sequence ID, and the value is the
* sequence name
*/
async getSequenceSizes(e) {
const s = {}, t = await this._getIndexes(e);
for (const n of Object.values(t))
s[n.name] = n.length;
return s;
}
/**
* @returns array of string sequence names that are present in the index, in
* which the array index indicates the sequence ID, and the value is the
* sequence name
*/
async getSequenceSize(e, s) {
var n;
return (n = (await this._getIndexes(s))[e]) == null ? void 0 : n.length;
}
/**
* @param name
*
* @returns true if the file contains the given reference sequence name
*/
async hasReferenceSequence(e, s) {
return !!(await this._getIndexes(s))[e];
}
/**
* @param seqName
* @param min
* @param max
*/
async getResiduesByName(e, s, t, n) {
const a = (await this._getIndexes(n))[e];
return a ? this._fetchFromIndexEntry(a, s, t, n) : void 0;
}
//alias for getResiduesByName
async getSequence(e, s, t, n) {
return this.getResiduesByName(e, s, t, n);
}
async _fetchFromIndexEntry(e, s = 0, t, n) {
let a = t;
if (s < 0)
throw new TypeError("regionStart cannot be less than 0");
if ((a === void 0 || a > e.length) && (a = e.length), s >= a)
return "";
const i = q(e, s), o = q(e, a) - i;
return new TextDecoder("utf8").decode(await this.fasta.read(o, i, n)).replace(/\s+/g, "");
}
}
class j extends F.BaseSequenceAdapter {
constructor() {
super(...arguments), this.seqCache = new L({
cache: new k({ maxSize: 200 }),
fill: async (e) => {
const { refName: s, start: t, end: n, fasta: a } = e;
return a.getSequence(s, t, n);
}
});
}
async getRefNames(e) {
const { fasta: s } = await this.setup();
return s.getSequenceNames();
}
async getRegions(e) {
const { fasta: s } = await this.setup(), t = await s.getSequenceSizes();
return Object.keys(t).map((n) => ({
refName: n,
start: 0,
end: t[n]
}));
}
async setupPre() {
const e = this.getConf("fastaLocation"), s = this.getConf("faiLocation");
return {
fasta: new O({
fasta: h.openLocation(e, this.pluginManager),
fai: h.openLocation(s, this.pluginManager)
})
};
}
async getHeader() {
const e = this.getConf("metadataLocation");
return e.uri === "" || e.uri === "/path/to/fa.metadata.yaml" ? null : h.openLocation(e, this.pluginManager).readFile("utf8");
}
async setup() {
return this.setupP || (this.setupP = this.setupPre().catch((e) => {
throw this.setupP = void 0, e;
})), this.setupP;
}
getFeatures(e, s) {
const { statusCallback: t = () => {
}, stopToken: n } = s || {}, { refName: a, start: i, end: o } = e;
return A.ObservableCreate(async (u) => {
await x.updateStatus2("Downloading sequence", t, n, async () => {
const { fasta: l } = await this.setup(), b = await l.getSequenceSize(a), p = Math.min(b || 0, o), g = [], f = 128e3, m = i - i % f, _ = o + (f - o % f);
for (let c = m; c < _; c += f) {
const w = {
refName: a,
start: c,
end: c + f
};
I.checkStopToken(n);
const S = await this.seqCache.get(JSON.stringify(w), {
...w,
fasta: l
});
if (!S)
break;
g.push(S);
}
const y = g.filter((c) => !!c).join("").slice(i - m).slice(0, o - i);
y && u.next(new x.SimpleFeature({
id: `${a}-${i}-${p}`,
data: {
refName: a,
start: i,
end: p,
seq: y
}
}));
}), u.complete();
});
}
}
const R = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: j
}, Symbol.toStringTag, { value: "Module" }));
export {
O as I,
j as a,
R as b
};
//# sourceMappingURL=IndexedFastaAdapter-CqEccOzJ.js.map