UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

305 lines (304 loc) 11.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = assemblyFactory; const abortable_promise_cache_1 = __importDefault(require("@gmod/abortable-promise-cache")); const mobx_1 = require("mobx"); const mobx_state_tree_1 = require("mobx-state-tree"); const configuration_1 = require("../configuration"); const util_1 = require("../data_adapters/util"); const util_2 = require("../util"); const QuickLRU_1 = __importDefault(require("../util/QuickLRU")); const refNameRegex = new RegExp('[0-9A-Za-z!#$%&+./:;?@^_|~-][0-9A-Za-z!#$%&*+./:;=?@^_|~-]*'); const refNameColors = [ 'rgb(153, 102, 0)', 'rgb(102, 102, 0)', 'rgb(153, 153, 30)', 'rgb(204, 0, 0)', 'rgb(255, 0, 0)', 'rgb(255, 0, 204)', 'rgb(165, 132, 132)', 'rgb(204, 122, 0)', 'rgb(178, 142, 0)', 'rgb(153, 153, 0)', 'rgb(122, 153, 0)', 'rgb(0, 165, 0)', 'rgb(53, 128, 0)', 'rgb(0, 0, 204)', 'rgb(96, 145, 242)', 'rgb(107, 142, 178)', 'rgb(0, 165, 165)', 'rgb(122, 153, 153)', 'rgb(153, 0, 204)', 'rgb(204, 51, 255)', 'rgb(173, 130, 216)', 'rgb(102, 102, 102)', 'rgb(145, 145, 145)', 'rgb(142, 142, 142)', 'rgb(142, 142, 107)', 'rgb(96, 163, 48)', ]; async function loadRefNameMap(assembly, adapterConfig, options, stopToken) { const { sessionId } = options; await (0, util_2.when)(() => !!(assembly.regions && assembly.refNameAliases), { name: 'when assembly ready', }); const refNames = (await assembly.rpcManager.call(sessionId || 'assemblyRpc', 'CoreGetRefNames', { adapterConfig, stopToken, ...options, }, { timeout: 1000000 })); const { refNameAliases } = assembly; if (!refNameAliases) { throw new Error(`error loading assembly ${assembly.name}'s refNameAliases`); } const refNameMap = Object.fromEntries(refNames.map(name => { checkRefName(name); return [assembly.getCanonicalRefName(name), name]; })); return { forwardMap: refNameMap, reverseMap: Object.fromEntries(Object.entries(refNameMap).map(([canonicalName, adapterName]) => [ adapterName, canonicalName, ])), }; } function checkRefName(refName) { if (!refNameRegex.test(refName)) { throw new Error(`Encountered invalid refName: "${refName}"`); } } function assemblyFactory(assemblyConfigType, pluginManager) { const adapterLoads = new abortable_promise_cache_1.default({ cache: new QuickLRU_1.default({ maxSize: 1000 }), async fill(args, _stopToken, statusCallback) { const { adapterConf, self, options } = args; return loadRefNameMap(self, adapterConf, { ...options, statusCallback }); }, }); return mobx_state_tree_1.types .model({ configuration: mobx_state_tree_1.types.safeReference(assemblyConfigType), }) .volatile(() => ({ error: undefined, loadingP: undefined, volatileRegions: undefined, refNameAliases: undefined, cytobands: undefined, })) .views(self => ({ getConf(arg) { return self.configuration ? (0, configuration_1.getConf)(self, arg) : undefined; }, get lowerCaseRefNameAliases() { return self.refNameAliases ? Object.fromEntries(Object.entries(self.refNameAliases).map(([key, val]) => { return [key.toLowerCase(), val]; })) : undefined; }, })) .views(self => ({ get initialized() { self.load(); return !!self.refNameAliases; }, get name() { return self.getConf('name') || ''; }, get regions() { self.load(); return self.volatileRegions; }, get aliases() { return self.getConf('aliases') || []; }, get displayName() { return self.getConf('displayName') || self.getConf('name') || ''; }, hasName(name) { return this.allAliases.includes(name); }, get allAliases() { return [this.name, ...this.aliases]; }, get allRefNames() { return !self.refNameAliases ? undefined : Object.keys(self.refNameAliases); }, get lowerCaseRefNames() { return !self.lowerCaseRefNameAliases ? undefined : Object.keys(self.lowerCaseRefNameAliases); }, get allRefNamesWithLowerCase() { return this.allRefNames && this.lowerCaseRefNames ? [...new Set([...this.allRefNames, ...this.lowerCaseRefNames])] : undefined; }, get rpcManager() { return (0, mobx_state_tree_1.getParent)(self, 2).rpcManager; }, get refNameColors() { const colors = self.getConf('refNameColors') || []; return colors.length === 0 ? refNameColors : colors; }, })) .views(self => ({ get refNames() { var _a; return (_a = self.regions) === null || _a === void 0 ? void 0 : _a.map(region => region.refName); }, })) .views(self => ({ getCanonicalRefName(refName) { if (!self.refNameAliases || !self.lowerCaseRefNameAliases) { throw new Error('aliases not loaded, we expect them to be loaded before getCanonicalRefName can be called'); } return (self.refNameAliases[refName] || self.lowerCaseRefNameAliases[refName]); }, getRefNameColor(refName) { if (!self.refNames) { return undefined; } const idx = self.refNames.indexOf(refName); return idx === -1 ? undefined : self.refNameColors[idx % self.refNameColors.length]; }, isValidRefName(refName) { if (!self.refNameAliases) { throw new Error('isValidRefName cannot be called yet, the assembly has not finished loading'); } return !!this.getCanonicalRefName(refName); }, })) .actions(self => ({ setLoaded({ regions, refNameAliases, cytobands, }) { this.setRegions(regions); this.setRefNameAliases(refNameAliases); this.setCytobands(cytobands); }, setError(e) { self.error = e; }, setRegions(regions) { self.volatileRegions = regions; }, setRefNameAliases(aliases) { self.refNameAliases = aliases; }, setCytobands(cytobands) { self.cytobands = cytobands; }, setLoadingP(p) { self.loadingP = p; }, load() { if (!self.loadingP) { self.loadingP = this.loadPre().catch((e) => { this.setLoadingP(undefined); this.setError(e); }); } return self.loadingP; }, async loadPre() { var _a, _b; var _c; const conf = self.configuration; const refNameAliasesAdapterConf = (_a = conf === null || conf === void 0 ? void 0 : conf.refNameAliases) === null || _a === void 0 ? void 0 : _a.adapter; const cytobandAdapterConf = (_b = conf === null || conf === void 0 ? void 0 : conf.cytobands) === null || _b === void 0 ? void 0 : _b.adapter; const sequenceAdapterConf = conf === null || conf === void 0 ? void 0 : conf.sequence.adapter; const assemblyName = self.name; const regions = await getAssemblyRegions({ config: sequenceAdapterConf, pluginManager, }); for (const r of regions) { checkRefName(r.refName); } const refNameAliases = {}; const refNameAliasCollection = await getRefNameAliases({ config: refNameAliasesAdapterConf, pluginManager, }); for (const { refName, aliases, override } of refNameAliasCollection) { for (const alias of aliases) { checkRefName(alias); refNameAliases[alias] = refName; } if (override) { refNameAliases[refName] = refName; } } for (const region of regions) { refNameAliases[_c = region.refName] || (refNameAliases[_c] = region.refName); } this.setLoaded({ refNameAliases, regions: regions.map(r => ({ ...r, refName: refNameAliases[r.refName] || r.refName, assemblyName, })), cytobands: await getCytobands({ config: cytobandAdapterConf, pluginManager, }), }); }, })) .views(self => ({ getAdapterMapEntry(adapterConf, options) { const { stopToken, statusCallback, ...rest } = options; if (!options.sessionId) { throw new Error('sessionId is required'); } return adapterLoads.get((0, util_1.adapterConfigCacheKey)(adapterConf), { adapterConf, self, options: rest, }, undefined, statusCallback); }, async getRefNameMapForAdapter(adapterConf, opts) { if (!opts.sessionId) { throw new Error('sessionId is required'); } const map = await this.getAdapterMapEntry(adapterConf, opts); return map.forwardMap; }, async getReverseRefNameMapForAdapter(adapterConf, opts) { const map = await this.getAdapterMapEntry(adapterConf, opts); return map.reverseMap; }, afterCreate() { (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => { self.allRefNamesWithLowerCase; })); }, })); } async function getRefNameAliases({ config, pluginManager, stopToken, }) { const type = pluginManager.getAdapterType(config.type); const CLASS = await type.getAdapterClass(); const adapter = new CLASS(config, undefined, pluginManager); return adapter.getRefNameAliases({ stopToken }); } async function getCytobands({ config, pluginManager, }) { const type = pluginManager.getAdapterType(config.type); const CLASS = await type.getAdapterClass(); const adapter = new CLASS(config, undefined, pluginManager); return adapter.getData(); } async function getAssemblyRegions({ config, pluginManager, stopToken, }) { const type = pluginManager.getAdapterType(config.type); const CLASS = await type.getAdapterClass(); const adapter = new CLASS(config, undefined, pluginManager); return adapter.getRegions({ stopToken }); }