@jbrowse/core
Version:
JBrowse 2 core libraries used by plugins
242 lines (241 loc) • 7.76 kB
JavaScript
;
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;
}