@hg-ts/config-loader 0.1.13 → 0.1.14
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 -1
- package/dist/config-loader.d.ts +3 -4
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +7 -16
- package/dist/config-loader.js.map +1 -1
- package/dist/tests/config-loader.test-suite.d.ts.map +1 -1
- package/dist/tests/config-loader.test-suite.js +12 -18
- package/dist/tests/config-loader.test-suite.js.map +1 -1
- package/dist-esm/config-loader.d.ts +3 -4
- package/dist-esm/config-loader.d.ts.map +1 -1
- package/dist-esm/config-loader.js +7 -16
- package/dist-esm/config-loader.js.map +1 -1
- package/dist-esm/tests/config-loader.test-suite.d.ts.map +1 -1
- package/dist-esm/tests/config-loader.test-suite.js +12 -18
- package/dist-esm/tests/config-loader.test-suite.js.map +1 -1
- package/dist-esm/zod-extension.d.ts +7 -0
- package/dist-esm/zod-extension.d.ts.map +1 -0
- package/dist-esm/zod-extension.js +6 -0
- package/dist-esm/zod-extension.js.map +1 -0
- package/package.json +12 -15
- package/src/config-loader.ts +14 -25
- package/src/tests/config-loader.test-suite.ts +12 -16
- package/dist/decorators/enforce-env.decorator.d.ts +0 -2
- package/dist/decorators/enforce-env.decorator.d.ts.map +0 -1
- package/dist/decorators/enforce-env.decorator.js +0 -9
- package/dist/decorators/enforce-env.decorator.js.map +0 -1
- package/dist/decorators/index.d.ts +0 -2
- package/dist/decorators/index.d.ts.map +0 -1
- package/dist/decorators/index.js +0 -5
- package/dist/decorators/index.js.map +0 -1
- package/src/decorators/enforce-env.decorator.ts +0 -5
- package/src/decorators/index.ts +0 -1
package/.eslintcache
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"/Volumes/Work/ts/hg/framework/packages/execution-mode/src/index.ts":"1","/Volumes/Work/ts/hg/framework/packages/config-loader/src/config-loader.ts":"2","/Volumes/Work/ts/hg/framework/packages/config-loader/src/
|
|
1
|
+
[{"/Volumes/Work/ts/hg/framework/packages/execution-mode/src/index.ts":"1","/Volumes/Work/ts/hg/framework/packages/config-loader/src/config-loader.ts":"2","/Volumes/Work/ts/hg/framework/packages/config-loader/src/exceptions/index.ts":"3","/Volumes/Work/ts/hg/framework/packages/config-loader/src/exceptions/no-base-config.exception.ts":"4","/Volumes/Work/ts/hg/framework/packages/config-loader/src/index.ts":"5","/Volumes/Work/ts/hg/framework/packages/config-loader/src/path-builder.ts":"6","/Volumes/Work/ts/hg/framework/packages/config-loader/src/tests/config-loader.test-suite.ts":"7","/Volumes/Work/ts/hg/framework/packages/config-loader/src/tests/path-builder.test-suite.ts":"8"},{"size":64,"mtime":1660865486194,"results":"9","hashOfConfig":"10"},{"size":2454,"mtime":1713665849194,"results":"11","hashOfConfig":"12"},{"size":44,"mtime":1664831211489,"results":"13","hashOfConfig":"12"},{"size":215,"mtime":1664831211490,"results":"14","hashOfConfig":"12"},{"size":84,"mtime":1713665848874,"results":"15","hashOfConfig":"12"},{"size":3437,"mtime":1665148294534,"results":"16","hashOfConfig":"12"},{"size":1629,"mtime":1713666195154,"results":"17","hashOfConfig":"12"},{"size":4026,"mtime":1665299715530,"results":"18","hashOfConfig":"12"},{"filePath":"19","messages":"20","suppressedMessages":"21","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"qbxc86",{"filePath":"22","messages":"23","suppressedMessages":"24","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"5sbno",{"filePath":"25","messages":"26","suppressedMessages":"27","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"28","messages":"29","suppressedMessages":"30","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"31","messages":"32","suppressedMessages":"33","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"34","messages":"35","suppressedMessages":"36","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"37","messages":"38","suppressedMessages":"39","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"40","messages":"41","suppressedMessages":"42","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Volumes/Work/ts/hg/framework/packages/execution-mode/src/index.ts",[],[],"/Volumes/Work/ts/hg/framework/packages/config-loader/src/config-loader.ts",[],[],"/Volumes/Work/ts/hg/framework/packages/config-loader/src/exceptions/index.ts",[],[],"/Volumes/Work/ts/hg/framework/packages/config-loader/src/exceptions/no-base-config.exception.ts",[],[],"/Volumes/Work/ts/hg/framework/packages/config-loader/src/index.ts",[],[],"/Volumes/Work/ts/hg/framework/packages/config-loader/src/path-builder.ts",[],[],"/Volumes/Work/ts/hg/framework/packages/config-loader/src/tests/config-loader.test-suite.ts",[],[],"/Volumes/Work/ts/hg/framework/packages/config-loader/src/tests/path-builder.test-suite.ts",[],[]]
|
package/dist/config-loader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import zod from '@hg-ts/validation';
|
|
2
2
|
import { PathBuilderOptions } from './path-builder';
|
|
3
3
|
export type ConfigLoaderOptions = PathBuilderOptions & {
|
|
4
4
|
recursive?: boolean;
|
|
@@ -9,11 +9,10 @@ export declare class ConfigLoader {
|
|
|
9
9
|
private readonly options;
|
|
10
10
|
private readonly cacheMap;
|
|
11
11
|
constructor(options?: ConfigLoaderOptions);
|
|
12
|
-
load<ConfigType extends object>(
|
|
12
|
+
load<ConfigType extends object>(schema: zod.Schema<ConfigType>, name: string): Promise<ConfigType>;
|
|
13
|
+
private validate;
|
|
13
14
|
private loadRawConfig;
|
|
14
15
|
private mergeConfigs;
|
|
15
|
-
private transform;
|
|
16
|
-
private validate;
|
|
17
16
|
private loadConfigFile;
|
|
18
17
|
}
|
|
19
18
|
//# sourceMappingURL=config-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"AAGA,OAAO,GAA8B,MAAM,mBAAmB,CAAC;AAG/D,OAAO,EAAe,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAAG;IACtD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAOF,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;gBAEtC,OAAO,GAAE,mBAAwB;IAKvC,IAAI,CAAC,UAAU,SAAS,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;YAoBjG,QAAQ;YAOR,aAAa;IAY3B,OAAO,CAAC,YAAY;YAeN,cAAc;CAS5B"}
|
package/dist/config-loader.js
CHANGED
|
@@ -4,8 +4,6 @@ exports.ConfigLoader = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const promises_1 = tslib_1.__importDefault(require("node:fs/promises"));
|
|
6
6
|
const strict_1 = tslib_1.__importDefault(require("node:assert/strict"));
|
|
7
|
-
const class_validator_1 = require("class-validator");
|
|
8
|
-
const class_transformer_1 = require("class-transformer");
|
|
9
7
|
const exceptions_1 = require("./exceptions");
|
|
10
8
|
const path_builder_1 = require("./path-builder");
|
|
11
9
|
class ConfigLoader {
|
|
@@ -16,20 +14,22 @@ class ConfigLoader {
|
|
|
16
14
|
this.pathBuilder = new path_builder_1.PathBuilder(options);
|
|
17
15
|
this.options = this.pathBuilder.options;
|
|
18
16
|
}
|
|
19
|
-
async load(
|
|
17
|
+
async load(schema, name) {
|
|
20
18
|
if (this.options.cache && this.cacheMap.has(name)) {
|
|
21
19
|
const cacheItem = this.cacheMap.get(name);
|
|
22
|
-
strict_1.default.ok(cacheItem.
|
|
20
|
+
strict_1.default.ok(cacheItem.schema === schema, `cached instance of config "${name}" has another schema`);
|
|
23
21
|
return cacheItem.config;
|
|
24
22
|
}
|
|
25
23
|
const rawConfig = await this.loadRawConfig(name);
|
|
26
|
-
const config = this.
|
|
27
|
-
await this.validate(config);
|
|
24
|
+
const config = await this.validate(schema, rawConfig);
|
|
28
25
|
if (this.options.cache) {
|
|
29
|
-
this.cacheMap.set(name, {
|
|
26
|
+
this.cacheMap.set(name, { schema, config });
|
|
30
27
|
}
|
|
31
28
|
return config;
|
|
32
29
|
}
|
|
30
|
+
async validate(schema, config) {
|
|
31
|
+
return schema.parseAsync(config);
|
|
32
|
+
}
|
|
33
33
|
async loadRawConfig(name) {
|
|
34
34
|
const paths = this.pathBuilder.build(name);
|
|
35
35
|
const configs = await Promise.all(paths.map(async (path) => this.loadConfigFile(path)));
|
|
@@ -52,15 +52,6 @@ class ConfigLoader {
|
|
|
52
52
|
};
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
-
transform(rawConfig, ctor) {
|
|
56
|
-
return (0, class_transformer_1.plainToInstance)(ctor, rawConfig);
|
|
57
|
-
}
|
|
58
|
-
async validate(config) {
|
|
59
|
-
const validationErrors = await (0, class_validator_1.validate)(config);
|
|
60
|
-
if (validationErrors.length > 0) {
|
|
61
|
-
throw new AggregateError(validationErrors, 'Config validation error');
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
55
|
async loadConfigFile(path) {
|
|
65
56
|
try {
|
|
66
57
|
const content = await promises_1.default.readFile(path, { encoding: 'utf-8' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":";;;;AAAA,wEAAkC;AAClC,wEAAwC;
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.test-suite.d.ts","sourceRoot":"","sources":["../../src/tests/config-loader.test-suite.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config-loader.test-suite.d.ts","sourceRoot":"","sources":["../../src/tests/config-loader.test-suite.ts"],"names":[],"mappings":"AAEA,OAAO,EAIN,SAAS,EACT,MAAM,cAAc,CAAC;AAItB,qBACa,qBAAsB,SAAQ,SAAS;IAEtC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBvB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAsBxC"}
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ConfigLoaderTestSuite = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const
|
|
5
|
+
const validation_1 = tslib_1.__importDefault(require("@hg-ts/validation"));
|
|
6
6
|
const tests_1 = require("@hg-ts/tests");
|
|
7
7
|
const config_loader_1 = require("../config-loader");
|
|
8
|
-
const decorators_1 = require("../decorators");
|
|
9
8
|
let ConfigLoaderTestSuite = class ConfigLoaderTestSuite extends tests_1.TestSuite {
|
|
10
9
|
async simple() {
|
|
11
10
|
const loader = new config_loader_1.ConfigLoader();
|
|
@@ -47,24 +46,19 @@ let ConfigLoaderTestSuite = class ConfigLoaderTestSuite extends tests_1.TestSuit
|
|
|
47
46
|
}
|
|
48
47
|
async enforceEnv() {
|
|
49
48
|
const loader = new config_loader_1.ConfigLoader();
|
|
50
|
-
|
|
51
|
-
number
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
tslib_1.__decorate([
|
|
60
|
-
(0, decorators_1.EnforceEnv)('SOME_BOOLEAN_ENV'),
|
|
61
|
-
(0, class_transformer_1.Transform)(({ value }) => (value === 'true' ? true : value === 'false' ? false : value)),
|
|
62
|
-
tslib_1.__metadata("design:type", Boolean)
|
|
63
|
-
], Config.prototype, "bool", void 0);
|
|
49
|
+
const configSchema = validation_1.default.object({
|
|
50
|
+
number: validation_1.default.union([validation_1.default.number(), validation_1.default.string()])
|
|
51
|
+
.enforceEnv('SOME_NUMERIC_ENV')
|
|
52
|
+
.transform(value => Number(value))
|
|
53
|
+
.pipe(validation_1.default.number()),
|
|
54
|
+
bool: validation_1.default.union([validation_1.default.string(), validation_1.default.boolean()])
|
|
55
|
+
.enforceEnv('SOME_BOOLEAN_ENV')
|
|
56
|
+
.transformBooleanString(),
|
|
57
|
+
});
|
|
64
58
|
process.env['SOME_NUMERIC_ENV'] = '10';
|
|
65
59
|
process.env['SOME_BOOLEAN_ENV'] = 'false';
|
|
66
|
-
const config = { number:
|
|
67
|
-
const transformed = loader['
|
|
60
|
+
const config = { number: 1, bool: true };
|
|
61
|
+
const transformed = await loader['validate'](configSchema, config);
|
|
68
62
|
(0, tests_1.expect)(transformed.number).toBe(10);
|
|
69
63
|
(0, tests_1.expect)(transformed.bool).toBe(false);
|
|
70
64
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.test-suite.js","sourceRoot":"","sources":["../../src/tests/config-loader.test-suite.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"config-loader.test-suite.js","sourceRoot":"","sources":["../../src/tests/config-loader.test-suite.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import zod from '@hg-ts/validation';
|
|
2
2
|
import { PathBuilderOptions } from './path-builder';
|
|
3
3
|
export type ConfigLoaderOptions = PathBuilderOptions & {
|
|
4
4
|
recursive?: boolean;
|
|
@@ -9,11 +9,10 @@ export declare class ConfigLoader {
|
|
|
9
9
|
private readonly options;
|
|
10
10
|
private readonly cacheMap;
|
|
11
11
|
constructor(options?: ConfigLoaderOptions);
|
|
12
|
-
load<ConfigType extends object>(
|
|
12
|
+
load<ConfigType extends object>(schema: zod.Schema<ConfigType>, name: string): Promise<ConfigType>;
|
|
13
|
+
private validate;
|
|
13
14
|
private loadRawConfig;
|
|
14
15
|
private mergeConfigs;
|
|
15
|
-
private transform;
|
|
16
|
-
private validate;
|
|
17
16
|
private loadConfigFile;
|
|
18
17
|
}
|
|
19
18
|
//# sourceMappingURL=config-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"AAGA,OAAO,GAA8B,MAAM,mBAAmB,CAAC;AAG/D,OAAO,EAAe,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAAG;IACtD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAOF,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;gBAEtC,OAAO,GAAE,mBAAwB;IAKvC,IAAI,CAAC,UAAU,SAAS,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;YAoBjG,QAAQ;YAOR,aAAa;IAY3B,OAAO,CAAC,YAAY;YAeN,cAAc;CAS5B"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { validate } from 'class-validator';
|
|
4
|
-
import { plainToInstance } from 'class-transformer';
|
|
5
3
|
import { NoBaseConfigException } from './exceptions';
|
|
6
4
|
import { PathBuilder } from './path-builder';
|
|
7
5
|
export class ConfigLoader {
|
|
@@ -12,20 +10,22 @@ export class ConfigLoader {
|
|
|
12
10
|
this.pathBuilder = new PathBuilder(options);
|
|
13
11
|
this.options = this.pathBuilder.options;
|
|
14
12
|
}
|
|
15
|
-
async load(
|
|
13
|
+
async load(schema, name) {
|
|
16
14
|
if (this.options.cache && this.cacheMap.has(name)) {
|
|
17
15
|
const cacheItem = this.cacheMap.get(name);
|
|
18
|
-
assert.ok(cacheItem.
|
|
16
|
+
assert.ok(cacheItem.schema === schema, `cached instance of config "${name}" has another schema`);
|
|
19
17
|
return cacheItem.config;
|
|
20
18
|
}
|
|
21
19
|
const rawConfig = await this.loadRawConfig(name);
|
|
22
|
-
const config = this.
|
|
23
|
-
await this.validate(config);
|
|
20
|
+
const config = await this.validate(schema, rawConfig);
|
|
24
21
|
if (this.options.cache) {
|
|
25
|
-
this.cacheMap.set(name, {
|
|
22
|
+
this.cacheMap.set(name, { schema, config });
|
|
26
23
|
}
|
|
27
24
|
return config;
|
|
28
25
|
}
|
|
26
|
+
async validate(schema, config) {
|
|
27
|
+
return schema.parseAsync(config);
|
|
28
|
+
}
|
|
29
29
|
async loadRawConfig(name) {
|
|
30
30
|
const paths = this.pathBuilder.build(name);
|
|
31
31
|
const configs = await Promise.all(paths.map(async (path) => this.loadConfigFile(path)));
|
|
@@ -48,15 +48,6 @@ export class ConfigLoader {
|
|
|
48
48
|
};
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
|
-
transform(rawConfig, ctor) {
|
|
52
|
-
return plainToInstance(ctor, rawConfig);
|
|
53
|
-
}
|
|
54
|
-
async validate(config) {
|
|
55
|
-
const validationErrors = await validate(config);
|
|
56
|
-
if (validationErrors.length > 0) {
|
|
57
|
-
throw new AggregateError(validationErrors, 'Config validation error');
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
51
|
async loadConfigFile(path) {
|
|
61
52
|
try {
|
|
62
53
|
const content = await fs.readFile(path, { encoding: 'utf-8' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,MAAM,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.test-suite.d.ts","sourceRoot":"","sources":["../../src/tests/config-loader.test-suite.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config-loader.test-suite.d.ts","sourceRoot":"","sources":["../../src/tests/config-loader.test-suite.ts"],"names":[],"mappings":"AAEA,OAAO,EAIN,SAAS,EACT,MAAM,cAAc,CAAC;AAItB,qBACa,qBAAsB,SAAQ,SAAS;IAEtC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBvB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAsBxC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import
|
|
2
|
+
import zod from '@hg-ts/validation';
|
|
3
3
|
import { Describe, expect, Test, TestSuite, } from '@hg-ts/tests';
|
|
4
4
|
import { ConfigLoader } from '../config-loader';
|
|
5
|
-
import { EnforceEnv } from '../decorators';
|
|
6
5
|
let ConfigLoaderTestSuite = class ConfigLoaderTestSuite extends TestSuite {
|
|
7
6
|
async simple() {
|
|
8
7
|
const loader = new ConfigLoader();
|
|
@@ -44,24 +43,19 @@ let ConfigLoaderTestSuite = class ConfigLoaderTestSuite extends TestSuite {
|
|
|
44
43
|
}
|
|
45
44
|
async enforceEnv() {
|
|
46
45
|
const loader = new ConfigLoader();
|
|
47
|
-
|
|
48
|
-
number
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
__decorate([
|
|
57
|
-
EnforceEnv('SOME_BOOLEAN_ENV'),
|
|
58
|
-
Transform(({ value }) => (value === 'true' ? true : value === 'false' ? false : value)),
|
|
59
|
-
__metadata("design:type", Boolean)
|
|
60
|
-
], Config.prototype, "bool", void 0);
|
|
46
|
+
const configSchema = zod.object({
|
|
47
|
+
number: zod.union([zod.number(), zod.string()])
|
|
48
|
+
.enforceEnv('SOME_NUMERIC_ENV')
|
|
49
|
+
.transform(value => Number(value))
|
|
50
|
+
.pipe(zod.number()),
|
|
51
|
+
bool: zod.union([zod.string(), zod.boolean()])
|
|
52
|
+
.enforceEnv('SOME_BOOLEAN_ENV')
|
|
53
|
+
.transformBooleanString(),
|
|
54
|
+
});
|
|
61
55
|
process.env['SOME_NUMERIC_ENV'] = '10';
|
|
62
56
|
process.env['SOME_BOOLEAN_ENV'] = 'false';
|
|
63
|
-
const config = { number:
|
|
64
|
-
const transformed = loader['
|
|
57
|
+
const config = { number: 1, bool: true };
|
|
58
|
+
const transformed = await loader['validate'](configSchema, config);
|
|
65
59
|
expect(transformed.number).toBe(10);
|
|
66
60
|
expect(transformed.bool).toBe(false);
|
|
67
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.test-suite.js","sourceRoot":"","sources":["../../src/tests/config-loader.test-suite.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"config-loader.test-suite.js","sourceRoot":"","sources":["../../src/tests/config-loader.test-suite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-extension.d.ts","sourceRoot":"","sources":["../src/zod-extension.ts"],"names":[],"mappings":"AAEA,OAAO,QAAQ,KAAK,CAAC;IAEpB,UAAU,SAAS,CAAC,MAAM,GAAG,GAAG;QAC/B,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC;KAC1D;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-extension.js","sourceRoot":"","sources":["../src/zod-extension.ts"],"names":[],"mappings":"AAAA,OAAO,GAAkB,MAAM,KAAK,CAAC;AAQrC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,GAAG,SAAS,UAAU,CAA+B,IAAY;IAC/F,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC;IACpD,OAAO,IAAI,CAAC;AACb,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hg-ts/config-loader",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist-esm/index.js",
|
|
6
6
|
"repository": "git@gitlab.com:hyper-graph/framework.git",
|
|
@@ -15,18 +15,17 @@
|
|
|
15
15
|
"test:coverage": "hg test:coverage"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@hg-ts-config/eslint-config": "0.1.
|
|
19
|
-
"@hg-ts-config/
|
|
20
|
-
"@hg-ts/
|
|
21
|
-
"@hg-ts/
|
|
22
|
-
"@hg-ts/
|
|
23
|
-
"@hg-ts/
|
|
24
|
-
"@hg-ts/
|
|
18
|
+
"@hg-ts-config/eslint-config": "0.1.14",
|
|
19
|
+
"@hg-ts-config/nyc": "0.1.14",
|
|
20
|
+
"@hg-ts-config/typescript": "0.1.14",
|
|
21
|
+
"@hg-ts/cli": "0.1.14",
|
|
22
|
+
"@hg-ts/exception": "0.1.14",
|
|
23
|
+
"@hg-ts/execution-mode": "0.1.14",
|
|
24
|
+
"@hg-ts/tests": "0.1.14",
|
|
25
|
+
"@hg-ts/types": "0.1.14",
|
|
25
26
|
"@types/node": "20.8.7",
|
|
26
27
|
"@typescript-eslint/eslint-plugin": "6.8.0",
|
|
27
28
|
"@typescript-eslint/parser": "6.8.0",
|
|
28
|
-
"class-transformer": "0.5.1",
|
|
29
|
-
"class-validator": "0.14.0",
|
|
30
29
|
"eslint": "8.52.0",
|
|
31
30
|
"mocha": "10.2.0",
|
|
32
31
|
"mocha-junit-reporter": "2.2.1",
|
|
@@ -37,14 +36,12 @@
|
|
|
37
36
|
"typescript": "5.2.2"
|
|
38
37
|
},
|
|
39
38
|
"peerDependencies": {
|
|
40
|
-
"@hg-ts/exception": "
|
|
41
|
-
"@hg-ts/execution-mode": "
|
|
42
|
-
"class-transformer": "*",
|
|
43
|
-
"class-validator": "*",
|
|
39
|
+
"@hg-ts/exception": "0.1.14",
|
|
40
|
+
"@hg-ts/execution-mode": "0.1.14",
|
|
44
41
|
"reflect-metadata": "*",
|
|
45
42
|
"tslib": "*"
|
|
46
43
|
},
|
|
47
44
|
"dependencies": {
|
|
48
|
-
"@hg-ts
|
|
45
|
+
"@hg-ts/validation": "0.1.14"
|
|
49
46
|
}
|
|
50
47
|
}
|
package/src/config-loader.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { plainToInstance } from 'class-transformer';
|
|
4
|
+
import zod, { ZodSchema, ZodTypeDef } from '@hg-ts/validation';
|
|
6
5
|
|
|
7
6
|
import { NoBaseConfigException } from './exceptions';
|
|
8
7
|
import { PathBuilder, PathBuilderOptions } from './path-builder';
|
|
@@ -13,7 +12,7 @@ export type ConfigLoaderOptions = PathBuilderOptions & {
|
|
|
13
12
|
};
|
|
14
13
|
|
|
15
14
|
type CacheItem = {
|
|
16
|
-
|
|
15
|
+
schema: zod.Schema<object>;
|
|
17
16
|
config: object;
|
|
18
17
|
};
|
|
19
18
|
|
|
@@ -27,30 +26,36 @@ export class ConfigLoader {
|
|
|
27
26
|
this.options = this.pathBuilder.options;
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
public async load<ConfigType extends object>(
|
|
29
|
+
public async load<ConfigType extends object>(schema: zod.Schema<ConfigType>, name: string): Promise<ConfigType> {
|
|
31
30
|
if (this.options.cache && this.cacheMap.has(name)) {
|
|
32
31
|
const cacheItem = this.cacheMap.get(name)!;
|
|
33
32
|
|
|
34
|
-
assert.ok(cacheItem.
|
|
33
|
+
assert.ok(cacheItem.schema === schema, `cached instance of config "${name}" has another schema`);
|
|
35
34
|
|
|
36
35
|
return cacheItem.config as ConfigType;
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
const rawConfig = await this.loadRawConfig(name);
|
|
40
39
|
|
|
41
|
-
const config = this.
|
|
42
|
-
|
|
43
|
-
await this.validate(config);
|
|
40
|
+
const config = await this.validate(schema, rawConfig);
|
|
44
41
|
|
|
45
42
|
if (this.options.cache) {
|
|
46
|
-
this.cacheMap.set(name, {
|
|
43
|
+
this.cacheMap.set(name, { schema, config });
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
return config;
|
|
50
47
|
}
|
|
51
48
|
|
|
49
|
+
private async validate<ConfigType>(
|
|
50
|
+
schema: ZodSchema<ConfigType, ZodTypeDef, unknown>,
|
|
51
|
+
config: unknown,
|
|
52
|
+
): Promise<ConfigType> {
|
|
53
|
+
return schema.parseAsync(config);
|
|
54
|
+
}
|
|
55
|
+
|
|
52
56
|
private async loadRawConfig(name: string): Promise<unknown> {
|
|
53
57
|
const paths = this.pathBuilder.build(name);
|
|
58
|
+
|
|
54
59
|
const configs = await Promise.all(paths.map(async path => this.loadConfigFile(path)));
|
|
55
60
|
|
|
56
61
|
if (!configs[0]) {
|
|
@@ -75,22 +80,6 @@ export class ConfigLoader {
|
|
|
75
80
|
});
|
|
76
81
|
}
|
|
77
82
|
|
|
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
83
|
private async loadConfigFile(path: string): Promise<unknown> {
|
|
95
84
|
try {
|
|
96
85
|
const content = await fs.readFile(path, { encoding: 'utf-8' });
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { Transform } from 'class-transformer';
|
|
1
|
+
import zod from '@hg-ts/validation';
|
|
3
2
|
|
|
4
3
|
import {
|
|
5
4
|
Describe,
|
|
@@ -9,7 +8,6 @@ import {
|
|
|
9
8
|
} from '@hg-ts/tests';
|
|
10
9
|
|
|
11
10
|
import { ConfigLoader } from '../config-loader';
|
|
12
|
-
import { EnforceEnv } from '../decorators';
|
|
13
11
|
|
|
14
12
|
@Describe()
|
|
15
13
|
export class ConfigLoaderTestSuite extends TestSuite {
|
|
@@ -62,24 +60,22 @@ export class ConfigLoaderTestSuite extends TestSuite {
|
|
|
62
60
|
@Test()
|
|
63
61
|
public async enforceEnv(): Promise<void> {
|
|
64
62
|
const loader = new ConfigLoader();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
public bool: boolean;
|
|
75
|
-
}
|
|
63
|
+
const configSchema = zod.object({
|
|
64
|
+
number: zod.union([zod.number(), zod.string()])
|
|
65
|
+
.enforceEnv('SOME_NUMERIC_ENV')
|
|
66
|
+
.transform(value => Number(value))
|
|
67
|
+
.pipe(zod.number()),
|
|
68
|
+
bool: zod.union([zod.string(), zod.boolean()])
|
|
69
|
+
.enforceEnv('SOME_BOOLEAN_ENV')
|
|
70
|
+
.transformBooleanString(),
|
|
71
|
+
});
|
|
76
72
|
|
|
77
73
|
process.env['SOME_NUMERIC_ENV'] = '10';
|
|
78
74
|
process.env['SOME_BOOLEAN_ENV'] = 'false';
|
|
79
75
|
|
|
80
|
-
const config
|
|
76
|
+
const config = { number: 1, bool: true };
|
|
81
77
|
|
|
82
|
-
const transformed = loader['
|
|
78
|
+
const transformed = await loader['validate'](configSchema, config);
|
|
83
79
|
|
|
84
80
|
expect(transformed.number).toBe(10);
|
|
85
81
|
expect(transformed.bool).toBe(false);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enforce-env.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/enforce-env.decorator.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAE1D"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EnforceEnv = void 0;
|
|
4
|
-
const class_transformer_1 = require("class-transformer");
|
|
5
|
-
function EnforceEnv(name) {
|
|
6
|
-
return (0, class_transformer_1.Transform)(({ value }) => process.env[name] ?? value);
|
|
7
|
-
}
|
|
8
|
-
exports.EnforceEnv = EnforceEnv;
|
|
9
|
-
//# sourceMappingURL=enforce-env.decorator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enforce-env.decorator.js","sourceRoot":"","sources":["../../src/decorators/enforce-env.decorator.ts"],"names":[],"mappings":";;;AAAA,yDAA8C;AAE9C,SAAgB,UAAU,CAAC,IAAY;IACtC,OAAO,IAAA,6BAAS,EAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC;AAC7D,CAAC;AAFD,gCAEC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC"}
|
package/dist/decorators/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":";;;AAAA,kEAAwC"}
|
package/src/decorators/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './enforce-env.decorator';
|