@biorate/config 3.2.1 → 3.2.3

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 (2) hide show
  1. package/README.md +144 -83
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -1,155 +1,216 @@
1
- # Config
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
- ### Examples:
5
+ ## Features
6
6
 
7
- #### Get / Set:
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('a', 1);
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<number>('a')); // 1
35
+ console.log(config.get<string>('url')); // 'http://localhost:3000/api'
36
+ console.log(config.has('host')); // true
17
37
  ```
18
38
 
19
- #### Has:
39
+ ## Module reference
40
+
41
+ ### `Config` — Main class
20
42
 
21
43
  ```ts
22
44
  import { Config } from '@biorate/config';
45
+ ```
23
46
 
24
- const config = new Config();
47
+ Decorated with `@injectable()` for DI use.
48
+
49
+ #### Static members
25
50
 
26
- config.set('a', 1);
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
- console.log(config.has('a')); // true
29
- console.log(config.has('b')); // false
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
- #### Merge:
78
+ ### `IConfig` — Interface
33
79
 
34
80
  ```ts
35
- import { Config } from '@biorate/config';
81
+ import { IConfig } from '@biorate/config';
82
+ ```
36
83
 
37
- const config = new Config();
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
- config.merge({
40
- a: { b: { c: 1 } },
41
- });
93
+ The contract used by DI consumers. `Config` implements `IConfig`.
42
94
 
43
- config.merge({
44
- a: { b: { d: 2 } },
45
- });
95
+ ### `IResult` — Template result type
46
96
 
47
- console.log(config.has('a')); // true
48
- console.log(config.has('a.b')); // true
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
- #### String template:
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 { Config } from '@biorate/config';
112
+ import { UndefinedConfigPathError } from '@biorate/config';
113
+ ```
57
114
 
58
- const config = new Config();
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
- console.log(config.get<string>('url')); // https://hostname.ru/main
136
+ config.get('url1'); // 'https://hostname.ru/main'
137
+ config.get('url2'); // 'https://hostname.ru/main'
68
138
  ```
69
139
 
70
- #### Link template:
140
+ Both `$` and `@` prefixes work identically. Supports recursion — templates within templates resolve iteratively.
71
141
 
72
- ```ts
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
- console.log(config.get<{ a: number; b: number }>('obj2')); // { "a": 1, "b": 2 }
150
+ config.get('obj2'); // { a: 1, b: 2 } — same object reference (via config lookup)
83
151
  ```
84
152
 
85
- #### RegExp template:
153
+ The entire value at the referenced path is injected.
86
154
 
87
- ```ts
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 regexp = config.get<RegExp>('regexp');
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
- #### Function template:
166
+ Creates a `RegExpExt` instance (extends `RegExp` with custom `toJSON()`).
102
167
 
103
- ```ts
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 sum = config.get<(a: number, b: number) => number>('sum');
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
- #### Empty template:
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
- config.merge({ data: '!{array}' });
128
- console.log(config.get('data')); // []
181
+ ### Empty templates — `!{type}`
129
182
 
130
- config.merge({ data: '!{void}' });
131
- console.log(config.get('data')); // undefined
183
+ | Template | Result |
184
+ |-----------------|-------------|
185
+ | `'!{object}'` | `{}` |
186
+ | `'!{array}'` | `[]` |
187
+ | `'!{void}'` | `undefined` |
188
+ | `'!{null}'` | `null` |
189
+ | `'!{string}'` | `""` |
190
+ | `'!{ }'` | `null` |
132
191
 
133
- config.merge({ data: '!{null}' });
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
- If you want to disable templates, you can turn off it in static `Config.Template` variable:
144
-
145
- ```ts
146
- import { Config } from '@biorate/config';
147
-
148
- Config.Template.string = false;
149
- Config.Template.empty = false;
150
- Config.Template.regexp = false;
151
- Config.Template.function = false;
152
- Config.Template.link = false;
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
- ### License
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.1",
3
+ "version": "3.2.3",
4
4
  "description": "Application configurator",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -45,13 +45,13 @@
45
45
  "keywords": [],
46
46
  "author": "llevkin",
47
47
  "license": "MIT",
48
- "gitHead": "ff1dcf14a733ce8004ca582d2c421a2154ce97cb",
48
+ "gitHead": "146d0a721093d0327ba4cacd275783a779bc3059",
49
49
  "peerDependencies": {
50
- "lodash-es": ">=4.17.21"
50
+ "lodash-es": ">=4.18.1"
51
51
  },
52
52
  "dependencies": {
53
- "@biorate/errors": "3.1.1",
54
- "@biorate/inversion": "3.1.1",
53
+ "@biorate/errors": "3.1.2",
54
+ "@biorate/inversion": "3.1.3",
55
55
  "traverse": "^0.6.6"
56
56
  },
57
57
  "devDependencies": {