@toa.io/norm 0.20.0-dev.8 → 0.20.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 -7
- package/src/.component/.expand/extensions.js +4 -1
- package/src/.component/.expand/operations.js +4 -1
- package/src/.component/.normalize/index.js +0 -2
- package/src/.component/.normalize/operations.js +4 -0
- package/src/.component/{.normalize/extensions.js → extensions.js} +1 -4
- package/src/.component/index.js +2 -0
- package/src/.component/normalize.js +2 -5
- package/src/.component/schema.yaml +31 -23
- 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/component.js +4 -5
- package/src/context.js +1 -4
- package/src/shortcuts.js +3 -1
- package/test/component/normalize.fixtures.js +6 -2
- package/test/component/normalize.test.js +0 -13
- package/test/component/validate.fixtures.js +10 -0
- package/test/component/validate.test.js +21 -6
- package/types/component.d.ts +52 -71
- package/types/context/declaration.d.ts +17 -0
- package/types/context.d.ts +31 -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.20.0
|
|
3
|
+
"version": "0.20.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,6 +12,7 @@
|
|
|
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
|
},
|
|
@@ -19,11 +20,11 @@
|
|
|
19
20
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
20
21
|
},
|
|
21
22
|
"dependencies": {
|
|
22
|
-
"@toa.io/core": "0.20.0
|
|
23
|
-
"@toa.io/generic": "0.20.0
|
|
24
|
-
"@toa.io/schema": "0.20.0
|
|
25
|
-
"@toa.io/schemas": "0.20.0
|
|
26
|
-
"@toa.io/yaml": "0.20.0
|
|
23
|
+
"@toa.io/core": "0.20.0",
|
|
24
|
+
"@toa.io/generic": "0.20.0",
|
|
25
|
+
"@toa.io/schema": "0.20.0",
|
|
26
|
+
"@toa.io/schemas": "0.20.0",
|
|
27
|
+
"@toa.io/yaml": "0.20.0"
|
|
27
28
|
},
|
|
28
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "28fc4b45c224c3683acaaf0e4abd1eb04e07b408"
|
|
29
30
|
}
|
|
@@ -9,8 +9,11 @@ function extensions (manifest) {
|
|
|
9
9
|
|
|
10
10
|
const SHORTCUTS = {
|
|
11
11
|
exposition: '@toa.io/extensions.exposition',
|
|
12
|
+
realtime: '@toa.io/extensions.realtime',
|
|
12
13
|
origins: '@toa.io/extensions.origins',
|
|
13
|
-
configuration: '@toa.io/extensions.configuration'
|
|
14
|
+
configuration: '@toa.io/extensions.configuration',
|
|
15
|
+
state: '@toa.io/extensions.state',
|
|
16
|
+
stash: '@toa.io/extensions.stash'
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
exports.extensions = extensions
|
|
@@ -10,7 +10,10 @@ function operations (manifest) {
|
|
|
10
10
|
if (operation.input !== undefined) operation.input = expand(operation.input)
|
|
11
11
|
if (operation.output !== undefined) operation.output = expand(operation.output)
|
|
12
12
|
if (operation.bridge !== undefined) operation.bridge = resolve(operation.bridge)
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
if (operation.bindings !== undefined && operation.bindings !== null) {
|
|
15
|
+
operation.bindings = operation.bindings.map(resolve)
|
|
16
|
+
}
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
19
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { events } = require('./events')
|
|
4
|
-
const { extensions } = require('./extensions')
|
|
5
4
|
const { operations } = require('./operations')
|
|
6
5
|
const { receivers } = require('./receivers')
|
|
7
6
|
|
|
8
7
|
exports.events = events
|
|
9
|
-
exports.extensions = extensions
|
|
10
8
|
exports.operations = operations
|
|
11
9
|
exports.receivers = receivers
|
|
@@ -4,7 +4,11 @@ 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.type === 'computation' || operation.type === 'effect')
|
|
8
|
+
operation.query = false
|
|
9
|
+
|
|
7
10
|
if (operation.bindings === undefined) operation.bindings = component.bindings
|
|
11
|
+
if (operation.bindings === null) operation.bindings = []
|
|
8
12
|
if (operation.virtual === true) delete component.operations[endpoint]
|
|
9
13
|
}
|
|
10
14
|
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { directory: { find } } = require('@toa.io/filesystem')
|
|
4
|
-
const { resolve } = require('
|
|
4
|
+
const { resolve } = require('../shortcuts')
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* @param {toa.norm.Component} manifest
|
|
8
|
-
*/
|
|
9
6
|
const extensions = (manifest) => {
|
|
10
7
|
if (manifest.extensions === undefined) return
|
|
11
8
|
|
package/src/.component/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const { expand } = require('./expand')
|
|
|
8
8
|
const { merge } = require('./merge')
|
|
9
9
|
const { normalize } = require('./normalize')
|
|
10
10
|
const { validate } = require('./validate')
|
|
11
|
+
const { extensions } = require('./extensions')
|
|
11
12
|
|
|
12
13
|
exports.collapse = collapse
|
|
13
14
|
exports.defaults = defaults
|
|
@@ -17,3 +18,4 @@ exports.expand = expand
|
|
|
17
18
|
exports.merge = merge
|
|
18
19
|
exports.normalize = normalize
|
|
19
20
|
exports.validate = validate
|
|
21
|
+
exports.extensions = extensions
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
const { events, operations, extensions, receivers } = require('./.normalize')
|
|
3
|
+
const { events, operations, receivers } = require('./.normalize')
|
|
5
4
|
|
|
6
|
-
const normalize = (component
|
|
7
|
-
convolve(component, environment)
|
|
5
|
+
const normalize = (component) => {
|
|
8
6
|
operations(component)
|
|
9
7
|
events(component)
|
|
10
8
|
receivers(component)
|
|
11
|
-
extensions(component)
|
|
12
9
|
}
|
|
13
10
|
|
|
14
11
|
exports.normalize = normalize
|
|
@@ -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,18 +68,17 @@ 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:
|
|
79
80
|
type: array
|
|
80
81
|
uniqueItems: true
|
|
81
|
-
minItems: 1
|
|
82
82
|
items:
|
|
83
83
|
$ref: '#/definitions/binding'
|
|
84
84
|
|
|
@@ -88,19 +88,19 @@ properties:
|
|
|
88
88
|
operations:
|
|
89
89
|
type: object
|
|
90
90
|
propertyNames:
|
|
91
|
-
$ref: 'definitions#/definitions/
|
|
91
|
+
$ref: 'definitions#/definitions/name'
|
|
92
92
|
patternProperties:
|
|
93
93
|
'.*':
|
|
94
94
|
type: object
|
|
95
95
|
properties:
|
|
96
96
|
type:
|
|
97
|
-
enum: [
|
|
97
|
+
enum: [transition, observation, assignment, computation, effect]
|
|
98
98
|
scope:
|
|
99
|
-
enum: [
|
|
99
|
+
enum: [object, objects, changeset, none]
|
|
100
100
|
concurrency:
|
|
101
|
-
enum: [
|
|
101
|
+
enum: [none, retry]
|
|
102
102
|
forward:
|
|
103
|
-
$ref: 'definitions#/definitions/
|
|
103
|
+
$ref: 'definitions#/definitions/name'
|
|
104
104
|
bridge:
|
|
105
105
|
type: string
|
|
106
106
|
bindings:
|
|
@@ -111,7 +111,7 @@ properties:
|
|
|
111
111
|
$ref: 'definitions#/definitions/schema'
|
|
112
112
|
query:
|
|
113
113
|
type: boolean
|
|
114
|
-
required: [
|
|
114
|
+
required: [type, scope, bindings]
|
|
115
115
|
allOf:
|
|
116
116
|
- if: # transition
|
|
117
117
|
properties:
|
|
@@ -120,15 +120,15 @@ properties:
|
|
|
120
120
|
then:
|
|
121
121
|
properties:
|
|
122
122
|
scope:
|
|
123
|
-
enum: [
|
|
123
|
+
enum: [object]
|
|
124
124
|
if: # transition query: false
|
|
125
125
|
not:
|
|
126
126
|
properties:
|
|
127
127
|
query:
|
|
128
128
|
const: false
|
|
129
|
-
required: [
|
|
129
|
+
required: [query]
|
|
130
130
|
then:
|
|
131
|
-
required: [
|
|
131
|
+
required: [concurrency]
|
|
132
132
|
- if: # not transition
|
|
133
133
|
not:
|
|
134
134
|
properties:
|
|
@@ -145,7 +145,7 @@ properties:
|
|
|
145
145
|
then:
|
|
146
146
|
properties:
|
|
147
147
|
scope:
|
|
148
|
-
enum: [
|
|
148
|
+
enum: [object, objects, none]
|
|
149
149
|
query:
|
|
150
150
|
not:
|
|
151
151
|
const: false
|
|
@@ -156,7 +156,7 @@ properties:
|
|
|
156
156
|
then:
|
|
157
157
|
properties:
|
|
158
158
|
scope:
|
|
159
|
-
enum: [
|
|
159
|
+
enum: [changeset]
|
|
160
160
|
- if: # computation
|
|
161
161
|
properties:
|
|
162
162
|
type:
|
|
@@ -166,6 +166,9 @@ properties:
|
|
|
166
166
|
scope:
|
|
167
167
|
const: none
|
|
168
168
|
default: none
|
|
169
|
+
query:
|
|
170
|
+
const: false
|
|
171
|
+
default: false
|
|
169
172
|
- if: # effect
|
|
170
173
|
properties:
|
|
171
174
|
type:
|
|
@@ -175,13 +178,16 @@ properties:
|
|
|
175
178
|
scope:
|
|
176
179
|
const: none
|
|
177
180
|
default: none
|
|
181
|
+
query:
|
|
182
|
+
const: false
|
|
183
|
+
default: false
|
|
178
184
|
additionalProperties: false
|
|
179
185
|
additionalProperties: false
|
|
180
186
|
|
|
181
187
|
events:
|
|
182
188
|
type: object
|
|
183
189
|
propertyNames:
|
|
184
|
-
$ref: 'definitions#/definitions/
|
|
190
|
+
$ref: 'definitions#/definitions/name'
|
|
185
191
|
patternProperties:
|
|
186
192
|
'.*':
|
|
187
193
|
type: object
|
|
@@ -198,7 +204,7 @@ properties:
|
|
|
198
204
|
subjective:
|
|
199
205
|
type: boolean
|
|
200
206
|
default: false
|
|
201
|
-
required: [
|
|
207
|
+
required: [bridge, path]
|
|
202
208
|
additionalProperties: false
|
|
203
209
|
|
|
204
210
|
receivers:
|
|
@@ -208,13 +214,15 @@ properties:
|
|
|
208
214
|
type: object
|
|
209
215
|
properties:
|
|
210
216
|
operation:
|
|
211
|
-
$ref: 'definitions#/definitions/
|
|
217
|
+
$ref: 'definitions#/definitions/name'
|
|
212
218
|
bridge:
|
|
213
219
|
type: string
|
|
214
220
|
binding:
|
|
215
221
|
type: string
|
|
216
222
|
source:
|
|
217
|
-
$ref: 'definitions#/definitions/
|
|
223
|
+
$ref: 'definitions#/definitions/name'
|
|
224
|
+
not:
|
|
225
|
+
const: context
|
|
218
226
|
path:
|
|
219
227
|
type: string
|
|
220
228
|
conditioned:
|
|
@@ -223,7 +231,7 @@ properties:
|
|
|
223
231
|
adaptive:
|
|
224
232
|
type: boolean
|
|
225
233
|
default: false
|
|
226
|
-
required: [
|
|
234
|
+
required: [operation]
|
|
227
235
|
additionalProperties: false
|
|
228
236
|
|
|
229
237
|
extensions:
|
|
@@ -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/component.js
CHANGED
|
@@ -14,17 +14,16 @@ const {
|
|
|
14
14
|
dereference,
|
|
15
15
|
defaults,
|
|
16
16
|
dependencies,
|
|
17
|
-
normalize
|
|
17
|
+
normalize,
|
|
18
|
+
extensions
|
|
18
19
|
} = require('./.component')
|
|
19
20
|
|
|
20
|
-
/**
|
|
21
|
-
* @type {toa.norm.component.Constructor}
|
|
22
|
-
*/
|
|
23
21
|
const component = async (path) => {
|
|
24
22
|
const manifest = await load(path)
|
|
25
23
|
|
|
26
|
-
normalize(manifest
|
|
24
|
+
normalize(manifest)
|
|
27
25
|
validate(manifest)
|
|
26
|
+
extensions(manifest)
|
|
28
27
|
|
|
29
28
|
manifest.locator = new Locator(manifest.name, manifest.namespace)
|
|
30
29
|
|
package/src/context.js
CHANGED
|
@@ -16,9 +16,6 @@ const {
|
|
|
16
16
|
validate
|
|
17
17
|
} = require('./.context')
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
* @type {toa.norm.context.Constructor}
|
|
21
|
-
*/
|
|
22
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)
|
|
@@ -35,7 +32,7 @@ const context = async (root, environment = process.env.TOA_ENV) => {
|
|
|
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
|
@@ -46,8 +46,10 @@ const SHORTCUTS = {
|
|
|
46
46
|
sql: '@toa.io/storages.sql',
|
|
47
47
|
queues: '@toa.io/storages.queues',
|
|
48
48
|
exposition: '@toa.io/extensions.exposition',
|
|
49
|
+
realtime: '@toa.io/extensions.realtime',
|
|
49
50
|
configuration: '@toa.io/extensions.configuration',
|
|
50
|
-
origins: '@toa.io/extensions.origins'
|
|
51
|
+
origins: '@toa.io/extensions.origins',
|
|
52
|
+
stash: '@toa.io/extensions.stash'
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
exports.recognize = recognize
|
|
@@ -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)
|
|
@@ -36,12 +29,6 @@ describe('extensions', () => {
|
|
|
36
29
|
|
|
37
30
|
expect(manifest.extensions[path]).toStrictEqual(origins)
|
|
38
31
|
})
|
|
39
|
-
|
|
40
|
-
it('should throw if manifest is undefined', () => {
|
|
41
|
-
manifest.extensions['./dummies/extension'].ok = false
|
|
42
|
-
|
|
43
|
-
expect(() => normalize(manifest)).toThrow(/hasn't returned manifest/)
|
|
44
|
-
})
|
|
45
32
|
})
|
|
46
33
|
|
|
47
34
|
describe('receivers', () => {
|
|
@@ -34,6 +34,16 @@ const ok = {
|
|
|
34
34
|
scope: 'changeset',
|
|
35
35
|
bridge: 'whatever',
|
|
36
36
|
bindings: ['@toa.io/bindings.http', '@toa.io/bindings.amqp']
|
|
37
|
+
},
|
|
38
|
+
compute: {
|
|
39
|
+
type: 'computation',
|
|
40
|
+
bridge: 'whatever',
|
|
41
|
+
bindings: ['@toa.io/bindings.http', '@toa.io/bindings.amqp']
|
|
42
|
+
},
|
|
43
|
+
affect: {
|
|
44
|
+
type: 'effect',
|
|
45
|
+
bridge: 'whatever',
|
|
46
|
+
bindings: ['@toa.io/bindings.http', '@toa.io/bindings.amqp']
|
|
37
47
|
}
|
|
38
48
|
},
|
|
39
49
|
events: {
|
|
@@ -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 = '
|
|
40
|
+
manifest.namespace = 'foo_bar'
|
|
41
41
|
expect(() => validate(manifest)).toThrow(/must match pattern/)
|
|
42
42
|
|
|
43
|
-
manifest.namespace = 'foo-
|
|
44
|
-
expect(() => validate(manifest)).
|
|
43
|
+
manifest.namespace = 'foo-'
|
|
44
|
+
expect(() => validate(manifest)).toThrow(/must match pattern/)
|
|
45
45
|
|
|
46
|
-
manifest.namespace = '
|
|
47
|
-
expect(() => validate(manifest)).
|
|
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()
|
|
@@ -172,6 +172,15 @@ describe('operations', () => {
|
|
|
172
172
|
expect(() => validate(manifest)).toThrow(/must NOT be valid/)
|
|
173
173
|
})
|
|
174
174
|
|
|
175
|
+
it.each([
|
|
176
|
+
['computation', 'compute'],
|
|
177
|
+
['effect', 'affect']
|
|
178
|
+
])('should set query: false for %s', async (_, operation) => {
|
|
179
|
+
validate(manifest)
|
|
180
|
+
|
|
181
|
+
expect(manifest.operations[operation].query).toBe(false)
|
|
182
|
+
})
|
|
183
|
+
|
|
175
184
|
describe('scope', () => {
|
|
176
185
|
it('should have scope', () => {
|
|
177
186
|
delete manifest.operations.get.scope
|
|
@@ -230,7 +239,7 @@ describe('operations', () => {
|
|
|
230
239
|
|
|
231
240
|
describe('receivers', () => {
|
|
232
241
|
it('should throw if transition points to undefined operation', () => {
|
|
233
|
-
manifest.receivers['foo.bar.happened'].operation = '
|
|
242
|
+
manifest.receivers['foo.bar.happened'].operation = 'notExists'
|
|
234
243
|
|
|
235
244
|
expect(() => validate(manifest)).toThrow(/refers to undefined operation/)
|
|
236
245
|
})
|
|
@@ -240,4 +249,10 @@ describe('receivers', () => {
|
|
|
240
249
|
|
|
241
250
|
expect(() => validate(manifest)).toThrow(/one of the allowed types/)
|
|
242
251
|
})
|
|
252
|
+
|
|
253
|
+
it('should throw if source has a name `context`', async () => {
|
|
254
|
+
manifest.receivers['foo.bar.happened'].source = 'context'
|
|
255
|
+
|
|
256
|
+
expect(() => validate(manifest)).toThrow(/must NOT be valid/)
|
|
257
|
+
})
|
|
243
258
|
})
|
package/types/component.d.ts
CHANGED
|
@@ -1,81 +1,62 @@
|
|
|
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
|
+
query?: boolean
|
|
15
|
+
}
|
|
37
16
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
conditioned: boolean
|
|
42
|
-
bridge: string
|
|
43
|
-
binding: string
|
|
44
|
-
path: string
|
|
45
|
-
source?: string
|
|
46
|
-
}
|
|
17
|
+
type Operations = {
|
|
18
|
+
[key: string]: Operation
|
|
19
|
+
}
|
|
47
20
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
initialized?: boolean
|
|
52
|
-
}
|
|
21
|
+
type Event = {
|
|
22
|
+
binding: string
|
|
23
|
+
}
|
|
53
24
|
|
|
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
|
-
}
|
|
25
|
+
type Events = {
|
|
26
|
+
[key: string]: Event
|
|
27
|
+
}
|
|
67
28
|
|
|
68
|
-
|
|
69
|
-
|
|
29
|
+
type Receiver = {
|
|
30
|
+
operation: string
|
|
31
|
+
adaptive: boolean
|
|
32
|
+
conditioned: boolean
|
|
33
|
+
bridge: string
|
|
34
|
+
binding: string
|
|
35
|
+
path: string
|
|
36
|
+
source?: string
|
|
37
|
+
}
|
|
70
38
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
39
|
+
type Entity = {
|
|
40
|
+
schema: Object
|
|
41
|
+
storage?: string
|
|
42
|
+
initialized?: boolean
|
|
75
43
|
}
|
|
76
44
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
45
|
+
type Declaration = {
|
|
46
|
+
prototype?: string
|
|
47
|
+
namespace: string
|
|
48
|
+
name: string
|
|
49
|
+
version: string
|
|
50
|
+
entity?: Entity
|
|
51
|
+
bindings?: string[]
|
|
52
|
+
operations: Operations
|
|
53
|
+
events?: Events
|
|
54
|
+
receivers?: Record<string, Receiver>
|
|
55
|
+
extensions?: Record<string, object>
|
|
56
|
+
properties?: Record<string, object>
|
|
57
|
+
}
|
|
80
58
|
|
|
81
|
-
export
|
|
59
|
+
export type Manifest = Declaration & {
|
|
60
|
+
locator: Locator
|
|
61
|
+
path: string
|
|
62
|
+
}
|
|
@@ -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,76 +1,41 @@
|
|
|
1
1
|
import * as _component from './component'
|
|
2
2
|
import { Locator } from '@toa.io/core/types'
|
|
3
|
+
import type { Declaration } from './context/declaration'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
version: string
|
|
10
|
-
registry?: string
|
|
11
|
-
proxy?: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface Registry {
|
|
15
|
-
base?: string
|
|
16
|
-
platforms?: string[] | null
|
|
17
|
-
build?: {
|
|
18
|
-
arguments?: string[]
|
|
19
|
-
run?: string
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface Composition {
|
|
24
|
-
name: string,
|
|
25
|
-
components: string[] | _component.Component[]
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
namespace dependencies {
|
|
29
|
-
|
|
30
|
-
type Instance = {
|
|
31
|
-
locator: Locator
|
|
32
|
-
manifest?: Object
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
type References = {
|
|
36
|
-
[reference: string]: _component.Component[]
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface Dependencies {
|
|
42
|
-
[reference: string]: dependencies.Instance[]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface Declaration {
|
|
46
|
-
name: string
|
|
47
|
-
description?: string
|
|
48
|
-
version?: string
|
|
49
|
-
runtime?: Runtime | string
|
|
50
|
-
registry?: Registry | string
|
|
51
|
-
packages?: string
|
|
52
|
-
compositions?: Composition[]
|
|
53
|
-
annotations?: Record<string, object>
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
type Constructor = (path: string, environment?: string) => Promise<Context>
|
|
57
|
-
}
|
|
5
|
+
interface Runtime {
|
|
6
|
+
version: string
|
|
7
|
+
registry?: string
|
|
8
|
+
proxy?: string
|
|
9
|
+
}
|
|
58
10
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
11
|
+
interface Registry {
|
|
12
|
+
base?: string
|
|
13
|
+
platforms?: string[] | null
|
|
14
|
+
build?: {
|
|
15
|
+
arguments?: string[]
|
|
16
|
+
run?: string
|
|
17
|
+
},
|
|
18
|
+
credentials: string
|
|
19
|
+
}
|
|
66
20
|
|
|
21
|
+
interface Composition {
|
|
22
|
+
name: string,
|
|
23
|
+
components: _component.Component[]
|
|
67
24
|
}
|
|
68
25
|
|
|
69
|
-
export
|
|
70
|
-
|
|
26
|
+
export interface Dependency<T = undefined> {
|
|
27
|
+
locator: Locator
|
|
28
|
+
manifest: T,
|
|
29
|
+
component: _component.Component
|
|
30
|
+
}
|
|
71
31
|
|
|
72
|
-
|
|
73
|
-
|
|
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[]>
|
|
74
39
|
}
|
|
75
40
|
|
|
76
|
-
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
|
-
}
|