@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.
- package/CHANGELOG.md +195 -0
- package/package.json +8 -7
- package/src/.component/.expand/bridge.js +2 -6
- package/src/.component/.expand/entity.js +2 -9
- package/src/.component/.expand/events.js +2 -6
- package/src/.component/.expand/extensions.js +4 -8
- package/src/.component/.expand/index.js +8 -19
- package/src/.component/.expand/operations.js +2 -9
- package/src/.component/.expand/properties.js +2 -6
- package/src/.component/.expand/receivers.js +2 -6
- package/src/.component/.expand/version.js +39 -27
- package/src/.component/.normalize/events.js +12 -5
- package/src/.component/.normalize/index.js +3 -9
- package/src/.component/.normalize/operations.js +2 -6
- package/src/.component/.normalize/receivers.js +1 -5
- package/src/.component/collapse.js +7 -6
- package/src/.component/defaults.js +14 -7
- package/src/.component/dependencies.js +7 -6
- package/src/.component/dereference.js +8 -7
- package/src/.component/expand.js +2 -15
- package/src/.component/extensions.js +13 -7
- package/src/.component/index.js +9 -21
- package/src/.component/merge.js +22 -9
- package/src/.component/normalize.js +3 -7
- package/src/.component/schema.yaml +82 -41
- package/src/.component/validate.js +15 -16
- package/src/.context/.dependencies/connectors.js +2 -6
- package/src/.context/.dependencies/describe.js +1 -5
- package/src/.context/.dependencies/extensions.js +55 -18
- package/src/.context/.dependencies/index.js +3 -9
- package/src/.context/.dependencies/load.js +14 -13
- package/src/.context/.dependencies/resolve.js +23 -6
- package/src/.context/complete.js +1 -5
- package/src/.context/dependencies.js +2 -6
- package/src/.context/dereference.js +9 -6
- package/src/.context/expand.js +8 -6
- package/src/.context/index.js +6 -15
- package/src/.context/normalize.js +2 -6
- package/src/.context/schema.yaml +126 -7
- package/src/.context/validate.js +8 -14
- package/src/component.js +31 -28
- package/src/context.js +28 -20
- package/src/index.js +3 -9
- package/src/shortcuts.js +7 -12
- package/test/component/collapse.fixtures.js +2 -5
- package/test/component/collapse.test.js +17 -10
- package/test/component/dependencies.test.js +12 -10
- package/test/component/dereference.fixtures.js +2 -7
- package/test/component/dereference.test.js +9 -8
- package/test/component/dummies/extension/index.js +1 -5
- package/test/component/expand.fixtures.js +13 -13
- package/test/component/expand.test.js +25 -10
- package/test/component/normalize.fixtures.js +3 -7
- package/test/component/normalize.test.js +27 -17
- package/test/component/validate.fixtures.js +1 -5
- package/test/component/validate.test.js +89 -90
- package/test/context/complete.fixtures.js +2 -8
- package/test/context/complete.test.js +10 -8
- package/test/context/dependencies.load.test.js +13 -12
- package/test/context/dereference.fixtures.js +3 -9
- package/test/context/dereference.test.js +17 -7
- package/test/context/expand.fixtures.js +1 -5
- package/test/context/expand.test.js +34 -8
- package/test/context/normalize.fixtures.js +2 -7
- package/test/context/normalize.test.js +10 -8
- package/test/context/validate.fixtures.js +1 -6
- package/test/context/validate.test.js +54 -30
- package/test/shortcuts.fixtures.js +4 -9
- package/test/shortcuts.test.js +16 -15
- package/types/context/declaration.d.ts +25 -2
- package/types/context.d.ts +5 -4
- package/types/index.d.ts +3 -3
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import { createRequire } from 'node:module'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { pathToFileURL } from 'node:url'
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
// import.meta.resolve takes no paths, and a dependency is named rather than
|
|
7
|
+
// written as a path
|
|
8
|
+
const require = createRequire(import.meta.url)
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* @param {string} path
|
|
7
|
-
* @returns {{ metadata: object, module: object }}
|
|
12
|
+
* @returns {Promise<{ metadata: object, module: object }>}
|
|
8
13
|
*/
|
|
9
|
-
function load (path) {
|
|
14
|
+
export async function load (path) {
|
|
10
15
|
const metadata = loadMetadata(path)
|
|
11
|
-
const module = loadModule(path)
|
|
16
|
+
const module = await loadModule(path)
|
|
12
17
|
|
|
13
18
|
return { metadata, module }
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
function loadMetadata (reference) {
|
|
17
|
-
reference = join(reference, 'package.json')
|
|
18
|
-
|
|
19
22
|
try {
|
|
20
|
-
return require(reference)
|
|
23
|
+
return JSON.parse(readFileSync(require.resolve(join(reference, 'package.json')), 'utf8'))
|
|
21
24
|
} catch {
|
|
22
25
|
return null
|
|
23
26
|
}
|
|
@@ -25,12 +28,10 @@ function loadMetadata (reference) {
|
|
|
25
28
|
|
|
26
29
|
/**
|
|
27
30
|
* @param {string} reference
|
|
28
|
-
* @returns {object}
|
|
31
|
+
* @returns {Promise<object>}
|
|
29
32
|
*/
|
|
30
|
-
function loadModule (reference) {
|
|
33
|
+
async function loadModule (reference) {
|
|
31
34
|
const path = require.resolve(reference)
|
|
32
35
|
|
|
33
|
-
return
|
|
36
|
+
return await import(pathToFileURL(path).href)
|
|
34
37
|
}
|
|
35
|
-
|
|
36
|
-
exports.load = load
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { load } from './load.js'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const resolve = (references, annotations) => {
|
|
3
|
+
export const resolve = async (references, annotations = {}) => {
|
|
6
4
|
const dependencies = {}
|
|
7
5
|
|
|
8
6
|
for (const [dependency, components] of Object.entries(references)) {
|
|
9
|
-
const { metadata, module } = load(dependency)
|
|
7
|
+
const { metadata, module } = await load(dependency)
|
|
10
8
|
const id = metadata.name
|
|
11
9
|
|
|
12
10
|
const instances = components.map((component) => ({
|
|
@@ -24,7 +22,26 @@ const resolve = (references, annotations) => {
|
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
|
|
25
|
+
for (const dependency of Object.keys(annotations)) {
|
|
26
|
+
if (dependency in dependencies) continue
|
|
27
|
+
|
|
28
|
+
// an annotation may be keyed by a dependency id rather than by a module reference
|
|
29
|
+
const module = await optional(dependency)
|
|
30
|
+
|
|
31
|
+
if (module?.standalone === true) dependencies[dependency] = []
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
return dependencies
|
|
28
35
|
}
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} reference
|
|
39
|
+
* @returns {object | null}
|
|
40
|
+
*/
|
|
41
|
+
async function optional (reference) {
|
|
42
|
+
try {
|
|
43
|
+
return (await load(reference)).module
|
|
44
|
+
} catch {
|
|
45
|
+
return null
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/.context/complete.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Completes missing compositions with unused components
|
|
5
3
|
* @param {toa.norm.Context} context
|
|
6
4
|
* @returns {void}
|
|
7
5
|
*/
|
|
8
|
-
const complete = (context) => {
|
|
6
|
+
export const complete = (context) => {
|
|
9
7
|
/** @type {Set<string>} */
|
|
10
8
|
const composed = new Set()
|
|
11
9
|
|
|
@@ -29,5 +27,3 @@ const complete = (context) => {
|
|
|
29
27
|
context.compositions.push({ name, components: [component] })
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
|
-
|
|
33
|
-
exports.complete = complete
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { connectors, extensions, resolve } from './.dependencies/index.js'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const dependencies = async (context) => {
|
|
3
|
+
export const dependencies = async (context) => {
|
|
6
4
|
const { extensions: e, components } = await extensions(context)
|
|
7
5
|
const c = connectors(context, components)
|
|
8
6
|
const references = { ...c, ...e }
|
|
9
7
|
|
|
10
8
|
return resolve(references, context.annotations)
|
|
11
9
|
}
|
|
12
|
-
|
|
13
|
-
exports.dependencies = dependencies
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Resolves component IDs within compositions with Component objects
|
|
5
3
|
* @param {toa.norm.Context} context
|
|
6
4
|
* @returns {void}
|
|
7
5
|
*/
|
|
8
|
-
const dereference = (context) => {
|
|
6
|
+
export const dereference = (context) => {
|
|
9
7
|
const components = map(context.components)
|
|
10
8
|
|
|
11
9
|
if (context.compositions !== undefined) {
|
|
12
10
|
for (const composition of context.compositions) {
|
|
13
|
-
composition.components = composition.components.map((id) =>
|
|
11
|
+
composition.components = composition.components.map((id) => {
|
|
12
|
+
const component = components[id]
|
|
13
|
+
|
|
14
|
+
if (component === undefined)
|
|
15
|
+
throw new Error(`Composition '${composition.name}' lists an unknown component '${id}'.`)
|
|
16
|
+
|
|
17
|
+
return component
|
|
18
|
+
})
|
|
14
19
|
}
|
|
15
20
|
}
|
|
16
21
|
}
|
|
@@ -27,5 +32,3 @@ const map = (components) => {
|
|
|
27
32
|
|
|
28
33
|
return map
|
|
29
34
|
}
|
|
30
|
-
|
|
31
|
-
exports.dereference = dereference
|
package/src/.context/expand.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const shortcuts = require('../shortcuts')
|
|
1
|
+
import * as shortcuts from '../shortcuts.js'
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* @param {toa.norm.context.Declaration | object} context
|
|
7
5
|
*/
|
|
8
|
-
const expand = (context) => {
|
|
6
|
+
export const expand = (context) => {
|
|
9
7
|
shortcuts.recognize(shortcuts.SHORTCUTS, context, 'annotations')
|
|
10
8
|
shortcuts.recognize(shortcuts.SHORTCUTS, context.annotations)
|
|
11
|
-
}
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
// a composition names a service the way a manifest names an extension, and everything
|
|
11
|
+
// downstream matches it against a dependency, which is keyed by package reference
|
|
12
|
+
for (const composition of context.compositions ?? [])
|
|
13
|
+
if (composition.services !== undefined)
|
|
14
|
+
composition.services = composition.services.map(shortcuts.resolve)
|
|
15
|
+
}
|
package/src/.context/index.js
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const { normalize } = require('./normalize')
|
|
8
|
-
const { validate } = require('./validate')
|
|
9
|
-
|
|
10
|
-
exports.complete = complete
|
|
11
|
-
exports.dependencies = dependencies
|
|
12
|
-
exports.dereference = dereference
|
|
13
|
-
exports.expand = expand
|
|
14
|
-
exports.normalize = normalize
|
|
15
|
-
exports.validate = validate
|
|
1
|
+
export { complete } from './complete.js'
|
|
2
|
+
export { dependencies } from './dependencies.js'
|
|
3
|
+
export { dereference } from './dereference.js'
|
|
4
|
+
export { expand } from './expand.js'
|
|
5
|
+
export { normalize } from './normalize.js'
|
|
6
|
+
export { validate } from './validate.js'
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import * as runtime from '@toa.io/runtime'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @param {toa.norm.context.Declaration | Object} context
|
|
5
5
|
*/
|
|
6
|
-
const normalize = (context) => {
|
|
7
|
-
const runtime = require('@toa.io/runtime')
|
|
8
|
-
|
|
6
|
+
export const normalize = (context) => {
|
|
9
7
|
if (context.runtime === undefined) context.runtime = { version: runtime.version }
|
|
10
8
|
if (typeof context.runtime === 'string') context.runtime = { version: context.runtime }
|
|
11
9
|
|
|
@@ -15,5 +13,3 @@ const normalize = (context) => {
|
|
|
15
13
|
|
|
16
14
|
if (typeof context.registry === 'string') context.registry = { base: context.registry }
|
|
17
15
|
}
|
|
18
|
-
|
|
19
|
-
exports.normalize = normalize
|
package/src/.context/schema.yaml
CHANGED
|
@@ -6,12 +6,10 @@ properties:
|
|
|
6
6
|
version:
|
|
7
7
|
type: string
|
|
8
8
|
name:
|
|
9
|
-
$ref: 'definitions#/definitions/label'
|
|
10
|
-
description:
|
|
11
9
|
type: string
|
|
12
|
-
|
|
10
|
+
pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(-([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))*$
|
|
11
|
+
description:
|
|
13
12
|
type: string
|
|
14
|
-
default: components/*
|
|
15
13
|
build:
|
|
16
14
|
type: object
|
|
17
15
|
properties:
|
|
@@ -46,24 +44,145 @@ properties:
|
|
|
46
44
|
- linux/amd64
|
|
47
45
|
- linux/arm/v7
|
|
48
46
|
- linux/arm64
|
|
49
|
-
required: [base
|
|
47
|
+
# required: [base]
|
|
50
48
|
compositions:
|
|
51
49
|
type: array
|
|
52
50
|
minItems: 1
|
|
53
51
|
items:
|
|
54
52
|
type: object
|
|
53
|
+
additionalProperties: false
|
|
55
54
|
properties:
|
|
56
55
|
name:
|
|
57
|
-
|
|
56
|
+
type: string
|
|
57
|
+
pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
|
|
58
58
|
image:
|
|
59
59
|
type: string
|
|
60
60
|
components:
|
|
61
61
|
type: array
|
|
62
62
|
minItems: 1
|
|
63
63
|
items:
|
|
64
|
-
|
|
64
|
+
type: string
|
|
65
|
+
pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(\.([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))$
|
|
66
|
+
services:
|
|
67
|
+
description: >
|
|
68
|
+
Extension services this composition runs in its own pod, named by shortcut or
|
|
69
|
+
package reference, rather than each as its own deployment. A service listed here
|
|
70
|
+
keeps its own Service and Ingress; what changes is the pod they select.
|
|
71
|
+
type: array
|
|
72
|
+
minItems: 1
|
|
73
|
+
items:
|
|
74
|
+
type: string
|
|
75
|
+
minLength: 1
|
|
76
|
+
resources:
|
|
77
|
+
$ref: '#/definitions/resources'
|
|
65
78
|
required: [name, components]
|
|
79
|
+
atomicity:
|
|
80
|
+
description: >
|
|
81
|
+
Where the replicas of a component decide together: who owns what, what they have spent
|
|
82
|
+
between them, and which of them holds a name while it works. Absent or unreachable,
|
|
83
|
+
nothing is owned and whoever asked stands down; metering and locking are refused.
|
|
84
|
+
type: object
|
|
85
|
+
additionalProperties: false
|
|
86
|
+
properties:
|
|
87
|
+
redis:
|
|
88
|
+
description: >
|
|
89
|
+
One address, or an odd number of them — independent servers, not the nodes of a
|
|
90
|
+
cluster. A lock is taken on a quorum of them; the registry and the meter use the
|
|
91
|
+
first, because each of them counts on a single key.
|
|
92
|
+
oneOf:
|
|
93
|
+
- type: string
|
|
94
|
+
- type: array
|
|
95
|
+
minItems: 1
|
|
96
|
+
items:
|
|
97
|
+
type: string
|
|
98
|
+
interval:
|
|
99
|
+
description: >
|
|
100
|
+
How often a replica registers, in milliseconds. It has to comfortably exceed a round
|
|
101
|
+
trip to Redis and the jitter around it, and nothing is owned until two consecutive
|
|
102
|
+
intervals have agreed — so this is also how long a replica owns nothing after it
|
|
103
|
+
joins, restarts or stalls.
|
|
104
|
+
type: integer
|
|
105
|
+
minimum: 100
|
|
106
|
+
required: [redis]
|
|
107
|
+
outbox:
|
|
108
|
+
type: object
|
|
109
|
+
additionalProperties: false
|
|
110
|
+
properties:
|
|
111
|
+
interval:
|
|
112
|
+
description: >
|
|
113
|
+
The pump's cycle, in milliseconds. One cycle reads what is unpublished, publishes it
|
|
114
|
+
and marks it. In steady state it reads nothing, so this is budgeted for how fast a rare
|
|
115
|
+
failure heals rather than for how fast events flow.
|
|
116
|
+
type: integer
|
|
117
|
+
minimum: 100
|
|
118
|
+
batch:
|
|
119
|
+
description: >
|
|
120
|
+
How many rows one read brings back. A page that comes back full is read on from,
|
|
121
|
+
so this bounds a read rather than a cycle.
|
|
122
|
+
type: integer
|
|
123
|
+
minimum: 1
|
|
124
|
+
retention:
|
|
125
|
+
description: >
|
|
126
|
+
Seconds a published row is kept as a change log before it expires. A row that never
|
|
127
|
+
made it out has no expiry and is never reaped.
|
|
128
|
+
type: integer
|
|
129
|
+
minimum: 0
|
|
130
|
+
events:
|
|
131
|
+
description: >
|
|
132
|
+
Events of this context that are consumed outside it. An event is otherwise published only
|
|
133
|
+
where something in the context receives it.
|
|
134
|
+
type: array
|
|
135
|
+
items:
|
|
136
|
+
type: string
|
|
137
|
+
pattern: ^[a-zA-Z][a-zA-Z0-9]*\.[a-zA-Z][a-zA-Z0-9]*\.[a-zA-Z][a-zA-Z0-9]*$
|
|
138
|
+
mono:
|
|
139
|
+
type: object
|
|
140
|
+
additionalProperties: false
|
|
141
|
+
properties:
|
|
142
|
+
replicas:
|
|
143
|
+
type: integer
|
|
144
|
+
minimum: 1
|
|
145
|
+
resources:
|
|
146
|
+
$ref: '#/definitions/resources'
|
|
147
|
+
ingress:
|
|
148
|
+
type: object
|
|
149
|
+
additionalProperties: false
|
|
150
|
+
properties:
|
|
151
|
+
hosts:
|
|
152
|
+
type: array
|
|
153
|
+
minItems: 1
|
|
154
|
+
items:
|
|
155
|
+
type: string
|
|
156
|
+
class:
|
|
157
|
+
type: string
|
|
158
|
+
annotations:
|
|
159
|
+
type: object
|
|
160
|
+
default:
|
|
161
|
+
type: boolean
|
|
66
162
|
annotations:
|
|
67
163
|
type: object
|
|
164
|
+
resources:
|
|
165
|
+
$ref: '#/definitions/resources'
|
|
68
166
|
required: [runtime, name, registry]
|
|
69
167
|
additionalProperties: false
|
|
168
|
+
|
|
169
|
+
definitions:
|
|
170
|
+
# What a deployment may take. `null` deploys it without any, which is a decision
|
|
171
|
+
# rather than an omission — every deployment has to make one.
|
|
172
|
+
resources:
|
|
173
|
+
type: object
|
|
174
|
+
nullable: true
|
|
175
|
+
additionalProperties: false
|
|
176
|
+
properties:
|
|
177
|
+
cpu:
|
|
178
|
+
type: array
|
|
179
|
+
items:
|
|
180
|
+
type: string
|
|
181
|
+
minItems: 2
|
|
182
|
+
maxItems: 2
|
|
183
|
+
memory:
|
|
184
|
+
type: array
|
|
185
|
+
items:
|
|
186
|
+
type: string
|
|
187
|
+
minItems: 2
|
|
188
|
+
maxItems: 2
|
package/src/.context/validate.js
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
6
|
-
const
|
|
7
|
+
const path = resolve(import.meta.dirname, 'schema.yaml')
|
|
8
|
+
const object = yaml.load(readFileSync(path, 'utf8'))
|
|
9
|
+
const schema = schemas.schema(object)
|
|
7
10
|
|
|
8
|
-
const
|
|
9
|
-
const object = load.sync(path)
|
|
10
|
-
const schema = new Schema(object)
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @param {toa.norm.context.Declaration} context
|
|
14
|
-
*/
|
|
15
|
-
const validate = (context) => {
|
|
11
|
+
export const validate = (context) => {
|
|
16
12
|
schema.validate(context)
|
|
17
13
|
}
|
|
18
|
-
|
|
19
|
-
exports.validate = validate
|
package/src/component.js
CHANGED
|
@@ -1,49 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
merge,
|
|
12
|
-
validate,
|
|
13
|
-
collapse,
|
|
14
|
-
dereference,
|
|
15
|
-
defaults,
|
|
16
|
-
normalize,
|
|
17
|
-
extensions
|
|
18
|
-
} = require('./.component')
|
|
19
|
-
|
|
20
|
-
const component = async (path) => {
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { readFile } from 'node:fs/promises'
|
|
4
|
+
import { yaml as jsyaml } from '@toa.io/generic'
|
|
5
|
+
import { find } from '@toa.io/generic'
|
|
6
|
+
import { Locator } from '@toa.io/core'
|
|
7
|
+
|
|
8
|
+
import { expand, merge, validate, collapse, dereference, defaults, normalize, extensions } from './.component/index.js'
|
|
9
|
+
|
|
10
|
+
export const component = async (path) => {
|
|
21
11
|
const manifest = await load(path)
|
|
22
12
|
|
|
23
|
-
normalize(manifest)
|
|
24
|
-
validate(manifest)
|
|
25
|
-
extensions(manifest)
|
|
13
|
+
await normalize(manifest, path)
|
|
14
|
+
await validate(manifest)
|
|
15
|
+
await extensions(manifest)
|
|
26
16
|
|
|
27
17
|
manifest.locator = new Locator(manifest.name, manifest.namespace)
|
|
28
18
|
|
|
29
19
|
return manifest
|
|
30
20
|
}
|
|
31
21
|
|
|
32
|
-
const load = async (path, base) => {
|
|
22
|
+
const load = async (path, base, proto = false) => {
|
|
33
23
|
if (base !== undefined) path = find(path, base, MANIFEST)
|
|
34
24
|
|
|
35
25
|
const file = join(path, MANIFEST)
|
|
36
|
-
const manifest =
|
|
26
|
+
const manifest = await read(file) ?? {}
|
|
37
27
|
|
|
38
28
|
manifest.path = path
|
|
39
29
|
|
|
40
|
-
defaults(manifest)
|
|
30
|
+
defaults(manifest, proto)
|
|
41
31
|
await expand(manifest)
|
|
42
32
|
|
|
43
33
|
await merge(path, manifest)
|
|
44
34
|
|
|
45
35
|
if (manifest.prototype !== null) {
|
|
46
|
-
const prototype = await load(manifest.prototype, path)
|
|
36
|
+
const prototype = await load(manifest.prototype, path, true)
|
|
47
37
|
|
|
48
38
|
collapse(manifest, prototype)
|
|
49
39
|
}
|
|
@@ -56,4 +46,17 @@ const load = async (path, base) => {
|
|
|
56
46
|
|
|
57
47
|
const MANIFEST = 'manifest.toa.yaml'
|
|
58
48
|
|
|
59
|
-
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Reads a YAML file, resolving anchors into distinct objects so that
|
|
53
|
+
* mutating one node cannot reach another.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} path
|
|
56
|
+
* @return {Promise<object>}
|
|
57
|
+
*/
|
|
58
|
+
async function read (path) {
|
|
59
|
+
const object = jsyaml.load(await readFile(path, 'utf8'))
|
|
60
|
+
|
|
61
|
+
return jsyaml.load(jsyaml.dump(object, { noRefs: true, lineWidth: -1 }))
|
|
62
|
+
}
|
package/src/context.js
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import { convolve } from '@toa.io/generic'
|
|
3
|
+
import glob from 'fast-glob'
|
|
4
|
+
import { readFile } from 'node:fs/promises'
|
|
5
|
+
import { yaml as jsyaml } from '@toa.io/generic'
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
const { convolve } = require('@toa.io/generic')
|
|
5
|
-
const { directory: { glob } } = require('@toa.io/filesystem')
|
|
6
|
-
const { load } = require('@toa.io/yaml')
|
|
7
|
+
import { component } from './component.js'
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
import { dependencies, normalize, complete, dereference, expand, validate } from './.context/index.js'
|
|
9
10
|
|
|
10
|
-
const {
|
|
11
|
-
dependencies,
|
|
12
|
-
normalize,
|
|
13
|
-
complete,
|
|
14
|
-
dereference,
|
|
15
|
-
expand,
|
|
16
|
-
validate
|
|
17
|
-
} = require('./.context')
|
|
18
|
-
|
|
19
|
-
const context = async (root, environment = process.env.TOA_ENV) => {
|
|
11
|
+
export const context = async (root, environment = process.env.TOA_ENV) => {
|
|
20
12
|
const path = resolve(root, CONTEXT)
|
|
21
|
-
const context = /** @type {toa.norm.Context} */ await
|
|
22
|
-
const pattern = resolve(root, context.packages)
|
|
13
|
+
const context = /** @type {toa.norm.Context} */ await read(path)
|
|
23
14
|
|
|
24
15
|
context.environment = environment
|
|
25
16
|
|
|
@@ -29,7 +20,7 @@ const context = async (root, environment = process.env.TOA_ENV) => {
|
|
|
29
20
|
|
|
30
21
|
validate(context)
|
|
31
22
|
|
|
32
|
-
const paths = await glob(
|
|
23
|
+
const paths = await glob(resolve(root, COMPONENTS), GLOB)
|
|
33
24
|
|
|
34
25
|
context.components = await Promise.all(paths.map(component))
|
|
35
26
|
context.dependencies = await dependencies(context)
|
|
@@ -41,5 +32,22 @@ const context = async (root, environment = process.env.TOA_ENV) => {
|
|
|
41
32
|
}
|
|
42
33
|
|
|
43
34
|
const CONTEXT = 'context.toa.yaml'
|
|
35
|
+
const COMPONENTS = 'components/*'
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
const GLOB = { onlyDirectories: true, absolute: true }
|
|
39
|
+
|
|
44
40
|
|
|
45
|
-
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Reads a YAML file, resolving anchors into distinct objects so that
|
|
44
|
+
* mutating one node cannot reach another.
|
|
45
|
+
*
|
|
46
|
+
* @param {string} path
|
|
47
|
+
* @return {Promise<object>}
|
|
48
|
+
*/
|
|
49
|
+
async function read (path) {
|
|
50
|
+
const object = jsyaml.load(await readFile(path, 'utf8'))
|
|
51
|
+
|
|
52
|
+
return jsyaml.load(jsyaml.dump(object, { noRefs: true, lineWidth: -1 }))
|
|
53
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const { component } = require('./component')
|
|
5
|
-
|
|
6
|
-
exports.shortcuts = require('./shortcuts')
|
|
7
|
-
|
|
8
|
-
exports.context = context
|
|
9
|
-
exports.component = component
|
|
1
|
+
export { context } from './context.js'
|
|
2
|
+
export { component } from './component.js'
|
|
3
|
+
export * as shortcuts from './shortcuts.js'
|
package/src/shortcuts.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { empty, merge } = require('@toa.io/generic')
|
|
1
|
+
import { empty, merge } from '@toa.io/generic'
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Resolves shortcuts
|
|
@@ -8,7 +6,7 @@ const { empty, merge } = require('@toa.io/generic')
|
|
|
8
6
|
* @param {string} token
|
|
9
7
|
* @returns {string}
|
|
10
8
|
*/
|
|
11
|
-
const resolve = (token) => {
|
|
9
|
+
export const resolve = (token) => {
|
|
12
10
|
if (token in SHORTCUTS) return SHORTCUTS[token]
|
|
13
11
|
else return token
|
|
14
12
|
}
|
|
@@ -20,7 +18,7 @@ const resolve = (token) => {
|
|
|
20
18
|
* @param {Object} object
|
|
21
19
|
* @param {string} [group]
|
|
22
20
|
*/
|
|
23
|
-
const recognize = (shortcuts, object, group) => {
|
|
21
|
+
export const recognize = (shortcuts, object, group) => {
|
|
24
22
|
if (object === undefined) return
|
|
25
23
|
|
|
26
24
|
const target = group === undefined ? object : {}
|
|
@@ -38,7 +36,7 @@ const recognize = (shortcuts, object, group) => {
|
|
|
38
36
|
if (group !== undefined && !empty(target)) object[group] = merge(object[group], target)
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
const SHORTCUTS = {
|
|
39
|
+
export const SHORTCUTS = {
|
|
42
40
|
amqp: '@toa.io/bindings.amqp',
|
|
43
41
|
node: '@toa.io/bridges.node',
|
|
44
42
|
bash: '@toa.io/bridges.bash',
|
|
@@ -48,11 +46,8 @@ const SHORTCUTS = {
|
|
|
48
46
|
exposition: '@toa.io/extensions.exposition',
|
|
49
47
|
realtime: '@toa.io/extensions.realtime',
|
|
50
48
|
configuration: '@toa.io/extensions.configuration',
|
|
51
|
-
origins: '@toa.io/extensions.origins',
|
|
52
49
|
stash: '@toa.io/extensions.stash',
|
|
53
|
-
storages: '@toa.io/extensions.storages'
|
|
50
|
+
storages: '@toa.io/extensions.storages',
|
|
51
|
+
telemetry: '@toa.io/extensions.telemetry',
|
|
52
|
+
introspection: '@toa.io/extensions.introspection'
|
|
54
53
|
}
|
|
55
|
-
|
|
56
|
-
exports.recognize = recognize
|
|
57
|
-
exports.resolve = resolve
|
|
58
|
-
exports.SHORTCUTS = SHORTCUTS
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { generate } = require('randomstring')
|
|
1
|
+
import { generate } from 'randomstring'
|
|
4
2
|
|
|
5
3
|
const entity = {
|
|
6
4
|
manifest: {
|
|
@@ -88,7 +86,6 @@ const operations = {
|
|
|
88
86
|
result: {
|
|
89
87
|
prototype: {
|
|
90
88
|
prototype: null,
|
|
91
|
-
path: expect.any(String),
|
|
92
89
|
operations: {
|
|
93
90
|
add: {
|
|
94
91
|
bridge: 'a'
|
|
@@ -131,4 +128,4 @@ const remotes = {
|
|
|
131
128
|
}
|
|
132
129
|
}
|
|
133
130
|
|
|
134
|
-
|
|
131
|
+
export const samples = { entity, operations, remotes }
|