@toa.io/norm 1.0.0-alpha.28 → 1.0.0-alpha.283

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.
Files changed (72) hide show
  1. package/CHANGELOG.md +195 -0
  2. package/package.json +8 -7
  3. package/src/.component/.expand/bridge.js +2 -6
  4. package/src/.component/.expand/entity.js +2 -9
  5. package/src/.component/.expand/events.js +2 -6
  6. package/src/.component/.expand/extensions.js +4 -8
  7. package/src/.component/.expand/index.js +8 -19
  8. package/src/.component/.expand/operations.js +2 -9
  9. package/src/.component/.expand/properties.js +2 -6
  10. package/src/.component/.expand/receivers.js +2 -6
  11. package/src/.component/.expand/version.js +39 -27
  12. package/src/.component/.normalize/events.js +12 -5
  13. package/src/.component/.normalize/index.js +3 -9
  14. package/src/.component/.normalize/operations.js +2 -6
  15. package/src/.component/.normalize/receivers.js +1 -5
  16. package/src/.component/collapse.js +7 -6
  17. package/src/.component/defaults.js +14 -7
  18. package/src/.component/dependencies.js +7 -6
  19. package/src/.component/dereference.js +8 -7
  20. package/src/.component/expand.js +2 -15
  21. package/src/.component/extensions.js +13 -7
  22. package/src/.component/index.js +9 -21
  23. package/src/.component/merge.js +22 -9
  24. package/src/.component/normalize.js +3 -7
  25. package/src/.component/schema.yaml +82 -41
  26. package/src/.component/validate.js +15 -16
  27. package/src/.context/.dependencies/connectors.js +2 -6
  28. package/src/.context/.dependencies/describe.js +1 -5
  29. package/src/.context/.dependencies/extensions.js +55 -18
  30. package/src/.context/.dependencies/index.js +3 -9
  31. package/src/.context/.dependencies/load.js +14 -13
  32. package/src/.context/.dependencies/resolve.js +23 -6
  33. package/src/.context/complete.js +1 -5
  34. package/src/.context/dependencies.js +2 -6
  35. package/src/.context/dereference.js +9 -6
  36. package/src/.context/expand.js +8 -6
  37. package/src/.context/index.js +6 -15
  38. package/src/.context/normalize.js +2 -6
  39. package/src/.context/schema.yaml +126 -7
  40. package/src/.context/validate.js +8 -14
  41. package/src/component.js +31 -28
  42. package/src/context.js +28 -20
  43. package/src/index.js +3 -9
  44. package/src/shortcuts.js +7 -12
  45. package/test/component/collapse.fixtures.js +2 -5
  46. package/test/component/collapse.test.js +17 -10
  47. package/test/component/dependencies.test.js +12 -10
  48. package/test/component/dereference.fixtures.js +2 -7
  49. package/test/component/dereference.test.js +9 -8
  50. package/test/component/dummies/extension/index.js +1 -5
  51. package/test/component/expand.fixtures.js +13 -13
  52. package/test/component/expand.test.js +25 -10
  53. package/test/component/normalize.fixtures.js +3 -7
  54. package/test/component/normalize.test.js +27 -17
  55. package/test/component/validate.fixtures.js +1 -5
  56. package/test/component/validate.test.js +89 -90
  57. package/test/context/complete.fixtures.js +2 -8
  58. package/test/context/complete.test.js +10 -8
  59. package/test/context/dependencies.load.test.js +13 -12
  60. package/test/context/dereference.fixtures.js +3 -9
  61. package/test/context/dereference.test.js +17 -7
  62. package/test/context/expand.fixtures.js +1 -5
  63. package/test/context/expand.test.js +34 -8
  64. package/test/context/normalize.fixtures.js +2 -7
  65. package/test/context/normalize.test.js +10 -8
  66. package/test/context/validate.fixtures.js +1 -6
  67. package/test/context/validate.test.js +54 -30
  68. package/test/shortcuts.fixtures.js +4 -9
  69. package/test/shortcuts.test.js +16 -15
  70. package/types/context/declaration.d.ts +25 -2
  71. package/types/context.d.ts +5 -4
  72. package/types/index.d.ts +3 -3
