@lionweb/validation 0.7.0-beta.1 → 0.7.0-beta.11
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/CHANGELOG.md +4 -0
- package/dist/issues/ValidationIssue.d.ts +3 -3
- package/dist/issues/ValidationIssue.d.ts.map +1 -1
- package/dist/issues/ValidationIssue.js +1 -1
- package/dist/issues/ValidationIssue.js.map +1 -1
- package/dist/languages/LanguageUtils.d.ts.map +1 -1
- package/dist/languages/LionWebLanguageWrapper.d.ts.map +1 -1
- package/dist/runners/Utils.js +2 -2
- package/dist/runners/Utils.js.map +1 -1
- package/dist/validators/LionWebChunkDefinitions.d.ts +4 -4
- package/dist/validators/LionWebChunkDefinitions.d.ts.map +1 -1
- package/dist/validators/LionWebChunkDefinitions.js +80 -90
- package/dist/validators/LionWebChunkDefinitions.js.map +1 -1
- package/dist/validators/LionWebLanguageReferenceValidator.d.ts +1 -1
- package/dist/validators/LionWebLanguageReferenceValidator.d.ts.map +1 -1
- package/dist/validators/LionWebLanguageReferenceValidator.js +3 -3
- package/dist/validators/LionWebLanguageReferenceValidator.js.map +1 -1
- package/dist/validators/LionWebSyntaxValidator.js +2 -2
- package/dist/validators/LionWebValidator.js +1 -1
- package/dist/validators/LionWebValidator.js.map +1 -1
- package/dist/validators/ValidationFunctions.d.ts +1 -1
- package/dist/validators/ValidationFunctions.d.ts.map +1 -1
- package/dist/validators/ValidationFunctions.js +5 -12
- package/dist/validators/ValidationFunctions.js.map +1 -1
- package/dist/validators/generic/SyntaxValidator.d.ts +7 -7
- package/dist/validators/generic/SyntaxValidator.d.ts.map +1 -1
- package/dist/validators/generic/SyntaxValidator.js +28 -33
- package/dist/validators/generic/SyntaxValidator.js.map +1 -1
- package/dist/validators/generic/index.d.ts +1 -1
- package/dist/validators/generic/index.d.ts.map +1 -1
- package/dist/validators/generic/index.js +1 -1
- package/dist/validators/generic/index.js.map +1 -1
- package/dist/validators/generic/schema/DefinitionSchema.d.ts +23 -0
- package/dist/validators/generic/schema/DefinitionSchema.d.ts.map +1 -0
- package/dist/validators/generic/schema/DefinitionSchema.js +43 -0
- package/dist/validators/generic/schema/DefinitionSchema.js.map +1 -0
- package/dist/validators/generic/{ValidationTypes.d.ts → schema/ValidationTypes.d.ts} +45 -12
- package/dist/validators/generic/schema/ValidationTypes.d.ts.map +1 -0
- package/dist/validators/generic/{ValidationTypes.js → schema/ValidationTypes.js} +18 -21
- package/dist/validators/generic/schema/ValidationTypes.js.map +1 -0
- package/dist/validators/generic/schema/index.d.ts +3 -0
- package/dist/validators/generic/schema/index.d.ts.map +1 -0
- package/dist/validators/generic/schema/index.js +3 -0
- package/dist/validators/generic/schema/index.js.map +1 -0
- package/package.json +5 -5
- package/src/issues/ValidationIssue.ts +4 -4
- package/src/runners/Utils.ts +2 -2
- package/src/validators/LionWebChunkDefinitions.ts +80 -90
- package/src/validators/LionWebLanguageReferenceValidator.ts +3 -3
- package/src/validators/LionWebSyntaxValidator.ts +2 -2
- package/src/validators/LionWebValidator.ts +1 -1
- package/src/validators/ValidationFunctions.ts +6 -13
- package/src/validators/generic/SyntaxValidator.ts +81 -87
- package/src/validators/generic/index.ts +1 -1
- package/src/validators/generic/schema/DefinitionSchema.ts +52 -0
- package/src/validators/generic/{ValidationTypes.ts → schema/ValidationTypes.ts} +65 -35
- package/src/validators/generic/schema/index.ts +2 -0
- package/dist/validators/generic/ValidationTypes.d.ts.map +0 -1
- package/dist/validators/generic/ValidationTypes.js.map +0 -1
|
@@ -1,112 +1,102 @@
|
|
|
1
|
-
import { MAY_BE_NULL,
|
|
1
|
+
import { DefinitionSchema, MAY_BE_NULL, PropertyDef, PrimitiveDef } from "./generic/index.js"
|
|
2
2
|
import { validateId, validateKey, validateSerializationFormatVersion, validateVersion } from "./ValidationFunctions.js"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The structure below defines the structure of a LionWeb Chunk by defining all the properties.
|
|
6
6
|
* It can
|
|
7
|
-
* - be
|
|
8
|
-
* - used to generate all the types for a LionWebChunk.
|
|
7
|
+
* - be used by the SyntaxValidator to validate an object sat runtime.
|
|
8
|
+
* - used to generate all the TypeScript types for a LionWebChunk.
|
|
9
9
|
*/
|
|
10
|
-
export const
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
[
|
|
14
|
-
PropertyDef({
|
|
15
|
-
PropertyDef({
|
|
16
|
-
PropertyDef({
|
|
10
|
+
export const LionWebSchema: DefinitionSchema = new DefinitionSchema([
|
|
11
|
+
{
|
|
12
|
+
name: "LionWebJsonMetaPointer",
|
|
13
|
+
properties: [
|
|
14
|
+
PropertyDef({ name: "key", type: "LionWebKey" }),
|
|
15
|
+
PropertyDef({ name: "version", type: "LionWebVersion" }),
|
|
16
|
+
PropertyDef({ name: "language", type: "LionWebKey" })
|
|
17
17
|
]
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
[
|
|
22
|
-
PropertyDef({
|
|
23
|
-
PropertyDef({
|
|
24
|
-
PropertyDef({
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "LionWebJsonMetaPointer",
|
|
21
|
+
properties: [
|
|
22
|
+
PropertyDef({ name: "key", type: "LionWebKey" }),
|
|
23
|
+
PropertyDef({ name: "version", type: "LionWebVersion" }),
|
|
24
|
+
PropertyDef({ name: "language", type: "LionWebKey" }),
|
|
25
25
|
]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
[
|
|
30
|
-
PropertyDef({
|
|
31
|
-
PropertyDef({
|
|
32
|
-
PropertyDef({
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "ResponseMessage",
|
|
29
|
+
properties: [
|
|
30
|
+
PropertyDef({ name: "kind", type: "JSstring" }),
|
|
31
|
+
PropertyDef({ name: "message", type: "JSstring" }),
|
|
32
|
+
PropertyDef({ name: "data", type: "JSobject", mayBeNull: true, isOptional: true })
|
|
33
33
|
]
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
[
|
|
38
|
-
PropertyDef({
|
|
39
|
-
PropertyDef({
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "LionWebJsonChunk",
|
|
37
|
+
properties: [
|
|
38
|
+
PropertyDef({ name: "serializationFormatVersion", type: "LionWebSerializationFormatVersion" }),
|
|
39
|
+
PropertyDef({ name: "languages", type: "LionWebJsonUsedLanguage", isList: true }),
|
|
40
|
+
PropertyDef({ name: "nodes", type: "LionWebJsonNode", isList: true })
|
|
40
41
|
]
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
[
|
|
45
|
-
PropertyDef({
|
|
46
|
-
PropertyDef({
|
|
47
|
-
PropertyDef({ property: "properties", expectedType: "LionWebProperty", isList: true }),
|
|
48
|
-
PropertyDef({ property: "containments", expectedType: "LionWebContainment", isList: true }),
|
|
49
|
-
PropertyDef({ property: "references", expectedType: "LionWebReference", isList: true }),
|
|
50
|
-
PropertyDef({ property: "annotations", expectedType: "LionWebId", isList: true }),
|
|
51
|
-
PropertyDef({ property: "parent", expectedType: "LionWebId", mayBeNull: MAY_BE_NULL }),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "LionWebJsonUsedLanguage",
|
|
45
|
+
properties: [
|
|
46
|
+
PropertyDef({ name: "key", type: "LionWebKey" }),
|
|
47
|
+
PropertyDef({ name: "version", type: "LionWebVersion" })
|
|
52
48
|
]
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
[
|
|
57
|
-
PropertyDef({
|
|
58
|
-
PropertyDef({
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "LionWebJsonNode",
|
|
52
|
+
properties: [
|
|
53
|
+
PropertyDef({ name: "id", type: "LionWebId" }),
|
|
54
|
+
PropertyDef({ name: "classifier", type: "LionWebJsonMetaPointer" }),
|
|
55
|
+
PropertyDef({ name: "properties", type: "LionWebJsonProperty", isList: true }),
|
|
56
|
+
PropertyDef({ name: "containments", type: "LionWebJsonContainment", isList: true }),
|
|
57
|
+
PropertyDef({ name: "references", type: "LionWebJsonReference", isList: true }),
|
|
58
|
+
PropertyDef({ name: "annotations", type: "LionWebId", isList: true }),
|
|
59
|
+
PropertyDef({ name: "parent", type: "LionWebId", mayBeNull: MAY_BE_NULL }),
|
|
59
60
|
]
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
[
|
|
64
|
-
PropertyDef({
|
|
65
|
-
PropertyDef({
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "LionWebJsonProperty",
|
|
64
|
+
properties: [
|
|
65
|
+
PropertyDef({ name: "property", type: "LionWebJsonMetaPointer" }),
|
|
66
|
+
PropertyDef({ name: "value", type: "JSstring", mayBeNull: MAY_BE_NULL }),
|
|
66
67
|
]
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
[
|
|
71
|
-
PropertyDef({
|
|
72
|
-
PropertyDef({
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "LionWebJsonContainment",
|
|
71
|
+
properties: [
|
|
72
|
+
PropertyDef({ name: "containment", type: "LionWebJsonMetaPointer" }),
|
|
73
|
+
PropertyDef({ name: "children", type: "LionWebId", isList: true }),
|
|
73
74
|
]
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"
|
|
77
|
-
[
|
|
78
|
-
PropertyDef({
|
|
79
|
-
PropertyDef({
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "LionWebJsonReference",
|
|
78
|
+
properties: [
|
|
79
|
+
PropertyDef({ name: "reference", type: "LionWebJsonMetaPointer"}),
|
|
80
|
+
PropertyDef({ name: "targets", type: "LionWebJsonReferenceTarget", isList: true}),
|
|
80
81
|
]
|
|
81
|
-
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "LionWebJsonReferenceTarget",
|
|
85
|
+
properties: [
|
|
86
|
+
PropertyDef({ name: "resolveInfo", type: "JSstring", mayBeNull: MAY_BE_NULL }),
|
|
87
|
+
PropertyDef({ name: "reference", type: "LionWebId", mayBeNull: MAY_BE_NULL }),
|
|
88
|
+
]
|
|
89
|
+
},
|
|
82
90
|
/**
|
|
83
91
|
* Elements without properties are assumed to be JSON/JS primitive values, and tested using `typeof`
|
|
84
92
|
* and the (optional) validate function.
|
|
85
93
|
*/
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
PrimitiveDef({ primitiveType: "string", validate: validateKey }),
|
|
93
|
-
],
|
|
94
|
-
[
|
|
95
|
-
"LionWebVersion",
|
|
96
|
-
PrimitiveDef({ primitiveType: "string", validate: validateVersion }),
|
|
97
|
-
],
|
|
98
|
-
[
|
|
99
|
-
"LionWebSerializationFormatVersion",
|
|
100
|
-
PrimitiveDef({ primitiveType: "string", validate: validateSerializationFormatVersion }),
|
|
101
|
-
],
|
|
102
|
-
[
|
|
103
|
-
"string",
|
|
104
|
-
PrimitiveDef({ primitiveType: "string" }),
|
|
105
|
-
],
|
|
106
|
-
[
|
|
107
|
-
"object",
|
|
108
|
-
PrimitiveDef({ primitiveType: "object" }),
|
|
109
|
-
]
|
|
94
|
+
PrimitiveDef({ name: "LionWebId", primitiveType: "string", validate: validateId }),
|
|
95
|
+
PrimitiveDef({ name: "LionWebKey", primitiveType: "string", validate: validateKey }),
|
|
96
|
+
PrimitiveDef({ name: "LionWebVersion",primitiveType: "string", validate: validateVersion }),
|
|
97
|
+
PrimitiveDef({ name: "LionWebSerializationFormatVersion",primitiveType: "string", validate: validateSerializationFormatVersion }),
|
|
98
|
+
PrimitiveDef({ name: "JSstring", primitiveType: "string" }),
|
|
99
|
+
PrimitiveDef({ name: "JSobject",primitiveType: "object" }),
|
|
110
100
|
])
|
|
111
101
|
|
|
112
102
|
|
|
@@ -66,7 +66,7 @@ export class LionWebLanguageReferenceValidator {
|
|
|
66
66
|
})
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
private validateContainment(
|
|
69
|
+
private validateContainment(_node: LionWebJsonNode, nodeConcept: LionWebJsonNode | undefined, containment: LionWebJsonContainment, context: JsonContext) {
|
|
70
70
|
const metaConcept = this.registry.getNodeByMetaPointer(containment.containment)
|
|
71
71
|
if (metaConcept === null || metaConcept === undefined) {
|
|
72
72
|
this.validationResult.issue(new Language_UnknownContainment_Issue(context, containment.containment))
|
|
@@ -85,7 +85,7 @@ export class LionWebLanguageReferenceValidator {
|
|
|
85
85
|
// TODO check type of children
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
private validateReference(
|
|
88
|
+
private validateReference(_node: LionWebJsonNode, nodeConcept: LionWebJsonNode | undefined, ref: LionWebJsonReference, context: JsonContext) {
|
|
89
89
|
const referenceDefinition = this.registry.getNodeByMetaPointer(ref.reference)
|
|
90
90
|
if (referenceDefinition === null || referenceDefinition === undefined) {
|
|
91
91
|
this.validationResult.issue(new Language_UnknownReference_Issue(context, ref.reference))
|
|
@@ -113,7 +113,7 @@ export class LionWebLanguageReferenceValidator {
|
|
|
113
113
|
* Checks wwhether the value of `prop1` is correct in relation with its property definition in the referred language.
|
|
114
114
|
* @param prop
|
|
115
115
|
*/
|
|
116
|
-
validateProperty(
|
|
116
|
+
validateProperty(_node: LionWebJsonNode, nodeConcept: LionWebJsonNode | undefined, prop: LionWebJsonProperty, context: JsonContext): void {
|
|
117
117
|
if (prop.value === null) {
|
|
118
118
|
return
|
|
119
119
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SyntaxValidator } from "./generic/SyntaxValidator.js"
|
|
2
2
|
import { ValidationResult } from "./generic/ValidationResult.js"
|
|
3
|
-
import {
|
|
3
|
+
import { LionWebSchema } from "./LionWebChunkDefinitions.js"
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* LionWebSyntaxValidator can check whether objects are structurally LionWeb objects.
|
|
@@ -8,7 +8,7 @@ import { expectedTypes } from "./LionWebChunkDefinitions.js"
|
|
|
8
8
|
export class LionWebSyntaxValidator extends SyntaxValidator {
|
|
9
9
|
|
|
10
10
|
constructor(validationResult: ValidationResult) {
|
|
11
|
-
super(validationResult,
|
|
11
|
+
super(validationResult, LionWebSchema)
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -34,7 +34,7 @@ export class LionWebValidator {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
validateSyntax() {
|
|
37
|
-
this.syntaxValidator.validate(this.object, "
|
|
37
|
+
this.syntaxValidator.validate(this.object, "LionWebJsonChunk")
|
|
38
38
|
this.syntaxCorrect = !this.validationResult.hasErrors()
|
|
39
39
|
if (this.syntaxCorrect) {
|
|
40
40
|
this.chunk = new LionWebJsonChunkWrapper(this.object as LionWebJsonChunk)
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
Syntax_VersionFormat_Issue
|
|
13
13
|
} from "../issues/SyntaxIssues.js"
|
|
14
14
|
import { ValidationResult } from "./generic/ValidationResult.js"
|
|
15
|
-
import { PropertyDefinition } from "./generic/ValidationTypes.js"
|
|
15
|
+
import { PropertyDefinition } from "./generic/schema/ValidationTypes.js"
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Check whether `id` is a valid LionWeb id.
|
|
@@ -20,7 +20,6 @@ import { PropertyDefinition } from "./generic/ValidationTypes.js"
|
|
|
20
20
|
* @param result Any validation issues found will be put into this object.
|
|
21
21
|
* @param context The context for the error message in errors.
|
|
22
22
|
*/
|
|
23
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
24
23
|
export function validateId<String>(value: String, result: ValidationResult, context: JsonContext): void {
|
|
25
24
|
const idString: string = "" + value
|
|
26
25
|
const regexp = /^[a-zA-Z0-9_-][a-zA-Z0-9_-]*$/
|
|
@@ -35,7 +34,6 @@ export function validateId<String>(value: String, result: ValidationResult, cont
|
|
|
35
34
|
* @param result Any validation issues found will be put into this object.
|
|
36
35
|
* @param context The context for the error message in errors.
|
|
37
36
|
*/
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
39
37
|
export function validateKey<String>(value: String, result: ValidationResult, context: JsonContext): void {
|
|
40
38
|
const keyString: string = "" + value
|
|
41
39
|
const regexp = /^[a-zA-Z0-9_-][a-zA-Z0-9_-]*$/
|
|
@@ -50,7 +48,6 @@ export function validateKey<String>(value: String, result: ValidationResult, con
|
|
|
50
48
|
* @param result Any validation issues found will be put into this object.
|
|
51
49
|
* @param context The location in the overall JSON.
|
|
52
50
|
*/
|
|
53
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
54
51
|
export function validateVersion<String>(value: String, result: ValidationResult, context: JsonContext): void {
|
|
55
52
|
const versionString: string = "" + value
|
|
56
53
|
if (versionString.length === 0) {
|
|
@@ -65,14 +62,13 @@ export function validateVersion<String>(value: String, result: ValidationResult,
|
|
|
65
62
|
* @param context The location in the overall JSON.
|
|
66
63
|
* @param propDef The PropertyDefinition for this value
|
|
67
64
|
*/
|
|
68
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
69
65
|
export function validateBoolean<String>(value: String, result: ValidationResult, context: JsonContext, propDef?: PropertyDefinition): void {
|
|
70
66
|
const valueAsPrimitive = "" + value
|
|
71
67
|
if (valueAsPrimitive !== "true" && valueAsPrimitive !== "false") {
|
|
72
68
|
result.issue(
|
|
73
69
|
new Language_PropertyValue_Issue(
|
|
74
70
|
context,
|
|
75
|
-
propDef ? propDef.
|
|
71
|
+
propDef ? propDef.name : "unknown",
|
|
76
72
|
valueAsPrimitive,
|
|
77
73
|
"boolean " + JSON.stringify(value)
|
|
78
74
|
)
|
|
@@ -87,12 +83,11 @@ export function validateBoolean<String>(value: String, result: ValidationResult,
|
|
|
87
83
|
* @param context The location in the overall JSON.
|
|
88
84
|
* @param propDef The PropertyDefinition for this value
|
|
89
85
|
*/
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
91
86
|
export function validateInteger<String>(value: String, result: ValidationResult, context: JsonContext, propDef?: PropertyDefinition): void {
|
|
92
87
|
const valueAsPrimitive = "" + value
|
|
93
88
|
const regexp = /^[+-]?(0|[1-9][0-9]*)$/
|
|
94
89
|
if (valueAsPrimitive === null || !regexp.test(valueAsPrimitive)) {
|
|
95
|
-
result.issue(new Language_PropertyValue_Issue(context, propDef ? propDef.
|
|
90
|
+
result.issue(new Language_PropertyValue_Issue(context, propDef ? propDef.name : "unknown", valueAsPrimitive, "integer"))
|
|
96
91
|
}
|
|
97
92
|
}
|
|
98
93
|
|
|
@@ -103,16 +98,15 @@ export function validateInteger<String>(value: String, result: ValidationResult,
|
|
|
103
98
|
* @param context The location in the overall JSON.
|
|
104
99
|
* @param propDef The PropertyDefinition for this value
|
|
105
100
|
*/
|
|
106
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
107
101
|
export function validateJSON<String>(value: String, result: ValidationResult, context: JsonContext, propDef?: PropertyDefinition): void {
|
|
108
102
|
const valueAsPrimitive = "" + value
|
|
109
103
|
if (value === null) {
|
|
110
|
-
result.issue(new Syntax_PropertyNullIssue(context, propDef!.
|
|
104
|
+
result.issue(new Syntax_PropertyNullIssue(context, propDef!.name!))
|
|
111
105
|
}
|
|
112
106
|
try {
|
|
113
107
|
JSON.parse(valueAsPrimitive)
|
|
114
|
-
} catch (
|
|
115
|
-
result.issue(new Language_PropertyValue_Issue(context, propDef ? propDef.
|
|
108
|
+
} catch (_) {
|
|
109
|
+
result.issue(new Language_PropertyValue_Issue(context, propDef ? propDef.name : "unknown", valueAsPrimitive, "JSON"))
|
|
116
110
|
}
|
|
117
111
|
}
|
|
118
112
|
|
|
@@ -122,7 +116,6 @@ export function validateJSON<String>(value: String, result: ValidationResult, co
|
|
|
122
116
|
* @param result
|
|
123
117
|
* @param context
|
|
124
118
|
*/
|
|
125
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
126
119
|
export function validateSerializationFormatVersion<String>(value: String, result: ValidationResult, context: JsonContext): void {
|
|
127
120
|
if (typeof value !== "string") {
|
|
128
121
|
result.issue(new Syntax_SerializationFormatVersion_Issue(context, JSON.stringify(value)))
|
|
@@ -9,40 +9,38 @@ import {
|
|
|
9
9
|
import { ValidationResult } from "./ValidationResult.js"
|
|
10
10
|
import {
|
|
11
11
|
isObjectDefinition,
|
|
12
|
-
isPrimitiveDefinition,
|
|
13
|
-
ObjectDefinition,
|
|
14
|
-
PrimitiveDefinition,
|
|
15
|
-
TypeDefinition,
|
|
12
|
+
isPrimitiveDefinition, ObjectDefinition, PrimitiveDefinition, DefinitionSchema,
|
|
16
13
|
UnknownObjectType
|
|
17
|
-
} from "./
|
|
14
|
+
} from "./schema/index.js"
|
|
18
15
|
|
|
19
16
|
/**
|
|
20
|
-
* Syntax Validator
|
|
21
|
-
* definitions given in `
|
|
17
|
+
* Syntax Validator checks whether objects are structurally conforming to the
|
|
18
|
+
* definitions given in `schema`.
|
|
22
19
|
*/
|
|
23
20
|
export class SyntaxValidator {
|
|
24
21
|
validationResult: ValidationResult
|
|
25
|
-
|
|
22
|
+
schema: DefinitionSchema
|
|
26
23
|
|
|
27
|
-
constructor(validationResult: ValidationResult,
|
|
24
|
+
constructor(validationResult: ValidationResult, schema: DefinitionSchema) {
|
|
28
25
|
this.validationResult = validationResult
|
|
29
|
-
this.
|
|
26
|
+
this.schema = schema
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
/**
|
|
33
30
|
* Check whether `obj` is a JSON object that conforms to the definition of `expectedType`.
|
|
34
|
-
* All errors found will be
|
|
31
|
+
* All errors found will be added to the `validationResult` object.
|
|
35
32
|
* @param obj The object to validate.
|
|
36
33
|
* @param expectedType The expected type of the object.
|
|
37
34
|
*/
|
|
38
35
|
validate(obj: unknown, expectedType: string) {
|
|
39
36
|
const object = obj as UnknownObjectType
|
|
40
|
-
const typeDef = this.
|
|
37
|
+
const typeDef = this.schema.getDefinition(expectedType)
|
|
38
|
+
|
|
41
39
|
if (typeDef === undefined) {
|
|
42
40
|
throw new Error(`SyntaxValidator.validate: cannot find definition for ${expectedType}`)
|
|
43
|
-
} else if (isObjectDefinition(typeDef)){
|
|
41
|
+
} else if (isObjectDefinition(typeDef)) {
|
|
44
42
|
this.validateObjectProperties(expectedType, typeDef, object, new JsonContext(null, ["$"]))
|
|
45
|
-
} else if(
|
|
43
|
+
} else if (isPrimitiveDefinition(typeDef)) {
|
|
46
44
|
this.validatePrimitiveValue("$", typeDef, object, new JsonContext(null, ["$"]))
|
|
47
45
|
}
|
|
48
46
|
}
|
|
@@ -50,7 +48,7 @@ export class SyntaxValidator {
|
|
|
50
48
|
/**
|
|
51
49
|
* Validate whether `object` is structured conform the properties in `propertyDef`
|
|
52
50
|
* @param originalProperty The property of which `object` it the value
|
|
53
|
-
* @param typeDef
|
|
51
|
+
* @param typeDef The property definitions that are being validated
|
|
54
52
|
* @param object The object being validated
|
|
55
53
|
* @param jsonContext The location in the JSON
|
|
56
54
|
* @private
|
|
@@ -59,93 +57,89 @@ export class SyntaxValidator {
|
|
|
59
57
|
if (typeDef === null || typeDef === undefined) {
|
|
60
58
|
return
|
|
61
59
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
continue
|
|
75
|
-
}
|
|
76
|
-
if (!propertyDef.mayBeNull && propertyValue === null) {
|
|
77
|
-
this.validationResult.issue(new Syntax_PropertyNullIssue(jsonContext, propertyDef.property))
|
|
78
|
-
continue
|
|
60
|
+
if (typeof object !== "object") {
|
|
61
|
+
this.validationResult.issue(new Syntax_PropertyTypeIssue(jsonContext, originalProperty, "object", typeof object))
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
for (const propertyDef of typeDef.properties) {
|
|
65
|
+
const expectedTypeDef = this.schema.getDefinition(propertyDef.type)
|
|
66
|
+
const validator = propertyDef.validate!
|
|
67
|
+
const propertyValue = object[propertyDef.name]
|
|
68
|
+
if (propertyValue === undefined) {
|
|
69
|
+
if (!propertyDef.isOptional) {
|
|
70
|
+
this.validationResult.issue(new Syntax_PropertyMissingIssue(jsonContext, propertyDef.name))
|
|
79
71
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
72
|
+
continue
|
|
73
|
+
}
|
|
74
|
+
if (!propertyDef.mayBeNull && propertyValue === null) {
|
|
75
|
+
this.validationResult.issue(new Syntax_PropertyNullIssue(jsonContext, propertyDef.name))
|
|
76
|
+
continue
|
|
77
|
+
}
|
|
78
|
+
if (propertyDef.mayBeNull && propertyValue === null) {
|
|
79
|
+
// Ok, stop checking, continue with next property def
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
if (propertyDef.isList) {
|
|
83
|
+
// Check whether value is an array
|
|
84
|
+
if (!Array.isArray(propertyValue)) {
|
|
85
|
+
const newContext = jsonContext.concat(propertyDef.name)
|
|
86
|
+
this.validationResult.issue(new Syntax_PropertyTypeIssue(newContext, propertyDef.name, "array", typeof propertyValue))
|
|
87
|
+
return
|
|
83
88
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.validationResult.issue(new
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const newContext = jsonContext.concat(propertyDef.property, index)
|
|
94
|
-
if (item === null) {
|
|
95
|
-
this.validationResult.issue(new Syntax_ArrayContainsNull_Issue(newContext, propertyDef.property, index))
|
|
96
|
-
} else {
|
|
97
|
-
if (expectedTypeDef !== undefined) {
|
|
98
|
-
if (isPrimitiveDefinition(expectedTypeDef)) {
|
|
99
|
-
// propertyValue should be a primitive as it has no property definitions
|
|
100
|
-
if (this.validatePrimitiveValue(propertyDef.property, expectedTypeDef, item, jsonContext)) {
|
|
101
|
-
validator.apply(null, [item, this.validationResult, newContext, propertyDef])
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
// propertyValue should be an object, validate its properties
|
|
105
|
-
this.validateObjectProperties(propertyDef.property, expectedTypeDef, item as UnknownObjectType, newContext)
|
|
89
|
+
// If an array, validate every item in the array
|
|
90
|
+
(propertyValue as UnknownObjectType[]).forEach((item, index) => {
|
|
91
|
+
const newContext = jsonContext.concat(propertyDef.name, index)
|
|
92
|
+
if (item === null) {
|
|
93
|
+
this.validationResult.issue(new Syntax_ArrayContainsNull_Issue(newContext, propertyDef.name, index))
|
|
94
|
+
} else {
|
|
95
|
+
if (expectedTypeDef !== undefined) {
|
|
96
|
+
if (isPrimitiveDefinition(expectedTypeDef)) {
|
|
97
|
+
if (this.validatePrimitiveValue(propertyDef.name, expectedTypeDef, item, jsonContext)) {
|
|
106
98
|
validator.apply(null, [item, this.validationResult, newContext, propertyDef])
|
|
107
99
|
}
|
|
108
100
|
} else {
|
|
109
|
-
|
|
101
|
+
// propertyValue should be an object, validate its properties
|
|
102
|
+
this.validateObjectProperties(propertyDef.name, expectedTypeDef, item as UnknownObjectType, newContext)
|
|
103
|
+
validator.apply(null, [item, this.validationResult, newContext, propertyDef])
|
|
110
104
|
}
|
|
105
|
+
} else {
|
|
106
|
+
throw new Error(`Expected type '${propertyDef.type} has neither property defs, nor a validator.`)
|
|
111
107
|
}
|
|
112
|
-
})
|
|
113
|
-
} else {
|
|
114
|
-
const newContext = jsonContext.concat(propertyDef.property)
|
|
115
|
-
if (Array.isArray(propertyValue)) {
|
|
116
|
-
this.validationResult.issue(new Syntax_PropertyTypeIssue(newContext, propertyDef.property, propertyDef.expectedType, "array"))
|
|
117
|
-
return
|
|
118
108
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
109
|
+
})
|
|
110
|
+
} else {
|
|
111
|
+
const newContext = jsonContext.concat(propertyDef.name)
|
|
112
|
+
if (Array.isArray(propertyValue)) {
|
|
113
|
+
this.validationResult.issue(new Syntax_PropertyTypeIssue(newContext, propertyDef.name, propertyDef.type, "array"))
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
// Single valued property, validate it
|
|
117
|
+
if (expectedTypeDef !== undefined) {
|
|
118
|
+
if (isPrimitiveDefinition(expectedTypeDef)) {
|
|
119
|
+
// propertyValue should be a primitive as it has no property definitions
|
|
120
|
+
if (this.validatePrimitiveValue(propertyDef.name, expectedTypeDef, propertyValue, jsonContext)) {
|
|
129
121
|
validator.apply(null, [propertyValue, this.validationResult, newContext, propertyDef])
|
|
130
|
-
} else {
|
|
131
|
-
throw new Error("EXPECTING ObjectDefinition or PrimitiveDefinition, but got something else")
|
|
132
122
|
}
|
|
123
|
+
} else if (isObjectDefinition(expectedTypeDef)) {
|
|
124
|
+
// propertyValue should be an object, validate its properties
|
|
125
|
+
this.validateObjectProperties(propertyDef.name, expectedTypeDef, propertyValue as UnknownObjectType, newContext)
|
|
126
|
+
validator.apply(null, [propertyValue, this.validationResult, newContext, propertyDef])
|
|
133
127
|
} else {
|
|
134
|
-
throw new Error(
|
|
128
|
+
throw new Error("EXPECTING ObjectDefinition or PrimitiveDefinition, but got something else")
|
|
135
129
|
}
|
|
130
|
+
} else {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Expected single type '${propertyDef.type}' for '${propertyDef.name}' at ${newContext.toString()} has neither property defs, nor a validator.`
|
|
133
|
+
)
|
|
136
134
|
}
|
|
137
135
|
}
|
|
138
|
-
|
|
136
|
+
}
|
|
137
|
+
this.checkStrayProperties(object, typeDef, jsonContext)
|
|
139
138
|
}
|
|
140
|
-
|
|
141
|
-
validatePrimitiveValue(propertyName: string, propDef: PrimitiveDefinition, object: unknown, jsonContext: JsonContext): boolean {
|
|
142
|
-
// if (!propDef.mayBeNull && (object === null || object === undefined)) {
|
|
143
|
-
// this.validationResult.issue(new Syntax_PropertyNullIssue(jsonContext, propDef.property))
|
|
144
|
-
// return false
|
|
145
|
-
// }
|
|
146
139
|
|
|
140
|
+
validatePrimitiveValue(propertyName: string, propDef: PrimitiveDefinition, object: unknown, jsonContext: JsonContext): boolean {
|
|
147
141
|
if (typeof object !== propDef.primitiveType) {
|
|
148
|
-
this.validationResult.issue(new Syntax_PropertyTypeIssue(jsonContext, propertyName, propDef.primitiveType,typeof object))
|
|
142
|
+
this.validationResult.issue(new Syntax_PropertyTypeIssue(jsonContext, propertyName, propDef.primitiveType, typeof object))
|
|
149
143
|
return false
|
|
150
144
|
}
|
|
151
145
|
propDef.validate!(object, this.validationResult, jsonContext)
|
|
@@ -160,8 +154,8 @@ export class SyntaxValidator {
|
|
|
160
154
|
*/
|
|
161
155
|
checkStrayProperties(obj: UnknownObjectType, def: ObjectDefinition, context: JsonContext) {
|
|
162
156
|
const own = Object.getOwnPropertyNames(obj)
|
|
163
|
-
const defined = def.map(pdef => pdef.
|
|
164
|
-
own.forEach(
|
|
157
|
+
const defined = def.properties.map(pdef => pdef.name)
|
|
158
|
+
own.forEach(ownProp => {
|
|
165
159
|
if (!defined.includes(ownProp)) {
|
|
166
160
|
this.validationResult.issue(new Syntax_PropertyUnknownIssue(context, ownProp))
|
|
167
161
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Definition, PrimitiveDefinition, TaggedUnionDefinition } from "./ValidationTypes.js"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A collection of object and primitive definitions describing JSON objects.
|
|
5
|
+
* Used to
|
|
6
|
+
* - validate an incoming JSON object
|
|
7
|
+
* - generate the corresponding TypeScript type definitions
|
|
8
|
+
* - generate handlers for the JSOn objects (in @lionweb/server)
|
|
9
|
+
*/
|
|
10
|
+
export class DefinitionSchema {
|
|
11
|
+
unionDefinition: TaggedUnionDefinition | undefined
|
|
12
|
+
/**
|
|
13
|
+
* Mapping from extenden object type name to list of extending Object Definitions
|
|
14
|
+
*/
|
|
15
|
+
definitionsMap: Map<string, Definition> = new Map<string, Definition>()
|
|
16
|
+
|
|
17
|
+
constructor(definitions: Definition[], taggedUnion?: TaggedUnionDefinition) {
|
|
18
|
+
this.add(definitions)
|
|
19
|
+
this.unionDefinition = taggedUnion
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getDefinition(name: string): Definition | undefined {
|
|
23
|
+
return this.definitionsMap.get(name)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
add(definitions :Definition[] | Definition) {
|
|
27
|
+
if (!Array.isArray(definitions)) {
|
|
28
|
+
definitions = [definitions]
|
|
29
|
+
}
|
|
30
|
+
for(const def of definitions) {
|
|
31
|
+
this.definitionsMap.set(def.name, def)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
isTagProperty(propertyName: string): boolean {
|
|
36
|
+
return this.unionDefinition?.unionProperty === propertyName
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
definitions(): Definition[] {
|
|
40
|
+
return Array.from(this.definitionsMap.values())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
isUnionDiscriminator(propDef: PrimitiveDefinition): boolean {
|
|
44
|
+
return this.unionDefinition?.unionDiscriminator === propDef.name
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
joinDefinitions(...schema: DefinitionSchema[]): void {
|
|
48
|
+
schema.forEach(sch => {
|
|
49
|
+
this.add(sch.definitions())
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|