taxonium-component
Version:
React component for exploring large phylogenetic trees in the browser
189 lines (188 loc) • 5.9 kB
JavaScript
import { A as b } from "./AbortablePromiseCache-CcuMrnn7.js";
import "./unzip-ASAuJ12U.js";
import { aX as d, a4 as h, u as S, R as F } from "./JBrowsePanel-uJIA-L6s.js";
import { B as I } from "./index-BnQfM3Nw.js";
import { Q as L } from "./QuickLRU-DcNaxluI.js";
import { r as k } from "./rxjs-BnZkaVAs.js";
function x(r, e) {
return r.offset + r.lineBytes * Math.floor(e / r.lineLength) + e % r.lineLength;
}
async function A(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 E {
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 = A(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 = x(e, s), o = x(e, a) - i;
return new TextDecoder("utf8").decode(await this.fasta.read(o, i, n)).replace(/\s+/g, "");
}
}
class O extends I.BaseSequenceAdapter {
constructor() {
super(...arguments), this.seqCache = new b({
cache: new L({ 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 E({
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 k.ObservableCreate(async (f) => {
await S.updateStatus2("Downloading sequence", t, n, async () => {
const { fasta: l } = await this.setup(), q = await l.getSequenceSize(a), p = Math.min(q || 0, o), g = [], u = 128e3, m = i - i % u, _ = o + (u - o % u);
for (let c = m; c < _; c += u) {
const w = {
refName: a,
start: c,
end: c + u
};
F.checkStopToken(n), g.push(await this.seqCache.get(JSON.stringify(w), { ...w, fasta: l }));
}
const y = g.filter((c) => !!c).join("").slice(i - m).slice(0, o - i);
y && f.next(new S.SimpleFeature({
id: `${a}-${i}-${p}`,
data: {
refName: a,
start: i,
end: p,
seq: y
}
}));
}), f.complete();
});
}
}
const P = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
default: O
}, Symbol.toStringTag, { value: "Module" }));
export {
E as I,
O as a,
P as b
};
//# sourceMappingURL=IndexedFastaAdapter-3PsrnaWp.js.map