@stxt-lang/core 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,7 +41,7 @@ The package ships CommonJS plus type declarations, so it works from both TypeScr
41
41
  ## Parsing
42
42
 
43
43
  ```ts
44
- import { Parser, ParseResult, Node } from '@stxt-lang/core';
44
+ import { Parser, ParseResult, Node, InlineNode } from '@stxt-lang/core';
45
45
 
46
46
  const text = [
47
47
  'Article (blog.post):',
@@ -62,14 +62,50 @@ if (result.hasErrors()) {
62
62
 
63
63
  const article: Node = result.getNodes()[0];
64
64
 
65
- console.log(article.getName()); // "Article"
66
- console.log(article.getNamespace()); // "blog.post"
67
- console.log(article.getChild('Title')?.getValue()); // "Getting started with STXT"
65
+ console.log(article.getName()); // "Article"
66
+ console.log(article.getNamespace()); // "blog.post"
67
+ if (article instanceof InlineNode) {
68
+ console.log(article.getChild('Title')?.getText()); // "Getting started with STXT"
69
+ }
68
70
  ```
69
71
 
70
72
  Use `parser.parse(text)` instead if you prefer an exception (`ParseException`) on the first error.
71
73
 
72
- Nodes are **frozen once parsed** — treat the tree as immutable.
74
+ ## Working with the tree
75
+
76
+ `Node` is an abstract class with exactly two forms, and each one owns only what is really its own: `InlineNode` (`Name: value`) has the optional value, the children and the child lookups (`getChildren()`, `getChild(name)`, `getChildrenByName(name)`); `TextNode` (`Name >>`) has the literal text lines and nothing else. What they share lives in `Node`: name and canonical name, declared and effective namespace, source line, parent (always an `InlineNode`) and `getText()` — the value of an inline node or the joined lines of a text node. Walking a tree therefore asks for the form (`node instanceof InlineNode`), the same way the canonical tree of STXT-TREE-SPEC has `children` only for inline nodes.
77
+
78
+ Trees are mutable and keep their own integrity: every node knows its parent, `addChild` links both ends and refuses a node that already has one, and `removeChild` / `detach()` undo it. Levels are derived from the chain of parents; the source line is only set by the parser.
79
+
80
+ ```ts
81
+ import { InlineNode, TextNode, Node } from '@stxt-lang/core';
82
+
83
+ const email = new InlineNode('Email', 'com.example.docs', 'Weekly report');
84
+ email.addInlineNode('From', 'ana@example.com');
85
+ const to = email.addInlineNode('To');
86
+ to.addInlineNode('Address', 'bob@example.com');
87
+ const body = email.addTextNode('Body', 'Hi Bob,\n\nSee attached.');
88
+
89
+ body.getParent() === email; // true
90
+ body.getLevel(); // 1
91
+ to.getNamespace(); // "com.example.docs", inherited
92
+ to.getDeclaredNamespace(); // "" — it declares none
93
+
94
+ // Reorganise: move "To" to the front
95
+ to.detach();
96
+ email.addChild(to, 0);
97
+
98
+ // Edit in place
99
+ email.setNamespace('com.example.mail'); // the whole inheriting subtree follows
100
+ body.setText('Hi Bob,\n\nSee the new attachment.');
101
+
102
+ for (const child of email.getChildren()) {
103
+ if (child instanceof InlineNode) { console.log(child.getValue(), child.getChildren().length); }
104
+ if (child instanceof TextNode) { console.log(child.getTextLines()); }
105
+ }
106
+ ```
107
+
108
+ Overloads with two strings always take the second one as the *content* (value or text); the namespace only appears in the three-argument forms. Adding a node that already has a parent throws `NODE_ALREADY_ATTACHED`; adding an ancestor throws `NODE_CYCLE`.
73
109
 
74
110
  ## Validating against a schema
75
111
 
@@ -259,7 +295,7 @@ const doc = NodeWriter.toSTXTDocs(result.getNodes(), IndentStyle.SPACES_4);
259
295
 
260
296
  Everything importable from the package:
261
297
 
