@config-bound/cli 0.1.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.json +6 -4
  3. package/scripts/generate-docs.ts +362 -0
  4. package/src/cli.module.ts +7 -1
  5. package/src/commands/generate-bind.command.ts +175 -0
  6. package/src/commands/generate.command.ts +13 -0
  7. package/src/services/bind-generator.service.ts +248 -0
  8. package/src/services/schema-export.service.spec.ts +3 -3
  9. package/tsconfig.json +7 -2
  10. package/.turbo/turbo-build.log +0 -4
  11. package/.turbo/turbo-format$colon$ci.log +0 -6
  12. package/.turbo/turbo-lint$colon$ci.log +0 -4
  13. package/.turbo/turbo-test.log +0 -19
  14. package/dist/cli.module.d.ts +0 -3
  15. package/dist/cli.module.d.ts.map +0 -1
  16. package/dist/cli.module.js +0 -29
  17. package/dist/cli.module.js.map +0 -1
  18. package/dist/commands/export.command.d.ts +0 -30
  19. package/dist/commands/export.command.d.ts.map +0 -1
  20. package/dist/commands/export.command.js +0 -226
  21. package/dist/commands/export.command.js.map +0 -1
  22. package/dist/commands/list.command.d.ts +0 -13
  23. package/dist/commands/list.command.d.ts.map +0 -1
  24. package/dist/commands/list.command.js +0 -93
  25. package/dist/commands/list.command.js.map +0 -1
  26. package/dist/main.d.ts +0 -3
  27. package/dist/main.d.ts.map +0 -1
  28. package/dist/main.js +0 -17
  29. package/dist/main.js.map +0 -1
  30. package/dist/services/config-discovery.service.d.ts +0 -15
  31. package/dist/services/config-discovery.service.d.ts.map +0 -1
  32. package/dist/services/config-discovery.service.js +0 -191
  33. package/dist/services/config-discovery.service.js.map +0 -1
  34. package/dist/services/config-discovery.service.spec.d.ts +0 -2
  35. package/dist/services/config-discovery.service.spec.d.ts.map +0 -1
  36. package/dist/services/config-discovery.service.spec.js +0 -137
  37. package/dist/services/config-discovery.service.spec.js.map +0 -1
  38. package/dist/services/config-loader.service.d.ts +0 -13
  39. package/dist/services/config-loader.service.d.ts.map +0 -1
  40. package/dist/services/config-loader.service.js +0 -241
  41. package/dist/services/config-loader.service.js.map +0 -1
  42. package/dist/services/file-writer.service.d.ts +0 -6
  43. package/dist/services/file-writer.service.d.ts.map +0 -1
  44. package/dist/services/file-writer.service.js +0 -38
  45. package/dist/services/file-writer.service.js.map +0 -1
  46. package/dist/services/file-writer.service.spec.d.ts +0 -2
  47. package/dist/services/file-writer.service.spec.d.ts.map +0 -1
  48. package/dist/services/file-writer.service.spec.js +0 -98
  49. package/dist/services/file-writer.service.spec.js.map +0 -1
  50. package/dist/services/schema-export.service.d.ts +0 -14
  51. package/dist/services/schema-export.service.d.ts.map +0 -1
  52. package/dist/services/schema-export.service.js +0 -58
  53. package/dist/services/schema-export.service.js.map +0 -1
  54. package/dist/services/schema-export.service.spec.d.ts +0 -2
  55. package/dist/services/schema-export.service.spec.d.ts.map +0 -1
  56. package/dist/services/schema-export.service.spec.js +0 -69
  57. package/dist/services/schema-export.service.spec.js.map +0 -1
