From dd33ebd03bc9f569dc70249553e98691f47386bd Mon Sep 17 00:00:00 2001 From: David Chanin Date: Thu, 28 Dec 2023 15:37:35 -0500 Subject: [PATCH] chore: fixing doc-comments for tsdoc --- src/lib/_format.ts | 55 ++++----- src/lib/_lexer.ts | 27 ++--- src/lib/_parse.ts | 72 ++++++------ src/lib/codec.ts | 49 ++++---- src/lib/constant.ts | 96 +++++++--------- src/lib/epigraph.ts | 16 +-- src/lib/graph.ts | 76 ++++++------ src/lib/layout.ts | 267 +++++++++++++++++++++---------------------- src/lib/model.ts | 221 ++++++++++++++++------------------- src/lib/surface.ts | 89 ++++++++------- src/lib/transform.ts | 209 +++++++++++++++++---------------- src/lib/tree.ts | 77 ++++++------- 12 files changed, 609 insertions(+), 645 deletions(-) diff --git a/src/lib/_format.ts b/src/lib/_format.ts index 199a72d..699000d 100644 --- a/src/lib/_format.ts +++ b/src/lib/_format.ts @@ -3,21 +3,22 @@ import { BasicTriple, Branch, Node } from './types'; import { lstrip } from './utils'; /** - * Format *tree* into a PENMAN string. + * Format a `Tree` object into a PENMAN string. * - * Args: - * tree: a Tree object - * indent: how to indent formatted strings - * compact: if ``True``, put initial attributes on the first line - * Returns: - * the PENMAN-serialized string of the Tree *t* - * Example: - * >>> import penman - * >>> print(penman.format( - * ... ('b', [('/', 'bark-01'), - * ... (':ARG0', ('d', [('/', 'dog')]))]))) - * (b / bark-01 - * :ARG0 (d / dog)) + * @param tree - A Tree object. + * @param indent - How to indent formatted strings. + * @param compact - If `true`, put initial attributes on the first line. + * @returns The PENMAN-serialized string of the `Tree` object. + * @example + * import { format } from 'penman-js'; + * + * console.log(format( + * ['b', [['/', 'bark-01'], + * [':ARG0', ['d', [['/', 'dog']]]]] + * ] + * )); + * // (b / bark-01 + * // :ARG0 (d / dog)) */ export const format = ( tree: Tree | Node, @@ -36,21 +37,21 @@ export const format = ( }; /** - * Return the formatted triple conjunction of *triples*. + * Return the formatted triple conjunction of `triples`. + * + * @param triples - An iterable of triples. + * @param indent - How to indent formatted strings. + * @returns The serialized triple conjunction of `triples`. + * @example + * import { decode, formatTriples } from 'penman-js'; * - * Args: - * triples: an iterable of triples - * indent: how to indent formatted strings - * Returns: - * the serialized triple conjunction of *triples* - * Example: - * >>> import penman - * >>> g = penman.decode('(b / bark-01 :ARG0 (d / dog))') - * >>> print(penman.format_triples(g.triples)) - * instance(b, bark-01) ^ - * ARG0(b, d) ^ - * instance(d, dog) + * const g = decode('(b / bark-01 :ARG0 (d / dog))'); + * console.log(formatTriples(g.triples)); + * // instance(b, bark-01) ^ + * // ARG0(b, d) ^ + * // instance(d, dog) */ + export const formatTriples = ( triples: BasicTriple[], indent = true, diff --git a/src/lib/_lexer.ts b/src/lib/_lexer.ts index b31a452..238200f 100644 --- a/src/lib/_lexer.ts +++ b/src/lib/_lexer.ts @@ -108,9 +108,7 @@ export class TokenIterator { /** * Advance the iterator and return the next token. * - * Raises: - * StopIteration - * If the iterator is already exhausted. + * @throws {Error} If the iterator is already exhausted. */ next(): IteratorResult { const current = this._next; @@ -126,14 +124,13 @@ export class TokenIterator { } /** - * Return the next token if its type is in *choices*. + * Return the next token if its type is in `choices`. * * The iterator is advanced if successful. * - * Raises: - * ~penman.exceptions.DecodeError - * If the next token type is not in *choices*. + * @throws {DecodeError} If the next token type is not in `choices`. */ + expect(...choices: string[]): Token { const token = this.next(); if (token.done) { @@ -180,18 +177,14 @@ export class TokenIterator { } /** - * Yield PENMAN tokens matched in *lines*. - * - * By default, this lexes strings in *lines* using the basic pattern - * for PENMAN graphs. If *pattern* is given, it is used for lexing - * instead. + * Yield PENMAN tokens matched in `lines`. * - * Args: - * lines: iterable of lines to lex - * pattern: pattern to use for lexing instead of the default ones + * By default, this function lexes strings in `lines` using the basic pattern + * for PENMAN graphs. If `pattern` is provided, it is used for lexing instead. * - * Returns: - * A :class:`TokenIterator` object + * @param lines - An iterable of lines to lex. + * @param pattern - The pattern to use for lexing instead of the default ones. + * @returns A `TokenIterator` object. */ export const lex = ( lines: Iterable | string, diff --git a/src/lib/_parse.ts b/src/lib/_parse.ts index a036bb4..9b18b62 100644 --- a/src/lib/_parse.ts +++ b/src/lib/_parse.ts @@ -4,37 +4,40 @@ import { Tree } from './tree'; import { BasicTriple, Branch, Node, Target } from './types'; /** - * Parse PENMAN-notation string *s* into its tree structure. + * Parse a PENMAN-notation string `s` into its tree structure. * - * Args: - * s: a string containing a single PENMAN-serialized graph - * Returns: - * The tree structure described by *s*. - * Example: - * >>> import penman - * >>> penman.parse('(b / bark-01 :ARG0 (d / dog))') // noqa - * Tree(('b', [('/', 'bark-01'), (':ARG0', ('d', [('/', 'dog')]))])) + * @param s - A string containing a single PENMAN-serialized graph. + * @returns The tree structure described by `s`. + * @example + * import { parse } from 'penman-js'; + * + * const tree = parse('(b / bark-01 :ARG0 (d / dog))'); + * console.log(tree); + * + * // Tree(['b', [['/', 'bark-01'], [':ARG0', ['d', [['/', 'dog']]]]]) */ + export const parse = (s: string): Tree => { const tokens = lex(s, PENMAN_RE); return _parse(tokens); }; /** - * Yield trees parsed from *lines*. + * Yield trees parsed from `lines`. + * + * @param lines - A string or open file with PENMAN-serialized graphs. + * @returns The `Tree` object described in `lines`. + * @example + * import { iterparse } from 'penman-js'; * - * Args: - * lines: a string or open file with PENMAN-serialized graphs - * Returns: - * The :class:`~penman.tree.Tree` object described in *lines*. - * Example: - * >>> import penman - * >>> for t in penman.iterparse('(a / alpha) (b / beta)'): - * ... print(repr(t)) - * ... - * Tree(('a', [('/', 'alpha')])) - * Tree(('b', [('/', 'beta')])) + * for (const t of iterparse('(a / alpha) (b / beta)')) { + * console.log(t); + * } + * + * // Tree(['a', [['/', 'alpha']]]) + * // Tree(['b', [['/', 'beta']]]) */ + export function* iterparse( lines: Iterable | string, ): IterableIterator { @@ -45,19 +48,24 @@ export function* iterparse( } /** - * Parse a triple conjunction from *s*. + * Parse a triple conjunction from `s`. * - * Example: - * >>> import penman - * >>> for triple in penman.parse_triples(''' - * ... instance(b, bark) ^ - * ... ARG0(b, d) ^ - * ... instance(d, dog)'''): - * ... print(triple) - * ('b', ':instance', 'bark') - * ('b', ':ARG0', 'd') - * ('d', ':instance', 'dog') + * @param s - A string containing the triple conjunction. + * @returns An iterator yielding triples. + * @example + * import { parseTriples } from 'penman-js'; + * + * for (const triple of parseTriples(` + * instance(b, bark) ^ + * ARG0(b, d) ^ + * instance(d, dog)`)) { + * console.log(triple); + * // ['b', ':instance', 'bark'] + * // ['b', ':ARG0', 'd'] + * // ['d', ':instance', 'dog'] + * } */ + export const parseTriples = (s: string): BasicTriple[] => { const tokens = lex(s, TRIPLE_RE); return _parseTriples(tokens); diff --git a/src/lib/codec.ts b/src/lib/codec.ts index d335c41..ff96eb0 100644 --- a/src/lib/codec.ts +++ b/src/lib/codec.ts @@ -226,13 +226,11 @@ export function _encode( } /** - * Deserialize a list of PENMAN-encoded graphs from *source*. - - * Args: - * source: a filename to read from - * model: the model used for interpreting the graph - * Returns: - * a list of Graph objects + * Deserialize a list of PENMAN-encoded graphs from `source`. + * + * @param source - A filename to read from. + * @param model - The model used for interpreting the graph. + * @returns A list of `Graph` objects. */ export function _load( source: string, @@ -247,13 +245,11 @@ export function _load( } /** - * Deserialize a list of PENMAN-encoded graphs from *string*. + * Deserialize a list of PENMAN-encoded graphs from a string. * - * Args: - * string: a string containing graph data - * model: the model used for interpreting the graph - * Returns: - * a list of Graph objects + * @param string - A string containing graph data. + * @param model - The model used for interpreting the graph. + * @returns A list of `Graph` objects. */ export function _loads(string: string, model?: Model): Graph[] { const codec = new PENMANCodec(model); @@ -261,14 +257,13 @@ export function _loads(string: string, model?: Model): Graph[] { } /** - * Serialize each graph in *graphs* to PENMAN and write to *file*. + * Serialize each graph in `graphs` to PENMAN notation and write to `file`. * - * Args: - * graphs: an iterable of Graph objects - * file: a filename to write to - * model: the model used for interpreting the graph - * indent: how to indent formatted strings - * compact: if ``True``, put initial attributes on the first line + * @param graphs - An iterable of Graph objects. + * @param file - A filename to write to. + * @param model - The model used for interpreting the graph. + * @param indent - How to indent formatted strings. + * @param compact - If `true`, put initial attributes on the first line. */ export function _dump( graphs: Graph[], @@ -304,15 +299,13 @@ export function _dumpStream( } /** - * Serialize each graph in *graphs* to the PENMAN format. + * Serialize each graph in `graphs` to the PENMAN format. * - * Args: - * graphs: an iterable of Graph objects - * model: the model used for interpreting the graph - * indent: how to indent formatted strings - * compact: if ``True``, put initial attributes on the first line - * Returns: - * the string of serialized graphs + * @param graphs - An iterable of Graph objects. + * @param model - The model used for interpreting the graph. + * @param indent - How to indent formatted strings. + * @param compact - If `true`, put initial attributes on the first line. + * @returns The string of serialized graphs. */ export function _dumps( graphs: Graph[], diff --git a/src/lib/constant.ts b/src/lib/constant.ts index 74ea114..91af651 100644 --- a/src/lib/constant.ts +++ b/src/lib/constant.ts @@ -19,20 +19,18 @@ export const FLOAT = Type.FLOAT; //: Float constants (e.g., :code:`(... :value 1 export const NULL = Type.NULL; //: Empty values (e.g., :code:`(... :ARG1 )`) /** - * Return the type of constant encoded by *constant_string*. + * Return the type of constant encoded by `constantString`. * - * Examples: - * >>> from penman import constant - * >>> constant.type('-') - * - * >>> constant.type('"foo"') - * - * >>> constant.type('1') - * - * >>> constant.type('1.2') - * - * >>> constant.type('') - * + * @param constantString - The string representation of the constant. + * @returns The type of the constant. + * @example + * import { type } from 'penman-js'; + * + * console.log(type('-')); // Outputs: 'Symbol' + * console.log(type('"foo"')); // Outputs: 'String' + * console.log(type('1')); // Outputs: 'Integer' + * console.log(type('1.2')); // Outputs: 'Float' + * console.log(type('')); // Outputs: 'Null' */ export const type = (constant_string: string | null | undefined): Type => { if (constant_string == null) { @@ -61,31 +59,28 @@ export const type = (constant_string: string | null | undefined): Type => { }; /** - * Evaluate and return *constant_string*. + * Evaluate and return the value of `constantString`. * - * If *constant_string* is ``None`` or an empty symbol (``''``), this - * function returns ``None``, while an empty string constant - * (``'""'``) returns an empty :py:class:`str` object - * (``''``). Otherwise, symbols are returned unchanged while strings - * get quotes removed and escape sequences are unescaped. Note that - * this means it is impossible to recover the original type of + * If `constantString` is `null` or an empty symbol (`''`), this + * function returns `null`. An empty string constant (`'""'`) returns an empty string (`''`). + * Symbols are returned unchanged, while strings get quotes removed and escape sequences unescaped. + * Note that this means it is impossible to recover the original type of * strings and symbols once they have been evaluated. For integer and - * float constants, this function returns the equivalent Python - * :py:class:`int` or :py:class:`float` objects. - - * Examples: - * >>> from penman import constant - * >>> constant.evaluate('-') - * '-' - * >>> constant.evaluate('"foo"') - * 'foo' - * >>> constant.evaluate('1') - * 1 - * >>> constant.evaluate('1.2') - * 1.2 - * >>> constant.evaluate('') is None - * True + * float constants, this function returns the equivalent JavaScript + * `Number` object. + * + * @param constantString - The string representation of the constant. + * @returns The evaluated value of the constant. + * @example + * import { evaluate } from 'penman-js/constant'; + * + * console.log(evaluate('-')); // Outputs: '-' + * console.log(evaluate('"foo"')); // Outputs: 'foo' + * console.log(evaluate('1')); // Outputs: 1 + * console.log(evaluate('1.2')); // Outputs: 1.2 + * console.log(evaluate('') === null); // Outputs: true */ + export const evaluate = ( constantString: string | null | undefined, ): Constant => { @@ -117,26 +112,23 @@ export const evaluate = ( }; /** - * Return *constant* as a quoted string. + * Return `constant` as a quoted string. * - * If *constant* is ``None``, this function returns an empty string - * constant (``'""'``). All other types are cast to a string and + * If `constant` is `null`, this function returns an empty string + * constant (`'""'`). All other types are cast to a string and * quoted. * - * Examples: - * >>> from penman import constant - * >>> constant.quote(None) - * '""' - * >>> constant.quote('') - * '""' - * >>> constant.quote('foo') - * '"foo"' - * >>> constant.quote('"foo"') - * '"\\\\"foo\\\\""' - * >>> constant.quote(1) - * '"1"' - * >>> constant.quote(1.5) - * '"1.5"' + * @param constant - The value to quote. + * @returns The quoted string representation of the constant. + * @example + * import { quote } from 'penman-js/constant'; + * + * console.log(quote(null)); // Outputs: '""' + * console.log(quote('')); // Outputs: '""' + * console.log(quote('foo')); // Outputs: '"foo"' + * console.log(quote('"foo"')); // Outputs: '"\\"foo\\""' + * console.log(quote(1)); // Outputs: '"1"' + * console.log(quote(1.5)); // Outputs: '"1.5"' */ export const quote = (constant: Constant): string => { if (constant == null) { diff --git a/src/lib/epigraph.ts b/src/lib/epigraph.ts index 61b2330..a150cc0 100644 --- a/src/lib/epigraph.ts +++ b/src/lib/epigraph.ts @@ -1,16 +1,16 @@ -/** -Base classes for epigraphical markers. - */ +/** Base classes for epigraphical markers. */ import { BasicTriple } from './types'; import { ArrayKeysMap } from './utils'; export class Epidatum { - //: The :attr:`mode` attribute specifies what the Epidatum annotates: - //: - //: * ``mode=0`` -- unspecified - //: * ``mode=1`` -- role epidata - //: * ``mode=2`` -- target epidata + /** + * The `mode` attribute specifies what the Epidatum annotates: + * + * - `mode = 0` -- unspecified + * - `mode = 1` -- role epidata + * - `mode = 2` -- target epidata + */ mode = 0; } diff --git a/src/lib/graph.ts b/src/lib/graph.ts index b71e041..7a54ca7 100644 --- a/src/lib/graph.ts +++ b/src/lib/graph.ts @@ -21,12 +21,11 @@ import { defaultdictPlusEqual } from './utils'; export const CONCEPT_ROLE = ':instance'; /** - * A relation between nodes or between a node and an constant. + * Represents a relation between nodes or between a node and a constant. * - * Args: - * source: the source variable of the triple - * role: the edge label between the source and target - * target: the target variable or constant + * @param source - The source variable of the triple. + * @param role - The edge label between the source and target. + * @param target - The target variable or constant. */ export type Triple = [source: Variable, role: Role, target: Target]; @@ -47,34 +46,35 @@ export type Attribute = [source: Variable, role: Role, target: Constant]; // hacky way to get a unique id for each graph // since JS has no id() function like Python -let graph_id_counter = 0; +let graphIdCounter = 0; /** - * A basic class for modeling a rooted, directed acyclic graph. - - * A Graph is defined by a list of triples, which can be divided into + * Represents a basic class for modeling a rooted, directed acyclic graph. + * + * A `Graph` is defined by a list of triples, which can be divided into * two parts: a list of graph edges where both the source and target * are variables (node identifiers), and a list of node attributes - * where only the source is a variable and the target is a - * constant. The raw triples are available via the :attr:`triples` - * attribute, while the :meth:`instances`, :meth:`edges` and - * :meth:`attributes` methods return only those that are concept - * relations, relations between nodes, or relations between a node - * and a constant, respectively. - - * Args: - * triples: an iterable of triples (:class:`Triple` or 3-tuples) - * top: the variable of the top node; if unspecified, the source - * of the first triple is used - * epidata: a mapping of triples to epigraphical markers - * metadata: a mapping of metadata types to descriptions - * Example: - * >>> from penman.graph import Graph - * >>> Graph([('b', ':instance', 'bark-01'), - * ... ('d', ':instance', 'dog'), - * ... ('b', ':ARG0', 'd')]) - * + * where only the source is a variable and the target is a constant. + * The raw triples are available via the `triples` property, while the + * `instances`, `edges`, and `attributes` methods return only those that + * are concept relations, relations between nodes, or relations between + * a node and a constant, respectively. + * + * @param triples - An iterable of triples (either `Triple` objects or 3-tuples). + * @param top - The variable of the top node; if unspecified, the source + * of the first triple is used. + * @param epidata - A mapping of triples to epigraphical markers. + * @param metadata - A mapping of metadata types to descriptions. + * @example + * import { Graph } from 'penman-js'; + * + * const graph = new Graph([ + * ['b', ':instance', 'bark-01'], + * ['d', ':instance', 'dog'], + * ['b', ':ARG0', 'd'] + * ]); */ + export class Graph { _id: number; @@ -92,7 +92,7 @@ export class Graph { tgt, ]); - this._id = graph_id_counter++; + this._id = graphIdCounter++; } __repr__() { @@ -231,8 +231,10 @@ export class Graph { return this._filterTriples(null, CONCEPT_ROLE, null); } - /** Return edges filtered by their *source*, *role*, or *target*. - * Edges don't include terminal triples (concepts or attributes). */ + /** + * Return edges filtered by their *source*, *role*, or *target*. + * Edges don't include terminal triples (concepts or attributes). + */ edges( source: Variable | null = null, role: Role | null = null, @@ -244,9 +246,11 @@ export class Graph { ) as Edge[]; } - /** Return attributes filtered by their *source*, *role*, or *target*. + /** + * Return attributes filtered by their *source*, *role*, or *target*. * Attributes don't include concept triples or those where the - * target is a nonterminal. */ + * target is a nonterminal. + */ attributes( source: Variable | null = null, role: Role | null = null, @@ -278,14 +282,16 @@ export class Graph { } } - /** Return a mapping of variables to their re-entrancy count. + /** + * Return a mapping of variables to their re-entrancy count. * A re-entrancy is when more than one edge selects a node as its * target. These graphs are rooted, so the top node always has an * implicit entrancy. Only nodes with re-entrancies are reported, * and the count is only for the entrant edges beyond the first. * Also note that these counts are for the interpreted graph, not * for the linearized form, so inverted edges are always - * re-entrant. */ + * re-entrant. + */ reentrancies(): Map { const entrancies = new Map(); if (this.top != null) { diff --git a/src/lib/layout.ts b/src/lib/layout.ts index f53b863..fdc9e82 100644 --- a/src/lib/layout.ts +++ b/src/lib/layout.ts @@ -41,9 +41,9 @@ * * PENMAN Graph Epigraph * (t / try-01 [('t', ':instance', 'try-01'), : - * :ARG0 (d / dog) ('t', ':ARG0', 'd'), : Push('d') - * :ARG1 (b / bark-01 ('d', ':instance', 'dog'), : POP - * :ARG0 d)) ('t', ':ARG1', 'b'), : Push('b') + * :ARG0 (d / dog) ('t', ':ARG0', 'd'), : Push('d') + * :ARG1 (b / bark-01 ('d', ':instance', 'dog'), : POP + * :ARG0 d)) ('t', ':ARG1', 'b'), : Push('b') * ('b', ':instance', 'bark-01'), : * ('b', ':ARG0', 'd')] : POP */ @@ -100,39 +100,40 @@ export class Pop extends LayoutMarker { } } -//: A singleton instance of :class:`Pop`. +/** A singleton instance of `Pop`. */ export const POP = new Pop(); /** - * Interpret tree *t* as a graph using *model*. - + * Interpret tree `t` as a graph using `model`. + * * Tree interpretation is the process of transforming the nodes and * edges of a tree into a directed graph. A semantic model determines - * which edges are inverted and how to deinvert them. If *model* is + * which edges are inverted and how to deinvert them. If `model` is * not provided, the default model will be used. - - * Args: - * t: the :class:`~penman.tree.Tree` to interpret - * model: the :class:`~penman.model.Model` used to interpret *t* - * Returns: - * The interpreted :class:`~penman.graph.Graph`. - * Example: * - * >>> from penman.tree import Tree - * >>> from penman import layout - * >>> t = Tree( - * ... ('b', [ - * ... ('/', 'bark-01'), - * ... ('ARG0', ('d', [ - * ... ('/', 'dog')]))])) - * >>> g = layout.interpret(t) - * >>> for triple in g.triples: - * ... print(triple) - * ... - * ('b', ':instance', 'bark-01') - * ('b', ':ARG0', 'd') - * ('d', ':instance', 'dog') + * @param t - The `Tree` object to interpret. + * @param model - The `Model` used to interpret `t`. + * @returns The interpreted `Graph` object. + * @example + * import { Tree } from 'penman-js/tree'; + * import { interpret } from 'penman-js/layout'; + * + * const t = new Tree('b', [ + * ['/', 'bark-01'], + * ['ARG0', new Tree('d', [ + * ['/', 'dog'] + * ])] + * ]); + * + * const g = interpret(t); + * for (const triple of g.triples) { + * console.log(triple); + * } + * // ['b', ':instance', 'bark-01'] + * // ['b', ':ARG0', 'd'] + * // ['d', ':instance', 'dog'] */ + export function interpret( t: Tree | null, model: Model = _default_model, @@ -251,7 +252,7 @@ const _processAtomic = (target: string): [string, Epidatum[]] => { /** * Create a tree from a graph by making as few decisions as possible. * - * A graph interpreted from a valid tree using :func:`interpret` will + * A graph interpreted from a valid tree using `interpret` will * contain epigraphical markers that describe how the triples of a * graph are to be expressed in a tree, and thus configuring this * tree requires only a single pass through the list of triples. If @@ -261,29 +262,26 @@ const _processAtomic = (target: string): [string, Epidatum[]] => { * deterministic, but may result in a tree different than the one * expected. * - * Args: - * g: the :class:`~penman.graph.Graph` to configure - * top: the variable to use as the top of the graph; if ``None``, - * the top of *g* will be used - * model: the :class:`~penman.model.Model` used to configure the - * tree - * Returns: - * The configured :class:`~penman.tree.Tree`. - * Example: + * @param g - The `Graph` object to configure. + * @param top - The variable to use as the top of the graph; if `null`, + * the top of `g` will be used. + * @param model - The `Model` used to configure the tree. + * @returns The configured `Tree` object. + * @example + * import { Graph } from 'penman-js/graph'; + * import { configure } from 'penman-js/layout'; + * + * const g = new Graph([ + * ['b', ':instance', 'bark-01'], + * ['b', ':ARG0', 'd'], + * ['d', ':instance', 'dog'] + * ]); * - * >>> from penman.graph import Graph - * >>> from penman import layout - * >>> g = Graph([('b', ':instance', 'bark-01'), - * ... ('b', ':ARG0', 'd'), - * ... ('d', ':instance', 'dog')]) - * >>> t = layout.configure(g) - * >>> print(t) - * Tree( - * ('b', [ - * ('/', 'bark-01'), - * (':ARG0', ('d', [ - * ('/', 'dog')]))])) + * const t = configure(g); + * console.log(t); + * // Tree('b', [['/', 'bark-01'], [':ARG0', new Tree('d', [['/', 'dog']])]]) */ + export function configure( g: Graph, top: Variable = null, @@ -413,8 +411,8 @@ function _preconfigure(g: Graph, model: Model) { * Configure a node and any descendants. * * Side-effects: - * * *data* is modified - * * *nodemap* is modified + * - `data` is modified + * - `nodemap` is modified */ function _configureNode( variable: Variable, @@ -571,7 +569,7 @@ function _processEpigraph(node: any): void { /** * Create a tree from a graph after any discarding layout markers. - * If *key* is provided, triples are sorted according to the key. + * If `key` is provided, triples are sorted according to the key. */ export function reconfigure( graph: Graph, @@ -596,53 +594,37 @@ export function reconfigure( } /** - * Sort the branches at each node in tree *t* according to *key*. - * Sort the branches at each node in tree *t* according to *key*. - - * Each node in a tree contains a list of branches. This function - * Each node in a tree contains a list of branches. This function - * sorts those lists in-place using the *key* function, which accepts - * sorts those lists in-place using the *key* function, which accepts - * a role and returns some sortable criterion. - * a role and returns some sortable criterion. + * Sort the branches at each node in tree `t` according to `key`. + * + * Each node in a tree contains a list of branches. This function sorts + * those lists in-place using the `key` function, which accepts a role and + * returns some sortable criterion. + * + * If the `attributesFirst` argument is `true`, attribute branches will + * appear before any edges. * - * If the *attributes_first* argument is ``True``, attribute branches - * If the *attributes_first* argument is ``True``, attribute branches - * are appear before any edges. - * are appear before any edges. + * Instance branches (`/`) always appear before any other branches. * - * Instance branches (``/``) always appear before any other branches. - * Instance branches (``/``) always appear before any other branches. + * @param t - The tree to rearrange. + * @param key - The function used for sorting branches. + * @param attributesFirst - If `true`, attribute branches appear before edges. + * @example + * import { rearrange } from 'penman-js/layout'; + * import { Model } from 'penman-js/model'; + * import { PENMANCodec } from 'penman-js/codec'; * - * Example: - * Example: - * >>> from penman import layout - * >>> from penman import layout - * >>> from penman.model import Model - * >>> from penman.model import Model - * >>> from penman.codec import PENMANCodec - * >>> from penman.codec import PENMANCodec - * >>> c = PENMANCodec() - * >>> c = PENMANCodec() - * >>> t = c.parse( - * >>> t = c.parse( - * ... '(s / see-01' - * ... '(s / see-01' - * ... ' :ARG1 (c / cat)' - * ... ' :ARG1 (c / cat)' - * ... ' :ARG0 (d / dog))') - * ... ' :ARG0 (d / dog))') - * >>> layout.rearrange(t, key=Model().canonical_order) - * >>> layout.rearrange(t, key=Model().canonical_order) - * >>> print(c.format(t)) - * >>> print(c.format(t)) - * (s / see-01 - * (s / see-01 - * :ARG0 (d / dog) - * :ARG0 (d / dog) - * :ARG1 (c / cat)) - * :ARG1 (c / cat)) + * const c = new PENMANCodec(); + * const t = c.parse(` + * (s / see-01 + * :ARG1 (c / cat) + * :ARG0 (d / dog))`); + * rearrange(t, Model().canonicalOrder, true); + * console.log(c.format(t)); + * // (s / see-01 + * // :ARG0 (d / dog) + * // :ARG1 (c / cat)) */ + export function rearrange( t: Tree, key: (role: Role) => any = null, @@ -679,17 +661,21 @@ const _rearrange = (node: Node, key: (branch: Branch) => any) => { branches.splice(0, branches.length, ...first, ...sortBy(rest, key)); }; -/* - * Return the variable pushed by *triple*, if any, otherwise ``None``. - - * Example: - * >>> from penman import decode - * >>> from penman.layout import get_pushed_variable - * >>> g = decode('(a / alpha :ARG0 (b / beta))') - * >>> get_pushed_variable(g, ('a', ':instance', 'alpha')) # None - * >>> get_pushed_variable(g, ('a', ':ARG0', 'b')) - * 'b' +/** + * Return the variable pushed by `triple`, if any, otherwise `null`. + * + * @param g - A graph object. + * @param triple - The triple to check for a pushed variable. + * @returns The variable pushed by `triple`, or `null` if none. + * @example + * import { decode } from 'penman-js'; + * import { getPushedVariable } from 'penman-js/layout'; + * + * const g = decode('(a / alpha :ARG0 (b / beta))'); + * console.log(getPushedVariable(g, ['a', ':instance', 'alpha'])); // Outputs: null + * console.log(getPushedVariable(g, ['a', ':ARG0', 'b'])); // Outputs: 'b' */ + export function getPushedVariable( g: Graph, triple: BasicTriple, @@ -703,24 +689,22 @@ export function getPushedVariable( } /** - * Return ``True`` if *triple* appears inverted in serialization. + * Return `true` if `triple` appears inverted in serialization. * - * More specifically, this function returns ``True`` if *triple* has - * a :class:`Push` epigraphical marker in graph *g* whose associated - * variable is the source variable of *triple*. This should be + * More specifically, this function returns `true` if `triple` has + * a `Push` epigraphical marker in graph `g` whose associated + * variable is the source variable of `triple`. This should be * accurate when testing a triple in a graph interpreted using - * :func:`interpret` (including :meth:`PENMANCodec.decode - * `, etc.), but it does not - * guarantee that a new serialization of *g* will express *triple* as - * inverted as it can change if the graph or its epigraphical markers - * are modified, if a new top is chosen, etc. + * `interpret` (including `PENMANCodec.decode` and similar methods), + * but it does not guarantee that a new serialization of `g` will + * express `triple` as inverted as it can change if the graph or its + * epigraphical markers are modified, if a new top is chosen, etc. * - * Args: - * g: a :class:`~penman.graph.Graph` containing *triple* - * triple: the triple that does or does not appear inverted - * Returns: - * ``True`` if *triple* appears inverted in graph *g*. + * @param g - A `Graph` object containing `triple`. + * @param triple - The triple that does or does not appear inverted. + * @returns `true` if `triple` appears inverted in graph `g`. */ + export function appearsInverted(g: Graph, triple: BasicTriple): boolean { const variables = g.variables(); if (triple[1] === CONCEPT_ROLE || !variables.has(triple[2] as string)) { @@ -747,28 +731,33 @@ export function appearsInverted(g: Graph, triple: BasicTriple): boolean { } /** - * Return the list of node contexts corresponding to triples in *g*. + * Return the list of node contexts corresponding to triples in `g`. + * + * If a node context is unknown, the value `null` is substituted. * - * If a node context is unknown, the value ``None`` is substituted. + * @param g - A graph object. + * @returns An array of node contexts corresponding to triples in `g`. + * @example + * import { decode, nodeContexts } from 'penman-js'; * - * Example: - * >>> from penman import decode, layout - * >>> g = decode(''' - * ... (a / alpha - * ... :attr val - * ... :ARG0 (b / beta :ARG0 (g / gamma)) - * ... :ARG0-of g)''') - * >>> for ctx, trp in zip(layout.node_contexts(g), g.triples): - * ... print(ctx, ':', trp) - * ... - * a : ('a', ':instance', 'alpha') - * a : ('a', ':attr', 'val') - * a : ('a', ':ARG0', 'b') - * b : ('b', ':instance', 'beta') - * b : ('b', ':ARG0', 'g') - * g : ('g', ':instance', 'gamma') - * a : ('g', ':ARG0', 'a') + * const g = decode(` + * (a / alpha + * :attr val + * :ARG0 (b / beta :ARG0 (g / gamma)) + * :ARG0-of g)`); + * for (const [ctx, trp] of zip(nodeContexts(g), g.triples)) { + * console.log(ctx, ':', trp); + * } + * + * // a : ['a', ':instance', 'alpha'] + * // a : ['a', ':attr', 'val'] + * // a : ['a', ':ARG0', 'b'] + * // b : ['b', ':instance', 'beta'] + * // b : ['b', ':ARG0', 'g'] + * // g : ['g', ':instance', 'gamma'] + * // a : ['g', ':ARG0', 'a'] */ + export function nodeContexts(g: Graph): Array { const variables = g.variables(); const stack = [g.top]; diff --git a/src/lib/model.ts b/src/lib/model.ts index 4c8072b..6bbfaec 100644 --- a/src/lib/model.ts +++ b/src/lib/model.ts @@ -12,18 +12,18 @@ type _Dereified = [Role, Role, Role]; type _Reification = [BasicTriple, BasicTriple, BasicTriple]; /** - * A semantic model for Penman graphs. - - * The model defines things like valid roles and transformations. - - * Args: - * top_variable: the variable of the graph's top - * top_role: the role linking the graph's top to the top node - * concept_role: the role associated with node concepts - * roles: a mapping of roles to associated data - * normalizations: a mapping of roles to normalized roles - * reifications: a list of 4-tuples used to define reifications + * Represents a semantic model for Penman graphs. + * + * The model defines elements such as valid roles and transformations. + * + * @param topVariable - The variable of the graph's top. + * @param topRole - The role linking the graph's top to the top node. + * @param conceptRole - The role associated with node concepts. + * @param roles - A mapping of roles to associated data. + * @param normalizations - A mapping of roles to normalized roles. + * @param reifications - An array of 4-tuples used to define reifications. */ + export class Model { reifications: { [key: Role]: Array<_Reified> }; dereifications: { [key: Constant]: Array<_Dereified> }; @@ -108,12 +108,15 @@ export class Model { } /** - * Return ``True`` if *role* is defined by the model. + * Return `true` if `role` is defined by the model. + * + * If `role` is not in the model but a single deinversion of + * `role` is in the model, then `true` is returned. Otherwise, + * `false` is returned, even if a method like `canonicalizeRole` + * could return a valid role. * - * If *role* is not in the model but a single deinversion of - * *role* is in the model, then ``True`` is returned. Otherwise - * ``False`` is returned, even if something like - * :meth:`canonicalize_role` could return a valid role. + * @param role - The role to check in the model. + * @returns `true` if the role is defined by the model, otherwise `false`. */ hasRole(role: Role): boolean { return ( @@ -127,14 +130,14 @@ export class Model { } /** - * Return ``True`` if *role* is inverted. + * Return `true` if `role` is inverted. */ isRoleInverted(role: Role): boolean { return !this._hasRole(role) && role.endsWith('-of'); } /** - * Invert *role*. + * Invert `role`. */ invertRole(role: Role): Role { if (!this._hasRole(role) && role.endsWith('-of')) { @@ -144,14 +147,18 @@ export class Model { } /** - * Invert *triple*. + * Invert `triple`. * * This will invert or deinvert a triple regardless of its - * current state. :meth:`deinvert` will deinvert a triple only if - * it is already inverted. Unlike :meth:`canonicalize`, this will + * current state. A method like `deinvert` will deinvert a triple only if + * it is already inverted. Unlike a method like `canonicalize`, this will * not perform multiple inversions or replace the role with a * normalized form. + * + * @param triple - The triple to invert. + * @returns The inverted or deinverted triple. */ + invert(triple: BasicTriple): BasicTriple { const [source, role, target] = triple; const inverse = this.invertRole(role); @@ -161,14 +168,18 @@ export class Model { } /** - * De-invert *triple* if it is inverted. + * De-invert `triple` if it is inverted. * - * Unlike :meth:`invert`, this only inverts a triple if the model + * Unlike a method such as `invert`, this only inverts a triple if the model * considers it to be already inverted, otherwise it is left - * alone. Unlike :meth:`canonicalize`, this will not normalize + * unchanged. Unlike a method such as `canonicalize`, this will not normalize * multiple inversions or replace the role with a normalized * form. + * + * @param triple - The triple to de-invert if necessary. + * @returns The de-inverted triple, or the original triple if it wasn't inverted. */ + deinvert(triple: BasicTriple): BasicTriple { if (this.isRoleInverted(triple[1])) { triple = this.invert(triple); @@ -176,39 +187,21 @@ export class Model { return triple; } - // def canonicalize_role(self, role: Role) -> Role: - // """ - // Canonicalize *role*. - - // Role canonicalization will do the following: - - // * Ensure the role starts with `':'` - - // * Normalize multiple inversions (e.g., ``ARG0-of-of`` becomes - // ``ARG0``), but it does *not* change the direction of the role - - // * Replace the resulting role with a normalized form if one is - // defined in the model - // """ - // if role != '/' and not role.startswith(':'): - // role = ':' + role - // role = self._canonicalize_inversion(role) - // role = self.normalizations.get(role, role) - // return role - /** - * Canonicalize *role*. - * - * Role canonicalization will do the following: - * - * * Ensure the role starts with `':'` + * Canonicalize `role`. * - * * Normalize multiple inversions (e.g., ``ARG0-of-of`` becomes - * ``ARG0``), but it does *not* change the direction of the role + * Role canonicalization will perform the following actions: * - * * Replace the resulting role with a normalized form if one is + * - Ensure the role starts with `':'` + * - Normalize multiple inversions (e.g., `ARG0-of-of` becomes `ARG0`), + * but it does not change the direction of the role + * - Replace the resulting role with a normalized form if one is * defined in the model + * + * @param role - The role to be canonicalized. + * @returns The canonicalized role. */ + canonicalizeRole(role: Role): Role { if (role !== '/' && !role.startsWith(':')) { role = ':' + role; @@ -218,17 +211,6 @@ export class Model { return role; } - // def _canonicalize_inversion(self, role: Role) -> Role: - // invert = self.invert_role - // if not self._has_role(role): - // while True: - // prev = role - // inverse = invert(role) - // role = invert(inverse) - // if prev == role: - // break - // return role - _canonicalizeInversion(role: Role): Role { if (!this._hasRole(role)) { while (true) { @@ -243,24 +225,15 @@ export class Model { return role; } - // def canonicalize(self, triple: BasicTriple) -> BasicTriple: - // """ - // Canonicalize *triple*. - - // See :meth:`canonicalize_role` for a description of how the - // role is canonicalized. Unlike :meth:`invert`, this does not - // swap the source and target of *triple*. - // """ - // source, role, target = triple - // canonical = self.canonicalize_role(role) - // return (source, canonical, target) - /** - * Canonicalize *triple*. + * Canonicalize `triple`. + * + * The role in the triple is canonicalized following the procedure + * described in the `canonicalizeRole` method. Unlike a method such as `invert`, + * this function does not swap the source and target of `triple`. * - * See :meth:`canonicalize_role` for a description of how the - * role is canonicalized. Unlike :meth:`invert`, this does not - * swap the source and target of *triple*. + * @param triple - The triple to be canonicalized. + * @returns The canonicalized triple. */ canonicalize(triple: BasicTriple): BasicTriple { const [source, role, target] = triple; @@ -269,30 +242,30 @@ export class Model { } /** - * Return ``True`` if *role* can be reified. + * Return `true` if `role` can be reified. */ isRoleReifiable(role: Role): boolean { return role in this.reifications; } /** - * Return the three triples that reify *triple*. + * Return the three triples that reify `triple`. * - * Note that, unless *variables* is given, the node variable + * Note that, unless `variables` is provided, the node variable * for the reified node is not necessarily valid for the target * graph. When incorporating the reified triples, this variable * should then be replaced. - - * If the role of *triple* does not have a defined reification, a - * :exc:`~penman.exceptions.ModelError` is raised. * - * Args: - * triple: the triple to reify - * variables: a set of variables that should not be used for - * the reified node's variable - * Returns: - * The 3-tuple of triples that reify *triple*. + * If the role of `triple` does not have a defined reification, + * a `ModelError` exception is raised. + * + * @param triple - The triple to reify. + * @param variables - A set of variables that should not be used for + * the reified node's variable. + * @returns The 3-tuple of triples that reify `triple`. + * @throws {ModelError} - If the role of `triple` does not have a defined reification. */ + reify(triple: BasicTriple, variables?: Set): _Reification { const [source, role, target] = triple; if (!(role in this.reifications)) { @@ -326,20 +299,19 @@ export class Model { /** * Return the triple that dereifies the three argument triples. * - * If the target of *instance_triple* does not have a defined - * dereification, or if the roles of *source_triple* and - * *target_triple* do not match those for the dereification of - * the concept, a :exc:`~penman.exceptions.ModelError` is - * raised. A :exc:`ValueError` is raised if *instance_triple* is - * not an instance triple or any triple does not have the same - * source variable as the others. + * If the target of `instanceTriple` does not have a defined + * dereification, or if the roles of `sourceTriple` and + * `targetTriple` do not match those for the dereification of + * the concept, a `ModelError` exception is raised. A `ValueError` is raised if + * `instanceTriple` is not an instance triple or any triple does not have the + * same source variable as the others. * - * Args: - * instance_triple: the triple containing the node's concept - * source_triple: the source triple from the node - * target_triple: the target triple from the node - * Returns: - * The triple that dereifies the three argument triples. + * @param instanceTriple - The triple containing the node's concept. + * @param sourceTriple - The source triple from the node. + * @param targetTriple - The target triple from the node. + * @returns The triple that dereifies the three argument triples. + * @throws {ModelError} - If dereification conditions are not met. + * @throws {ValueError} - If `instanceTriple` is not valid or if any triple has a different source. */ dereify( instanceTriple: BasicTriple, @@ -414,25 +386,32 @@ export class Model { } /** - * Return a description of model errors detected in *graph*. - - * The description is a dictionary mapping a context to a list of + * Return a description of model errors detected in `graph`. + * + * The description is an object mapping a context to a list of * errors. A context is a triple if the error is relevant for the - * triple, or ``None`` for general graph errors. - - * Example: - - * >>> from penman.models.amr import model - * >>> from penman.graph import Graph - * >>> g = Graph([('a', ':instance', 'alpha'), - * ... ('a', ':foo', 'bar'), - * ... ('b', ':instance', 'beta')]) - * >>> for context, errors in model.errors(g).items(): - * ... print(context, errors) - * ... - * ('a', ':foo', 'bar') ['invalid role'] - * ('b', ':instance', 'beta') ['unreachable'] + * triple, or `null` for general graph errors. + * + * @param graph - The graph to check for errors. + * @returns An object describing detected model errors in the graph. + * @example + * import { model } from 'penman-js/models/amr'; + * import { Graph } from 'penman-js/graph'; + * + * const g = new Graph([ + * ['a', ':instance', 'alpha'], + * ['a', ':foo', 'bar'], + * ['b', ':instance', 'beta'] + * ]); + * + * for (const [context, errors] of Object.entries(model.errors(g))) { + * console.log(context, errors); + * } + * + * // ['a', ':foo', 'bar'] ['invalid role'] + * // ['b', ':instance', 'beta'] ['unreachable'] */ + errors(graph: Graph): { [key: string]: string[] } { const err: { [key: string]: string[] } = {}; if (graph.triples.length === 0) { diff --git a/src/lib/surface.ts b/src/lib/surface.ts index 4939a11..d9e2c22 100644 --- a/src/lib/surface.ts +++ b/src/lib/surface.ts @@ -19,15 +19,20 @@ export class AlignmentMarker extends Epidatum { } /** - * Instantiate the alignment marker from its string *s*. + * Instantiate the alignment marker from its string `s`. * - * Examples: - * >>> from penman import surface - * >>> surface.Alignment.from_string('1') - * Alignment((1,)) - * >>> surface.RoleAlignment.from_string('e.2,3') - * RoleAlignment((2, 3), prefix='e.') + * @param s - The string representation of the alignment marker. + * @returns An instance of Alignment or RoleAlignment based on the provided string. + * @example + * import { Alignment, RoleAlignment } from 'penman-js/surface'; + * + * Alignment.fromString('1'); + * // Alignment([1]) + * + * RoleAlignment.fromString('e.2,3'); + * // RoleAlignment([2, 3], 'e.') */ + static fromString(s: string): T { let _s = lstrip(s, '~'); let prefix: string | null = null; @@ -90,49 +95,51 @@ export class RoleAlignment extends AlignmentMarker { type _Alignments = ArrayKeysMap; /** - * Return a mapping of triples to alignments in graph *g*. + * Return a mapping of triples to alignments in graph `g`. * - * Args: - * g: a :class:`~penman.graph.Graph` containing alignment data - * Returns: - * A :class:`dict` mapping :class:`~penman.graph.Triple` objects - * to their corresponding :class:`Alignment` objects, if any. - * Example: - * >>> from penman import decode - * >>> from penman import surface - * >>> g = decode( - * ... '(c / chase-01~4' - * ... ' :ARG0~5 (d / dog~7)' - * ... ' :ARG0~3 (c / cat~2))') - * >>> surface.alignments(g) // doctest: +NORMALIZE_WHITESPACE - * {('c', ':instance', 'chase-01'): Alignment((4,)), - * ('d', ':instance', 'dog'): Alignment((7,)), - * ('c', ':instance', 'cat'): Alignment((2,))} + * @param g - A `Graph` object containing alignment data. + * @returns An object mapping `Triple` objects to their corresponding `Alignment` objects, if any. + * @example + * import { decode } from 'penman-js'; + * import { alignments } from 'penman-js/surface'; + * + * const g = decode( + * `(c / chase-01~4 + * :ARG0~5 (d / dog~7) + * :ARG0~3 (c / cat~2))` + * ); + * alignments(g); + * // ArrayKeysMap({ + * // ['c', ':instance', 'chase-01']: Alignment([4]), + * // ['d', ':instance', 'dog']: Alignment([7]), + * // ['c', ':instance', 'cat']: Alignment([2]) + * // }) */ export function alignments(g: Graph): _Alignments { return _getAlignments(g, Alignment); } /** - * Return a mapping of triples to role alignments in graph *g*. + * Return a mapping of triples to role alignments in graph `g`. + * + * @param g - A `Graph` object containing role alignment data. + * @returns An object mapping `Triple` objects to their corresponding `RoleAlignment` objects, if any. + * @example + * import { decode } from 'penman-js'; + * import { roleAlignments } from 'penman-js/surface'; * - * Args: - * g: a :class:`~penman.graph.Graph` containing role alignment - * data - * Returns: - * A :class:`dict` mapping :class:`~penman.graph.Triple` objects - * to their corresponding :class:`RoleAlignment` objects, if any. - * Example: - * >>> from penman import decode - * >>> from penman import surface - * >>> g = decode( - * ... '(c / chase-01~4' - * ... ' :ARG0~5 (d / dog~7)' - * ... ' :ARG0~3 (c / cat~2))') - * >>> surface.role_alignments(g) // doctest: +NORMALIZE_WHITESPACE - * {('c', ':ARG0', 'd'): RoleAlignment((5,)), - * ('c', ':ARG0', 'c'): RoleAlignment((3,))} + * const g = decode( + * `(c / chase-01~4 + * :ARG0~5 (d / dog~7) + * :ARG0~3 (c / cat~2))` + * ); + * roleAlignments(g); + * // ArrayKeysMap({ + * // ['c', ':ARG0', 'd']: RoleAlignment([5]), + * // ['c', ':ARG0', 'c']: RoleAlignment([3]) + * // }) */ + export function roleAlignments(g: Graph): _Alignments { return _getAlignments(g, RoleAlignment); } diff --git a/src/lib/transform.ts b/src/lib/transform.ts index bf0aab2..c772742 100644 --- a/src/lib/transform.ts +++ b/src/lib/transform.ts @@ -12,29 +12,28 @@ import { BasicTriple, Branch, Node, Target, Variable } from './types'; import { partition } from './utils'; /** - * Normalize roles in *t* so they are canonical according to *model*. + * Normalize roles in `t` so they are canonical according to `model`. * - * This is a tree transformation instead of a graph transformation + * This is a tree transformation rather than a graph transformation * because the orientation of the pure graph's triples is not decided * until the graph is configured into a tree. * - * Args: - * t: a :class:`~penman.tree.Tree` object - * model: a model defining role normalizations - * Returns: - * A new :class:`~penman.tree.Tree` object with canonicalized - * roles. - * Example: - * >>> from penman.codec import PENMANCodec - * >>> from penman.models.amr import model - * >>> from penman.transform import canonicalize_roles - * >>> codec = PENMANCodec() - * >>> t = codec.parse('(c / chapter :domain-of 7)') - * >>> t = canonicalize_roles(t, model) - * >>> print(codec.format(t)) - * (c / chapter - * :mod 7) + * @param t - A `Tree` object. + * @param model - A model defining role normalizations. + * @returns A new `Tree` object with canonicalized roles. + * @example + * import { PENMANCodec } from 'penman-js/codec'; + * import { model } from 'penman-js/models/amr'; + * import { canonicalizeRoles } from 'penman-js/transform'; + * + * const codec = new PENMANCodec(); + * const t = codec.parse('(c / chapter :domain-of 7)'); + * const canonicalizedTree = canonicalizeRoles(t, model); + * console.log(codec.format(canonicalizedTree)); + * // (c / chapter + * // :mod 7) */ + export const canonicalizeRoles = ( t: Tree, model: Model | null = null, @@ -65,24 +64,23 @@ const _canonicalizeNode = (node: Node, model: Model): Node => { }; /** - * Reify all edges in *g* that have reifications in *model*. + * Reify all edges in `g` that have reifications in `model`. + * + * @param g - A `Graph` object. + * @param model - A model defining reifications. + * @returns A new `Graph` object with reified edges. + * @example + * import { PENMANCodec } from 'penman-js/codec'; + * import { model } from 'penman-js/models/amr'; + * import { reifyEdges } from 'penman-js/transform'; * - * Args: - * g: a :class:`~penman.graph.Graph` object - * model: a model defining reifications - * Returns: - * A new :class:`~penman.graph.Graph` object with reified edges. - * Example: - * >>> from penman.codec import PENMANCodec - * >>> from penman.models.amr import model - * >>> from penman.transform import reify_edges - * >>> codec = PENMANCodec(model=model) - * >>> g = codec.decode('(c / chapter :mod 7)') - * >>> g = reify_edges(g, model) - * >>> print(codec.encode(g)) - * (c / chapter - * :ARG1-of (_ / have-mod-91 - * :ARG2 7)) + * const codec = new PENMANCodec(model); + * const g = codec.decode('(c / chapter :mod 7)'); + * const reifiedGraph = reifyEdges(g, model); + * console.log(codec.encode(reifiedGraph)); + * // (c / chapter + * // :ARG1-of (_ / have-mod-91 + * // :ARG2 7)) */ export const reifyEdges = (g: Graph, model: Model | null = null): Graph => { const vars = g.variables(); @@ -121,27 +119,28 @@ export const reifyEdges = (g: Graph, model: Model | null = null): Graph => { }; /** - * Dereify edges in *g* that have reifications in *model*. + * Dereify edges in `g` that have reifications in `model`. * - * Args: - * g: a :class:`~penman.graph.Graph` object - * Returns: - * A new :class:`~penman.graph.Graph` object with dereified - * edges. - * Example: - * >>> from penman.codec import PENMANCodec - * >>> from penman.models.amr import model - * >>> from penman.transform import dereify_edges - * >>> codec = PENMANCodec(model=model) - * >>> g = codec.decode( - * ... '(c / chapter' - * ... ' :ARG1-of (_ / have-mod-91' - * ... ' :ARG2 7))') - * >>> g = dereify_edges(g, model) - * >>> print(codec.encode(g)) - * (c / chapter - * :mod 7) + * @param g - A `Graph` object. + * @param model - A model defining reifications. + * @returns A new `Graph` object with dereified edges. + * @example + * import { PENMANCodec } from 'penman-js/codec'; + * import { model } from 'penman-js/models/amr'; + * import { dereifyEdges } from 'penman-js/transform'; + * + * const codec = new PENMANCodec({ model }); + * const g = codec.decode( + * `(c / chapter + * :ARG1-of (_ / have-mod-91 + * :ARG2 7))` + * ); + * const dereifiedGraph = dereifyEdges(g, model); + * console.log(codec.encode(dereifiedGraph)); + * // (c / chapter + * // :mod 7) */ + export const dereifyEdges = (g: Graph, model: Model | null = null): Graph => { if (model == null) { model = new Model(); @@ -172,24 +171,23 @@ export const dereifyEdges = (g: Graph, model: Model | null = null): Graph => { }; /** - * Reify all attributes in *g*. + * Reify all attributes in `g`. + * + * @param g - A `Graph` object. + * @returns A new `Graph` object with reified attributes. + * @example + * import { PENMANCodec } from 'penman-js/codec'; + * import { model } from 'penman-js/models/amr'; + * import { reifyAttributes } from 'penman-js/transform'; * - * Args: - * g: a :class:`~penman.graph.Graph` object - * Returns: - * A new :class:`~penman.graph.Graph` object with reified - * attributes. - * Example: - * >>> from penman.codec import PENMANCodec - * >>> from penman.models.amr import model - * >>> from penman.transform import reify_attributes - * >>> codec = PENMANCodec(model=model) - * >>> g = codec.decode('(c / chapter :mod 7)') - * >>> g = reify_attributes(g) - * >>> print(codec.encode(g)) - * (c / chapter - * :mod (_ / 7)) + * const codec = new PENMANCodec(model); + * const g = codec.decode('(c / chapter :mod 7)'); + * const reifiedGraph = reifyAttributes(g); + * console.log(codec.encode(reifiedGraph)); + * // (c / chapter + * // :mod (_ / 7)) */ + export const reifyAttributes = (g: Graph): Graph => { const variables = g.variables(); const newEpidata = new EpidataMap(g.epidata.entries()); @@ -223,39 +221,37 @@ export const reifyAttributes = (g: Graph): Graph => { }; /** - * Insert TOP triples in *g* indicating the tree structure. + * Insert TOP triples in `g` indicating the tree structure. + * + * Note: This depends on `g` containing the epigraphical layout markers + * from parsing; it will not work with programmatically + * constructed Graph objects or those whose epigraphical data + * were removed. * - * Note: - * This depends on *g* containing the epigraphical layout markers - * from parsing; it will not work with programmatically - * constructed Graph objects or those whose epigraphical data - * were removed. + * @param g - A `Graph` object. + * @param model - A model defining the TOP role. + * @returns A new `Graph` object with TOP roles indicating tree branches. + * @example + * import { PENMANCodec } from 'penman-js/codec'; + * import { model } from 'penman-js/models/amr'; + * import { indicateBranches } from 'penman-js/transform'; * - * Args: - * g: a :class:`~penman.graph.Graph` object - * model: a model defining the TOP role - * Returns: - * A new :class:`~penman.graph.Graph` object with TOP roles - * indicating tree branches. - * Example: - * >>> from penman.codec import PENMANCodec - * >>> from penman.models.amr import model - * >>> from penman.transform import indicate_branches - * >>> codec = PENMANCodec(model=model) - * >>> g = codec.decode(''' - * ... (w / want-01 - * ... :ARG0 (b / boy) - * ... :ARG1 (g / go-02 - * ... :ARG0 b))''') - * >>> g = indicate_branches(g, model) - * >>> print(codec.encode(g)) - * (w / want-01 - * :TOP b - * :ARG0 (b / boy) - * :TOP g - * :ARG1 (g / go-02 - * :ARG0 b)) + * const codec = new PENMANCodec(model); + * const g = codec.decode(` + * (w / want-01 + * :ARG0 (b / boy) + * :ARG1 (g / go-02 + * :ARG0 b))`); + * const branchedGraph = indicateBranches(g, model); + * console.log(codec.encode(branchedGraph)); + * // (w / want-01 + * // :TOP b + * // :ARG0 (b / boy) + * // :TOP g + * // :ARG1 (g / go-02 + * // :ARG0 b)) */ + export const indicateBranches = (g: Graph, model: Model): Graph => { const newTriples: BasicTriple[] = []; for (const t of g.triples) { @@ -282,20 +278,23 @@ type _SplitMarkers = [Push | null, Pop[], Epidata, Epidata]; /** * Return epigraphical markers broken down by function. * - * When a relation is reified the original triple disappears so its - * epigraphical data needs to be moved and sometimes altered. - * Consider the following, which has surface alignment markers:: + * When a relation is reified, the original triple disappears, so its + * epigraphical data needs to be moved and sometimes altered. For example, + * consider a case with surface alignment markers: * * (a :role~1 b~2) * - * Under edge reification, the desired outcome is:: + * Under edge reification, the desired outcome is: * * (a :ARG1-of (_ / role-label~1 :ARG2 b~2)) * - * Under attribute reification, it is:: + * Under attribute reification, it is: * * (a :role~1 (_ / b~2)) + * + * @returns Epigraphical markers categorized by their function. */ + const _reifiedMarkers = (epidata: Epidata): _SplitMarkers => { let push: Push | null = null; const pops: Pop[] = []; diff --git a/src/lib/tree.ts b/src/lib/tree.ts index 0fc5571..1619122 100644 --- a/src/lib/tree.ts +++ b/src/lib/tree.ts @@ -54,36 +54,37 @@ export class Tree { nodes(): Node[] { return _nodes(this.node); } - /** * Iterate over branches in the tree. * - * This function yields pairs of (*path*, *branch*) where each - * *path* is a tuple of 0-based indices of branches to get to - * *branch*. For example, the path (2, 0) is the concept branch + * This function yields pairs of (`path`, `branch`) where each + * `path` is an array of 0-based indices of branches to get to + * `branch`. For example, the path [2, 0] is the concept branch * `('/', 'bark-01')` in the tree for the following PENMAN * string, traversing first to the third (index 2) branch of the - * top node, then to the first (index 0) branch of that node:: + * top node, then to the first (index 0) branch of that node: * * (t / try-01 * :ARG0 (d / dog) * :ARG1 (b / bark-01 * :ARG0 d)) * - * The (*path*, *branch*) pairs are yielded in depth-first order + * The (`path`, `branch`) pairs are yielded in depth-first order * of the tree traversal. + * + * @returns An iterator yielding pairs of path and branch in depth-first order. */ *walk(): Generator<_Step> { yield* _walk(this.node, []); } /** - * Recreate node variables formatted using *fmt*. + * Recreate node variables formatted using `fmt`. * - * The *fmt* string can be formatted with the following values: + * The `fmt` string can be formatted with the following values: * - * - ``prefix``: first alphabetic character in the node's concept - * - ``i``: 0-based index of the current occurrence of the prefix - * - ``j``: 1-based index starting from the second occurrence + * - `prefix`: first alphabetic character in the node's concept + * - `i`: 0-based index of the current occurrence of the prefix + * - `j`: 1-based index starting from the second occurrence */ resetVariables(fmt = '{prefix}{j}'): void { const varmap: VarMap = {}; @@ -158,28 +159,25 @@ function* _walk(node: Node, path: number[]) { } /** - * Return the variable prefix for *concept*. + * Return the variable prefix for `concept`. * - * If *concept* is a non-empty string, the prefix is the first + * If `concept` is a non-empty string, the prefix is the first * alphabetic character in the string, if there are any, downcased. - * Otherwise the prefix is ``'_'``. + * Otherwise, the prefix is `'_'`. * - * Examples: - * >>> _default_variable_prefix('Alphabet') - * 'a' - * >>> _default_variable_prefix('chase-01') - * 'c' - * >>> _default_variable_prefix('"string"') - * 's' - * >>> _default_variable_prefix('_predicate_n_1"') - * 'p' - * >>> _default_variable_prefix(1) - * '_' - * >>> _default_variable_prefix(None) - * '_' - * >>> _default_variable_prefix('') - * '_' + * @param concept - The concept to determine the prefix for. + * @returns The variable prefix for the given `concept`. + * @example + * // Assuming the function is named defaultVariablePrefix + * console.log(defaultVariablePrefix('Alphabet')); // Outputs: 'a' + * console.log(defaultVariablePrefix('chase-01')); // Outputs: 'c' + * console.log(defaultVariablePrefix('"string"')); // Outputs: 's' + * console.log(defaultVariablePrefix('_predicate_n_1"')); // Outputs: 'p' + * console.log(defaultVariablePrefix(1)); // Outputs: '_' + * console.log(defaultVariablePrefix(null)); // Outputs: '_' + * console.log(defaultVariablePrefix('')); // Outputs: '_' */ + export const _defaultVariablePrefix = (concept: any): Variable => { let prefix = '_'; if (concept && typeof concept === 'string') { @@ -215,19 +213,18 @@ const _mapVars = (node: Node, varmap: VarMap): Node => { }; /** - * Return ``True`` if *x* is a valid atomic value. + * Return `true` if `x` is a valid atomic value. * - * Examples: - * >>> from penman.tree import is_atomic - * >>> is_atomic('a') - * True - * >>> is_atomic(None) - * True - * >>> is_atomic(3.14) - * True - * >>> is_atomic(('a', [('/', 'alpha')])) - * False + * @param x - The value to check. + * @returns `true` if `x` is a valid atomic value, otherwise `false`. + * @example + * // Assuming the function is named isAtomic + * console.log(isAtomic('a')); // Outputs: true + * console.log(isAtomic(null)); // Outputs: true + * console.log(isAtomic(3.14)); // Outputs: true + * console.log(isAtomic(['a', [['/', 'alpha']]])); // Outputs: false */ + export const isAtomic = (x: any): boolean => { return ( x == null ||