@toa.io/norm 1.0.0-alpha.8 → 1.0.0-alpha.81
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/package.json +6 -7
- package/src/.component/.normalize/operations.js +1 -1
- package/src/.component/defaults.js +14 -3
- package/src/.component/dereference.js +6 -1
- package/src/.component/extensions.js +8 -1
- package/src/.component/schema.yaml +26 -18
- package/src/.component/validate.js +3 -3
- package/src/.context/.dependencies/resolve.js +9 -0
- package/src/.context/schema.yaml +8 -4
- package/src/.context/validate.js +2 -5
- package/src/component.js +5 -5
- package/src/shortcuts.js +2 -1
- package/test/component/validate.test.js +13 -13
- package/test/context/validate.test.js +3 -2
- package/types/component.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/norm",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.81",
|
|
4
4
|
"description": "Toa declarations normalization and validation",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -20,11 +20,10 @@
|
|
|
20
20
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@toa.io/core": "1.0.0-alpha.
|
|
24
|
-
"@toa.io/generic": "1.0.0-alpha.
|
|
25
|
-
"@toa.io/
|
|
26
|
-
"@toa.io/
|
|
27
|
-
"@toa.io/yaml": "1.0.0-alpha.8"
|
|
23
|
+
"@toa.io/core": "1.0.0-alpha.81",
|
|
24
|
+
"@toa.io/generic": "1.0.0-alpha.63",
|
|
25
|
+
"@toa.io/schemas": "1.0.0-alpha.63",
|
|
26
|
+
"@toa.io/yaml": "1.0.0-alpha.63"
|
|
28
27
|
},
|
|
29
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "99c366c07ee6a34206ecb15d46c0f53e46eb9b06"
|
|
30
29
|
}
|
|
@@ -4,7 +4,7 @@ const operations = (component) => {
|
|
|
4
4
|
if (component.operations === undefined) return
|
|
5
5
|
|
|
6
6
|
for (const [endpoint, operation] of Object.entries(component.operations)) {
|
|
7
|
-
if (operation.
|
|
7
|
+
if (operation.scope === 'none')
|
|
8
8
|
operation.query = false
|
|
9
9
|
|
|
10
10
|
if (operation.bindings === undefined) operation.bindings = component.bindings
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { hash } = require('@toa.io/generic')
|
|
4
|
-
const assert = require('node:assert')
|
|
5
4
|
|
|
6
5
|
// these defaults are required before validation
|
|
7
|
-
const defaults = (manifest) => {
|
|
8
|
-
if (manifest.name === undefined)
|
|
6
|
+
const defaults = (manifest, proto) => {
|
|
7
|
+
if (manifest.name === undefined)
|
|
8
|
+
if (proto) manifest.name = protoName(manifest)
|
|
9
|
+
else nameAfterDir(manifest)
|
|
10
|
+
|
|
9
11
|
if (manifest.bindings === undefined) manifest.bindings = ['@toa.io/bindings.amqp']
|
|
10
12
|
if (manifest.bridge === undefined) manifest.bridge = '@toa.io/bridges.node'
|
|
11
13
|
|
|
@@ -24,4 +26,13 @@ function protoName (manifest) {
|
|
|
24
26
|
return 'proto' + hash(manifest.path)
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
function nameAfterDir (manifest) {
|
|
30
|
+
const parts = manifest.path.split('/')
|
|
31
|
+
const dirname = parts[parts.length - 1]
|
|
32
|
+
const [name, namespace] = dirname.split('.').reverse()
|
|
33
|
+
|
|
34
|
+
manifest.name = name
|
|
35
|
+
manifest.namespace = namespace
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
exports.defaults = defaults
|
|
@@ -25,7 +25,12 @@ const createResolver = (properties) => (property) => {
|
|
|
25
25
|
function operations (manifest, resolver) {
|
|
26
26
|
for (const operation of Object.values(manifest.operations)) {
|
|
27
27
|
if (operation.input !== undefined) operation.input = schema(operation.input, resolver)
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
if (operation.output !== undefined)
|
|
30
|
+
if (Array.isArray(operation.output) && operation.output.length === 1)
|
|
31
|
+
operation.output = [schema(operation.output[0], resolver)]
|
|
32
|
+
else
|
|
33
|
+
operation.output = schema(operation.output, resolver)
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
// forwarding
|
|
@@ -4,7 +4,10 @@ const { directory: { find } } = require('@toa.io/filesystem')
|
|
|
4
4
|
const { resolve } = require('../shortcuts')
|
|
5
5
|
|
|
6
6
|
const extensions = (manifest) => {
|
|
7
|
-
if (manifest.extensions === undefined)
|
|
7
|
+
if (manifest.extensions === undefined)
|
|
8
|
+
manifest.extensions = PREDEFINED
|
|
9
|
+
else
|
|
10
|
+
manifest.extensions = Object.assign({}, PREDEFINED, manifest.extensions)
|
|
8
11
|
|
|
9
12
|
const extensions = manifest.extensions
|
|
10
13
|
|
|
@@ -29,4 +32,8 @@ const extensions = (manifest) => {
|
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
|
|
35
|
+
const PREDEFINED = {
|
|
36
|
+
'@toa.io/extensions.telemetry': null
|
|
37
|
+
}
|
|
38
|
+
|
|
32
39
|
exports.extensions = extensions
|
|
@@ -38,15 +38,19 @@ properties:
|
|
|
38
38
|
type: object
|
|
39
39
|
properties:
|
|
40
40
|
id:
|
|
41
|
-
|
|
41
|
+
type: string
|
|
42
|
+
pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(\.([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))$
|
|
42
43
|
label:
|
|
43
|
-
|
|
44
|
+
type: string
|
|
45
|
+
pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(-([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))*$
|
|
44
46
|
|
|
45
47
|
name:
|
|
46
|
-
|
|
48
|
+
type: string
|
|
49
|
+
pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
|
|
47
50
|
|
|
48
51
|
namespace:
|
|
49
|
-
|
|
52
|
+
type: string
|
|
53
|
+
pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
|
|
50
54
|
default: 'default'
|
|
51
55
|
not:
|
|
52
56
|
oneOf:
|
|
@@ -68,7 +72,7 @@ properties:
|
|
|
68
72
|
type: string
|
|
69
73
|
default: '@toa.io/storages.mongodb'
|
|
70
74
|
schema:
|
|
71
|
-
$ref:
|
|
75
|
+
$ref: https://json-schema.org/draft/2019-09/schema
|
|
72
76
|
type: object
|
|
73
77
|
properties:
|
|
74
78
|
type:
|
|
@@ -79,7 +83,7 @@ properties:
|
|
|
79
83
|
propertyNames:
|
|
80
84
|
oneOf:
|
|
81
85
|
- $ref: '#/definitions/name'
|
|
82
|
-
- enum: [_version]
|
|
86
|
+
- enum: [_version, _created, _updated, _deleted]
|
|
83
87
|
unique:
|
|
84
88
|
type: object
|
|
85
89
|
patternProperties:
|
|
@@ -96,7 +100,7 @@ properties:
|
|
|
96
100
|
'.*':
|
|
97
101
|
type: string
|
|
98
102
|
enum: [asc, desc, hash]
|
|
99
|
-
|
|
103
|
+
associated:
|
|
100
104
|
type: boolean
|
|
101
105
|
default: false
|
|
102
106
|
custom:
|
|
@@ -125,7 +129,7 @@ properties:
|
|
|
125
129
|
type:
|
|
126
130
|
enum: [transition, observation, assignment, computation, effect]
|
|
127
131
|
scope:
|
|
128
|
-
enum: [object, objects, changeset, none]
|
|
132
|
+
enum: [object, objects, changeset, stream, none]
|
|
129
133
|
concurrency:
|
|
130
134
|
enum: [none, retry]
|
|
131
135
|
forward:
|
|
@@ -135,9 +139,14 @@ properties:
|
|
|
135
139
|
bindings:
|
|
136
140
|
$ref: '#/properties/bindings'
|
|
137
141
|
input:
|
|
138
|
-
$ref:
|
|
142
|
+
$ref: https://json-schema.org/draft/2019-09/schema
|
|
139
143
|
output:
|
|
140
|
-
$ref:
|
|
144
|
+
$ref: https://json-schema.org/draft/2019-09/schema
|
|
145
|
+
default: { }
|
|
146
|
+
errors:
|
|
147
|
+
type: array
|
|
148
|
+
items:
|
|
149
|
+
type: string
|
|
141
150
|
query:
|
|
142
151
|
type: boolean
|
|
143
152
|
required: [type, scope, bindings]
|
|
@@ -174,7 +183,7 @@ properties:
|
|
|
174
183
|
then:
|
|
175
184
|
properties:
|
|
176
185
|
scope:
|
|
177
|
-
enum: [object, objects, none]
|
|
186
|
+
enum: [object, objects, stream, none]
|
|
178
187
|
query:
|
|
179
188
|
not:
|
|
180
189
|
const: false
|
|
@@ -205,18 +214,15 @@ properties:
|
|
|
205
214
|
then:
|
|
206
215
|
properties:
|
|
207
216
|
scope:
|
|
208
|
-
const: none
|
|
209
217
|
default: none
|
|
210
|
-
|
|
211
|
-
const: false
|
|
212
|
-
default: false
|
|
218
|
+
enum: [object, objects, stream, none]
|
|
213
219
|
additionalProperties: false
|
|
214
220
|
additionalProperties: false
|
|
215
221
|
|
|
216
222
|
events:
|
|
217
223
|
type: object
|
|
218
224
|
propertyNames:
|
|
219
|
-
$ref: '
|
|
225
|
+
$ref: '#/definitions/name'
|
|
220
226
|
patternProperties:
|
|
221
227
|
'.*':
|
|
222
228
|
type: object
|
|
@@ -243,13 +249,13 @@ properties:
|
|
|
243
249
|
type: object
|
|
244
250
|
properties:
|
|
245
251
|
operation:
|
|
246
|
-
$ref: '
|
|
252
|
+
$ref: '#/definitions/name'
|
|
247
253
|
bridge:
|
|
248
254
|
type: string
|
|
249
255
|
binding:
|
|
250
256
|
type: string
|
|
251
257
|
source:
|
|
252
|
-
$ref: '
|
|
258
|
+
$ref: '#/definitions/name'
|
|
253
259
|
not:
|
|
254
260
|
const: context
|
|
255
261
|
path:
|
|
@@ -260,6 +266,8 @@ properties:
|
|
|
260
266
|
adaptive:
|
|
261
267
|
type: boolean
|
|
262
268
|
default: false
|
|
269
|
+
arguments:
|
|
270
|
+
type: array
|
|
263
271
|
required: [operation]
|
|
264
272
|
additionalProperties: false
|
|
265
273
|
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
const path = require('node:path')
|
|
4
4
|
|
|
5
5
|
const { load } = require('@toa.io/yaml')
|
|
6
|
-
const
|
|
6
|
+
const schemas = require('@toa.io/schemas')
|
|
7
7
|
|
|
8
8
|
const object = load.sync(path.resolve(__dirname, 'schema.yaml'))
|
|
9
|
-
const schema =
|
|
9
|
+
const schema = schemas.schema(object)
|
|
10
10
|
|
|
11
11
|
const validate = (manifest) => {
|
|
12
12
|
const error = schema.fit(manifest)
|
|
13
13
|
|
|
14
|
-
if (error) throw
|
|
14
|
+
if (error) throw error
|
|
15
15
|
|
|
16
16
|
if (manifest.events !== undefined) events(manifest)
|
|
17
17
|
if (manifest.receivers !== undefined) receivers(manifest)
|
|
@@ -24,6 +24,15 @@ const resolve = (references, annotations) => {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
for (const dependency of Object.keys(annotations)) {
|
|
28
|
+
const { module } = load(dependency)
|
|
29
|
+
|
|
30
|
+
if (!module.standalone || (dependency in dependencies))
|
|
31
|
+
continue
|
|
32
|
+
|
|
33
|
+
dependencies[dependency] = []
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
return dependencies
|
|
28
37
|
}
|
|
29
38
|
|
package/src/.context/schema.yaml
CHANGED
|
@@ -6,11 +6,13 @@ properties:
|
|
|
6
6
|
version:
|
|
7
7
|
type: string
|
|
8
8
|
name:
|
|
9
|
-
|
|
9
|
+
type: string
|
|
10
|
+
pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(-([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))*$
|
|
10
11
|
description:
|
|
11
12
|
type: string
|
|
12
13
|
packages:
|
|
13
14
|
type: string
|
|
15
|
+
default: components/*
|
|
14
16
|
build:
|
|
15
17
|
type: object
|
|
16
18
|
properties:
|
|
@@ -53,16 +55,18 @@ properties:
|
|
|
53
55
|
type: object
|
|
54
56
|
properties:
|
|
55
57
|
name:
|
|
56
|
-
|
|
58
|
+
type: string
|
|
59
|
+
pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
|
|
57
60
|
image:
|
|
58
61
|
type: string
|
|
59
62
|
components:
|
|
60
63
|
type: array
|
|
61
64
|
minItems: 1
|
|
62
65
|
items:
|
|
63
|
-
|
|
66
|
+
type: string
|
|
67
|
+
pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(\.([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))$
|
|
64
68
|
required: [name, components]
|
|
65
69
|
annotations:
|
|
66
70
|
type: object
|
|
67
|
-
required: [runtime, name,
|
|
71
|
+
required: [runtime, name, registry]
|
|
68
72
|
additionalProperties: false
|
package/src/.context/validate.js
CHANGED
|
@@ -3,15 +3,12 @@
|
|
|
3
3
|
const { resolve } = require('node:path')
|
|
4
4
|
|
|
5
5
|
const { load } = require('@toa.io/yaml')
|
|
6
|
-
const
|
|
6
|
+
const schemas = require('@toa.io/schemas')
|
|
7
7
|
|
|
8
8
|
const path = resolve(__dirname, 'schema.yaml')
|
|
9
9
|
const object = load.sync(path)
|
|
10
|
-
const schema =
|
|
10
|
+
const schema = schemas.schema(object)
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* @param {toa.norm.context.Declaration} context
|
|
14
|
-
*/
|
|
15
12
|
const validate = (context) => {
|
|
16
13
|
schema.validate(context)
|
|
17
14
|
}
|
package/src/component.js
CHANGED
|
@@ -20,7 +20,7 @@ const {
|
|
|
20
20
|
const component = async (path) => {
|
|
21
21
|
const manifest = await load(path)
|
|
22
22
|
|
|
23
|
-
normalize(manifest)
|
|
23
|
+
normalize(manifest, path)
|
|
24
24
|
validate(manifest)
|
|
25
25
|
extensions(manifest)
|
|
26
26
|
|
|
@@ -29,21 +29,21 @@ const component = async (path) => {
|
|
|
29
29
|
return manifest
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const load = async (path, base) => {
|
|
32
|
+
const load = async (path, base, proto = false) => {
|
|
33
33
|
if (base !== undefined) path = find(path, base, MANIFEST)
|
|
34
34
|
|
|
35
35
|
const file = join(path, MANIFEST)
|
|
36
|
-
const manifest =
|
|
36
|
+
const manifest = await yaml(file) ?? {}
|
|
37
37
|
|
|
38
38
|
manifest.path = path
|
|
39
39
|
|
|
40
|
-
defaults(manifest)
|
|
40
|
+
defaults(manifest, proto)
|
|
41
41
|
await expand(manifest)
|
|
42
42
|
|
|
43
43
|
await merge(path, manifest)
|
|
44
44
|
|
|
45
45
|
if (manifest.prototype !== null) {
|
|
46
|
-
const prototype = await load(manifest.prototype, path)
|
|
46
|
+
const prototype = await load(manifest.prototype, path, true)
|
|
47
47
|
|
|
48
48
|
collapse(manifest, prototype)
|
|
49
49
|
}
|
package/src/shortcuts.js
CHANGED
|
@@ -50,7 +50,8 @@ const SHORTCUTS = {
|
|
|
50
50
|
configuration: '@toa.io/extensions.configuration',
|
|
51
51
|
origins: '@toa.io/extensions.origins',
|
|
52
52
|
stash: '@toa.io/extensions.stash',
|
|
53
|
-
storages: '@toa.io/extensions.storages'
|
|
53
|
+
storages: '@toa.io/extensions.storages',
|
|
54
|
+
telemetry: '@toa.io/extensions.telemetry'
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
exports.recognize = recognize
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// noinspection JSUnresolvedVariable
|
|
2
|
-
|
|
3
1
|
'use strict'
|
|
4
2
|
|
|
5
3
|
const clone = require('clone-deep')
|
|
@@ -20,13 +18,13 @@ it('should be ok', () => {
|
|
|
20
18
|
it('should provide error', () => {
|
|
21
19
|
manifest.foo = 'bar'
|
|
22
20
|
|
|
23
|
-
expect(() => validate(manifest)).toThrow(
|
|
21
|
+
expect(() => validate(manifest)).toThrow()
|
|
24
22
|
})
|
|
25
23
|
|
|
26
24
|
it('should not have additional properties', () => {
|
|
27
25
|
manifest.foo = 'bar'
|
|
28
26
|
|
|
29
|
-
expect(() => validate(manifest)).toThrow(
|
|
27
|
+
expect(() => validate(manifest)).toThrow()
|
|
30
28
|
})
|
|
31
29
|
|
|
32
30
|
describe('namespace', () => {
|
|
@@ -83,13 +81,13 @@ describe('entity', () => {
|
|
|
83
81
|
|
|
84
82
|
it('should not have additional properties', () => {
|
|
85
83
|
manifest.entity.foo = 'bar'
|
|
86
|
-
expect(() => validate(manifest)).toThrow(
|
|
84
|
+
expect(() => validate(manifest)).toThrow()
|
|
87
85
|
})
|
|
88
86
|
|
|
89
87
|
describe('schema', () => {
|
|
90
88
|
it('should be required', () => {
|
|
91
89
|
delete manifest.entity.schema
|
|
92
|
-
expect(() => validate(manifest)).toThrow(
|
|
90
|
+
expect(() => validate(manifest)).toThrow()
|
|
93
91
|
})
|
|
94
92
|
|
|
95
93
|
it('should be JSON schema object', () => {
|
|
@@ -99,7 +97,7 @@ describe('entity', () => {
|
|
|
99
97
|
|
|
100
98
|
it('should be JSON schema object of type object', () => {
|
|
101
99
|
manifest.entity.schema = { type: 'integer' }
|
|
102
|
-
expect(() => validate(manifest)).toThrow(/must be equal to constant
|
|
100
|
+
expect(() => validate(manifest)).toThrow(/must be equal to constant/)
|
|
103
101
|
|
|
104
102
|
manifest.entity.schema = {}
|
|
105
103
|
validate(manifest)
|
|
@@ -112,15 +110,18 @@ describe('entity', () => {
|
|
|
112
110
|
})
|
|
113
111
|
|
|
114
112
|
it('should allow default id', () => {
|
|
115
|
-
manifest.entity.schema.properties.id = {
|
|
113
|
+
manifest.entity.schema.properties.id = {
|
|
114
|
+
type: 'string',
|
|
115
|
+
pattern: '^[a-fA-F0-9]+$'
|
|
116
|
+
}
|
|
116
117
|
expect(() => validate(manifest)).not.toThrow()
|
|
117
118
|
})
|
|
118
119
|
})
|
|
119
120
|
|
|
120
|
-
describe('
|
|
121
|
+
describe('associated', () => {
|
|
121
122
|
it('should provide default', () => {
|
|
122
123
|
expect(() => validate(manifest)).not.toThrow()
|
|
123
|
-
expect(manifest.entity.
|
|
124
|
+
expect(manifest.entity.associated).toBe(false)
|
|
124
125
|
})
|
|
125
126
|
})
|
|
126
127
|
})
|
|
@@ -151,7 +152,7 @@ describe('operations', () => {
|
|
|
151
152
|
|
|
152
153
|
it('should not have additional properties', () => {
|
|
153
154
|
manifest.operations.get.foo = 'bar'
|
|
154
|
-
expect(() => validate(manifest)).toThrow(
|
|
155
|
+
expect(() => validate(manifest)).toThrow()
|
|
155
156
|
})
|
|
156
157
|
|
|
157
158
|
it('should have type (transition or observation)', () => {
|
|
@@ -173,8 +174,7 @@ describe('operations', () => {
|
|
|
173
174
|
})
|
|
174
175
|
|
|
175
176
|
it.each([
|
|
176
|
-
['computation', 'compute']
|
|
177
|
-
['effect', 'affect']
|
|
177
|
+
['computation', 'compute']
|
|
178
178
|
])('should set query: false for %s', async (_, operation) => {
|
|
179
179
|
validate(manifest)
|
|
180
180
|
|
|
@@ -72,9 +72,10 @@ it('should require name as label', () => {
|
|
|
72
72
|
expect(() => validate(context)).not.toThrow(/pattern/)
|
|
73
73
|
})
|
|
74
74
|
|
|
75
|
-
it('should
|
|
75
|
+
it('should set default packages location', () => {
|
|
76
76
|
delete context.packages
|
|
77
|
-
expect(() => validate(context)).toThrow(
|
|
77
|
+
expect(() => validate(context)).not.toThrow()
|
|
78
|
+
expect(context.packages).toBe('components/*')
|
|
78
79
|
})
|
|
79
80
|
|
|
80
81
|
it('should require registry url', () => {
|