@@ -0,0 +1,248 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import * as path from 'path';
3
+ import { FileWriterService } from './file-writer.service.js';
4
+
5
+ const DIGIT_WORDS = new Map([
6
+ ['1', 'One'],
7
+ ['2', 'Two'],
8
+ ['3', 'Three'],
9
+ ['4', 'Four'],
10
+ ['5', 'Five'],
11
+ ['6', 'Six'],
12
+ ['7', 'Seven'],
13
+ ['8', 'Eight'],
14
+ ['9', 'Nine'],
15
+ ['10', 'Ten']
16
+ ]);
17
+
18
+ function digitWordsPrefix(digits: string): string {
19
+ return DIGIT_WORDS.get(digits) ?? `N${digits}`;
20
+ }
21
+
22
+ export type BindGeneratorMode = 'package' | 'embedded';
23
+
24
+ export interface BindNames {
25
+ kebab: string;
26
+ pascal: string;
27
+ }
28
+
29
+ export interface GeneratedFile {
30
+ relativePath: string;
31
+ content: string;
32
+ }
33
+
34
+ @Injectable()
35
+ export class BindGeneratorService {
36
+ constructor(private readonly fileWriter: FileWriterService) {}
37
+
38
+ deriveNames(input: string): BindNames {
39
+ const kebab = input
40
+ .toLowerCase()
41
+ .replace(/[^a-z0-9-]/g, '-')
42
+ .replace(/-+/g, '-')
43
+ .replace(/^-|-$/g, '');
44
+
45
+ const pascal = kebab
46
+ .split('-')
47
+ .map((part) => {
48
+ // Handle numeric-leading segments (e.g. "1password" → "OnePassword")
49
+ const withoutLeadingDigits = part.replace(/^\d+/, digitWordsPrefix);
50
+ return (
51
+ withoutLeadingDigits.charAt(0).toUpperCase() +
52
+ withoutLeadingDigits.slice(1)
53
+ );
54
+ })
55
+ .join('');
56
+
57
+ return { kebab, pascal };
58
+ }
59
+
60
+ renderFiles(names: BindNames, mode: BindGeneratorMode): GeneratedFile[] {
61
+ if (mode === 'embedded') {
62
+ return [
63
+ {
64
+ relativePath: `${names.pascal}Bind.ts`,
65
+ content: this.renderBindClass(names)
66
+ }
67
+ ];
68
+ }
69
+
70
+ const packageDir = `bind-${names.kebab}`;
71
+ return [
72
+ {
73
+ relativePath: path.join(packageDir, 'src', `${names.pascal}Bind.ts`),
74
+ content: this.renderBindClass(names)
75
+ },
76
+ {
77
+ relativePath: path.join(packageDir, 'src', 'index.ts'),
78
+ content: this.renderIndex(names)
79
+ },
80
+ {
81
+ relativePath: path.join(packageDir, 'package.json'),
82
+ content: this.renderPackageJson(names)
83
+ },
84
+ {
85
+ relativePath: path.join(packageDir, 'tsconfig.json'),
86
+ content: this.renderTsConfig()
87
+ },
88
+ {
89
+ relativePath: path.join(packageDir, 'eslint.config.mjs'),
90
+ content: this.renderEslintConfig()
91
+ }
92
+ ];
93
+ }
94
+
95
+ writeFiles(files: GeneratedFile[], outputDir: string): void {
96
+ for (const file of files) {
97
+ const fullPath = path.join(outputDir, file.relativePath);
98
+ this.fileWriter.writeToFile(fullPath, file.content);
99
+ }
100
+ }
101
+
102
+ private renderBindClass(names: BindNames): string {
103
+ return `import { Bind } from '@config-bound/config-bound/bind';
104
+
105
+ /**
106
+ * Options for constructing a ${names.pascal}Bind.
107
+ * Add the SDK client / credential options for ${names.pascal} here.
108
+ */
109
+ export interface ${names.pascal}BindOptions {
110
+ // e.g. token?: string; endpoint?: string;
111
+ }
112
+
113
+ /**
114
+ * A {@link Bind} that retrieves values from ${names.pascal}.
115
+ *
116
+ * Uses a static factory method ({@link ${names.pascal}Bind.create}) to pre-load all values
117
+ * into an in-memory map at startup, so that {@link ${names.pascal}Bind.retrieve} reads
118
+ * from memory without making additional network calls.
119
+ *
120
+ * @example
121
+ * \`\`\`typescript
122
+ * const bind = await ${names.pascal}Bind.create({ token: process.env.${names.kebab.toUpperCase().replace(/-/g, '_')}_TOKEN });
123
+ * const config = ConfigBound.createConfig(schema, { binds: [bind] });
124
+ * \`\`\`
125
+ */
126
+ export class ${names.pascal}Bind extends Bind {
127
+ private readonly values: Map<string, unknown>;
128
+
129
+ private constructor(values: Map<string, unknown>) {
130
+ super('${names.pascal}');
131
+ this.values = values;
132
+ }
133
+
134
+ /**
135
+ * Creates a ${names.pascal}Bind by pre-loading values from the source.
136
+ *
137
+ * Call this once at application startup and pass the returned instance to
138
+ * \`ConfigBound.createConfig\`.
139
+ */
140
+ static async create(_options: ${names.pascal}BindOptions): Promise<${names.pascal}Bind> {
141
+ const values = new Map<string, unknown>();
142
+
143
+ // TODO: Initialize the SDK client using \`options\`, fetch values, and
144
+ // populate \`values\` with entries keyed by the full element path
145
+ // (format: "sectionName.elementName"). For example:
146
+ //
147
+ // const client = new SdkClient(options);
148
+ // const secrets = await client.listValues();
149
+ // for (const secret of secrets) {
150
+ // values.set(secret.path, secret.data);
151
+ // }
152
+ return new ${names.pascal}Bind(values);
153
+ }
154
+
155
+ async retrieve<T>(elementName: string): Promise<T | undefined> {
156
+ return this.values.get(elementName) as T | undefined;
157
+ }
158
+ }
159
+ `;
160
+ }
161
+
162
+ private renderIndex(names: BindNames): string {
163
+ return `export { ${names.pascal}Bind, type ${names.pascal}BindOptions } from './${names.pascal}Bind.js';
164
+ `;
165
+ }
166
+
167
+ private renderPackageJson(names: BindNames): string {
168
+ return `{
169
+ "name": "configbound-bind-${names.kebab}",
170
+ "version": "0.1.0",
171
+ "description": "${names.pascal} bind for ConfigBound",
172
+ "private": true,
173
+ "main": "./dist/index.js",
174
+ "types": "./dist/index.d.ts",
175
+ "exports": {
176
+ ".": {
177
+ "types": "./dist/index.d.ts",
178
+ "require": "./dist/index.js",
179
+ "import": "./dist/index.js"
180
+ }
181
+ },
182
+ "scripts": {
183
+ "build": "tsc",
184
+ "clean": "rimraf dist",
185
+ "test": "jest",
186
+ "lint": "eslint src/**/*.ts --fix",
187
+ "lint:ci": "eslint src/**/*.ts",
188
+ "format": "prettier --write src/**/*.ts",
189
+ "format:ci": "prettier --check src/**/*.ts"
190
+ },
191
+ "keywords": ["configbound", "config", "${names.kebab}"],
192
+ "license": "MIT",
193
+ "dependencies": {
194
+ "@config-bound/config-bound": "^0.1.0"
195
+ },
196
+ "devDependencies": {
197
+ "@eslint/js": "^9.0.0",
198
+ "@types/jest": "^30.0.0",
199
+ "@types/node": "^24.0.0",
200
+ "eslint": "^9.0.0",
201
+ "jest": "^30.0.0",
202
+ "rimraf": "^6.0.0",
203
+ "ts-jest": "^29.0.0",
204
+ "typescript": "^6.0.0",
205
+ "typescript-eslint": "^8.0.0"
206
+ },
207
+ "publishConfig": {
208
+ "access": "public",
209
+ "registry": "https://registry.npmjs.org"
210
+ }
211
+ }
212
+ `;
213
+ }
214
+
215
+ private renderTsConfig(): string {
216
+ return `{
217
+ "compilerOptions": {
218
+ "target": "ES2022",
219
+ "module": "NodeNext",
220
+ "moduleResolution": "NodeNext",
221
+ "lib": ["ES2022"],
222
+ "outDir": "./dist",
223
+ "rootDir": "./src",
224
+ "strict": true,
225
+ "esModuleInterop": true,
226
+ "skipLibCheck": true,
227
+ "declaration": true,
228
+ "declarationMap": true,
229
+ "sourceMap": true
230
+ },
231
+ "include": ["src/**/*"],
232
+ "exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
233
+ }
234
+ `;
235
+ }
236
+
237
+ private renderEslintConfig(): string {
238
+ return `import js from '@eslint/js';
239
+ import tseslint from 'typescript-eslint';
240
+
241
+ export default [
242
+ { ignores: ['**/dist/**', '**/node_modules/**'] },
243
+ js.configs.recommended,
244
+ ...tseslint.configs.recommended,
245
+ ];
246
+ `;
247
+ }
248
+ }
@@ -4,7 +4,7 @@ import { describe, beforeEach, it, expect } from '@jest/globals';
4
4
  import { ConfigBound } from '@config-bound/config-bound';
