traced-config 0.0.0 → 0.2.0

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/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { CliValue } from './types.js';
2
+ export declare function parseCli(argv: string[]): Map<string, CliValue>;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CA4B9D"}
package/dist/cli.js ADDED
@@ -0,0 +1,25 @@
1
+ export function parseCli(argv) {
2
+ const parsed = new Map();
3
+ for (let index = 2; index < argv.length; index += 1) {
4
+ const token = argv[index];
5
+ if (!token || !token.startsWith('--')) {
6
+ continue;
7
+ }
8
+ const equalIndex = token.indexOf('=');
9
+ if (equalIndex !== -1) {
10
+ const name = token.slice(0, equalIndex);
11
+ const value = token.slice(equalIndex + 1);
12
+ parsed.set(name, { value, source: name });
13
+ continue;
14
+ }
15
+ const next = argv[index + 1];
16
+ if (typeof next === 'string' && !next.startsWith('--')) {
17
+ parsed.set(token, { value: next, source: token });
18
+ index += 1;
19
+ continue;
20
+ }
21
+ parsed.set(token, { value: 'true', source: token });
22
+ }
23
+ return parsed;
24
+ }
25
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,QAAQ,CAAC,IAAc;IACrC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE3C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;YACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,KAAK,IAAI,CAAC,CAAC;YACX,SAAS;QACX,CAAC;QAED,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { tracedConfig } from './traced-config.js';
2
+ export type { InferSchemaValues, Origin, SchemaEntry, SchemaShape, TracedConfigApi, TracedConfigOptions, TracedValue, ValidateError, } from './types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,YAAY,EACV,iBAAiB,EACjB,MAAM,EACN,WAAW,EACX,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,aAAa,GACd,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { tracedConfig } from './traced-config.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,13 @@
1
+ export declare function toScreamingSnake(input: string): string;
2
+ export declare function toKebab(input: string): string;
3
+ declare const ENV_NAME_BUILDERS: {
4
+ readonly SCREAMING_SNAKE: typeof toScreamingSnake;
5
+ };
6
+ declare const ARG_NAME_BUILDERS: {
7
+ readonly kebab: (key: string) => string;
8
+ };
9
+ export declare function buildDefaultEnvName(key: string, envStyle: keyof typeof ENV_NAME_BUILDERS): string;
10
+ export declare function buildDefaultArgName(key: string, argStyle: keyof typeof ARG_NAME_BUILDERS): string;
11
+ export declare function normalizeArgName(argName: string): string;
12
+ export {};
13
+ //# sourceMappingURL=naming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMtD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM7C;AAED,QAAA,MAAM,iBAAiB;;CAEb,CAAC;AAEX,QAAA,MAAM,iBAAiB;0BACR,MAAM;CACX,CAAC;AAEX,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,iBAAiB,GAAG,MAAM,CAEjG;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,iBAAiB,GAAG,MAAM,CAEjG;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD"}
package/dist/naming.js ADDED
@@ -0,0 +1,30 @@
1
+ export function toScreamingSnake(input) {
2
+ return input
3
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
4
+ .replace(/([A-Z])([A-Z][a-z])/g, '$1_$2')
5
+ .replace(/[\s.-]+/g, '_')
6
+ .toUpperCase();
7
+ }
8
+ export function toKebab(input) {
9
+ return input
10
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
11
+ .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
12
+ .replace(/[\s._]+/g, '-')
13
+ .toLowerCase();
14
+ }
15
+ const ENV_NAME_BUILDERS = {
16
+ SCREAMING_SNAKE: toScreamingSnake,
17
+ };
18
+ const ARG_NAME_BUILDERS = {
19
+ kebab: (key) => `--${toKebab(key)}`,
20
+ };
21
+ export function buildDefaultEnvName(key, envStyle) {
22
+ return ENV_NAME_BUILDERS[envStyle](key);
23
+ }
24
+ export function buildDefaultArgName(key, argStyle) {
25
+ return ARG_NAME_BUILDERS[argStyle](key);
26
+ }
27
+ export function normalizeArgName(argName) {
28
+ return argName.startsWith('--') ? argName : `--${argName}`;
29
+ }
30
+ //# sourceMappingURL=naming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.js","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,KAAK;SACT,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,sBAAsB,EAAE,OAAO,CAAC;SACxC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,sBAAsB,EAAE,OAAO,CAAC;SACxC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,iBAAiB,GAAG;IACxB,eAAe,EAAE,gBAAgB;CACzB,CAAC;AAEX,MAAM,iBAAiB,GAAG;IACxB,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE;CACnC,CAAC;AAEX,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,QAAwC;IACvF,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,QAAwC;IACvF,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { InferSchemaValues, SchemaShape, TracedConfigApi, TracedConfigOptions } from './types.js';
2
+ export declare function tracedConfig<TSchema extends SchemaShape = {}>(options?: TracedConfigOptions<TSchema>): TracedConfigApi<InferSchemaValues<TSchema>>;
3
+ //# sourceMappingURL=traced-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traced-config.d.ts","sourceRoot":"","sources":["../src/traced-config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAKV,iBAAiB,EAGjB,WAAW,EAEX,eAAe,EACf,mBAAmB,EAIpB,MAAM,YAAY,CAAC;AAWpB,wBAAgB,YAAY,CAAC,OAAO,SAAS,WAAW,GAAG,EAAE,EAC3D,OAAO,GAAE,mBAAmB,CAAC,OAAO,CAAM,GACzC,eAAe,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CA+R7C"}
@@ -0,0 +1,254 @@
1
+ import { access, readFile } from 'node:fs/promises';
2
+ import { constants } from 'node:fs';
3
+ import { parseCli } from './cli.js';
4
+ import { buildDefaultArgName, buildDefaultEnvName, normalizeArgName } from './naming.js';
5
+ import { createDefaultParsers, flattenFileEntries, getFileExtension, isMissingFileError, isPlainObject } from './utils.js';
6
+ import { coerceInputValue, isBuiltinStringFormat, validateFormatValue } from './validation.js';
7
+ const DEFAULT_SOURCES = {
8
+ global: true,
9
+ local: true,
10
+ env: true,
11
+ cli: false,
12
+ };
13
+ export function tracedConfig(options = {}) {
14
+ const envStyle = options.envStyle ?? 'SCREAMING_SNAKE';
15
+ const argStyle = options.argStyle ?? 'kebab';
16
+ const schema = new Map();
17
+ const globalValues = new Map();
18
+ const localValues = new Map();
19
+ const unknownFileKeys = [];
20
+ const parsers = createDefaultParsers();
21
+ const customFormats = new Map();
22
+ const cachedCliValues = parseCli(process.argv);
23
+ function assertKnownKey(key) {
24
+ const entry = schema.get(key);
25
+ if (!entry) {
26
+ throw new Error(`Schema key '${key}' is not defined`);
27
+ }
28
+ return entry;
29
+ }
30
+ function findPrefixCollision(key, keys) {
31
+ for (const existingKey of keys) {
32
+ if (key.startsWith(`${existingKey}.`) || existingKey.startsWith(`${key}.`)) {
33
+ return existingKey;
34
+ }
35
+ }
36
+ return null;
37
+ }
38
+ function resolveKey(key) {
39
+ const entry = assertKnownKey(key);
40
+ let traced = {
41
+ value: entry.default,
42
+ source: null,
43
+ origin: 'default',
44
+ };
45
+ if (entry.sources.global) {
46
+ const fromGlobal = globalValues.get(key);
47
+ if (fromGlobal) {
48
+ traced = { value: fromGlobal.value, source: fromGlobal.source, origin: 'global' };
49
+ }
50
+ }
51
+ if (entry.sources.local) {
52
+ const fromLocal = localValues.get(key);
53
+ if (fromLocal) {
54
+ traced = { value: fromLocal.value, source: fromLocal.source, origin: 'local' };
55
+ }
56
+ }
57
+ if (entry.sources.env) {
58
+ const envValue = process.env[entry.env];
59
+ if (envValue !== undefined) {
60
+ traced = {
61
+ value: coerceInputValue(envValue, entry),
62
+ source: entry.env,
63
+ origin: 'env',
64
+ };
65
+ }
66
+ }
67
+ if (entry.sources.cli) {
68
+ const cliValue = cachedCliValues.get(entry.arg);
69
+ if (cliValue) {
70
+ traced = {
71
+ value: coerceInputValue(cliValue.value, entry),
72
+ source: cliValue.source,
73
+ origin: 'cli',
74
+ };
75
+ }
76
+ }
77
+ return traced;
78
+ }
79
+ function addSchema(next) {
80
+ const pendingEntries = [];
81
+ for (const [key, rawEntry] of Object.entries(next)) {
82
+ if (schema.has(key)) {
83
+ throw new Error(`Schema key '${key}' is already defined`);
84
+ }
85
+ const collidedKey = findPrefixCollision(key, schema.keys()) ?? findPrefixCollision(key, pendingEntries.map(([pendingKey]) => pendingKey));
86
+ if (collidedKey) {
87
+ throw new Error(`Schema key '${key}' has a prefix collision with existing key '${collidedKey}'`);
88
+ }
89
+ if (typeof rawEntry.doc !== 'string' || rawEntry.doc.trim().length === 0) {
90
+ throw new Error(`Schema key '${key}' must define a non-empty doc string`);
91
+ }
92
+ const env = rawEntry.env ?? buildDefaultEnvName(key, envStyle);
93
+ const arg = rawEntry.arg ?? buildDefaultArgName(key, argStyle);
94
+ const sources = {
95
+ ...DEFAULT_SOURCES,
96
+ ...(rawEntry.sources ?? {}),
97
+ };
98
+ pendingEntries.push([key, {
99
+ default: rawEntry.default,
100
+ doc: rawEntry.doc,
101
+ format: rawEntry.format,
102
+ env,
103
+ arg: normalizeArgName(arg),
104
+ sources,
105
+ }]);
106
+ }
107
+ for (const [key, entry] of pendingEntries) {
108
+ schema.set(key, entry);
109
+ }
110
+ return api;
111
+ }
112
+ function addParser(extension, parser) {
113
+ if (typeof extension !== 'string' || extension.trim().length === 0) {
114
+ throw new Error('Parser extension must be a non-empty string');
115
+ }
116
+ if (typeof parser !== 'function') {
117
+ throw new Error('Parser must be a function');
118
+ }
119
+ const normalized = extension.replace(/^\./, '').toLowerCase();
120
+ parsers.set(normalized, parser);
121
+ }
122
+ function addFormat(name, validator) {
123
+ if (typeof name !== 'string' || name.trim().length === 0) {
124
+ throw new Error('Format name must be a non-empty string');
125
+ }
126
+ if (typeof validator !== 'function') {
127
+ throw new Error('Format validator must be a function');
128
+ }
129
+ customFormats.set(name, validator);
130
+ }
131
+ async function loadFile(entries) {
132
+ for (const entry of entries) {
133
+ if (!isPlainObject(entry) || typeof entry.path !== 'string' || (entry.label !== 'global' && entry.label !== 'local')) {
134
+ throw new Error('loadFile entries must be objects with { path, label } where label is global or local');
135
+ }
136
+ try {
137
+ await access(entry.path, constants.F_OK);
138
+ }
139
+ catch (error) {
140
+ if (isMissingFileError(error)) {
141
+ continue;
142
+ }
143
+ throw error;
144
+ }
145
+ const content = await readFile(entry.path, 'utf8');
146
+ const extension = getFileExtension(entry.path);
147
+ const parser = parsers.get(extension);
148
+ if (!parser) {
149
+ throw new Error(`Unsupported file type for path: ${entry.path}`);
150
+ }
151
+ let parsedRaw;
152
+ try {
153
+ parsedRaw = parser(content);
154
+ }
155
+ catch {
156
+ throw new Error(`Failed to parse config file '${entry.path}' (label: ${entry.label})`);
157
+ }
158
+ const parsedEntries = isPlainObject(parsedRaw) ? flattenFileEntries(parsedRaw, new Set(schema.keys())) : [];
159
+ for (const [key, value] of parsedEntries) {
160
+ if (!schema.has(key)) {
161
+ unknownFileKeys.push({ key, source: entry.path, origin: entry.label });
162
+ continue;
163
+ }
164
+ if (entry.label === 'global') {
165
+ globalValues.set(key, { value, source: entry.path });
166
+ }
167
+ else {
168
+ localValues.set(key, { value, source: entry.path });
169
+ }
170
+ }
171
+ }
172
+ }
173
+ function get(key) {
174
+ return resolveKey(key).value;
175
+ }
176
+ function getSource(key) {
177
+ return resolveKey(key).source;
178
+ }
179
+ function getOrigin(key) {
180
+ return resolveKey(key).origin;
181
+ }
182
+ function getTraced(key) {
183
+ return resolveKey(key);
184
+ }
185
+ function getSchema() {
186
+ const snapshot = {};
187
+ for (const [key, entry] of schema.entries()) {
188
+ snapshot[key] = {
189
+ default: entry.default,
190
+ doc: entry.doc,
191
+ format: entry.format,
192
+ env: entry.env,
193
+ arg: entry.arg.replace(/^--/u, ''),
194
+ sources: { ...entry.sources },
195
+ };
196
+ }
197
+ return snapshot;
198
+ }
199
+ function validate(validateOptions = {}) {
200
+ const errors = [];
201
+ for (const [key, entry] of schema.entries()) {
202
+ const resolved = resolveKey(key);
203
+ let error = validateFormatValue(key, resolved.value, entry.format);
204
+ if (!error && typeof entry.format === 'string') {
205
+ const validator = customFormats.get(entry.format);
206
+ if (validator && !validator(resolved.value)) {
207
+ error = {
208
+ key,
209
+ value: resolved.value,
210
+ message: `${entry.format} validation failed`,
211
+ };
212
+ }
213
+ else if (!validator && !isBuiltinStringFormat(entry.format)) {
214
+ error = {
215
+ key,
216
+ value: resolved.value,
217
+ message: `Unknown format '${entry.format}'`,
218
+ };
219
+ }
220
+ }
221
+ if (error) {
222
+ errors.push(error);
223
+ }
224
+ }
225
+ if (validateOptions.strict) {
226
+ for (const unknown of unknownFileKeys) {
227
+ errors.push({
228
+ key: unknown.key,
229
+ source: unknown.source,
230
+ origin: unknown.origin,
231
+ message: `Unknown key '${unknown.key}'`,
232
+ });
233
+ }
234
+ }
235
+ return errors;
236
+ }
237
+ const api = {
238
+ addSchema,
239
+ addParser,
240
+ addFormat,
241
+ loadFile,
242
+ get,
243
+ getSource,
244
+ getOrigin,
245
+ getTraced,
246
+ getSchema,
247
+ validate,
248
+ };
249
+ if (options.schema) {
250
+ addSchema(options.schema);
251
+ }
252
+ return api;
253
+ }
254
+ //# sourceMappingURL=traced-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traced-config.js","sourceRoot":"","sources":["../src/traced-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ export type Origin = 'default' | 'global' | 'local' | 'env' | 'cli';
2
+ export type FileLabel = 'global' | 'local';
3
+ export type SourceToggles = {
4
+ global: boolean;
5
+ local: boolean;
6
+ env: boolean;
7
+ cli: boolean;
8
+ };
9
+ export type SchemaEntry<TDefault> = {
10
+ default: TDefault;
11
+ doc: string;
12
+ format?: unknown;
13
+ env?: string;
14
+ arg?: string;
15
+ sources?: Partial<SourceToggles>;
16
+ };
17
+ export type SchemaShape = Record<string, SchemaEntry<unknown>>;
18
+ export type InferSchemaValues<TSchema extends SchemaShape> = {
19
+ [K in keyof TSchema]: TSchema[K]['default'];
20
+ };
21
+ export type TracedValue<TValue> = {
22
+ value: TValue;
23
+ source: string | null;
24
+ origin: Origin;
25
+ };
26
+ export type ValidateError = {
27
+ key: string;
28
+ message: string;
29
+ value?: unknown;
30
+ source?: string | null;
31
+ origin?: string;
32
+ };
33
+ export type TracedConfigOptions<TSchema extends SchemaShape = {}> = {
34
+ envStyle?: 'SCREAMING_SNAKE';
35
+ argStyle?: 'kebab';
36
+ schema?: TSchema;
37
+ };
38
+ export type FileParser = (content: string) => unknown;
39
+ export type FormatValidator = (value: unknown) => boolean;
40
+ export type ResolvedSchemaEntry = {
41
+ default: unknown;
42
+ doc: string;
43
+ format?: unknown;
44
+ env: string;
45
+ arg: string;
46
+ sources: SourceToggles;
47
+ };
48
+ export type FileValueRecord = {
49
+ value: unknown;
50
+ source: string;
51
+ };
52
+ export type CliValue = {
53
+ value: string;
54
+ source: string;
55
+ };
56
+ export type UnknownKeyIssue = {
57
+ key: string;
58
+ source: string;
59
+ origin: FileLabel;
60
+ };
61
+ export type TracedConfigApi<TValues extends Record<string, unknown>> = {
62
+ addSchema: <TSchema extends SchemaShape>(schema: TSchema) => TracedConfigApi<TValues & InferSchemaValues<TSchema>>;
63
+ addParser: (extension: string, parser: FileParser) => void;
64
+ addFormat: (name: string, validator: FormatValidator) => void;
65
+ loadFile: (entries: Array<{
66
+ path: string;
67
+ label: FileLabel;
68
+ }>) => Promise<void>;
69
+ get: <TKey extends Extract<keyof TValues, string>>(key: TKey) => TValues[TKey];
70
+ getSource: <TKey extends Extract<keyof TValues, string>>(key: TKey) => string | null;
71
+ getOrigin: <TKey extends Extract<keyof TValues, string>>(key: TKey) => Origin;
72
+ getTraced: <TKey extends Extract<keyof TValues, string>>(key: TKey) => TracedValue<TValues[TKey]>;
73
+ getSchema: () => Record<string, ResolvedSchemaEntry>;
74
+ validate: (options?: {
75
+ strict?: boolean;
76
+ }) => ValidateError[];
77
+ };
78
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ import type { FileParser } from './types.js';
2
+ export declare function isMissingFileError(error: unknown): boolean;
3
+ export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
4
+ export declare function flattenFileEntries(value: Record<string, unknown>, leafKeys?: ReadonlySet<string>): Array<[string, unknown]>;
5
+ export declare function getFileExtension(filePath: string): string;
6
+ export declare function createDefaultParsers(): Map<string, FileParser>;
7
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwC7C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM1D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9E;AAID,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAqB,GAChD,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA0E1B;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED,wBAAgB,oBAAoB,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAO9D"}
package/dist/utils.js ADDED
@@ -0,0 +1,112 @@
1
+ import YAML from 'yaml';
2
+ function parseDotEnv(content) {
3
+ const parsed = {};
4
+ const lines = content.split(/\r?\n/u);
5
+ for (const [index, line] of lines.entries()) {
6
+ const lineNumber = index + 1;
7
+ const trimmed = line.trim();
8
+ if (trimmed.length === 0 || trimmed.startsWith('#')) {
9
+ continue;
10
+ }
11
+ const withoutExport = trimmed.startsWith('export ') ? trimmed.slice('export '.length) : trimmed;
12
+ const separatorIndex = withoutExport.indexOf('=');
13
+ if (separatorIndex <= 0) {
14
+ throw new Error(`Invalid .env entry at line ${lineNumber}`);
15
+ }
16
+ const key = withoutExport.slice(0, separatorIndex).trim();
17
+ let value = withoutExport.slice(separatorIndex + 1).trim();
18
+ if (key.length === 0) {
19
+ throw new Error(`Invalid .env entry at line ${lineNumber}`);
20
+ }
21
+ if (value.length >= 2
22
+ && ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith('\'') && value.endsWith('\'')))) {
23
+ value = value.slice(1, -1);
24
+ }
25
+ parsed[key] = value;
26
+ }
27
+ return parsed;
28
+ }
29
+ export function isMissingFileError(error) {
30
+ if (!(error instanceof Error)) {
31
+ return false;
32
+ }
33
+ return 'code' in error && error.code === 'ENOENT';
34
+ }
35
+ export function isPlainObject(value) {
36
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
37
+ }
38
+ const MAX_CONFIG_NESTING_DEPTH = 100;
39
+ export function flattenFileEntries(value, leafKeys = new Set()) {
40
+ const flattened = [];
41
+ const activeAncestors = new WeakSet();
42
+ const stack = [
43
+ {
44
+ value,
45
+ prefix: '',
46
+ entries: Object.entries(value),
47
+ index: 0,
48
+ depth: 0,
49
+ },
50
+ ];
51
+ activeAncestors.add(value);
52
+ while (stack.length > 0) {
53
+ const current = stack[stack.length - 1];
54
+ if (!current) {
55
+ break;
56
+ }
57
+ if (current.index >= current.entries.length) {
58
+ activeAncestors.delete(current.value);
59
+ stack.pop();
60
+ continue;
61
+ }
62
+ const nextEntry = current.entries[current.index];
63
+ if (!nextEntry) {
64
+ activeAncestors.delete(current.value);
65
+ stack.pop();
66
+ continue;
67
+ }
68
+ const [key, nestedValue] = nextEntry;
69
+ current.index += 1;
70
+ const dottedKey = current.prefix.length === 0 ? key : `${current.prefix}.${key}`;
71
+ if (!isPlainObject(nestedValue)) {
72
+ flattened.push([dottedKey, nestedValue]);
73
+ continue;
74
+ }
75
+ if (activeAncestors.has(nestedValue)) {
76
+ throw new Error('Circular references in config files are not supported');
77
+ }
78
+ if (leafKeys.has(dottedKey)) {
79
+ flattened.push([dottedKey, nestedValue]);
80
+ continue;
81
+ }
82
+ const nextDepth = current.depth + 1;
83
+ if (nextDepth > MAX_CONFIG_NESTING_DEPTH) {
84
+ throw new Error(`Config file nesting exceeds maximum depth of ${MAX_CONFIG_NESTING_DEPTH}`);
85
+ }
86
+ activeAncestors.add(nestedValue);
87
+ stack.push({
88
+ value: nestedValue,
89
+ prefix: dottedKey,
90
+ entries: Object.entries(nestedValue),
91
+ index: 0,
92
+ depth: nextDepth,
93
+ });
94
+ }
95
+ return flattened;
96
+ }
97
+ export function getFileExtension(filePath) {
98
+ const lastDot = filePath.lastIndexOf('.');
99
+ if (lastDot === -1 || lastDot === filePath.length - 1) {
100
+ throw new Error(`Unsupported file type for path: ${filePath}`);
101
+ }
102
+ return filePath.slice(lastDot + 1).toLowerCase();
103
+ }
104
+ export function createDefaultParsers() {
105
+ return new Map([
106
+ ['yaml', (content) => YAML.parse(content)],
107
+ ['yml', (content) => YAML.parse(content)],
108
+ ['json', (content) => JSON.parse(content)],
109
+ ['env', (content) => parseDotEnv(content)],
110
+ ]);
111
+ }
112
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ResolvedSchemaEntry, ValidateError } from './types.js';
2
+ export declare function isBuiltinStringFormat(format: string): boolean;
3
+ export declare function coerceInputValue(value: unknown, entry: ResolvedSchemaEntry): unknown;
4
+ export declare function validateFormatValue(key: string, value: unknown, format: unknown): ValidateError | null;
5
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwCrE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAuBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAkCpF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CAqCtG"}
@@ -0,0 +1,111 @@
1
+ const BUILTIN_STRING_FORMAT_VALIDATORS = {
2
+ port: (key, value) => {
3
+ const valid = typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 65535;
4
+ return valid ? null : { key, value, message: 'port must be 0-65535' };
5
+ },
6
+ nat: (key, value) => {
7
+ const valid = typeof value === 'number' && Number.isInteger(value) && value >= 0;
8
+ return valid ? null : { key, value, message: 'nat must be a non-negative integer' };
9
+ },
10
+ int: (key, value) => {
11
+ const valid = typeof value === 'number' && Number.isInteger(value);
12
+ return valid ? null : { key, value, message: 'int must be an integer' };
13
+ },
14
+ url: (key, value) => {
15
+ if (typeof value !== 'string') {
16
+ return { key, value, message: 'url must be a string' };
17
+ }
18
+ try {
19
+ new URL(value);
20
+ return null;
21
+ }
22
+ catch {
23
+ return { key, value, message: 'url must be a valid URL' };
24
+ }
25
+ },
26
+ ipaddress: (key, value) => {
27
+ if (typeof value !== 'string') {
28
+ return { key, value, message: 'ipaddress must be a string' };
29
+ }
30
+ const ipv4 = /^(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/;
31
+ const ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::1|::)$/;
32
+ return ipv4.test(value) || ipv6.test(value) ? null : { key, value, message: 'ipaddress must be a valid IPv4 or IPv6 address' };
33
+ },
34
+ };
35
+ export function isBuiltinStringFormat(format) {
36
+ return Object.hasOwn(BUILTIN_STRING_FORMAT_VALIDATORS, format);
37
+ }
38
+ function coerceNumberString(value) {
39
+ const parsed = Number(value);
40
+ return Number.isNaN(parsed) ? value : parsed;
41
+ }
42
+ function coerceBooleanString(value) {
43
+ if (value === 'true' || value === '1') {
44
+ return true;
45
+ }
46
+ if (value === 'false' || value === '0') {
47
+ return false;
48
+ }
49
+ return value;
50
+ }
51
+ function coerceArrayString(value) {
52
+ return value.split(',').map((part) => part.trim());
53
+ }
54
+ export function coerceInputValue(value, entry) {
55
+ if (typeof value !== 'string') {
56
+ return value;
57
+ }
58
+ if (entry.format === Array) {
59
+ return coerceArrayString(value);
60
+ }
61
+ if (entry.format === Number || entry.format === 'port' || entry.format === 'nat' || entry.format === 'int') {
62
+ return coerceNumberString(value);
63
+ }
64
+ if (entry.format === Boolean) {
65
+ return coerceBooleanString(value);
66
+ }
67
+ if (entry.format === String) {
68
+ return value;
69
+ }
70
+ if (Array.isArray(entry.default)) {
71
+ return coerceArrayString(value);
72
+ }
73
+ if (typeof entry.default === 'number') {
74
+ return coerceNumberString(value);
75
+ }
76
+ if (typeof entry.default === 'boolean') {
77
+ return coerceBooleanString(value);
78
+ }
79
+ return value;
80
+ }
81
+ export function validateFormatValue(key, value, format) {
82
+ if (format === undefined) {
83
+ return null;
84
+ }
85
+ if (Array.isArray(format)) {
86
+ if (!format.includes(value)) {
87
+ return { key, value, message: `Value must be one of: ${format.join(', ')}` };
88
+ }
89
+ return null;
90
+ }
91
+ if (format === String) {
92
+ return typeof value === 'string' ? null : { key, value, message: 'Value must be a string' };
93
+ }
94
+ if (format === Number) {
95
+ return typeof value === 'number' && Number.isFinite(value) ? null : { key, value, message: 'Value must be a number' };
96
+ }
97
+ if (format === Boolean) {
98
+ return typeof value === 'boolean' ? null : { key, value, message: 'Value must be a boolean' };
99
+ }
100
+ if (format === Array) {
101
+ return Array.isArray(value) ? null : { key, value, message: 'Value must be an array' };
102
+ }
103
+ if (typeof format === 'string') {
104
+ const validator = BUILTIN_STRING_FORMAT_VALIDATORS[format];
105
+ if (validator) {
106
+ return validator(key, value);
107
+ }
108
+ }
109
+ return null;
110
+ }
111
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,26 @@
1
1
  {
2
2
  "name": "traced-config",
3
- "version": "0.0.0",
3
+ "version": "0.2.0",
4
4
  "description": "Configuration management with key-level source tracing. Know where every value came from.",
5
- "license": "MIT",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/nrslib/traced-config.git"
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "watch": "tsc --watch",
20
+ "test": "vitest run",
21
+ "test:watch": "vitest",
22
+ "lint": "eslint src/",
23
+ "prepublishOnly": "npm run build && npm run test"
9
24
  },
10
25
  "keywords": [
11
26
  "config",
@@ -16,5 +31,22 @@
16
31
  "env",
17
32
  "cli",
18
33
  "precedence"
19
- ]
34
+ ],
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/nrslib/traced-config.git"
39
+ },
40
+ "engines": {
41
+ "node": ">=20"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^22.19.11",
45
+ "eslint": "^9.0.0",
46
+ "typescript": "^5.9.3",
47
+ "vitest": "^3.2.4"
48
+ },
49
+ "dependencies": {
50
+ "yaml": "^2.8.1"
51
+ }
20
52
  }
@@ -1,20 +0,0 @@
1
- name: Publish to npm
2
-
3
- on:
4
- workflow_dispatch:
5
-
6
- jobs:
7
- publish:
8
- runs-on: ubuntu-latest
9
- steps:
10
- - uses: actions/checkout@v4
11
-
12
- - uses: actions/setup-node@v4
13
- with:
14
- node-version: '20'
15
- registry-url: 'https://registry.npmjs.org'
16
-
17
- - name: Publish package
18
- run: npm publish
19
- env:
20
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}