@stxt-lang/core 0.8.0 → 0.9.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/out/core/InlineNode.js +1 -1
- package/out/core/Line.d.ts +5 -2
- package/out/core/Line.js +3 -2
- package/out/core/LineParser.d.ts +4 -1
- package/out/core/LineParser.js +20 -4
- package/out/core/NameNamespaceParser.js +3 -2
- package/out/core/NodeCreator.js +2 -1
- package/out/core/Parser.js +2 -0
- package/out/core/StringUtils.d.ts +22 -5
- package/out/core/StringUtils.js +34 -15
- package/package.json +1 -1
package/out/core/InlineNode.js
CHANGED
|
@@ -37,7 +37,7 @@ class InlineNode extends Node_1.Node {
|
|
|
37
37
|
* @param value new value, or null/undefined for none. It is trimmed.
|
|
38
38
|
*/
|
|
39
39
|
setValue(value) {
|
|
40
|
-
this.value =
|
|
40
|
+
this.value = StringUtils_1.StringUtils.trim(value);
|
|
41
41
|
}
|
|
42
42
|
getText() {
|
|
43
43
|
return this.value;
|
package/out/core/Line.d.ts
CHANGED
|
@@ -8,7 +8,10 @@ export declare class Line {
|
|
|
8
8
|
readonly level: number;
|
|
9
9
|
/** Content of the line with the indentation already removed. */
|
|
10
10
|
readonly content: string;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* True if the line is a comment (`#`). Its indentation has already been validated like a
|
|
13
|
+
* node's (spec 9), but it produces no node and never moves the hierarchy.
|
|
14
|
+
*/
|
|
12
15
|
readonly isComment: boolean;
|
|
13
16
|
/** True if the line is a text line belonging to an open BLOCK node (`>>`). */
|
|
14
17
|
readonly isBlock: boolean;
|
|
@@ -24,6 +27,6 @@ export declare class Line {
|
|
|
24
27
|
* @param indentLength number of characters the indentation took up.
|
|
25
28
|
*/
|
|
26
29
|
constructor(level: number, content: string, isComment: boolean, isBlock: boolean, indentLength: number);
|
|
27
|
-
/** @returns true if the line has no content beyond
|
|
30
|
+
/** @returns true if the line has no content beyond blanks (space/tab only, spec 4). */
|
|
28
31
|
isEmpty(): boolean;
|
|
29
32
|
}
|
package/out/core/Line.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Line = void 0;
|
|
4
|
+
const StringUtils_1 = require("./StringUtils");
|
|
4
5
|
/**
|
|
5
6
|
* A source line already split into its indentation and its content, as produced by
|
|
6
7
|
* {@link parseLine}. It is what tells the {@link Parser} whether the line opens a node, continues
|
|
@@ -23,9 +24,9 @@ class Line {
|
|
|
23
24
|
this.isBlock = isBlock;
|
|
24
25
|
this.indentLength = indentLength;
|
|
25
26
|
}
|
|
26
|
-
/** @returns true if the line has no content beyond
|
|
27
|
+
/** @returns true if the line has no content beyond blanks (space/tab only, spec 4). */
|
|
27
28
|
isEmpty() {
|
|
28
|
-
return
|
|
29
|
+
return StringUtils_1.StringUtils.trim(this.content) === "";
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
exports.Line = Line;
|
package/out/core/LineParser.d.ts
CHANGED
|
@@ -5,7 +5,10 @@ import { Line } from "./Line";
|
|
|
5
5
|
*
|
|
6
6
|
* Indentation is one level per tab or per {@link Constants.TAB_SPACES} spaces; mixing both, using
|
|
7
7
|
* a number of spaces that is not a multiple of four or going more than one level deeper than the
|
|
8
|
-
* previous node are errors (spec 8.1 and 8.3).
|
|
8
|
+
* previous node are errors (spec 8.1 and 8.3). Comment lines are validated exactly like node lines
|
|
9
|
+
* (spec 9 and 11): they produce no node and never move the hierarchy, but their indentation must
|
|
10
|
+
* be homogeneous, a multiple of four when spaces, and at most one level deeper than the last node.
|
|
11
|
+
* Only empty lines are exempt.
|
|
9
12
|
*
|
|
10
13
|
* @param line source line, with its indentation.
|
|
11
14
|
* @param lastNodeBlock true if the node currently open is a BLOCK text node.
|
package/out/core/LineParser.js
CHANGED
|
@@ -11,7 +11,10 @@ const Line_1 = require("./Line");
|
|
|
11
11
|
*
|
|
12
12
|
* Indentation is one level per tab or per {@link Constants.TAB_SPACES} spaces; mixing both, using
|
|
13
13
|
* a number of spaces that is not a multiple of four or going more than one level deeper than the
|
|
14
|
-
* previous node are errors (spec 8.1 and 8.3).
|
|
14
|
+
* previous node are errors (spec 8.1 and 8.3). Comment lines are validated exactly like node lines
|
|
15
|
+
* (spec 9 and 11): they produce no node and never move the hierarchy, but their indentation must
|
|
16
|
+
* be homogeneous, a multiple of four when spaces, and at most one level deeper than the last node.
|
|
17
|
+
* Only empty lines are exempt.
|
|
15
18
|
*
|
|
16
19
|
* @param line source line, with its indentation.
|
|
17
20
|
* @param lastNodeBlock true if the node currently open is a BLOCK text node.
|
|
@@ -28,6 +31,7 @@ function parseLine(line, lastNodeBlock, lastLevel, numLine, validate = true) {
|
|
|
28
31
|
let pointer = 0;
|
|
29
32
|
let sawSpace = false;
|
|
30
33
|
let sawTab = false;
|
|
34
|
+
let isComment = false;
|
|
31
35
|
while (pointer < line.length) {
|
|
32
36
|
const c = line.charAt(pointer);
|
|
33
37
|
if (c === Constants_1.Constants.SPACE) {
|
|
@@ -44,7 +48,13 @@ function parseLine(line, lastNodeBlock, lastLevel, numLine, validate = true) {
|
|
|
44
48
|
spaces = 0;
|
|
45
49
|
}
|
|
46
50
|
else if (c === Constants_1.Constants.COMMENT_CHAR) {
|
|
47
|
-
|
|
51
|
+
// Comment line: produces no node, but its indentation is validated below exactly like
|
|
52
|
+
// a node's (spec 9). Reached only when the line is not block text (a '#' deeper than an
|
|
53
|
+
// open block is caught as text by the check below, before getting here), so inside an
|
|
54
|
+
// open block a comment always has indent <= the block node: the Parser closes the block
|
|
55
|
+
// (spec 9.1) and hands the comment over to the observers.
|
|
56
|
+
isComment = true;
|
|
57
|
+
break;
|
|
48
58
|
}
|
|
49
59
|
else {
|
|
50
60
|
// First character that is not space/tab/comment => end of indentation
|
|
@@ -79,11 +89,17 @@ function parseLine(line, lastNodeBlock, lastLevel, numLine, validate = true) {
|
|
|
79
89
|
if (validate && spaces > 0) {
|
|
80
90
|
throw new ParseException_1.ParseException(numLine, "INVALID_NUMBER_SPACES", `There are ${spaces} spaces before node`);
|
|
81
91
|
}
|
|
82
|
-
// Validate the level
|
|
92
|
+
// Validate the level (spec 11.3). Comments included (spec 9): lastLevel is the level of the
|
|
93
|
+
// last NODE, a comment never becomes the reference.
|
|
83
94
|
if (validate && level > lastLevel + 1) {
|
|
84
95
|
throw new ParseException_1.ParseException(numLine, "INDENTATION_LEVEL_NOT_VALID", `Level of indent incorrect: ${level}`);
|
|
85
96
|
}
|
|
97
|
+
// Comment: the text after '#', verbatim
|
|
98
|
+
if (isComment) {
|
|
99
|
+
return new Line_1.Line(level, line.substring(pointer + 1), true, false, pointer);
|
|
100
|
+
}
|
|
86
101
|
// General case: return the line without the indentation already consumed
|
|
87
|
-
|
|
102
|
+
// Blank-only trim (spec 4): an NBSP after the value is part of it
|
|
103
|
+
return new Line_1.Line(level, StringUtils_1.StringUtils.trim(line.substring(pointer)), false, false, pointer);
|
|
88
104
|
}
|
|
89
105
|
//# sourceMappingURL=LineParser.js.map
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.NameNamespaceParser = void 0;
|
|
4
4
|
const ParseException_1 = require("../exceptions/ParseException");
|
|
5
5
|
const NameNamespace_1 = require("./NameNamespace");
|
|
6
|
+
const StringUtils_1 = require("./StringUtils");
|
|
6
7
|
/** Extracts the name and the namespace `(a.b.c)` from the left-hand side of an STXT line. */
|
|
7
8
|
class NameNamespaceParser {
|
|
8
9
|
constructor() {
|
|
@@ -21,7 +22,7 @@ class NameNamespaceParser {
|
|
|
21
22
|
if (rawName === null || rawName === undefined) {
|
|
22
23
|
throw new ParseException_1.ParseException(lineNumber, "INVALID_LINE", `Line not valid: ${fullLine}`);
|
|
23
24
|
}
|
|
24
|
-
rawName =
|
|
25
|
+
rawName = StringUtils_1.StringUtils.trim(rawName);
|
|
25
26
|
const startIndex = rawName.indexOf("(");
|
|
26
27
|
const endIndex = rawName.indexOf(")");
|
|
27
28
|
let name;
|
|
@@ -31,7 +32,7 @@ class NameNamespaceParser {
|
|
|
31
32
|
if (startIndex > endIndex || endIndex !== rawName.length - 1) {
|
|
32
33
|
throw new ParseException_1.ParseException(lineNumber, "INVALID_NAMESPACE", `Line not valid: ${fullLine}`);
|
|
33
34
|
}
|
|
34
|
-
name = rawName.substring(0, startIndex)
|
|
35
|
+
name = StringUtils_1.StringUtils.trim(rawName.substring(0, startIndex));
|
|
35
36
|
// No trim: the grammar (STXT-SPEC 7/16) does not allow spaces inside '( )'
|
|
36
37
|
namespace = rawName.substring(startIndex + 1, endIndex);
|
|
37
38
|
if (namespace.length === 0) {
|
package/out/core/NodeCreator.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createNode = createNode;
|
|
4
|
+
const StringUtils_1 = require("./StringUtils");
|
|
4
5
|
const NameNamespaceParser_1 = require("./NameNamespaceParser");
|
|
5
6
|
const InlineNode_1 = require("./InlineNode");
|
|
6
7
|
const TextNode_1 = require("./TextNode");
|
|
@@ -47,7 +48,7 @@ function createNode(lineIndent, lineNumber) {
|
|
|
47
48
|
name = line.substring(0, nodeIndex);
|
|
48
49
|
value = line.substring(nodeIndex + Constants_1.Constants.SEP_NODE.length);
|
|
49
50
|
}
|
|
50
|
-
if (textNode &&
|
|
51
|
+
if (textNode && StringUtils_1.StringUtils.trim(value).length > 0) {
|
|
51
52
|
throw new ParseException_1.ParseException(lineNumber, "INLINE_VALUE_NOT_VALID", `Line not valid: ${line}`);
|
|
52
53
|
}
|
|
53
54
|
// The namespace the line declares, if any (empty when it inherits)
|
package/out/core/Parser.js
CHANGED
|
@@ -90,6 +90,8 @@ class Parser {
|
|
|
90
90
|
// Parse the line
|
|
91
91
|
const line = (0, LineParser_1.parseLine)(lineString, lastNodeText, lastLevel, lineNumber);
|
|
92
92
|
if (line.isComment) {
|
|
93
|
+
// Its indentation was validated by parseLine like a node's (spec 9), but it never
|
|
94
|
+
// becomes the reference level: the stack (and so lastLevel) is only moved by nodes.
|
|
93
95
|
// A comment at the level of an open block node (or shallower) closes the block
|
|
94
96
|
// (spec 6.1 and 9.1): a block is a literal and cannot be commented from inside.
|
|
95
97
|
// Only the block closes; the comment does not touch the rest of the hierarchy.
|
|
@@ -2,12 +2,29 @@
|
|
|
2
2
|
export declare class StringUtils {
|
|
3
3
|
private static readonly NODE_NAME;
|
|
4
4
|
private static readonly NODE_NAME_LETTER_OR_DIGIT;
|
|
5
|
+
private static readonly LEADING_BLANKS;
|
|
6
|
+
private static readonly TRAILING_BLANKS;
|
|
7
|
+
private static readonly BLANK_RUN;
|
|
5
8
|
private constructor();
|
|
6
9
|
/**
|
|
7
|
-
*
|
|
10
|
+
* Tells whether a character is an STXT blank (STXT-SPEC 4): space or tab.
|
|
8
11
|
*
|
|
9
|
-
* @param
|
|
10
|
-
* @returns
|
|
12
|
+
* @param c single character.
|
|
13
|
+
* @returns true for U+0020 and U+0009 only.
|
|
14
|
+
*/
|
|
15
|
+
static isBlank(c: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Removes the leading and trailing blanks (space and tab only, STXT-SPEC 4) of a string.
|
|
18
|
+
*
|
|
19
|
+
* @param s string to trim.
|
|
20
|
+
* @returns the trimmed string; null/undefined is treated as the empty string.
|
|
21
|
+
*/
|
|
22
|
+
static trim(s: string | null | undefined): string;
|
|
23
|
+
/**
|
|
24
|
+
* Removes the trailing blanks (space and tab only, STXT-SPEC 4, 10.2) of a string.
|
|
25
|
+
*
|
|
26
|
+
* @param s string to strip the trailing blanks from.
|
|
27
|
+
* @returns the string without trailing blanks; null/undefined is treated as the empty string.
|
|
11
28
|
*/
|
|
12
29
|
static rightTrim(s: string | null | undefined): string;
|
|
13
30
|
/**
|
|
@@ -25,10 +42,10 @@ export declare class StringUtils {
|
|
|
25
42
|
*/
|
|
26
43
|
static lowerCase(input: string | null | undefined): string;
|
|
27
44
|
/**
|
|
28
|
-
* Trims a string and collapses its inner
|
|
45
|
+
* Trims a string and collapses its inner runs of blanks (space and tab only).
|
|
29
46
|
*
|
|
30
47
|
* @param s string to compact.
|
|
31
|
-
* @returns the string with the outer
|
|
48
|
+
* @returns the string with the outer blanks trimmed and the inner runs collapsed into a single space; null/undefined is treated as the empty string.
|
|
32
49
|
*/
|
|
33
50
|
static compactSpaces(s: string | null | undefined): string;
|
|
34
51
|
/**
|
package/out/core/StringUtils.js
CHANGED
|
@@ -5,20 +5,33 @@ exports.StringUtils = void 0;
|
|
|
5
5
|
class StringUtils {
|
|
6
6
|
constructor() {
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Tells whether a character is an STXT blank (STXT-SPEC 4): space or tab.
|
|
10
|
+
*
|
|
11
|
+
* @param c single character.
|
|
12
|
+
* @returns true for U+0020 and U+0009 only.
|
|
13
|
+
*/
|
|
14
|
+
static isBlank(c) {
|
|
15
|
+
return c === " " || c === "\t";
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Removes the leading and trailing blanks (space and tab only, STXT-SPEC 4) of a string.
|
|
19
|
+
*
|
|
20
|
+
* @param s string to trim.
|
|
21
|
+
* @returns the trimmed string; null/undefined is treated as the empty string.
|
|
22
|
+
*/
|
|
23
|
+
static trim(s) {
|
|
24
|
+
return (s ?? "").replace(this.LEADING_BLANKS, "").replace(this.TRAILING_BLANKS, "");
|
|
25
|
+
}
|
|
8
26
|
// Used for name>> nodes
|
|
9
27
|
/**
|
|
10
|
-
* Removes the trailing
|
|
28
|
+
* Removes the trailing blanks (space and tab only, STXT-SPEC 4, 10.2) of a string.
|
|
11
29
|
*
|
|
12
|
-
* @param s string to strip the trailing
|
|
13
|
-
* @returns the string without trailing
|
|
30
|
+
* @param s string to strip the trailing blanks from.
|
|
31
|
+
* @returns the string without trailing blanks; null/undefined is treated as the empty string.
|
|
14
32
|
*/
|
|
15
33
|
static rightTrim(s) {
|
|
16
|
-
|
|
17
|
-
let i = value.length - 1;
|
|
18
|
-
while (i >= 0 && /\s/.test(value.charAt(i))) {
|
|
19
|
-
i--;
|
|
20
|
-
}
|
|
21
|
-
return value.substring(0, i + 1);
|
|
34
|
+
return (s ?? "").replace(this.TRAILING_BLANKS, "");
|
|
22
35
|
}
|
|
23
36
|
// Used for BASE64 and HEXADECIMAL nodes
|
|
24
37
|
/**
|
|
@@ -43,13 +56,13 @@ class StringUtils {
|
|
|
43
56
|
}
|
|
44
57
|
// Used for the name of the nodes
|
|
45
58
|
/**
|
|
46
|
-
* Trims a string and collapses its inner
|
|
59
|
+
* Trims a string and collapses its inner runs of blanks (space and tab only).
|
|
47
60
|
*
|
|
48
61
|
* @param s string to compact.
|
|
49
|
-
* @returns the string with the outer
|
|
62
|
+
* @returns the string with the outer blanks trimmed and the inner runs collapsed into a single space; null/undefined is treated as the empty string.
|
|
50
63
|
*/
|
|
51
64
|
static compactSpaces(s) {
|
|
52
|
-
return
|
|
65
|
+
return this.trim(s).replace(this.BLANK_RUN, " ");
|
|
53
66
|
}
|
|
54
67
|
/**
|
|
55
68
|
* Tells whether a value is a valid STXT node name.
|
|
@@ -73,14 +86,14 @@ class StringUtils {
|
|
|
73
86
|
* @returns the canonical name of a node: NFC + lower case, with separators collapsed into '-'; null/undefined is treated as the empty string.
|
|
74
87
|
*/
|
|
75
88
|
static normalize(input) {
|
|
76
|
-
let s =
|
|
89
|
+
let s = this.trim(input);
|
|
77
90
|
if (s.length === 0) {
|
|
78
91
|
return "";
|
|
79
92
|
}
|
|
80
93
|
s = s.normalize("NFC");
|
|
81
94
|
s = s.toLowerCase();
|
|
82
|
-
// every run of separators ('-', '_',
|
|
83
|
-
s = s.replace(/[-_\
|
|
95
|
+
// every run of separators ('-', '_', blanks) => a single '-'
|
|
96
|
+
s = s.replace(/[-_ \t]+/g, "-");
|
|
84
97
|
// trim the '-'
|
|
85
98
|
s = s.replace(/^-+|-+$/g, "");
|
|
86
99
|
return s;
|
|
@@ -92,4 +105,10 @@ exports.StringUtils = StringUtils;
|
|
|
92
105
|
// decomposed spelling such as "e" + combining acute is accepted as "é".
|
|
93
106
|
StringUtils.NODE_NAME = /^[\p{L}\p{Nd}\p{Mn}\p{Mc}\-_ ]+$/u;
|
|
94
107
|
StringUtils.NODE_NAME_LETTER_OR_DIGIT = /[\p{L}\p{Nd}]/u;
|
|
108
|
+
// STXT-SPEC 4: a blank is exactly U+0020 or U+0009. Every trim in the core works on
|
|
109
|
+
// these two characters only; String.prototype.trim and /\s/ are deliberately avoided
|
|
110
|
+
// because they also remove NBSP, U+3000, U+2028... which STXT treats as content.
|
|
111
|
+
StringUtils.LEADING_BLANKS = /^[ \t]+/;
|
|
112
|
+
StringUtils.TRAILING_BLANKS = /[ \t]+$/;
|
|
113
|
+
StringUtils.BLANK_RUN = /[ \t]+/g;
|
|
95
114
|
//# sourceMappingURL=StringUtils.js.map
|