geneea-nlp-client
Version:
The TypeScript Client for Geneea Interpretor G3 API.
230 lines (229 loc) • 8.79 kB
JavaScript
;
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;