@stxt-lang/core 0.9.1 → 0.10.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/all.d.ts CHANGED
@@ -5,6 +5,12 @@ export { Parser } from "./core/Parser";
5
5
  export { ParseResult } from "./core/ParseResult";
6
6
  export { Line } from "./core/Line";
7
7
  export { Constants } from "./core/Constants";
8
+ /**
9
+ * Version of the STXT specifications (STXT-SPEC, STXT-TREE-SPEC, STXT-SCHEMA-SPEC,
10
+ * STXT-TEMPLATE-SPEC, STXT-DISCOVERY-SPEC) this library implements, distinct from the version of
11
+ * the package. Same value as `Constants.SPEC_VERSION`.
12
+ */
13
+ export declare const SPEC_VERSION: string;
8
14
  export { parseLine } from "./core/LineParser";
9
15
  export { StringUtils } from "./core/StringUtils";
10
16
  export { ParseException } from "./exceptions/ParseException";
package/out/all.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // Anything that should be consumable by third parties (e.g. the VSCode extension)
4
4
  // has to be re-exported from here.
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DiscoveryError = exports.DiscoveryResult = exports.DiscoveryResolver = exports.transformTemplateNodeToSchema = exports.toCanonicalJson = exports.toCanonicalTree = exports.IndentStyle = exports.NodeWriter = exports.ConditionalValidator = exports.UnifiedSchemaProvider = exports.transformNodeToSchema = exports.ChildDefinition = exports.NodeDefinition = exports.SchemaValidator = exports.Schema = exports.ValidationException = exports.ParseException = exports.StringUtils = exports.parseLine = exports.Constants = exports.Line = exports.ParseResult = exports.Parser = exports.TextNode = exports.InlineNode = exports.Node = void 0;
6
+ exports.DiscoveryError = exports.DiscoveryResult = exports.DiscoveryResolver = exports.transformTemplateNodeToSchema = exports.toCanonicalJson = exports.toCanonicalTree = exports.IndentStyle = exports.NodeWriter = exports.ConditionalValidator = exports.UnifiedSchemaProvider = exports.transformNodeToSchema = exports.ChildDefinition = exports.NodeDefinition = exports.SchemaValidator = exports.Schema = exports.ValidationException = exports.ParseException = exports.StringUtils = exports.parseLine = exports.SPEC_VERSION = exports.Constants = exports.Line = exports.ParseResult = exports.Parser = exports.TextNode = exports.InlineNode = exports.Node = void 0;
7
7
  var Node_1 = require("./core/Node");
8
8
  Object.defineProperty(exports, "Node", { enumerable: true, get: function () { return Node_1.Node; } });
9
9
  var InlineNode_1 = require("./core/InlineNode");
@@ -18,6 +18,13 @@ var Line_1 = require("./core/Line");
18
18
  Object.defineProperty(exports, "Line", { enumerable: true, get: function () { return Line_1.Line; } });
19
19
  var Constants_1 = require("./core/Constants");
20
20
  Object.defineProperty(exports, "Constants", { enumerable: true, get: function () { return Constants_1.Constants; } });
21
+ const Constants_2 = require("./core/Constants");
22
+ /**
23
+ * Version of the STXT specifications (STXT-SPEC, STXT-TREE-SPEC, STXT-SCHEMA-SPEC,
24
+ * STXT-TEMPLATE-SPEC, STXT-DISCOVERY-SPEC) this library implements, distinct from the version of
25
+ * the package. Same value as `Constants.SPEC_VERSION`.
26
+ */
27
+ exports.SPEC_VERSION = Constants_2.Constants.SPEC_VERSION;
21
28
  var LineParser_1 = require("./core/LineParser");
22
29
  Object.defineProperty(exports, "parseLine", { enumerable: true, get: function () { return LineParser_1.parseLine; } });
23
30
  var StringUtils_1 = require("./core/StringUtils");
@@ -1,5 +1,12 @@
1
1
  /** Characters and sizes fixed by STXT-SPEC that the parser and the writer share. */
