UNPKG

geneea-nlp-client

Version:

The TypeScript Client for Geneea Interpretor G3 API.

107 lines (106 loc) 4.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TreeBuilder = exports.Tree = void 0; const common_1 = require("./../../common/common"); const node_1 = require("./node"); /** A temporary class used during the construction of a tree of tokens or tecto-tokens. */ class Tree { constructor(root, tokens) { this.root = root; this.tokens = tokens; } } exports.Tree = Tree; class TreeBuilder { constructor() { this.nodes = []; /** Dependency edges between nodes. */ this.deps = new Map(); } /** * Record a single token as a node of the tree. * @param node Token to add. Its index must be correct, parent and children fields are ignored. * @returns The builder to allow chained calls. */ addNode(node) { this.nodes.push(node); return this; } /** * Record a collection of tokens as nodes of the tree. * @param nodes Tokens to add. Their index must be correct, parent and children fields are ignored. * @returns The builder to allow chained calls. */ addNodes(nodes) { for (const n of nodes) this.nodes.push(n); return this; } /** * Record a dependency edge. The tokens connected by the edge might be added later. * @param childIdx Index of the child token (note: tokens are indexed within their sentence). * @param parentIdx Index of the parent token (note: tokens are indexed within their sentence); * @returns The builder to allow chained calls. */ addDependency(childIdx, parentIdx) { if (childIdx < 0) throw new Error(`Negative node index ${childIdx}.`); if (parentIdx < 0) throw new Error(`Negative node index ${parentIdx}`); if (childIdx === parentIdx) throw new Error("Dependency edge cannot be reflexive."); if (this.deps.has(childIdx) && this.deps.get(childIdx) !== parentIdx) throw new Error(`Node ${childIdx} has multiple parents: [${this.nodes[parentIdx].id}, ${this.nodes[this.deps.get(childIdx)].id}].`); this.deps.set(childIdx, parentIdx); return this; } /** All nodes are hanged to the first one. */ addDummyDependencies() { if (this.deps.size !== 0) throw new Error("Dummy dependencies cannot be added when other dependencies have been specified."); if (this.nodes.length === 0) return; node_1.NodeUtils.sort(this.nodes); for (const n of this.nodes.slice(1)) this.addDependency(n.idx, 0); } fillParents() { const maxIdx = this.nodes.length - 1; for (const [c, p] of this.deps) { if (c > maxIdx) throw new Error(`The child of the dependency edge ${c} -> ${p} is out of range (max=${maxIdx}).`); if (p > maxIdx) throw new Error(`The parent of the dependency edge ${c} -> ${p} is out of range (max=${maxIdx}).`); this.nodes[c].parent = this.nodes[p]; } } findRoot() { const roots = this.nodes.filter((n) => n.isRoot()); if (roots.length === 0) throw new Error("No root."); if (roots.length > 1) throw new Error(`Multiple roots: ${roots.map((r) => r.id)}.`); return roots[0]; } fillChildren() { for (const n of this.nodes) { n.children = this.nodes.filter((x) => x.parent === n); } } /** Builds a tree based on the current state. Should not be called more than once. */ build() { if (this.nodes.length === 0) return null; // Creates an ordered dependency tree based on the contents this builder. node_1.NodeUtils.sort(this.nodes); if (this.nodes[0].idx !== 0 || !(0, common_1.isSequential)(this.nodes.map((x) => x.idx))) { throw new Error("Indexes are not sequential."); } this.fillParents(); const root = this.findRoot(); // exactly one root check; addDependency checks for multiple parents => tree this.fillChildren(); return new Tree(root, this.nodes); } } exports.TreeBuilder = TreeBuilder;