@toa.io/norm 1.0.0-alpha.7 → 1.0.0-alpha.73

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