@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,17 +1,6 @@
1
- 'use strict'
1
+ import { entity, bridge, operations, events, receivers, extensions, properties, version } from './.expand/index.js'
2
2
 
3
- const {
4
- entity,
5
- bridge,
6
- operations,
7
- events,
8
- receivers,
9
- extensions,
10
- properties,
11
- version
12
- } = require('./.expand')
13
-
14
- async function expand (manifest) {
3
+ export async function expand (manifest) {
15
4
  entity(manifest)
16
5
  bridge(manifest)
17
6
  operations(manifest)
@@ -22,5 +11,3 @@ async function expand (manifest) {
22
11
 
23
12
  await version(manifest)
24
13
  }
25
-
26
- exports.expand = expand
@@ -1,10 +1,10 @@
1
- 'use strict'
1
+ import { find } from '@toa.io/generic'
2
+ import { resolve } from '../shortcuts.js'
2
3
 
3
- const { directory: { find } } = require('@toa.io/filesystem')
4
- const { resolve } = require('../shortcuts')
4
+ const cache = {}
5
5
 
6
- const extensions = (manifest) => {
7
- if (manifest.extensions === undefined) return
6
+ export const extensions = async (manifest) => {
7
+ manifest.extensions = Object.assign({}, PREDEFINED, manifest.extensions)
8
8
 
9
9
  const extensions = manifest.extensions
10
10
 
@@ -14,7 +14,9 @@ const extensions = (manifest) => {
14
14
  // relative path
15
15
  if (key[0] === '.') key = find(key, manifest.path)
16
16
 
17
- const extension = require(key)
17
+ cache[key] ??= import(key)
18
+
19
+ const extension = await cache[key]
18
20
 
19
21
  if (extension.manifest !== undefined) {
20
22
  declaration = extension.manifest(declaration, manifest)
@@ -29,4 +31,8 @@ const extensions = (manifest) => {
29
31
  }
30
32
  }
31
33
 
32
- exports.extensions = extensions
34
+ const PREDEFINED = {
35
+ '@toa.io/extensions.telemetry': null,
36
+ '@toa.io/extensions.fetch': null,
37
+ '@toa.io/extensions.introspection': null
38
+ }
@@ -1,21 +1,9 @@
1
- 'use strict'
2
-
3
- const { collapse } = require('./collapse')
4
- const { defaults } = require('./defaults')
5
- const { dependencies } = require('./dependencies')
6
- const { dereference } = require('./dereference')
7
- const { expand } = require('./expand')
8
- const { merge } = require('./merge')
9
- const { normalize } = require('./normalize')
10
- const { validate } = require('./validate')
11
- const { extensions } = require('./extensions')
12
-
13
- exports.collapse = collapse
14
- exports.defaults = defaults
15
- exports.dependencies = dependencies
16
- exports.dereference = dereference
17
- exports.expand = expand
18
- exports.merge = merge
19
- exports.normalize = normalize
20
- exports.validate = validate
21
- exports.extensions = extensions
1
+ export { collapse } from './collapse.js'
2
+ export { defaults } from './defaults.js'
3
+ export { dependencies } from './dependencies.js'
4
+ export { dereference } from './dereference.js'
5
+ export { expand } from './expand.js'
6
+ export { merge } from './merge.js'
7
+ export { normalize } from './normalize.js'
8
+ export { validate } from './validate.js'
9
+ export { extensions } from './extensions.js'
@@ -1,12 +1,11 @@
1
- 'use strict'
2
-
3
- const { merge } = require('@toa.io/generic')
1
+ import { merge } from '@toa.io/generic'
4
2
 
5
3
  const bridge = async (root, manifest) => {
6
4
  await Promise.all([
7
5
  define(root, manifest, 'operations'),
8
6
  define(root, manifest, 'events'),
9
- define(root, manifest, 'receivers')
7
+ define(root, manifest, 'receivers'),
8
+ define(root, manifest, 'guards')
10
9
  ])
11
10
  }
12
11
 
@@ -19,7 +18,7 @@ const define = async (root, manifest, property) => {
19
18
  if (item.bridge === undefined || item.bridge === manifest.bridge) continue // default bridge later
20
19
 
21
20
  const bridge = item.bridge || manifest.bridge
22
- const { define } = require(bridge)
21
+ const { define } = await req(bridge)
23
22
  const definition = await define[singular](root, endpoint)
24
23
 
25
24
  merge(item, definition)
@@ -44,18 +43,32 @@ const define = async (root, manifest, property) => {
44
43
 
45
44
  const declared = manifest[property][endpoint]
46
45
 
47
- if (declared === undefined) manifest[property][endpoint] = item
48
- else merge(declared, item)
46
+ try {
47
+ if (declared === undefined) manifest[property][endpoint] = item
48
+ else merge(declared, item)
49
+ } catch (error) {
50
+ console.error(`Error merging ${singular} '${endpoint}' in ${root}`)
51
+ throw error
52
+ }
49
53
  }
50
54
  }
51
55
  }
52
56
 
57
+ const cache = {}
58
+
59
+ // the promise is what is remembered, so a bridge is loaded once
60
+ function req (mod) {
61
+ cache[mod] ??= import(mod)
62
+
63
+ return cache[mod]
64
+ }
65
+
53
66
  const scan = async (bridge, root, property) => {
54
- const { define } = require(bridge)
67
+ const { define } = await req(bridge)
55
68
 
56
69
  if (property in define)
57
70
  return define[property](root)
58
71
  else return undefined
59
72
  }
60
73
 
61
- exports.merge = bridge
74
+ export { bridge as merge }
@@ -1,11 +1,7 @@
1
- 'use strict'
1
+ import { events, operations, receivers } from './.normalize/index.js'
2
2
 
3
- const { events, operations, receivers } = require('./.normalize')
4
-
5
- const normalize = (component) => {
3
+ export const normalize = async (component) => {
6
4
  operations(component)
7
- events(component)
5
+ await events(component)
8
6
  receivers(component)
9
7
  }
10
-
11
- exports.normalize = normalize
@@ -8,7 +8,7 @@ definitions:
8
8
  binding:
9
9
  type: string
10
10
  not:
11
- const: '@toa.io/bindings.loop' # loop is for system use only
11
+ const: "@toa.io/bindings.loop" # loop is for system use only
12
12
 
13
13
  type: object
14
14
  properties:
@@ -17,19 +17,19 @@ properties:
17
17
  nullable: true
18
18
  properties:
19
19
  prototype:
20
- $ref: '#/properties/prototype'
20
+ $ref: "#/properties/prototype"
21
21
  path:
22
22
  type: string
23
23
  operations:
24
24
  type: object
25
25
  propertyNames:
26
- $ref: '#/definitions/name'
26
+ $ref: "#/definitions/name"
27
27
  patternProperties:
28
- '.*':
28
+ ".*":
29
29
  type: object
30
30
  properties:
31
31
  bridge:
32
- $ref: '#/properties/bridge'
32
+ $ref: "#/properties/bridge"
33
33
 
34
34
  path:
35
35
  type: string
@@ -38,19 +38,23 @@ 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'
50
- default: 'default'
52
+ type: string
53
+ pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
54
+ default: "default"
51
55
  not:
52
56
  oneOf:
53
- - const: 'system'
57
+ - const: "system"
54
58
 
55
59
  version:
56
60
  type: string
@@ -60,15 +64,17 @@ properties:
60
64
  properties:
61
65
  image:
62
66
  type: string
67
+ run:
68
+ type: string
63
69
 
64
70
  entity:
65
71
  type: object
66
72
  properties:
67
73
  storage:
68
74
  type: string
69
- default: '@toa.io/storages.mongodb'
75
+ default: "@toa.io/storages.mongodb"
70
76
  schema:
71
- $ref: 'definitions#/definitions/schema'
77
+ $ref: https://json-schema.org/draft/2019-09/schema
72
78
  type: object
73
79
  properties:
74
80
  type:
@@ -78,24 +84,24 @@ properties:
78
84
  type: object
79
85
  propertyNames:
80
86
  oneOf:
81
- - $ref: '#/definitions/name'
87
+ - $ref: "#/definitions/name"
82
88
  - enum: [_version, _created, _updated, _deleted]
83
89
  unique:
84
90
  type: object
85
91
  patternProperties:
86
- '.*':
92
+ ".*":
87
93
  type: array
88
94
  items:
89
95
  type: string
90
96
  index:
91
97
  type: object
92
98
  patternProperties:
93
- '.*':
99
+ ".*":
94
100
  type: object
95
101
  patternProperties:
96
- '.*':
102
+ ".*":
97
103
  type: string
98
- enum: [asc, desc, hash]
104
+ enum: [asc, desc, hash, text]
99
105
  associated:
100
106
  type: boolean
101
107
  default: false
@@ -109,7 +115,7 @@ properties:
109
115
  type: array
110
116
  uniqueItems: true
111
117
  items:
112
- $ref: '#/definitions/binding'
118
+ $ref: "#/definitions/binding"
113
119
 
114
120
  bridge:
115
121
  type: string
@@ -117,27 +123,41 @@ properties:
117
123
  operations:
118
124
  type: object
119
125
  propertyNames:
120
- $ref: '#/definitions/name'
126
+ $ref: "#/definitions/name"
121
127
  patternProperties:
122
- '.*':
128
+ ".*":
123
129
  type: object
124
130
  properties:
125
131
  type:
126
- enum: [transition, observation, assignment, computation, effect]
132
+ enum:
133
+ [
134
+ transition,
135
+ observation,
136
+ assignment,
137
+ computation,
138
+ effect,
139
+ unmanaged,
140
+ ]
127
141
  scope:
128
- enum: [object, objects, changeset, none]
142
+ enum: [object, objects, changeset, stream, none]
129
143
  concurrency:
130
144
  enum: [none, retry]
131
145
  forward:
132
- $ref: '#/definitions/name'
146
+ $ref: "#/definitions/name"
133
147
  bridge:
134
148
  type: string
135
149
  bindings:
136
- $ref: '#/properties/bindings'
150
+ $ref: "#/properties/bindings"
137
151
  input:
138
- $ref: 'definitions#/definitions/schema'
152
+ $ref: https://json-schema.org/draft/2019-09/schema
139
153
  output:
140
- $ref: 'definitions#/definitions/schema'
154
+ $ref: https://json-schema.org/draft/2019-09/schema
155
+ default: {}
156
+ errors:
157
+ # what a reply may carry as a code: the error schema allows either
158
+ type: array
159
+ items:
160
+ type: [string, integer]
141
161
  query:
142
162
  type: boolean
143
163
  required: [type, scope, bindings]
@@ -149,8 +169,8 @@ properties:
149
169
  then:
150
170
  properties:
151
171
  scope:
152
- enum: [object]
153
- if: # transition query: false
172
+ enum: [object, objects]
173
+ if: # not query: false
154
174
  not:
155
175
  properties:
156
176
  query:
@@ -158,6 +178,17 @@ properties:
158
178
  required: [query]
159
179
  then:
160
180
  required: [concurrency]
181
+ - if: # transition and scope=objects
182
+ properties:
183
+ type:
184
+ const: transition
185
+ scope:
186
+ const: objects
187
+ then:
188
+ properties:
189
+ query:
190
+ not:
191
+ const: false
161
192
  - if: # not transition
162
193
  not:
163
194
  properties:
@@ -174,7 +205,7 @@ properties:
174
205
  then:
175
206
  properties:
176
207
  scope:
177
- enum: [object, objects, none]
208
+ enum: [object, objects, stream, none]
178
209
  query:
179
210
  not:
180
211
  const: false
@@ -189,7 +220,7 @@ properties:
189
220
  - if: # computation
190
221
  properties:
191
222
  type:
192
- const: computation
223
+ enum: [computation, unmanaged]
193
224
  then:
194
225
  properties:
195
226
  scope:
@@ -205,20 +236,17 @@ properties:
205
236
  then:
206
237
  properties:
207
238
  scope:
208
- const: none
209
239
  default: none
210
- query:
211
- const: false
212
- default: false
240
+ enum: [object, objects, stream, none]
213
241
  additionalProperties: false
214
242
  additionalProperties: false
215
243
 
216
244
  events:
217
245
  type: object
218
246
  propertyNames:
219
- $ref: 'definitions#/definitions/name'
247
+ $ref: "#/definitions/name"
220
248
  patternProperties:
221
- '.*':
249
+ ".*":
222
250
  type: object
223
251
  properties:
224
252
  bridge:
@@ -226,7 +254,7 @@ properties:
226
254
  path:
227
255
  type: string
228
256
  binding:
229
- $ref: '#/definitions/binding'
257
+ $ref: "#/definitions/binding"
230
258
  conditioned:
231
259
  type: boolean
232
260
  default: false
@@ -239,17 +267,17 @@ properties:
239
267
  receivers:
240
268
  type: object
241
269
  patternProperties:
242
- '.*':
270
+ ".*":
243
271
  type: object
244
272
  properties:
245
273
  operation:
246
- $ref: 'definitions#/definitions/name'
274
+ $ref: "#/definitions/name"
247
275
  bridge:
248
276
  type: string
249
277
  binding:
250
278
  type: string
251
279
  source:
252
- $ref: 'definitions#/definitions/name'
280
+ $ref: "#/definitions/name"
253
281
  not:
254
282
  const: context
255
283
  path:
@@ -260,9 +288,22 @@ properties:
260
288
  adaptive:
261
289
  type: boolean
262
290
  default: false
291
+ arguments:
292
+ type: array
263
293
  required: [operation]
264
294
  additionalProperties: false
265
295
 
296
+ guards:
297
+ type: object
298
+ patternProperties:
299
+ ".*":
300
+ type: object
301
+ properties:
302
+ bridge: { type: string }
303
+ path: { type: string }
304
+ required: [bridge, path]
305
+ additionalProperties: false
306
+
266
307
  extensions:
267
308
  type: object
268
309
 
@@ -1,25 +1,26 @@
1
- 'use strict'
1
+ import path from 'node:path'
2
2
 
3
- const path = require('node:path')
3
+ import { readFileSync } from 'node:fs'
4
+ import { yaml } from '@toa.io/generic'
5
+ import * as schemas from '@toa.io/schemas'
4
6
 
5
- const { load } = require('@toa.io/yaml')
6
- const { Schema } = require('@toa.io/schema')
7
+ const object = yaml.load(readFileSync(path.resolve(import.meta.dirname, 'schema.yaml'), 'utf8'))
8
+ const schema = schemas.schema(object)
7
9
 
8
- const object = load.sync(path.resolve(__dirname, 'schema.yaml'))
9
- const schema = new Schema(object)
10
-
11
- const validate = (manifest) => {
10
+ export const validate = async (manifest) => {
12
11
  const error = schema.fit(manifest)
13
12
 
14
- if (error) throw new Error(error.message)
13
+ if (error) throw error
15
14
 
16
- if (manifest.events !== undefined) events(manifest)
15
+ if (manifest.events !== undefined) await events(manifest)
17
16
  if (manifest.receivers !== undefined) receivers(manifest)
18
17
  }
19
18
 
20
- const events = (manifest) => {
19
+ const events = async (manifest) => {
21
20
  for (const [label, event] of Object.entries(manifest.events)) {
22
- if (require(event.binding).properties.async !== true) {
21
+ const { properties } = await import(event.binding)
22
+
23
+ if (properties.async !== true) {
23
24
  throw new Error(`Event '${label}' binding '${event.binding}' is not async`)
24
25
  }
25
26
  }
@@ -32,11 +33,9 @@ const receivers = (manifest) => {
32
33
  }
33
34
 
34
35
  if (!TYPES.has(manifest.operations[receiver.operation].type)) {
35
- throw new Error(`Receiver '${locator}' must refer to an operation of one of the allowed types: ${Array.from(TYPES).join(', ')}`)
36
+ throw new Error(`Receiver '${locator}' must refer to an operation of the allowed types: ${Array.from(TYPES).join(', ')}`)
36
37
  }
37
38
  }
38
39
  }
39
40
 
40
- const TYPES = new Set(['transition', 'effect'])
41
-
42
- exports.validate = validate
41
+ const TYPES = new Set(['transition', 'assignment', 'effect', 'unmanaged'])
@@ -1,8 +1,6 @@
1
- 'use strict'
1
+ import { resolve } from 'node:path'
2
2
 
3
- const { resolve } = require('node:path')
4
-
5
- const connectors = (context, extracted) => {
3
+ export const connectors = (context, extracted) => {
6
4
  const connectors = {}
7
5
 
8
6
  const components = (context.components === undefined
@@ -47,5 +45,3 @@ const connectors = (context, extracted) => {
47
45
 
48
46
  return connectors
49
47
  }
50
-
51
- exports.connectors = connectors
@@ -1,10 +1,6 @@
1
- 'use strict'
2
-
3
1
  /**
4
2
  * @param {toa.norm.Component} component
5
3
  * @param {Object} manifest
6
4
  * @returns {toa.norm.context.dependencies.Instance}
7
5
  */
8
- const describe = (component, manifest = undefined) => ({ locator: component.locator, manifest })
9
-
10
- exports.describe = describe
6
+ export const describe = (component, manifest = undefined) => ({ locator: component.locator, manifest })
@@ -1,9 +1,16 @@
1
- 'use strict'
1
+ import { component as load } from '../../component.js'
2
+ import { load as loadDependency } from './load.js'
2
3
 
3
- const extensions = async (context) => {
4
+ export const extensions = async (context) => {
4
5
  const extensions = {}
5
6
  const components = context.components?.slice() ?? []
6
- const extracted = await extractExtensionComponents(components, extensions)
7
+
8
+ // an extension a composition runs may be referenced by no component of this context,
9
+ // and its own components must be extracted all the same
10
+ const declared = await extractDeclaredServices(context, extensions)
11
+
12
+ const extracted = declared.concat(
13
+ await extractExtensionComponents(components.concat(declared), extensions, context.annotations))
7
14
 
8
15
  components.push(...extracted)
9
16
 
@@ -20,8 +27,25 @@ const extensions = async (context) => {
20
27
  return { extensions, components: extracted }
21
28
  }
22
29
 
23
- async function extractExtensionComponents (components, extensions) {
24
- const { component: load } = require('../../component')
30
+ async function extractDeclaredServices (context, extensions) {
31
+ const extracted = []
32
+
33
+ for (const composition of context.compositions ?? [])
34
+ for (const reference of composition.services ?? []) {
35
+ if (reference in extensions) continue
36
+
37
+ try {
38
+ extracted.push(...await extract(reference, extensions, context.annotations))
39
+ } catch (e) {
40
+ throw new Error(`Composition '${composition.name}' lists '${reference}', ` +
41
+ `which cannot be resolved: ${e.message}`, { cause: e })
42
+ }
43
+ }
44
+
45
+ return extracted
46
+ }
47
+
48
+ async function extractExtensionComponents (components, extensions, annotations) {
25
49
 
26
50
  const extracted = []
27
51
 
@@ -31,26 +55,39 @@ async function extractExtensionComponents (components, extensions) {
31
55
  for (const reference of Object.keys(component.extensions)) {
32
56
  if (reference in extensions) continue
33
57
 
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)
44
- }
58
+ extracted.push(...await extract(reference, extensions, annotations))
45
59
  }
46
60
  }
47
61
 
48
62
  if (extracted.length === 0)
49
63
  return extracted
50
64
 
51
- const deeper = await extractExtensionComponents(extracted, extensions)
65
+ const deeper = await extractExtensionComponents(extracted, extensions, annotations)
52
66
 
53
67
  return extracted.concat(deeper)
54
68
  }
55
69
 
56
- exports.extensions = extensions
70
+ /**
71
+ * The components an extension contributes, if it contributes any.
72
+ *
73
+ * @param {string} reference
74
+ * @param {object} extensions
75
+ * @param {object} [annotations]
76
+ * @returns {Promise<Array<toa.norm.Component>>}
77
+ */
78
+ async function extract (reference, extensions, annotations) {
79
+ extensions[reference] = []
80
+
81
+ const { metadata, module: mod } = await loadDependency(reference)
82
+
83
+ if (mod.components === undefined) return []
84
+
85
+ // the annotation decides whether an extension contributes components at all
86
+ const annotation = annotations?.[metadata?.name ?? reference]
87
+ const extracted = []
88
+
89
+ for (const path of mod.components(annotation).paths)
90
+ extracted.push(await load(path))
91
+
92
+ return extracted
93
+ }
@@ -1,9 +1,3 @@
1
- 'use strict'
2
-
3
- const { connectors } = require('./connectors')
4
- const { extensions } = require('./extensions')
5
- const { resolve } = require('./resolve')
6
-
7
- exports.connectors = connectors
8
- exports.extensions = extensions
9
- exports.resolve = resolve
1
+ export { connectors } from './connectors.js'
2
+ export { extensions } from './extensions.js'
3
+ export { resolve } from './resolve.js'