@biorate/config 3.2.0 → 3.2.2
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/README.md +144 -83
- package/package.json +22 -21
package/README.md
CHANGED
|
@@ -1,155 +1,216 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @biorate/config
|
|
2
2
|
|
|
3
|
-
Application configurator
|
|
3
|
+
Application configurator — hierarchical key-value store with string interpolation, references, and template expressions.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- **`get / has / set / merge`** — standard config API with dot-notation and array paths.
|
|
8
|
+
- **String interpolation** — `${path}` and `@{path}` placeholders resolve to other config values.
|
|
9
|
+
- **Link references** — `#{path}` points to an entire subtree.
|
|
10
|
+
- **RegExp templates** — `R{/pattern/flags}` creates `RegExp` objects at config runtime.
|
|
11
|
+
- **Function templates** — `F{args => body}` creates executable functions.
|
|
12
|
+
- **Empty value templates** — `!{object}`, `!{array}`, `!{void}`, `!{null}`, `!{string}` produce typed empty values.
|
|
13
|
+
- **Toggle per template type** — `Config.Template.*` flags enable/disable individual template processors.
|
|
14
|
+
- **Recursive templating** — `get()` resolves templates on read (not on merge), so circular-safe.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add @biorate/config
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requires `@biorate/errors`, `@biorate/inversion`, `traverse`, `lodash-es` (peer).
|
|
23
|
+
|
|
24
|
+
## Quick start
|
|
8
25
|
|
|
9
26
|
```ts
|
|
10
27
|
import { Config } from '@biorate/config';
|
|
11
28
|
|
|
12
29
|
const config = new Config();
|
|
13
30
|
|
|
14
|
-
config.set('
|
|
31
|
+
config.set('host', 'localhost');
|
|
32
|
+
config.set('port', 3000);
|
|
33
|
+
config.merge({ url: 'http://${host}:${port}/api' });
|
|
15
34
|
|
|
16
|
-
console.log(config.get<
|
|
35
|
+
console.log(config.get<string>('url')); // 'http://localhost:3000/api'
|
|
36
|
+
console.log(config.has('host')); // true
|
|
17
37
|
```
|
|
18
38
|
|
|
19
|
-
|
|
39
|
+
## Module reference
|
|
40
|
+
|
|
41
|
+
### `Config` — Main class
|
|
20
42
|
|
|
21
43
|
```ts
|
|
22
44
|
import { Config } from '@biorate/config';
|
|
45
|
+
```
|
|
23
46
|
|
|
24
|
-
|
|
47
|
+
Decorated with `@injectable()` for DI use.
|
|
48
|
+
|
|
49
|
+
#### Static members
|
|
25
50
|
|
|
26
|
-
|
|
51
|
+
| Member | Signature | Description |
|
|
52
|
+
|---------------------|------------------------------------------------|--------------------------------------|
|
|
53
|
+
| `Config.Template` | `static Template: { string, link, regexp, function, empty }` | Toggle each template type (`true` by default). |
|
|
27
54
|
|
|
28
|
-
|
|
29
|
-
|
|
55
|
+
#### Instance members
|
|
56
|
+
|
|
57
|
+
| Member | Signature | Description |
|
|
58
|
+
|------------|---------------------------------------------------------|-------------------------------------------------------|
|
|
59
|
+
| `get<T>` | `get<T = unknown>(path, def?): T` | Resolves path. Throws `UndefinedConfigPathError` if no `def`. String/object values are template-resolved. |
|
|
60
|
+
| `has` | `has(path): boolean` | Checks if path exists in the data tree. |
|
|
61
|
+
| `set` | `set(path, value): void` | Sets a value at the path (creates intermediates). |
|
|
62
|
+
| `merge` | `merge(data): void` | Deep merges data into the store via `lodash.merge`. |
|
|
63
|
+
|
|
64
|
+
`path` is of type `PropertyPath = string | string[]` — dot-separated or array paths.
|
|
65
|
+
|
|
66
|
+
#### Template types
|
|
67
|
+
|
|
68
|
+
Configured per key by flag:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
Config.Template.string = false; // disable ${...} / @{...} interpolation
|
|
72
|
+
Config.Template.link = false; // disable #{...} references
|
|
73
|
+
Config.Template.regexp = false; // disable R{/pattern/}
|
|
74
|
+
Config.Template.function = false; // disable F{...} function creation
|
|
75
|
+
Config.Template.empty = false; // disable !{...} empty values
|
|
30
76
|
```
|
|
31
77
|
|
|
32
|
-
|
|
78
|
+
### `IConfig` — Interface
|
|
33
79
|
|
|
34
80
|
```ts
|
|
35
|
-
import {
|
|
81
|
+
import { IConfig } from '@biorate/config';
|
|
82
|
+
```
|
|
36
83
|
|
|
37
|
-
|
|
84
|
+
```ts
|
|
85
|
+
interface IConfig {
|
|
86
|
+
get<T>(path: PropertyPath, def?: T): T;
|
|
87
|
+
has(path: PropertyPath): boolean;
|
|
88
|
+
set(path: PropertyPath, value: unknown): void;
|
|
89
|
+
merge(data: unknown): void;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
38
92
|
|
|
39
|
-
|
|
40
|
-
a: { b: { c: 1 } },
|
|
41
|
-
});
|
|
93
|
+
The contract used by DI consumers. `Config` implements `IConfig`.
|
|
42
94
|
|
|
43
|
-
|
|
44
|
-
a: { b: { d: 2 } },
|
|
45
|
-
});
|
|
95
|
+
### `IResult` — Template result type
|
|
46
96
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
console.log(config.get<number>('a.b.c')); // 1
|
|
50
|
-
console.log(config.get<number>('a.b.d')); // 2
|
|
97
|
+
```ts
|
|
98
|
+
import { IResult } from '@biorate/config';
|
|
51
99
|
```
|
|
52
100
|
|
|
53
|
-
|
|
101
|
+
```ts
|
|
102
|
+
type IResult = {
|
|
103
|
+
value: string | RegExp | (() => unknown) | unknown[] | unknown | Record<string, unknown> | null | undefined;
|
|
104
|
+
};
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Internal type representing the resolved value after a template processor runs.
|
|
108
|
+
|
|
109
|
+
### `UndefinedConfigPathError` — Error class
|
|
54
110
|
|
|
55
111
|
```ts
|
|
56
|
-
import {
|
|
112
|
+
import { UndefinedConfigPathError } from '@biorate/config';
|
|
113
|
+
```
|
|
57
114
|
|
|
58
|
-
|
|
115
|
+
```ts
|
|
116
|
+
class UndefinedConfigPathError extends BaseError {
|
|
117
|
+
constructor(path: PropertyPath);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
59
120
|
|
|
121
|
+
Thrown by `config.get(path)` when a path does not exist and no default value is provided.
|
|
122
|
+
|
|
123
|
+
## Template reference
|
|
124
|
+
|
|
125
|
+
### String interpolation — `${...}` / `@{...}`
|
|
126
|
+
|
|
127
|
+
```ts
|
|
60
128
|
config.merge({
|
|
61
|
-
url: '${protocol}${host}/${path}',
|
|
62
129
|
protocol: 'https://',
|
|
63
130
|
host: 'hostname.ru',
|
|
64
131
|
path: 'main',
|
|
132
|
+
url1: '${protocol}${host}/${path}',
|
|
133
|
+
url2: '@{protocol}@{host}/@{path}',
|
|
65
134
|
});
|
|
66
135
|
|
|
67
|
-
|
|
136
|
+
config.get('url1'); // 'https://hostname.ru/main'
|
|
137
|
+
config.get('url2'); // 'https://hostname.ru/main'
|
|
68
138
|
```
|
|
69
139
|
|
|
70
|
-
|
|
140
|
+
Both `$` and `@` prefixes work identically. Supports recursion — templates within templates resolve iteratively.
|
|
71
141
|
|
|
72
|
-
|
|
73
|
-
import { Config } from '@biorate/config';
|
|
74
|
-
|
|
75
|
-
const config = new Config();
|
|
142
|
+
### Link references — `#{...}`
|
|
76
143
|
|
|
144
|
+
```ts
|
|
77
145
|
config.merge({
|
|
78
146
|
obj1: { a: 1, b: 2 },
|
|
79
147
|
obj2: '#{obj1}',
|
|
80
148
|
});
|
|
81
149
|
|
|
82
|
-
|
|
150
|
+
config.get('obj2'); // { a: 1, b: 2 } — same object reference (via config lookup)
|
|
83
151
|
```
|
|
84
152
|
|
|
85
|
-
|
|
153
|
+
The entire value at the referenced path is injected.
|
|
86
154
|
|
|
87
|
-
|
|
88
|
-
import { Config } from '@biorate/config';
|
|
89
|
-
|
|
90
|
-
const config = new Config();
|
|
155
|
+
### RegExp templates — `R{/pattern/flags}`
|
|
91
156
|
|
|
157
|
+
```ts
|
|
92
158
|
config.merge({
|
|
93
159
|
regexp: 'R{/^test$/igm}',
|
|
94
160
|
});
|
|
95
161
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
console.log(regexp.test('test')); // true
|
|
162
|
+
const re = config.get<RegExp>('regexp');
|
|
163
|
+
console.log(re.test('test')); // true
|
|
99
164
|
```
|
|
100
165
|
|
|
101
|
-
|
|
166
|
+
Creates a `RegExpExt` instance (extends `RegExp` with custom `toJSON()`).
|
|
102
167
|
|
|
103
|
-
|
|
104
|
-
import { Config } from '@biorate/config';
|
|
105
|
-
|
|
106
|
-
const config = new Config();
|
|
168
|
+
### Function templates — `F{args => body}`
|
|
107
169
|
|
|
170
|
+
```ts
|
|
108
171
|
config.merge({
|
|
109
172
|
sum: 'F{a, b => return a + b;}',
|
|
110
173
|
});
|
|
111
174
|
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
console.log(sum(1, 2)); // 3
|
|
175
|
+
const fn = config.get<(a: number, b: number) => number>('sum');
|
|
176
|
+
console.log(fn(1, 2)); // 3
|
|
115
177
|
```
|
|
116
178
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
```ts
|
|
120
|
-
import { Config } from '@biorate/config';
|
|
121
|
-
|
|
122
|
-
const config = new Config();
|
|
123
|
-
|
|
124
|
-
config.merge({ data: '!{object}' });
|
|
125
|
-
console.log(config.get('data')); // {}
|
|
179
|
+
Arguments are comma-separated, body follows `=>`.
|
|
126
180
|
|
|
127
|
-
|
|
128
|
-
console.log(config.get('data')); // []
|
|
181
|
+
### Empty templates — `!{type}`
|
|
129
182
|
|
|
130
|
-
|
|
131
|
-
|
|
183
|
+
| Template | Result |
|
|
184
|
+
|-----------------|-------------|
|
|
185
|
+
| `'!{object}'` | `{}` |
|
|
186
|
+
| `'!{array}'` | `[]` |
|
|
187
|
+
| `'!{void}'` | `undefined` |
|
|
188
|
+
| `'!{null}'` | `null` |
|
|
189
|
+
| `'!{string}'` | `""` |
|
|
190
|
+
| `'!{ }'` | `null` |
|
|
132
191
|
|
|
133
|
-
|
|
134
|
-
console.log(config.get('data')); // null
|
|
192
|
+
## Architecture
|
|
135
193
|
|
|
136
|
-
config.merge({ data: '!{string}' });
|
|
137
|
-
console.log(config.get('data')); // ""
|
|
138
|
-
|
|
139
|
-
config.merge({ data: '!{ }' });
|
|
140
|
-
console.log(config.get('data')); // null
|
|
141
194
|
```
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
195
|
+
Config implements IConfig
|
|
196
|
+
│
|
|
197
|
+
├── data: {} Internal object tree
|
|
198
|
+
├── Template (static flags) Toggle processors
|
|
199
|
+
│
|
|
200
|
+
├── get(path, def?)
|
|
201
|
+
│ ├── lodash.get(data, path)
|
|
202
|
+
│ ├── if string → template(value)
|
|
203
|
+
│ │ ├── Template.string() Replace ${...} / @{...}
|
|
204
|
+
│ │ ├── Template.link() Replace #{...}
|
|
205
|
+
│ │ ├── Template.regexp() Parse R{/.../}
|
|
206
|
+
│ │ ├── Template.function() Parse F{...}
|
|
207
|
+
│ │ └── Template.empty() Parse !{...}
|
|
208
|
+
│ ├── if object → templatize() Recursive via traverse
|
|
209
|
+
│ └── throw UndefinedConfigPathError if missing and no def
|
|
210
|
+
│
|
|
211
|
+
├── has(path) lodash.has(data, path)
|
|
212
|
+
├── set(path, value) lodash.set(data, path, value)
|
|
213
|
+
└── merge(data) lodash.merge(data, data)
|
|
153
214
|
```
|
|
154
215
|
|
|
155
216
|
### Learn
|
|
@@ -160,7 +221,7 @@ Config.Template.link = false;
|
|
|
160
221
|
|
|
161
222
|
See the [CHANGELOG](https://github.com/biorate/core/blob/master/packages/%40biorate/config/CHANGELOG.md)
|
|
162
223
|
|
|
163
|
-
|
|
224
|
+
## License
|
|
164
225
|
|
|
165
226
|
[MIT](https://github.com/biorate/core/blob/master/packages/%40biorate/config/LICENSE)
|
|
166
227
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@biorate/config",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"description": "Application configurator",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -18,6 +18,21 @@
|
|
|
18
18
|
"README.md",
|
|
19
19
|
"LICENSE"
|
|
20
20
|
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clean": "cleanup dist",
|
|
23
|
+
"build:cjs": "npx tsc -p ./tsconfig.build.cjs.json",
|
|
24
|
+
"build:esm": "npx tsc -p ./tsconfig.build.esm.json",
|
|
25
|
+
"build:types": "npx tsc -p ./tsconfig.build.types.json",
|
|
26
|
+
"build": "pnpm run clean && pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
|
|
27
|
+
"postbuild:cjs": "node ../../../.scripts/write-package-type.js dist/cjs commonjs",
|
|
28
|
+
"postbuild:esm": "tsc-esm-fix --tsconfig=./tsconfig.build.esm.json --target=./dist/esm && node ../../../.scripts/write-package-type.js dist/esm module",
|
|
29
|
+
"format": "prettier --check src",
|
|
30
|
+
"lint": "eslint src --ext .ts",
|
|
31
|
+
"format:fix": "prettier --write src",
|
|
32
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
33
|
+
"test": "npx vitest run --coverage",
|
|
34
|
+
"prepublishOnly": "pnpm run build"
|
|
35
|
+
},
|
|
21
36
|
"repository": {
|
|
22
37
|
"type": "git",
|
|
23
38
|
"url": "git+https://github.com/biorate/core.git",
|
|
@@ -30,30 +45,16 @@
|
|
|
30
45
|
"keywords": [],
|
|
31
46
|
"author": "llevkin",
|
|
32
47
|
"license": "MIT",
|
|
33
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "e17a03900999e261a0eb04c6afb09b9535cad952",
|
|
34
49
|
"peerDependencies": {
|
|
35
|
-
"lodash-es": ">=4.
|
|
50
|
+
"lodash-es": ">=4.18.1"
|
|
36
51
|
},
|
|
37
52
|
"dependencies": {
|
|
38
|
-
"
|
|
39
|
-
"@biorate/
|
|
40
|
-
"
|
|
53
|
+
"@biorate/errors": "3.1.2",
|
|
54
|
+
"@biorate/inversion": "3.1.2",
|
|
55
|
+
"traverse": "^0.6.6"
|
|
41
56
|
},
|
|
42
57
|
"devDependencies": {
|
|
43
58
|
"@types/traverse": "^0.6.32"
|
|
44
|
-
},
|
|
45
|
-
"scripts": {
|
|
46
|
-
"clean": "cleanup dist",
|
|
47
|
-
"build:cjs": "npx tsc -p ./tsconfig.build.cjs.json",
|
|
48
|
-
"build:esm": "npx tsc -p ./tsconfig.build.esm.json",
|
|
49
|
-
"build:types": "npx tsc -p ./tsconfig.build.types.json",
|
|
50
|
-
"build": "pnpm run clean && pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
|
|
51
|
-
"postbuild:cjs": "node ../../../.scripts/write-package-type.js dist/cjs commonjs",
|
|
52
|
-
"postbuild:esm": "tsc-esm-fix --tsconfig=./tsconfig.build.esm.json --target=./dist/esm && node ../../../.scripts/write-package-type.js dist/esm module",
|
|
53
|
-
"format": "prettier --check src",
|
|
54
|
-
"lint": "eslint src --ext .ts",
|
|
55
|
-
"format:fix": "prettier --write src",
|
|
56
|
-
"lint:fix": "eslint src --ext .ts --fix",
|
|
57
|
-
"test": "npx vitest run --coverage"
|
|
58
59
|
}
|
|
59
|
-
}
|
|
60
|
+
}
|