@stxt-lang/core 0.5.2 → 0.6.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.
Files changed (120) hide show
  1. package/README.md +116 -1
  2. package/out/all.d.ts +5 -0
  3. package/out/all.js +10 -4
  4. package/out/core/Constants.d.ts +8 -0
  5. package/out/core/Constants.js +8 -0
  6. package/out/core/Line.d.ts +20 -0
  7. package/out/core/Line.js +15 -0
  8. package/out/core/LineParser.d.ts +17 -0
  9. package/out/core/LineParser.js +27 -10
  10. package/out/core/NameNamespace.d.ts +9 -0
  11. package/out/core/NameNamespace.js +9 -0
  12. package/out/core/NameNamespaceParser.d.ts +11 -0
  13. package/out/core/NameNamespaceParser.js +16 -5
  14. package/out/core/NamespaceValidator.d.ts +18 -0
  15. package/out/core/NamespaceValidator.js +18 -0
  16. package/out/core/Node.d.ts +55 -0
  17. package/out/core/Node.js +56 -1
  18. package/out/core/NodeCreator.d.ts +11 -0
  19. package/out/core/NodeCreator.js +14 -3
  20. package/out/core/ParseResult.d.ts +26 -0
  21. package/out/core/ParseResult.js +26 -0
  22. package/out/core/Parser.d.ts +31 -0
  23. package/out/core/Parser.js +50 -19
  24. package/out/core/StringUtils.d.ts +31 -0
  25. package/out/core/StringUtils.js +40 -9
  26. package/out/discovery/DiscoveryEnvironment.d.ts +35 -0
  27. package/out/discovery/DiscoveryEnvironment.js +3 -0
  28. package/out/discovery/DiscoveryError.d.ts +30 -0
  29. package/out/discovery/DiscoveryError.js +36 -0
  30. package/out/discovery/DiscoveryFileSystem.d.ts +57 -0
  31. package/out/discovery/DiscoveryFileSystem.js +3 -0
  32. package/out/discovery/DiscoveryResolver.d.ts +74 -0
  33. package/out/discovery/DiscoveryResolver.js +232 -0
  34. package/out/discovery/DiscoveryResult.d.ts +94 -0
  35. package/out/discovery/DiscoveryResult.js +111 -0
  36. package/out/exceptions/ParseException.d.ts +14 -0
  37. package/out/exceptions/ParseException.js +12 -0
  38. package/out/exceptions/RuntimeException.d.ts +14 -0
  39. package/out/exceptions/RuntimeException.js +13 -0
  40. package/out/exceptions/ValidationException.d.ts +8 -0
  41. package/out/exceptions/ValidationException.js +8 -0
  42. package/out/processors/Observer.d.ts +29 -0
  43. package/out/processors/Validator.d.ts +9 -0
  44. package/out/runtime/ConditionalValidator.d.ts +15 -0
  45. package/out/runtime/ConditionalValidator.js +16 -2
  46. package/out/runtime/NodeWriter.d.ts +18 -0
  47. package/out/runtime/NodeWriter.js +18 -0
  48. package/out/runtime/UnifiedSchemaProvider.d.ts +23 -5
  49. package/out/runtime/UnifiedSchemaProvider.js +28 -10
  50. package/out/schema/ChildDefinition.d.ts +18 -0
  51. package/out/schema/ChildDefinition.js +18 -0
  52. package/out/schema/NodeDefinition.d.ts +44 -0
  53. package/out/schema/NodeDefinition.js +47 -3
  54. package/out/schema/Schema.d.ts +26 -0
  55. package/out/schema/Schema.js +26 -1
  56. package/out/schema/SchemaParser.d.ts +7 -0
  57. package/out/schema/SchemaParser.js +26 -16
  58. package/out/schema/SchemaProvider.d.ts +7 -0
  59. package/out/schema/SchemaProviderMemory.d.ts +27 -0
  60. package/out/schema/SchemaProviderMemory.js +27 -0
  61. package/out/schema/SchemaProviderMeta.d.ts +16 -0
  62. package/out/schema/SchemaProviderMeta.js +16 -0
  63. package/out/schema/SchemaValidator.d.ts +20 -0
  64. package/out/schema/SchemaValidator.js +27 -7
  65. package/out/schema/Type.d.ts +9 -0
  66. package/out/schema/TypeRegistry.d.ts +13 -0
  67. package/out/schema/TypeRegistry.js +18 -5
  68. package/out/schema/type/BASE64.d.ts +1 -0
  69. package/out/schema/type/BASE64.js +5 -4
  70. package/out/schema/type/BINARY.d.ts +1 -0
  71. package/out/schema/type/BINARY.js +2 -1
  72. package/out/schema/type/BLOCK.d.ts +1 -0
  73. package/out/schema/type/BLOCK.js +2 -1
  74. package/out/schema/type/BOOLEAN.d.ts +1 -0
  75. package/out/schema/type/BOOLEAN.js +1 -0
  76. package/out/schema/type/DATE.d.ts +1 -0
  77. package/out/schema/type/DATE.js +1 -0
  78. package/out/schema/type/EMAIL.d.ts +1 -0
  79. package/out/schema/type/EMAIL.js +1 -0
  80. package/out/schema/type/ENUM.d.ts +1 -0
  81. package/out/schema/type/ENUM.js +2 -1
  82. package/out/schema/type/GROUP.d.ts +1 -0
  83. package/out/schema/type/GROUP.js +2 -1
  84. package/out/schema/type/HEXADECIMAL.d.ts +1 -0
  85. package/out/schema/type/HEXADECIMAL.js +2 -1
  86. package/out/schema/type/INLINE.d.ts +1 -0
  87. package/out/schema/type/INLINE.js +2 -1
  88. package/out/schema/type/INTEGER.d.ts +1 -0
  89. package/out/schema/type/INTEGER.js +1 -0
  90. package/out/schema/type/MARKDOWN.d.ts +4 -0
  91. package/out/schema/type/MARKDOWN.js +4 -2
  92. package/out/schema/type/NATURAL.d.ts +1 -0
  93. package/out/schema/type/NATURAL.js +1 -0
  94. package/out/schema/type/NUMBER.d.ts +1 -0
  95. package/out/schema/type/NUMBER.js +1 -0
  96. package/out/schema/type/TEXT.d.ts +1 -0
  97. package/out/schema/type/TEXT.js +1 -0
  98. package/out/schema/type/TIME.d.ts +1 -0
  99. package/out/schema/type/TIME.js +1 -0
  100. package/out/schema/type/TIMESTAMP.d.ts +1 -0
  101. package/out/schema/type/TIMESTAMP.js +1 -0
  102. package/out/schema/type/URL.d.ts +1 -0
  103. package/out/schema/type/URL.js +2 -1
  104. package/out/schema/type/UUID.d.ts +1 -0
  105. package/out/schema/type/UUID.js +1 -0
  106. package/out/schema/type/binaryValue.d.ts +9 -0
  107. package/out/schema/type/binaryValue.js +9 -3
  108. package/out/schema/type/regexType.d.ts +8 -0
  109. package/out/schema/type/regexType.js +9 -1
  110. package/out/template/ChildLine.d.ts +14 -0
  111. package/out/template/ChildLine.js +14 -0
  112. package/out/template/ChildLineParser.d.ts +10 -0
  113. package/out/template/ChildLineParser.js +17 -8
  114. package/out/template/MetaTemplateSchemaProvider.d.ts +16 -0
  115. package/out/template/MetaTemplateSchemaProvider.js +17 -1
  116. package/out/template/TemplateParser.d.ts +8 -0
  117. package/out/template/TemplateParser.js +49 -39
  118. package/out/template/TemplateSchemaProviderMemory.d.ts +18 -0
  119. package/out/template/TemplateSchemaProviderMemory.js +21 -3
  120. package/package.json +2 -1