262
- - **Parsing** — `Node`, `Parser`, `ParseResult`, `Line`, `Constants`, `parseLine`, `StringUtils`
298
+ - **Parsing** — `Node`, `InlineNode`, `TextNode`, `Parser`, `ParseResult`, `Line`, `Constants`, `parseLine`, `StringUtils`
263
299
  - **Exceptions** — `ParseException`, `ValidationException`
264
300
  - **Extension points** — `Observer`
265
301
  - **Schemas** — `Schema`, `SchemaValidator`, `SchemaProvider`, `NodeDefinition`, `ChildDefinition`, `transformNodeToSchema`, `transformTemplateNodeToSchema`
package/out/all.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export { Node } from "./core/Node";
2
+ export { InlineNode } from "./core/InlineNode";
3
+ export { TextNode } from "./core/TextNode";
2
4
  export { Parser } from "./core/Parser";
3
5
  export { ParseResult } from "./core/ParseResult";
4
6
  export { Line } from "./core/Line";
package/out/all.js CHANGED
@@ -3,9 +3,13 @@
3
3
  // Anything that should be consumable by third parties (e.g. the VSCode extension)
4
4
  // has to be re-exported from here.
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DiscoveryError = exports.DiscoveryResult = exports.DiscoveryResolver = exports.transformTemplateNodeToSchema = exports.toCanonicalJson = exports.toCanonicalTree = exports.IndentStyle = exports.NodeWriter = exports.ConditionalValidator = exports.UnifiedSchemaProvider = exports.transformNodeToSchema = exports.ChildDefinition = exports.NodeDefinition = exports.SchemaValidator = exports.Schema = exports.ValidationException = exports.ParseException = exports.StringUtils = exports.parseLine = exports.Constants = exports.Line = exports.ParseResult = exports.Parser = exports.Node = void 0;
6
+ exports.DiscoveryError = exports.DiscoveryResult = exports.DiscoveryResolver = exports.transformTemplateNodeToSchema = exports.toCanonicalJson = exports.toCanonicalTree = exports.IndentStyle = exports.NodeWriter = exports.ConditionalValidator = exports.UnifiedSchemaProvider = exports.transformNodeToSchema = exports.ChildDefinition = exports.NodeDefinition = exports.SchemaValidator = exports.Schema = exports.ValidationException = exports.ParseException = exports.StringUtils = exports.parseLine = exports.Constants = exports.Line = exports.ParseResult = exports.Parser = exports.TextNode = exports.InlineNode = exports.Node = void 0;
7
7
  var Node_1 = require("./core/Node");
8
8
  Object.defineProperty(exports, "Node", { enumerable: true, get: function () { return Node_1.Node; } });
9
+ var InlineNode_1 = require("./core/InlineNode");
10
+ Object.defineProperty(exports, "InlineNode", { enumerable: true, get: function () { return InlineNode_1.InlineNode; } });
11
+ var TextNode_1 = require("./core/TextNode");
12
+ Object.defineProperty(exports, "TextNode", { enumerable: true, get: function () { return TextNode_1.TextNode; } });
9
13
  var Parser_1 = require("./core/Parser");
10
14
  Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return Parser_1.Parser; } });
11
15
  var ParseResult_1 = require("./core/ParseResult");