5
5
  import { Section } from '@config-bound/config-bound/section';
6
6
  import { Element } from '@config-bound/config-bound/element';
7
- import Joi from 'joi';
7
+ import { z } from 'zod';
8
8
 
9
9
  describe('SchemaExportService', () => {
10
10
  let service: SchemaExportService;
@@ -25,7 +25,7 @@ describe('SchemaExportService', () => {
25
25
  undefined,
26
26
  false,
27
27
  false,
28
- Joi.string()
28
+ z.string()
29
29
  );
30
30
 
31
31
  const portElement = new Element<number>(
@@ -35,7 +35,7 @@ describe('SchemaExportService', () => {
35
35
  undefined,
36
36
  false,
37
37
  false,
38
- Joi.number()
38
+ z.number()
39
39
  );
40
40
 
41
41
  const databaseSection = new Section(
package/tsconfig.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
- "extends": "@config-bound/typescript-config/cli.tsconfig.json",
2
+ "extends": "@config-bound/typescript-config/base.tsconfig.json",
3
3
  "compilerOptions": {
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
4
6
  "outDir": "./dist",
5
7
  "rootDir": "./src",
8
+ "removeComments": true,
9
+ "emitDecoratorMetadata": true,
10
+ "experimentalDecorators": true,
6
11
  "types": ["node", "jest"]
7
12
  },
8
13
  "include": ["src/**/*"],
9
- "exclude": ["node_modules", "dist"]
14
+ "exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
10
15
  }
@@ -1,4 +0,0 @@
1
-
2
- > @config-bound/cli@0.1.0 build
3
- > tsc
4
-
@@ -1,6 +0,0 @@
1
-
2
- > @config-bound/cli@0.1.0 format:ci
3
- > prettier --check --config ../../.config/.prettierrc --ignore-path ../../.config/.prettierignore src/**/*.ts
4
-
5
- Checking formatting...
6
- All matched files use Prettier code style!
@@ -1,4 +0,0 @@
1
-
2
- > @config-bound/cli@0.1.0 lint:ci
3
- > eslint src/**/*.ts
4
-
@@ -1,19 +0,0 @@
1
-
2
- > @config-bound/cli@0.1.0 test
3
- > NODE_OPTIONS='--experimental-vm-modules' jest
4
-
5
- (node:2957) ExperimentalWarning: VM Modules is an experimental feature and might change at any time
6
- (Use `node --trace-warnings ...` to show where the warning was created)
7
- PASS src/services/file-writer.service.spec.ts
8
- (node:2959) ExperimentalWarning: VM Modules is an experimental feature and might change at any time
9
- (Use `node --trace-warnings ...` to show where the warning was created)
10
- PASS src/services/schema-export.service.spec.ts
11
- (node:2956) ExperimentalWarning: VM Modules is an experimental feature and might change at any time
12
- (Use `node --trace-warnings ...` to show where the warning was created)
13
- PASS src/services/config-discovery.service.spec.ts (17.134 s)
14
-
15
- Test Suites: 3 passed, 3 total
16
- Tests: 27 passed, 27 total
17
- Snapshots: 0 total
18
- Time: 18.949 s
19
- Ran all test suites.
@@ -1,3 +0,0 @@
1
- export declare class CliModule {
2
- }
3
- //# sourceMappingURL=cli.module.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.module.d.ts","sourceRoot":"","sources":["../src/cli.module.ts"],"names":[],"mappings":"AAQA,qBAUa,SAAS;CAAG"}
@@ -1,29 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { Module } from '@nestjs/common';
8
- import { ListCommand } from './commands/list.command.js';
9
- import { ExportCommand } from './commands/export.command.js';
10
- import { ConfigDiscoveryService } from './services/config-discovery.service.js';
11
- import { ConfigLoaderService } from './services/config-loader.service.js';
12
- import { SchemaExportService } from './services/schema-export.service.js';
13
- import { FileWriterService } from './services/file-writer.service.js';
14
- let CliModule = class CliModule {
15
- };
16
- CliModule = __decorate([
17
- Module({
18
- providers: [
19
- ListCommand,
20
- ExportCommand,
21
- ConfigDiscoveryService,
22
- ConfigLoaderService,
23
- SchemaExportService,
24
- FileWriterService
25
- ]
26
- })
27
- ], CliModule);
28
- export { CliModule };
29
- //# sourceMappingURL=cli.module.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.module.js","sourceRoot":"","sources":["../src/cli.module.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAY/D,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,SAAS;IAVrB,MAAM,CAAC;QACN,SAAS,EAAE;YACT,WAAW;YACX,aAAa;YACb,sBAAsB;YACtB,mBAAmB;YACnB,mBAAmB;YACnB,iBAAiB;SAClB;KACF,CAAC;GACW,SAAS,CAAG"}
@@ -1,30 +0,0 @@
1
- import { CommandRunner } from 'nest-commander';
2
- import { ConfigLoaderService } from '../services/config-loader.service.js';
3
- import { ConfigDiscoveryService } from '../services/config-discovery.service.js';
4
- import { SchemaExportService, type ExportFormat } from '../services/schema-export.service.js';
5
- import { FileWriterService } from '../services/file-writer.service.js';
6
- interface ExportCommandOptions {
7
- config?: string;
8
- format: ExportFormat;
9
- output?: string;
10
- includeOmitted?: boolean;
11
- pretty?: boolean;
12
- name?: string;
13
- }
14
- export declare class ExportCommand extends CommandRunner {
15
- private readonly loaderService;
16
- private readonly discoveryService;
17
- private readonly exportService;
18
- private readonly writerService;
19
- constructor(loaderService: ConfigLoaderService, discoveryService: ConfigDiscoveryService, exportService: SchemaExportService, writerService: FileWriterService);
20
- run(_passedParams: string[], options?: ExportCommandOptions): Promise<void>;
21
- private discoverAndSelect;
22
- parseConfig(val: string): string;
23
- parseFormat(val: string): ExportFormat;
24
- parseOutput(val: string): string;
25
- parseIncludeOmitted(): boolean;
26
- parsePretty(val: string): boolean;
27
- parseName(val: string): string;
28
- }
29
- export {};
30
- //# sourceMappingURL=export.command.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"export.command.d.ts","sourceRoot":"","sources":["../../src/commands/export.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EACL,mBAAmB,EACnB,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAIvE,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAIa,aAAc,SAAQ,aAAa;IAE5C,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAHb,aAAa,EAAE,mBAAmB,EAClC,gBAAgB,EAAE,sBAAsB,EACxC,aAAa,EAAE,mBAAmB,EAClC,aAAa,EAAE,iBAAiB;IAK7C,GAAG,CACP,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,IAAI,CAAC;YAgEF,iBAAiB;IAoG/B,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAShC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY;IActC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAQhC,mBAAmB,IAAI,OAAO;IAS9B,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAQjC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAG/B"}
@@ -1,226 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- var __metadata = (this && this.__metadata) || function (k, v) {
8
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
- };
10
- import { Command, CommandRunner, Option } from 'nest-commander';
11
- import { ConfigLoaderService } from '../services/config-loader.service.js';
12
- import { ConfigDiscoveryService } from '../services/config-discovery.service.js';
13
- import { SchemaExportService } from '../services/schema-export.service.js';
14
- import { FileWriterService } from '../services/file-writer.service.js';
15
- import chalk from 'chalk';
16
- import * as readline from 'readline';
17
- let ExportCommand = class ExportCommand extends CommandRunner {
18
- loaderService;
19
- discoveryService;
20
- exportService;
21
- writerService;
22
- constructor(loaderService, discoveryService, exportService, writerService) {
23
- super();
24
- this.loaderService = loaderService;
25
- this.discoveryService = discoveryService;
26
- this.exportService = exportService;
27
- this.writerService = writerService;
28
- }
29
- async run(_passedParams, options) {
30
- try {
31
- let configPath;
32
- let exportName;
33
- if (!options?.config) {
34
- const discovered = await this.discoverAndSelect();
35
- if (!discovered) {
36
- console.log(chalk.yellow('Export cancelled.'));
37
- return;
38
- }
39
- configPath = discovered.filePath;
40
- exportName =
41
- discovered.exportName === 'default'
42
- ? undefined
43
- : discovered.exportName;
44
- }
45
- else {
46
- configPath = options.config;
47
- exportName = options.name;
48
- }
49
- const format = options?.format || 'json';
50
- const includeOmitted = options?.includeOmitted || false;
51
- const pretty = options?.pretty !== false;
52
- const output = options?.output;
53
- console.log(chalk.blue('Loading configuration...'));
54
- const config = await this.loaderService.loadConfig(configPath, exportName);
55
- console.log(chalk.green(`Loaded config: ${chalk.bold(config.name)}`));
56
- const exportedSchema = this.exportService.exportToString(config.name, config.sections, config.instance, {
57
- format,
58
- includeOmitted,
59
- pretty
60
- });
61
- if (output) {
62
- this.writerService.writeToFile(output, exportedSchema);
63
- console.log(chalk.green(`Schema exported to: ${output}`));
64
- }
65
- else {
66
- console.log(chalk.blue('\nExported schema:\n'));
67
- this.writerService.writeToStdout(exportedSchema);
68
- }
69
- }
70
- catch (error) {
71
- if (error instanceof Error) {
72
- console.error(chalk.red(`Error: ${error.message}`));
73
- }
74
- else {
75
- console.error(chalk.red(`Error: ${String(error)}`));
76
- }
77
- process.exit(1);
78
- }
79
- }
80
- async discoverAndSelect() {
81
- const startTime = Date.now();
82
- console.log(chalk.blue('Searching for ConfigBound configurations...'));
83
- const configs = await this.discoveryService.discoverConfigs(process.cwd(), true);
84
- const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
85
- console.log(chalk.gray(`Search completed in ${elapsed}s`));
86
- if (configs.length === 0) {
87
- console.log(chalk.yellow('\nNo ConfigBound configurations found in project.'));
88
- console.log(chalk.gray('Tip: Use --config <path> to specify a config file explicitly.'));
89
- return null;
90
- }
91
- if (configs.length === 1) {
92
- const selected = configs[0];
93
- const exportType = selected.isDefault ? 'default' : 'named';
94
- const relativePath = selected.filePath.replace(process.cwd() + '/', '');
95
- console.log(chalk.green(`\nFound 1 configuration - auto-selected: ${chalk.bold(selected.configName || 'unnamed')} (${exportType} export: ${selected.exportName})`));
96
- console.log(chalk.gray(` from ${relativePath}\n`));
97
- return {
98
- filePath: selected.filePath,
99
- exportName: selected.exportName
100
- };
101
- }
102
- console.log(chalk.green(`\nFound ${configs.length} configurations:\n`));
103
- configs.forEach((config, index) => {
104
- const exportType = config.isDefault ? '(default)' : '(named)';
105
- const configNamePart = config.configName
106
- ? chalk.bold(config.configName)
107
- : chalk.gray('unnamed');
108
- const relativePath = config.filePath.replace(process.cwd() + '/', '');
109
- console.log(`${chalk.cyan((index + 1).toString().padStart(2))}. ${configNamePart} ${chalk.gray(exportType + ' - ' + config.exportName)}`);
110
- console.log(` ${chalk.gray(relativePath)}`);
111
- });
112
- const rl = readline.createInterface({
113
- input: process.stdin,
114
- output: process.stdout
115
- });
116
- const answer = await new Promise((resolve) => {
117
- rl.question(chalk.yellow(`\nSelect configuration (1-${configs.length}) or Ctrl+C to cancel: `), (answer) => {
118
- rl.close();
119
- resolve(answer);
120
- });
121
- });
122
- const selectedIndex = parseInt(answer, 10) - 1;
123
- if (isNaN(selectedIndex) ||
124
- selectedIndex < 0 ||
125
- selectedIndex >= configs.length) {
126
- console.log(chalk.red('Invalid selection.'));
127
- return null;
128
- }
129
- const selected = configs[selectedIndex];
130
- console.log();
131
- return {
132
- filePath: selected.filePath,
133
- exportName: selected.exportName
134
- };
135
- }
136
- parseConfig(val) {
137
- return val;
138
- }
139
- parseFormat(val) {
140
- const validFormats = ['json', 'yaml', 'env'];
141
- if (!validFormats.includes(val)) {
142
- throw new Error(`Invalid format: ${val}. Valid formats: ${validFormats.join(', ')}`);
143
- }
144
- return val;
145
- }
146
- parseOutput(val) {
147
- return val;
148
- }
149
- parseIncludeOmitted() {
150
- return true;
151
- }
152
- parsePretty(val) {
153
- return val !== 'false';
154
- }
155
- parseName(val) {
156
- return val;
157
- }
158
- };
159
- __decorate([
160
- Option({
161
- flags: '-c, --config <path>',
162
- description: 'Path to config file'
163
- }),
164
- __metadata("design:type", Function),
165
- __metadata("design:paramtypes", [String]),
166
- __metadata("design:returntype", String)
167
- ], ExportCommand.prototype, "parseConfig", null);
168
- __decorate([
169
- Option({
170
- flags: '-f, --format <format>',
171
- description: 'Output format: json, yaml, env (default: json)',
172
- defaultValue: 'json'
173
- }),
174
- __metadata("design:type", Function),
175
- __metadata("design:paramtypes", [String]),
176
- __metadata("design:returntype", String)
177
- ], ExportCommand.prototype, "parseFormat", null);
178
- __decorate([
179
- Option({
180
- flags: '-o, --output <path>',
181
- description: 'Output file path (default: stdout)'
182
- }),
183
- __metadata("design:type", Function),
184
- __metadata("design:paramtypes", [String]),
185
- __metadata("design:returntype", String)
186
- ], ExportCommand.prototype, "parseOutput", null);
187
- __decorate([
188
- Option({
189
- flags: '--include-omitted',
190
- description: 'Include elements marked with omitFromSchema: true'
191
- }),
192
- __metadata("design:type", Function),
193
- __metadata("design:paramtypes", []),
194
- __metadata("design:returntype", Boolean)
195
- ], ExportCommand.prototype, "parseIncludeOmitted", null);
196
- __decorate([
197
- Option({
198
- flags: '--pretty [boolean]',
199
- description: 'Pretty-print JSON output (default: true)',
200
- defaultValue: true
201
- }),
202
- __metadata("design:type", Function),
203
- __metadata("design:paramtypes", [String]),
204
- __metadata("design:returntype", Boolean)
205
- ], ExportCommand.prototype, "parsePretty", null);
206
- __decorate([
207
- Option({
208
- flags: '--name <name>',
209
- description: 'Export named variable when file has multiple exports'
210
- }),
211
- __metadata("design:type", Function),
212
- __metadata("design:paramtypes", [String]),
213
- __metadata("design:returntype", String)
214
- ], ExportCommand.prototype, "parseName", null);
215
- ExportCommand = __decorate([
216
- Command({
217
- name: 'export',
218
- description: 'Export ConfigBound schema in various formats'
219
- }),
220
- __metadata("design:paramtypes", [ConfigLoaderService,
221
- ConfigDiscoveryService,
222
- SchemaExportService,
223
- FileWriterService])
224
- ], ExportCommand);
225
- export { ExportCommand };
226
- //# sourceMappingURL=export.command.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"export.command.js","sourceRoot":"","sources":["../../src/commands/export.command.ts"],"names":[],"mappings":"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"}
@@ -1,13 +0,0 @@
1
- import { CommandRunner } from 'nest-commander';
2
- import { ConfigDiscoveryService } from '../services/config-discovery.service.js';
3
- interface ListCommandOptions {
4
- recursive?: boolean;
5
- }
6
- export declare class ListCommand extends CommandRunner {
7
- private readonly discoveryService;
8
- constructor(discoveryService: ConfigDiscoveryService);
9
- run(passedParams: string[], options?: ListCommandOptions): Promise<void>;
10
- parseRecursive(val: string): boolean;
11
- }
12
- export {};
13
- //# sourceMappingURL=list.command.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"list.command.d.ts","sourceRoot":"","sources":["../../src/commands/list.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAIjF,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,qBAQa,WAAY,SAAQ,aAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,sBAAsB;IAI/D,GAAG,CACP,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,IAAI,CAAC;IA+EhB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAGrC"}