molstar
Version:
A comprehensive macromolecular library.
345 lines (344 loc) • 13.8 kB
JavaScript
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { StateTree } from '../tree';
import { StateTransform } from '../transform';
var StateSelection;
(function (StateSelection) {
function select(s, state) {
return compile(s)(state);
}
StateSelection.select = select;
function compile(s) {
const selector = s ? s : Generators.root;
let query;
if (isBuilder(selector))
query = selector.compile();
else if (isObj(selector))
query = Generators.byValue(selector).compile();
else if (isQuery(selector))
query = selector;
else
query = Generators.byRef(selector).compile();
return query;
}
StateSelection.compile = compile;
function isObj(arg) {
return arg.transform !== void 0 && arg.status !== void 0;
}
function isBuilder(arg) {
return arg.compile !== void 0;
}
function isQuery(arg) {
return typeof arg === 'function';
}
const BuilderPrototype = {
select(state) {
return select(this, state || this.state);
}
};
function registerModifier(name, f) {
BuilderPrototype[name] = function (...args) { return f.call(void 0, this, ...args); };
}
function build(compile) {
return Object.create(BuilderPrototype, { compile: { writable: false, configurable: false, value: compile } });
}
let Generators;
(function (Generators) {
Generators.root = build(() => (state) => [state.cells.get(state.tree.root.ref)]);
function byRef(...refs) {
return build(() => (state) => {
const ret = [];
for (const ref of refs) {
const n = state.cells.get(ref);
if (!n)
continue;
ret.push(n);
}
return ret;
});
}
Generators.byRef = byRef;
function byValue(...objects) { return build(() => (state) => objects); }
Generators.byValue = byValue;
function rootsOfType(type, root = StateTransform.RootRef) {
return build(() => state => {
const ctx = { roots: [], cells: state.cells, type: type.type };
StateTree.doPreOrder(state.tree, state.tree.transforms.get(root), ctx, _findRootsOfType);
return ctx.roots;
});
}
Generators.rootsOfType = rootsOfType;
function ofType(type, root = StateTransform.RootRef) {
return build(() => state => {
const ctx = { ret: [], cells: state.cells, type: type.type };
StateTree.doPreOrder(state.tree, state.tree.transforms.get(root), ctx, _findOfType);
return ctx.ret;
});
}
Generators.ofType = ofType;
function ofTransformer(t, root = StateTransform.RootRef) {
return build(() => state => {
const ctx = { ret: [], cells: state.cells, t };
StateTree.doPreOrder(state.tree, state.tree.transforms.get(root), ctx, _findOfTransformer);
return ctx.ret;
});
}
Generators.ofTransformer = ofTransformer;
function ofTransformerWithError(t, root = StateTransform.RootRef) {
return build(() => state => {
const ctx = { ret: [], cells: state.cells, t };
StateTree.doPreOrder(state.tree, state.tree.transforms.get(root), ctx, _findOfTransformerWithError);
return ctx.ret;
});
}
Generators.ofTransformerWithError = ofTransformerWithError;
function _findRootsOfType(n, _, s) {
const cell = s.cells.get(n.ref);
if (cell && cell.obj && cell.obj.type === s.type) {
s.roots.push(cell);
return false;
}
return true;
}
function _findOfType(n, _, s) {
const cell = s.cells.get(n.ref);
if (cell && cell.obj && cell.obj.type === s.type) {
s.ret.push(cell);
}
return true;
}
function _findOfTransformer(n, _, s) {
const cell = s.cells.get(n.ref);
if (cell && cell.obj && cell.transform.transformer === s.t) {
s.ret.push(cell);
}
return true;
}
function _findOfTransformerWithError(n, _, s) {
const cell = s.cells.get(n.ref);
if (cell && cell.status === 'error' && cell.transform.transformer === s.t) {
s.ret.push(cell);
}
return true;
}
})(Generators = StateSelection.Generators || (StateSelection.Generators = {}));
registerModifier('flatMap', flatMap);
function flatMap(b, f) {
const q = compile(b);
return build(() => (state) => {
const ret = [];
for (const n of q(state)) {
for (const m of f(n, state)) {
ret.push(m);
}
}
return ret;
});
}
StateSelection.flatMap = flatMap;
registerModifier('mapObject', mapObject);
function mapObject(b, f) {
const q = compile(b);
return build(() => (state) => {
const ret = [];
for (const n of q(state)) {
const x = f(n, state);
if (x)
ret.push(x);
}
return ret;
});
}
StateSelection.mapObject = mapObject;
registerModifier('unique', unique);
function unique(b) {
const q = compile(b);
return build(() => (state) => {
const set = new Set();
const ret = [];
for (const n of q(state)) {
if (!n)
continue;
if (!set.has(n.transform.ref)) {
set.add(n.transform.ref);
ret.push(n);
}
}
return ret;
});
}
StateSelection.unique = unique;
registerModifier('first', first);
function first(b) {
const q = compile(b);
return build(() => (state) => {
const r = q(state);
return r.length ? [r[0]] : [];
});
}
StateSelection.first = first;
registerModifier('filter', filter);
function filter(b, p) { return flatMap(b, n => p(n) ? [n] : []); }
StateSelection.filter = filter;
registerModifier('withStatus', withStatus);
function withStatus(b, s) { return filter(b, n => n.status === s); }
StateSelection.withStatus = withStatus;
registerModifier('withTag', withTag);
function withTag(b, tag) { return filter(b, n => !!n.transform.tags && n.transform.tags.indexOf(tag) >= 0); }
StateSelection.withTag = withTag;
registerModifier('subtree', subtree);
function subtree(b) {
return flatMap(b, (n, s) => {
const nodes = [];
StateTree.doPreOrder(s.tree, s.tree.transforms.get(n.transform.ref), nodes, (x, _, ctx) => { ctx.push(x.ref); });
return nodes.map(x => s.cells.get(x));
});
}
StateSelection.subtree = subtree;
registerModifier('children', children);
function children(b) {
return flatMap(b, (n, s) => {
const nodes = [];
s.tree.children.get(n.transform.ref).forEach(c => nodes.push(s.cells.get(c)));
return nodes;
});
}
StateSelection.children = children;
registerModifier('ofType', ofType);
function ofType(b, t) { return filter(b, n => n.obj ? n.obj.type === t.type : false); }
StateSelection.ofType = ofType;
registerModifier('ancestor', ancestor);
function ancestor(b, test) { return unique(mapObject(b, (n, s) => findAncestor(s.tree, s.cells, n.transform.ref, test))); }
StateSelection.ancestor = ancestor;
registerModifier('ancestorOfType', ancestorOfType);
function ancestorOfType(b, types) { return unique(mapObject(b, (n, s) => findAncestorOfType(s.tree, s.cells, n.transform.ref, types))); }
StateSelection.ancestorOfType = ancestorOfType;
registerModifier('ancestorWithTransformer', ancestorWithTransformer);
function ancestorWithTransformer(b, transfomers) { return unique(mapObject(b, (n, s) => findAncestorWithTransformer(s.tree, s.cells, n.transform.ref, transfomers))); }
StateSelection.ancestorWithTransformer = ancestorWithTransformer;
registerModifier('withTransformer', withTransformer);
function withTransformer(b, t) { return filter(b, o => o.transform.transformer === t); }
StateSelection.withTransformer = withTransformer;
registerModifier('root', root);
function root(b, test) { return unique(mapObject(b, (n, s) => findRoot(s.tree, s.cells, n.transform.ref, test))); }
StateSelection.root = root;
registerModifier('rootOfType', rootOfType);
function rootOfType(b, types) { return unique(mapObject(b, (n, s) => findRootOfType(s.tree, s.cells, n.transform.ref, types))); }
StateSelection.rootOfType = rootOfType;
registerModifier('parent', parent);
function parent(b) { return unique(mapObject(b, (n, s) => s.cells.get(s.tree.transforms.get(n.transform.ref).parent))); }
StateSelection.parent = parent;
function _findAncestor(tree, cells, root, test, findClosest) {
let current = tree.transforms.get(root);
let ret = void 0;
while (true) {
current = tree.transforms.get(current.parent);
const cell = cells.get(current.ref);
if (cell.obj && test(cell)) {
ret = cell;
if (findClosest)
return ret;
}
if (current.ref === StateTransform.RootRef) {
return ret;
}
}
}
// Return first ancestor that satisfies the given test
function findAncestor(tree, cells, root, test) {
return _findAncestor(tree, cells, root, test, true);
}
StateSelection.findAncestor = findAncestor;
// Return last (with lowest depth) ancestor that satisfies the given test
function findRoot(tree, cells, root, test) {
return _findAncestor(tree, cells, root, test, false);
}
StateSelection.findRoot = findRoot;
function findAncestorWithTransformer(tree, cells, root, transfomers) {
return findAncestor(tree, cells, root, Array.isArray(transfomers)
? cell => transfomers.indexOf(cell.transform.transformer) >= 0
: cell => cell.transform.transformer === transfomers);
}
StateSelection.findAncestorWithTransformer = findAncestorWithTransformer;
function findAncestorOfType(tree, cells, root, types) {
return findAncestor(tree, cells, root, _testTypes(types));
}
StateSelection.findAncestorOfType = findAncestorOfType;
function findRootOfType(tree, cells, root, types) {
return findRoot(tree, cells, root, _testTypes(types));
}
StateSelection.findRootOfType = findRootOfType;
function _testTypes(types) {
return Array.isArray(types)
? (cell) => {
for (const t of types) {
if (t.type === cell.obj.type)
return true;
}
} : (cell) => cell.obj.type === types.type;
}
function findUniqueTagsInSubtree(tree, root, tags) {
return StateTree.doPreOrder(tree, tree.transforms.get(root), { refs: {}, tags }, _findUniqueTagsInSubtree).refs;
}
StateSelection.findUniqueTagsInSubtree = findUniqueTagsInSubtree;
function _findUniqueTagsInSubtree(n, _, s) {
if (n.tags) {
for (const t of n.tags) {
if (!s.tags.has(t))
continue;
s.refs[t] = n.ref;
break;
}
}
return true;
}
function findTagInSubtree(tree, root, tag) {
return StateTree.doPreOrder(tree, tree.transforms.get(root), { ref: void 0, tag }, _findTagInSubtree).ref;
}
StateSelection.findTagInSubtree = findTagInSubtree;
function _findTagInSubtree(n, _, s) {
if (n.tags && n.tags.indexOf(s.tag) >= 0) {
s.ref = n.ref;
return false;
}
return true;
}
function findWithAllTags(tree, root, tags) {
return StateTree.doPreOrder(tree, tree.transforms.get(root), { refs: [], tags }, _findWithAllTags).refs;
}
StateSelection.findWithAllTags = findWithAllTags;
function _findWithAllTags(n, _, s) {
if (n.tags) {
const len = s.tags.size;
let found = 0;
for (const t of n.tags) {
if (!s.tags.has(t))
continue;
found++;
if (found === len) {
s.refs.push(n);
break;
}
}
}
else if (s.tags.size === 0) {
s.refs.push(n);
}
}
function tryFindDecorator(state, root, transformer) {
const t = state.transforms.get(root);
if (t.transformer === transformer)
return state.cells.get(root);
const children = state.tree.children.get(root);
if (children.size !== 1)
return;
const first = children.first();
if (first && state.transforms.get(first).transformer.definition.isDecorator)
return tryFindDecorator(state, first, transformer);
}
StateSelection.tryFindDecorator = tryFindDecorator;
})(StateSelection || (StateSelection = {}));
export { StateSelection };