@stxt-lang/core 0.6.0 → 0.6.2
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 +2 -0
- package/out/all.js +4 -1
- package/out/core/Node.d.ts +0 -1
- package/out/core/Node.js +1 -6
- package/out/core/StringUtils.d.ts +11 -0
- package/out/core/StringUtils.js +16 -0
- package/out/discovery/DiscoveryResolver.js +7 -8
- package/out/discovery/DiscoveryResult.d.ts +2 -0
- package/out/discovery/DiscoveryResult.js +10 -0
- package/out/runtime/TreeJson.d.ts +40 -0
- package/out/runtime/TreeJson.js +46 -0
- package/out/schema/ChildDefinition.js +1 -1
- package/out/schema/NodeDefinition.js +1 -1
- package/out/schema/SchemaProviderMemory.js +7 -2
- package/out/template/TemplateParser.js +5 -0
- package/out/template/TemplateSchemaProviderMemory.d.ts +2 -1
- package/out/template/TemplateSchemaProviderMemory.js +8 -3
- package/package.json +1 -1
package/out/all.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export { transformNodeToSchema } from "./schema/SchemaParser";
|
|
|
17
17
|
export { UnifiedSchemaProvider } from "./runtime/UnifiedSchemaProvider";
|
|
18
18
|
export { ConditionalValidator } from "./runtime/ConditionalValidator";
|
|
19
19
|
export { NodeWriter, IndentStyle } from "./runtime/NodeWriter";
|
|
20
|
+
export { toCanonicalTree, toCanonicalJson } from "./runtime/TreeJson";
|
|
21
|
+
export type { CanonicalDocument, CanonicalNode, CanonicalInlineNode, CanonicalBlockNode } from "./runtime/TreeJson";
|
|
20
22
|
export { transformTemplateNodeToSchema } from "./template/TemplateParser";
|
|
21
23
|
export { DiscoveryResolver, DiscoveryOptions } from "./discovery/DiscoveryResolver";
|
|
22
24
|
export { DiscoveryResult, DiscoveryDefinition, DiscoveryLevel } from "./discovery/DiscoveryResult";
|
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.IndentStyle = exports.NodeWriter = exports.ConditionalValidator = exports.UnifiedSchemaProvider = exports.transformNodeToSchema = exports.ChildDefinition = exports.NodeDefinition = exports.SchemaValidator = exports.Schema = exports.ValidationException = exports.ParseException = exports.StringUtils = exports.parseLine = exports.Constants = exports.Line = exports.ParseResult = exports.Parser = exports.Node = void 0;
|
|
6
|
+
exports.DiscoveryError = exports.DiscoveryResult = exports.DiscoveryResolver = exports.transformTemplateNodeToSchema = exports.toCanonicalJson = exports.toCanonicalTree = exports.IndentStyle = exports.NodeWriter = exports.ConditionalValidator = exports.UnifiedSchemaProvider = exports.transformNodeToSchema = exports.ChildDefinition = exports.NodeDefinition = exports.SchemaValidator = exports.Schema = exports.ValidationException = exports.ParseException = exports.StringUtils = exports.parseLine = exports.Constants = exports.Line = exports.ParseResult = exports.Parser = exports.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");
|
|
@@ -39,6 +39,9 @@ Object.defineProperty(exports, "ConditionalValidator", { enumerable: true, get:
|
|
|
39
39
|
var NodeWriter_1 = require("./runtime/NodeWriter");
|
|
40
40
|
Object.defineProperty(exports, "NodeWriter", { enumerable: true, get: function () { return NodeWriter_1.NodeWriter; } });
|
|
41
41
|
Object.defineProperty(exports, "IndentStyle", { enumerable: true, get: function () { return NodeWriter_1.IndentStyle; } });
|
|
42
|
+
var TreeJson_1 = require("./runtime/TreeJson");
|
|
43
|
+
Object.defineProperty(exports, "toCanonicalTree", { enumerable: true, get: function () { return TreeJson_1.toCanonicalTree; } });
|
|
44
|
+
Object.defineProperty(exports, "toCanonicalJson", { enumerable: true, get: function () { return TreeJson_1.toCanonicalJson; } });
|
|
42
45
|
var TemplateParser_1 = require("./template/TemplateParser");
|
|
43
46
|
Object.defineProperty(exports, "transformTemplateNodeToSchema", { enumerable: true, get: function () { return TemplateParser_1.transformTemplateNodeToSchema; } });
|
|
44
47
|
var DiscoveryResolver_1 = require("./discovery/DiscoveryResolver");
|
package/out/core/Node.d.ts
CHANGED
package/out/core/Node.js
CHANGED
|
@@ -38,10 +38,7 @@ class Node {
|
|
|
38
38
|
if (this.value.length > 0 && this.isTextNode()) {
|
|
39
39
|
throw new RuntimeException_1.RuntimeException("INLINE_VALUE_NOT_VALID", "Not empty value with textNode");
|
|
40
40
|
}
|
|
41
|
-
if (!
|
|
42
|
-
throw new ParseException_1.ParseException(line, "INVALID_NODE_NAME", `Node name contains invalid characters: ${name}`);
|
|
43
|
-
}
|
|
44
|
-
if (this.normalizedName.length === 0) {
|
|
41
|
+
if (!StringUtils_1.StringUtils.isValidNodeName(this.name)) {
|
|
45
42
|
throw new ParseException_1.ParseException(line, "INVALID_NODE_NAME", `Node name not valid: ${name}`);
|
|
46
43
|
}
|
|
47
44
|
}
|
|
@@ -166,6 +163,4 @@ class Node {
|
|
|
166
163
|
}
|
|
167
164
|
}
|
|
168
165
|
exports.Node = Node;
|
|
169
|
-
// STXT-SPEC 4.2: Unicode letters and digits (categories L and Nd) plus '-', '_' and space
|
|
170
|
-
Node.VALID_NAME = /^[\p{L}\p{Nd}\-_ ]+$/u;
|
|
171
166
|
//# sourceMappingURL=Node.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** String normalization helpers used for names, namespaces and values. */
|
|
2
2
|
export declare class StringUtils {
|
|
3
|
+
private static readonly NODE_NAME;
|
|
3
4
|
private constructor();
|
|
4
5
|
/**
|
|
5
6
|
* Removes the trailing whitespace of a string.
|
|
@@ -29,6 +30,16 @@ export declare class StringUtils {
|
|
|
29
30
|
* @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
31
|
*/
|
|
31
32
|
static compactSpaces(s: string | null | undefined): string;
|
|
33
|
+
/**
|
|
34
|
+
* Tells whether a value is a valid STXT node name.
|
|
35
|
+
*
|
|
36
|
+
* The test happens after NFC normalization: the source may use either the
|
|
37
|
+
* precomposed or decomposed Unicode spelling of a letter with a diacritic.
|
|
38
|
+
*
|
|
39
|
+
* @param input name to validate.
|
|
40
|
+
* @returns true if the name contains only permitted characters and has a non-empty canonical name.
|
|
41
|
+
*/
|
|
42
|
+
static isValidNodeName(input: string | null | undefined): boolean;
|
|
32
43
|
/**
|
|
33
44
|
* Builds the canonical name of a node, as defined by STXT-SPEC 4.3.
|
|
34
45
|
*
|
package/out/core/StringUtils.js
CHANGED
|
@@ -51,6 +51,19 @@ class StringUtils {
|
|
|
51
51
|
static compactSpaces(s) {
|
|
52
52
|
return (s ?? "").trim().replace(/\s+/g, " ");
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Tells whether a value is a valid STXT node name.
|
|
56
|
+
*
|
|
57
|
+
* The test happens after NFC normalization: the source may use either the
|
|
58
|
+
* precomposed or decomposed Unicode spelling of a letter with a diacritic.
|
|
59
|
+
*
|
|
60
|
+
* @param input name to validate.
|
|
61
|
+
* @returns true if the name contains only permitted characters and has a non-empty canonical name.
|
|
62
|
+
*/
|
|
63
|
+
static isValidNodeName(input) {
|
|
64
|
+
const nfc = this.compactSpaces(input).normalize("NFC");
|
|
65
|
+
return this.NODE_NAME.test(nfc) && this.normalize(nfc).length > 0;
|
|
66
|
+
}
|
|
54
67
|
// Used for the normalized name of the nodes (STXT-SPEC 4.3): NFC + lower case,
|
|
55
68
|
// keeping diacritics and non-Latin alphabets (IDN model)
|
|
56
69
|
/**
|
|
@@ -74,4 +87,7 @@ class StringUtils {
|
|
|
74
87
|
}
|
|
75
88
|
}
|
|
76
89
|
exports.StringUtils = StringUtils;
|
|
90
|
+
// STXT-SPEC 4.2 / 4.3: validate the logical name after NFC so that a
|
|
91
|
+
// decomposed spelling such as "e" + combining acute is accepted as "é".
|
|
92
|
+
StringUtils.NODE_NAME = /^[\p{L}\p{Nd}\-_ ]+$/u;
|
|
77
93
|
//# sourceMappingURL=StringUtils.js.map
|
|
@@ -127,10 +127,9 @@ class DiscoveryResolver {
|
|
|
127
127
|
if (cached) {
|
|
128
128
|
return cached;
|
|
129
129
|
}
|
|
130
|
-
const level = { dir, definitions: new Map(), errors: [] };
|
|
131
|
-
const conflicted = new Set();
|
|
130
|
+
const level = { dir, definitions: new Map(), conflictedNamespaces: new Set(), errors: [] };
|
|
132
131
|
for (const file of await this.collectFiles(dir)) {
|
|
133
|
-
await this.loadFile(file, level
|
|
132
|
+
await this.loadFile(file, level);
|
|
134
133
|
}
|
|
135
134
|
this.levelCache.set(dir, level);
|
|
136
135
|
return level;
|
|
@@ -152,7 +151,7 @@ class DiscoveryResolver {
|
|
|
152
151
|
}
|
|
153
152
|
// Loads one file of a level: parses it and registers every root as a definition,
|
|
154
153
|
// reporting the errors of spec section 8.
|
|
155
|
-
async loadFile(file, level
|
|
154
|
+
async loadFile(file, level) {
|
|
156
155
|
// Spec section 3: every file under a resolution directory must be a definition.
|
|
157
156
|
if (!file.endsWith(STXT_EXTENSION)) {
|
|
158
157
|
level.errors.push(new DiscoveryError_1.DiscoveryError(DiscoveryError_1.DiscoveryError.NOT_A_DEFINITION, file, `Not an STXT definition file: ${file}`));
|
|
@@ -171,12 +170,12 @@ class DiscoveryResolver {
|
|
|
171
170
|
return;
|
|
172
171
|
}
|
|
173
172
|
for (const node of nodes) {
|
|
174
|
-
this.loadRootNode(node, file, level
|
|
173
|
+
this.loadRootNode(node, file, level);
|
|
175
174
|
}
|
|
176
175
|
}
|
|
177
176
|
// Validates one root node against its meta-schema, compiles it to a schema and
|
|
178
177
|
// registers it in the level, detecting same-level duplicates.
|
|
179
|
-
loadRootNode(node, file, level
|
|
178
|
+
loadRootNode(node, file, level) {
|
|
180
179
|
const namespace = node.getNamespace();
|
|
181
180
|
let schema;
|
|
182
181
|
try {
|
|
@@ -200,10 +199,10 @@ class DiscoveryResolver {
|
|
|
200
199
|
const existing = level.definitions.get(key);
|
|
201
200
|
// Spec section 8: on a same-level duplicate, never silently pick one of the
|
|
202
201
|
// definitions — the namespace has no active definition while the conflict exists.
|
|
203
|
-
if (
|
|
202
|
+
if (level.conflictedNamespaces.has(key) || existing) {
|
|
204
203
|
if (existing) {
|
|
205
204
|
level.definitions.delete(key);
|
|
206
|
-
|
|
205
|
+
level.conflictedNamespaces.add(key);
|
|
207
206
|
}
|
|
208
207
|
const firstFile = existing ? existing.file : "another file of this level";
|
|
209
208
|
level.errors.push(new DiscoveryError_1.DiscoveryError(DiscoveryError_1.DiscoveryError.DUPLICATE_NAMESPACE, file, `Duplicate definition for namespace '${schema.getNamespace()}' at level ${level.dir}: ` +
|
|
@@ -24,6 +24,8 @@ export interface DiscoveryLevel {
|
|
|
24
24
|
dir: string;
|
|
25
25
|
/** Definitions of the level by lowercased target namespace, conflicts excluded. */
|
|
26
26
|
definitions: Map<string, DiscoveryDefinition>;
|
|
27
|
+
/** Namespaces with a same-level conflict; they block fallback to farther levels. */
|
|
28
|
+
conflictedNamespaces: Set<string>;
|
|
27
29
|
/** Resolution errors found while loading this level. */
|
|
28
30
|
errors: DiscoveryError[];
|
|
29
31
|
}
|
|
@@ -52,6 +52,11 @@ class DiscoveryResult {
|
|
|
52
52
|
getDefinition(namespace) {
|
|
53
53
|
const key = StringUtils_1.StringUtils.lowerCase(namespace);
|
|
54
54
|
for (const level of this.levels) {
|
|
55
|
+
// STXT-DISCOVERY-SPEC section 8: a closer conflict leaves the namespace
|
|
56
|
+
// without an active definition instead of falling back to a farther level.
|
|
57
|
+
if (level.conflictedNamespaces.has(key)) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
55
60
|
const definition = level.definitions.get(key);
|
|
56
61
|
if (definition) {
|
|
57
62
|
return definition;
|
|
@@ -69,6 +74,11 @@ class DiscoveryResult {
|
|
|
69
74
|
const seen = new Set();
|
|
70
75
|
const result = [];
|
|
71
76
|
for (const level of this.levels) {
|
|
77
|
+
// Mark conflicts as seen so getActiveDefinitions() has the same semantics
|
|
78
|
+
// as getDefinition(): they block definitions in farther levels.
|
|
79
|
+
for (const key of level.conflictedNamespaces) {
|
|
80
|
+
seen.add(key);
|
|
81
|
+
}
|
|
72
82
|
for (const [key, definition] of level.definitions) {
|
|
73
83
|
if (!seen.has(key)) {
|
|
74
84
|
seen.add(key);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Node } from "../core/Node";
|
|
2
|
+
/** Canonical JSON representation of a parsed STXT document (STXT-TREE-SPEC). */
|
|
3
|
+
export type CanonicalDocument = CanonicalNode[];
|
|
4
|
+
/** A node in the canonical JSON representation of an STXT document. */
|
|
5
|
+
export type CanonicalNode = CanonicalInlineNode | CanonicalBlockNode;
|
|
6
|
+
/** Canonical representation of an INLINE (`:`) node. */
|
|
7
|
+
export interface CanonicalInlineNode {
|
|
8
|
+
name: string;
|
|
9
|
+
canonicalName: string;
|
|
10
|
+
namespace: string;
|
|
11
|
+
form: "inline";
|
|
12
|
+
value: string;
|
|
13
|
+
children: CanonicalNode[];
|
|
14
|
+
}
|
|
15
|
+
/** Canonical representation of a BLOCK (`>>`) node. */
|
|
16
|
+
export interface CanonicalBlockNode {
|
|
17
|
+
name: string;
|
|
18
|
+
canonicalName: string;
|
|
19
|
+
namespace: string;
|
|
20
|
+
form: "block";
|
|
21
|
+
lines: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Converts every root node of a parsed document to the logical tree defined by
|
|
25
|
+
* STXT-TREE-SPEC. The result deliberately excludes source positions, indentation
|
|
26
|
+
* style, comments and derived values such as a qualified name.
|
|
27
|
+
*
|
|
28
|
+
* @param nodes root nodes of an already parsed STXT document.
|
|
29
|
+
* @returns the canonical document tree, ready to be serialized as JSON.
|
|
30
|
+
*/
|
|
31
|
+
export declare function toCanonicalTree(nodes: ReadonlyArray<Node>): CanonicalDocument;
|
|
32
|
+
/**
|
|
33
|
+
* Serializes the canonical tree of a parsed document as human-readable JSON.
|
|
34
|
+
* JSON whitespace is not part of STXT-TREE-SPEC; two-space indentation is this
|
|
35
|
+
* implementation's deterministic presentation for command-line use.
|
|
36
|
+
*
|
|
37
|
+
* @param nodes root nodes of an already parsed STXT document.
|
|
38
|
+
* @returns the canonical document tree encoded as JSON, without a final line break.
|
|
39
|
+
*/
|
|
40
|
+
export declare function toCanonicalJson(nodes: ReadonlyArray<Node>): string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toCanonicalTree = toCanonicalTree;
|
|
4
|
+
exports.toCanonicalJson = toCanonicalJson;
|
|
5
|
+
/**
|
|
6
|
+
* Converts every root node of a parsed document to the logical tree defined by
|
|
7
|
+
* STXT-TREE-SPEC. The result deliberately excludes source positions, indentation
|
|
8
|
+
* style, comments and derived values such as a qualified name.
|
|
9
|
+
*
|
|
10
|
+
* @param nodes root nodes of an already parsed STXT document.
|
|
11
|
+
* @returns the canonical document tree, ready to be serialized as JSON.
|
|
12
|
+
*/
|
|
13
|
+
function toCanonicalTree(nodes) {
|
|
14
|
+
return nodes.map(node => toCanonicalNode(node));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Serializes the canonical tree of a parsed document as human-readable JSON.
|
|
18
|
+
* JSON whitespace is not part of STXT-TREE-SPEC; two-space indentation is this
|
|
19
|
+
* implementation's deterministic presentation for command-line use.
|
|
20
|
+
*
|
|
21
|
+
* @param nodes root nodes of an already parsed STXT document.
|
|
22
|
+
* @returns the canonical document tree encoded as JSON, without a final line break.
|
|
23
|
+
*/
|
|
24
|
+
function toCanonicalJson(nodes) {
|
|
25
|
+
return JSON.stringify(toCanonicalTree(nodes), null, 2);
|
|
26
|
+
}
|
|
27
|
+
function toCanonicalNode(node) {
|
|
28
|
+
if (node.isTextNode()) {
|
|
29
|
+
return {
|
|
30
|
+
name: node.getName(),
|
|
31
|
+
canonicalName: node.getNormalizedName(),
|
|
32
|
+
namespace: node.getNamespace(),
|
|
33
|
+
form: "block",
|
|
34
|
+
lines: [...node.getTextLines()],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
name: node.getName(),
|
|
39
|
+
canonicalName: node.getNormalizedName(),
|
|
40
|
+
namespace: node.getNamespace(),
|
|
41
|
+
form: "inline",
|
|
42
|
+
value: node.getValue(),
|
|
43
|
+
children: node.getChildren().map(child => toCanonicalNode(child)),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=TreeJson.js.map
|
|
@@ -23,7 +23,7 @@ class ChildDefinition {
|
|
|
23
23
|
this.min = min;
|
|
24
24
|
this.max = max;
|
|
25
25
|
NamespaceValidator_1.NamespaceValidator.validateNamespaceFormat(this.namespace, numLine);
|
|
26
|
-
if (this.
|
|
26
|
+
if (!StringUtils_1.StringUtils.isValidNodeName(this.name)) {
|
|
27
27
|
throw new ValidationException_1.ValidationException(numLine, "INVALID_NODE_NAME", `Node name not valid: ${name}`);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -24,7 +24,7 @@ class NodeDefinition {
|
|
|
24
24
|
this.normalizedName = StringUtils_1.StringUtils.normalize(name);
|
|
25
25
|
this.type = type;
|
|
26
26
|
this.description = description;
|
|
27
|
-
if (this.
|
|
27
|
+
if (!StringUtils_1.StringUtils.isValidNodeName(this.name)) {
|
|
28
28
|
throw new ValidationException_1.ValidationException(line, "INVALID_NODE_NAME", `Node name not valid: ${name}`);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -52,9 +52,14 @@ class SchemaProviderMemory {
|
|
|
52
52
|
addSchema(txt) {
|
|
53
53
|
const parser = new Parser_1.Parser();
|
|
54
54
|
const node = parser.parse(txt)[0];
|
|
55
|
-
|
|
55
|
+
// A schema that does not validate against its meta-schema must not be
|
|
56
|
+
// registered (same policy as UnifiedSchemaProvider/DiscoveryResolver)
|
|
56
57
|
const schemaValidator = new SchemaValidator_1.SchemaValidator(new SchemaProviderMeta_1.SchemaProviderMeta(), true);
|
|
57
|
-
schemaValidator.validate(node);
|
|
58
|
+
const errors = schemaValidator.validate(node);
|
|
59
|
+
if (errors.length > 0) {
|
|
60
|
+
throw errors[0];
|
|
61
|
+
}
|
|
62
|
+
const schema = (0, SchemaParser_1.transformNodeToSchema)(node);
|
|
58
63
|
const key = schema.getNamespace();
|
|
59
64
|
this.schemas.set(key, schema);
|
|
60
65
|
}
|
|
@@ -72,6 +72,11 @@ function transformTemplateNodeToSchema(node) {
|
|
|
72
72
|
}
|
|
73
73
|
/** Adds to the schema the definition a node of the structure declares, along with its children. */
|
|
74
74
|
function addToSchema(schema, node) {
|
|
75
|
+
// A Structure line must use the template grammar's ':' form. The core parser
|
|
76
|
+
// also accepts BLOCK nodes here, so reject them explicitly (STXT-TEMPLATE-SPEC 6.3).
|
|
77
|
+
if (node.isTextNode()) {
|
|
78
|
+
throw new ValidationException_1.ValidationException(node.getLine(), "INVALID_CHILD_LINE", "Template Structure lines must use ':'");
|
|
79
|
+
}
|
|
75
80
|
// Get the qualified name
|
|
76
81
|
let namespace = node.getNamespace();
|
|
77
82
|
const name = node.getName();
|
|
@@ -18,7 +18,8 @@ export declare class TemplateSchemaProviderMemory extends SchemaProviderMemory {
|
|
|
18
18
|
*
|
|
19
19
|
* @param template text of the `@stxt.template` document.
|
|
20
20
|
* @throws ValidationException with code `INVALID_SCHEMA` if the document does not hold exactly
|
|
21
|
-
* one template
|
|
21
|
+
* one template or the resulting schema has no namespace, or the first validation error
|
|
22
|
+
* if the template does not validate against the template meta-schema.
|
|
22
23
|
*/
|
|
23
24
|
addTemplate(template: string): void;
|
|
24
25
|
}
|
|
@@ -31,7 +31,8 @@ class TemplateSchemaProviderMemory extends SchemaProviderMemory_1.SchemaProvider
|
|
|
31
31
|
*
|
|
32
32
|
* @param template text of the `@stxt.template` document.
|
|
33
33
|
* @throws ValidationException with code `INVALID_SCHEMA` if the document does not hold exactly
|
|
34
|
-
* one template
|
|
34
|
+
* one template or the resulting schema has no namespace, or the first validation error
|
|
35
|
+
* if the template does not validate against the template meta-schema.
|
|
35
36
|
*/
|
|
36
37
|
addTemplate(template) {
|
|
37
38
|
const parser = new Parser_1.Parser();
|
|
@@ -39,9 +40,13 @@ class TemplateSchemaProviderMemory extends SchemaProviderMemory_1.SchemaProvider
|
|
|
39
40
|
if (nodes.length !== 1) {
|
|
40
41
|
throw new ValidationException_1.ValidationException(0, "INVALID_SCHEMA", `There are ${nodes.length}, and expected is 1`);
|
|
41
42
|
}
|
|
42
|
-
//
|
|
43
|
+
// A template that does not validate against the template meta-schema must not
|
|
44
|
+
// be registered (same policy as UnifiedSchemaProvider/DiscoveryResolver)
|
|
43
45
|
const schemaValidator = new SchemaValidator_1.SchemaValidator(new MetaTemplateSchemaProvider_1.MetaTemplateSchemaProvider(), true);
|
|
44
|
-
schemaValidator.validate(nodes[0]);
|
|
46
|
+
const errors = schemaValidator.validate(nodes[0]);
|
|
47
|
+
if (errors.length > 0) {
|
|
48
|
+
throw errors[0];
|
|
49
|
+
}
|
|
45
50
|
// Build the schema out of the template
|
|
46
51
|
const sch = (0, TemplateParser_1.transformTemplateNodeToSchema)(nodes[0]);
|
|
47
52
|
// Minimum safety check (Java checked the expected namespace here too)
|