2
2
  export declare class Constants {
3
+ /**
4
+ * Version of the STXT specifications (STXT-SPEC, STXT-TREE-SPEC, STXT-SCHEMA-SPEC,
5
+ * STXT-TEMPLATE-SPEC, STXT-DISCOVERY-SPEC) this library implements. It is distinct from the
6
+ * version of the package: the package may be released many times against the same
7
+ * specification version.
8
+ */
9
+ static readonly SPEC_VERSION: string;
3
10
  /** Character that opens a comment line. */
4
11
  static readonly COMMENT_CHAR: string;
5
12
  /** Number of spaces that make up one indentation level. */
@@ -5,6 +5,13 @@ exports.Constants = void 0;
5
5
  class Constants {
6
6
  }
7
7
  exports.Constants = Constants;
8
+ /**
9
+ * Version of the STXT specifications (STXT-SPEC, STXT-TREE-SPEC, STXT-SCHEMA-SPEC,
10
+ * STXT-TEMPLATE-SPEC, STXT-DISCOVERY-SPEC) this library implements. It is distinct from the
11
+ * version of the package: the package may be released many times against the same
12
+ * specification version.
13
+ */
14
+ Constants.SPEC_VERSION = "1.0";
8
15
  /** Character that opens a comment line. */
9
16
  Constants.COMMENT_CHAR = "#";
10
17
  /** Number of spaces that make up one indentation level. */
@@ -15,6 +15,12 @@ export declare class ParseException extends Error {
15
15
  * @param message descriptive message.
16
16
  */
17
17
  constructor(line: number, code: string, message: string);
18
- /** @returns a readable representation of the error, with its line and its code. */
18
+ /**
19
+ * The string form carries the frame that `message` deliberately leaves out: `message` is only
20
+ * the description, and the code and the line are separate fields that whoever formats output
21
+ * composes. Same framing in every port since 0.10.0.
22
+ *
23
+ * @returns `[CODE] line N: message`.
24
+ */
19
25
  toString(): string;
20
26
  }
@@ -20,9 +20,15 @@ class ParseException extends Error {
20
20
  this.code = code;
21
21
  Object.setPrototypeOf(this, ParseException.prototype);
22
22
  }
23
- /** @returns a readable representation of the error, with its line and its code. */
23
+ /**
24
+ * The string form carries the frame that `message` deliberately leaves out: `message` is only
25
+ * the description, and the code and the line are separate fields that whoever formats output
26
+ * composes. Same framing in every port since 0.10.0.
27
+ *
28
+ * @returns `[CODE] line N: message`.
29
+ */
24
30
  toString() {
25
- return `${this.name} [line=${this.line}, code=${this.code}]: ${this.message}`;
31
+ return `[${this.code}] line ${this.line}: ${this.message}`;
26
32
  }
27
33
  }
28
34
  exports.ParseException = ParseException;
@@ -15,6 +15,11 @@ export declare class RuntimeException extends Error {
15
15
  constructor(code: string, message: string);
16
16
  /** @returns the error code in UPPERCASE. */
17
17
  getCode(): string;
18
- /** @returns a readable representation of the error, with its code. */
18
+ /**
19
+ * The string form carries the frame that `message` deliberately leaves out; same framing in
20
+ * every port since 0.10.0.
21
+ *
22
+ * @returns `[CODE] message`.
23
+ */
19
24
  toString(): string;
20
25
  }
@@ -23,10 +23,14 @@ class RuntimeException extends Error {
23
23
  getCode() {
24
24
  return this.code;
25
25
  }
26
- /** @returns a readable representation of the error, with its code. */
26
+ /**
27
+ * The string form carries the frame that `message` deliberately leaves out; same framing in
28
+ * every port since 0.10.0.
29
+ *
30
+ * @returns `[CODE] message`.
31
+ */
27
32
  toString() {
28
- const message = this.message;
29
- return `${this.name}[${this.code}]${message ? `: ${message}` : ""}`;
33
+ return `[${this.code}] ${this.message}`;
30
34
  }
31
35
  }
32
36
  exports.RuntimeException = RuntimeException;
