UNPKG

geneea-nlp-client

Version:

The TypeScript Client for Geneea Interpretor G3 API.

230 lines (229 loc) 8.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeUtils = exports.Node = void 0; const common_1 = require("./../../common/common"); /** * This is an implementation class, used as a super data class of Token and TectoToken. * We use the word node to refer to both tokens and tecto-tokens. * In general, we assume that any tree can be non-projective (i.e. generated by context-sensitive grammar), * even though the linear order of tecto-tokens has no meaning. * * All nodes in the tree have to be of the same type: either all Tokens or all TectoTokens. */ class Node { constructor() { /** Node that this node depends on. Null for the root or if no tree-structure is in the analysis. */ this.parent = null; /** Nodes that depend on this node, ordered by word-order; empty for leafs or if no tree-structure is in the analysis. */ this.children = []; } /** Check whether this node is a leaf (i.e has no dependents). */ isLeaf() { return this.children.length === 0; } /** Check whether this node is the root of the sentence. */ isRoot() { return this.parent === null; } /** Checks if the phrase dominated by this node is continuous. */ isContinuous() { return NodeUtils.isContinuous(this.coverage()); } /** Children of this node that precede it. */ leftChildren() { return this.children.filter((n) => n.idx < this.idx); } /** Children of this node that follow it. */ rigthChildren() { return this.children.filter((n) => n.idx > this.idx); } /** * Depth of this node in the dependency tree. * @returns The distance, i.e. number of dependency edges, from the root of the sentence. */ depth() { return this.parent !== null ? this.parent.depth() + 1 : 0; } /** * Parenthesised representation of the subtree of this node. * @param printToken Function printing individual nodes. * @returns A string representation of the tree rooted in this node. */ toTreeString(printToken) { if (this.children.length > 0) { const childrenStr = this.children .map((c) => c.toTreeString(printToken)) .join(","); return printToken(this) + "(" + childrenStr + ")"; } else { return printToken(this); } } /** * Indented string representation of the subtree of this node. * @param printToken A function printing individual nodes. * @param indentStr A string used to indent each level from the previous one. * @param depth Indentation level to start with. */ toIndentTreeString(printToken, indentStr = " ", depth = 0) { let childrenStr = ""; if (this.children.length > 0) { childrenStr = this.children .map((c) => c.toIndentTreeString(printToken, indentStr, depth + 1)) .join("\n"); childrenStr = "\n" + childrenStr + "\n"; } return (indentStr.repeat(depth) + printToken(this) + childrenStr); } /** Simple representation of this tree using toSimpleString to convert individual nodes. */ toSimpleTreeString() { return this.toTreeString((t) => t.toSimpleString()); } /** Simple indented representation of this tree using toSimpleString to convert individual nodes. */ toSimpleIndentString() { return this.toIndentTreeString((t) => t.toSimpleString()); } /** * All nodes dominated by this node. * @param reflexive Whether this node itself is included. * @param ordered Whether the result should be ordered by word order. */ coverage(reflexive = true, ordered = true) { const nodes = this.children .map((c) => c.coverage(true, false)) .reduce((acc, cur) => acc.concat(cur), []); if (reflexive) nodes.push(this); if (ordered) NodeUtils.sorted(nodes); return nodes; } /** In-order iterator over the subtree of this node. */ *inOrder() { for (const c of this.leftChildren()) { for (const cc of c.inOrder()) yield cc; } yield this; for (const c of this.rigthChildren()) { for (const cc of c.inOrder()) yield cc; } } /** * In-order iterator over the subtree of this node, optionally skipping some subtrees. * @param includeFilteredRoot If true, the nodes on which [skipPredicate] returns true are included in the result. * @param skipPredicate When this predicate is true on any node, the node's subtree is not traversed (skipping only their subtrees). */ *filteredInOrder(includeFilteredRoot = true, skipPredicate) { if (skipPredicate(this)) { if (includeFilteredRoot) { yield this; } } else { for (const c of this.leftChildren()) { for (const cc of c.filteredInOrder(includeFilteredRoot, skipPredicate)) yield cc; } yield this; for (const c of this.rigthChildren()) { for (const cc of c.filteredInOrder(includeFilteredRoot, skipPredicate)) yield cc; } } } /** Pre-order iterator over the subtree of this node. */ *preOrder() { yield this; for (const c of this.children) { for (const cc of c.preOrder()) yield cc; } } /** * Pre-order iterator over the subtree of this node, optionally skipping some subtrees. * @param includeFilteredRoot If true, the nodes on which [skipPredicate] returns true are included in the result (skipping only their subtrees). * @param skipPredicate When this predicate is true on any node, the node's subtree is not traversed. */ *filteredPreOrder(includeFilteredRoot = true, skipPredicate) { if (skipPredicate(this)) { if (includeFilteredRoot) yield this; } else { yield this; for (const c of this.children) { for (const cc of c.filteredPreOrder(includeFilteredRoot, skipPredicate)) yield cc; } } } } exports.Node = Node; class NodeUtils { /** * Orders the list of nodes in-place by word-order (i.e. their sentence index). * @param tokens A list of nodes, assumed to be from the same sentence (not checked). */ static sort(tokens) { return tokens.sort((a, b) => a.idx - b.idx); } /** * Orders a copy of this list of nodes by word-order (i.e. their sentence index). * @param tokens A list of nodes, assumed to be from the same sentenced (not checked). */ static sorted(tokens) { return [...tokens].sort((a, b) => a.idx - b.idx); } /** * Checks if this list of nodes is sorted by word-order (i.e. their sentence index). * @param tokens A list of nodes, assumed to be from the same sentenced (not checked). */ static isSorted(tokens) { return (0, common_1.isSorted)(tokens.map((t) => t.idx)); } /** * Checks if all nodes come from the same sentence. * @param tokens A list of nodes. * @returns true if the list of nodes is empty or all nodes are within the same sentence; false otherwise. */ static isFromSameSentence(tokens) { if (tokens.length === 0) { return true; } else { const sentence = tokens[0].sentence; return tokens.every((t) => t.sentence === sentence); } } /** * Checks if this list of nodes forms a continuous sequence. * Assumes the nodes to be sorted and from the same sentence (not checked). * @param tokens A list of nodes * @returns true if the list is continuous, false otherwise. */ static isContinuous(tokens) { return (0, common_1.isSequential)(tokens.map((t) => t.idx)); } /** * Utility method converting this list of nodes to a string with a simplified node representation, * using [Node.toSimpleString]. * @param tokens A list of nodes. * @param quote Should each node string be surrounded with double quotes? */ static toSimpleString(tokens, quote = false) { if (quote) { return ("[" + tokens.map((t) => '"' + t.toSimpleString() + '"').join(", ") + "]"); } else { return "[" + tokens.map((t) => t.toSimpleString()).join(", ") + "]"; } } } exports.NodeUtils = NodeUtils;