@toa.io/extensions.configuration 0.20.0-dev.31 → 0.20.0-dev.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +16 -9
- package/readme.md +68 -155
- package/schemas/annotation.cos.yaml +1 -0
- package/schemas/manifest.cos.yaml +2 -0
- package/source/Aspect.test.ts +15 -0
- package/source/Aspect.ts +23 -0
- package/source/Factory.ts +12 -0
- package/source/configuration.test.ts +89 -0
- package/source/configuration.ts +52 -0
- package/source/deployment.test.ts +21 -0
- package/source/deployment.ts +69 -0
- package/source/index.ts +3 -0
- package/source/manifest.test.ts +15 -0
- package/source/manifest.ts +15 -0
- package/source/schemas.ts +8 -0
- package/tsconfig.json +9 -0
- package/docs/discussion.md +0 -109
- package/source/.deployment/index.js +0 -7
- package/source/.deployment/secrets.js +0 -33
- package/source/.deployment/variables.js +0 -26
- package/source/.manifest/.normalize/verbose.js +0 -51
- package/source/.manifest/index.js +0 -7
- package/source/.manifest/normalize.js +0 -16
- package/source/.manifest/schema.yaml +0 -9
- package/source/.manifest/validate.js +0 -13
- package/source/.provider/env.js +0 -19
- package/source/.provider/form.js +0 -20
- package/source/.provider/index.js +0 -7
- package/source/annotation.fixtures.js +0 -39
- package/source/annotation.js +0 -36
- package/source/annotation.test.js +0 -43
- package/source/aspect.fixtures.js +0 -32
- package/source/aspect.js +0 -36
- package/source/aspect.test.js +0 -76
- package/source/configuration.js +0 -19
- package/source/deployment.fixtures.js +0 -38
- package/source/deployment.js +0 -20
- package/source/deployment.test.js +0 -70
- package/source/factory.js +0 -39
- package/source/factory.test.js +0 -22
- package/source/index.js +0 -13
- package/source/manifest.js +0 -13
- package/source/manifest.test.js +0 -123
- package/source/provider.js +0 -119
- package/source/provider.test.js +0 -130
- package/source/secrets.js +0 -28
- package/source/secrets.test.js +0 -47
- package/types/aspect.d.ts +0 -11
- package/types/factory.d.ts +0 -12
- package/types/provider.d.ts +0 -22
- /package/{docs → notes}/consistency.md +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import * as schemas from '@toa.io/schemas'
|
|
3
|
+
|
|
4
|
+
const path = resolve(__dirname, '../schemas')
|
|
5
|
+
const namespace = schemas.namespace(path)
|
|
6
|
+
|
|
7
|
+
export const manifest = namespace.schema('manifest')
|
|
8
|
+
export const annotation = namespace.schema('annotation')
|
package/tsconfig.json
ADDED
package/docs/discussion.md
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
# Discussion
|
|
2
|
-
|
|
3
|
-
## Change Requests
|
|
4
|
-
|
|
5
|
-
- [x] feat(configuration): add configuration extension
|
|
6
|
-
- manifest (schema) validation
|
|
7
|
-
- context extension
|
|
8
|
-
- [x] feat(formation): add well-known extension 'configuration'
|
|
9
|
-
- component
|
|
10
|
-
- context
|
|
11
|
-
- [x] feat(node): add well-known context extension 'configuration'
|
|
12
|
-
- [x] feat(configuration): add concise declarations
|
|
13
|
-
- [x] feat(configuration): add runtime configuration resolution
|
|
14
|
-
- [x] feat(cli): add `toa configure <key> <value> --reset`
|
|
15
|
-
- validate type
|
|
16
|
-
- [x] feat(operations): add configuration deployment
|
|
17
|
-
- annotations (values) validation
|
|
18
|
-
- [ ] feat(configuration): add secrets resolution
|
|
19
|
-
- [ ] feat(operations): add secrets deployment
|
|
20
|
-
- [ ] feat(cli): add `toa conceal`
|
|
21
|
-
- validate type
|
|
22
|
-
- [ ] feat(cli): add `toa configure`
|
|
23
|
-
- prompt required values
|
|
24
|
-
- use JSON Schema title
|
|
25
|
-
|
|
26
|
-
## Statements
|
|
27
|
-
|
|
28
|
-
### Common
|
|
29
|
-
|
|
30
|
-
- Secrets are being deployed separately by `toa conceal` command
|
|
31
|
-
|
|
32
|
-
### 1: Environment variables
|
|
33
|
-
|
|
34
|
-
- Configuration values and secrets are mapped as environment variables to composition deployments
|
|
35
|
-
- Extensions may expose *deployment mutators*, which are able to modify deployment declaration
|
|
36
|
-
- Configuration context extension reads environment variables to resolve configuration and secrets
|
|
37
|
-
|
|
38
|
-
### 2: Dedicated Components
|
|
39
|
-
|
|
40
|
-
- Hot updates
|
|
41
|
-
- [Configuration consistency](consistency.md)
|
|
42
|
-
|
|
43
|
-
## Questions
|
|
44
|
-
|
|
45
|
-
### Where are values comes from?
|
|
46
|
-
|
|
47
|
-
Environment variables.
|
|
48
|
-
|
|
49
|
-
### Is there a configuration service or configuration component?
|
|
50
|
-
|
|
51
|
-
No. It will be implemented later as a part of [consistent configuration](consistency.md).
|
|
52
|
-
|
|
53
|
-
### How are configuration values being stored?
|
|
54
|
-
|
|
55
|
-
As a kubernetes secrets mapped as environment variables.
|
|
56
|
-
|
|
57
|
-
### Where are secrets being stored and how do they resolve to value?
|
|
58
|
-
|
|
59
|
-
As a kubernetes secrets mapped as environment variables.
|
|
60
|
-
|
|
61
|
-
### Is configuration a single environment variable or a set (one per component)?
|
|
62
|
-
|
|
63
|
-
#### Context Configuration
|
|
64
|
-
|
|
65
|
-
In later versions, context extension will resolve configuration values by component locator. Given
|
|
66
|
-
that it is yet
|
|
67
|
-
unknown when this will happen, a certain context might have appeared which configuration is big
|
|
68
|
-
enough to not fit the
|
|
69
|
-
environment variable limitations.
|
|
70
|
-
|
|
71
|
-
That is, Context Configuration must be mapped as a set of environment variables (one per component).
|
|
72
|
-
Values are
|
|
73
|
-
serialized Configuration Objects.
|
|
74
|
-
|
|
75
|
-
> This will also allow to configure local environment per component.
|
|
76
|
-
|
|
77
|
-
#### Secrets
|
|
78
|
-
|
|
79
|
-
Secrets are mapped per secret as they are not bound to components.
|
|
80
|
-
|
|
81
|
-
### Is configuration a single kubernetes secret or a set (one per component)?
|
|
82
|
-
|
|
83
|
-
#### Configuration
|
|
84
|
-
|
|
85
|
-
Single secret with a set of values per component.
|
|
86
|
-
|
|
87
|
-
#### Secrets
|
|
88
|
-
|
|
89
|
-
Once kubernetes secret per configuration secret.
|
|
90
|
-
|
|
91
|
-
### Is there an option to configure local environment?
|
|
92
|
-
|
|
93
|
-
<dl>
|
|
94
|
-
<dt><code>toa configure <component></code></dt>
|
|
95
|
-
<dd>Create local environment configuration values</dd>
|
|
96
|
-
</dl>
|
|
97
|
-
|
|
98
|
-
### Whose responsibility is to call annotations?
|
|
99
|
-
|
|
100
|
-
- norm
|
|
101
|
-
- deployment
|
|
102
|
-
|
|
103
|
-
`toa export context` should throw errors if context has invalid annotations, and it's not a part of
|
|
104
|
-
the deployment.
|
|
105
|
-
|
|
106
|
-
## References
|
|
107
|
-
|
|
108
|
-
- [#125](https://github.com/toa-io/toa/issues/125)
|
|
109
|
-
- [#132](https://github.com/toa-io/toa/issues/132)
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const find = require('../secrets')
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {toa.norm.context.dependencies.Instance[]} components
|
|
7
|
-
* @param {object} annotations
|
|
8
|
-
* @return {toa.deployment.dependency.Variables}
|
|
9
|
-
*/
|
|
10
|
-
function secrets (components, annotations) {
|
|
11
|
-
/** @type {toa.deployment.dependency.Variables} */
|
|
12
|
-
const variables = {}
|
|
13
|
-
|
|
14
|
-
for (const [id, annotation] of Object.entries(annotations)) {
|
|
15
|
-
const component = components.find((component) => component.locator.id === id)
|
|
16
|
-
const label = component.locator.label
|
|
17
|
-
|
|
18
|
-
find.secrets(annotation, (variable, key) => {
|
|
19
|
-
if (variables[label] === undefined) variables[label] = []
|
|
20
|
-
|
|
21
|
-
variables[label].push({
|
|
22
|
-
name: variable,
|
|
23
|
-
secret: { name: SECRET_NAME, key }
|
|
24
|
-
})
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return variables
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const SECRET_NAME = 'toa-configuration'
|
|
32
|
-
|
|
33
|
-
exports.secrets = secrets
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { encode } = require('@toa.io/generic')
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {toa.norm.context.dependencies.Instance[]} components
|
|
7
|
-
* @param {object} annotations
|
|
8
|
-
* @return {toa.deployment.dependency.Variables}
|
|
9
|
-
*/
|
|
10
|
-
function variables (components, annotations) {
|
|
11
|
-
/** @type {toa.deployment.dependency.Variables} */
|
|
12
|
-
const variables = {}
|
|
13
|
-
|
|
14
|
-
for (const [id, annotation] of Object.entries(annotations)) {
|
|
15
|
-
const component = components.find((component) => component.locator.id === id)
|
|
16
|
-
|
|
17
|
-
variables[component.locator.label] = [{
|
|
18
|
-
name: 'TOA_CONFIGURATION_' + component.locator.uppercase,
|
|
19
|
-
value: encode(annotation)
|
|
20
|
-
}]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return variables
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
exports.variables = variables
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { remap } = require('@toa.io/generic')
|
|
4
|
-
|
|
5
|
-
const verbose = (node) => {
|
|
6
|
-
const isObject = node.properties !== undefined
|
|
7
|
-
const isValue = node.type !== undefined && node.type !== 'object'
|
|
8
|
-
const isProperties = node[SYM] === 1
|
|
9
|
-
|
|
10
|
-
if (!isObject && !isValue && !isProperties) return convert(node)
|
|
11
|
-
|
|
12
|
-
return node
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const convert = (node) => {
|
|
16
|
-
const properties = remap(node, property)
|
|
17
|
-
|
|
18
|
-
properties[SYM] = 1
|
|
19
|
-
|
|
20
|
-
return { type: 'object', properties, additionalProperties: false }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function property (node) {
|
|
24
|
-
if (node === null) return { type: 'null', default: null }
|
|
25
|
-
|
|
26
|
-
const type = Array.isArray(node) ? 'array' : typeof node
|
|
27
|
-
|
|
28
|
-
if (type === 'object') return node
|
|
29
|
-
if (type === 'array') return array(node)
|
|
30
|
-
|
|
31
|
-
return { type, default: node }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const array = (array) => {
|
|
35
|
-
if (array.length === 0) throw new Error('Configuration: cannot resolve concise array items type because it\'s empty')
|
|
36
|
-
|
|
37
|
-
const type = typeof array[0]
|
|
38
|
-
|
|
39
|
-
const schema = {
|
|
40
|
-
type: 'array',
|
|
41
|
-
default: array
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (array.length === 1) schema.items = array[0]
|
|
45
|
-
|
|
46
|
-
return schema
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const SYM = Symbol()
|
|
50
|
-
|
|
51
|
-
exports.verbose = verbose
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { traverse } = require('@toa.io/generic')
|
|
4
|
-
const { verbose } = require('./.normalize/verbose')
|
|
5
|
-
|
|
6
|
-
const normalize = (manifest) => {
|
|
7
|
-
if (manifest.properties === undefined) manifest = expand(manifest)
|
|
8
|
-
|
|
9
|
-
return manifest
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const expand = (concise) => {
|
|
13
|
-
return traverse(concise, verbose)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
exports.normalize = normalize
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
$schema: https://json-schema.org/draft/2019-09/schema
|
|
2
|
-
$id: https://schemas.toa.io/0.0.0/extensions/configuration/manifest
|
|
3
|
-
|
|
4
|
-
$ref: 'https://schemas.toa.io/0.0.0/definitions#/definitions/schema'
|
|
5
|
-
type: object
|
|
6
|
-
properties:
|
|
7
|
-
type:
|
|
8
|
-
const: object
|
|
9
|
-
default: object
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const path = require('path')
|
|
4
|
-
|
|
5
|
-
const { Schema } = require('@toa.io/schema')
|
|
6
|
-
const { load } = require('@toa.io/yaml')
|
|
7
|
-
|
|
8
|
-
const schema = load.sync(path.resolve(__dirname, 'schema.yaml'))
|
|
9
|
-
const validator = new Schema(schema)
|
|
10
|
-
|
|
11
|
-
const validate = (declaration) => validator.validate(declaration)
|
|
12
|
-
|
|
13
|
-
exports.validate = validate
|
package/source/.provider/env.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { map } = require('@toa.io/generic')
|
|
4
|
-
|
|
5
|
-
function env (object) {
|
|
6
|
-
return map(object,
|
|
7
|
-
/**
|
|
8
|
-
* @type {toa.generic.map.transform<string>}
|
|
9
|
-
*/
|
|
10
|
-
(value) => {
|
|
11
|
-
if (typeof value !== 'string') return
|
|
12
|
-
|
|
13
|
-
return value.replaceAll(RX, (match, variable) => process.env[variable] ?? match)
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const RX = /\${(?<variable>[A-Z0-9_]{1,32})}/g
|
|
18
|
-
|
|
19
|
-
exports.env = env
|
package/source/.provider/form.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { traverse } = require('@toa.io/generic')
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {toa.schema.JSON | Object} schema
|
|
7
|
-
* @return {Object}
|
|
8
|
-
*/
|
|
9
|
-
const form = (schema) => {
|
|
10
|
-
const defaults = (node) => {
|
|
11
|
-
if (node.type === 'object' && node.properties !== undefined) return { ...node.properties }
|
|
12
|
-
if (node.default !== undefined) return node.default
|
|
13
|
-
|
|
14
|
-
return null
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return traverse(schema, defaults)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
exports.form = form
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { generate } = require('randomstring')
|
|
4
|
-
const { Locator } = require('@toa.io/core')
|
|
5
|
-
const { random } = require('@toa.io/generic')
|
|
6
|
-
|
|
7
|
-
const instance = () => {
|
|
8
|
-
const name = generate()
|
|
9
|
-
const namespace = generate()
|
|
10
|
-
const locator = new Locator(name, namespace)
|
|
11
|
-
|
|
12
|
-
const manifest = {
|
|
13
|
-
type: 'object',
|
|
14
|
-
properties: {
|
|
15
|
-
foo: {
|
|
16
|
-
type: 'number',
|
|
17
|
-
default: 1
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return { locator, manifest }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** @type {toa.norm.context.dependencies.Instance[]} */
|
|
26
|
-
const instances = []
|
|
27
|
-
|
|
28
|
-
for (let i = 0; i < random(5) + 5; i++) instances.push(instance())
|
|
29
|
-
|
|
30
|
-
/** @type {Object} */
|
|
31
|
-
const annotation = {}
|
|
32
|
-
|
|
33
|
-
for (let i = 0; i < random(instances.length - 1) + 1; i++) {
|
|
34
|
-
const instance = instances[i]
|
|
35
|
-
annotation[instance.locator.id] = { foo: random() }
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
exports.instances = instances
|
|
39
|
-
exports.annotation = annotation
|
package/source/annotation.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { Schema } = require('@toa.io/schema')
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {Object} annotation
|
|
7
|
-
* @param {toa.norm.context.dependencies.Instance[]} instances
|
|
8
|
-
*/
|
|
9
|
-
const annotation = (annotation, instances) => {
|
|
10
|
-
const keys = Object.keys(annotation)
|
|
11
|
-
|
|
12
|
-
check(keys, instances)
|
|
13
|
-
|
|
14
|
-
for (const instance of instances) {
|
|
15
|
-
const object = annotation[instance.locator.id] ?? {}
|
|
16
|
-
const schema = new Schema(instance.manifest)
|
|
17
|
-
|
|
18
|
-
schema.validate(object)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return annotation
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @param {string[]} keys
|
|
26
|
-
* @param {toa.norm.context.dependencies.Instance[]} instances
|
|
27
|
-
*/
|
|
28
|
-
const check = (keys, instances) => {
|
|
29
|
-
const ids = instances.map((instance) => instance.locator.id)
|
|
30
|
-
|
|
31
|
-
for (const key of keys) {
|
|
32
|
-
if (!ids.includes(key)) throw new Error(`Configuration Schema '${key}' is not defined`)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
exports.annotation = annotation
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const clone = require('clone-deep')
|
|
4
|
-
const { generate } = require('randomstring')
|
|
5
|
-
const { sample } = require('@toa.io/generic')
|
|
6
|
-
|
|
7
|
-
const fixtures = require('./annotation.fixtures')
|
|
8
|
-
const { annotation } = require('../')
|
|
9
|
-
|
|
10
|
-
let input
|
|
11
|
-
/** @type {toa.norm.context.dependencies.Instance[]} */ let instances
|
|
12
|
-
|
|
13
|
-
const call = () => annotation(input, instances)
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
input = clone(fixtures.annotation)
|
|
17
|
-
instances = clone(fixtures.instances)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('sample must be valid', () => {
|
|
21
|
-
expect(call).not.toThrow()
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('should must be a function', () => {
|
|
25
|
-
expect(annotation).toBeDefined()
|
|
26
|
-
expect(annotation).toBeInstanceOf(Function)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('should throw on non-existent component', () => {
|
|
30
|
-
input[generate()] = {}
|
|
31
|
-
|
|
32
|
-
expect(call).toThrow(/Configuration Schema/)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('should throw if object doesn\'t match schema', () => {
|
|
36
|
-
const keys = Object.keys(input)
|
|
37
|
-
const key = sample(keys)
|
|
38
|
-
const object = input[key]
|
|
39
|
-
|
|
40
|
-
object.foo = generate()
|
|
41
|
-
|
|
42
|
-
expect(call).toThrow(/foo must be number/)
|
|
43
|
-
})
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { generate } = require('randomstring')
|
|
4
|
-
|
|
5
|
-
const schema = {
|
|
6
|
-
type: 'object',
|
|
7
|
-
properties: {
|
|
8
|
-
foo: {
|
|
9
|
-
type: 'string',
|
|
10
|
-
default: generate()
|
|
11
|
-
},
|
|
12
|
-
bar: {
|
|
13
|
-
type: 'object',
|
|
14
|
-
properties: {
|
|
15
|
-
baz: {
|
|
16
|
-
type: 'number',
|
|
17
|
-
default: 1
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const concise = {
|
|
25
|
-
foo: schema.properties.foo.default,
|
|
26
|
-
bar: {
|
|
27
|
-
baz: schema.properties.bar.properties.baz.default
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
exports.schema = schema
|
|
32
|
-
exports.concise = concise
|
package/source/aspect.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { Connector } = require('@toa.io/core')
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @implements {toa.extensions.configuration.Aspect}
|
|
7
|
-
*/
|
|
8
|
-
class Aspect extends Connector {
|
|
9
|
-
/** @readonly */
|
|
10
|
-
name = 'configuration'
|
|
11
|
-
|
|
12
|
-
/** @type {toa.core.Reflection} */
|
|
13
|
-
#refection
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {toa.core.Reflection} reflection
|
|
17
|
-
*/
|
|
18
|
-
constructor (reflection) {
|
|
19
|
-
super()
|
|
20
|
-
|
|
21
|
-
this.#refection = reflection
|
|
22
|
-
|
|
23
|
-
this.depends(reflection)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
invoke (path) {
|
|
27
|
-
/** @type {any} */
|
|
28
|
-
let cursor = this.#refection.value
|
|
29
|
-
|
|
30
|
-
if (path !== undefined) for (const segment of path) cursor = cursor[segment]
|
|
31
|
-
|
|
32
|
-
return cursor
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
exports.Aspect = Aspect
|
package/source/aspect.test.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { Locator } = require('@toa.io/core')
|
|
4
|
-
const { encode } = require('@toa.io/generic')
|
|
5
|
-
|
|
6
|
-
const fixtures = require('./aspect.fixtures')
|
|
7
|
-
const { Factory } = require('../')
|
|
8
|
-
const { generate } = require('randomstring')
|
|
9
|
-
|
|
10
|
-
const factory = new Factory()
|
|
11
|
-
|
|
12
|
-
/** @type {toa.extensions.configuration.Aspect} */
|
|
13
|
-
let aspect
|
|
14
|
-
|
|
15
|
-
/** @type {toa.core.Locator} */
|
|
16
|
-
let locator
|
|
17
|
-
|
|
18
|
-
describe('defaults', () => {
|
|
19
|
-
beforeEach(async () => {
|
|
20
|
-
const namespace = generate()
|
|
21
|
-
const name = generate()
|
|
22
|
-
|
|
23
|
-
locator = new Locator(name, namespace)
|
|
24
|
-
|
|
25
|
-
aspect = factory.aspect(locator, fixtures.schema)
|
|
26
|
-
|
|
27
|
-
await aspect.connect()
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it('should return schema defaults', () => {
|
|
31
|
-
const foo = aspect.invoke(['foo'])
|
|
32
|
-
|
|
33
|
-
expect(foo).toStrictEqual(fixtures.schema.properties.foo.default)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('should return nested values', () => {
|
|
37
|
-
const baz = aspect.invoke(['bar', 'baz'])
|
|
38
|
-
|
|
39
|
-
expect(baz).toStrictEqual(fixtures.schema.properties.bar.properties.baz.default)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should expose configuration tree', () => {
|
|
43
|
-
const configuration = aspect.invoke()
|
|
44
|
-
|
|
45
|
-
expect(configuration).toStrictEqual({
|
|
46
|
-
foo: fixtures.schema.properties.foo.default,
|
|
47
|
-
bar: {
|
|
48
|
-
baz: fixtures.schema.properties.bar.properties.baz.default
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
describe('resolution', () => {
|
|
55
|
-
let object
|
|
56
|
-
let varname
|
|
57
|
-
|
|
58
|
-
beforeEach(() => {
|
|
59
|
-
object = { foo: generate() }
|
|
60
|
-
|
|
61
|
-
varname = 'TOA_CONFIGURATION_' + locator.uppercase
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('should resolve configuration object from environment variable', async () => {
|
|
65
|
-
process.env[varname] = encode(object)
|
|
66
|
-
|
|
67
|
-
aspect = factory.aspect(locator, fixtures.schema)
|
|
68
|
-
|
|
69
|
-
await aspect.connect()
|
|
70
|
-
|
|
71
|
-
const configuration = aspect.invoke()
|
|
72
|
-
|
|
73
|
-
expect(configuration.foo).toStrictEqual(object.foo)
|
|
74
|
-
expect(configuration.bar.baz).toStrictEqual(fixtures.schema.properties.bar.properties.baz.default)
|
|
75
|
-
})
|
|
76
|
-
})
|
package/source/configuration.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { Reflection } = require('@toa.io/core')
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @implements {toa.core.Reflection}
|
|
7
|
-
*/
|
|
8
|
-
class Configuration extends Reflection {
|
|
9
|
-
/**
|
|
10
|
-
* @param {toa.extensions.configuration.Provider} provider
|
|
11
|
-
*/
|
|
12
|
-
constructor (provider) {
|
|
13
|
-
super(provider.source)
|
|
14
|
-
|
|
15
|
-
this.depends(provider)
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
exports.Configuration = Configuration
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { generate } = require('randomstring')
|
|
4
|
-
|
|
5
|
-
const { Locator } = require('@toa.io/core')
|
|
6
|
-
const { random } = require('@toa.io/generic')
|
|
7
|
-
|
|
8
|
-
const component = () => {
|
|
9
|
-
const namespace = generate()
|
|
10
|
-
const name = generate()
|
|
11
|
-
|
|
12
|
-
return { locator: new Locator(name, namespace) }
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** @type {toa.norm.context.dependencies.Instance[]} */
|
|
16
|
-
const components = []
|
|
17
|
-
const annotations = {}
|
|
18
|
-
|
|
19
|
-
const annotate = (component) => {
|
|
20
|
-
const key = component.locator.id
|
|
21
|
-
|
|
22
|
-
annotations[key] = { [generate()]: generate() }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
for (let i = 0; i < random(10) + 5; i++) components.push(component())
|
|
26
|
-
for (let i = 0; i < components.length; i++) if (i % 2 === 0) annotate(components[i])
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @param {string} id
|
|
30
|
-
* @returns {toa.norm.context.dependencies.Instance}
|
|
31
|
-
*/
|
|
32
|
-
const find = (id) => {
|
|
33
|
-
return components.find((component) => component.locator.id === id)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
exports.components = components
|
|
37
|
-
exports.annotations = annotations
|
|
38
|
-
exports.find = find
|