@config-bound/schema-export 0.1.2 → 0.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @config-bound/schema-export
2
2
 
3
+ ## 0.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [87d2ab6]
8
+ - @config-bound/core@1.0.0
9
+
3
10
  ## 0.1.2
4
11
 
5
12
  ### Patch Changes
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Robert Keyser
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -11,7 +11,7 @@ npm install @config-bound/schema-export
11
11
  ## Usage
12
12
 
13
13
  ```typescript
14
- import { ConfigBound } from '@config-bound/config-bound';
14
+ import { ConfigBound } from '@config-bound/core';
15
15
  import {
16
16
  exportSchema,
17
17
  formatAsJSON,
package/package.json CHANGED
@@ -1,25 +1,32 @@
1
1
  {
2
2
  "name": "@config-bound/schema-export",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Schema export utilities for ConfigBound configuration library",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
7
5
  "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.mts",
8
9
  "exports": {
9
10
  ".": {
10
- "types": "./dist/index.d.ts",
11
- "require": "./dist/index.js",
12
- "import": "./dist/index.js"
11
+ "import": {
12
+ "types": "./dist/index.d.mts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
13
19
  }
14
20
  },
15
- "scripts": {
16
- "build": "tsc",
17
- "clean": "rimraf dist",
18
- "test": "jest",
19
- "lint": "eslint src/**/*.ts --fix",
20
- "lint:ci": "eslint src/**/*.ts",
21
- "format": "prettier --write --config ../../.config/.prettierrc --ignore-path ../../.config/.prettierignore src/**/*.ts",
22
- "format:ci": "prettier --check --config ../../.config/.prettierrc --ignore-path ../../.config/.prettierignore src/**/*.ts"
21
+ "sideEffects": false,
22
+ "files": [
23
+ "dist",
24
+ "README.md",
25
+ "LICENSE",
26
+ "CHANGELOG.md"
27
+ ],
28
+ "engines": {
29
+ "node": ">=20"
23
30
  },
24
31
  "keywords": [
25
32
  "config",
@@ -32,13 +39,14 @@
32
39
  ],
33
40
  "author": "Robert Keyser",
34
41
  "license": "MIT",
42
+ "peerDependencies": {
43
+ "zod": "^4.4.1"
44
+ },
35
45
  "dependencies": {
36
- "@config-bound/config-bound": "0.3.0",
37
46
  "js-yaml": "^4.1.0",
38
- "zod": "^4.4.1"
47
+ "@config-bound/core": "1.0.0"
39
48
  },
40
49
  "devDependencies": {
41
- "@config-bound/eslint-config": "*",
42
50
  "@types/jest": "^30.0.0",
43
51
  "@types/js-yaml": "^4.0.9",
44
52
  "@types/node": "^24.10.0",
@@ -46,14 +54,36 @@
46
54
  "jest": "^30.2.0",
47
55
  "rimraf": "^6.1.0",
48
56
  "ts-jest": "^29.4.5",
49
- "typescript": "^6.0.0"
57
+ "typescript": "^6.0.0",
58
+ "zod": "^4.4.1",
59
+ "@config-bound/eslint-config": "0.0.0",
60
+ "@config-bound/typescript-config": "0.0.0"
50
61
  },
51
62
  "publishConfig": {
52
63
  "access": "public",
53
64
  "registry": "https://registry.npmjs.org"
54
65
  },
66
+ "typedocOptions": {
67
+ "entryPoints": [
68
+ "./src/index.ts"
69
+ ],
70
+ "tsconfig": "./tsconfig.typedoc.json",
71
+ "exclude": [
72
+ "**/*.spec.ts"
73
+ ]
74
+ },
55
75
  "repository": {
56
76
  "type": "git",
57
- "url": "https://github.com/notr-ai/ConfigBound"
77
+ "url": "git+https://github.com/notr-ai/ConfigBound.git"
78
+ },
79
+ "scripts": {
80
+ "build": "tsdown",
81
+ "typecheck": "tsc --noEmit",
82
+ "clean": "rimraf dist",
83
+ "test": "jest",
84
+ "lint": "eslint src/**/*.ts --fix",
85
+ "lint:ci": "eslint src/**/*.ts",
86
+ "format": "prettier --write --config ../../.config/.prettierrc --ignore-path ../../.config/.prettierignore src/**/*.ts",
87
+ "format:ci": "prettier --check --config ../../.config/.prettierrc --ignore-path ../../.config/.prettierignore src/**/*.ts"
58
88
  }
59
- }
89
+ }
package/eslint.config.mjs DELETED
@@ -1,3 +0,0 @@
1
- import configBoundConfig from '@config-bound/eslint-config/package.eslint.mjs';
2
-
3
- export default configBoundConfig;
package/jest.config.js DELETED
@@ -1,26 +0,0 @@
1
- /* eslint-disable @typescript-eslint/naming-convention */
2
-
3
- /** @type {import('ts-jest').JestConfigWithTsJest} **/
4
- export default {
5
- testEnvironment: 'node',
6
- rootDir: './src',
7
- testMatch: ['**/*.spec.ts'],
8
- extensionsToTreatAsEsm: ['.ts'],
9
- moduleNameMapper: {
10
- '^(\\.{1,2}/.*)\\.js$': '$1'
11
- },
12
- transform: {
13
- '^.+\\.tsx?$': [
14
- 'ts-jest',
15
- {
16
- useESM: true,
17
- tsconfig: {
18
- isolatedModules: false
19
- },
20
- diagnostics: {
21
- ignoreCodes: [151002]
22
- }
23
- }
24
- ]
25
- }
26
- };
package/src/index.ts DELETED
@@ -1,14 +0,0 @@
1
- export {
2
- exportElement,
3
- exportSection,
4
- exportSchema,
5
- type ExportedElement,
6
- type ExportedSection,
7
- type ExportedSchema
8
- } from './schemaExporter.js';
9
-
10
- export {
11
- formatAsJSON,
12
- formatAsYAML,
13
- formatAsEnvExample
14
- } from './schemaFormatters.js';
@@ -1,285 +0,0 @@
1
- import { Section } from '@config-bound/config-bound/section';
2
- import { Element } from '@config-bound/config-bound/element';
3
- import { z } from 'zod';
4
- import {
5
- exportElement,
6
- exportSection,
7
- exportSchema
8
- } from './schemaExporter.js';
9
-
10
- describe('Schema Exporter', () => {
11
- describe('exportElement', () => {
12
- it('should export a basic element', () => {
13
- const element = new Element<string>(
14
- 'testElement',
15
- 'A test element',
16
- 'default-value',
17
- 'example-value',
18
- false,
19
- false,
20
- z.string()
21
- );
22
-
23
- const exported = exportElement(element);
24
-
25
- expect(exported.name).toBe('testElement');
26
- expect(exported.description).toBe('A test element');
27
- expect(exported.type).toBe('string');
28
- expect(exported.default).toBe('default-value');
29
- expect(exported.example).toBe('example-value');
30
- expect(exported.required).toBe(true);
31
- expect(exported.sensitive).toBe(false);
32
- });
33
-
34
- it('should handle required elements', () => {
35
- const element = new Element<number>(
36
- 'requiredElement',
37
- 'A required element',
38
- undefined,
39
- 42,
40
- false,
41
- false,
42
- z.number()
43
- );
44
-
45
- const exported = exportElement(element);
46
-
47
- expect(exported.required).toBe(true);
48
- });
49
-
50
- it('should handle sensitive elements', () => {
51
- const element = new Element<string>(
52
- 'secretKey',
53
- 'API secret key',
54
- undefined,
55
- 'sk_test_123',
56
- true,
57
- false,
58
- z.string()
59
- );
60
-
61
- const exported = exportElement(element);
62
-
63
- expect(exported.sensitive).toBe(true);
64
- });
65
-
66
- it('should handle elements with omitFromSchema', () => {
67
- const element = new Element<string>(
68
- 'privateKey',
69
- 'Private configuration key',
70
- 'default',
71
- 'example',
72
- false,
73
- true,
74
- z.string()
75
- );
76
-
77
- expect(element.omitFromSchema).toBe(true);
78
- });
79
-
80
- it('should extract zod validation object', () => {
81
- const element = new Element<number>(
82
- 'port',
83
- 'Server port',
84
- 3000,
85
- undefined,
86
- false,
87
- false,
88
- z.number().min(1).max(65535)
89
- );
90
-
91
- const exported = exportElement(element);
92
-
93
- expect(exported.zodValidation).toBeDefined();
94
- expect((exported.zodValidation as any).type).toBe('number');
95
- });
96
-
97
- it('should handle enum types', () => {
98
- const element = new Element<string>(
99
- 'environment',
100
- 'Runtime environment',
101
- 'development',
102
- undefined,
103
- false,
104
- false,
105
- z.enum(['development', 'staging', 'production'])
106
- );
107
-
108
- const exported = exportElement(element);
109
-
110
- expect(exported.type).toContain('development');
111
- expect(exported.type).toContain('staging');
112
- expect(exported.type).toContain('production');
113
- });
114
- });
115
-
116
- describe('exportSection', () => {
117
- it('should export a section with elements', () => {
118
- const elements = [
119
- new Element<string>('host', 'Database host', 'localhost'),
120
- new Element<number>('port', 'Database port', 5432)
121
- ];
122
-
123
- const section = new Section(
124
- 'database',
125
- elements,
126
- 'Database configuration'
127
- );
128
-
129
- const exported = exportSection(section);
130
-
131
- expect(exported.name).toBe('database');
132
- expect(exported.description).toBe('Database configuration');
133
- expect(exported.elements).toHaveLength(2);
134
- expect(exported.elements[0].name).toBe('host');
135
- expect(exported.elements[1].name).toBe('port');
136
- });
137
-
138
- it('should handle empty sections', () => {
139
- const section = new Section('empty', [], 'Empty section');
140
-
141
- const exported = exportSection(section);
142
-
143
- expect(exported.name).toBe('empty');
144
- expect(exported.elements).toHaveLength(0);
145
- });
146
-
147
- it('should filter out elements with omitFromSchema: true', () => {
148
- const publicElement = new Element<string>(
149
- 'appName',
150
- 'Application name',
151
- 'myApp',
152
- 'exampleApp',
153
- false,
154
- false,
155
- z.string()
156
- );
157
- const privateElement = new Element<string>(
158
- 'internalKey',
159
- 'Internal configuration key',
160
- 'secret',
161
- 'example',
162
- false,
163
- true,
164
- z.string()
165
- );
166
-
167
- const section = new Section(
168
- 'app',
169
- [publicElement, privateElement],
170
- 'Application settings'
171
- );
172
- const exported = exportSection(section);
173
-
174
- expect(exported.name).toBe('app');
175
- expect(exported.description).toBe('Application settings');
176
- expect(exported.elements).toHaveLength(1);
177
- expect(exported.elements[0].name).toBe('appName');
178
- expect(
179
- exported.elements.find(
180
- (e: { name: string }) => e.name === 'internalKey'
181
- )
182
- ).toBeUndefined();
183
- });
184
-
185
- it('should include omitted elements when includeOmitted is true', () => {
186
- const publicElement = new Element<string>(
187
- 'appName',
188
- 'Application name',
189
- 'myApp',
190
- 'exampleApp',
191
- false,
192
- false,
193
- z.string()
194
- );
195
- const privateElement = new Element<string>(
196
- 'internalKey',
197
- 'Internal configuration key',
198
- 'secret',
199
- 'example',
200
- false,
201
- true,
202
- z.string()
203
- );
204
-
205
- const section = new Section(
206
- 'app',
207
- [publicElement, privateElement],
208
- 'Application settings'
209
- );
210
- const exported = exportSection(section, true);
211
-
212
- expect(exported.name).toBe('app');
213
- expect(exported.description).toBe('Application settings');
214
- expect(exported.elements).toHaveLength(2);
215
- expect(exported.elements[0].name).toBe('appName');
216
- expect(exported.elements[1].name).toBe('internalKey');
217
- });
218
- });
219
-
220
- describe('exportSchema', () => {
221
- it('should export a complete schema', () => {
222
- const appElements = [
223
- new Element<number>('port', 'Application port', 3000),
224
- new Element<string>('host', 'Application host', 'localhost')
225
- ];
226
-
227
- const dbElements = [
228
- new Element<string>(
229
- 'connectionString',
230
- 'Database connection',
231
- undefined
232
- )
233
- ];
234
-
235
- const sections = [
236
- new Section('app', appElements, 'Application settings'),
237
- new Section('database', dbElements, 'Database settings')
238
- ];
239
-
240
- const schema = exportSchema('myApp', sections);
241
-
242
- expect(schema.name).toBe('myApp');
243
- expect(schema.sections).toHaveLength(2);
244
- expect(schema.sections[0].name).toBe('app');
245
- expect(schema.sections[1].name).toBe('database');
246
- });
247
-
248
- it('should include omitted elements when includeOmitted is true', () => {
249
- const publicElement = new Element<string>(
250
- 'appName',
251
- 'Application name',
252
- 'myApp',
253
- 'exampleApp',
254
- false,
255
- false,
256
- z.string()
257
- );
258
- const privateElement = new Element<string>(
259
- 'internalKey',
260
- 'Internal configuration key',
261
- 'secret',
262
- 'example',
263
- false,
264
- true,
265
- z.string()
266
- );
267
-
268
- const sections = [
269
- new Section(
270
- 'app',
271
- [publicElement, privateElement],
272
- 'Application settings'
273
- )
274
- ];
275
-
276
- const schema = exportSchema('myApp', sections, true);
277
-
278
- expect(schema.name).toBe('myApp');
279
- expect(schema.sections).toHaveLength(1);
280
- expect(schema.sections[0].elements).toHaveLength(2);
281
- expect(schema.sections[0].elements[0].name).toBe('appName');
282
- expect(schema.sections[0].elements[1].name).toBe('internalKey');
283
- });
284
- });
285
- });
@@ -1,162 +0,0 @@
1
- import { Section } from '@config-bound/config-bound/section';
2
- import { Element } from '@config-bound/config-bound/element';
3
- import { z } from 'zod';
4
-
5
- /**
6
- * Represents a single configuration element in the exported schema
7
- */
8
- export interface ExportedElement {
9
- name: string;
10
- description?: string;
11
- type: string;
12
- default?: unknown;
13
- example?: unknown;
14
- required: boolean;
15
- sensitive: boolean;
16
- zodValidation: unknown;
17
- }
18
-
19
- /**
20
- * Represents a configuration section in the exported schema
21
- */
22
- export interface ExportedSection {
23
- name: string;
24
- description?: string;
25
- elements: ExportedElement[];
26
- }
27
-
28
- /**
29
- * The complete exported configuration schema
30
- */
31
- export interface ExportedSchema {
32
- name: string;
33
- sections: ExportedSection[];
34
- }
35
-
36
- /**
37
- * Extracts a human-readable type string from a Zod schema.
38
- *
39
- * @param validator - Zod validator to inspect.
40
- * @returns Human-readable type string.
41
- */
42
- function extractZodType(validator: z.ZodType): string {
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- const typeName = (validator as any)._def?.type;
45
-
46
- // Handle ZodOptional and ZodNullable wrappers
47
- if (typeName === 'optional' || typeName === 'nullable') {
48
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
- return extractZodType((validator as any)._def.innerType);
50
- }
51
-
52
- // Map common Zod type names to readable types
53
- switch (typeName) {
54
- case 'string':
55
- return 'string';
56
- case 'number':
57
- return 'number';
58
- case 'boolean':
59
- return 'boolean';
60
- case 'enum': {
61
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
- const enumValues = Object.values((validator as any)._def.entries ?? {});
63
- return enumValues.map((v) => String(v)).join(' | ');
64
- }
65
- case 'literal':
66
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
- return String((validator as any)._def.value);
68
- case 'array':
69
- return 'array';
70
- case 'object':
71
- return 'object';
72
- case 'union':
73
- case 'discriminatedUnion': {
74
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
- const options = (validator as any)._def.options;
76
- if (options) {
77
- return options.map((opt: z.ZodType) => extractZodType(opt)).join(' | ');
78
- }
79
- return 'union';
80
- }
81
- case 'any':
82
- return 'any';
83
- case 'unknown':
84
- return 'unknown';
85
- default:
86
- return typeName || 'unknown';
87
- }
88
- }
89
-
90
- /**
91
- * Converts a Zod validator to a JSON Schema representation.
92
- *
93
- * @param validator - Zod validator to convert.
94
- * @returns JSON Schema object.
95
- */
96
- function extractZodValidation(validator: z.ZodType): unknown {
97
- return z.toJSONSchema(validator, {
98
- target: 'openapi-3.0',
99
- reused: 'inline'
100
- });
101
- }
102
-
103
- /**
104
- * Exports an Element to the external schema format.
105
- *
106
- * @param element - Element to export.
107
- * @returns Exported element representation.
108
- */
109
- export function exportElement(element: Element<unknown>): ExportedElement {
110
- return {
111
- name: element.name,
112
- description: element.description,
113
- type: extractZodType(element.validator),
114
- default: element.default,
115
- example: element.example,
116
- required: element.isRequired(),
117
- sensitive: element.sensitive,
118
- zodValidation: extractZodValidation(element.validator)
119
- };
120
- }
121
-
122
- /**
123
- * Exports a Section to the external schema format.
124
- *
125
- * @param section - The section to export.
126
- * @param includeOmitted - Whether to include elements marked with omitFromSchema (default: false).
127
- * @returns Exported section representation.
128
- */
129
- export function exportSection(
130
- section: Section,
131
- includeOmitted: boolean = false
132
- ): ExportedSection {
133
- return {
134
- name: section.name,
135
- description: section.description,
136
- elements: section
137
- .getElements()
138
- .filter(
139
- (element: Element<unknown>) => includeOmitted || !element.omitFromSchema
140
- )
141
- .map(exportElement)
142
- };
143
- }
144
-
145
- /**
146
- * Exports the complete schema to a structured format.
147
- *
148
- * @param name - Name of the configuration.
149
- * @param sections - Sections to include in the export.
150
- * @param includeOmitted - Whether to include elements marked with omitFromSchema (default: false).
151
- * @returns Exported schema representation.
152
- */
153
- export function exportSchema(
154
- name: string,
155
- sections: Section[],
156
- includeOmitted: boolean = false
157
- ): ExportedSchema {
158
- return {
159
- name,
160
- sections: sections.map((section) => exportSection(section, includeOmitted))
161
- };
162
- }
@@ -1,188 +0,0 @@
1
- import {
2
- formatAsJSON,
3
- formatAsYAML,
4
- formatAsEnvExample
5
- } from './schemaFormatters.js';
6
- import { ExportedSchema } from './schemaExporter.js';
7
-
8
- describe('Schema Formatters', () => {
9
- const mockSchema: ExportedSchema = {
10
- name: 'testApp',
11
- sections: [
12
- {
13
- name: 'app',
14
- description: 'Application settings',
15
- elements: [
16
- {
17
- name: 'port',
18
- description: 'Server port',
19
- type: 'number',
20
- default: 3000,
21
- example: 8080,
22
- required: false,
23
- sensitive: false,
24
- zodValidation: {
25
- type: 'number',
26
- rules: [
27
- { name: 'min', args: { limit: 1 } },
28
- { name: 'max', args: { limit: 65535 } }
29
- ]
30
- }
31
- },
32
- {
33
- name: 'apiKey',
34
- description: 'API key',
35
- type: 'string',
36
- default: undefined,
37
- example: 'sk_test_123',
38
- required: true,
39
- sensitive: true,
40
- zodValidation: { type: 'string', flags: { presence: 'required' } }
41
- }
42
- ]
43
- },
44
- {
45
- name: 'database',
46
- description: 'Database configuration',
47
- elements: [
48
- {
49
- name: 'host',
50
- description: 'Database host',
51
- type: 'string',
52
- default: 'localhost',
53
- example: undefined,
54
- required: false,
55
- sensitive: false,
56
- zodValidation: { type: 'string' }
57
- }
58
- ]
59
- }
60
- ]
61
- };
62
-
63
- describe('formatAsJSON', () => {
64
- it('should format schema as pretty JSON', () => {
65
- const result = formatAsJSON(mockSchema, true);
66
-
67
- expect(result).toContain('"name": "testApp"');
68
- expect(result).toContain('"port"');
69
- expect(result).toContain('"database"');
70
- expect(JSON.parse(result)).toEqual(mockSchema);
71
- });
72
-
73
- it('should format schema as compact JSON', () => {
74
- const result = formatAsJSON(mockSchema, false);
75
-
76
- expect(result).not.toContain('\n');
77
- expect(JSON.parse(result)).toEqual(mockSchema);
78
- });
79
- });
80
-
81
- describe('formatAsYAML', () => {
82
- it('should format schema as YAML', () => {
83
- const result = formatAsYAML(mockSchema);
84
-
85
- expect(result).toContain('name: testApp');
86
- expect(result).toContain('- name: port');
87
- expect(result).toContain('- name: database');
88
- expect(result).toBeTruthy();
89
- });
90
- });
91
-
92
- describe('formatAsEnvExample', () => {
93
- it('should format schema as .env.example without prefix', () => {
94
- const result = formatAsEnvExample(mockSchema);
95
-
96
- expect(result).toContain('# testApp Configuration');
97
- expect(result).toContain('# Generated from schema export');
98
- expect(result).toContain('APP_PORT=');
99
- expect(result).toContain('APP_APIKEY=');
100
- expect(result).toContain('DATABASE_HOST=');
101
- expect(result).toContain('# Server port');
102
- expect(result).toContain('# API key');
103
- expect(result).toContain('# Database host');
104
- });
105
-
106
- it('should format schema as .env.example with prefix', () => {
107
- const result = formatAsEnvExample(mockSchema, 'MYAPP');
108
-
109
- expect(result).toContain('MYAPP_APP_PORT=');
110
- expect(result).toContain('MYAPP_APP_APIKEY=');
111
- expect(result).toContain('MYAPP_DATABASE_HOST=');
112
- });
113
-
114
- it('should include example values when available', () => {
115
- const result = formatAsEnvExample(mockSchema);
116
-
117
- expect(result).toContain('APP_PORT=8080');
118
- });
119
-
120
- it('should include default values when example is not available', () => {
121
- const result = formatAsEnvExample(mockSchema);
122
-
123
- expect(result).toContain('DATABASE_HOST=localhost');
124
- });
125
-
126
- it('should use placeholder for sensitive values', () => {
127
- const result = formatAsEnvExample(mockSchema);
128
-
129
- expect(result).toContain('APP_APIKEY=your-example-value');
130
- });
131
-
132
- it('should mark required fields', () => {
133
- const result = formatAsEnvExample(mockSchema);
134
-
135
- expect(result).toContain('# API key (required)');
136
- });
137
-
138
- it('should handle sections without descriptions', () => {
139
- const schemaWithoutDesc: ExportedSchema = {
140
- name: 'test',
141
- sections: [
142
- {
143
- name: 'app',
144
- elements: [
145
- {
146
- name: 'port',
147
- type: 'number',
148
- default: 3000,
149
- required: false,
150
- sensitive: false,
151
- zodValidation: {}
152
- }
153
- ]
154
- }
155
- ]
156
- };
157
-
158
- const result = formatAsEnvExample(schemaWithoutDesc);
159
- expect(result).toContain('APP_PORT=3000');
160
- });
161
-
162
- it('should handle elements without descriptions', () => {
163
- const schemaWithoutElementDesc: ExportedSchema = {
164
- name: 'test',
165
- sections: [
166
- {
167
- name: 'app',
168
- description: 'App config',
169
- elements: [
170
- {
171
- name: 'port',
172
- type: 'number',
173
- default: 3000,
174
- required: false,
175
- sensitive: false,
176
- zodValidation: {}
177
- }
178
- ]
179
- }
180
- ]
181
- };
182
-
183
- const result = formatAsEnvExample(schemaWithoutElementDesc);
184
- expect(result).toContain('# App config');
185
- expect(result).toContain('APP_PORT=3000');
186
- });
187
- });
188
- });
@@ -1,124 +0,0 @@
1
- import yaml from 'js-yaml';
2
- import { ExportedSchema, ExportedElement } from './schemaExporter.js';
3
-
4
- /**
5
- * Formats the schema as JSON string
6
- * @param schema - The schema to format
7
- * @param pretty - Whether to pretty print the JSON
8
- * @returns The configuration schema as a JSON string
9
- */
10
- export function formatAsJSON(
11
- schema: ExportedSchema,
12
- pretty: boolean = true
13
- ): string {
14
- return JSON.stringify(schema, null, pretty ? 2 : 0);
15
- }
16
-
17
- /**
18
- * Formats the schema as YAML string
19
- * @param schema - The schema to format
20
- * @returns The configuration schema as a YAML string
21
- */
22
- export function formatAsYAML(schema: ExportedSchema): string {
23
- return yaml.dump(schema, {
24
- indent: 2,
25
- lineWidth: 80,
26
- noRefs: true
27
- });
28
- }
29
-
30
- /**
31
- * Generates an environment variable name from section and element names
32
- * @param sectionName - The name of the section
33
- * @param elementName - The name of the element
34
- * @param prefix - Optional prefix for the environment variable name
35
- * @returns The environment variable name
36
- */
37
- function generateEnvVarName(
38
- sectionName: string,
39
- elementName: string,
40
- prefix?: string
41
- ): string {
42
- let name = `${sectionName}_${elementName}`.replace(/\./g, '_');
43
- if (prefix) {
44
- name = `${prefix}_${name}`;
45
- }
46
- return name.toUpperCase();
47
- }
48
-
49
- /**
50
- * Formats a value for display in .env.example file
51
- * @param element - The element to format
52
- * @returns The formatted value
53
- */
54
- function formatEnvValue(element: ExportedElement): string {
55
- if (element.sensitive) {
56
- if (element.example !== undefined) {
57
- return 'your-example-value';
58
- }
59
- return 'your-secret-value';
60
- }
61
-
62
- if (element.example !== undefined) {
63
- return String(element.example);
64
- }
65
-
66
- if (element.default !== undefined) {
67
- return String(element.default);
68
- }
69
-
70
- switch (element.type) {
71
- case 'string':
72
- return 'your-value';
73
- case 'number':
74
- return '0';
75
- case 'boolean':
76
- return 'true';
77
- case 'array':
78
- return 'value1,value2';
79
- default:
80
- return 'your-value';
81
- }
82
- }
83
-
84
- /**
85
- * Formats the schema as a .env.example file
86
- * @param schema - The exported schema
87
- * @param prefix - Optional prefix for environment variable names (e.g., 'MYAPP')
88
- * @returns The .env.example file content as a string
89
- */
90
- export function formatAsEnvExample(
91
- schema: ExportedSchema,
92
- prefix?: string
93
- ): string {
94
- const lines: string[] = [];
95
-
96
- lines.push(`# ${schema.name} Configuration`);
97
- lines.push('# Generated from schema export');
98
- lines.push('');
99
-
100
- for (const section of schema.sections) {
101
- if (section.description) {
102
- lines.push(`# ${section.description}`);
103
- }
104
-
105
- for (const element of section.elements) {
106
- const envVarName = generateEnvVarName(section.name, element.name, prefix);
107
- const value = formatEnvValue(element);
108
- const isRequired = element.required && element.default === undefined;
109
-
110
- if (element.description) {
111
- lines.push(
112
- `# ${element.description}${isRequired ? ' (required)' : ''}`
113
- );
114
- } else if (isRequired) {
115
- lines.push('# Required');
116
- }
117
-
118
- lines.push(`${envVarName}=${value}`);
119
- lines.push('');
120
- }
121
- }
122
-
123
- return lines.join('\n');
124
- }
package/tsconfig.json DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "extends": "@config-bound/typescript-config/package.tsconfig.json",
3
- "compilerOptions": {
4
- "target": "ES2024",
5
- "lib": ["ES2024"],
6
- "module": "NodeNext",
7
- "moduleResolution": "NodeNext",
8
- "outDir": "./dist",
9
- "rootDir": "./src"
10
- },
11
- "include": ["src/**/*", "src/**/*.spec.ts"]
12
- }