@toa.io/norm 0.10.0 → 0.20.0-alpha.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/package.json +8 -10
- package/src/.component/.expand/extensions.js +3 -1
- package/src/.component/.expand/receivers.js +1 -1
- package/src/.component/.normalize/receivers.js +3 -1
- package/src/.component/collapse.js +2 -2
- package/src/.component/defaults.js +8 -10
- package/src/.component/normalize.js +0 -2
- package/src/.component/schema.yaml +26 -23
- package/src/.component/validate.js +6 -4
- package/src/.context/.dependencies/connectors.js +7 -7
- package/src/.context/.dependencies/extensions.js +44 -12
- package/src/.context/.dependencies/resolve.js +2 -8
- package/src/.context/dependencies.js +4 -7
- package/src/.context/schema.yaml +6 -0
- package/src/component.js +1 -1
- package/src/context.js +2 -5
- package/src/shortcuts.js +2 -1
- package/test/component/expand.fixtures.js +3 -3
- package/test/component/normalize.fixtures.js +6 -2
- package/test/component/normalize.test.js +17 -7
- package/test/component/validate.fixtures.js +1 -1
- package/test/component/validate.test.js +17 -11
- package/test/context/validate.fixtures.js +3 -0
- package/types/component.d.ts +51 -71
- package/types/context/declaration.d.ts +17 -0
- package/types/context.d.ts +32 -66
- package/types/index.d.ts +3 -4
- package/features/component.operations.feature +0 -54
- package/features/steps/.test/manifest.test.js +0 -111
- package/features/steps/.types/context.d.ts +0 -9
- package/features/steps/hooks.js +0 -18
- package/features/steps/manifest.js +0 -66
- package/features/steps/parameters.js +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/norm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0-alpha.0",
|
|
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",
|
|
@@ -12,21 +12,19 @@
|
|
|
12
12
|
"url": "https://github.com/toa-io/toa/issues"
|
|
13
13
|
},
|
|
14
14
|
"main": "src/index.js",
|
|
15
|
+
"types": "types/index.d.ts",
|
|
15
16
|
"publishConfig": {
|
|
16
17
|
"access": "public"
|
|
17
18
|
},
|
|
18
19
|
"scripts": {
|
|
19
20
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
20
21
|
},
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"@toa.io/mock": "0.7.6"
|
|
23
|
-
},
|
|
24
22
|
"dependencies": {
|
|
25
|
-
"@toa.io/core": "0.
|
|
26
|
-
"@toa.io/generic": "0.
|
|
27
|
-
"@toa.io/schema": "0.
|
|
28
|
-
"@toa.io/schemas": "0.
|
|
29
|
-
"@toa.io/yaml": "0.
|
|
23
|
+
"@toa.io/core": "0.20.0-alpha.0",
|
|
24
|
+
"@toa.io/generic": "0.20.0-alpha.0",
|
|
25
|
+
"@toa.io/schema": "0.20.0-alpha.0",
|
|
26
|
+
"@toa.io/schemas": "0.20.0-alpha.0",
|
|
27
|
+
"@toa.io/yaml": "0.20.0-alpha.0"
|
|
30
28
|
},
|
|
31
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "d047190899218b5249901a01a2a4caec5b34cf09"
|
|
32
30
|
}
|
|
@@ -10,7 +10,9 @@ function extensions (manifest) {
|
|
|
10
10
|
const SHORTCUTS = {
|
|
11
11
|
exposition: '@toa.io/extensions.exposition',
|
|
12
12
|
origins: '@toa.io/extensions.origins',
|
|
13
|
-
configuration: '@toa.io/extensions.configuration'
|
|
13
|
+
configuration: '@toa.io/extensions.configuration',
|
|
14
|
+
state: '@toa.io/extensions.state',
|
|
15
|
+
stash: '@toa.io/extensions.stash'
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
exports.extensions = extensions
|
|
@@ -6,7 +6,7 @@ function receivers (manifest) {
|
|
|
6
6
|
if (manifest.receivers === undefined) return
|
|
7
7
|
|
|
8
8
|
for (const [locator, receiver] of Object.entries(manifest.receivers)) {
|
|
9
|
-
if (typeof receiver === 'string') manifest.receivers[locator] = {
|
|
9
|
+
if (typeof receiver === 'string') manifest.receivers[locator] = { operation: receiver }
|
|
10
10
|
|
|
11
11
|
if (receiver.binding !== undefined) receiver.binding = resolve(receiver.binding)
|
|
12
12
|
if (receiver.bridge !== undefined) receiver.bridge = resolve(receiver.bridge)
|
|
@@ -7,8 +7,10 @@ function receivers (component) {
|
|
|
7
7
|
|
|
8
8
|
for (const [key, value] of Object.entries(receivers)) {
|
|
9
9
|
const segments = key.split('.')
|
|
10
|
+
const source = value.source ?? 'default'
|
|
10
11
|
|
|
11
|
-
if (
|
|
12
|
+
if (source !== 'default') continue
|
|
13
|
+
if (segments.length === 3) continue // already with a namespace
|
|
12
14
|
|
|
13
15
|
const newKey = 'default.' + key
|
|
14
16
|
|
|
@@ -36,9 +36,9 @@ const collapse = (manifest, prototype) => {
|
|
|
36
36
|
|
|
37
37
|
delete prototype.entity?.storage // ???
|
|
38
38
|
|
|
39
|
-
const { entity, events } = prototype
|
|
39
|
+
const { entity, events, extensions } = prototype
|
|
40
40
|
|
|
41
|
-
merge(manifest, { entity, events })
|
|
41
|
+
merge(manifest, { entity, events, extensions })
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
exports.collapse = collapse
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { hash } = require('@toa.io/generic')
|
|
4
|
+
|
|
3
5
|
// these defaults are required before validation
|
|
4
6
|
const defaults = (manifest) => {
|
|
5
7
|
if (manifest.prototype === undefined) manifest.prototype = '@toa.io/prototype'
|
|
6
|
-
|
|
7
|
-
if (manifest.bindings === undefined)
|
|
8
|
-
const local = process.env.TOA_DEV === '1'
|
|
9
|
-
|
|
10
|
-
manifest.bindings = local
|
|
11
|
-
? ['@toa.io/bindings.amqp']
|
|
12
|
-
: ['@toa.io/bindings.http', '@toa.io/bindings.amqp']
|
|
13
|
-
}
|
|
14
|
-
|
|
8
|
+
if (manifest.name === undefined) manifest.name = protoName(manifest)
|
|
9
|
+
if (manifest.bindings === undefined) manifest.bindings = ['@toa.io/bindings.amqp']
|
|
15
10
|
if (manifest.bridge === undefined) manifest.bridge = '@toa.io/bridges.node'
|
|
16
|
-
|
|
17
11
|
if (manifest.entity === null || manifest.entity === undefined) manifest.entity = { storage: null }
|
|
18
12
|
if (manifest.entity.storage === undefined) manifest.entity.storage = '@toa.io/storages.mongodb'
|
|
19
13
|
if (manifest.entity.storage === null) manifest.entity.storage = '@toa.io/storages.null'
|
|
@@ -22,4 +16,8 @@ const defaults = (manifest) => {
|
|
|
22
16
|
if (manifest.version === undefined) manifest.version = '0.0.0'
|
|
23
17
|
}
|
|
24
18
|
|
|
19
|
+
function protoName (manifest) {
|
|
20
|
+
return 'proto' + hash(manifest.path)
|
|
21
|
+
}
|
|
22
|
+
|
|
25
23
|
exports.defaults = defaults
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { convolve } = require('@toa.io/generic')
|
|
4
3
|
const { events, operations, extensions, receivers } = require('./.normalize')
|
|
5
4
|
|
|
6
5
|
const normalize = (component, environment) => {
|
|
7
|
-
convolve(component, environment)
|
|
8
6
|
operations(component)
|
|
9
7
|
events(component)
|
|
10
8
|
receivers(component)
|
|
@@ -20,7 +20,7 @@ properties:
|
|
|
20
20
|
operations:
|
|
21
21
|
type: object
|
|
22
22
|
propertyNames:
|
|
23
|
-
$ref: 'definitions#/definitions/
|
|
23
|
+
$ref: 'definitions#/definitions/name'
|
|
24
24
|
patternProperties:
|
|
25
25
|
'.*':
|
|
26
26
|
type: object
|
|
@@ -39,14 +39,15 @@ properties:
|
|
|
39
39
|
label:
|
|
40
40
|
$ref: 'definitions#/definitions/label'
|
|
41
41
|
|
|
42
|
+
name:
|
|
43
|
+
$ref: 'definitions#/definitions/token'
|
|
44
|
+
|
|
42
45
|
namespace:
|
|
43
46
|
$ref: 'definitions#/definitions/token'
|
|
44
47
|
default: 'default'
|
|
45
48
|
not:
|
|
46
49
|
oneOf:
|
|
47
50
|
- const: 'system'
|
|
48
|
-
name:
|
|
49
|
-
$ref: 'definitions#/definitions/token'
|
|
50
51
|
|
|
51
52
|
version:
|
|
52
53
|
$ref: 'definitions#/definitions/version'
|
|
@@ -67,12 +68,12 @@ properties:
|
|
|
67
68
|
type: object
|
|
68
69
|
propertyNames:
|
|
69
70
|
oneOf:
|
|
70
|
-
- $ref: 'definitions#/definitions/
|
|
71
|
-
- enum: [
|
|
71
|
+
- $ref: 'definitions#/definitions/name'
|
|
72
|
+
- enum: [_version]
|
|
72
73
|
initialized:
|
|
73
74
|
type: boolean
|
|
74
75
|
default: false
|
|
75
|
-
required: [
|
|
76
|
+
required: [schema]
|
|
76
77
|
additionalProperties: false
|
|
77
78
|
|
|
78
79
|
bindings:
|
|
@@ -88,19 +89,19 @@ properties:
|
|
|
88
89
|
operations:
|
|
89
90
|
type: object
|
|
90
91
|
propertyNames:
|
|
91
|
-
$ref: 'definitions#/definitions/
|
|
92
|
+
$ref: 'definitions#/definitions/name'
|
|
92
93
|
patternProperties:
|
|
93
94
|
'.*':
|
|
94
95
|
type: object
|
|
95
96
|
properties:
|
|
96
97
|
type:
|
|
97
|
-
enum: [
|
|
98
|
+
enum: [transition, observation, assignment, computation, effect]
|
|
98
99
|
scope:
|
|
99
|
-
enum: [
|
|
100
|
+
enum: [object, objects, changeset, none]
|
|
100
101
|
concurrency:
|
|
101
|
-
enum: [
|
|
102
|
+
enum: [none, retry]
|
|
102
103
|
forward:
|
|
103
|
-
$ref: 'definitions#/definitions/
|
|
104
|
+
$ref: 'definitions#/definitions/name'
|
|
104
105
|
bridge:
|
|
105
106
|
type: string
|
|
106
107
|
bindings:
|
|
@@ -111,7 +112,7 @@ properties:
|
|
|
111
112
|
$ref: 'definitions#/definitions/schema'
|
|
112
113
|
query:
|
|
113
114
|
type: boolean
|
|
114
|
-
required: [
|
|
115
|
+
required: [type, scope, bindings]
|
|
115
116
|
allOf:
|
|
116
117
|
- if: # transition
|
|
117
118
|
properties:
|
|
@@ -120,15 +121,15 @@ properties:
|
|
|
120
121
|
then:
|
|
121
122
|
properties:
|
|
122
123
|
scope:
|
|
123
|
-
enum: [
|
|
124
|
+
enum: [object]
|
|
124
125
|
if: # transition query: false
|
|
125
126
|
not:
|
|
126
127
|
properties:
|
|
127
128
|
query:
|
|
128
129
|
const: false
|
|
129
|
-
required: [
|
|
130
|
+
required: [query]
|
|
130
131
|
then:
|
|
131
|
-
required: [
|
|
132
|
+
required: [concurrency]
|
|
132
133
|
- if: # not transition
|
|
133
134
|
not:
|
|
134
135
|
properties:
|
|
@@ -145,7 +146,7 @@ properties:
|
|
|
145
146
|
then:
|
|
146
147
|
properties:
|
|
147
148
|
scope:
|
|
148
|
-
enum: [
|
|
149
|
+
enum: [object, objects, none]
|
|
149
150
|
query:
|
|
150
151
|
not:
|
|
151
152
|
const: false
|
|
@@ -156,7 +157,7 @@ properties:
|
|
|
156
157
|
then:
|
|
157
158
|
properties:
|
|
158
159
|
scope:
|
|
159
|
-
enum: [
|
|
160
|
+
enum: [changeset]
|
|
160
161
|
- if: # computation
|
|
161
162
|
properties:
|
|
162
163
|
type:
|
|
@@ -181,7 +182,7 @@ properties:
|
|
|
181
182
|
events:
|
|
182
183
|
type: object
|
|
183
184
|
propertyNames:
|
|
184
|
-
$ref: 'definitions#/definitions/
|
|
185
|
+
$ref: 'definitions#/definitions/name'
|
|
185
186
|
patternProperties:
|
|
186
187
|
'.*':
|
|
187
188
|
type: object
|
|
@@ -198,7 +199,7 @@ properties:
|
|
|
198
199
|
subjective:
|
|
199
200
|
type: boolean
|
|
200
201
|
default: false
|
|
201
|
-
required: [
|
|
202
|
+
required: [bridge, path]
|
|
202
203
|
additionalProperties: false
|
|
203
204
|
|
|
204
205
|
receivers:
|
|
@@ -207,14 +208,16 @@ properties:
|
|
|
207
208
|
'.*':
|
|
208
209
|
type: object
|
|
209
210
|
properties:
|
|
210
|
-
|
|
211
|
-
$ref: 'definitions#/definitions/
|
|
211
|
+
operation:
|
|
212
|
+
$ref: 'definitions#/definitions/name'
|
|
212
213
|
bridge:
|
|
213
214
|
type: string
|
|
214
215
|
binding:
|
|
215
216
|
type: string
|
|
216
217
|
source:
|
|
217
|
-
$ref: 'definitions#/definitions/
|
|
218
|
+
$ref: 'definitions#/definitions/name'
|
|
219
|
+
not:
|
|
220
|
+
const: context
|
|
218
221
|
path:
|
|
219
222
|
type: string
|
|
220
223
|
conditioned:
|
|
@@ -223,7 +226,7 @@ properties:
|
|
|
223
226
|
adaptive:
|
|
224
227
|
type: boolean
|
|
225
228
|
default: false
|
|
226
|
-
required: [
|
|
229
|
+
required: [operation]
|
|
227
230
|
additionalProperties: false
|
|
228
231
|
|
|
229
232
|
extensions:
|
|
@@ -27,14 +27,16 @@ const events = (manifest) => {
|
|
|
27
27
|
|
|
28
28
|
const receivers = (manifest) => {
|
|
29
29
|
for (const [locator, receiver] of Object.entries(manifest.receivers)) {
|
|
30
|
-
if (manifest.operations?.[receiver.
|
|
31
|
-
throw new Error(`Receiver '${locator}' refers to undefined
|
|
30
|
+
if (manifest.operations?.[receiver.operation] === undefined) {
|
|
31
|
+
throw new Error(`Receiver '${locator}' refers to undefined operation '${receiver.operation}'`)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
if (manifest.operations[receiver.
|
|
35
|
-
throw new Error(`Receiver '${locator}'
|
|
34
|
+
if (!TYPES.has(manifest.operations[receiver.operation].type)) {
|
|
35
|
+
throw new Error(`Receiver '${locator}' must refer to an operation of one of the allowed types: ${Array.from(TYPES).join(', ')}`)
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
const TYPES = new Set(['transition', 'effect'])
|
|
41
|
+
|
|
40
42
|
exports.validate = validate
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* @param {toa.norm.Context} context
|
|
5
|
-
* @returns {toa.norm.context.dependencies.References}
|
|
6
|
-
*/
|
|
7
|
-
const connectors = (context) => {
|
|
8
|
-
/** @type {toa.norm.context.dependencies.References} */
|
|
3
|
+
const connectors = (context, extracted) => {
|
|
9
4
|
const connectors = {}
|
|
10
5
|
|
|
11
|
-
|
|
6
|
+
const components = (context.components === undefined
|
|
7
|
+
? extracted
|
|
8
|
+
: context.components.concat(extracted)
|
|
9
|
+
) ?? []
|
|
10
|
+
|
|
11
|
+
for (const component of components) {
|
|
12
12
|
if (connectors[component.entity.storage] === undefined) {
|
|
13
13
|
connectors[component.entity.storage] = []
|
|
14
14
|
}
|
|
@@ -1,24 +1,56 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* @param {toa.norm.Context} context
|
|
5
|
-
* @returns {toa.norm.context.dependencies.References}
|
|
6
|
-
*/
|
|
7
|
-
const extensions = (context) => {
|
|
8
|
-
/** @type {toa.norm.context.dependencies.References} */
|
|
3
|
+
const extensions = async (context) => {
|
|
9
4
|
const extensions = {}
|
|
5
|
+
const components = context.components?.slice() ?? []
|
|
6
|
+
const extracted = await extractExtensionComponents(components, extensions)
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
if (component.extensions !== undefined) {
|
|
13
|
-
for (const reference of Object.keys(component.extensions)) {
|
|
14
|
-
if (extensions[reference] === undefined) extensions[reference] = []
|
|
8
|
+
components.push(...extracted)
|
|
15
9
|
|
|
16
|
-
|
|
10
|
+
for (const component of components) {
|
|
11
|
+
if (component.extensions === undefined) continue
|
|
12
|
+
|
|
13
|
+
for (const reference of Object.keys(component.extensions)) {
|
|
14
|
+
if (extensions[reference] === undefined) extensions[reference] = []
|
|
15
|
+
|
|
16
|
+
extensions[reference].push(component)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return { extensions, components: extracted }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function extractExtensionComponents (components, extensions) {
|
|
24
|
+
const { component: load } = require('../../component')
|
|
25
|
+
|
|
26
|
+
const extracted = []
|
|
27
|
+
|
|
28
|
+
for (const component of components) {
|
|
29
|
+
if (component.extensions === undefined) continue
|
|
30
|
+
|
|
31
|
+
for (const reference of Object.keys(component.extensions)) {
|
|
32
|
+
if (reference in extensions) continue
|
|
33
|
+
|
|
34
|
+
extensions[reference] = []
|
|
35
|
+
|
|
36
|
+
const mod = require(reference)
|
|
37
|
+
|
|
38
|
+
if (mod.components === undefined) continue
|
|
39
|
+
|
|
40
|
+
for (const path of mod.components().paths) {
|
|
41
|
+
const component = await load(path)
|
|
42
|
+
|
|
43
|
+
extracted.push(component)
|
|
17
44
|
}
|
|
18
45
|
}
|
|
19
46
|
}
|
|
20
47
|
|
|
21
|
-
|
|
48
|
+
if (extracted.length === 0)
|
|
49
|
+
return extracted
|
|
50
|
+
|
|
51
|
+
const deeper = await extractExtensionComponents(extracted, extensions)
|
|
52
|
+
|
|
53
|
+
return extracted.concat(deeper)
|
|
22
54
|
}
|
|
23
55
|
|
|
24
56
|
exports.extensions = extensions
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { join } = require('node:path')
|
|
4
3
|
const { load } = require('./load')
|
|
5
4
|
|
|
6
|
-
/**
|
|
7
|
-
* @param {toa.norm.context.dependencies.References} references
|
|
8
|
-
* @param {Object} annotations
|
|
9
|
-
* @returns {toa.norm.context.Dependencies}
|
|
10
|
-
*/
|
|
11
5
|
const resolve = (references, annotations) => {
|
|
12
|
-
/** @type {toa.norm.context.Dependencies} */
|
|
13
6
|
const dependencies = {}
|
|
14
7
|
|
|
15
8
|
for (const [dependency, components] of Object.entries(references)) {
|
|
@@ -18,7 +11,8 @@ const resolve = (references, annotations) => {
|
|
|
18
11
|
|
|
19
12
|
const instances = components.map((component) => ({
|
|
20
13
|
locator: component.locator,
|
|
21
|
-
manifest: component.extensions?.[id]
|
|
14
|
+
manifest: component.extensions?.[id],
|
|
15
|
+
component
|
|
22
16
|
}))
|
|
23
17
|
|
|
24
18
|
dependencies[dependency] = instances
|
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const { connectors, extensions, resolve } = require('./.dependencies')
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const dependencies = (context) => {
|
|
10
|
-
/** @type {toa.norm.context.dependencies.References} */
|
|
11
|
-
const references = { ...connectors(context), ...extensions(context) }
|
|
5
|
+
const dependencies = async (context) => {
|
|
6
|
+
const { extensions: e, components } = await extensions(context)
|
|
7
|
+
const c = connectors(context, components)
|
|
8
|
+
const references = { ...c, ...e }
|
|
12
9
|
|
|
13
10
|
return resolve(references, context.annotations)
|
|
14
11
|
}
|
package/src/.context/schema.yaml
CHANGED
package/src/component.js
CHANGED
|
@@ -35,7 +35,7 @@ const load = async (path, base) => {
|
|
|
35
35
|
if (base !== undefined) path = find(path, base, MANIFEST)
|
|
36
36
|
|
|
37
37
|
const file = join(path, MANIFEST)
|
|
38
|
-
const manifest = /** @type {toa.norm.Component} */ await yaml(file)
|
|
38
|
+
const manifest = /** @type {toa.norm.Component} */ await yaml(file) ?? {}
|
|
39
39
|
|
|
40
40
|
manifest.path = path
|
|
41
41
|
|
package/src/context.js
CHANGED
|
@@ -16,10 +16,7 @@ const {
|
|
|
16
16
|
validate
|
|
17
17
|
} = require('./.context')
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
* @type {toa.norm.context.Constructor}
|
|
21
|
-
*/
|
|
22
|
-
const context = async (root, environment = undefined) => {
|
|
19
|
+
const context = async (root, environment = process.env.TOA_ENV) => {
|
|
23
20
|
const path = resolve(root, CONTEXT)
|
|
24
21
|
const context = /** @type {toa.norm.Context} */ await load(path)
|
|
25
22
|
const pattern = resolve(root, context.packages)
|
|
@@ -35,7 +32,7 @@ const context = async (root, environment = undefined) => {
|
|
|
35
32
|
const paths = await glob(pattern)
|
|
36
33
|
|
|
37
34
|
context.components = await Promise.all(paths.map(component))
|
|
38
|
-
context.dependencies = dependencies(context)
|
|
35
|
+
context.dependencies = await dependencies(context)
|
|
39
36
|
|
|
40
37
|
dereference(context)
|
|
41
38
|
complete(context)
|
package/src/shortcuts.js
CHANGED
|
@@ -47,7 +47,8 @@ const SHORTCUTS = {
|
|
|
47
47
|
queues: '@toa.io/storages.queues',
|
|
48
48
|
exposition: '@toa.io/extensions.exposition',
|
|
49
49
|
configuration: '@toa.io/extensions.configuration',
|
|
50
|
-
origins: '@toa.io/extensions.origins'
|
|
50
|
+
origins: '@toa.io/extensions.origins',
|
|
51
|
+
stash: '@toa.io/extensions.stash'
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
exports.recognize = recognize
|
|
@@ -53,7 +53,7 @@ const source = {
|
|
|
53
53
|
two: {
|
|
54
54
|
binding: 'amqp',
|
|
55
55
|
bridge: 'node',
|
|
56
|
-
|
|
56
|
+
operation: 'transit'
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -123,12 +123,12 @@ const target = {
|
|
|
123
123
|
},
|
|
124
124
|
receivers: {
|
|
125
125
|
one: {
|
|
126
|
-
|
|
126
|
+
operation: 'transit'
|
|
127
127
|
},
|
|
128
128
|
two: {
|
|
129
129
|
bridge: '@toa.io/bridges.node',
|
|
130
130
|
binding: '@toa.io/bindings.amqp',
|
|
131
|
-
|
|
131
|
+
operation: 'transit'
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
}
|
|
@@ -3,15 +3,19 @@
|
|
|
3
3
|
const { generate } = require('randomstring')
|
|
4
4
|
|
|
5
5
|
const operations = {
|
|
6
|
+
namespace: 'dummies',
|
|
7
|
+
name: 'dummy',
|
|
6
8
|
path: __dirname,
|
|
7
9
|
bindings: ['foo', 'bar'],
|
|
8
10
|
'bindings@local': ['foo'],
|
|
9
11
|
operations: {
|
|
10
|
-
add: {
|
|
12
|
+
add: {
|
|
13
|
+
type: 'assignment'
|
|
14
|
+
}
|
|
11
15
|
},
|
|
12
16
|
extensions: {
|
|
13
17
|
'@toa.io/extensions.exposition': {
|
|
14
|
-
['/' + generate()]:
|
|
18
|
+
['/' + generate()]: {}
|
|
15
19
|
},
|
|
16
20
|
'./dummies/extension': {
|
|
17
21
|
ok: true
|
|
@@ -12,13 +12,6 @@ beforeEach(() => {
|
|
|
12
12
|
manifest = clone(fixtures.operations)
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
-
describe('environment', () => {
|
|
16
|
-
it('should convolve with environment argument', () => {
|
|
17
|
-
normalize(manifest, 'local')
|
|
18
|
-
expect(manifest.operations.add.bindings).toStrictEqual(['foo'])
|
|
19
|
-
})
|
|
20
|
-
})
|
|
21
|
-
|
|
22
15
|
describe('operations', () => {
|
|
23
16
|
it('should set default bindings', () => {
|
|
24
17
|
normalize(manifest)
|
|
@@ -56,4 +49,21 @@ describe('receivers', () => {
|
|
|
56
49
|
'default.messages.created': 'add'
|
|
57
50
|
})
|
|
58
51
|
})
|
|
52
|
+
|
|
53
|
+
it('should not substitute default namespace for foreign events', async () => {
|
|
54
|
+
const receiver = {
|
|
55
|
+
transition: 'add',
|
|
56
|
+
source: 'test'
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
manifest.receivers = {
|
|
60
|
+
'messages.created': receiver
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
normalize(manifest)
|
|
64
|
+
|
|
65
|
+
expect(manifest.receivers).toStrictEqual({
|
|
66
|
+
'messages.created': receiver
|
|
67
|
+
})
|
|
68
|
+
})
|
|
59
69
|
})
|
|
@@ -37,14 +37,14 @@ describe('namespace', () => {
|
|
|
37
37
|
manifest.namespace = 'foo_'
|
|
38
38
|
expect(() => validate(manifest)).toThrow(/must match pattern/)
|
|
39
39
|
|
|
40
|
+
manifest.namespace = 'foo_bar'
|
|
41
|
+
expect(() => validate(manifest)).toThrow(/must match pattern/)
|
|
42
|
+
|
|
40
43
|
manifest.namespace = 'foo-'
|
|
41
44
|
expect(() => validate(manifest)).toThrow(/must match pattern/)
|
|
42
45
|
|
|
43
|
-
manifest.namespace = 'foo-
|
|
44
|
-
expect(() => validate(manifest)).
|
|
45
|
-
|
|
46
|
-
manifest.namespace = 'foo_bar'
|
|
47
|
-
expect(() => validate(manifest)).not.toThrow()
|
|
46
|
+
manifest.namespace = 'foo-bar'
|
|
47
|
+
expect(() => validate(manifest)).toThrow('must match pattern')
|
|
48
48
|
|
|
49
49
|
manifest.namespace = 'FooBar12'
|
|
50
50
|
expect(() => validate(manifest)).not.toThrow()
|
|
@@ -229,15 +229,21 @@ describe('operations', () => {
|
|
|
229
229
|
})
|
|
230
230
|
|
|
231
231
|
describe('receivers', () => {
|
|
232
|
-
it('should throw if transition points to undefined
|
|
233
|
-
manifest.receivers['foo.bar.happened'].
|
|
232
|
+
it('should throw if transition points to undefined operation', () => {
|
|
233
|
+
manifest.receivers['foo.bar.happened'].operation = 'notExists'
|
|
234
234
|
|
|
235
|
-
expect(() => validate(manifest)).toThrow(/refers to undefined
|
|
235
|
+
expect(() => validate(manifest)).toThrow(/refers to undefined operation/)
|
|
236
236
|
})
|
|
237
237
|
|
|
238
|
-
it('should throw if transition points to
|
|
239
|
-
manifest.receivers['foo.bar.happened'].
|
|
238
|
+
it('should throw if transition points to observation', () => {
|
|
239
|
+
manifest.receivers['foo.bar.happened'].operation = 'get'
|
|
240
|
+
|
|
241
|
+
expect(() => validate(manifest)).toThrow(/one of the allowed types/)
|
|
242
|
+
})
|
|
240
243
|
|
|
241
|
-
|
|
244
|
+
it('should throw if source has a name `context`', async () => {
|
|
245
|
+
manifest.receivers['foo.bar.happened'].source = 'context'
|
|
246
|
+
|
|
247
|
+
expect(() => validate(manifest)).toThrow(/must NOT be valid/)
|
|
242
248
|
})
|
|
243
249
|
})
|
package/types/component.d.ts
CHANGED
|
@@ -1,81 +1,61 @@
|
|
|
1
|
-
import type { Locator } from '@toa.io/core
|
|
1
|
+
import type { Locator, operations } from '@toa.io/core'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
namespace operations {
|
|
7
|
-
|
|
8
|
-
type Type = 'transition' | 'observation' | 'assignment' | 'computation' | 'effect'
|
|
9
|
-
type Scope = 'object' | 'objects' | 'changeset'
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface Map {
|
|
14
|
-
[id: string]: Component
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface Operation {
|
|
18
|
-
type?: operations.Type
|
|
19
|
-
scope?: operations.Scope
|
|
20
|
-
bindings?: string[]
|
|
21
|
-
input?: any
|
|
22
|
-
output?: any
|
|
23
|
-
error?: any
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
interface Operations {
|
|
27
|
-
[key: string]: Operation
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface Event {
|
|
31
|
-
binding: string
|
|
32
|
-
}
|
|
3
|
+
type Map = {
|
|
4
|
+
[id: string]: Component
|
|
5
|
+
}
|
|
33
6
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
7
|
+
type Operation = {
|
|
8
|
+
type: operations.type
|
|
9
|
+
scope?: operations.scope
|
|
10
|
+
bindings?: string[]
|
|
11
|
+
input?: any
|
|
12
|
+
output?: any
|
|
13
|
+
error?: any
|
|
14
|
+
}
|
|
37
15
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
conditioned: boolean
|
|
42
|
-
bridge: string
|
|
43
|
-
binding: string
|
|
44
|
-
path: string
|
|
45
|
-
source?: string
|
|
46
|
-
}
|
|
16
|
+
type Operations = {
|
|
17
|
+
[key: string]: Operation
|
|
18
|
+
}
|
|
47
19
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
initialized?: boolean
|
|
52
|
-
}
|
|
20
|
+
type Event = {
|
|
21
|
+
binding: string
|
|
22
|
+
}
|
|
53
23
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
name: string
|
|
58
|
-
version: string
|
|
59
|
-
entity: Entity
|
|
60
|
-
bindings: string[]
|
|
61
|
-
operations?: Operations
|
|
62
|
-
events?: Events
|
|
63
|
-
receivers: Record<string, Receiver>
|
|
64
|
-
extensions?: Record<string, object>
|
|
65
|
-
properties?: Record<string, object>
|
|
66
|
-
}
|
|
24
|
+
type Events = {
|
|
25
|
+
[key: string]: Event
|
|
26
|
+
}
|
|
67
27
|
|
|
68
|
-
|
|
69
|
-
|
|
28
|
+
type Receiver = {
|
|
29
|
+
operation: string
|
|
30
|
+
adaptive: boolean
|
|
31
|
+
conditioned: boolean
|
|
32
|
+
bridge: string
|
|
33
|
+
binding: string
|
|
34
|
+
path: string
|
|
35
|
+
source?: string
|
|
36
|
+
}
|
|
70
37
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
38
|
+
type Entity = {
|
|
39
|
+
schema: Object
|
|
40
|
+
storage?: string
|
|
41
|
+
initialized?: boolean
|
|
75
42
|
}
|
|
76
43
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
44
|
+
type Declaration = {
|
|
45
|
+
prototype?: string
|
|
46
|
+
namespace: string
|
|
47
|
+
name: string
|
|
48
|
+
version: string
|
|
49
|
+
entity?: Entity
|
|
50
|
+
bindings?: string[]
|
|
51
|
+
operations: Operations
|
|
52
|
+
events?: Events
|
|
53
|
+
receivers?: Record<string, Receiver>
|
|
54
|
+
extensions?: Record<string, object>
|
|
55
|
+
properties?: Record<string, object>
|
|
56
|
+
}
|
|
80
57
|
|
|
81
|
-
export
|
|
58
|
+
export type Manifest = Declaration & {
|
|
59
|
+
locator: Locator
|
|
60
|
+
path: string
|
|
61
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Composition, Registry, Runtime } from '../context'
|
|
2
|
+
|
|
3
|
+
interface Composition {
|
|
4
|
+
name: string,
|
|
5
|
+
components: string[]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Declaration {
|
|
9
|
+
name: string
|
|
10
|
+
description?: string
|
|
11
|
+
version?: string
|
|
12
|
+
runtime?: Runtime | string
|
|
13
|
+
registry?: Registry | string
|
|
14
|
+
packages?: string
|
|
15
|
+
compositions?: Composition[]
|
|
16
|
+
annotations?: Record<string, object>
|
|
17
|
+
}
|
package/types/context.d.ts
CHANGED
|
@@ -1,75 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { Component } from './component'
|
|
1
|
+
import * as _component from './component'
|
|
4
2
|
import { Locator } from '@toa.io/core/types'
|
|
3
|
+
import type { Declaration } from './context/declaration'
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
version: string
|
|
12
|
-
registry?: string
|
|
13
|
-
proxy?: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface Registry {
|
|
17
|
-
base: string
|
|
18
|
-
platforms?: string[] | null
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface Composition {
|
|
22
|
-
name: string,
|
|
23
|
-
components: string[] | Component[]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
namespace dependencies {
|
|
27
|
-
|
|
28
|
-
type Instance = {
|
|
29
|
-
locator: Locator
|
|
30
|
-
manifest?: Object
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
type References = {
|
|
34
|
-
[reference: string]: Component[]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface Dependencies {
|
|
40
|
-
[reference: string]: dependencies.Instance[]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
interface Declaration {
|
|
44
|
-
name: string
|
|
45
|
-
description: string
|
|
46
|
-
version: string
|
|
47
|
-
runtime: Runtime | string
|
|
48
|
-
registry: Registry | string
|
|
49
|
-
packages: string
|
|
50
|
-
compositions?: Composition[]
|
|
51
|
-
annotations?: Record<string, object>
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
type Constructor = (path: string, environment?: string) => Promise<Context>
|
|
55
|
-
}
|
|
5
|
+
interface Runtime {
|
|
6
|
+
version: string
|
|
7
|
+
registry?: string
|
|
8
|
+
proxy?: string
|
|
9
|
+
}
|
|
56
10
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
11
|
+
interface Registry {
|
|
12
|
+
base?: string
|
|
13
|
+
platforms?: string[] | null
|
|
14
|
+
build?: {
|
|
15
|
+
arguments?: string[]
|
|
16
|
+
run?: string
|
|
17
|
+
},
|
|
18
|
+
credentials: string
|
|
19
|
+
}
|
|
65
20
|
|
|
21
|
+
interface Composition {
|
|
22
|
+
name: string,
|
|
23
|
+
components: _component.Component[]
|
|
66
24
|
}
|
|
67
25
|
|
|
68
|
-
export
|
|
69
|
-
|
|
26
|
+
export interface Dependency<T = undefined> {
|
|
27
|
+
locator: Locator
|
|
28
|
+
manifest: T,
|
|
29
|
+
component: _component.Component
|
|
30
|
+
}
|
|
70
31
|
|
|
71
|
-
|
|
72
|
-
|
|
32
|
+
interface Context extends Declaration {
|
|
33
|
+
runtime?: Runtime
|
|
34
|
+
environment?: string
|
|
35
|
+
registry?: Registry
|
|
36
|
+
compositions?: Composition[]
|
|
37
|
+
components?: _component.Component[]
|
|
38
|
+
dependencies?: Record<string, Dependency[]>
|
|
73
39
|
}
|
|
74
40
|
|
|
75
|
-
export
|
|
41
|
+
export function context (path: string, environment?: string): Promise<Context>
|
package/types/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export * as context from './context'
|
|
2
|
+
export * as component from './component'
|
|
3
3
|
|
|
4
|
-
export
|
|
5
|
-
export type { Component, Operation } from './component'
|
|
4
|
+
export { Manifest } from './component'
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
Feature: Operations declaration
|
|
2
|
-
|
|
3
|
-
Scenario Outline: Operation <channel> entity references
|
|
4
|
-
|
|
5
|
-
Operation IO schemas may reference entity's properties using syntax:
|
|
6
|
-
- `.` - entity's property with the same name
|
|
7
|
-
- '.foo` - entity's property with `foo` name
|
|
8
|
-
|
|
9
|
-
Given I have an entity schema:
|
|
10
|
-
"""
|
|
11
|
-
foo: string
|
|
12
|
-
bar: 1
|
|
13
|
-
"""
|
|
14
|
-
When I declare assignment with:
|
|
15
|
-
"""
|
|
16
|
-
<channel>:
|
|
17
|
-
foo: .
|
|
18
|
-
baz: .bar
|
|
19
|
-
"""
|
|
20
|
-
Then normalized assignment declaration must contain:
|
|
21
|
-
"""
|
|
22
|
-
<channel>:
|
|
23
|
-
type: object
|
|
24
|
-
properties:
|
|
25
|
-
foo:
|
|
26
|
-
type: string
|
|
27
|
-
baz:
|
|
28
|
-
type: number
|
|
29
|
-
default: 1
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
Examples:
|
|
33
|
-
| channel |
|
|
34
|
-
| input |
|
|
35
|
-
| output |
|
|
36
|
-
|
|
37
|
-
Scenario: Prototype property reference
|
|
38
|
-
|
|
39
|
-
Operation IO schemas must be able to reference prototype's entity properties.
|
|
40
|
-
|
|
41
|
-
When I declare assignment with:
|
|
42
|
-
"""
|
|
43
|
-
output:
|
|
44
|
-
id: .
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
Then normalized assignment declaration must contain:
|
|
48
|
-
"""
|
|
49
|
-
output:
|
|
50
|
-
type: object
|
|
51
|
-
properties:
|
|
52
|
-
id:
|
|
53
|
-
$ref: https://schemas.toa.io/0.0.0/definitions#/definitions/id
|
|
54
|
-
"""
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { AssertionError } = require('assert')
|
|
4
|
-
const { generate } = require('randomstring')
|
|
5
|
-
const { dump } = require('@toa.io/yaml')
|
|
6
|
-
const gherkin = require('@toa.io/tomato')
|
|
7
|
-
|
|
8
|
-
const mock = { gherkin }
|
|
9
|
-
|
|
10
|
-
jest.mock('@cucumber/cucumber', () => mock.gherkin)
|
|
11
|
-
require('../manifest')
|
|
12
|
-
|
|
13
|
-
it('should be', () => undefined)
|
|
14
|
-
|
|
15
|
-
/** @type {toa.norm.features.Context} */
|
|
16
|
-
let context
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
const manifest = /** @type {toa.norm.component.Declaration} */ {
|
|
20
|
-
name: 'test',
|
|
21
|
-
namespace: 'features',
|
|
22
|
-
version: '1.0.0',
|
|
23
|
-
entity: null
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
context = { manifest }
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
describe('Given I have an entity schema:', () => {
|
|
30
|
-
const step = gherkin.steps.Gi('I have an entity schema:')
|
|
31
|
-
|
|
32
|
-
it('should be', () => undefined)
|
|
33
|
-
|
|
34
|
-
it('should set entity schema', () => {
|
|
35
|
-
const schema = { foo: 'string' }
|
|
36
|
-
const yaml = dump(schema)
|
|
37
|
-
|
|
38
|
-
step.call(context, yaml)
|
|
39
|
-
|
|
40
|
-
expect(context.manifest.entity).toStrictEqual({ schema })
|
|
41
|
-
})
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
describe('When I declare {operation} with:', () => {
|
|
45
|
-
const step = gherkin.steps.Wh('I declare {operation} with:')
|
|
46
|
-
|
|
47
|
-
it('should be', () => undefined)
|
|
48
|
-
|
|
49
|
-
it('should declare operation', () => {
|
|
50
|
-
const type = 'assignment'
|
|
51
|
-
const scope = 'changeset'
|
|
52
|
-
const input = {}
|
|
53
|
-
const yaml = dump(input)
|
|
54
|
-
|
|
55
|
-
step.call(context, type, yaml)
|
|
56
|
-
|
|
57
|
-
expect(context.manifest.operations[type]).toStrictEqual({ type, scope })
|
|
58
|
-
})
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
describe('Then normalized {operation} declaration must contain:', () => {
|
|
62
|
-
const step = gherkin.steps.Th('normalized {operation} declaration must contain:')
|
|
63
|
-
|
|
64
|
-
it('should be', () => undefined)
|
|
65
|
-
|
|
66
|
-
it('should throw if does not contain', async () => {
|
|
67
|
-
const type = 'assignment'
|
|
68
|
-
|
|
69
|
-
context.manifest.operations = {
|
|
70
|
-
[type]: {
|
|
71
|
-
type,
|
|
72
|
-
input: { bar: 'number' },
|
|
73
|
-
scope: 'changeset'
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const input = {
|
|
78
|
-
type: 'object',
|
|
79
|
-
properties: {
|
|
80
|
-
bar: { type: 'string' }
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const yaml = dump({ input })
|
|
85
|
-
|
|
86
|
-
await expect(step.call(context, type, yaml)).rejects.toThrow(AssertionError)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('should not throw if contain', async () => {
|
|
90
|
-
const type = 'assignment'
|
|
91
|
-
|
|
92
|
-
context.manifest.operations = {
|
|
93
|
-
[type]: {
|
|
94
|
-
type,
|
|
95
|
-
input: { bar: 'number' },
|
|
96
|
-
scope: 'changeset'
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const input = {
|
|
101
|
-
type: 'object',
|
|
102
|
-
properties: {
|
|
103
|
-
bar: { type: 'number' }
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const yaml = dump({ input })
|
|
108
|
-
|
|
109
|
-
await expect(step.call(context, type, yaml)).resolves.not.toThrow()
|
|
110
|
-
})
|
|
111
|
-
})
|
package/features/steps/hooks.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { Before } = require('@cucumber/cucumber')
|
|
4
|
-
|
|
5
|
-
Before(
|
|
6
|
-
/**
|
|
7
|
-
* @this {toa.norm.features.Context}
|
|
8
|
-
*/
|
|
9
|
-
function () {
|
|
10
|
-
this.manifest = {
|
|
11
|
-
name: 'test',
|
|
12
|
-
namespace: 'features',
|
|
13
|
-
version: '1.0.0',
|
|
14
|
-
entity: {
|
|
15
|
-
storage: null
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
})
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const assert = require('node:assert')
|
|
4
|
-
const { join } = require('node:path')
|
|
5
|
-
const { parse, save } = require('@toa.io/yaml')
|
|
6
|
-
const { directory } = require('@toa.io/filesystem')
|
|
7
|
-
const { match } = require('@toa.io/generic')
|
|
8
|
-
|
|
9
|
-
const { component: load } = require('../../src')
|
|
10
|
-
|
|
11
|
-
const { Given, When, Then } = require('@cucumber/cucumber')
|
|
12
|
-
|
|
13
|
-
Given('I have an entity schema:',
|
|
14
|
-
/**
|
|
15
|
-
* @param {string} yaml
|
|
16
|
-
* @this {toa.norm.features.Context}
|
|
17
|
-
*/
|
|
18
|
-
function (yaml) {
|
|
19
|
-
const schema = parse(yaml)
|
|
20
|
-
|
|
21
|
-
this.manifest.entity = { schema }
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
When('I declare {operation} with:',
|
|
25
|
-
/**
|
|
26
|
-
* @param {toa.norm.component.operations.Type} type
|
|
27
|
-
* @param {string} yaml
|
|
28
|
-
* @this {toa.norm.features.Context}
|
|
29
|
-
*/
|
|
30
|
-
function (type, yaml) {
|
|
31
|
-
/** @type {toa.norm.component.Operation} */
|
|
32
|
-
const declaration = parse(yaml)
|
|
33
|
-
|
|
34
|
-
declaration.type = type
|
|
35
|
-
declaration.scope = scope(type)
|
|
36
|
-
|
|
37
|
-
this.manifest.operations = { [type]: declaration }
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
Then('normalized {operation} declaration must contain:',
|
|
41
|
-
/**
|
|
42
|
-
* @param {toa.norm.component.operations.Type} type
|
|
43
|
-
* @param {string} yaml
|
|
44
|
-
* @this {toa.norm.features.Context}
|
|
45
|
-
*/
|
|
46
|
-
async function (type, yaml) {
|
|
47
|
-
const temp = await directory.temp()
|
|
48
|
-
const path = join(temp, 'manifest.toa.yaml')
|
|
49
|
-
|
|
50
|
-
await save(this.manifest, path)
|
|
51
|
-
|
|
52
|
-
const manifest = await load(temp)
|
|
53
|
-
const operation = manifest.operations[type]
|
|
54
|
-
const query = parse(yaml)
|
|
55
|
-
const contains = match(operation, query)
|
|
56
|
-
|
|
57
|
-
assert.equal(contains, true)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @param {toa.norm.component.operations.Type} type
|
|
62
|
-
* @returns {toa.norm.component.operations.Scope}
|
|
63
|
-
*/
|
|
64
|
-
const scope = (type) => {
|
|
65
|
-
return type === 'assignment' ? 'changeset' : 'object'
|
|
66
|
-
}
|