@@ -0,0 +1,126 @@
1
+ import { Node } from "./Node";
2
+ import { TextNode } from "./TextNode";
3
+ /**
4
+ * INLINE node of the STXT tree (`Name: value`): an optional inline value and an ordered list of
5
+ * children. It is the only form that has children — and so the only one with child lookups
6
+ * ({@link InlineNode.getChild}, {@link InlineNode.getChildrenByName}) — and the only one that can
7
+ * create them ({@link InlineNode.addInlineNode}, {@link InlineNode.addTextNode}).
8
+ *
9
+ * Overloads with two strings always take the second one as the *content* (the value); the
10
+ * namespace only exists in the three-argument forms.
11
+ */
12
+ export declare class InlineNode extends Node {
13
+ private value;
14
+ private readonly children;
15
+ /**
16
+ * Creates an inline node with no value, no declared namespace and no known source line.
17
+ *
18
+ * @param name name of the node.
19
+ */
20
+ constructor(name: string);
21
+ /**
22
+ * Creates an inline node with a value, no declared namespace and no known source line.
23
+ *
24
+ * @param name name of the node.
25
+ * @param value inline value, or null/undefined for none.
26
+ */
27
+ constructor(name: string, value: string | null | undefined);
28
+ /**
29
+ * Creates an inline node with a declared namespace and a value; the source line is optional.
30
+ * This is the form the {@link Parser} uses.
31
+ *
32
+ * @param name name of the node.
33
+ * @param namespace namespace the node declares, or null/undefined/empty for none.
34
+ * @param value inline value, or null/undefined for none.
35
+ * @param line source line, or {@link Node.NO_LINE} (the default).
36
+ * @throws ParseException if the name or the namespace are not valid.
37
+ */
38
+ constructor(name: string, namespace: string | null | undefined, value: string | null | undefined, line?: number);
39
+ /** @returns the inline value of the node, trimmed; the empty string if it has none. */
40
+ getValue(): string;
41
+ /**
42
+ * Sets the inline value of the node.
43
+ *
44
+ * @param value new value, or null/undefined for none. It is trimmed.
45
+ */
46
+ setValue(value: string | null | undefined): void;
47
+ getText(): string;
48
+ isTextNode(): boolean;
49
+ /** @returns the children of the node in order of appearance, as a read-only view. */
50
+ getChildren(): ReadonlyArray<Node>;
51
+ /**
52
+ * Adds a child, linking both ends: afterwards `child.getParent()` is this node. It is appended
53
+ * at the end unless a position is given.
54
+ *
55
+ * @param child node to add; it must not have a parent yet.
56
+ * @param index position where to insert it (0 = first); at the end when omitted.
57
+ * @throws RuntimeException with code `NODE_ALREADY_ATTACHED` if the child already has a parent
58
+ * (detach it first), or `NODE_CYCLE` if it is this node or one of its ancestors.
59
+ * @throws RangeError if the index is out of range.
60
+ */
61
+ addChild(child: Node, index?: number): void;
62
+ /**
63
+ * Removes a direct child, unlinking both ends: afterwards `child.getParent()` is null and the
64
+ * child is a root on its own.
65
+ *
66
+ * @param child the child to remove.
67
+ * @returns true if it was a direct child of this node and has been removed; false otherwise.
68
+ */
69
+ removeChild(child: Node): boolean;
70
+ /**
71
+ * Looks up the only direct child with that name.
72
+ *
73
+ * @param cname name of the child to look for.
74
+ * @param namespace effective namespace to search in; this node's own effective namespace when omitted.
75
+ * @returns the only direct child with that name, or null if there is none.
76
+ * @throws RuntimeException with code `AMBIGUOUS_CHILD` if there is more than one; use {@link InlineNode.getChildrenByName} then.
77
+ */
78
+ getChild(cname: string, namespace?: string): Node | null;
79
+ /**
80
+ * Looks up every direct child with that name.
81
+ *
82
+ * @param cname name of the child to look for.
83
+ * @param namespace effective namespace to search in; this node's own effective namespace when omitted.
84
+ * @returns every direct child with that name in that namespace, in order of appearance.
85
+ */
86
+ getChildrenByName(cname: string, namespace?: string): Node[];
87
+ /**
88
+ * Creates an inline child and appends it. With two strings the second one is the value; the
89
+ * namespace only exists in the three-argument form.
90
+ *
91
+ * @param name name of the child.
92
+ * @returns the child created, already attached to this node.
93
+ */
94
+ addInlineNode(name: string): InlineNode;
95
+ /**
96
+ * @param name name of the child.
97
+ * @param value inline value, or null/undefined for none.
98
+ */
99
+ addInlineNode(name: string, value: string | null | undefined): InlineNode;
100
+ /**
101
+ * @param name name of the child.
102
+ * @param namespace namespace the child declares, or null/undefined/empty to inherit this node's.
103
+ * @param value inline value, or null/undefined for none.
104
+ */
105
+ addInlineNode(name: string, namespace: string | null | undefined, value: string | null | undefined): InlineNode;
106
+ /**
107
+ * Creates a text child and appends it. With two strings the second one is the text; the
108
+ * namespace only exists in the three-argument form.
109
+ *
110
+ * @param name name of the child.
111
+ * @returns the child created, already attached to this node.
112
+ */
113
+ addTextNode(name: string): TextNode;
114
+ /**
115
+ * @param name name of the child.
116
+ * @param text text of the child (split into lines at every line break), or its lines.
117
+ */
118
+ addTextNode(name: string, text: string | ReadonlyArray<string> | null | undefined): TextNode;
119
+ /**
120
+ * @param name name of the child.
121
+ * @param namespace namespace the child declares, or null/undefined/empty to inherit this node's.
122
+ * @param text text of the child (split into lines at every line break), or its lines.
123
+ */
124
+ addTextNode(name: string, namespace: string | null | undefined, text: string | ReadonlyArray<string> | null | undefined): TextNode;
125
+ protected describe(): string;
126
+ }
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InlineNode = void 0;
4
+ const Node_1 = require("./Node");
5
+ const TextNode_1 = require("./TextNode");
6
+ const RuntimeException_1 = require("../exceptions/RuntimeException");
7
+ const StringUtils_1 = require("./StringUtils");
8
+ /**
9
+ * INLINE node of the STXT tree (`Name: value`): an optional inline value and an ordered list of
10
+ * children. It is the only form that has children — and so the only one with child lookups
11
+ * ({@link InlineNode.getChild}, {@link InlineNode.getChildrenByName}) — and the only one that can
12
+ * create them ({@link InlineNode.addInlineNode}, {@link InlineNode.addTextNode}).
13
+ *
14
+ * Overloads with two strings always take the second one as the *content* (the value); the
15
+ * namespace only exists in the three-argument forms.
16
+ */
17
+ class InlineNode extends Node_1.Node {
18
+ constructor(name, ...rest) {
19
+ // With two strings the second one is the value; the namespace only exists with three or more
20
+ const [namespace, value, line] = rest.length <= 1
21
+ ? [null, rest[0], Node_1.Node.NO_LINE]
22
+ : [rest[0], rest[1], rest[2] ?? Node_1.Node.NO_LINE];
23
+ super(name, namespace, line);
24
+ this.children = [];
25
+ this.setValue(value);
26
+ }
27
+ // ----------------------------------------------------------------
28
+ // Value
29
+ // ----------------------------------------------------------------
30
+ /** @returns the inline value of the node, trimmed; the empty string if it has none. */
31
+ getValue() {
32
+ return this.value;
33
+ }
34
+ /**
35
+ * Sets the inline value of the node.
36
+ *
37
+ * @param value new value, or null/undefined for none. It is trimmed.
38
+ */
39
+ setValue(value) {
40
+ this.value = (value ?? "").trim();
41
+ }
42
+ getText() {
43
+ return this.value;
44
+ }
45
+ isTextNode() {
46
+ return false;
47
+ }
48
+ // ----------------------------------------------------------------
49
+ // Children
50
+ // ----------------------------------------------------------------
51
+ /** @returns the children of the node in order of appearance, as a read-only view. */
52
+ getChildren() {
53
+ return this.children;
54
+ }
55
+ /**
56
+ * Adds a child, linking both ends: afterwards `child.getParent()` is this node. It is appended
57
+ * at the end unless a position is given.
58
+ *
59
+ * @param child node to add; it must not have a parent yet.
60
+ * @param index position where to insert it (0 = first); at the end when omitted.
61
+ * @throws RuntimeException with code `NODE_ALREADY_ATTACHED` if the child already has a parent
62
+ * (detach it first), or `NODE_CYCLE` if it is this node or one of its ancestors.
63
+ * @throws RangeError if the index is out of range.
64
+ */
65
+ addChild(child, index) {
66
+ if (child.getParent() !== null) {
67
+ throw new RuntimeException_1.RuntimeException("NODE_ALREADY_ATTACHED", `Node '${child.getName()}' already has a parent: detach it first`);
68
+ }
69
+ for (let p = this; p !== null; p = p.getParent()) {
70
+ if (p === child) {
71
+ throw new RuntimeException_1.RuntimeException("NODE_CYCLE", `Node '${child.getName()}' cannot be a child of itself or of one of its descendants`);
72
+ }
73
+ }
74
+ const at = index ?? this.children.length;
75
+ if (!Number.isInteger(at) || at < 0 || at > this.children.length) {
76
+ throw new RangeError(`Index ${index} out of range [0, ${this.children.length}]`);
77
+ }
78
+ this.children.splice(at, 0, child);
79
+ child._setParent(this);
80
+ }
81
+ /**
82
+ * Removes a direct child, unlinking both ends: afterwards `child.getParent()` is null and the
83
+ * child is a root on its own.
84
+ *
85
+ * @param child the child to remove.
86
+ * @returns true if it was a direct child of this node and has been removed; false otherwise.
87
+ */
88
+ removeChild(child) {
89
+ if (child.getParent() !== this) {
90
+ return false;
91
+ }
92
+ // Identity, not equality: two children may look alike
93
+ const i = this.children.indexOf(child);
94
+ if (i === -1) {
95
+ return false;
96
+ }
97
+ this.children.splice(i, 1);
98
+ child._setParent(null);
99
+ return true;
100
+ }
101
+ /**
102
+ * Looks up the only direct child with that name.
103
+ *
104
+ * @param cname name of the child to look for.
105
+ * @param namespace effective namespace to search in; this node's own effective namespace when omitted.
106
+ * @returns the only direct child with that name, or null if there is none.
107
+ * @throws RuntimeException with code `AMBIGUOUS_CHILD` if there is more than one; use {@link InlineNode.getChildrenByName} then.
108
+ */
109
+ getChild(cname, namespace) {
110
+ const result = this.getChildrenByName(cname, namespace);
111
+ if (result.length > 1) {
112
+ throw new RuntimeException_1.RuntimeException("AMBIGUOUS_CHILD", "More than 1 child. Use getChildrenByName");
113
+ }
114
+ return result.length === 0 ? null : result[0];
115
+ }
116
+ /**
117
+ * Looks up every direct child with that name.
118
+ *
119
+ * @param cname name of the child to look for.
120
+ * @param namespace effective namespace to search in; this node's own effective namespace when omitted.
121
+ * @returns every direct child with that name in that namespace, in order of appearance.
122
+ */
123
+ getChildrenByName(cname, namespace) {
124
+ const key = StringUtils_1.StringUtils.normalize(cname);
125
+ const targetNamespace = namespace !== undefined ? namespace : this.getNamespace();
126
+ return this.children.filter(child => child.getCanonicalName() === key && child.getNamespace() === targetNamespace);
127
+ }
128
+ addInlineNode(name, ...rest) {
129
+ const child = rest.length <= 1
130
+ ? new InlineNode(name, rest[0])
131
+ : new InlineNode(name, rest[0], rest[1]);
132
+ this.addChild(child);
133
+ return child;
134
+ }
135
+ addTextNode(name, ...rest) {
136
+ const child = rest.length <= 1
137
+ ? new TextNode_1.TextNode(name, rest[0])
138
+ : new TextNode_1.TextNode(name, rest[0], rest[1]);
139
+ this.addChild(child);
140
+ return child;
141
+ }
142
+ describe() {
143
+ let s = "";
144
+ if (this.value.length > 0) {
145
+ s += `, value='${this.value}'`;
146
+ }
147
+ s += `, children=${this.children.length}`;
148
+ return s;
149
+ }
150
+ }
151
+ exports.InlineNode = InlineNode;
152
+ //# sourceMappingURL=InlineNode.js.map
@@ -1,83 +1,101 @@
1
+ import type { InlineNode } from "./InlineNode";
1
2
  /**
2
- * Node of the STXT tree. Mutable while parsing ({@link Node.addChild}/{@link Node.addTextLine}
3
- * are public); once the document is closed it must be treated as read-only. It represents both
4
- * INLINE nodes (with {@link Node.getValue}) and BLOCK text nodes (with {@link Node.getTextLines}),
5
- * as told apart by {@link Node.isTextNode}.
3
+ * Node of the STXT tree: what INLINE nodes ({@link InlineNode}) and BLOCK text nodes
4
+ * ({@link TextNode}) have in common. Those two are the only forms, and each one owns what is
5
+ * really its own only an `InlineNode` has a value and children (and so the child lookups); only
6
+ * a `TextNode` has text lines. Code that walks a tree asks for the form
7
+ * (`node instanceof InlineNode`), the same way the canonical tree of STXT-TREE-SPEC has
8
+ * `children` only for inline nodes.
9
+ *
10
+ * Nodes are mutable, and the tree keeps its own integrity: a node knows its
11
+ * {@link Node.getParent | parent} (always an `InlineNode`), {@link InlineNode.addChild} links
12
+ * both ends and refuses a node that already has a parent, and {@link InlineNode.removeChild} /
13
+ * {@link Node.detach} undo it. The {@link Node.getLevel | level} is derived from the chain of
14
+ * parents, never stored.
15
+ *
16
+ * The namespace a node *declares* ({@link Node.getDeclaredNamespace}) and the one that *applies*
17
+ * to it ({@link Node.getNamespace}) are different things: the effective namespace is the declared
18
+ * one or, failing that, the parent's effective namespace (STXT-SPEC: namespaces are inherited
19
+ * vertically). Changing the declared namespace of a node therefore changes the effective
20
+ * namespace of the whole subtree that inherited it, and so does moving a subtree.
21
+ *
22
+ * The source line ({@link Node.getLine}) is optional: the parser sets it, code that builds trees
23
+ * usually does not ({@link Node.NO_LINE}).
6
24
  */