@@ -1,11 +1,10 @@
1
- // noinspection JSUnresolvedVariable
1
+ import { describe, it, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- 'use strict'
4
+ import clone from 'clone-deep'
4
5
 
5
- const clone = require('clone-deep')
6
-
7
- const { validate } = require('../../src/.component')
8
- const fixtures = require('./validate.fixtures')
6
+ import { validate } from '../../src/.component/index.js'
7
+ import * as fixtures from './validate.fixtures.js'
9
8
 
10
9
  let manifest
11
10
 
@@ -13,249 +12,249 @@ beforeEach(() => {
13
12
  manifest = clone(fixtures.ok)
14
13
  })
15
14
 
16
- it('should be ok', () => {
17
- expect(() => validate(manifest)).not.toThrow()
15
+ it('should be ok', async () => {
16
+ await assert.doesNotReject(validate(manifest))
18
17
  })
19
18
 
20
- it('should provide error', () => {
19
+ it('should provide error', async () => {
21
20
  manifest.foo = 'bar'
22
21
 
23
- expect(() => validate(manifest)).toThrow(/must NOT have additional property/)
22
+ await assert.rejects(validate(manifest))
24
23
  })
25
24
 
26
- it('should not have additional properties', () => {
25
+ it('should not have additional properties', async () => {
27
26
  manifest.foo = 'bar'
28
27
 
29
- expect(() => validate(manifest)).toThrow(/must NOT have additional property/)
28
+ await assert.rejects(validate(manifest))
30
29
  })
31
30
 
32
31
  describe('namespace', () => {
33
- it('should match token pattern', () => {
32
+ it('should match token pattern', async () => {
34
33
  manifest.namespace = '1'
35
- expect(() => validate(manifest)).toThrow(/must match pattern/)
34
+ await assert.rejects(validate(manifest), (error) => /must match pattern/.test(error.message))
36
35
 
37
36
  manifest.namespace = 'foo_'
38
- expect(() => validate(manifest)).toThrow(/must match pattern/)
37
+ await assert.rejects(validate(manifest), (error) => /must match pattern/.test(error.message))
39
38
 
40
39
  manifest.namespace = 'foo_bar'
41
- expect(() => validate(manifest)).toThrow(/must match pattern/)
40
+ await assert.rejects(validate(manifest), (error) => /must match pattern/.test(error.message))
42
41
 
43
42
  manifest.namespace = 'foo-'
44
- expect(() => validate(manifest)).toThrow(/must match pattern/)
43
+ await assert.rejects(validate(manifest), (error) => /must match pattern/.test(error.message))
45
44
 
46
45
  manifest.namespace = 'foo-bar'
47
- expect(() => validate(manifest)).toThrow('must match pattern')
46
+ await assert.rejects(validate(manifest), (error) => /must match pattern/.test(error.message))
48
47
 
49
48
  manifest.namespace = 'FooBar12'
50
- expect(() => validate(manifest)).not.toThrow()
49
+ await assert.doesNotReject(validate(manifest))
51
50
  })
52
51
 
53
- it('should forbid \'system\' namespace', () => {
52
+ it('should forbid \'system\' namespace', async () => {
54
53
  manifest.namespace = 'system'
55
- expect(() => validate(manifest)).toThrow(/must NOT be valid/)
54
+ await assert.rejects(validate(manifest), (error) => /must NOT be valid/.test(error.message))
56
55
  })
57
56
 
58
57
  it('should set `default` namespace', async () => {
59
58
  delete manifest.namespace
60
59
 
61
- expect(() => validate(manifest)).not.toThrow()
62
- expect(manifest.namespace).toStrictEqual('default')
60
+ await assert.doesNotReject(validate(manifest))
61
+ assert.deepStrictEqual(manifest.namespace, 'default')
63
62
  })
64
63
  })
65
64
 
66
65
  describe('name', () => {
67
- it('should be optional', () => {
66
+ it('should be optional', async () => {
68
67
  delete manifest.name
69
- expect(() => validate(manifest)).not.toThrow()
68
+ await assert.doesNotReject(validate(manifest))
70
69
  })
71
70
  })
72
71
 
73
72
  describe('entity', () => {
74
- it('should be optional', () => {
73
+ it('should be optional', async () => {
75
74
  delete manifest.entity
76
- expect(() => validate(manifest)).not.toThrow()
75
+ await assert.doesNotReject(validate(manifest))
77
76
  })
78
77
 
79
- it('should be object', () => {
78
+ it('should be object', async () => {
80
79
  manifest.entity = 'foo'
81
- expect(() => validate(manifest)).toThrow(/must be object/)
80
+ await assert.rejects(validate(manifest), (error) => /must be object/.test(error.message))
82
81
  })
83
82
 
84
- it('should not have additional properties', () => {
83
+ it('should not have additional properties', async () => {
85
84
  manifest.entity.foo = 'bar'
86
- expect(() => validate(manifest)).toThrow(/must NOT have additional property/)
85
+ await assert.rejects(validate(manifest))
87
86
  })
88
87
 
89
88
  describe('schema', () => {
90
- it('should be required', () => {
89
+ it('should be required', async () => {
91
90
  delete manifest.entity.schema
92
- expect(() => validate(manifest)).toThrow(/must have required property/)
91
+ await assert.rejects(validate(manifest))
93
92
  })
94
93
 
95
- it('should be JSON schema object', () => {
94
+ it('should be JSON schema object', async () => {
96
95
  manifest.entity.schema = { properties: { foo: 'bar' } }
97
- expect(() => validate(manifest)).toThrow()
96
+ await assert.rejects(validate(manifest))
98
97
  })
99
98
 
100
- it('should be JSON schema object of type object', () => {
99
+ it('should be JSON schema object of type object', async () => {
101
100
  manifest.entity.schema = { type: 'integer' }
102
- expect(() => validate(manifest)).toThrow(/must be equal to constant 'object'/)
101
+ await assert.rejects(validate(manifest), (error) => /must be equal to constant/.test(error.message))
103
102
 
104
103
  manifest.entity.schema = {}
105
104
  validate(manifest)
106
- expect(manifest.entity.schema.type).toBe('object')
105
+ assert.strictEqual(manifest.entity.schema.type, 'object')
107
106
  })
108
107
 
109
- it('should have property names matching token pattern', () => {
108
+ it('should have property names matching token pattern', async () => {
110
109
  manifest.entity.schema.properties._foo = { type: 'string' }
111
- expect(() => validate(manifest)).toThrow(/pattern/)
110
+ await assert.rejects(validate(manifest), (error) => /pattern/.test(error.message))
112
111
  })
113
112
 
114
- it('should allow default id', () => {
113
+ it('should allow default id', async () => {
115
114
  manifest.entity.schema.properties.id = {
116
115
  type: 'string',
117
116
  pattern: '^[a-fA-F0-9]+$'
118
117
  }
119
- expect(() => validate(manifest)).not.toThrow()
118
+ await assert.doesNotReject(validate(manifest))
120
119
  })
121
120
  })
122
121
 
123
122
  describe('associated', () => {
124
- it('should provide default', () => {
125
- expect(() => validate(manifest)).not.toThrow()
126
- expect(manifest.entity.associated).toBe(false)
123
+ it('should provide default', async () => {
124
+ await assert.doesNotReject(validate(manifest))
125
+ assert.strictEqual(manifest.entity.associated, false)
127
126
  })
128
127
  })
129
128
  })
130
129
 
131
130
  describe('bindings', () => {
132
- it('should be array of unique strings', () => {
131
+ it('should be array of unique strings', async () => {
133
132
  manifest.bindings = 'oops'
134
- expect(() => validate(manifest)).toThrow(/must be array/)
133
+ await assert.rejects(validate(manifest), (error) => /must be array/.test(error.message))
135
134
 
136
135
  manifest.bindings = ['oops', 'oops']
137
- expect(() => validate(manifest)).toThrow(/duplicate items/)
136
+ await assert.rejects(validate(manifest), (error) => /duplicate items/.test(error.message))
138
137
 
139
138
  manifest.bindings = ['oops', {}]
140
- expect(() => validate(manifest)).toThrow(/must be string/)
139
+ await assert.rejects(validate(manifest), (error) => /must be string/.test(error.message))
141
140
  })
142
141
 
143
- it('should forbid explicit loop', () => {
142
+ it('should forbid explicit loop', async () => {
144
143
  manifest.bindings = ['@toa.io/bindings.loop']
145
- expect(() => validate(manifest)).toThrow(/must NOT be valid/)
144
+ await assert.rejects(validate(manifest), (error) => /must NOT be valid/.test(error.message))
146
145
  })
147
146
  })
148
147
 
149
148
  describe('operations', () => {
150
- it('should be object', () => {
149
+ it('should be object', async () => {
151
150
  manifest.operations.get = 'bar'
152
- expect(() => validate(manifest)).toThrow(/must be object/)
151
+ await assert.rejects(validate(manifest), (error) => /must be object/.test(error.message))
153
152
  })
154
153
 
155
- it('should not have additional properties', () => {
154
+ it('should not have additional properties', async () => {
156
155
  manifest.operations.get.foo = 'bar'
157
- expect(() => validate(manifest)).toThrow(/additional property/)
156
+ await assert.rejects(validate(manifest))
158
157
  })
159
158
 
160
- it('should have type (transition or observation)', () => {
159
+ it('should have type (transition or observation)', async () => {
161
160
  delete manifest.operations.get.type
162
- expect(() => validate(manifest)).toThrow()
161
+ await assert.rejects(validate(manifest))
163
162
 
164
163
  manifest.operations.get.type = 'foo'
165
- expect(() => validate(manifest)).toThrow(/one of the allowed values/)
164
+ await assert.rejects(validate(manifest), (error) => /one of the allowed values/.test(error.message))
166
165
  })
167
166
 
168
- it('should forbid explicit loop', () => {
167
+ it('should forbid explicit loop', async () => {
169
168
  manifest.operations.get.bindings = ['@toa.io/bindings.loop']
170
- expect(() => validate(manifest)).toThrow(/must NOT be valid/)
169
+ await assert.rejects(validate(manifest), (error) => /must NOT be valid/.test(error.message))
171
170
  })
172
171
 
173
- it('should forbid query: false for observations', () => {
172
+ it('should forbid query: false for observations', async () => {
174
173
  manifest.operations.get.query = false
175
- expect(() => validate(manifest)).toThrow(/must NOT be valid/)
174
+ await assert.rejects(validate(manifest), (error) => /must NOT be valid/.test(error.message))
176
175
  })
177
176
 
178
- it.each([
179
- ['computation', 'compute'],
180
- ['effect', 'affect']
181
- ])('should set query: false for %s', async (_, operation) => {
177
+ for (const [_, operation] of [
178
+ ['computation', 'compute']
179
+ ])
180
+ it(`should set query: false for ${_}`, async () => {
182
181
  validate(manifest)
183
182
 
184
- expect(manifest.operations[operation].query).toBe(false)
183
+ assert.strictEqual(manifest.operations[operation].query, false)
185
184
  })
186
185
 
187
186
  describe('scope', () => {
188
- it('should have scope', () => {
187
+ it('should have scope', async () => {
189
188
  delete manifest.operations.get.scope
190
- expect(() => validate(manifest)).toThrow(/required property/)
189
+ await assert.rejects(validate(manifest), (error) => /required property/.test(error.message))
191
190
  })
192
191
 
193
- it('should allow only entity or set for observations', () => {
192
+ it('should allow only entity or set for observations', async () => {
194
193
  manifest.operations.get.scope = 'changeset'
195
- expect(() => validate(manifest)).toThrow(/allowed values/)
194
+ await assert.rejects(validate(manifest), (error) => /allowed values/.test(error.message))
196
195
  })
197
196
 
198
- it('should allow only entity for transitions', () => {
197
+ it('should allow only entity for transitions', async () => {
199
198
  manifest.operations.add.scope = 'changeset'
200
- expect(() => validate(manifest)).toThrow(/allowed values/)
199
+ await assert.rejects(validate(manifest), (error) => /allowed values/.test(error.message))
201
200
 
202
201
  manifest.operations.add.scope = 'set'
203
- expect(() => validate(manifest)).toThrow(/allowed values/)
202
+ await assert.rejects(validate(manifest), (error) => /allowed values/.test(error.message))
204
203
  })
205
204
 
206
- it('should allow only changeset for assignments', () => {
205
+ it('should allow only changeset for assignments', async () => {
207
206
  manifest.operations.set.scope = 'changeset'
208
- expect(() => validate(manifest)).not.toThrow()
207
+ await assert.doesNotReject(validate(manifest))
209
208
 
210
209
  manifest.operations.set.scope = 'set'
211
- expect(() => validate(manifest)).toThrow(/allowed values/)
210
+ await assert.rejects(validate(manifest), (error) => /allowed values/.test(error.message))
212
211
  })
213
212
  })
214
213
 
215
214
  describe('concurrency', () => {
216
- it('should be required for transitions', () => {
215
+ it('should be required for transitions', async () => {
217
216
  delete manifest.operations.add.concurrency
218
- expect(() => validate(manifest)).toThrow(/required property/)
217
+ await assert.rejects(validate(manifest), (error) => /required property/.test(error.message))
219
218
  })
220
219
 
221
- it('should throw for observations, assignments', () => {
220
+ it('should throw for observations, assignments', async () => {
222
221
  manifest.operations.get.concurrency = 'none'
223
- expect(() => validate(manifest)).toThrow()
222
+ await assert.rejects(validate(manifest))
224
223
  delete manifest.operations.get.concurrency
225
224
 
226
225
  manifest.operations.set.concurrency = 'none'
227
- expect(() => validate(manifest)).toThrow()
226
+ await assert.rejects(validate(manifest))
228
227
  })
229
228
  })
230
229
 
231
230
  describe('input, output', () => {
232
- it('should be schema', () => {
231
+ it('should be schema', async () => {
233
232
  manifest.operations.get.input = { properties: { foo: 'bar' } }
234
- expect(() => validate(manifest)).toThrow()
233
+ await assert.rejects(validate(manifest))
235
234
 
236
235
  delete manifest.operations.get.input
237
236
  manifest.operations.get.output = { properties: { foo: 'bar' } }
238
- expect(() => validate(manifest)).toThrow()
237
+ await assert.rejects(validate(manifest))
239
238
  })
240
239
  })
241
240
  })
242
241
 
243
242
  describe('receivers', () => {
244
- it('should throw if transition points to undefined operation', () => {
243
+ it('should throw if transition points to undefined operation', async () => {
245
244
  manifest.receivers['foo.bar.happened'].operation = 'notExists'
246
245
 
247
- expect(() => validate(manifest)).toThrow(/refers to undefined operation/)
246
+ await assert.rejects(validate(manifest), (error) => /refers to undefined operation/.test(error.message))
248
247
  })
249
248
 
250
- it('should throw if transition points to observation', () => {
249
+ it('should throw if transition points to observation', async () => {
251
250
  manifest.receivers['foo.bar.happened'].operation = 'get'
252
251
 
253
- expect(() => validate(manifest)).toThrow(/one of the allowed types/)
252
+ await assert.rejects(validate(manifest), (error) => /of the allowed types/.test(error.message))
254
253
  })
255
254
 
256
255
  it('should throw if source has a name `context`', async () => {
257
256
  manifest.receivers['foo.bar.happened'].source = 'context'
258
257
 
259
- expect(() => validate(manifest)).toThrow(/must NOT be valid/)
258
+ await assert.rejects(validate(manifest), (error) => /must NOT be valid/.test(error.message))
260
259
  })
261
260
  })
@@ -1,5 +1,3 @@
1
- 'use strict'
2
-
3
1
  const component = (id) => {
4
2
  const [namespace, name] = id.split('.')
5
3
 
@@ -16,12 +14,11 @@ const component = (id) => {
16
14
  }
17
15
  }
18
16
 
19
- const context = {
17
+ export const context = {
20
18
  runtime: '0.0.0',
21
19
  name: 'test',
22
20
  description: 'context fixture',
23
21
  version: '0.0.0',
24
- packages: 'namespaces/**/*',
25
22
  registry: 'localhost:5000',
26
23
  components: [
27
24
  component('a.b'),
@@ -43,7 +40,7 @@ const context = {
43
40
  }
44
41
 
45
42
  /** @type {Array<toa.norm.context.Composition>} */
46
- const compositions = [
43
+ export const compositions = [
47
44
  ...context.compositions,
48
45
  {
49
46
  name: 'd-a',
@@ -54,6 +51,3 @@ const compositions = [
54
51
  components: [component('d.b')]
55
52
  }
56
53
  ]
57
-
58
- exports.context = context
59
- exports.compositions = compositions
@@ -1,9 +1,11 @@
1
- 'use strict'
1
+ import { it, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { isDeepStrictEqual } from 'node:util'
2
4
 
3
- const clone = require('clone-deep')
5
+ import clone from 'clone-deep'
4
6
 
5
- const { complete } = require('../../src/.context')
6
- const fixtures = require('./complete.fixtures')
7
+ import { complete } from '../../src/.context/index.js'
8
+ import * as fixtures from './complete.fixtures.js'
7
9
 
8
10
  /** @type {toa.norm.Context} */
9
11
  let context
@@ -14,8 +16,8 @@ beforeEach(() => {
14
16
  })
15
17
 
16
18
  it('should complete compositions', () => {
17
- expect(context.compositions.length).toEqual(fixtures.compositions.length)
18
- expect(context.compositions).toEqual(expect.arrayContaining(fixtures.compositions))
19
+ assert.deepStrictEqual(context.compositions.length, fixtures.compositions.length)
20
+ assert.ok(fixtures.compositions.every((item) => context.compositions.some((candidate) => isDeepStrictEqual(candidate, item))))
19
21
  })
20
22
 
21
23
  it('should create if compositions are not set', () => {
@@ -26,6 +28,6 @@ it('should create if compositions are not set', () => {
26
28
  components: [component]
27
29
  }))
28
30
 
29
- expect(() => complete(context)).not.toThrow()
30
- expect(context.compositions).toStrictEqual(compositions)
31
+ assert.doesNotThrow(() => complete(context))
32
+ assert.deepStrictEqual(context.compositions, compositions)
31
33
  })
@@ -1,24 +1,25 @@
1
- 'use strict'
1
+ import { it } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const { join } = require('node:path')
4
- const { load } = require('../../src/.context/.dependencies/load')
4
+ import { join } from 'node:path'
5
+ import { load } from '../../src/.context/.dependencies/load.js'
5
6
 
6
7
  it('should be', async () => {
7
- expect(load).toBeInstanceOf(Function)
8
+ assert.ok(load instanceof Function)
8
9
  })
9
10
 
10
11
  it('should load module', async () => {
11
- const path = join(__dirname, '../../')
12
- const { metadata, module } = load(path)
12
+ const path = join(import.meta.dirname, '../../')
13
+ const { metadata, module } = await load(path)
13
14
 
14
- expect(metadata.name).toStrictEqual('@toa.io/norm')
15
- expect(module.context).toBeInstanceOf(Function)
15
+ assert.deepStrictEqual(metadata.name, '@toa.io/norm')
16
+ assert.ok(module.context instanceof Function)
16
17
  })
17
18
 
18
19
  it('should return null metadata if no package.json', async () => {
19
- const path = join(__dirname, '../../src')
20
- const { metadata, module } = load(path)
20
+ const path = join(import.meta.dirname, '../../src')
21
+ const { metadata, module } = await load(path)
21
22
 
22
- expect(metadata).toBeNull()
23
- expect(module.context).toBeInstanceOf(Function)
23
+ assert.strictEqual(metadata, null)
24
+ assert.ok(module.context instanceof Function)
24
25
  })
@@ -1,6 +1,4 @@
1
- 'use strict'
2
-
3
- const clone = require('clone-deep')
1
+ import clone from 'clone-deep'
4
2
 
5
3
  /**
6
4
  * @param id {string}
@@ -22,12 +20,11 @@ const component = (id) => {
22
20
  }
23
21
  }
24
22
 
25
- const context = {
23
+ export const context = {
26
24
  name: 'test',
27
25
  description: 'context fixture',
28
26
  version: '0.0.0',
29
27
  runtime: '0.0.0',
30
- packages: 'namespaces/**/*',
31
28
  registry: 'localhost:5000',
32
29
  components: [component('a.b'), component('b.a'), component('d.c')],
33
30
  compositions: [
@@ -42,7 +39,7 @@ const context = {
42
39
  ]
43
40
  }
44
41
 
45
- const expected = clone(context)
42
+ export const expected = clone(context)
46
43
 
47
44
  expected.compositions = [
48
45
  {
@@ -54,6 +51,3 @@ expected.compositions = [
54
51
  components: [component('d.c'), component('a.b')]
55
52
  }
56
53
  ]
57
-
58
- exports.context = context
59
- exports.expected = expected
@@ -1,24 +1,34 @@
1
- 'use strict'
1
+ import { it, before } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const clone = require('clone-deep')
4
+ import clone from 'clone-deep'
4
5
 
5
- const { dereference } = require('../../src/.context')
6
- const fixtures = require('./dereference.fixtures')
6
+ import { dereference } from '../../src/.context/index.js'
7
+ import * as fixtures from './dereference.fixtures.js'
7
8
 
8
9
  /** @type {toa.norm.Context} */
9
10
  let context
10
11
 
11
- beforeAll(() => {
12
+ before(() => {
12
13
  context = clone(fixtures.context)
13
14
  dereference(context)
14
15
  })
15
16
 
16
17
  it('should dereference', () => {
17
- expect(context).toEqual(expect.objectContaining(fixtures.expected))
18
+ assert.partialDeepStrictEqual(context, fixtures.expected)
18
19
  })
19
20
 
20
21
  it('should not throw on empty compositions', () => {
21
22
  context.compositions = undefined
22
23
 
23
- expect(() => dereference(context)).not.toThrow()
24
+ assert.doesNotThrow(() => dereference(context))
25
+ })
26
+
27
+ it('should throw on an unknown component', () => {
28
+ const broken = clone(fixtures.context)
29
+
30
+ broken.compositions[1].components.push('nope.here')
31
+
32
+ assert.throws(() => dereference(broken),
33
+ { message: "Composition 'bar' lists an unknown component 'nope.here'." })
24
34
  })
@@ -1,5 +1 @@
1
- 'use strict'
2
-
3
- const { context } = require('./validate.fixtures')
4
-
5
- exports.context = context
1
+ export { context } from './validate.fixtures.js'
@@ -1,10 +1,11 @@
1
- 'use strict'
1
+ import { describe, it, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
 
3
- const clone = require('clone-deep')
4
- const { generate } = require('randomstring')
4
+ import clone from 'clone-deep'
5
+ import { generate } from 'randomstring'
5
6
 
6
- const { expand } = require('../../src/.context')
7
- const fixtures = require('./expand.fixtures')
7
+ import { expand } from '../../src/.context/index.js'
8
+ import * as fixtures from './expand.fixtures.js'
8
9
 
9
10
  /** @type {toa.norm.context.Declaration | object} */
10
11
  let context
@@ -17,7 +18,7 @@ describe('annotations', () => {
17
18
  it('should not throw without annotations', () => {
18
19
  delete context.annotations
19
20
 
20
- expect(() => expand(context)).not.toThrow()
21
+ assert.doesNotThrow(() => expand(context))
21
22
  })
22
23
 
23
24
  it('should expand known annotations', () => {
@@ -28,7 +29,7 @@ describe('annotations', () => {
28
29
 
29
30
  expand(context)
30
31
 
31
- expect(context.annotations).toStrictEqual(fixtures.context.annotations)
32
+ assert.deepStrictEqual(context.annotations, fixtures.context.annotations)
32
33
  })
33
34
 
34
35
  it('should recognize annotations', () => {
@@ -36,6 +37,31 @@ describe('annotations', () => {
36
37
 
37
38
  expand(context)
38
39
 
39
- expect(context.annotations['@toa.io/storages.mongodb']).toBeDefined()
40
+ assert.notStrictEqual(context.annotations['@toa.io/storages.mongodb'], undefined)
41
+ })
42
+ })
43
+
44
+ describe('composition services', () => {
45
+ it('should resolve shortcuts', () => {
46
+ context.compositions[0].services = ['exposition', 'configuration']
47
+
48
+ expand(context)
49
+
50
+ assert.deepStrictEqual(context.compositions[0].services,
51
+ ['@toa.io/extensions.exposition', '@toa.io/extensions.configuration'])
52
+ })
53
+
54
+ it('should leave a package reference alone', () => {
55
+ context.compositions[0].services = ['@acme/extension']
56
+
57
+ expand(context)
58
+
59
+ assert.deepStrictEqual(context.compositions[0].services, ['@acme/extension'])
60
+ })
61
+
62
+ it('should not throw without compositions', () => {
63
+ delete context.compositions
64
+
65
+ assert.doesNotThrow(() => expand(context))
40
66
  })
41
67
  })
@@ -1,15 +1,12 @@
1
- 'use strict'
1
+ import { generate } from 'randomstring'
2
2
 
3
- const { generate } = require('randomstring')
4
-
5
- const context = {
3
+ export const context = {
6
4
  runtime: {
7
5
  version: '0.0.0'
8
6
  },
9
7
  name: 'test',
10
8
  description: 'context fixture',
11
9
  version: '0.0.0',
12
- packages: 'namespaces/**/*',
13
10
  registry: 'localhost:5000',
14
11
  compositions: [
15
12
  {
@@ -28,5 +25,3 @@ const context = {
28
25
  }
29
26
  }
30
27
  }
31
-
32
- exports.context = context