UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

242 lines (241 loc) 7.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = ConfigSlot; const mobx_state_tree_1 = require("mobx-state-tree"); const util_1 = require("../util"); const jexlStrings_1 = require("../util/jexlStrings"); const mst_1 = require("../util/types/mst"); function isValidColorString() { return true; } const typeModels = { stringArray: mobx_state_tree_1.types.array(mobx_state_tree_1.types.string), stringArrayMap: mobx_state_tree_1.types.map(mobx_state_tree_1.types.array(mobx_state_tree_1.types.string)), numberMap: mobx_state_tree_1.types.map(mobx_state_tree_1.types.number), boolean: mobx_state_tree_1.types.boolean, color: mobx_state_tree_1.types.refinement('Color', mobx_state_tree_1.types.string, isValidColorString), integer: mobx_state_tree_1.types.integer, number: mobx_state_tree_1.types.number, string: mobx_state_tree_1.types.string, text: mobx_state_tree_1.types.string, fileLocation: mst_1.FileLocation, frozen: mobx_state_tree_1.types.frozen(), }; const fallbackDefaults = { stringArray: [], stringArrayMap: {}, numberMap: {}, boolean: true, color: 'black', integer: 1, number: 1, string: '', text: '', fileLocation: { uri: '/path/to/resource.txt', locationType: 'UriLocation' }, frozen: {}, }; const literalJSON = (self) => ({ views: { get valueJSON() { return self.value; }, }, }); const objectJSON = (self) => ({ views: { get valueJSON() { return JSON.stringify(self.value); }, }, }); const typeModelExtensions = { fileLocation: objectJSON, number: literalJSON, integer: literalJSON, boolean: literalJSON, frozen: objectJSON, stringArray: (self) => ({ views: { get valueJSON() { return JSON.stringify(self.value); }, }, actions: { add(val) { self.value.push(val); }, removeAtIndex(idx) { self.value.splice(idx, 1); }, setAtIndex(idx, val) { self.value[idx] = val; }, }, }), stringArrayMap: (self) => ({ views: { get valueJSON() { return JSON.stringify(self.value); }, }, actions: { add(key, val) { self.value.set(key, val); }, remove(key) { self.value.delete(key); }, addToKey(key, val) { const ar = self.value.get(key); if (!ar) { throw new Error(`${key} not found`); } ar.push(val); }, removeAtKeyIndex(key, idx) { const ar = self.value.get(key); if (!ar) { throw new Error(`${key} not found`); } ar.splice(idx, 1); }, setAtKeyIndex(key, idx, val) { const ar = self.value.get(key); if (!ar) { throw new Error(`${key} not found`); } ar[idx] = val; }, }, }), numberMap: (self) => ({ views: { get valueJSON() { return JSON.stringify(self.value); }, }, actions: { add(key, val) { self.value.set(key, val); }, remove(key) { self.value.delete(key); }, }, }), }; const JexlStringType = mobx_state_tree_1.types.refinement('JexlString', mobx_state_tree_1.types.string, str => str.startsWith('jexl:')); function json(value) { return (value === null || value === void 0 ? void 0 : value.toJSON) ? value.toJSON() : `"${value}"`; } function ConfigSlot(slotName, { description = '', model, type, defaultValue, contextVariable = [], }) { if (!type) { throw new Error('type name required'); } if (!model) { model = typeModels[type]; } if (!model) { throw new Error(`no builtin config slot type "${type}", and no 'model' param provided`); } if (defaultValue === undefined) { throw new Error("no 'defaultValue' provided"); } const configSlotModelName = `${slotName .charAt(0) .toUpperCase()}${slotName.slice(1)}ConfigSlot`; let slot = mobx_state_tree_1.types .model(configSlotModelName, { name: mobx_state_tree_1.types.literal(slotName), description: mobx_state_tree_1.types.literal(description), type: mobx_state_tree_1.types.literal(type), value: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.union(JexlStringType, model), defaultValue), }) .volatile(() => ({ contextVariable, })) .views(self => ({ get isCallback() { return String(self.value).startsWith('jexl:'); }, })) .views(self => ({ get expr() { if (self.isCallback) { const { pluginManager } = (0, util_1.getEnv)(self); if (!pluginManager && typeof jest === 'undefined') { console.warn('no pluginManager detected on config env (if you dynamically instantiate a config, for example in renderProps for your display model, check that you add the env argument)'); } return (0, jexlStrings_1.stringToJexlExpression)(String(self.value), pluginManager === null || pluginManager === void 0 ? void 0 : pluginManager.jexl); } return { evalSync: () => self.value }; }, get valueJSON() { if (self.isCallback) { return undefined; } return json(self.value); }, })) .preProcessSnapshot(val => typeof val === 'object' && val.name === slotName ? val : { name: slotName, description, type, value: val, }) .postProcessSnapshot(snap => { if (typeof snap.value === 'object') { return JSON.stringify(snap.value) !== JSON.stringify(defaultValue) ? snap.value : undefined; } return snap.value !== defaultValue ? snap.value : undefined; }) .actions(self => ({ set(newVal) { self.value = newVal; }, reset() { self.value = defaultValue; }, convertToCallback() { if (self.isCallback) { return; } self.value = `jexl:${self.valueJSON || "''"}`; }, convertToValue() { if (!self.isCallback) { return; } try { const funcResult = self.expr.evalSync(); if (funcResult !== undefined) { self.value = funcResult; return; } } catch (e) { } self.value = defaultValue; if (!(type in fallbackDefaults)) { throw new Error(`no fallbackDefault defined for type ${type}`); } self.value = fallbackDefaults[type]; }, })); if (typeModelExtensions[type]) { slot = slot.extend(typeModelExtensions[type]); } const completeModel = mobx_state_tree_1.types.optional(slot, { name: slotName, type, description, value: defaultValue, }); const m = completeModel; Object.defineProperty(m, 'isJBrowseConfigurationSlot', { value: true }); return m; }