@toa.io/norm 0.20.0-dev.9 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/norm",
3
- "version": "0.20.0-dev.9",
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-dev.9",
23
- "@toa.io/generic": "0.20.0-dev.9",
24
- "@toa.io/schema": "0.20.0-dev.9",
25
- "@toa.io/schemas": "0.20.0-dev.9",
26
- "@toa.io/yaml": "0.20.0-dev.9"
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": "4e503ffe4fe6dfab1165e795832d3d4fba711582"
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
- if (operation.bindings !== undefined) operation.bindings = operation.bindings.map(resolve)
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('../../shortcuts')
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
 
@@ -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 { convolve } = require('@toa.io/generic')
4
- const { events, operations, extensions, receivers } = require('./.normalize')
3
+ const { events, operations, receivers } = require('./.normalize')
5
4
 
6
- const normalize = (component, environment) => {
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/token'
23
+ $ref: 'definitions#/definitions/name'
24
24
  patternProperties:
25
25
  '.*':
26
26
  type: object
@@ -68,7 +68,7 @@ properties:
68
68
  type: object
69
69
  propertyNames:
70
70
  oneOf:
71
- - $ref: 'definitions#/definitions/token'
71
+ - $ref: 'definitions#/definitions/name'
72
72
  - enum: [_version]
73
73
  initialized:
74
74
  type: boolean
@@ -79,7 +79,6 @@ properties:
79
79
  bindings:
80
80
  type: array
81
81
  uniqueItems: true
82
- minItems: 1
83
82
  items:
84
83
  $ref: '#/definitions/binding'
85
84
 
@@ -89,7 +88,7 @@ properties:
89
88
  operations:
90
89
  type: object
91
90
  propertyNames:
92
- $ref: 'definitions#/definitions/token'
91
+ $ref: 'definitions#/definitions/name'
93
92
  patternProperties:
94
93
  '.*':
95
94
  type: object
@@ -101,7 +100,7 @@ properties:
101
100
  concurrency:
102
101
  enum: [none, retry]
103
102
  forward:
104
- $ref: 'definitions#/definitions/token'
103
+ $ref: 'definitions#/definitions/name'
105
104
  bridge:
106
105
  type: string
107
106
  bindings:
@@ -167,6 +166,9 @@ properties:
167
166
  scope:
168
167
  const: none
169
168
  default: none
169
+ query:
170
+ const: false
171
+ default: false
170
172
  - if: # effect
171
173
  properties:
172
174
  type:
@@ -176,13 +178,16 @@ properties:
176
178
  scope:
177
179
  const: none
178
180
  default: none
181
+ query:
182
+ const: false
183
+ default: false
179
184
  additionalProperties: false
180
185
  additionalProperties: false
181
186
 
182
187
  events:
183
188
  type: object
184
189
  propertyNames:
185
- $ref: 'definitions#/definitions/token'
190
+ $ref: 'definitions#/definitions/name'
186
191
  patternProperties:
187
192
  '.*':
188
193
  type: object
@@ -209,13 +214,15 @@ properties:
209
214
  type: object
210
215
  properties:
211
216
  operation:
212
- $ref: 'definitions#/definitions/token'
217
+ $ref: 'definitions#/definitions/name'
213
218
  bridge:
214
219
  type: string
215
220
  binding:
216
221
  type: string
217
222
  source:
218
- $ref: 'definitions#/definitions/token'
223
+ $ref: 'definitions#/definitions/name'
224
+ not:
225
+ const: context
219
226
  path:
220
227
  type: string
221
228
  conditioned:
@@ -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
- for (const component of context.components) {
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
- for (const component of context.components) {
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
- extensions[reference].push(component)
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
- return extensions
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
- * @param {toa.norm.Context} context
7
- * @returns {toa.norm.context.Dependencies}
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, process.env.TOA_ENV)
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()]: ['add']
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: {
@@ -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
@@ -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
  })
@@ -1,81 +1,62 @@
1
- import type {Locator} from '@toa.io/core/types'
1
+ import type { Locator, operations } from '@toa.io/core'
2
2
 
3
- export namespace toa.norm {
4
-
5
- namespace component {
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
- interface Events {
35
- [key: string]: Event
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
- interface Receiver {
39
- operation: string
40
- adaptive: boolean
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
- type Entity = {
49
- schema: Object
50
- storage?: string
51
- initialized?: boolean
52
- }
21
+ type Event = {
22
+ binding: string
23
+ }
53
24
 
54
- interface Declaration {
55
- prototype: string
56
- namespace: string
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
- type Constructor = (path: string) => Promise<Component>
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
- interface Component extends component.Declaration {
72
- locator: Locator
73
- path: string
74
- }
39
+ type Entity = {
40
+ schema: Object
41
+ storage?: string
42
+ initialized?: boolean
75
43
  }
76
44
 
77
- export type Component = toa.norm.Component
78
- export type Operation = toa.norm.component.Operation
79
- export type Declaration = toa.norm.component.Declaration
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 const component: toa.norm.component.Constructor
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
+ }
@@ -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
- declare namespace toa.norm {
5
-
6
- namespace context {
7
-
8
- interface Runtime {
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
- interface Context extends context.Declaration {
60
- runtime?: context.Runtime
61
- environment?: string
62
- registry?: context.Registry
63
- components?: _component.Component[]
64
- dependencies?: context.Dependencies
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 type Composition = toa.norm.context.Composition
70
- export type Context = toa.norm.Context
26
+ export interface Dependency<T = undefined> {
27
+ locator: Locator
28
+ manifest: T,
29
+ component: _component.Component
30
+ }
71
31
 
72
- export namespace dependencies {
73
- export type Instance = toa.norm.context.dependencies.Instance
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 const context: toa.norm.context.Constructor
41
+ export function context (path: string, environment?: string): Promise<Context>
package/types/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- export { component } from './component'
2
- export { context } from './context'
1
+ export * as context from './context'
2
+ export * as component from './component'
3
3
 
4
- export type { Composition, dependencies } from './context'
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
- })
@@ -1,9 +0,0 @@
1
- import { Declaration } from '../../../types/component'
2
-
3
- declare namespace toa.norm.features {
4
-
5
- type Context = {
6
- manifest?: Declaration
7
- }
8
-
9
- }
@@ -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
- }
@@ -1,9 +0,0 @@
1
- 'use strict'
2
-
3
- const { defineParameterType } = require('@cucumber/cucumber')
4
-
5
- defineParameterType({
6
- name: 'operation',
7
- regexp: /transition|observation|assignment/,
8
- transformer: (type) => type
9
- })