@@ -100,6 +100,11 @@ function createFrom(node, namespace) {
100
100
  const valuesNode = valuesNodes[0];
101
101
  const values = inline(valuesNode).getChildrenByName("value");
102
102
  for (const v of values) {
103
+ // An empty Value: is a schema error (STXT-SCHEMA-SPEC 7.2, condition 14 of section 13):
104
+ // an enumeration whose only valid value is the empty string makes no sense
105
+ if (v.getText().length === 0) {
106
+ throw new ValidationException_1.ValidationException(v.getLine(), "VALUE_EMPTY", "Value of ENUM cannot be empty");
107
+ }
103
108
  result.addValue(v.getText(), v.getLine());
104
109
  }
105
110
  // For the final ENUM check
@@ -1,3 +1,12 @@
1
1
  import { Type } from "../Type";
2
+ /**
3
+ * STXT-SCHEMA-SPEC 9.5: standard Base64 (not URL-safe), padding optional, no leftover bits,
4
+ * never empty. The check is a regular expression plus the leftover-bits rule, never the
5
+ * platform decoder, which silently ignores characters outside the alphabet.
6
+ *
7
+ * @param value value already stripped of blanks.
8
+ * @returns whether it is valid Base64.
9
+ */
10
+ export declare function isValidBase64(value: string): boolean;
2
11
  /** `BASE64` type: checks that the content is valid Base64. */
3
12
  export declare const BASE64: Type;
@@ -1,29 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BASE64 = void 0;
4
+ exports.isValidBase64 = isValidBase64;
4
5
  const ValidationException_1 = require("../../exceptions/ValidationException");
5
6
  const binaryValue_1 = require("./binaryValue");
7
+ /** Standard alphabet of RFC 4648 section 4, used to check the leftover bits of the last character. */
8
+ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
9
+ /**
10
+ * Shape of a Base64 value (STXT-SCHEMA-SPEC 9.5): groups of four characters of the standard
11
+ * alphabet, with an optional final group of two or three characters whose `=` padding may be
12
+ * omitted. The empty string matches here and is rejected separately.
13
+ */
14
+ const SHAPE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}(?:==)?|[A-Za-z0-9+/]{3}=?)?$/;
15
+ /**
16
+ * STXT-SCHEMA-SPEC 9.5: standard Base64 (not URL-safe), padding optional, no leftover bits,
17
+ * never empty. The check is a regular expression plus the leftover-bits rule, never the
18
+ * platform decoder, which silently ignores characters outside the alphabet.
19
+ *
20
+ * @param value value already stripped of blanks.
21
+ * @returns whether it is valid Base64.
22
+ */
23
+ function isValidBase64(value) {
24
+ if (value.length === 0 || !SHAPE.test(value)) {
25
+ return false;
26
+ }
27
+ const data = value.replace(/=+$/, "");
28
+ const rest = data.length % 4;
29
+ if (rest === 0) {
30
+ return true;
31
+ }
32
+ // The last character encodes 6 bits; with 2 characters 4 of them are leftover, with 3, 2 of them.
33
+ const last = ALPHABET.indexOf(data.charAt(data.length - 1));
34
+ const mask = rest === 2 ? 0x0f : 0x03;
35
+ return (last & mask) === 0;
36
+ }
6
37
  /** `BASE64` type: checks that the content is valid Base64. */
