UNPKG

read-gedcom

Version:
300 lines 12 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _SelectionAny_instances, _SelectionAny_selfConstructor; import { enumerable } from '../meta'; import { nodeToString } from '../tree'; import { SelectionGedcom } from './internal'; /** * A selection of Gedcom nodes, represented in an array-like datastructure. */ export class SelectionAny { /** * @param rootNode * @param nodes * @category Base */ constructor(rootNode, nodes) { _SelectionAny_instances.add(this); this.rootNode = rootNode; this.length = nodes.length; for (let i = 0; i < nodes.length; i++) { this[i] = nodes[i]; } } /** * Returns an array of {@link TreeNode.tag}. * @category Base */ tag() { const array = []; for (let i = 0; i < this.length; i++) { array.push(this[i].tag); } return array; } /** * Returns an array of {@link TreeNode.pointer}. * @category Base */ pointer() { const array = []; for (let i = 0; i < this.length; i++) { array.push(this[i].pointer); } return array; } /** * Returns an array of {@link TreeNode.value}. * @category Base */ value() { const array = []; for (let i = 0; i < this.length; i++) { array.push(this[i].value); } return array; } /** * Calls {@link value} and filters out <code>null</code> values. * @category Base */ valueNonNull() { return this.value().filter((v) => v !== null); } /** * Wraps the value of {@link rootNode} in {@link SelectionGedcom}. * The selection will contain exactly one node. * @category Base */ root() { return new SelectionGedcom(this.rootNode, [this.rootNode]); } // Implementation get(tag, pointer, adapter) { const Adapter = adapter != null ? adapter : SelectionAny; // Type safety of this cast is enforced by the signature of the visible methods const tags = tag != null ? (Array.isArray(tag) ? tag : [tag]) : null; const pointers = pointer != null ? (Array.isArray(pointer) ? pointer : [pointer]) : null; const selection = []; for (let i = 0; i < this.length; i++) { const node = this[i]; if (tags === null && pointers === null) { // No need of index node.children.forEach(child => selection.push(child)); } else if (node._index !== undefined) { // Use index const index = node._index; const intermediary = []; const requiresSorting = (tags !== null && tags.length > 0) || (pointers !== null && pointers.length > 0); if (pointers !== null) { const rootIndex = index; if (rootIndex.byTagPointer !== undefined) { // If the cast is unsafe then the selection should be empty if (tags !== null) { tags.forEach(t => pointers.forEach(p => { const childIdx = rootIndex.byTagPointer[t][p]; if (childIdx !== undefined) { intermediary.push(node.children[childIdx]); } })); } else { Object.values(rootIndex.byTagPointer).forEach(nodes => pointers.forEach(p => { const childIdx = nodes[p]; if (childIdx !== undefined) { intermediary.push(node.children[childIdx]); } })); } } } else { const tagsNonNull = tags; // Safe cast tagsNonNull.forEach(t => { const nodesIdx = index.byTag[t]; if (nodesIdx !== undefined) { nodesIdx.forEach(childIdx => intermediary.push(node.children[childIdx])); } }); } if (requiresSorting) { intermediary.sort((a, b) => a.indexSource - b.indexSource); } intermediary.forEach(child => selection.push(child)); } else { // No index fallback node.children.filter(child => (tags === null || (child.tag !== null && tags.includes(child.tag))) && (pointers === null || (child.pointer !== null && pointers.includes(child.pointer)))).forEach(child => selection.push(child)); } } return new Adapter(this.rootNode, selection); } /** * Filter nodes from the selection based on a predicate. * @param f The filtering predicate * @category Base */ filter(f) { const nodes = []; for (let i = 0; i < this.length; i++) { const node = this[i]; if (f(node)) { nodes.push(node); } } const Constructor = __classPrivateFieldGet(this, _SelectionAny_instances, "m", _SelectionAny_selfConstructor).call(this); return new Constructor(this.rootNode, nodes); } /** * Filter lifted nodes from the selection based on a predicate. * The argument is a selection of one node. * @param f The filtering predicate * @category Base */ filterSelect(f) { const Constructor = __classPrivateFieldGet(this, _SelectionAny_instances, "m", _SelectionAny_selfConstructor).call(this); const nodes = []; for (let i = 0; i < this.length; i++) { const node = this[i]; if (f(new Constructor(this.rootNode, [node]))) { nodes.push(node); } } return new Constructor(this.rootNode, nodes); } /** * View this selection as a different type. This method can be used to extend functionality for non-standard Gedcom files. * @param Adapter The class adapter * @category Base */ as(Adapter) { return new Adapter(this.rootNode, this); } /** * Export the selection as an array of nodes. * The inverse operation is {@link of}. * @category Base */ array() { const array = []; for (let i = 0; i < this.length; i++) { array.push(this[i]); } return array; } /** * Exports the selection as an array of selections of one element. * @category Base */ arraySelect() { const Constructor = __classPrivateFieldGet(this, _SelectionAny_instances, "m", _SelectionAny_selfConstructor).call(this); const array = []; for (let i = 0; i < this.length; i++) { array.push(new Constructor(this.rootNode, [this[i]])); } return array; } /** * Returns a concatenation of two selections. * The right hand side selection should be a subtype of the left hand side's. * The resulting selection will be the same type as the left hand side's. * @param other The right hand side selection * @category Base */ concatenate(other) { const Constructor = __classPrivateFieldGet(this, _SelectionAny_instances, "m", _SelectionAny_selfConstructor).call(this); const nodes = []; for (let i = 0; i < this.length; i++) { nodes.push(this[i]); } for (let i = 0; i < other.length; i++) { nodes.push(other[i]); } return new Constructor(this.rootNode, nodes); } /** * Returns a concatenation of two selections. * The right hand side selection should be a subtype of the left hand side's. * The resulting selection will be the same type as the left hand side's, with the elements of the right hand side's first. * @param other The right hand side selection * @category Base */ concatenateLeft(other) { const Constructor = __classPrivateFieldGet(this, _SelectionAny_instances, "m", _SelectionAny_selfConstructor).call(this); const nodes = []; for (let i = 0; i < other.length; i++) { nodes.push(other[i]); } for (let i = 0; i < this.length; i++) { nodes.push(this[i]); } return new Constructor(this.rootNode, nodes); } /** * Returns a sorted selection, with respect to the comparator. * The default comparator relies on the {@link TreeNode.indexSource} attribute. * @param comparator The comparator * @category Base */ sorted(comparator = (a, b) => a.indexSource - b.indexSource) { const Constructor = __classPrivateFieldGet(this, _SelectionAny_instances, "m", _SelectionAny_selfConstructor).call(this); const nodes = []; for (let i = 0; i < this.length; i++) { nodes.push(this[i]); } nodes.sort(comparator); return new Constructor(this.rootNode, nodes); } /** * Checks whether two selections are equal. * Note that the strategy used here is reference equality, hence for this method to return <code>true</code>, the nodes must be the same references (and in the same order). * @param other The selection to compare it against * @category Base */ equals(other) { if (this.length !== other.length) { return false; } for (let i = 0; i < this.length; i++) { if (this[i] !== other[i]) { return false; } } return true; } /** * Returns a string representation for this selection. * @category Base */ toString() { return this.length > 0 ? this.array().map(nodeToString).join('\n\n') : '(empty selection)'; } // Implementation static of(previous, nodes, Adapter) { const AdapterClass = Adapter != null ? Adapter : SelectionAny; const nodesArray = Array.isArray(nodes) ? nodes : [nodes]; return new AdapterClass(previous.rootNode, nodesArray); } } _SelectionAny_instances = new WeakSet(), _SelectionAny_selfConstructor = function _SelectionAny_selfConstructor() { if (Object.getPrototypeOf !== undefined) { return Object.getPrototypeOf(this).constructor; } else { return this.__proto__.constructor; // eslint-disable-line no-proto } }; __decorate([ enumerable(false), __metadata("design:type", Object) ], SelectionAny.prototype, "rootNode", void 0); //# sourceMappingURL=SelectionAny.js.map