7
- export declare class Node {
8
- private readonly name;
9
- private readonly normalizedName;
10
- private readonly namespace;
11
- private readonly textNode;
12
- private readonly value;
13
- private textLines;
14
- private readonly line;
15
- private readonly level;
16
- private children;
25
+ export declare abstract class Node {
26
+ /** Value of {@link Node.getLine} when the node has no known position in a document. */
27
+ static readonly NO_LINE = -1;
28
+ private name;
29
+ private canonicalName;
30
+ private declaredNamespace;
31
+ private line;
32
+ private parent;
17
33
  /**
18
- * Creates a node with its full position in the document. This is the constructor the
19
- * {@link Parser} uses while parsing.
34
+ * Common initialisation, for the two concrete forms.
20
35
  *
21
- * @param line line number of the document where the node opens.
22
- * @param level indentation level of the node (0 for root nodes).
23
36
  * @param name name of the node.
24
- * @param namespace namespace of the node, or null/undefined if it has none.
25
- * @param textNode true if it is a text block node (BLOCK); false if it is INLINE.
26
- * @param value inline value of the node (INLINE node), ignored when it is BLOCK.
27
- * @throws ParseException if the name or the namespace are not valid.
37
+ * @param namespace namespace the node declares, or null/undefined/empty if it declares none.
38
+ * @param line source line, or {@link Node.NO_LINE}.
39
+ * @throws ParseException with code `INVALID_NODE_NAME` if the name is not a valid STXT node
40
+ * name, or if the namespace does not have a valid format.
28
41
  */
29
- constructor(line: number, level: number, name: string, namespace: string | null | undefined, textNode: boolean, value: string | null | undefined);
42
+ protected constructor(name: string, namespace: string | null | undefined, line: number);
43
+ /** @returns the original name of the node as it appears in the document (with spaces compacted). */
44
+ getName(): string;
30
45
  /**
31
- * Appends a text line to a BLOCK node.
46
+ * Renames the node. The canonical name is recomputed.
32
47
  *
33
- * @param line text line to append to a BLOCK node ({@link Node.isTextNode}).
48
+ * @param name new name of the node.
49
+ * @throws ParseException with code `INVALID_NODE_NAME` if it is not a valid STXT node name.
50
+ */
51
+ setName(name: string): void;
52
+ /** @returns the canonical name of the node (STXT-SPEC §4.3), used to compare/look up by structural identity. */
53
+ getCanonicalName(): string;
54
+ /**
55
+ * @returns the canonical name of the node.
56
+ * @deprecated since 0.7.0, use {@link Node.getCanonicalName}; "canonical name" is the term of
57
+ * the specifications. To be removed in a later version.
34
58
  */
35
- addTextLine(line: string): void;
36
- /** @returns the original name of the node as it appears in the document (with spaces compacted). */
37
- getName(): string;
38
- /** @returns the canonical name of the node, used to compare/look up by structural identity. */
39
59
  getNormalizedName(): string;
40
- /** @returns the canonical name prefixed by its namespace (`namespace:name`), or just the name when there is no namespace. */
60
+ /** @returns the canonical name prefixed by the effective namespace (`namespace:name`), or just the canonical name when there is no namespace. */
41
61
  getQualifiedName(): string;
42
- /** @returns the effective namespace of the node (its own or inherited from the parent), lower-cased, or the empty string if it has none. */
43
- getNamespace(): string;
44
- /** @returns the children of the node in order of appearance, as a read-only view. */
45
- getChildren(): ReadonlyArray<Node>;
62
+ /** @returns the namespace this node declares itself, lower-cased, or the empty string if it declares none (and so inherits the parent's). */
63
+ getDeclaredNamespace(): string;
46
64
  /**
47
- * Appends an already closed child to this node.
65
+ * Sets the namespace this node declares. The empty string (or null/undefined) means "none":
66
+ * the node then inherits the effective namespace of its parent.
48
67
  *
49
- * @param node already closed child to append at the end of this node's list of children.
68
+ * @param namespace namespace to declare, or null/undefined/empty for none.
69
+ * @throws ParseException if the namespace does not have a valid format (STXT-SPEC §7).
50
70
  */
51
- addChild(node: Node): void;
52
- /** @returns the inline value of the node (INLINE node), or the empty string if it is a BLOCK node. */
53
- getValue(): string;
54
- /** @returns the text lines of a BLOCK node ({@link Node.isTextNode}), in order of appearance. */
55
- getTextLines(): ReadonlyArray<string>;
56
- /** @returns the line number of the document where this node was opened. */
71
+ setNamespace(namespace: string | null | undefined): void;
72
+ /** @returns the effective namespace of the node: the one it declares or, failing that, the effective namespace of its parent; the empty string if there is none. */
73
+ getNamespace(): string;
74
+ /** @returns the line number of the document where this node was opened, or {@link Node.NO_LINE} if unknown. */
57
75
  getLine(): number;
58
- /** @returns the indentation level of the node (0 for root nodes). */
59
- getLevel(): number;
60
- /** @returns true if the node is a text block (BLOCK, `>>`); false if it is INLINE. */
61
- isTextNode(): boolean;
62
- /** @returns the textual content of the node: the text lines joined with '\n' if it is BLOCK, or the inline value otherwise. */
63
- getText(): string;
64
76
  /**
65
- * Looks up the only direct child with that name.
77
+ * Sets the source line of the node.
66
78
  *
67
- * @param cname name of the child to look for.
68
- * @param namespace namespace to search in; this node's own namespace when omitted.
69
- * @returns the only direct child with that name, or null if there is none.
70
- * @throws RuntimeException with code `AMBIGUOUS_CHILD` if there is more than one; use {@link Node.getChildrenByName} then.
79
+ * @param line line number, or {@link Node.NO_LINE} if unknown.
71
80
  */
72
- getChild(cname: string, namespace?: string): Node | null;
81
+ setLine(line: number): void;
82
+ /** @returns the depth of the node in its tree: 0 for a root node, 1 for its children, and so on. */
83
+ getLevel(): number;
84
+ /** @returns the parent of this node, or null if it is a root node. */
85
+ getParent(): InlineNode | null;
73
86
  /**
74
- * Looks up every direct child with that name.
87
+ * Removes this node from its parent, if it has one. Afterwards the node is a root, and its
88
+ * effective namespace is the one it declares.
75
89
  *
76
- * @param cname name of the child to look for.
77
- * @param namespace namespace to search in; this node's own namespace when omitted.
78
- * @returns every direct child with that name in the given namespace, in order of appearance.
90
+ * @returns true if the node had a parent and was detached; false if it was already a root.
79
91
  */
80
- getChildrenByName(cname: string, namespace?: string): Node[];
92
+ detach(): boolean;
93
+ /** @returns true if the node is a text block (BLOCK, `>>`); false if it is INLINE. */
94
+ abstract isTextNode(): boolean;
95
+ /** @returns the textual content of the node: the text lines joined with '\n' if it is BLOCK, or the inline value otherwise. */
96
+ abstract getText(): string;
81
97
  /** @returns a readable representation of the node, for debugging and error messages. */
82
98
  toString(): string;
99
+ /** Form-specific part of {@link Node.toString}. */
100
+ protected abstract describe(): string;
83
101
  }