package/README.md CHANGED
@@ -6,6 +6,7 @@ STXT is a plain-text format for writing structured, semantic documents: no brace
6
6
 
7
7
  - Website and language reference: <https://stxt.dev>
8
8
  - VSCode extension: [STXT - Semantic Text](https://marketplace.visualstudio.com/items?itemName=stxt-lang.stxt)
9
+ - Java implementation: [`dev.stxt:stxt-core`](https://central.sonatype.com/artifact/dev.stxt/stxt-core) on Maven Central
9
10
 
10
11
  ## What STXT looks like
11
12
 
@@ -114,6 +115,113 @@ for (const error of result.getErrors()) {
114
115
 
115
116
  Available value types: `INLINE`, `BLOCK`, `TEXT`, `BOOLEAN`, `INTEGER`, `NATURAL`, `NUMBER`, `DATE`, `TIMESTAMP`, `EMAIL`, `URL`, `HEXADECIMAL`, `BASE64`, `GROUP`, `ENUM`.
116
117
 
118
+ ## Finding the schemas: discovery
119
+
120
+ `UnifiedSchemaProvider` expects you to hand it the schema text. **Discovery** answers the previous question: *given this document, which schema definitions apply to it?* `DiscoveryResolver` is the reference implementation of the STXT discovery specification, so a command line, an editor and a build step all agree on the answer by construction.
121
+
122
+ Definitions live in `.stxt/` directories. For a given document the resolution chain is, highest precedence first:
123
+
124
+ 1. every ancestor `.stxt/` directory, nearest first — the ascent does **not** stop at the first one, so in a monorepo both the subproject's and the repo root's participate;
125
+ 2. the user level, `$HOME/.stxt` (`%USERPROFILE%\.stxt` on Windows);
126
+ 3. the system level, `/etc/stxt` (`%ProgramData%\stxt` on Windows).
127
+
128
+ Precedence is **per namespace**: the nearest level that defines a namespace wins, and the rest of the chain still contributes the namespaces that level does not define. Defining one namespace twice at the same level is a resolution error, and leaves that namespace without an active definition. When `STXT_PATH` is defined it replaces the whole chain — useful in CI and tests.
129
+
130
+ The resolver never touches the file system or the environment itself: you inject a `DiscoveryFileSystem` and a `DiscoveryEnvironment`. That is what lets the same logic run over Node's `fs`, over an editor's virtual file system (`vscode.workspace.fs`) or over an in-memory tree in a test. Here are the Node adapters:
131
+
132
+ ```ts
133
+ import * as fs from 'fs/promises';
134
+ import * as os from 'os';
135
+ import * as path from 'path';
136
+ import {
137
+ DiscoveryEntry,
138
+ DiscoveryEnvironment,
139
+ DiscoveryFileSystem,
140
+ DiscoveryResolver,
141
+ } from '@stxt-lang/core';
142
+
143
+ class NodeFileSystem implements DiscoveryFileSystem {
144
+ async isDirectory(p: string): Promise<boolean> {
145
+ try {
146
+ return (await fs.stat(p)).isDirectory();
147
+ } catch {
148
+ return false; // not existing is the normal case, not an error
149
+ }
150
+ }
151
+ async listDirectory(p: string): Promise<DiscoveryEntry[]> {
152
+ const entries = await fs.readdir(p, { withFileTypes: true });
153
+ return entries.map(entry => ({
154
+ path: path.join(p, entry.name),
155
+ name: entry.name,
156
+ isDirectory: entry.isDirectory(),
157
+ }));
158
+ }
159
+ readFile(p: string): Promise<string> {
160
+ return fs.readFile(p, 'utf-8');
161
+ }
162
+ parentOf(p: string): string | null {
163
+ const parent = path.dirname(p);
164
+ return parent === p ? null : parent; // null at the file-system root
165
+ }
166
+ join(p: string, name: string): string {
167
+ return path.join(p, name);
168
+ }
169
+ }
170
+
171
+ class NodeEnvironment implements DiscoveryEnvironment {
172
+ getStxtPath(): string[] | null {
173
+ const value = process.env.STXT_PATH;
174
+ // null (not defined) and [] (defined but empty) mean different things
175
+ return value === undefined ? null : value.split(path.delimiter).filter(e => e !== '');
176
+ }
177
+ getUserLevelDir(): string | null {
178
+ return path.join(os.homedir(), '.stxt');
179
+ }
180
+ getSystemLevelDir(): string | null {
181
+ return '/etc/stxt';
182
+ }
183
+ }
184
+ ```
185
+
186
+ With those in place, resolving a document and validating it is two steps — and note that `DiscoveryResult` implements `SchemaProvider`, so it goes straight into the validator:
187
+
188
+ ```ts
189
+ import { Parser, SchemaValidator, ConditionalValidator } from '@stxt-lang/core';
190
+
191
+ const resolver = new DiscoveryResolver(new NodeFileSystem(), new NodeEnvironment());
192
+
193
+ // The chain is per document: pass the directory the document lives in
194
+ // (null for stdin or an unsaved buffer, which starts the chain at the user level).
195
+ const result = await resolver.resolve('/repo/site/posts');
196
+
197
+ console.log(result.getChain());
198
+ // [ '/repo/site/.stxt', '/repo/.stxt' ] ← both ancestors, nearest first
199
+
200
+ // Resolution errors are collected, never thrown: report them and carry on
201
+ for (const error of result.getErrors()) {
202
+ console.error(`[${error.code}] ${error.message}`);
203
+ }
204
+
205
+ const parser = new Parser();
206
+ parser.registerValidator(new ConditionalValidator(new SchemaValidator(result)));
207
+
208
+ const parsed = parser.parseResult(documentText);
209
+ ```
210
+
211
+ `DiscoveryResult` also tells you *where* a schema came from, which is what an editor needs for "go to definition" or a diagnostic that explains itself:
212
+
213
+ ```ts
214
+ const definition = result.getDefinition('blog.post');
215
+
216
+ console.log(definition?.file); // '/repo/site/.stxt/blog.stxt'
217
+ console.log(definition?.levelDir); // '/repo/site/.stxt' ← the level that won
218
+
219
+ result.getActiveDefinitions(); // one entry per namespace, precedence applied
220
+ result.getAllSchemas(); // just the schemas of the above
221
+ ```
222
+
223
+ Levels are cached by directory, so resolving many documents that share ancestors reads each `.stxt/` once. Call `resolver.clearCache()` when the definition files may have changed — from a file watcher, for instance.
224
+
117
225
  ## Observing the parse
118
226
 
119
227
  `Observer` receives streaming callbacks while the document is parsed — useful for syntax highlighting, indexes or any per-line bookkeeping.
@@ -149,7 +257,14 @@ const doc = NodeWriter.toSTXTDocs(result.getNodes(), IndentStyle.SPACES_4);
149
257
 
150
258
  ## API surface
151
259
 
152
- Everything importable from the package: `Node`, `Parser`, `ParseResult`, `Line`, `Constants`, `parseLine`, `StringUtils`, `ParseException`, `ValidationException`, `Observer`, `Schema`, `SchemaValidator`, `SchemaProvider`, `NodeDefinition`, `ChildDefinition`, `transformNodeToSchema`, `UnifiedSchemaProvider`, `ConditionalValidator`, `NodeWriter`, `IndentStyle`, `transformTemplateNodeToSchema`.
260
+ Everything importable from the package:
261
+
262
+ - **Parsing** — `Node`, `Parser`, `ParseResult`, `Line`, `Constants`, `parseLine`, `StringUtils`
263
+ - **Exceptions** — `ParseException`, `ValidationException`
264
+ - **Extension points** — `Observer`
265
+ - **Schemas** — `Schema`, `SchemaValidator`, `SchemaProvider`, `NodeDefinition`, `ChildDefinition`, `transformNodeToSchema`, `transformTemplateNodeToSchema`
266
+ - **Runtime** — `UnifiedSchemaProvider`, `ConditionalValidator`, `NodeWriter`, `IndentStyle`
267
+ - **Discovery** — `DiscoveryResolver`, `DiscoveryOptions`, `DiscoveryResult`, `DiscoveryDefinition`, `DiscoveryLevel`, `DiscoveryError`, `DiscoveryFileSystem`, `DiscoveryEntry`, `DiscoveryEnvironment`
153
268
 
154
269
  ## License
155
270
 
package/out/all.d.ts CHANGED
@@ -18,3 +18,8 @@ export { UnifiedSchemaProvider } from "./runtime/UnifiedSchemaProvider";
18
18
  export { ConditionalValidator } from "./runtime/ConditionalValidator";
19
19
  export { NodeWriter, IndentStyle } from "./runtime/NodeWriter";
20
20
  export { transformTemplateNodeToSchema } from "./template/TemplateParser";
21
+ export { DiscoveryResolver, DiscoveryOptions } from "./discovery/DiscoveryResolver";
22
+ export { DiscoveryResult, DiscoveryDefinition, DiscoveryLevel } from "./discovery/DiscoveryResult";
23
+ export { DiscoveryError } from "./discovery/DiscoveryError";
24
+ export { DiscoveryFileSystem, DiscoveryEntry } from "./discovery/DiscoveryFileSystem";
25
+ export { DiscoveryEnvironment } from "./discovery/DiscoveryEnvironment";
package/out/all.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
- // Punto de entrada público del paquete (out/all.js / out/all.d.ts).
3
- // Todo lo que deba ser consumible por terceros (p. ej. la extensión VSCode)
4
- // debe re-exportarse desde aquí.
2
+ // Public entry point of the package (out/all.js / out/all.d.ts).
3
+ // Anything that should be consumable by third parties (e.g. the VSCode extension)
4
+ // has to be re-exported from here.
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.transformTemplateNodeToSchema = 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.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;
7
7
  var Node_1 = require("./core/Node");
8
8
  Object.defineProperty(exports, "Node", { enumerable: true, get: function () { return Node_1.Node; } });
9
9
  var Parser_1 = require("./core/Parser");
@@ -41,4 +41,10 @@ Object.defineProperty(exports, "NodeWriter", { enumerable: true, get: function (
41
41
  Object.defineProperty(exports, "IndentStyle", { enumerable: true, get: function () { return NodeWriter_1.IndentStyle; } });
42
42
  var TemplateParser_1 = require("./template/TemplateParser");
43
43
  Object.defineProperty(exports, "transformTemplateNodeToSchema", { enumerable: true, get: function () { return TemplateParser_1.transformTemplateNodeToSchema; } });
44
+ var DiscoveryResolver_1 = require("./discovery/DiscoveryResolver");
45
+ Object.defineProperty(exports, "DiscoveryResolver", { enumerable: true, get: function () { return DiscoveryResolver_1.DiscoveryResolver; } });
46
+ var DiscoveryResult_1 = require("./discovery/DiscoveryResult");
47
+ Object.defineProperty(exports, "DiscoveryResult", { enumerable: true, get: function () { return DiscoveryResult_1.DiscoveryResult; } });
48
+ var DiscoveryError_1 = require("./discovery/DiscoveryError");
49
+ Object.defineProperty(exports, "DiscoveryError", { enumerable: true, get: function () { return DiscoveryError_1.DiscoveryError; } });
44
50
  //# sourceMappingURL=all.js.map
@@ -1,9 +1,17 @@
1
+ /** Characters and sizes fixed by STXT-SPEC that the parser and the writer share. */
1
2
  export declare class Constants {
3
+ /** Character that opens a comment line. */
2
4
  static readonly COMMENT_CHAR: string;
5
+ /** Number of spaces that make up one indentation level. */
3
6
  static readonly TAB_SPACES: number;
7
+ /** Tab character, the other way of indenting one level. */
4
8
  static readonly TAB: string;
9
+ /** Space character. */
5
10
  static readonly SPACE: string;
11
+ /** Separator between the name and the value of an INLINE node. */
6
12
  static readonly SEP_NODE: string;
13
+ /** Marker that turns a node into a BLOCK text node. */
7
14
  static readonly SEP_TEXT_NODE: string;
15
+ /** Namespace of a node that declares none and inherits none. */
8
16
  static readonly EMPTY_NAMESPACE: string;
9
17
  }
@@ -1,14 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Constants = void 0;
4
+ /** Characters and sizes fixed by STXT-SPEC that the parser and the writer share. */
4
5
  class Constants {
5
6
  }
6
7
  exports.Constants = Constants;
8
+ /** Character that opens a comment line. */
7
9
  Constants.COMMENT_CHAR = "#";
10
+ /** Number of spaces that make up one indentation level. */
8
11
  Constants.TAB_SPACES = 4;
12
+ /** Tab character, the other way of indenting one level. */
9
13
  Constants.TAB = "\t";
14
+ /** Space character. */
10
15
  Constants.SPACE = " ";
16
+ /** Separator between the name and the value of an INLINE node. */
11
17
  Constants.SEP_NODE = ":";
18
+ /** Marker that turns a node into a BLOCK text node. */
12
19
  Constants.SEP_TEXT_NODE = ">>";
20
+ /** Namespace of a node that declares none and inherits none. */
13
21
  Constants.EMPTY_NAMESPACE = "";
14
22
  //# sourceMappingURL=Constants.js.map
@@ -1,9 +1,29 @@
1
+ /**
2
+ * A source line already split into its indentation and its content, as produced by
3
+ * {@link parseLine}. It is what tells the {@link Parser} whether the line opens a node, continues
4
+ * a text block or is just a comment.
5
+ */
1
6
  export declare class Line {
7
+ /** Indentation level of the line (one level per tab or per {@link Constants.TAB_SPACES} spaces). */
2
8
  readonly level: number;
9
+ /** Content of the line with the indentation already removed. */
3
10
  readonly content: string;
11
+ /** True if the line is a comment (`#`). */
4
12
  readonly isComment: boolean;
13
+ /** True if the line is a text line belonging to an open BLOCK node (`>>`). */
5
14
  readonly isBlock: boolean;
15
+ /** Number of characters the indentation took up. */
6
16
  readonly indentLength: number;
17
+ /**
18
+ * Creates a line already split into indentation and content.
19
+ *
20
+ * @param level indentation level of the line.
21
+ * @param content content of the line without its indentation.
22
+ * @param isComment true if the line is a comment.
23
+ * @param isBlock true if the line belongs to an open text block.
24
+ * @param indentLength number of characters the indentation took up.
25
+ */
7
26
  constructor(level: number, content: string, isComment: boolean, isBlock: boolean, indentLength: number);
27
+ /** @returns true if the line has no content beyond whitespace. */
8
28
  isEmpty(): boolean;
9
29
  }
package/out/core/Line.js CHANGED
@@ -1,7 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Line = void 0;
4
+ /**
5
+ * A source line already split into its indentation and its content, as produced by
6
+ * {@link parseLine}. It is what tells the {@link Parser} whether the line opens a node, continues
7
+ * a text block or is just a comment.
8
+ */
4
9
  class Line {
10
+ /**
11
+ * Creates a line already split into indentation and content.
12
+ *
13
+ * @param level indentation level of the line.
14
+ * @param content content of the line without its indentation.
15
+ * @param isComment true if the line is a comment.
16
+ * @param isBlock true if the line belongs to an open text block.
17
+ * @param indentLength number of characters the indentation took up.
18
+ */
5
19
  constructor(level, content, isComment, isBlock, indentLength) {
6
20
  this.level = level;
7
21
  this.content = content;
@@ -9,6 +23,7 @@ class Line {
9
23
  this.isBlock = isBlock;
10
24
  this.indentLength = indentLength;
11
25
  }
26
+ /** @returns true if the line has no content beyond whitespace. */
12
27
  isEmpty() {
13
28
  return this.content.trim() === "";
14
29
  }
@@ -1,2 +1,19 @@
1
1
  import { Line } from "./Line";
2
+ /**
3
+ * Splits a source line into its indentation and its content, and classifies it as a comment, a
4
+ * text line of an open block or a regular line.
5
+ *
6
+ * Indentation is one level per tab or per {@link Constants.TAB_SPACES} spaces; mixing both, using
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).
9
+ *
10
+ * @param line source line, with its indentation.
11
+ * @param lastNodeBlock true if the node currently open is a BLOCK text node.
12
+ * @param lastLevel indentation level of the node currently open.
13
+ * @param numLine line number, for the error messages.
14
+ * @param validate false to split the line without enforcing the indentation rules.
15
+ * @returns the line already split into indentation and content.
16
+ * @throws ParseException with code `MIXED_INDENTATION`, `INVALID_NUMBER_SPACES` or
17
+ * `INDENTATION_LEVEL_NOT_VALID` if the indentation is not valid.
18
+ */
2
19
  export declare function parseLine(line: string, lastNodeBlock: boolean, lastLevel: number, numLine: number, validate?: boolean): Line;
@@ -5,6 +5,23 @@ const Constants_1 = require("./Constants");
5
5
  const StringUtils_1 = require("./StringUtils");
6
6
  const ParseException_1 = require("../exceptions/ParseException");
7
7
  const Line_1 = require("./Line");
8
+ /**
9
+ * Splits a source line into its indentation and its content, and classifies it as a comment, a
10
+ * text line of an open block or a regular line.
11
+ *
12
+ * Indentation is one level per tab or per {@link Constants.TAB_SPACES} spaces; mixing both, using
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).
15
+ *
16
+ * @param line source line, with its indentation.
17
+ * @param lastNodeBlock true if the node currently open is a BLOCK text node.
18
+ * @param lastLevel indentation level of the node currently open.
19
+ * @param numLine line number, for the error messages.
20
+ * @param validate false to split the line without enforcing the indentation rules.
21
+ * @returns the line already split into indentation and content.
22
+ * @throws ParseException with code `MIXED_INDENTATION`, `INVALID_NUMBER_SPACES` or
23
+ * `INDENTATION_LEVEL_NOT_VALID` if the indentation is not valid.
24
+ */
8
25
  function parseLine(line, lastNodeBlock, lastLevel, numLine, validate = true) {
9
26
  let level = 0;
10
27
  let spaces = 0;
@@ -30,23 +47,23 @@ function parseLine(line, lastNodeBlock, lastLevel, numLine, validate = true) {
30
47
  return new Line_1.Line(level, line.substring(pointer + 1), true, false, pointer);
31
48
  }
32
49
  else {
33
- // Primer carácter no espacio/tab/comentario => fin de indentación
50
+ // First character that is not space/tab/comment => end of indentation
34
51
  break;
35
52
  }
36
- // Dentro del bloque de texto
53
+ // Inside the text block
37
54
  if (lastNodeBlock && level > lastLevel) {
38
55
  const text = StringUtils_1.StringUtils.rightTrim(line.substring(pointer + 1));
39
- // El prefijo que cubre el nivel de bloque debe ser homogéneo (spec 10.2, regla 2);
40
- // las líneas vacías se preservan siempre y quedan exentas (spec 10.3)
56
+ // The prefix covering the block level must be homogeneous (spec 10.2, rule 2);
57
+ // empty lines are always preserved and are exempt from it (spec 10.3)
41
58
  if (validate && sawSpace && sawTab && text.length > 0) {
42
59
  throw new ParseException_1.ParseException(numLine, "MIXED_INDENTATION", `Mixed tabs and spaces in indentation`);
43
60
  }
44
61
  return new Line_1.Line(level, text, false, true, pointer);
45
62
  }
46
- // Aumentamos pointer
63
+ // Move the pointer forward
47
64
  pointer++;
48
65
  }
49
- // En este punto ya estamos fuera de bloque de texto (si existía)
66
+ // From here on we are outside the text block (if there was one)
50
67
  // Empty
51
68
  if (pointer === line.length) {
52
69
  if (lastNodeBlock) {
@@ -54,19 +71,19 @@ function parseLine(line, lastNodeBlock, lastLevel, numLine, validate = true) {
54
71
  }
55
72
  return new Line_1.Line(level, "", false, false, pointer);
56
73
  }
57
- // Mezcla de espacios y tabuladores en la indentación (spec 8.1 y 8.3)
74
+ // Tabs and spaces mixed in the indentation (spec 8.1 and 8.3)
58
75
  if (validate && sawSpace && sawTab) {
59
76
  throw new ParseException_1.ParseException(numLine, "MIXED_INDENTATION", `Mixed tabs and spaces in indentation`);
60
77
  }
61
- // Indentación no es múltiplo de 4 con espacios
78
+ // Indentation with spaces that is not a multiple of 4
62
79
  if (validate && spaces > 0) {
63
80
  throw new ParseException_1.ParseException(numLine, "INVALID_NUMBER_SPACES", `There are ${spaces} spaces before node`);
64
81
  }
65
- // Validamos level
82
+ // Validate the level
66
83
  if (validate && level > lastLevel + 1) {
67
84
  throw new ParseException_1.ParseException(numLine, "INDENTATION_LEVEL_NOT_VALID", `Level of indent incorrect: ${level}`);
68
85
  }
69
- // Caso general: devolver la línea sin la indentación consumida
86
+ // General case: return the line without the indentation already consumed
70
87
  return new Line_1.Line(level, line.substring(pointer).trim(), false, false, pointer);
71
88
  }
72
89
  //# sourceMappingURL=LineParser.js.map
@@ -1,7 +1,16 @@
1
+ /** Result of splitting a raw node name into its resolved name and namespace. */
1
2
  export declare class NameNamespace {
2
3
  private readonly name;
3
4
  private readonly namespace;
5
+ /**
6
+ * Creates a resolved name and namespace pair.
7
+ *
8
+ * @param name name of the node without the namespace part.
9
+ * @param namespace resolved namespace (its own or inherited).
10
+ */
4
11
  constructor(name: string, namespace: string);
12
+ /** @returns the name of the node, without the namespace part. */
5
13
  getName(): string;
14
+ /** @returns the resolved namespace (its own or inherited from the parent), or the empty string if it has none. */
6
15
  getNamespace(): string;
7
16
  }
@@ -1,14 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NameNamespace = void 0;
4
+ /** Result of splitting a raw node name into its resolved name and namespace. */
4
5
  class NameNamespace {
6
+ /**
7
+ * Creates a resolved name and namespace pair.
8
+ *
9
+ * @param name name of the node without the namespace part.
10
+ * @param namespace resolved namespace (its own or inherited).
11
+ */
5
12
  constructor(name, namespace) {
6
13
  this.name = name;
7
14
  this.namespace = namespace;
8
15
  }
16
+ /** @returns the name of the node, without the namespace part. */
9
17
  getName() {
10
18
  return this.name;
11
19
  }
20
+ /** @returns the resolved namespace (its own or inherited from the parent), or the empty string if it has none. */
12
21
  getNamespace() {
13
22
  return this.namespace;
14
23
  }
@@ -1,5 +1,16 @@
1
1
  import { NameNamespace } from "./NameNamespace";
2
+ /** Extracts the name and the namespace `(a.b.c)` from the left-hand side of an STXT line. */
2
3
  export declare class NameNamespaceParser {
3
4
  private constructor();
5
+ /**
6
+ * Splits a raw node name into its name and its namespace.
7
+ *
8
+ * @param rawName raw name, with the namespace in parentheses if it carries one.
9
+ * @param inheritedNs namespace inherited from the parent, used when `rawName` brings none of its own.
10
+ * @param lineNumber line number, for the error messages.
11
+ * @param fullLine original full line, for the error messages.
12
+ * @returns the name and the namespace, already split apart and resolved.
13
+ * @throws ParseException if the name or the namespace are not well formed.
14
+ */
4
15
  static parse(rawName: string | null | undefined, inheritedNs: string | null | undefined, lineNumber: number, fullLine: string): NameNamespace;
5
16
  }
@@ -3,9 +3,20 @@ 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
+ /** Extracts the name and the namespace `(a.b.c)` from the left-hand side of an STXT line. */
6
7
  class NameNamespaceParser {
7
8
  constructor() {
8
9
  }
10
+ /**
11
+ * Splits a raw node name into its name and its namespace.
12
+ *
13
+ * @param rawName raw name, with the namespace in parentheses if it carries one.
14
+ * @param inheritedNs namespace inherited from the parent, used when `rawName` brings none of its own.
15
+ * @param lineNumber line number, for the error messages.
16
+ * @param fullLine original full line, for the error messages.
17
+ * @returns the name and the namespace, already split apart and resolved.
18
+ * @throws ParseException if the name or the namespace are not well formed.
19
+ */
9
20
  static parse(rawName, inheritedNs, lineNumber, fullLine) {
10
21
  if (rawName === null || rawName === undefined) {
11
22
  throw new ParseException_1.ParseException(lineNumber, "INVALID_LINE", `Line not valid: ${fullLine}`);
@@ -15,27 +26,27 @@ class NameNamespaceParser {
15
26
  const endIndex = rawName.indexOf(")");
16
27
  let name;
17
28
  let namespace = inheritedNs ?? "";
18
- // Encontrados los dos
29
+ // Both of them found
19
30
  if (startIndex !== -1 && endIndex !== -1) {
20
31
  if (startIndex > endIndex || endIndex !== rawName.length - 1) {
21
32
  throw new ParseException_1.ParseException(lineNumber, "INVALID_NAMESPACE", `Line not valid: ${fullLine}`);
22
33
  }
23
34
  name = rawName.substring(0, startIndex).trim();
24
- // Sin trim: la gramática (STXT-SPEC 7/16) no admite espacios dentro de '( )'
35
+ // No trim: the grammar (STXT-SPEC 7/16) does not allow spaces inside '( )'
25
36
  namespace = rawName.substring(startIndex + 1, endIndex);
26
37
  if (namespace.length === 0) {
27
38
  throw new ParseException_1.ParseException(lineNumber, "INVALID_NAMESPACE", `Line not valid: ${fullLine}`);
28
39
  }
29
40
  }
30
- // Ninguno de los dos
41
+ // Neither of them
31
42
  else if (startIndex === -1 && endIndex === -1) {
32
43
  name = rawName;
33
44
  }
34
- // Solo uno de los dos
45
+ // Only one of the two
35
46
  else {
36
47
  throw new ParseException_1.ParseException(lineNumber, "INVALID_NAMESPACE", `Line not valid: ${fullLine}`);
37
48
  }
38
- // Retorno
49
+ // Return
39
50
  return new NameNamespace_1.NameNamespace(name, namespace.toLowerCase());
40
51
  }
41
52
  }
@@ -1,4 +1,22 @@
1
+ /** Validates the format of STXT `(a.b.c)` namespaces. */
1
2
  export declare class NamespaceValidator {
3
+ /**
4
+ * Format of the logical namespace.
5
+ *
6
+ * Rules:
7
+ * - Lower-case letters, digits and dot only.
8
+ * - It may optionally start with '@'.
9
+ * - It must be one or more domain-style labels separated by '.':
10
+ * label := [a-z0-9]+
11
+ * valid examples: "xxx", "xxx.ddd", "zzz.ttt.ooo", "@xxx", "@xxx.ddd".
12
+ */
2
13
  private static readonly NAMESPACE_FORMAT;
14
+ /**
15
+ * Validates the format of a namespace.
16
+ *
17
+ * @param namespace already normalized namespace to validate; ignored when null or empty.
18
+ * @param lineNumber line number, for the error message.
19
+ * @throws ParseException with code `INVALID_NAMESPACE` if it does not match the format.
20
+ */
3
21
  static validateNamespaceFormat(namespace: string | null | undefined, lineNumber: number): void;
4
22
  }
@@ -2,7 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NamespaceValidator = void 0;
4
4
  const ParseException_1 = require("../exceptions/ParseException");
5
+ /** Validates the format of STXT `(a.b.c)` namespaces. */
5
6
  class NamespaceValidator {
7
+ /**
8
+ * Validates the format of a namespace.
9
+ *
10
+ * @param namespace already normalized namespace to validate; ignored when null or empty.
11
+ * @param lineNumber line number, for the error message.
12
+ * @throws ParseException with code `INVALID_NAMESPACE` if it does not match the format.
13
+ */
6
14
  static validateNamespaceFormat(namespace, lineNumber) {
7
15
  if (!namespace) {
8
16
  return;
@@ -13,5 +21,15 @@ class NamespaceValidator {
13
21
  }
14
22
  }
15
23
  exports.NamespaceValidator = NamespaceValidator;
24
+ /**
25
+ * Format of the logical namespace.
26
+ *
27
+ * Rules:
28
+ * - Lower-case letters, digits and dot only.
29
+ * - It may optionally start with '@'.
30
+ * - It must be one or more domain-style labels separated by '.':
31
+ * label := [a-z0-9]+
32
+ * valid examples: "xxx", "xxx.ddd", "zzz.ttt.ooo", "@xxx", "@xxx.ddd".
33
+ */
16
34
  NamespaceValidator.NAMESPACE_FORMAT = /^@?[a-z0-9]+(\.[a-z0-9]+)+$/;
17
35
  //# sourceMappingURL=NamespaceValidator.js.map
@@ -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
  }