@stxt-lang/core 0.5.1 → 0.5.3
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/LICENSE +21 -0
- package/README.md +157 -0
- package/out/all.d.ts +1 -0
- package/out/all.js +6 -4
- package/out/core/Constants.d.ts +8 -0
- package/out/core/Constants.js +8 -0
- package/out/core/Line.d.ts +20 -0
- package/out/core/Line.js +15 -0
- package/out/core/LineParser.d.ts +17 -0
- package/out/core/LineParser.js +27 -10
- package/out/core/NameNamespace.d.ts +9 -0
- package/out/core/NameNamespace.js +9 -0
- package/out/core/NameNamespaceParser.d.ts +11 -0
- package/out/core/NameNamespaceParser.js +16 -5
- package/out/core/NamespaceValidator.d.ts +18 -0
- package/out/core/NamespaceValidator.js +18 -0
- package/out/core/Node.d.ts +55 -0
- package/out/core/Node.js +56 -1
- package/out/core/NodeCreator.d.ts +11 -0
- package/out/core/NodeCreator.js +14 -3
- package/out/core/ParseResult.d.ts +26 -0
- package/out/core/ParseResult.js +26 -0
- package/out/core/Parser.d.ts +31 -0
- package/out/core/Parser.js +50 -19
- package/out/core/StringUtils.d.ts +31 -0
- package/out/core/StringUtils.js +40 -9
- package/out/exceptions/ParseException.d.ts +14 -0
- package/out/exceptions/ParseException.js +12 -0
- package/out/exceptions/RuntimeException.d.ts +14 -0
- package/out/exceptions/RuntimeException.js +13 -0
- package/out/exceptions/ValidationException.d.ts +8 -0
- package/out/exceptions/ValidationException.js +8 -0
- package/out/processors/Observer.d.ts +29 -0
- package/out/processors/Validator.d.ts +9 -0
- package/out/runtime/ConditionalValidator.d.ts +15 -0
- package/out/runtime/ConditionalValidator.js +16 -2
- package/out/runtime/NodeWriter.d.ts +18 -0
- package/out/runtime/NodeWriter.js +18 -0
- package/out/runtime/UnifiedSchemaProvider.d.ts +23 -5
- package/out/runtime/UnifiedSchemaProvider.js +28 -10
- package/out/schema/ChildDefinition.d.ts +18 -0
- package/out/schema/ChildDefinition.js +18 -0
- package/out/schema/NodeDefinition.d.ts +44 -0
- package/out/schema/NodeDefinition.js +47 -3
- package/out/schema/Schema.d.ts +26 -0
- package/out/schema/Schema.js +26 -1
- package/out/schema/SchemaParser.d.ts +7 -0
- package/out/schema/SchemaParser.js +26 -16
- package/out/schema/SchemaProvider.d.ts +7 -0
- package/out/schema/SchemaProviderMemory.d.ts +27 -0
- package/out/schema/SchemaProviderMemory.js +27 -0
- package/out/schema/SchemaProviderMeta.d.ts +16 -0
- package/out/schema/SchemaProviderMeta.js +78 -62
- package/out/schema/SchemaValidator.d.ts +20 -0
- package/out/schema/SchemaValidator.js +27 -7
- package/out/schema/Type.d.ts +9 -0
- package/out/schema/TypeRegistry.d.ts +13 -0
- package/out/schema/TypeRegistry.js +18 -5
- package/out/schema/type/BASE64.d.ts +1 -0
- package/out/schema/type/BASE64.js +5 -4
- package/out/schema/type/BINARY.d.ts +1 -0
- package/out/schema/type/BINARY.js +2 -1
- package/out/schema/type/BLOCK.d.ts +1 -0
- package/out/schema/type/BLOCK.js +2 -1
- package/out/schema/type/BOOLEAN.d.ts +1 -0
- package/out/schema/type/BOOLEAN.js +1 -0
- package/out/schema/type/DATE.d.ts +1 -0
- package/out/schema/type/DATE.js +1 -0
- package/out/schema/type/EMAIL.d.ts +1 -0
- package/out/schema/type/EMAIL.js +1 -0
- package/out/schema/type/ENUM.d.ts +1 -0
- package/out/schema/type/ENUM.js +2 -1
- package/out/schema/type/GROUP.d.ts +1 -0
- package/out/schema/type/GROUP.js +2 -1
- package/out/schema/type/HEXADECIMAL.d.ts +1 -0
- package/out/schema/type/HEXADECIMAL.js +2 -1
- package/out/schema/type/INLINE.d.ts +1 -0
- package/out/schema/type/INLINE.js +2 -1
- package/out/schema/type/INTEGER.d.ts +1 -0
- package/out/schema/type/INTEGER.js +1 -0
- package/out/schema/type/MARKDOWN.d.ts +4 -0
- package/out/schema/type/MARKDOWN.js +4 -2
- package/out/schema/type/NATURAL.d.ts +1 -0
- package/out/schema/type/NATURAL.js +1 -0
- package/out/schema/type/NUMBER.d.ts +1 -0
- package/out/schema/type/NUMBER.js +1 -0
- package/out/schema/type/TEXT.d.ts +1 -0
- package/out/schema/type/TEXT.js +1 -0
- package/out/schema/type/TIME.d.ts +1 -0
- package/out/schema/type/TIME.js +1 -0
- package/out/schema/type/TIMESTAMP.d.ts +1 -0
- package/out/schema/type/TIMESTAMP.js +1 -0
- package/out/schema/type/URL.d.ts +1 -0
- package/out/schema/type/URL.js +2 -1
- package/out/schema/type/UUID.d.ts +1 -0
- package/out/schema/type/UUID.js +1 -0
- package/out/schema/type/binaryValue.d.ts +9 -0
- package/out/schema/type/binaryValue.js +9 -3
- package/out/schema/type/regexType.d.ts +8 -0
- package/out/schema/type/regexType.js +9 -1
- package/out/template/ChildLine.d.ts +14 -0
- package/out/template/ChildLine.js +14 -0
- package/out/template/ChildLineParser.d.ts +10 -0
- package/out/template/ChildLineParser.js +17 -8
- package/out/template/MetaTemplateSchemaProvider.d.ts +16 -0
- package/out/template/MetaTemplateSchemaProvider.js +22 -6
- package/out/template/TemplateParser.d.ts +8 -0
- package/out/template/TemplateParser.js +49 -39
- package/out/template/TemplateSchemaProviderMemory.d.ts +18 -0
- package/out/template/TemplateSchemaProviderMemory.js +21 -3
- package/package.json +60 -45
- package/out/all.js.map +0 -1
- package/out/core/Constants.js.map +0 -1
- package/out/core/Line.js.map +0 -1
- package/out/core/LineParser.js.map +0 -1
- package/out/core/NameNamespace.js.map +0 -1
- package/out/core/NameNamespaceParser.js.map +0 -1
- package/out/core/NamespaceValidator.js.map +0 -1
- package/out/core/Node.js.map +0 -1
- package/out/core/NodeCreator.js.map +0 -1
- package/out/core/ParseResult.js.map +0 -1
- package/out/core/Parser.js.map +0 -1
- package/out/core/StringUtils.js.map +0 -1
- package/out/exceptions/ParseException.js.map +0 -1
- package/out/exceptions/RuntimeException.js.map +0 -1
- package/out/exceptions/ValidationException.js.map +0 -1
- package/out/processors/Observer.js.map +0 -1
- package/out/processors/Validator.js.map +0 -1
- package/out/runtime/ConditionalValidator.js.map +0 -1
- package/out/runtime/NodeWriter.js.map +0 -1
- package/out/runtime/UnifiedSchemaProvider.js.map +0 -1
- package/out/schema/ChildDefinition.js.map +0 -1
- package/out/schema/NodeDefinition.js.map +0 -1
- package/out/schema/Schema.js.map +0 -1
- package/out/schema/SchemaParser.js.map +0 -1
- package/out/schema/SchemaProvider.js.map +0 -1
- package/out/schema/SchemaProviderMemory.js.map +0 -1
- package/out/schema/SchemaProviderMeta.js.map +0 -1
- package/out/schema/SchemaValidator.js.map +0 -1
- package/out/schema/Type.js.map +0 -1
- package/out/schema/TypeRegistry.js.map +0 -1
- package/out/schema/type/BASE64.js.map +0 -1
- package/out/schema/type/BINARY.js.map +0 -1
- package/out/schema/type/BLOCK.js.map +0 -1
- package/out/schema/type/BOOLEAN.js.map +0 -1
- package/out/schema/type/DATE.js.map +0 -1
- package/out/schema/type/EMAIL.js.map +0 -1
- package/out/schema/type/ENUM.js.map +0 -1
- package/out/schema/type/GROUP.js.map +0 -1
- package/out/schema/type/HEXADECIMAL.js.map +0 -1
- package/out/schema/type/INLINE.js.map +0 -1
- package/out/schema/type/INTEGER.js.map +0 -1
- package/out/schema/type/MARKDOWN.js.map +0 -1
- package/out/schema/type/NATURAL.js.map +0 -1
- package/out/schema/type/NUMBER.js.map +0 -1
- package/out/schema/type/TEXT.js.map +0 -1
- package/out/schema/type/TIME.js.map +0 -1
- package/out/schema/type/TIMESTAMP.js.map +0 -1
- package/out/schema/type/URL.js.map +0 -1
- package/out/schema/type/UUID.js.map +0 -1
- package/out/schema/type/binaryValue.js.map +0 -1
- package/out/schema/type/regexType.js.map +0 -1
- package/out/template/ChildLine.js.map +0 -1
- package/out/template/ChildLineParser.js.map +0 -1
- package/out/template/MetaTemplateSchemaProvider.js.map +0 -1
- package/out/template/TemplateParser.js.map +0 -1
- package/out/template/TemplateSchemaProviderMemory.js.map +0 -1
package/out/core/Node.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
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}.
|
|
6
|
+
*/
|
|
1
7
|
export declare class Node {
|
|
2
8
|
private static readonly VALID_NAME;
|
|
3
9
|
private readonly name;
|
|
@@ -9,21 +15,70 @@ export declare class Node {
|
|
|
9
15
|
private readonly line;
|
|
10
16
|
private readonly level;
|
|
11
17
|
private children;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a node with its full position in the document. This is the constructor the
|
|
20
|
+
* {@link Parser} uses while parsing.
|
|
21
|
+
*
|
|
22
|
+
* @param line line number of the document where the node opens.
|
|
23
|
+
* @param level indentation level of the node (0 for root nodes).
|
|
24
|
+
* @param name name of the node.
|
|
25
|
+
* @param namespace namespace of the node, or null/undefined if it has none.
|
|
26
|
+
* @param textNode true if it is a text block node (BLOCK); false if it is INLINE.
|
|
27
|
+
* @param value inline value of the node (INLINE node), ignored when it is BLOCK.
|
|
28
|
+
* @throws ParseException if the name or the namespace are not valid.
|
|
29
|
+
*/
|
|
12
30
|
constructor(line: number, level: number, name: string, namespace: string | null | undefined, textNode: boolean, value: string | null | undefined);
|
|
31
|
+
/**
|
|
32
|
+
* Appends a text line to a BLOCK node.
|
|
33
|
+
*
|
|
34
|
+
* @param line text line to append to a BLOCK node ({@link Node.isTextNode}).
|
|
35
|
+
*/
|
|
13
36
|
addTextLine(line: string): void;
|
|
37
|
+
/** @returns the original name of the node as it appears in the document (with spaces compacted). */
|
|
14
38
|
getName(): string;
|
|
39
|
+
/** @returns the canonical name of the node, used to compare/look up by structural identity. */
|
|
15
40
|
getNormalizedName(): string;
|
|
41
|
+
/** @returns the canonical name prefixed by its namespace (`namespace:name`), or just the name when there is no namespace. */
|
|
16
42
|
getQualifiedName(): string;
|
|
43
|
+
/** @returns the effective namespace of the node (its own or inherited from the parent), lower-cased, or the empty string if it has none. */
|
|
17
44
|
getNamespace(): string;
|
|
45
|
+
/** @returns the children of the node in order of appearance, as a read-only view. */
|
|
18
46
|
getChildren(): ReadonlyArray<Node>;
|
|
47
|
+
/**
|
|
48
|
+
* Appends an already closed child to this node.
|
|
49
|
+
*
|
|
50
|
+
* @param node already closed child to append at the end of this node's list of children.
|
|
51
|
+
*/
|
|
19
52
|
addChild(node: Node): void;
|
|
53
|
+
/** @returns the inline value of the node (INLINE node), or the empty string if it is a BLOCK node. */
|
|
20
54
|
getValue(): string;
|
|
55
|
+
/** @returns the text lines of a BLOCK node ({@link Node.isTextNode}), in order of appearance. */
|
|
21
56
|
getTextLines(): ReadonlyArray<string>;
|
|
57
|
+
/** @returns the line number of the document where this node was opened. */
|
|
22
58
|
getLine(): number;
|
|
59
|
+
/** @returns the indentation level of the node (0 for root nodes). */
|
|
23
60
|
getLevel(): number;
|
|
61
|
+
/** @returns true if the node is a text block (BLOCK, `>>`); false if it is INLINE. */
|
|
24
62
|
isTextNode(): boolean;
|
|
63
|
+
/** @returns the textual content of the node: the text lines joined with '\n' if it is BLOCK, or the inline value otherwise. */
|
|
25
64
|
getText(): string;
|
|
65
|
+
/**
|
|
66
|
+
* Looks up the only direct child with that name.
|
|
67
|
+
*
|
|
68
|
+
* @param cname name of the child to look for.
|
|
69
|
+
* @param namespace namespace to search in; this node's own namespace when omitted.
|
|
70
|
+
* @returns the only direct child with that name, or null if there is none.
|
|
71
|
+
* @throws RuntimeException with code `AMBIGUOUS_CHILD` if there is more than one; use {@link Node.getChildrenByName} then.
|
|
72
|
+
*/
|
|
26
73
|
getChild(cname: string, namespace?: string): Node | null;
|
|
74
|
+
/**
|
|
75
|
+
* Looks up every direct child with that name.
|
|
76
|
+
*
|
|
77
|
+
* @param cname name of the child to look for.
|
|
78
|
+
* @param namespace namespace to search in; this node's own namespace when omitted.
|
|
79
|
+
* @returns every direct child with that name in the given namespace, in order of appearance.
|
|
80
|
+
*/
|
|
27
81
|
getChildrenByName(cname: string, namespace?: string): Node[];
|
|
82
|
+
/** @returns a readable representation of the node, for debugging and error messages. */
|
|
28
83
|
toString(): string;
|
|
29
84
|
}
|
package/out/core/Node.js
CHANGED
|
@@ -5,7 +5,25 @@ const ParseException_1 = require("../exceptions/ParseException");
|
|
|
5
5
|
const RuntimeException_1 = require("../exceptions/RuntimeException");
|
|
6
6
|
const NamespaceValidator_1 = require("./NamespaceValidator");
|
|
7
7
|
const StringUtils_1 = require("./StringUtils");
|
|
8
|
+
/**
|
|
9
|
+
* Node of the STXT tree. Mutable while parsing ({@link Node.addChild}/{@link Node.addTextLine}
|
|
10
|
+
* are public); once the document is closed it must be treated as read-only. It represents both
|
|
11
|
+
* INLINE nodes (with {@link Node.getValue}) and BLOCK text nodes (with {@link Node.getTextLines}),
|
|
12
|
+
* as told apart by {@link Node.isTextNode}.
|
|
13
|
+
*/
|
|
8
14
|
class Node {
|
|
15
|
+
/**
|
|
16
|
+
* Creates a node with its full position in the document. This is the constructor the
|
|
17
|
+
* {@link Parser} uses while parsing.
|
|
18
|
+
*
|
|
19
|
+
* @param line line number of the document where the node opens.
|
|
20
|
+
* @param level indentation level of the node (0 for root nodes).
|
|
21
|
+
* @param name name of the node.
|
|
22
|
+
* @param namespace namespace of the node, or null/undefined if it has none.
|
|
23
|
+
* @param textNode true if it is a text block node (BLOCK); false if it is INLINE.
|
|
24
|
+
* @param value inline value of the node (INLINE node), ignored when it is BLOCK.
|
|
25
|
+
* @throws ParseException if the name or the namespace are not valid.
|
|
26
|
+
*/
|
|
9
27
|
constructor(line, level, name, namespace, textNode, value) {
|
|
10
28
|
this.textLines = [];
|
|
11
29
|
this.children = [];
|
|
@@ -27,47 +45,76 @@ class Node {
|
|
|
27
45
|
throw new ParseException_1.ParseException(line, "INVALID_NODE_NAME", `Node name not valid: ${name}`);
|
|
28
46
|
}
|
|
29
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Appends a text line to a BLOCK node.
|
|
50
|
+
*
|
|
51
|
+
* @param line text line to append to a BLOCK node ({@link Node.isTextNode}).
|
|
52
|
+
*/
|
|
30
53
|
addTextLine(line) {
|
|
31
54
|
this.textLines.push(line);
|
|
32
55
|
}
|
|
56
|
+
/** @returns the original name of the node as it appears in the document (with spaces compacted). */
|
|
33
57
|
getName() {
|
|
34
58
|
return this.name;
|
|
35
59
|
}
|
|
60
|
+
/** @returns the canonical name of the node, used to compare/look up by structural identity. */
|
|
36
61
|
getNormalizedName() {
|
|
37
62
|
return this.normalizedName;
|
|
38
63
|
}
|
|
64
|
+
/** @returns the canonical name prefixed by its namespace (`namespace:name`), or just the name when there is no namespace. */
|
|
39
65
|
getQualifiedName() {
|
|
40
66
|
return this.namespace.length === 0
|
|
41
67
|
? this.normalizedName
|
|
42
68
|
: `${this.namespace}:${this.normalizedName}`;
|
|
43
69
|
}
|
|
70
|
+
/** @returns the effective namespace of the node (its own or inherited from the parent), lower-cased, or the empty string if it has none. */
|
|
44
71
|
getNamespace() {
|
|
45
72
|
return this.namespace;
|
|
46
73
|
}
|
|
74
|
+
/** @returns the children of the node in order of appearance, as a read-only view. */
|
|
47
75
|
getChildren() {
|
|
48
76
|
return this.children;
|
|
49
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Appends an already closed child to this node.
|
|
80
|
+
*
|
|
81
|
+
* @param node already closed child to append at the end of this node's list of children.
|
|
82
|
+
*/
|
|
50
83
|
addChild(node) {
|
|
51
84
|
this.children.push(node);
|
|
52
85
|
}
|
|
86
|
+
/** @returns the inline value of the node (INLINE node), or the empty string if it is a BLOCK node. */
|
|
53
87
|
getValue() {
|
|
54
88
|
return this.value;
|
|
55
89
|
}
|
|
90
|
+
/** @returns the text lines of a BLOCK node ({@link Node.isTextNode}), in order of appearance. */
|
|
56
91
|
getTextLines() {
|
|
57
92
|
return this.textLines;
|
|
58
93
|
}
|
|
94
|
+
/** @returns the line number of the document where this node was opened. */
|
|
59
95
|
getLine() {
|
|
60
96
|
return this.line;
|
|
61
97
|
}
|
|
98
|
+
/** @returns the indentation level of the node (0 for root nodes). */
|
|
62
99
|
getLevel() {
|
|
63
100
|
return this.level;
|
|
64
101
|
}
|
|
102
|
+
/** @returns true if the node is a text block (BLOCK, `>>`); false if it is INLINE. */
|
|
65
103
|
isTextNode() {
|
|
66
104
|
return this.textNode;
|
|
67
105
|
}
|
|
106
|
+
/** @returns the textual content of the node: the text lines joined with '\n' if it is BLOCK, or the inline value otherwise. */
|
|
68
107
|
getText() {
|
|
69
108
|
return this.isTextNode() ? this.textLines.join("\n") : this.value;
|
|
70
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Looks up the only direct child with that name.
|
|
112
|
+
*
|
|
113
|
+
* @param cname name of the child to look for.
|
|
114
|
+
* @param namespace namespace to search in; this node's own namespace when omitted.
|
|
115
|
+
* @returns the only direct child with that name, or null if there is none.
|
|
116
|
+
* @throws RuntimeException with code `AMBIGUOUS_CHILD` if there is more than one; use {@link Node.getChildrenByName} then.
|
|
117
|
+
*/
|
|
71
118
|
getChild(cname, namespace) {
|
|
72
119
|
const result = this.getChildrenByName(cname, namespace);
|
|
73
120
|
if (result.length > 1) {
|
|
@@ -79,6 +126,13 @@ class Node {
|
|
|
79
126
|
return result[0];
|
|
80
127
|
}
|
|
81
128
|
// Fast access methods to children
|
|
129
|
+
/**
|
|
130
|
+
* Looks up every direct child with that name.
|
|
131
|
+
*
|
|
132
|
+
* @param cname name of the child to look for.
|
|
133
|
+
* @param namespace namespace to search in; this node's own namespace when omitted.
|
|
134
|
+
* @returns every direct child with that name in the given namespace, in order of appearance.
|
|
135
|
+
*/
|
|
82
136
|
getChildrenByName(cname, namespace) {
|
|
83
137
|
const key = StringUtils_1.StringUtils.normalize(cname);
|
|
84
138
|
const targetNamespace = namespace !== undefined ? namespace : this.namespace;
|
|
@@ -90,6 +144,7 @@ class Node {
|
|
|
90
144
|
}
|
|
91
145
|
return result;
|
|
92
146
|
}
|
|
147
|
+
/** @returns a readable representation of the node, for debugging and error messages. */
|
|
93
148
|
toString() {
|
|
94
149
|
let s = "Node{";
|
|
95
150
|
s += `line=${this.line}`;
|
|
@@ -111,6 +166,6 @@ class Node {
|
|
|
111
166
|
}
|
|
112
167
|
}
|
|
113
168
|
exports.Node = Node;
|
|
114
|
-
// STXT-SPEC 4.2:
|
|
169
|
+
// STXT-SPEC 4.2: Unicode letters and digits (categories L and Nd) plus '-', '_' and space
|
|
115
170
|
Node.VALID_NAME = /^[\p{L}\p{Nd}\-_ ]+$/u;
|
|
116
171
|
//# sourceMappingURL=Node.js.map
|
|
@@ -1,3 +1,14 @@
|
|
|
1
1
|
import { Line } from "./Line";
|
|
2
2
|
import { Node } from "./Node";
|
|
3
|
+
/**
|
|
4
|
+
* Builds the node a line opens, telling apart the INLINE form (`Name: value`) from the BLOCK one
|
|
5
|
+
* (`Name >>`) and resolving the namespace against the parent.
|
|
6
|
+
*
|
|
7
|
+
* @param lineIndent line already split into indentation and content.
|
|
8
|
+
* @param lineNumber line number of the document where the node opens.
|
|
9
|
+
* @param level indentation level of the node.
|
|
10
|
+
* @param parent node currently open, whose namespace is inherited, or null at root level.
|
|
11
|
+
* @returns the node the line opens, still with no children and no text lines.
|
|
12
|
+
* @throws ParseException if the line is not a valid node declaration.
|
|
13
|
+
*/
|
|
3
14
|
export declare function createNode(lineIndent: Line, lineNumber: number, level: number, parent: Node | null): Node;
|
package/out/core/NodeCreator.js
CHANGED
|
@@ -5,6 +5,17 @@ const NameNamespaceParser_1 = require("./NameNamespaceParser");
|
|
|
5
5
|
const Node_1 = require("./Node");
|
|
6
6
|
const ParseException_1 = require("../exceptions/ParseException");
|
|
7
7
|
const Constants_1 = require("./Constants");
|
|
8
|
+
/**
|
|
9
|
+
* Builds the node a line opens, telling apart the INLINE form (`Name: value`) from the BLOCK one
|
|
10
|
+
* (`Name >>`) and resolving the namespace against the parent.
|
|
11
|
+
*
|
|
12
|
+
* @param lineIndent line already split into indentation and content.
|
|
13
|
+
* @param lineNumber line number of the document where the node opens.
|
|
14
|
+
* @param level indentation level of the node.
|
|
15
|
+
* @param parent node currently open, whose namespace is inherited, or null at root level.
|
|
16
|
+
* @returns the node the line opens, still with no children and no text lines.
|
|
17
|
+
* @throws ParseException if the line is not a valid node declaration.
|
|
18
|
+
*/
|
|
8
19
|
function createNode(lineIndent, lineNumber, level, parent) {
|
|
9
20
|
const line = lineIndent.content;
|
|
10
21
|
let name;
|
|
@@ -38,15 +49,15 @@ function createNode(lineIndent, lineNumber, level, parent) {
|
|
|
38
49
|
if (textNode && value.trim().length > 0) {
|
|
39
50
|
throw new ParseException_1.ParseException(lineNumber, "INLINE_VALUE_NOT_VALID", `Line not valid: ${line}`);
|
|
40
51
|
}
|
|
41
|
-
//
|
|
52
|
+
// Default namespace: inherited from the parent
|
|
42
53
|
const nameNamespace = NameNamespaceParser_1.NameNamespaceParser.parse(name, parent ? parent.getNamespace() : null, lineNumber, line);
|
|
43
54
|
name = nameNamespace.getName();
|
|
44
55
|
const namespace = nameNamespace.getNamespace();
|
|
45
|
-
//
|
|
56
|
+
// Validate the name
|
|
46
57
|
if (name.length === 0) {
|
|
47
58
|
throw new ParseException_1.ParseException(lineNumber, "INVALID_LINE", `Line not valid: ${line}`);
|
|
48
59
|
}
|
|
49
|
-
//
|
|
60
|
+
// Create the node
|
|
50
61
|
return new Node_1.Node(lineNumber, level, name, namespace, textNode, value);
|
|
51
62
|
}
|
|
52
63
|
//# sourceMappingURL=NodeCreator.js.map
|
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
import { Node } from "./Node";
|
|
2
2
|
import { ParseException } from "../exceptions/ParseException";
|
|
3
|
+
/**
|
|
4
|
+
* Result of a parse in multi-error mode: it collects the root nodes obtained and every error
|
|
5
|
+
* found (both syntax and validation ones), without bailing out on the first one.
|
|
6
|
+
*
|
|
7
|
+
* See {@link Parser.parseResult}. For the traditional fail-fast mode use {@link Parser.parse},
|
|
8
|
+
* which internally uses this result and throws the first error.
|
|
9
|
+
*/
|
|
3
10
|
export declare class ParseResult {
|
|
4
11
|
private readonly nodes;
|
|
5
12
|
private readonly errors;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a result, empty by default.
|
|
15
|
+
*
|
|
16
|
+
* @param nodes root nodes to start from.
|
|
17
|
+
* @param errors errors to start from.
|
|
18
|
+
*/
|
|
6
19
|
constructor(nodes?: Node[], errors?: ParseException[]);
|
|
20
|
+
/** @returns the root nodes collected so far. */
|
|
7
21
|
getNodes(): Node[];
|
|
22
|
+
/** @returns the syntax or validation errors collected so far, in order of appearance. */
|
|
8
23
|
getErrors(): ParseException[];
|
|
24
|
+
/** @returns true if at least one error has been collected. */
|
|
9
25
|
hasErrors(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Adds an error found while parsing.
|
|
28
|
+
*
|
|
29
|
+
* @param error error found while parsing, without aborting the traversal.
|
|
30
|
+
*/
|
|
10
31
|
addError(error: ParseException): void;
|
|
32
|
+
/**
|
|
33
|
+
* Adds a root node to the result.
|
|
34
|
+
*
|
|
35
|
+
* @param node already closed root node to add to the result.
|
|
36
|
+
*/
|
|
11
37
|
addNode(node: Node): void;
|
|
12
38
|
}
|
package/out/core/ParseResult.js
CHANGED
|
@@ -1,23 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ParseResult = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Result of a parse in multi-error mode: it collects the root nodes obtained and every error
|
|
6
|
+
* found (both syntax and validation ones), without bailing out on the first one.
|
|
7
|
+
*
|
|
8
|
+
* See {@link Parser.parseResult}. For the traditional fail-fast mode use {@link Parser.parse},
|
|
9
|
+
* which internally uses this result and throws the first error.
|
|
10
|
+
*/
|
|
4
11
|
class ParseResult {
|
|
12
|
+
/**
|
|
13
|
+
* Creates a result, empty by default.
|
|
14
|
+
*
|
|
15
|
+
* @param nodes root nodes to start from.
|
|
16
|
+
* @param errors errors to start from.
|
|
17
|
+
*/
|
|
5
18
|
constructor(nodes = [], errors = []) {
|
|
6
19
|
this.nodes = nodes;
|
|
7
20
|
this.errors = errors;
|
|
8
21
|
}
|
|
22
|
+
/** @returns the root nodes collected so far. */
|
|
9
23
|
getNodes() {
|
|
10
24
|
return this.nodes;
|
|
11
25
|
}
|
|
26
|
+
/** @returns the syntax or validation errors collected so far, in order of appearance. */
|
|
12
27
|
getErrors() {
|
|
13
28
|
return this.errors;
|
|
14
29
|
}
|
|
30
|
+
/** @returns true if at least one error has been collected. */
|
|
15
31
|
hasErrors() {
|
|
16
32
|
return this.errors.length > 0;
|
|
17
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Adds an error found while parsing.
|
|
36
|
+
*
|
|
37
|
+
* @param error error found while parsing, without aborting the traversal.
|
|
38
|
+
*/
|
|
18
39
|
addError(error) {
|
|
19
40
|
this.errors.push(error);
|
|
20
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Adds a root node to the result.
|
|
44
|
+
*
|
|
45
|
+
* @param node already closed root node to add to the result.
|
|
46
|
+
*/
|
|
21
47
|
addNode(node) {
|
|
22
48
|
this.nodes.push(node);
|
|
23
49
|
}
|
package/out/core/Parser.d.ts
CHANGED
|
@@ -2,12 +2,43 @@ import { Node } from "./Node";
|
|
|
2
2
|
import { Observer } from "../processors/Observer";
|
|
3
3
|
import { Validator } from "../processors/Validator";
|
|
4
4
|
import { ParseResult } from "./ParseResult";
|
|
5
|
+
/**
|
|
6
|
+
* Line-by-line STXT parsing engine. It knows nothing about schemas: semantic validation is
|
|
7
|
+
* plugged in through {@link Parser.registerValidator} and {@link Parser.registerObserver}.
|
|
8
|
+
* See {@link UnifiedSchemaProvider} for the usual way of building the validators to register.
|
|
9
|
+
*/
|
|
5
10
|
export declare class Parser {
|
|
6
11
|
private observers;
|
|
7
12
|
private validators;
|
|
13
|
+
/**
|
|
14
|
+
* Registers an observer, notified when each node is opened and closed.
|
|
15
|
+
*
|
|
16
|
+
* @param observer the {@link Observer} to register, notified while parsing.
|
|
17
|
+
*/
|
|
8
18
|
registerObserver(observer: Observer): void;
|
|
19
|
+
/**
|
|
20
|
+
* Registers a validator, invoked when each node is closed.
|
|
21
|
+
*
|
|
22
|
+
* @param validator the {@link Validator} to register, invoked when each node is closed during parsing.
|
|
23
|
+
*/
|
|
9
24
|
registerValidator(validator: Validator): void;
|
|
25
|
+
/**
|
|
26
|
+
* Traditional fail-fast mode: throws the first error found (either syntax or validation).
|
|
27
|
+
* Internally it reuses the same traversal as {@link Parser.parseResult}, and throws the first
|
|
28
|
+
* error it collected.
|
|
29
|
+
*
|
|
30
|
+
* @param content the whole STXT document to parse.
|
|
31
|
+
* @returns the root nodes of the document.
|
|
32
|
+
* @throws ParseException the first error found, be it syntax or validation.
|
|
33
|
+
*/
|
|
10
34
|
parse(content: string): Node[];
|
|
35
|
+
/**
|
|
36
|
+
* Multi-error mode: parses the whole content collecting every error found (both syntax and
|
|
37
|
+
* validation) without bailing out on the first one. See {@link ParseResult}.
|
|
38
|
+
*
|
|
39
|
+
* @param content the whole STXT document to parse.
|
|
40
|
+
* @returns the collected result, with the root nodes obtained and every error found.
|
|
41
|
+
*/
|
|
11
42
|
parseResult(content: string): ParseResult;
|
|
12
43
|
private processLine;
|
|
13
44
|
private handleError;
|
package/out/core/Parser.js
CHANGED
|
@@ -5,17 +5,41 @@ const LineParser_1 = require("./LineParser");
|
|
|
5
5
|
const NodeCreator_1 = require("./NodeCreator");
|
|
6
6
|
const ParseResult_1 = require("./ParseResult");
|
|
7
7
|
const ParseException_1 = require("../exceptions/ParseException");
|
|
8
|
+
/**
|
|
9
|
+
* Line-by-line STXT parsing engine. It knows nothing about schemas: semantic validation is
|
|
10
|
+
* plugged in through {@link Parser.registerValidator} and {@link Parser.registerObserver}.
|
|
11
|
+
* See {@link UnifiedSchemaProvider} for the usual way of building the validators to register.
|
|
12
|
+
*/
|
|
8
13
|
class Parser {
|
|
9
14
|
constructor() {
|
|
10
15
|
this.observers = [];
|
|
11
16
|
this.validators = [];
|
|
12
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Registers an observer, notified when each node is opened and closed.
|
|
20
|
+
*
|
|
21
|
+
* @param observer the {@link Observer} to register, notified while parsing.
|
|
22
|
+
*/
|
|
13
23
|
registerObserver(observer) {
|
|
14
24
|
this.observers.push(observer);
|
|
15
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Registers a validator, invoked when each node is closed.
|
|
28
|
+
*
|
|
29
|
+
* @param validator the {@link Validator} to register, invoked when each node is closed during parsing.
|
|
30
|
+
*/
|
|
16
31
|
registerValidator(validator) {
|
|
17
32
|
this.validators.push(validator);
|
|
18
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Traditional fail-fast mode: throws the first error found (either syntax or validation).
|
|
36
|
+
* Internally it reuses the same traversal as {@link Parser.parseResult}, and throws the first
|
|
37
|
+
* error it collected.
|
|
38
|
+
*
|
|
39
|
+
* @param content the whole STXT document to parse.
|
|
40
|
+
* @returns the root nodes of the document.
|
|
41
|
+
* @throws ParseException the first error found, be it syntax or validation.
|
|
42
|
+
*/
|
|
19
43
|
parse(content) {
|
|
20
44
|
const result = this.parseResult(content);
|
|
21
45
|
if (result.hasErrors()) {
|
|
@@ -24,6 +48,13 @@ class Parser {
|
|
|
24
48
|
}
|
|
25
49
|
return result.getNodes();
|
|
26
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Multi-error mode: parses the whole content collecting every error found (both syntax and
|
|
53
|
+
* validation) without bailing out on the first one. See {@link ParseResult}.
|
|
54
|
+
*
|
|
55
|
+
* @param content the whole STXT document to parse.
|
|
56
|
+
* @returns the collected result, with the root nodes obtained and every error found.
|
|
57
|
+
*/
|
|
27
58
|
parseResult(content) {
|
|
28
59
|
content = this.removeUTF8BOM(content);
|
|
29
60
|
const result = new ParseResult_1.ParseResult();
|
|
@@ -31,8 +62,8 @@ class Parser {
|
|
|
31
62
|
const documents = [];
|
|
32
63
|
let lineNumber = 0;
|
|
33
64
|
const lines = content.split(/\r?\n/);
|
|
34
|
-
//
|
|
35
|
-
//
|
|
65
|
+
// The final line break terminates the last line, it is not an extra empty line
|
|
66
|
+
// (this avoids adding a spurious line to a >> block at EOF, spec 10.3)
|
|
36
67
|
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
37
68
|
lines.pop();
|
|
38
69
|
}
|
|
@@ -40,13 +71,13 @@ class Parser {
|
|
|
40
71
|
lineNumber++;
|
|
41
72
|
this.processLine(line, lineNumber, stack, documents, result);
|
|
42
73
|
}
|
|
43
|
-
//
|
|
74
|
+
// Close every node still open at EOF
|
|
44
75
|
this.closeToLevel(stack, documents, 0, result);
|
|
45
|
-
//
|
|
76
|
+
// Add the nodes to the result
|
|
46
77
|
for (const doc of documents) {
|
|
47
78
|
result.addNode(doc);
|
|
48
79
|
}
|
|
49
|
-
//
|
|
80
|
+
// Return the result
|
|
50
81
|
return result;
|
|
51
82
|
}
|
|
52
83
|
processLine(lineString, lineNumber, stack, documents, result) {
|
|
@@ -54,40 +85,40 @@ class Parser {
|
|
|
54
85
|
const lastNode = stack.length === 0 ? null : stack[stack.length - 1];
|
|
55
86
|
const lastLevel = lastNode ? lastNode.getLevel() : 0;
|
|
56
87
|
const lastNodeText = lastNode ? lastNode.isTextNode() : false;
|
|
57
|
-
//
|
|
88
|
+
// Parse the line
|
|
58
89
|
const line = (0, LineParser_1.parseLine)(lineString, lastNodeText, lastLevel, lineNumber);
|
|
59
90
|
if (line.isComment) {
|
|
60
|
-
//
|
|
91
|
+
// Hand it over to the observers
|
|
61
92
|
this.observers.forEach(observer => {
|
|
62
93
|
observer.onComment(lineNumber, lineString);
|
|
63
94
|
});
|
|
64
95
|
return;
|
|
65
96
|
}
|
|
66
97
|
const currentLevel = line.level;
|
|
67
|
-
//
|
|
68
|
-
//
|
|
98
|
+
// When we are inside a text node and the level says it is still text,
|
|
99
|
+
// append the text line instead of creating a node.
|
|
69
100
|
if (line.isBlock) {
|
|
70
101
|
lastNode.addTextLine(line.content);
|
|
71
|
-
//
|
|
102
|
+
// Notify the observers about the text line
|
|
72
103
|
this.observers.forEach(observer => {
|
|
73
104
|
observer.onTextLine(lastNode, lineNumber, lineString, line);
|
|
74
105
|
});
|
|
75
106
|
return;
|
|
76
107
|
}
|
|
77
|
-
//
|
|
108
|
+
// Empty lines are ignored
|
|
78
109
|
if (line.isEmpty()) {
|
|
79
110
|
return;
|
|
80
111
|
}
|
|
81
|
-
//
|
|
112
|
+
// Close the nodes down to the current level (this "finishes" them and attaches them to the parent/documents)
|
|
82
113
|
this.closeToLevel(stack, documents, currentLevel, result);
|
|
83
|
-
//
|
|
114
|
+
// Create the new node and leave it "open" on the stack (do NOT attach it yet)
|
|
84
115
|
const parent = stack.length === 0 ? null : stack[stack.length - 1];
|
|
85
116
|
const node = (0, NodeCreator_1.createNode)(line, lineNumber, currentLevel, parent);
|
|
86
|
-
//
|
|
117
|
+
// Hand it over to the observers
|
|
87
118
|
this.observers.forEach(observer => {
|
|
88
119
|
observer.onCreate(node, lineString);
|
|
89
120
|
});
|
|
90
|
-
//
|
|
121
|
+
// Push it onto the stack
|
|
91
122
|
stack.push(node);
|
|
92
123
|
}
|
|
93
124
|
catch (e) {
|
|
@@ -99,18 +130,18 @@ class Parser {
|
|
|
99
130
|
result.addError(e);
|
|
100
131
|
}
|
|
101
132
|
else if (e instanceof Error) {
|
|
102
|
-
//
|
|
133
|
+
// Turn generic errors into a ParseException
|
|
103
134
|
result.addError(new ParseException_1.ParseException(line, errorCode, e.message));
|
|
104
135
|
}
|
|
105
136
|
else {
|
|
106
|
-
//
|
|
137
|
+
// Unknown error
|
|
107
138
|
result.addError(new ParseException_1.ParseException(line, unknownErrorCode, String(e)));
|
|
108
139
|
}
|
|
109
140
|
}
|
|
110
141
|
closeToLevel(stack, documents, targetLevel, result) {
|
|
111
142
|
while (stack.length > targetLevel) {
|
|
112
143
|
const completed = stack.pop();
|
|
113
|
-
//
|
|
144
|
+
// Hand it over to the validators
|
|
114
145
|
this.validators.forEach(validator => {
|
|
115
146
|
try {
|
|
116
147
|
const errors = validator.validate(completed);
|
|
@@ -128,7 +159,7 @@ class Parser {
|
|
|
128
159
|
else {
|
|
129
160
|
stack[stack.length - 1].addChild(completed);
|
|
130
161
|
}
|
|
131
|
-
//
|
|
162
|
+
// Hand it over to the observers
|
|
132
163
|
this.observers.forEach(observer => {
|
|
133
164
|
observer.onFinish(completed);
|
|
134
165
|
});
|
|
@@ -1,8 +1,39 @@
|
|
|
1
|
+
/** String normalization helpers used for names, namespaces and values. */
|
|
1
2
|
export declare class StringUtils {
|
|
2
3
|
private constructor();
|
|
4
|
+
/**
|
|
5
|
+
* Removes the trailing whitespace of a string.
|
|
6
|
+
*
|
|
7
|
+
* @param s string to strip the trailing spaces from.
|
|
8
|
+
* @returns the string without trailing whitespace; null/undefined is treated as the empty string.
|
|
9
|
+
*/
|
|
3
10
|
static rightTrim(s: string | null | undefined): string;
|
|
11
|
+
/**
|
|
12
|
+
* Removes every whitespace character of a string.
|
|
13
|
+
*
|
|
14
|
+
* @param input string to remove the spaces from.
|
|
15
|
+
* @returns the string without any whitespace at all.
|
|
16
|
+
*/
|
|
4
17
|
static cleanSpaces(input: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Lower-cases a string.
|
|
20
|
+
*
|
|
21
|
+
* @param input string to lower-case.
|
|
22
|
+
* @returns the lower-cased string; null/undefined is treated as the empty string.
|
|
23
|
+
*/
|
|
5
24
|
static lowerCase(input: string | null | undefined): string;
|
|
25
|
+
/**
|
|
26
|
+
* Trims a string and collapses its inner whitespace.
|
|
27
|
+
*
|
|
28
|
+
* @param s string to compact.
|
|
29
|
+
* @returns the string with the outer spaces trimmed and the inner ones collapsed into a single one; null/undefined is treated as the empty string.
|
|
30
|
+
*/
|
|
6
31
|
static compactSpaces(s: string | null | undefined): string;
|
|
32
|
+
/**
|
|
33
|
+
* Builds the canonical name of a node, as defined by STXT-SPEC 4.3.
|
|
34
|
+
*
|
|
35
|
+
* @param input string to normalize.
|
|
36
|
+
* @returns the canonical name of a node: NFC + lower case, with separators collapsed into '-'; null/undefined is treated as the empty string.
|
|
37
|
+
*/
|
|
7
38
|
static normalize(input: string | null | undefined): string;
|
|
8
39
|
}
|