7
38
  exports.BASE64 = {
8
39
  getName() {
9
40
  return "BASE64";
10
41
  },
11
42
  validate(ndef, n) {
12
- const raw = (0, binaryValue_1.binaryValue)(n);
13
- try {
14
- // Try to decode it
15
- const buf = Buffer.from(raw, "base64");
16
- // Re-encode to check consistency
17
- // (this keeps partially valid strings out)
18
- const reencoded = buf.toString("base64");
19
- // Normalize the padding before comparing
20
- const normalizedInput = raw.replace(/=+$/, "");
21
- const normalizedReencoded = reencoded.replace(/=+$/, "");
22
- if (normalizedInput !== normalizedReencoded) {
23
- throw new ValidationException_1.ValidationException(n.getLine(), "INVALID_VALUE", `Node '${n.getName()}' Invalid Base64`);
24
- }
25
- }
26
- catch {
43
+ if (!isValidBase64((0, binaryValue_1.binaryValue)(n))) {
27
44
  throw new ValidationException_1.ValidationException(n.getLine(), "INVALID_VALUE", `Node '${n.getName()}' Invalid Base64`);
28
45
  }
29
46
  },
@@ -1,11 +1,13 @@
1
1
  import { Node } from "../../core/Node";
2
2
  /**
3
3
  * STXT-SCHEMA-SPEC 9.5: effective value for the INLINE/BLOCK binary types
4
- * (HEXADECIMAL, BINARY, BASE64). In BLOCK form, validation applies to the
5
- * concatenation of the lines of the block, ignoring line breaks, empty lines
6
- * and the leading and trailing spaces or tabs of each line.
4
+ * (HEXADECIMAL, BINARY, BASE64). Every blank (U+0020 space, U+0009 tab) is
5
+ * removed wherever it is, in both forms; in BLOCK form the lines are
6
+ * concatenated first, which also drops line breaks and empty lines. So
7
+ * `DE AD BE EF`, `1010 1010` and Base64 wrapped at 76 columns validate. No
8
+ * other character is removed: `DE:AD` or `DE-AD` stay invalid.
7
9
  *
8
10
  * @param node node whose value is wanted.
9
- * @returns the inline value, or the lines of the block already concatenated.
11
+ * @returns the value with no blanks, ready for the grammar of the type.
10
12
  */
11
13
  export declare function binaryValue(node: Node): string;
@@ -4,17 +4,17 @@ exports.binaryValue = binaryValue;
4
4
  const TextNode_1 = require("../../core/TextNode");
5
5
  /**
6
6
  * STXT-SCHEMA-SPEC 9.5: effective value for the INLINE/BLOCK binary types
7
- * (HEXADECIMAL, BINARY, BASE64). In BLOCK form, validation applies to the
8
- * concatenation of the lines of the block, ignoring line breaks, empty lines
9
- * and the leading and trailing spaces or tabs of each line.
7
+ * (HEXADECIMAL, BINARY, BASE64). Every blank (U+0020 space, U+0009 tab) is
8
+ * removed wherever it is, in both forms; in BLOCK form the lines are
9
+ * concatenated first, which also drops line breaks and empty lines. So
10
+ * `DE AD BE EF`, `1010 1010` and Base64 wrapped at 76 columns validate. No
11
+ * other character is removed: `DE:AD` or `DE-AD` stay invalid.
10
12
  *
11
13
  * @param node node whose value is wanted.
12
- * @returns the inline value, or the lines of the block already concatenated.
14
+ * @returns the value with no blanks, ready for the grammar of the type.
13
15
  */
14
16
  function binaryValue(node) {
15
- if (!(node instanceof TextNode_1.TextNode)) {
16
- return node.getText();
17
- }
18
- return node.getTextLines().map((line) => line.trim()).join("");
17
+ const raw = node instanceof TextNode_1.TextNode ? node.getTextLines().join("") : node.getText();
18
+ return raw.replace(/[ \t]/g, "");
19
19
  }
20
20
  //# sourceMappingURL=binaryValue.js.map
@@ -77,6 +77,12 @@ class ChildLineParser {
77
77
  const list = [];
78
78
  for (let part of parts) {
79
79
  part = part.trim();
80
+ // An empty item ("[a, , b]", "[a, b,]") is an error, as an empty Value: is in a
81
+ // schema (STXT-TEMPLATE-SPEC 14.14). Only the whole list may be empty ("[]"),
82
+ // which the template parser reports as VALUES_REQUIRED.
83
+ if (part.length === 0 && parts.length > 1) {
84
+ throw new ValidationException_1.ValidationException(lineNumber, "VALUE_EMPTY", `Empty ENUM value in ${valuesStr}`);
85
+ }
80
86
  if (part.length === 0) {
81
87
  continue;
82
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stxt-lang/core",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "Parser and schema validator for STXT, an indentation-based structured-text format.",
5
5
  "main": "out/all.js",
6
6
  "types": "out/all.d.ts",