@toa.io/norm 1.0.0-alpha.4 → 1.0.0-alpha.41
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 +7 -7
- package/src/.component/.expand/version.js +35 -9
- package/src/.component/.normalize/operations.js +1 -1
- package/src/.component/defaults.js +14 -2
- package/src/.component/expand.js +3 -2
- package/src/.component/schema.yaml +23 -8
- package/src/.context/schema.yaml +2 -1
- package/src/component.js +5 -5
- package/test/component/validate.test.js +7 -5
- 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.41",
|
|
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,11 @@
|
|
|
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/schema": "1.0.0-alpha.
|
|
26
|
-
"@toa.io/schemas": "1.0.0-alpha.
|
|
27
|
-
"@toa.io/yaml": "1.0.0-alpha.
|
|
23
|
+
"@toa.io/core": "1.0.0-alpha.41",
|
|
24
|
+
"@toa.io/generic": "1.0.0-alpha.41",
|
|
25
|
+
"@toa.io/schema": "1.0.0-alpha.41",
|
|
26
|
+
"@toa.io/schemas": "1.0.0-alpha.41",
|
|
27
|
+
"@toa.io/yaml": "1.0.0-alpha.41"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "3b338a3f21ff9113cefa75d7789d9267917d41e3"
|
|
30
30
|
}
|
|
@@ -1,19 +1,45 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const { join } = require('node:path')
|
|
4
|
+
const { createHash } = require('node:crypto')
|
|
5
|
+
const fs = require('node:fs/promises')
|
|
6
|
+
const { createReadStream } = require('node:fs')
|
|
7
|
+
const { once } = require('node:events')
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
async function version (manifest) {
|
|
10
|
+
manifest.version ??= await hash(manifest.path)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function hash (path) {
|
|
14
|
+
const hash = await hashd(path)
|
|
15
|
+
|
|
16
|
+
return hash.digest('hex').slice(0, 8)
|
|
17
|
+
}
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} path
|
|
21
|
+
* @param {import('node:crypto').Hash} hash
|
|
22
|
+
*/
|
|
23
|
+
async function hashd (path, hash = createHash('sha256')) {
|
|
24
|
+
const stat = await fs.stat(path)
|
|
13
25
|
|
|
14
|
-
|
|
26
|
+
if (stat.isFile()) {
|
|
27
|
+
const stream = createReadStream(path)
|
|
28
|
+
|
|
29
|
+
stream.pipe(hash, { end: false })
|
|
30
|
+
|
|
31
|
+
return await once(stream, 'end')
|
|
15
32
|
}
|
|
16
33
|
|
|
34
|
+
if (stat.isDirectory()) {
|
|
35
|
+
const entries = await fs.opendir(path)
|
|
36
|
+
|
|
37
|
+
for await (const entry of entries) {
|
|
38
|
+
await hashd(join(path, entry.name), hash)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return hash
|
|
42
|
+
}
|
|
17
43
|
}
|
|
18
44
|
|
|
19
45
|
exports.version = version
|
|
@@ -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
|
|
@@ -4,8 +4,11 @@ const { hash } = require('@toa.io/generic')
|
|
|
4
4
|
const assert = require('node:assert')
|
|
5
5
|
|
|
6
6
|
// these defaults are required before validation
|
|
7
|
-
const defaults = (manifest) => {
|
|
8
|
-
if (manifest.name === undefined)
|
|
7
|
+
const defaults = (manifest, proto) => {
|
|
8
|
+
if (manifest.name === undefined)
|
|
9
|
+
if (proto) manifest.name = protoName(manifest)
|
|
10
|
+
else nameAfterDir(manifest)
|
|
11
|
+
|
|
9
12
|
if (manifest.bindings === undefined) manifest.bindings = ['@toa.io/bindings.amqp']
|
|
10
13
|
if (manifest.bridge === undefined) manifest.bridge = '@toa.io/bridges.node'
|
|
11
14
|
|
|
@@ -24,4 +27,13 @@ function protoName (manifest) {
|
|
|
24
27
|
return 'proto' + hash(manifest.path)
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
function nameAfterDir (manifest) {
|
|
31
|
+
const parts = manifest.path.split('/')
|
|
32
|
+
const dirname = parts[parts.length - 1]
|
|
33
|
+
const [name, namespace] = dirname.split('.').reverse()
|
|
34
|
+
|
|
35
|
+
manifest.name = name
|
|
36
|
+
manifest.namespace = namespace
|
|
37
|
+
}
|
|
38
|
+
|
|
27
39
|
exports.defaults = defaults
|
package/src/.component/expand.js
CHANGED
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
version
|
|
12
12
|
} = require('./.expand')
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
async function expand (manifest) {
|
|
15
15
|
entity(manifest)
|
|
16
16
|
bridge(manifest)
|
|
17
17
|
operations(manifest)
|
|
@@ -19,7 +19,8 @@ const expand = (manifest) => {
|
|
|
19
19
|
receivers(manifest)
|
|
20
20
|
properties(manifest)
|
|
21
21
|
extensions(manifest)
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
await version(manifest)
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
exports.expand = expand
|
|
@@ -79,8 +79,24 @@ properties:
|
|
|
79
79
|
propertyNames:
|
|
80
80
|
oneOf:
|
|
81
81
|
- $ref: '#/definitions/name'
|
|
82
|
-
- enum: [_version]
|
|
83
|
-
|
|
82
|
+
- enum: [_version, _created, _updated, _deleted]
|
|
83
|
+
unique:
|
|
84
|
+
type: object
|
|
85
|
+
patternProperties:
|
|
86
|
+
'.*':
|
|
87
|
+
type: array
|
|
88
|
+
items:
|
|
89
|
+
type: string
|
|
90
|
+
index:
|
|
91
|
+
type: object
|
|
92
|
+
patternProperties:
|
|
93
|
+
'.*':
|
|
94
|
+
type: object
|
|
95
|
+
patternProperties:
|
|
96
|
+
'.*':
|
|
97
|
+
type: string
|
|
98
|
+
enum: [asc, desc, hash]
|
|
99
|
+
associated:
|
|
84
100
|
type: boolean
|
|
85
101
|
default: false
|
|
86
102
|
custom:
|
|
@@ -109,7 +125,7 @@ properties:
|
|
|
109
125
|
type:
|
|
110
126
|
enum: [transition, observation, assignment, computation, effect]
|
|
111
127
|
scope:
|
|
112
|
-
enum: [object, objects, changeset, none]
|
|
128
|
+
enum: [object, objects, changeset, stream, none]
|
|
113
129
|
concurrency:
|
|
114
130
|
enum: [none, retry]
|
|
115
131
|
forward:
|
|
@@ -158,7 +174,7 @@ properties:
|
|
|
158
174
|
then:
|
|
159
175
|
properties:
|
|
160
176
|
scope:
|
|
161
|
-
enum: [object, objects, none]
|
|
177
|
+
enum: [object, objects, stream, none]
|
|
162
178
|
query:
|
|
163
179
|
not:
|
|
164
180
|
const: false
|
|
@@ -189,11 +205,8 @@ properties:
|
|
|
189
205
|
then:
|
|
190
206
|
properties:
|
|
191
207
|
scope:
|
|
192
|
-
const: none
|
|
193
208
|
default: none
|
|
194
|
-
|
|
195
|
-
const: false
|
|
196
|
-
default: false
|
|
209
|
+
enum: [object, objects, stream, none]
|
|
197
210
|
additionalProperties: false
|
|
198
211
|
additionalProperties: false
|
|
199
212
|
|
|
@@ -244,6 +257,8 @@ properties:
|
|
|
244
257
|
adaptive:
|
|
245
258
|
type: boolean
|
|
246
259
|
default: false
|
|
260
|
+
arguments:
|
|
261
|
+
type: array
|
|
247
262
|
required: [operation]
|
|
248
263
|
additionalProperties: false
|
|
249
264
|
|
package/src/.context/schema.yaml
CHANGED
|
@@ -11,6 +11,7 @@ properties:
|
|
|
11
11
|
type: string
|
|
12
12
|
packages:
|
|
13
13
|
type: string
|
|
14
|
+
default: components/*
|
|
14
15
|
build:
|
|
15
16
|
type: object
|
|
16
17
|
properties:
|
|
@@ -64,5 +65,5 @@ properties:
|
|
|
64
65
|
required: [name, components]
|
|
65
66
|
annotations:
|
|
66
67
|
type: object
|
|
67
|
-
required: [runtime, name,
|
|
68
|
+
required: [runtime, name, registry]
|
|
68
69
|
additionalProperties: false
|
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,7 +29,7 @@ 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)
|
|
@@ -37,13 +37,13 @@ const load = async (path, base) => {
|
|
|
37
37
|
|
|
38
38
|
manifest.path = path
|
|
39
39
|
|
|
40
|
-
defaults(manifest)
|
|
41
|
-
expand(manifest)
|
|
40
|
+
defaults(manifest, proto)
|
|
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
|
}
|
|
@@ -112,15 +112,18 @@ describe('entity', () => {
|
|
|
112
112
|
})
|
|
113
113
|
|
|
114
114
|
it('should allow default id', () => {
|
|
115
|
-
manifest.entity.schema.properties.id = {
|
|
115
|
+
manifest.entity.schema.properties.id = {
|
|
116
|
+
type: 'string',
|
|
117
|
+
pattern: '^[a-fA-F0-9]+$'
|
|
118
|
+
}
|
|
116
119
|
expect(() => validate(manifest)).not.toThrow()
|
|
117
120
|
})
|
|
118
121
|
})
|
|
119
122
|
|
|
120
|
-
describe('
|
|
123
|
+
describe('associated', () => {
|
|
121
124
|
it('should provide default', () => {
|
|
122
125
|
expect(() => validate(manifest)).not.toThrow()
|
|
123
|
-
expect(manifest.entity.
|
|
126
|
+
expect(manifest.entity.associated).toBe(false)
|
|
124
127
|
})
|
|
125
128
|
})
|
|
126
129
|
})
|
|
@@ -173,8 +176,7 @@ describe('operations', () => {
|
|
|
173
176
|
})
|
|
174
177
|
|
|
175
178
|
it.each([
|
|
176
|
-
['computation', 'compute']
|
|
177
|
-
['effect', 'affect']
|
|
179
|
+
['computation', 'compute']
|
|
178
180
|
])('should set query: false for %s', async (_, operation) => {
|
|
179
181
|
validate(manifest)
|
|
180
182
|
|
|
@@ -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', () => {
|