@toa.io/norm 1.0.0-alpha.32 → 1.0.0-alpha.320
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 +298 -0
- package/package.json +9 -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 +7 -9
- package/src/.component/.expand/index.js +7 -19
- package/src/.component/.expand/operations.js +2 -9
- package/src/.component/.expand/receivers.js +4 -7
- package/src/.component/.expand/version.js +69 -28
- package/src/.component/.normalize/entity.js +7 -0
- package/src/.component/.normalize/events.js +16 -4
- package/src/.component/.normalize/index.js +4 -9
- package/src/.component/.normalize/operations.js +13 -6
- package/src/.component/.normalize/receivers.js +4 -5
- package/src/.component/collapse.js +60 -9
- package/src/.component/defaults.js +5 -11
- package/src/.component/dependencies.js +14 -10
- package/src/.component/dereference.js +5 -49
- package/src/.component/expand.js +3 -9
- package/src/.component/extensions.js +9 -10
- package/src/.component/index.js +10 -21
- package/src/.component/merge.js +25 -15
- package/src/.component/migrations.js +57 -0
- package/src/.component/normalize.js +10 -6
- package/src/.component/schema.yaml +162 -73
- package/src/.component/validate.js +63 -17
- package/src/.context/.dependencies/connectors.js +5 -9
- package/src/.context/.dependencies/describe.js +4 -5
- package/src/.context/.dependencies/extensions.js +93 -20
- package/src/.context/.dependencies/index.js +3 -9
- package/src/.context/.dependencies/resolve.js +44 -7
- package/src/.context/complete.js +1 -5
- package/src/.context/converge.js +31 -0
- package/src/.context/dependencies.js +43 -6
- package/src/.context/dereference.js +11 -6
- package/src/.context/evict.js +38 -0
- package/src/.context/expand.js +11 -6
- package/src/.context/index.js +8 -15
- package/src/.context/normalize.js +9 -7
- package/src/.context/schema.yaml +183 -11
- package/src/.context/validate.js +11 -14
- package/src/component.js +33 -14
- package/src/context.js +44 -15
- package/src/definition.js +63 -0
- package/src/entity.js +15 -0
- package/src/index.js +7 -9
- package/src/manifest.js +154 -0
- package/src/map.js +24 -0
- package/src/shortcuts.js +11 -15
- package/test/component/collapse.fixtures.js +30 -39
- package/test/component/collapse.test.js +90 -10
- package/test/component/dependencies.test.js +16 -14
- package/test/component/dereference.fixtures.js +10 -98
- package/test/component/dereference.test.js +10 -14
- package/test/component/dummies/extension/index.js +1 -5
- package/test/component/dummies/migrations/conflicting/migrations/0001-one.yaml +2 -0
- package/test/component/dummies/migrations/conflicting/migrations/0001-one.yml +2 -0
- package/test/component/dummies/migrations/malformed/migrations/0001-one.yaml +1 -0
- package/test/component/dummies/migrations/ordered/migrations/0001-first.yml +4 -0
- package/test/component/dummies/migrations/ordered/migrations/0002-second.yaml +4 -0
- package/test/component/dummies/migrations/ordered/migrations/0010-third.json +1 -0
- package/test/component/dummies/migrations/stateless/migrations/0001-one.yaml +2 -0
- package/test/component/expand.fixtures.js +13 -13
- package/test/component/expand.test.js +17 -13
- package/test/component/migrations.test.js +62 -0
- package/test/component/normalize.fixtures.js +3 -7
- package/test/component/normalize.test.js +94 -28
- package/test/component/validate.fixtures.js +17 -15
- package/test/component/validate.test.js +271 -109
- package/test/context/complete.fixtures.js +2 -8
- package/test/context/complete.test.js +14 -8
- package/test/context/converge.test.js +57 -0
- package/test/context/dereference.fixtures.js +3 -9
- package/test/context/dereference.test.js +18 -7
- package/test/context/evict.fixtures.js +39 -0
- package/test/context/evict.test.js +73 -0
- package/test/context/expand.fixtures.js +1 -5
- package/test/context/expand.test.js +36 -8
- package/test/context/normalize.fixtures.js +2 -7
- package/test/context/normalize.test.js +33 -9
- package/test/context/validate.fixtures.js +1 -6
- package/test/context/validate.test.js +173 -35
- package/test/definition.test.js +35 -0
- package/test/dummies/bare/index.js +1 -0
- package/test/dummies/defined/definition.js +1 -0
- package/test/dummies/defined/index.js +1 -0
- package/test/dummies/defined/package.json +1 -0
- package/test/manifest.test.js +126 -0
- package/test/shortcuts.fixtures.js +4 -9
- package/test/shortcuts.test.js +17 -15
- package/test/system.test.js +31 -0
- package/types/component.d.ts +29 -4
- package/types/context/declaration.d.ts +34 -3
- package/types/context.d.ts +27 -13
- package/types/entity.d.ts +7 -0
- package/types/index.d.ts +18 -3
- package/src/.component/.expand/properties.js +0 -14
- package/src/.context/.dependencies/load.js +0 -36
- package/test/context/dependencies.load.test.js +0 -24
|
@@ -1,12 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
import { Locator } from '@toa.io/core'
|
|
2
|
+
import { converge } from '../converge.js'
|
|
3
|
+
import { component as load } from '../../component.js'
|
|
4
|
+
import { definition } from '../../definition.js'
|
|
2
5
|
|
|
3
|
-
const extensions = async (context) => {
|
|
6
|
+
export const extensions = async (context) => {
|
|
4
7
|
const extensions = {}
|
|
5
8
|
const components = context.components?.slice() ?? []
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
/** the components each extension brings, by reference
|
|
11
|
+
* @type {Map<string, toa.norm.Component[]>} */
|
|
12
|
+
const contributed = new Map()
|
|
13
|
+
|
|
14
|
+
// an extension a composition runs may be referenced by no component of this context,
|
|
15
|
+
// and its own components must be extracted all the same
|
|
16
|
+
const declared = await extractDeclaredServices(context, extensions, contributed)
|
|
17
|
+
|
|
18
|
+
const extracted = declared.concat(
|
|
19
|
+
await extractExtensionComponents(
|
|
20
|
+
components.concat(declared),
|
|
21
|
+
extensions,
|
|
22
|
+
contributed,
|
|
23
|
+
context.annotations
|
|
24
|
+
)
|
|
25
|
+
)
|
|
7
26
|
|
|
8
27
|
components.push(...extracted)
|
|
9
28
|
|
|
29
|
+
// after the extraction, because what an extension ships converges like anything else
|
|
30
|
+
converge(context, components)
|
|
31
|
+
|
|
10
32
|
for (const component of components) {
|
|
11
33
|
if (component.extensions === undefined) continue
|
|
12
34
|
|
|
@@ -17,12 +39,33 @@ const extensions = async (context) => {
|
|
|
17
39
|
}
|
|
18
40
|
}
|
|
19
41
|
|
|
20
|
-
return { extensions, components: extracted }
|
|
42
|
+
return { extensions, components: extracted, contributed }
|
|
21
43
|
}
|
|
22
44
|
|
|
23
|
-
async function
|
|
24
|
-
const
|
|
45
|
+
async function extractDeclaredServices(context, extensions, contributed) {
|
|
46
|
+
const extracted = []
|
|
47
|
+
|
|
48
|
+
for (const composition of context.compositions ?? [])
|
|
49
|
+
for (const reference of composition.services ?? []) {
|
|
50
|
+
if (reference in extensions) continue
|
|
25
51
|
|
|
52
|
+
try {
|
|
53
|
+
extracted.push(
|
|
54
|
+
...(await extract(reference, extensions, contributed, context.annotations))
|
|
55
|
+
)
|
|
56
|
+
} catch (e) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Composition '${composition.name}' lists '${reference}', ` +
|
|
59
|
+
`which cannot be resolved: ${e.message}`,
|
|
60
|
+
{ cause: e }
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return extracted
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function extractExtensionComponents(components, extensions, contributed, annotations) {
|
|
26
69
|
const extracted = []
|
|
27
70
|
|
|
28
71
|
for (const component of components) {
|
|
@@ -31,26 +74,56 @@ async function extractExtensionComponents (components, extensions) {
|
|
|
31
74
|
for (const reference of Object.keys(component.extensions)) {
|
|
32
75
|
if (reference in extensions) continue
|
|
33
76
|
|
|
34
|
-
|
|
77
|
+
extracted.push(...(await extract(reference, extensions, contributed, annotations)))
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (extracted.length === 0) return extracted
|
|
35
82
|
|
|
36
|
-
|
|
83
|
+
const deeper = await extractExtensionComponents(
|
|
84
|
+
extracted,
|
|
85
|
+
extensions,
|
|
86
|
+
contributed,
|
|
87
|
+
annotations
|
|
88
|
+
)
|
|
37
89
|
|
|
38
|
-
|
|
90
|
+
return extracted.concat(deeper)
|
|
91
|
+
}
|
|
39
92
|
|
|
40
|
-
|
|
41
|
-
|
|
93
|
+
/**
|
|
94
|
+
* The components an extension contributes, if it contributes any.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} reference
|
|
97
|
+
* @param {object} extensions
|
|
98
|
+
* @param {Map<string, toa.norm.Component[]>} contributed
|
|
99
|
+
* @param {object} [annotations]
|
|
100
|
+
* @returns {Promise<Array<toa.norm.Component>>}
|
|
101
|
+
*/
|
|
102
|
+
async function extract(reference, extensions, contributed, annotations) {
|
|
103
|
+
extensions[reference] = []
|
|
42
104
|
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
105
|
+
const { name, module: mod } = await definition(reference)
|
|
47
106
|
|
|
48
|
-
if (
|
|
49
|
-
return extracted
|
|
107
|
+
if (mod.components === undefined) return []
|
|
50
108
|
|
|
51
|
-
|
|
109
|
+
// the annotation decides whether an extension contributes components at all
|
|
110
|
+
const annotation = annotations?.[name]
|
|
111
|
+
const { manifests, paths } = mod.components(annotation)
|
|
52
112
|
|
|
53
|
-
|
|
113
|
+
// a definition carries the manifests, read where the extension is not installed;
|
|
114
|
+
// an entry names the directories, where it is
|
|
115
|
+
const extracted = manifests === undefined ? [] : manifests.map(revive)
|
|
116
|
+
|
|
117
|
+
if (manifests === undefined) for (const path of paths) extracted.push(await load(path))
|
|
118
|
+
|
|
119
|
+
contributed.set(reference, extracted)
|
|
120
|
+
|
|
121
|
+
return extracted
|
|
54
122
|
}
|
|
55
123
|
|
|
56
|
-
|
|
124
|
+
/** A manifest as a digest carries it, which is one norm read, without the locator. */
|
|
125
|
+
function revive(manifest) {
|
|
126
|
+
manifest.locator = new Locator(manifest.name, manifest.namespace)
|
|
127
|
+
|
|
128
|
+
return manifest
|
|
129
|
+
}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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'
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { definition } from '../../definition.js'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const resolve = (references, annotations) => {
|
|
3
|
+
export const resolve = async (references, annotations = {}, context = {}) => {
|
|
6
4
|
const dependencies = {}
|
|
7
5
|
|
|
8
6
|
for (const [dependency, components] of Object.entries(references)) {
|
|
9
|
-
const {
|
|
10
|
-
const id = metadata.name
|
|
7
|
+
const { name: id, module } = await definition(dependency)
|
|
11
8
|
|
|
12
9
|
const instances = components.map((component) => ({
|
|
13
10
|
locator: component.locator,
|
|
@@ -22,9 +19,49 @@ const resolve = (references, annotations) => {
|
|
|
22
19
|
if (annotation !== undefined && module.annotation !== undefined) {
|
|
23
20
|
annotations[id] = module.annotation(annotation, instances)
|
|
24
21
|
}
|
|
22
|
+
|
|
23
|
+
// what a declaration costs to install, read from the definition rather than from the
|
|
24
|
+
// package: a deploy installs it, and nothing that declares nothing carries it. A component
|
|
25
|
+
// is asked for its own instance; a composition that runs the package's service is asked
|
|
26
|
+
// with none, because what a service brings is not a component's to declare
|
|
27
|
+
if (module.installs !== undefined) {
|
|
28
|
+
for (const instance of instances)
|
|
29
|
+
Object.assign(
|
|
30
|
+
(instance.component.packages ??= {}),
|
|
31
|
+
module.installs(instance, annotations[id])
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const service = module.installs(undefined, annotations[id])
|
|
35
|
+
|
|
36
|
+
// mono runs every service in one process, so it takes every service's packages
|
|
37
|
+
Object.assign((context.packages ??= {}), service)
|
|
38
|
+
|
|
39
|
+
for (const composition of context.compositions ?? [])
|
|
40
|
+
if (composition.services?.includes(dependency) === true)
|
|
41
|
+
Object.assign((composition.packages ??= {}), service)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const dependency of Object.keys(annotations)) {
|
|
46
|
+
if (dependency in dependencies) continue
|
|
47
|
+
|
|
48
|
+
// an annotation may be keyed by a dependency id rather than by a module reference
|
|
49
|
+
const module = await optional(dependency)
|
|
50
|
+
|
|
51
|
+
if (module?.standalone === true) dependencies[dependency] = []
|
|
25
52
|
}
|
|
26
53
|
|
|
27
54
|
return dependencies
|
|
28
55
|
}
|
|
29
56
|
|
|
30
|
-
|
|
57
|
+
/**
|
|
58
|
+
* @param {string} reference
|
|
59
|
+
* @returns {object | null}
|
|
60
|
+
*/
|
|
61
|
+
async function optional(reference) {
|
|
62
|
+
try {
|
|
63
|
+
return (await definition(reference)).module
|
|
64
|
+
} catch {
|
|
65
|
+
return null
|
|
66
|
+
}
|
|
67
|
+
}
|
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
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A context that declares convergence converges every component that stores anything, and no
|
|
3
|
+
* manifest says so. An extension is loaded, deployed and hooked because a component's
|
|
4
|
+
* `extensions` names it, so this is where they come to name it.
|
|
5
|
+
*
|
|
6
|
+
* **Including the components an extension ships**, which is why this runs where they are
|
|
7
|
+
* known rather than over what the context declares: an application deployed as two regions
|
|
8
|
+
* whose identity does not converge is one where a user registered in the first does not
|
|
9
|
+
* exist in the second.
|
|
10
|
+
*
|
|
11
|
+
* There is nothing per-component to normalize and nothing to opt out of: a region is
|
|
12
|
+
* infrastructure, and what a component stores is not its business. What is genuinely owned by
|
|
13
|
+
* one region — which delayed calls this one makes — is said where that is decided, in
|
|
14
|
+
* `cadence.regions`, and not by holding the records back.
|
|
15
|
+
*
|
|
16
|
+
* @param {toa.norm.Context} context
|
|
17
|
+
* @param {toa.norm.Component[]} components every component the context deploys
|
|
18
|
+
* @returns {void}
|
|
19
|
+
*/
|
|
20
|
+
export const converge = (context, components) => {
|
|
21
|
+
if (context.annotations?.[REFERENCE] === undefined) return
|
|
22
|
+
|
|
23
|
+
for (const component of components) {
|
|
24
|
+
if (component.entity === undefined) continue
|
|
25
|
+
|
|
26
|
+
component.extensions ??= {}
|
|
27
|
+
component.extensions[REFERENCE] ??= null
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const REFERENCE = '@toa.io/extensions.convergence'
|
|
@@ -1,13 +1,50 @@
|
|
|
1
|
-
|
|
1
|
+
import { connectors, extensions, resolve } from './.dependencies/index.js'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
export const dependencies = async (context) => {
|
|
4
|
+
const { extensions: e, components, contributed } = await extensions(context)
|
|
5
|
+
|
|
6
|
+
unmanaged(context, contributed)
|
|
4
7
|
|
|
5
|
-
const dependencies = async (context) => {
|
|
6
|
-
const { extensions: e, components } = await extensions(context)
|
|
7
8
|
const c = connectors(context, components)
|
|
8
9
|
const references = { ...c, ...e }
|
|
9
10
|
|
|
10
|
-
return resolve(references, context.annotations)
|
|
11
|
+
return resolve(references, context.annotations, context)
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Marks as evicted what only evicted components require: the components an extension brings,
|
|
16
|
+
* where nothing a deployment carries references the extension and no composition runs it. A
|
|
17
|
+
* storage or a binding needs no mark of its own — its instances are components, and a
|
|
18
|
+
* deployment reads theirs.
|
|
19
|
+
*
|
|
20
|
+
* @param {toa.norm.Context} context
|
|
21
|
+
* @param {Map<string, toa.norm.Component[]>} contributed
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
function unmanaged(context, contributed) {
|
|
25
|
+
const components = context.components ?? []
|
|
26
|
+
|
|
27
|
+
if (!components.some((component) => component.evicted === true)) return
|
|
28
|
+
|
|
29
|
+
const required = new Set()
|
|
30
|
+
const pending = components.filter((component) => component.evicted !== true)
|
|
31
|
+
|
|
32
|
+
// what a composition runs is deployed for being listed, whoever references it
|
|
33
|
+
for (const composition of context.compositions ?? [])
|
|
34
|
+
for (const reference of composition.services ?? [])
|
|
35
|
+
pending.push(...(contributed.get(reference) ?? []))
|
|
36
|
+
|
|
37
|
+
while (pending.length > 0) {
|
|
38
|
+
const component = pending.pop()
|
|
39
|
+
|
|
40
|
+
if (required.has(component)) continue
|
|
41
|
+
|
|
42
|
+
required.add(component)
|
|
43
|
+
|
|
44
|
+
for (const reference of Object.keys(component.extensions ?? {}))
|
|
45
|
+
pending.push(...(contributed.get(reference) ?? []))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const brought of contributed.values())
|
|
49
|
+
for (const component of brought) if (!required.has(component)) component.evicted = true
|
|
50
|
+
}
|
|
@@ -1,16 +1,23 @@
|
|
|
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(
|
|
16
|
+
`Composition '${composition.name}' lists an unknown component '${id}'.`
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
return component
|
|
20
|
+
})
|
|
14
21
|
}
|
|
15
22
|
}
|
|
16
23
|
}
|
|
@@ -27,5 +34,3 @@ const map = (components) => {
|
|
|
27
34
|
|
|
28
35
|
return map
|
|
29
36
|
}
|
|
30
|
-
|
|
31
|
-
exports.dereference = dereference
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marks what the context evicts. An evicted component stays in the context like any other — it
|
|
3
|
+
* is called, its types are written, what it receives is published — and only a deployment
|
|
4
|
+
* leaves it out, because something else deploys it. What only evicted components require is
|
|
5
|
+
* marked once the extensions are extracted, by `dependencies`.
|
|
6
|
+
*
|
|
7
|
+
* An evicted service is taken off the compositions that list it, so that none of them runs it.
|
|
8
|
+
*
|
|
9
|
+
* @param {toa.norm.Context} context
|
|
10
|
+
* @returns {void}
|
|
11
|
+
*/
|
|
12
|
+
export const evict = (context) => {
|
|
13
|
+
if (context.evicted === undefined) return
|
|
14
|
+
|
|
15
|
+
const components = new Set(context.evicted.components ?? [])
|
|
16
|
+
const services = new Set(context.evicted.services ?? [])
|
|
17
|
+
|
|
18
|
+
if (components.size > 0) {
|
|
19
|
+
const present = new Set(context.components.map((component) => component.locator.id))
|
|
20
|
+
|
|
21
|
+
for (const id of components)
|
|
22
|
+
if (!present.has(id))
|
|
23
|
+
throw new Error(`'evicted' names an unknown component '${id}'.`)
|
|
24
|
+
|
|
25
|
+
for (const component of context.components)
|
|
26
|
+
if (components.has(component.locator.id)) component.evicted = true
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (context.compositions === undefined) return
|
|
30
|
+
|
|
31
|
+
for (const composition of context.compositions) {
|
|
32
|
+
if (composition.services === undefined) continue
|
|
33
|
+
|
|
34
|
+
composition.services = composition.services.filter((reference) => !services.has(reference))
|
|
35
|
+
|
|
36
|
+
if (composition.services.length === 0) delete composition.services
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/.context/expand.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
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
|
+
|
|
16
|
+
if (context.evicted?.services !== undefined)
|
|
17
|
+
context.evicted.services = context.evicted.services.map(shortcuts.resolve)
|
|
18
|
+
}
|
package/src/.context/index.js
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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 { converge } from './converge.js'
|
|
3
|
+
export { dependencies } from './dependencies.js'
|
|
4
|
+
export { dereference } from './dereference.js'
|
|
5
|
+
export { evict } from './evict.js'
|
|
6
|
+
export { expand } from './expand.js'
|
|
7
|
+
export { normalize } from './normalize.js'
|
|
8
|
+
export { validate } from './validate.js'
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import * as definitions from '@toa.io/definitions'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @param {toa.norm.context.Declaration | Object} context
|
|
5
5
|
*/
|
|
6
|
-
const normalize = (context) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (context.runtime === undefined) context.runtime = { version: runtime.version }
|
|
6
|
+
export const normalize = (context) => {
|
|
7
|
+
if (context.runtime === undefined) context.runtime = { version: definitions.version }
|
|
10
8
|
if (typeof context.runtime === 'string') context.runtime = { version: context.runtime }
|
|
11
9
|
|
|
12
10
|
if (context.runtime.version === undefined || context.runtime.version === '.') {
|
|
13
|
-
context.runtime.version =
|
|
11
|
+
context.runtime.version = definitions.version
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
if (typeof context.registry === 'string') context.registry = { base: context.registry }
|
|
15
|
+
|
|
16
|
+
// what an image is built for, where the Context does not say; `~` says the runner's own
|
|
17
|
+
if (context.registry !== undefined && context.registry.platforms === undefined)
|
|
18
|
+
context.registry.platforms = PLATFORMS
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
const PLATFORMS = ['linux/amd64', 'linux/arm/v7', 'linux/arm64']
|