@hg-ts/config-loader 0.0.15
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/.eslintcache +1 -0
- package/.eslintrc.json +3 -0
- package/.mocharc.cjs +1 -0
- package/README.md +106 -0
- package/dist/config-loader.d.ts +18 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +75 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/decorators/enforce-env.decorator.d.ts +2 -0
- package/dist/decorators/enforce-env.decorator.d.ts.map +1 -0
- package/dist/decorators/enforce-env.decorator.js +9 -0
- package/dist/decorators/enforce-env.decorator.js.map +1 -0
- package/dist/decorators/index.d.ts +2 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/index.js +5 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/exceptions/index.d.ts +2 -0
- package/dist/exceptions/index.d.ts.map +1 -0
- package/dist/exceptions/index.js +5 -0
- package/dist/exceptions/index.js.map +1 -0
- package/dist/exceptions/no-base-config.exception.d.ts +5 -0
- package/dist/exceptions/no-base-config.exception.d.ts.map +1 -0
- package/dist/exceptions/no-base-config.exception.js +11 -0
- package/dist/exceptions/no-base-config.exception.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/path-builder.d.ts +22 -0
- package/dist/path-builder.d.ts.map +1 -0
- package/dist/path-builder.js +79 -0
- package/dist/path-builder.js.map +1 -0
- package/dist/tests/config-loader.test-suite.d.ts +7 -0
- package/dist/tests/config-loader.test-suite.d.ts.map +1 -0
- package/dist/tests/config-loader.test-suite.js +94 -0
- package/dist/tests/config-loader.test-suite.js.map +1 -0
- package/dist/tests/path-builder.test-suite.d.ts +15 -0
- package/dist/tests/path-builder.test-suite.d.ts.map +1 -0
- package/dist/tests/path-builder.test-suite.js +155 -0
- package/dist/tests/path-builder.test-suite.js.map +1 -0
- package/dist-esm/config-loader.d.ts +18 -0
- package/dist-esm/config-loader.d.ts.map +1 -0
- package/dist-esm/config-loader.js +70 -0
- package/dist-esm/config-loader.js.map +1 -0
- package/dist-esm/decorators/enforce-env.decorator.d.ts +2 -0
- package/dist-esm/decorators/enforce-env.decorator.d.ts.map +1 -0
- package/dist-esm/decorators/enforce-env.decorator.js +5 -0
- package/dist-esm/decorators/enforce-env.decorator.js.map +1 -0
- package/dist-esm/decorators/index.d.ts +2 -0
- package/dist-esm/decorators/index.d.ts.map +1 -0
- package/dist-esm/decorators/index.js +2 -0
- package/dist-esm/decorators/index.js.map +1 -0
- package/dist-esm/exceptions/index.d.ts +2 -0
- package/dist-esm/exceptions/index.d.ts.map +1 -0
- package/dist-esm/exceptions/index.js +2 -0
- package/dist-esm/exceptions/index.js.map +1 -0
- package/dist-esm/exceptions/no-base-config.exception.d.ts +5 -0
- package/dist-esm/exceptions/no-base-config.exception.d.ts.map +1 -0
- package/dist-esm/exceptions/no-base-config.exception.js +7 -0
- package/dist-esm/exceptions/no-base-config.exception.js.map +1 -0
- package/dist-esm/index.d.ts +4 -0
- package/dist-esm/index.d.ts.map +1 -0
- package/dist-esm/index.js +4 -0
- package/dist-esm/index.js.map +1 -0
- package/dist-esm/path-builder.d.ts +22 -0
- package/dist-esm/path-builder.d.ts.map +1 -0
- package/dist-esm/path-builder.js +75 -0
- package/dist-esm/path-builder.js.map +1 -0
- package/dist-esm/tests/config-loader.test-suite.d.ts +7 -0
- package/dist-esm/tests/config-loader.test-suite.d.ts.map +1 -0
- package/dist-esm/tests/config-loader.test-suite.js +91 -0
- package/dist-esm/tests/config-loader.test-suite.js.map +1 -0
- package/dist-esm/tests/path-builder.test-suite.d.ts +15 -0
- package/dist-esm/tests/path-builder.test-suite.d.ts.map +1 -0
- package/dist-esm/tests/path-builder.test-suite.js +152 -0
- package/dist-esm/tests/path-builder.test-suite.js.map +1 -0
- package/package.json +45 -0
- package/src/config-loader.ts +103 -0
- package/src/decorators/enforce-env.decorator.ts +5 -0
- package/src/decorators/index.ts +1 -0
- package/src/exceptions/index.ts +1 -0
- package/src/exceptions/no-base-config.exception.ts +7 -0
- package/src/index.ts +4 -0
- package/src/path-builder.ts +158 -0
- package/src/tests/config-loader.test-suite.ts +87 -0
- package/src/tests/path-builder.test-suite.ts +133 -0
- package/tsconfig.esm.json +10 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { Describe, expect, Test, TestSuite, } from '@hg-ts/tests';
|
|
3
|
+
import { ExecutionModeVariants, MockExecutionMode, } from '@hg-ts/execution-mode';
|
|
4
|
+
import { PathBuilder, } from '../path-builder';
|
|
5
|
+
let PathBuilderTestSuite = class PathBuilderTestSuite extends TestSuite {
|
|
6
|
+
async simple() {
|
|
7
|
+
const paths = this.getPaths();
|
|
8
|
+
expect(paths).toHaveLength(1);
|
|
9
|
+
expect(paths[0]).toBe('/tmp/example.json');
|
|
10
|
+
}
|
|
11
|
+
async recursive() {
|
|
12
|
+
const paths = this.getPaths({ recursive: true });
|
|
13
|
+
expect(paths).toHaveLength(2);
|
|
14
|
+
expect(paths[0]).toBe('/tmp/example.json');
|
|
15
|
+
expect(paths[1]).toBe('/example.json');
|
|
16
|
+
}
|
|
17
|
+
async full() {
|
|
18
|
+
const paths = this.getPaths({
|
|
19
|
+
recursive: true,
|
|
20
|
+
overridePostfix: 'override',
|
|
21
|
+
basePostfix: 'config',
|
|
22
|
+
envBuilder: true,
|
|
23
|
+
overrideEnv: new MockExecutionMode(ExecutionModeVariants.DEMO),
|
|
24
|
+
configDir: 'config',
|
|
25
|
+
});
|
|
26
|
+
let index = 0;
|
|
27
|
+
expect(paths).toHaveLength(12);
|
|
28
|
+
expect(paths[index++]).toBe('/tmp/config/base/example.config.json');
|
|
29
|
+
expect(paths[index++]).toBe('/tmp/config/base/example.override.json');
|
|
30
|
+
expect(paths[index++]).toBe('/tmp/config/demo/example.config.json');
|
|
31
|
+
expect(paths[index++]).toBe('/tmp/config/demo/example.override.json');
|
|
32
|
+
expect(paths[index++]).toBe('/tmp/config/local/example.config.json');
|
|
33
|
+
expect(paths[index++]).toBe('/tmp/config/local/example.override.json');
|
|
34
|
+
expect(paths[index++]).toBe('/config/base/example.config.json');
|
|
35
|
+
expect(paths[index++]).toBe('/config/base/example.override.json');
|
|
36
|
+
expect(paths[index++]).toBe('/config/demo/example.config.json');
|
|
37
|
+
expect(paths[index++]).toBe('/config/demo/example.override.json');
|
|
38
|
+
expect(paths[index++]).toBe('/config/local/example.config.json');
|
|
39
|
+
expect(paths[index++]).toBe('/config/local/example.override.json');
|
|
40
|
+
}
|
|
41
|
+
async configDir() {
|
|
42
|
+
const paths = this.getPaths({ configDir: 'config' });
|
|
43
|
+
expect(paths).toHaveLength(1);
|
|
44
|
+
expect(paths[0]).toBe('/tmp/config/example.json');
|
|
45
|
+
}
|
|
46
|
+
async envBuilder() {
|
|
47
|
+
const paths = this.getPaths({ envBuilder: true });
|
|
48
|
+
expect(paths).toHaveLength(2);
|
|
49
|
+
expect(paths[0]).toBe('/tmp/base/example.json');
|
|
50
|
+
expect(paths[1]).toBe('/tmp/local/example.json');
|
|
51
|
+
}
|
|
52
|
+
async envBuilderWithOverrideProd() {
|
|
53
|
+
const paths = this.getPaths({ envBuilder: true, overrideEnv: new MockExecutionMode(ExecutionModeVariants.PROD) });
|
|
54
|
+
expect(paths).toHaveLength(3);
|
|
55
|
+
expect(paths[0]).toBe('/tmp/base/example.json');
|
|
56
|
+
expect(paths[1]).toBe('/tmp/prod/example.json');
|
|
57
|
+
expect(paths[2]).toBe('/tmp/local/example.json');
|
|
58
|
+
}
|
|
59
|
+
async envBuilderWithOverrideDev() {
|
|
60
|
+
const paths = this.getPaths({ envBuilder: true, overrideEnv: new MockExecutionMode(ExecutionModeVariants.DEV) });
|
|
61
|
+
expect(paths).toHaveLength(3);
|
|
62
|
+
expect(paths[0]).toBe('/tmp/base/example.json');
|
|
63
|
+
expect(paths[1]).toBe('/tmp/dev/example.json');
|
|
64
|
+
expect(paths[2]).toBe('/tmp/local/example.json');
|
|
65
|
+
}
|
|
66
|
+
async basePostfix() {
|
|
67
|
+
const paths = this.getPaths({ basePostfix: 'config' });
|
|
68
|
+
expect(paths).toHaveLength(1);
|
|
69
|
+
expect(paths[0]).toBe('/tmp/example.config.json');
|
|
70
|
+
}
|
|
71
|
+
async basePostfixWithOverridePostfix() {
|
|
72
|
+
const paths = this.getPaths({ basePostfix: 'config', overridePostfix: 'override' });
|
|
73
|
+
expect(paths).toHaveLength(2);
|
|
74
|
+
expect(paths[0]).toBe('/tmp/example.config.json');
|
|
75
|
+
expect(paths[1]).toBe('/tmp/example.override.json');
|
|
76
|
+
}
|
|
77
|
+
async overridePostfix() {
|
|
78
|
+
const paths = this.getPaths({ overridePostfix: 'override' });
|
|
79
|
+
expect(paths).toHaveLength(2);
|
|
80
|
+
expect(paths[0]).toBe('/tmp/example.json');
|
|
81
|
+
expect(paths[1]).toBe('/tmp/example.override.json');
|
|
82
|
+
}
|
|
83
|
+
getPaths(options = {}) {
|
|
84
|
+
const builder = new PathBuilder({ appPath: '/tmp', ...options });
|
|
85
|
+
return builder.build('example');
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
__decorate([
|
|
89
|
+
Test(),
|
|
90
|
+
__metadata("design:type", Function),
|
|
91
|
+
__metadata("design:paramtypes", []),
|
|
92
|
+
__metadata("design:returntype", Promise)
|
|
93
|
+
], PathBuilderTestSuite.prototype, "simple", null);
|
|
94
|
+
__decorate([
|
|
95
|
+
Test(),
|
|
96
|
+
__metadata("design:type", Function),
|
|
97
|
+
__metadata("design:paramtypes", []),
|
|
98
|
+
__metadata("design:returntype", Promise)
|
|
99
|
+
], PathBuilderTestSuite.prototype, "recursive", null);
|
|
100
|
+
__decorate([
|
|
101
|
+
Test(),
|
|
102
|
+
__metadata("design:type", Function),
|
|
103
|
+
__metadata("design:paramtypes", []),
|
|
104
|
+
__metadata("design:returntype", Promise)
|
|
105
|
+
], PathBuilderTestSuite.prototype, "full", null);
|
|
106
|
+
__decorate([
|
|
107
|
+
Test(),
|
|
108
|
+
__metadata("design:type", Function),
|
|
109
|
+
__metadata("design:paramtypes", []),
|
|
110
|
+
__metadata("design:returntype", Promise)
|
|
111
|
+
], PathBuilderTestSuite.prototype, "configDir", null);
|
|
112
|
+
__decorate([
|
|
113
|
+
Test(),
|
|
114
|
+
__metadata("design:type", Function),
|
|
115
|
+
__metadata("design:paramtypes", []),
|
|
116
|
+
__metadata("design:returntype", Promise)
|
|
117
|
+
], PathBuilderTestSuite.prototype, "envBuilder", null);
|
|
118
|
+
__decorate([
|
|
119
|
+
Test(),
|
|
120
|
+
__metadata("design:type", Function),
|
|
121
|
+
__metadata("design:paramtypes", []),
|
|
122
|
+
__metadata("design:returntype", Promise)
|
|
123
|
+
], PathBuilderTestSuite.prototype, "envBuilderWithOverrideProd", null);
|
|
124
|
+
__decorate([
|
|
125
|
+
Test(),
|
|
126
|
+
__metadata("design:type", Function),
|
|
127
|
+
__metadata("design:paramtypes", []),
|
|
128
|
+
__metadata("design:returntype", Promise)
|
|
129
|
+
], PathBuilderTestSuite.prototype, "envBuilderWithOverrideDev", null);
|
|
130
|
+
__decorate([
|
|
131
|
+
Test(),
|
|
132
|
+
__metadata("design:type", Function),
|
|
133
|
+
__metadata("design:paramtypes", []),
|
|
134
|
+
__metadata("design:returntype", Promise)
|
|
135
|
+
], PathBuilderTestSuite.prototype, "basePostfix", null);
|
|
136
|
+
__decorate([
|
|
137
|
+
Test(),
|
|
138
|
+
__metadata("design:type", Function),
|
|
139
|
+
__metadata("design:paramtypes", []),
|
|
140
|
+
__metadata("design:returntype", Promise)
|
|
141
|
+
], PathBuilderTestSuite.prototype, "basePostfixWithOverridePostfix", null);
|
|
142
|
+
__decorate([
|
|
143
|
+
Test(),
|
|
144
|
+
__metadata("design:type", Function),
|
|
145
|
+
__metadata("design:paramtypes", []),
|
|
146
|
+
__metadata("design:returntype", Promise)
|
|
147
|
+
], PathBuilderTestSuite.prototype, "overridePostfix", null);
|
|
148
|
+
PathBuilderTestSuite = __decorate([
|
|
149
|
+
Describe()
|
|
150
|
+
], PathBuilderTestSuite);
|
|
151
|
+
export { PathBuilderTestSuite };
|
|
152
|
+
//# sourceMappingURL=path-builder.test-suite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-builder.test-suite.js","sourceRoot":"","sources":["../../src/tests/path-builder.test-suite.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hg-ts/config-loader",
|
|
3
|
+
"version": "0.0.15",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"module": "dist-esm/index.js",
|
|
6
|
+
"repository": "git@gitlab.com:hyper-graph/framework.git",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"prepack": "yarn build && yarn lint && yarn test",
|
|
9
|
+
"build": "hg build",
|
|
10
|
+
"build:dev": "hg build:dev",
|
|
11
|
+
"lint": "hg lint",
|
|
12
|
+
"lint:fix": "hg lint:fix",
|
|
13
|
+
"test": "hg test"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@hg-ts-config/eslint-config": "0.0.15",
|
|
17
|
+
"@hg-ts-config/typescript": "0.0.15",
|
|
18
|
+
"@hg-ts/cli": "0.0.15",
|
|
19
|
+
"@hg-ts/exception": "0.0.15",
|
|
20
|
+
"@hg-ts/execution-mode": "0.0.15",
|
|
21
|
+
"@hg-ts/tests": "0.0.15",
|
|
22
|
+
"@hg-ts/types": "0.0.15",
|
|
23
|
+
"@types/node": "18.0.3",
|
|
24
|
+
"@typescript-eslint/eslint-plugin": "5.33.1",
|
|
25
|
+
"@typescript-eslint/parser": "5.33.1",
|
|
26
|
+
"class-transformer": "0.5.1",
|
|
27
|
+
"class-validator": "0.13.2",
|
|
28
|
+
"eslint": "8.24.0",
|
|
29
|
+
"eslint-formatter-codeframe": "7.32.1",
|
|
30
|
+
"mocha": "10.0.0",
|
|
31
|
+
"mocha-junit-reporter": "2.0.2",
|
|
32
|
+
"reflect-metadata": "0.1.13",
|
|
33
|
+
"tsc-watch": "5.0.3",
|
|
34
|
+
"tslib": "2.4.0",
|
|
35
|
+
"typescript": "4.7.4"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@hg-ts/exception": "*",
|
|
39
|
+
"@hg-ts/execution-mode": "*",
|
|
40
|
+
"class-transformer": "*",
|
|
41
|
+
"class-validator": "*",
|
|
42
|
+
"reflect-metadata": "*",
|
|
43
|
+
"tslib": "*"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
|
|
4
|
+
import { validate } from 'class-validator';
|
|
5
|
+
import { plainToInstance } from 'class-transformer';
|
|
6
|
+
|
|
7
|
+
import { NoBaseConfigException } from './exceptions';
|
|
8
|
+
import { PathBuilder, PathBuilderOptions } from './path-builder';
|
|
9
|
+
|
|
10
|
+
export type ConfigLoaderOptions = PathBuilderOptions & {
|
|
11
|
+
recursive?: boolean;
|
|
12
|
+
cache?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type CacheItem = {
|
|
16
|
+
ctor: Class<object>;
|
|
17
|
+
config: object;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export class ConfigLoader {
|
|
21
|
+
private readonly pathBuilder: PathBuilder;
|
|
22
|
+
private readonly options: ConfigLoaderOptions;
|
|
23
|
+
private readonly cacheMap = new Map<string, CacheItem>();
|
|
24
|
+
|
|
25
|
+
public constructor(options: ConfigLoaderOptions = {}) {
|
|
26
|
+
this.pathBuilder = new PathBuilder(options);
|
|
27
|
+
this.options = this.pathBuilder.options;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async load<ConfigType extends object>(ctor: Class<ConfigType>, name: string): Promise<ConfigType> {
|
|
31
|
+
if (this.options.cache && this.cacheMap.has(name)) {
|
|
32
|
+
const cacheItem = this.cacheMap.get(name)!;
|
|
33
|
+
|
|
34
|
+
assert.ok(cacheItem.ctor === ctor, `cached instance of config "${name}" has another dto class`);
|
|
35
|
+
|
|
36
|
+
return cacheItem.config as ConfigType;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const rawConfig = await this.loadRawConfig(name);
|
|
40
|
+
|
|
41
|
+
const config = this.transform(rawConfig, ctor);
|
|
42
|
+
|
|
43
|
+
await this.validate(config);
|
|
44
|
+
|
|
45
|
+
if (this.options.cache) {
|
|
46
|
+
this.cacheMap.set(name, { ctor, config });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return config;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async loadRawConfig(name: string): Promise<unknown> {
|
|
53
|
+
const paths = this.pathBuilder.build(name);
|
|
54
|
+
const configs = await Promise.all(paths.map(async path => this.loadConfigFile(path)));
|
|
55
|
+
|
|
56
|
+
if (!configs[0]) {
|
|
57
|
+
throw new NoBaseConfigException(name);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return this.mergeConfigs(configs);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private mergeConfigs(configs: unknown[]): Record<string, unknown> {
|
|
64
|
+
return configs
|
|
65
|
+
.filter(config => config !== null)
|
|
66
|
+
.filter((config): config is Record<string, unknown> => typeof config === 'object')
|
|
67
|
+
.reduce((merged, next) => {
|
|
68
|
+
if (merged['root'] === true && this.options.recursive) {
|
|
69
|
+
return merged;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
...merged,
|
|
73
|
+
...next,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private transform<ConfigType extends object>(rawConfig: unknown, ctor: Class<ConfigType>): ConfigType {
|
|
79
|
+
return plainToInstance(ctor, rawConfig);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private async validate<ConfigType extends object>(config: ConfigType): Promise<void> {
|
|
83
|
+
const validationErrors = await validate(config);
|
|
84
|
+
|
|
85
|
+
if (validationErrors.length > 0) {
|
|
86
|
+
/*
|
|
87
|
+
* TODO: Use aggregate exception from @hg/exception
|
|
88
|
+
* TODO: Map validateErrors to BaseException from @hg/exception
|
|
89
|
+
*/
|
|
90
|
+
throw new AggregateError(validationErrors, 'Config validation error');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private async loadConfigFile(path: string): Promise<unknown> {
|
|
95
|
+
try {
|
|
96
|
+
const content = await fs.readFile(path, { encoding: 'utf-8' });
|
|
97
|
+
|
|
98
|
+
return JSON.parse(content) as unknown;
|
|
99
|
+
} catch (error: unknown) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './enforce-env.decorator';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './no-base-config.exception';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { ExecutionMode } from '@hg-ts/execution-mode';
|
|
2
|
+
import {
|
|
3
|
+
dirname,
|
|
4
|
+
resolve,
|
|
5
|
+
} from 'path';
|
|
6
|
+
|
|
7
|
+
export type PathBuilderOptions = {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* Override default app path
|
|
12
|
+
* @default process.cwd()
|
|
13
|
+
*/
|
|
14
|
+
appPath?: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* Additional directory to appPath
|
|
19
|
+
* @default null
|
|
20
|
+
*/
|
|
21
|
+
configDir?: Nullable<string>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* Use environment variable for build config.
|
|
26
|
+
* Get base config, apply ${env} config and, after, apply local config
|
|
27
|
+
* @default false
|
|
28
|
+
*/
|
|
29
|
+
envBuilder?: boolean;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* Override injected env
|
|
34
|
+
* Uses only with envBuilder: true
|
|
35
|
+
*/
|
|
36
|
+
overrideEnv?: Nullable<ExecutionMode>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* Used for loading root package config. Useful with overridePostfix option
|
|
41
|
+
* @default null
|
|
42
|
+
* @todo Implement
|
|
43
|
+
*/
|
|
44
|
+
basePostfix?: Nullable<string>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* Useful with basePostfix.
|
|
49
|
+
* For example:
|
|
50
|
+
* You can specify configName to 'hg', basePostfix to 'config' and overridePostfix to 'override'.
|
|
51
|
+
* In this case will be loaded 'bg.config.{ext}' and overrode by 'hg.override.{ext}'.
|
|
52
|
+
* Similar scheme used by many tools like 'docker-compose'.
|
|
53
|
+
* @default null
|
|
54
|
+
* @todo Implement
|
|
55
|
+
*/
|
|
56
|
+
overridePostfix?: Nullable<string>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Apply all configs from `appDir` to `/` until `root` field won't be specified
|
|
60
|
+
* @default false
|
|
61
|
+
* @todo Implement
|
|
62
|
+
*/
|
|
63
|
+
recursive?: boolean;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export class PathBuilder {
|
|
67
|
+
public readonly options: Required<PathBuilderOptions>;
|
|
68
|
+
private paths: string[];
|
|
69
|
+
|
|
70
|
+
public constructor(options: PathBuilderOptions = {}) {
|
|
71
|
+
this.options = {
|
|
72
|
+
appPath: process.cwd(),
|
|
73
|
+
configDir: null,
|
|
74
|
+
envBuilder: false,
|
|
75
|
+
overrideEnv: null,
|
|
76
|
+
overridePostfix: null,
|
|
77
|
+
basePostfix: null,
|
|
78
|
+
recursive: false,
|
|
79
|
+
...options,
|
|
80
|
+
};
|
|
81
|
+
this.paths = [];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public build(name: string): string[] {
|
|
85
|
+
return this.prepareBasePaths()
|
|
86
|
+
.addEnvFolders()
|
|
87
|
+
.addConfigName(name)
|
|
88
|
+
.paths;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
protected prepareBasePaths(): this {
|
|
92
|
+
const { appPath, configDir, recursive } = this.options;
|
|
93
|
+
if (recursive) {
|
|
94
|
+
let nextPath = appPath;
|
|
95
|
+
const basePaths: string[] = [appPath];
|
|
96
|
+
|
|
97
|
+
while (nextPath !== '/') {
|
|
98
|
+
nextPath = dirname(nextPath);
|
|
99
|
+
basePaths.push(nextPath);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.paths = basePaths;
|
|
103
|
+
|
|
104
|
+
if (configDir) {
|
|
105
|
+
this.mergePaths([configDir]);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
this.paths = [this.buildPathToConfig([appPath, configDir])];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
protected addEnvFolders(): this {
|
|
115
|
+
const { envBuilder, overrideEnv } = this.options;
|
|
116
|
+
const envFolders: string[] = [];
|
|
117
|
+
|
|
118
|
+
if (!envBuilder) {
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
envFolders.push('base');
|
|
123
|
+
|
|
124
|
+
if (overrideEnv) {
|
|
125
|
+
envFolders.push(overrideEnv.getValue());
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
envFolders.push('local');
|
|
129
|
+
|
|
130
|
+
return this.mergePaths(envFolders);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
protected addConfigName(configName: string): this {
|
|
134
|
+
const { overridePostfix, basePostfix } = this.options;
|
|
135
|
+
const baseName = basePostfix ? `${configName}.${basePostfix}.json` : `${configName}.json`;
|
|
136
|
+
const overrideName = overridePostfix ? `${configName}.${overridePostfix}.json` : null;
|
|
137
|
+
|
|
138
|
+
const names = [baseName];
|
|
139
|
+
|
|
140
|
+
if (overrideName) {
|
|
141
|
+
names.push(overrideName);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return this.mergePaths(names);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private mergePaths(additionalParts: string[]): this {
|
|
148
|
+
this.paths = this.paths.flatMap(path => additionalParts.map(part => this.buildPathToConfig([path, part])));
|
|
149
|
+
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private buildPathToConfig(parts: Nullable<string>[]): string {
|
|
154
|
+
const filteredParts = parts.filter((part): part is string => part !== null);
|
|
155
|
+
|
|
156
|
+
return resolve(...filteredParts);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// eslint-disable-next-line max-classes-per-file
|
|
2
|
+
import { Transform } from 'class-transformer';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Describe,
|
|
6
|
+
expect,
|
|
7
|
+
Test,
|
|
8
|
+
TestSuite,
|
|
9
|
+
} from '@hg-ts/tests';
|
|
10
|
+
|
|
11
|
+
import { ConfigLoader } from '../config-loader';
|
|
12
|
+
import { EnforceEnv } from '../decorators';
|
|
13
|
+
|
|
14
|
+
@Describe()
|
|
15
|
+
export class ConfigLoaderTestSuite extends TestSuite {
|
|
16
|
+
@Test()
|
|
17
|
+
public async simple(): Promise<void> {
|
|
18
|
+
const loader = new ConfigLoader();
|
|
19
|
+
|
|
20
|
+
const merged = loader['mergeConfigs']([
|
|
21
|
+
{
|
|
22
|
+
a: 'a',
|
|
23
|
+
b: 'b',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
a: 'aa',
|
|
27
|
+
c: 'c',
|
|
28
|
+
},
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
expect(merged['a']).toBe('aa');
|
|
32
|
+
expect(merged['b']).toBe('b');
|
|
33
|
+
expect(merged['c']).toBe('c');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Test()
|
|
37
|
+
public async recursive(): Promise<void> {
|
|
38
|
+
const loader = new ConfigLoader({ recursive: true });
|
|
39
|
+
|
|
40
|
+
const merged = loader['mergeConfigs']([
|
|
41
|
+
{
|
|
42
|
+
a: 'a',
|
|
43
|
+
b: 'b',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
a: 'aa',
|
|
47
|
+
c: 'c',
|
|
48
|
+
root: true,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
a: 'aaa',
|
|
52
|
+
b: 'bbb',
|
|
53
|
+
c: 'ccc',
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
expect(merged['a']).toBe('aa');
|
|
58
|
+
expect(merged['b']).toBe('b');
|
|
59
|
+
expect(merged['c']).toBe('c');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Test()
|
|
63
|
+
public async enforceEnv(): Promise<void> {
|
|
64
|
+
const loader = new ConfigLoader();
|
|
65
|
+
|
|
66
|
+
class Config {
|
|
67
|
+
@EnforceEnv('SOME_NUMERIC_ENV')
|
|
68
|
+
@Transform(({ value }) => (Number.isNaN(Number(value)) ? value : Number(value)))
|
|
69
|
+
public number: number;
|
|
70
|
+
|
|
71
|
+
@EnforceEnv('SOME_BOOLEAN_ENV')
|
|
72
|
+
// eslint-disable-next-line no-nested-ternary
|
|
73
|
+
@Transform(({ value }) => (value === 'true' ? true : value === 'false' ? false : value))
|
|
74
|
+
public bool: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
process.env['SOME_NUMERIC_ENV'] = '10';
|
|
78
|
+
process.env['SOME_BOOLEAN_ENV'] = 'false';
|
|
79
|
+
|
|
80
|
+
const config: Record<string, unknown> = { number: '1', bool: true };
|
|
81
|
+
|
|
82
|
+
const transformed = loader['transform'](config, Config);
|
|
83
|
+
|
|
84
|
+
expect(transformed.number).toBe(10);
|
|
85
|
+
expect(transformed.bool).toBe(false);
|
|
86
|
+
}
|
|
87
|
+
}
|