schemantic 0.1.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 (131) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/LICENSE +21 -0
  3. package/README.md +827 -0
  4. package/dist/__tests__/setup.d.ts +6 -0
  5. package/dist/__tests__/setup.d.ts.map +1 -0
  6. package/dist/__tests__/setup.js +30 -0
  7. package/dist/__tests__/setup.js.map +1 -0
  8. package/dist/__tests__/test-config.d.ts +36 -0
  9. package/dist/__tests__/test-config.d.ts.map +1 -0
  10. package/dist/__tests__/test-config.js +563 -0
  11. package/dist/__tests__/test-config.js.map +1 -0
  12. package/dist/cli/index.d.ts +118 -0
  13. package/dist/cli/index.d.ts.map +1 -0
  14. package/dist/cli/index.js +657 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/core/index.d.ts +5 -0
  17. package/dist/core/index.d.ts.map +1 -0
  18. package/dist/core/index.js +21 -0
  19. package/dist/core/index.js.map +1 -0
  20. package/dist/core/schemantic.d.ts +95 -0
  21. package/dist/core/schemantic.d.ts.map +1 -0
  22. package/dist/core/schemantic.js +543 -0
  23. package/dist/core/schemantic.js.map +1 -0
  24. package/dist/generators/api-client-generator.d.ts +145 -0
  25. package/dist/generators/api-client-generator.d.ts.map +1 -0
  26. package/dist/generators/api-client-generator.js +856 -0
  27. package/dist/generators/api-client-generator.js.map +1 -0
  28. package/dist/generators/base.d.ts +117 -0
  29. package/dist/generators/base.d.ts.map +1 -0
  30. package/dist/generators/base.js +232 -0
  31. package/dist/generators/base.js.map +1 -0
  32. package/dist/generators/enum-generator.d.ts +52 -0
  33. package/dist/generators/enum-generator.d.ts.map +1 -0
  34. package/dist/generators/enum-generator.js +178 -0
  35. package/dist/generators/enum-generator.js.map +1 -0
  36. package/dist/generators/factory.d.ts +59 -0
  37. package/dist/generators/factory.d.ts.map +1 -0
  38. package/dist/generators/factory.js +127 -0
  39. package/dist/generators/factory.js.map +1 -0
  40. package/dist/generators/hook-generator.d.ts +36 -0
  41. package/dist/generators/hook-generator.d.ts.map +1 -0
  42. package/dist/generators/hook-generator.js +495 -0
  43. package/dist/generators/hook-generator.js.map +1 -0
  44. package/dist/generators/index.d.ts +10 -0
  45. package/dist/generators/index.d.ts.map +1 -0
  46. package/dist/generators/index.js +26 -0
  47. package/dist/generators/index.js.map +1 -0
  48. package/dist/generators/object-generator.d.ts +48 -0
  49. package/dist/generators/object-generator.d.ts.map +1 -0
  50. package/dist/generators/object-generator.js +280 -0
  51. package/dist/generators/object-generator.js.map +1 -0
  52. package/dist/generators/primitive-generator.d.ts +40 -0
  53. package/dist/generators/primitive-generator.d.ts.map +1 -0
  54. package/dist/generators/primitive-generator.js +150 -0
  55. package/dist/generators/primitive-generator.js.map +1 -0
  56. package/dist/index.d.ts +17 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +42 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/parsers/base.d.ts +101 -0
  61. package/dist/parsers/base.d.ts.map +1 -0
  62. package/dist/parsers/base.js +77 -0
  63. package/dist/parsers/base.js.map +1 -0
  64. package/dist/parsers/factory.d.ts +64 -0
  65. package/dist/parsers/factory.d.ts.map +1 -0
  66. package/dist/parsers/factory.js +116 -0
  67. package/dist/parsers/factory.js.map +1 -0
  68. package/dist/parsers/index.d.ts +7 -0
  69. package/dist/parsers/index.d.ts.map +1 -0
  70. package/dist/parsers/index.js +23 -0
  71. package/dist/parsers/index.js.map +1 -0
  72. package/dist/parsers/openapi.d.ts +52 -0
  73. package/dist/parsers/openapi.d.ts.map +1 -0
  74. package/dist/parsers/openapi.js +396 -0
  75. package/dist/parsers/openapi.js.map +1 -0
  76. package/dist/plugins/branded-types.d.ts +28 -0
  77. package/dist/plugins/branded-types.d.ts.map +1 -0
  78. package/dist/plugins/branded-types.js +568 -0
  79. package/dist/plugins/branded-types.js.map +1 -0
  80. package/dist/plugins/builtin.d.ts +38 -0
  81. package/dist/plugins/builtin.d.ts.map +1 -0
  82. package/dist/plugins/builtin.js +283 -0
  83. package/dist/plugins/builtin.js.map +1 -0
  84. package/dist/plugins/index.d.ts +7 -0
  85. package/dist/plugins/index.d.ts.map +1 -0
  86. package/dist/plugins/index.js +23 -0
  87. package/dist/plugins/index.js.map +1 -0
  88. package/dist/plugins/loader.d.ts +92 -0
  89. package/dist/plugins/loader.d.ts.map +1 -0
  90. package/dist/plugins/loader.js +245 -0
  91. package/dist/plugins/loader.js.map +1 -0
  92. package/dist/plugins/manager.d.ts +99 -0
  93. package/dist/plugins/manager.d.ts.map +1 -0
  94. package/dist/plugins/manager.js +233 -0
  95. package/dist/plugins/manager.js.map +1 -0
  96. package/dist/plugins/performance-monitoring.d.ts +98 -0
  97. package/dist/plugins/performance-monitoring.d.ts.map +1 -0
  98. package/dist/plugins/performance-monitoring.js +596 -0
  99. package/dist/plugins/performance-monitoring.js.map +1 -0
  100. package/dist/plugins/request-deduplication.d.ts +27 -0
  101. package/dist/plugins/request-deduplication.d.ts.map +1 -0
  102. package/dist/plugins/request-deduplication.js +650 -0
  103. package/dist/plugins/request-deduplication.js.map +1 -0
  104. package/dist/plugins/zod-validation.d.ts +63 -0
  105. package/dist/plugins/zod-validation.d.ts.map +1 -0
  106. package/dist/plugins/zod-validation.js +743 -0
  107. package/dist/plugins/zod-validation.js.map +1 -0
  108. package/dist/types/core.d.ts +203 -0
  109. package/dist/types/core.d.ts.map +1 -0
  110. package/dist/types/core.js +24 -0
  111. package/dist/types/core.js.map +1 -0
  112. package/dist/types/index.d.ts +7 -0
  113. package/dist/types/index.d.ts.map +1 -0
  114. package/dist/types/index.js +23 -0
  115. package/dist/types/index.js.map +1 -0
  116. package/dist/types/openapi.d.ts +250 -0
  117. package/dist/types/openapi.d.ts.map +1 -0
  118. package/dist/types/openapi.js +8 -0
  119. package/dist/types/openapi.js.map +1 -0
  120. package/dist/types/schema.d.ts +68 -0
  121. package/dist/types/schema.d.ts.map +1 -0
  122. package/dist/types/schema.js +22 -0
  123. package/dist/types/schema.js.map +1 -0
  124. package/docs/ADVANCED_PLUGINS_IMPLEMENTATION.md +355 -0
  125. package/docs/ADVANCED_PLUGIN_DEVELOPMENT.md +309 -0
  126. package/docs/API.md +600 -0
  127. package/docs/CONFIGURATION.md +722 -0
  128. package/docs/FASTAPI_TUTORIAL.md +1497 -0
  129. package/docs/PLUGINS.md +683 -0
  130. package/docs/PLUGIN_DEVELOPMENT.md +720 -0
  131. package/package.json +90 -0
@@ -0,0 +1,657 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * CLI interface for schemantic
5
+ * Provides command-line interface for generating TypeScript types and API clients
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.cli = exports.SchemanticCli = void 0;
42
+ const commander_1 = require("commander");
43
+ const core_1 = require("../types/core");
44
+ const schemantic_1 = require("../core/schemantic");
45
+ const plugins_1 = require("../plugins");
46
+ const builtin_1 = require("../plugins/builtin");
47
+ const readline = __importStar(require("readline"));
48
+ /**
49
+ * Main CLI class
50
+ */
51
+ class SchemanticCli {
52
+ constructor() {
53
+ this.program = new commander_1.Command();
54
+ this.setupProgram();
55
+ }
56
+ /**
57
+ * Setup the CLI program
58
+ */
59
+ setupProgram() {
60
+ this.program
61
+ .name("schemantic")
62
+ .description("Generate TypeScript types and API clients from OpenAPI schemas")
63
+ .version("1.0.0")
64
+ .option("-i, --interactive", "Run in interactive mode")
65
+ .option("-v, --verbose", "Verbose output")
66
+ .option("-q, --quiet", "Quiet output")
67
+ .option("--no-color", "Disable colored output");
68
+ // Add commands
69
+ this.addGenerateCommand();
70
+ this.addValidateCommand();
71
+ this.addPluginCommand();
72
+ this.addInitCommand();
73
+ this.addHelpCommand();
74
+ }
75
+ /**
76
+ * Add generate command
77
+ */
78
+ addGenerateCommand() {
79
+ this.program
80
+ .command("generate [source]")
81
+ .alias("gen")
82
+ .description("Generate TypeScript types and API client from OpenAPI schema")
83
+ .option("-u, --url <url>", "OpenAPI schema URL")
84
+ .option("-f, --file <file>", "OpenAPI schema file path")
85
+ .option("-o, --output <dir>", "Output directory", "./src/generated")
86
+ .option("--types", "Generate types only")
87
+ .option("--client", "Generate API client only")
88
+ .option("--hooks", "Generate React hooks")
89
+ .option("--strict", "Use strict TypeScript types", true)
90
+ .option("--naming <convention>", "Naming convention (camelCase|snake_case|PascalCase)", "camelCase")
91
+ .option("--prefix <prefix>", "Type name prefix", "API")
92
+ .option("--suffix <suffix>", "Type name suffix", "")
93
+ .option("--exclude-paths <paths>", "Exclude paths (comma-separated)")
94
+ .option("--include-paths <paths>", "Include paths (comma-separated)")
95
+ .option("--exclude-schemas <schemas>", "Exclude schemas (comma-separated)")
96
+ .option("--include-schemas <schemas>", "Include schemas (comma-separated)")
97
+ .option("--plugins <plugins>", "Enable plugins (comma-separated)")
98
+ .option("-c, --config <file>", "Configuration file path")
99
+ .option("--watch", "Watch for changes and regenerate")
100
+ .action(async (source, options) => {
101
+ await this.handleGenerateCommand(source, options);
102
+ });
103
+ }
104
+ /**
105
+ * Add validate command
106
+ */
107
+ addValidateCommand() {
108
+ this.program
109
+ .command("validate [source]")
110
+ .alias("check")
111
+ .description("Validate OpenAPI schema")
112
+ .option("-u, --url <url>", "OpenAPI schema URL")
113
+ .option("-f, --file <file>", "OpenAPI schema file path")
114
+ .option("--fix", "Attempt to fix common issues")
115
+ .action(async (source, options) => {
116
+ await this.handleValidateCommand(source, options);
117
+ });
118
+ }
119
+ /**
120
+ * Add plugin command
121
+ */
122
+ addPluginCommand() {
123
+ const pluginCommand = this.program
124
+ .command("plugin")
125
+ .alias("plugins")
126
+ .description("Manage plugins");
127
+ pluginCommand
128
+ .command("list")
129
+ .alias("ls")
130
+ .description("List available plugins")
131
+ .action(async () => {
132
+ await this.handlePluginListCommand();
133
+ });
134
+ pluginCommand
135
+ .command("load <path>")
136
+ .description("Load plugin from file or package")
137
+ .action(async (path) => {
138
+ await this.handlePluginLoadCommand(path);
139
+ });
140
+ }
141
+ /**
142
+ * Add init command
143
+ */
144
+ addInitCommand() {
145
+ this.program
146
+ .command("init [directory]")
147
+ .description("Initialize a new schemantic configuration")
148
+ .option("-t, --template <template>", "Configuration template", "default")
149
+ .option("--yes", "Skip interactive prompts")
150
+ .action(async (directory, options) => {
151
+ await this.handleInitCommand(directory, options);
152
+ });
153
+ }
154
+ /**
155
+ * Add help command
156
+ */
157
+ addHelpCommand() {
158
+ this.program
159
+ .command("help [command]")
160
+ .description("Display help for a specific command")
161
+ .action((command) => {
162
+ this.handleHelpCommand(command);
163
+ });
164
+ }
165
+ /**
166
+ * Handle generate command
167
+ */
168
+ async handleGenerateCommand(source, options = {}) {
169
+ try {
170
+ // Check for interactive mode
171
+ const globalOptions = this.program.opts();
172
+ if (globalOptions.interactive) {
173
+ await this.runInteractiveMode();
174
+ return;
175
+ }
176
+ // Load configuration
177
+ const config = await this.loadConfiguration(source, options);
178
+ // Create Schemantic instance
179
+ const schemanticInstance = new schemantic_1.Schemantic(config);
180
+ // Load plugins
181
+ await this.loadPlugins(config, schemanticInstance);
182
+ // Generate types and client
183
+ const result = await schemanticInstance.generate();
184
+ // Output results
185
+ this.outputResults(result, options);
186
+ }
187
+ catch (error) {
188
+ this.handleError(error, options);
189
+ }
190
+ }
191
+ /**
192
+ * Handle validate command
193
+ */
194
+ async handleValidateCommand(source, options = {}) {
195
+ try {
196
+ // Load configuration
197
+ const config = await this.loadConfiguration(source, options);
198
+ // Create Schemantic instance
199
+ const schemanticInstance = new schemantic_1.Schemantic(config);
200
+ // Validate schema
201
+ const result = await schemanticInstance.validate();
202
+ // Output validation results
203
+ this.outputValidationResults(result, options);
204
+ }
205
+ catch (error) {
206
+ this.handleError(error, options);
207
+ }
208
+ }
209
+ /**
210
+ * Handle init command
211
+ */
212
+ async handleInitCommand(directory, options = {}) {
213
+ try {
214
+ const targetDir = directory || process.cwd();
215
+ if (options.yes) {
216
+ await this.createDefaultConfig(targetDir);
217
+ }
218
+ else {
219
+ await this.runInitInteractive(targetDir, options);
220
+ }
221
+ }
222
+ catch (error) {
223
+ this.handleError(error, options);
224
+ }
225
+ }
226
+ /**
227
+ * Handle plugin list command
228
+ */
229
+ async handlePluginListCommand() {
230
+ try {
231
+ const builtinPlugins = (0, builtin_1.getBuiltinPlugins)();
232
+ console.log("Built-in plugins:");
233
+ for (const plugin of builtinPlugins) {
234
+ console.log(` ${plugin.name} (${plugin.version}) - ${plugin.description}`);
235
+ }
236
+ }
237
+ catch (error) {
238
+ this.handleError(error, {});
239
+ }
240
+ }
241
+ /**
242
+ * Handle plugin load command
243
+ */
244
+ async handlePluginLoadCommand(path) {
245
+ try {
246
+ const loader = new plugins_1.PluginLoader();
247
+ const plugin = await loader.loadPluginFromFile(path);
248
+ console.log(`Loaded plugin: ${plugin.name} (${plugin.version})`);
249
+ console.log(`Description: ${plugin.description}`);
250
+ }
251
+ catch (error) {
252
+ this.handleError(error, {});
253
+ }
254
+ }
255
+ /**
256
+ * Handle help command
257
+ */
258
+ handleHelpCommand(command) {
259
+ if (command) {
260
+ // Show help for specific command
261
+ const subCommand = this.program.commands.find((cmd) => cmd.name() === command);
262
+ if (subCommand) {
263
+ subCommand.help();
264
+ }
265
+ else {
266
+ console.log(`Unknown command: ${command}`);
267
+ console.log("Available commands:");
268
+ this.program.commands.forEach((cmd) => {
269
+ console.log(` ${cmd.name()} - ${cmd.description()}`);
270
+ });
271
+ }
272
+ }
273
+ else {
274
+ // Show general help with examples
275
+ console.log("šŸ“š Schemantic CLI Examples:");
276
+ console.log("\nļæ½ Basic Usage:");
277
+ console.log(" # Generate from FastAPI server");
278
+ console.log(" npx schemantic generate --url http://localhost:8000/openapi.json");
279
+ console.log("\n # Generate from local file");
280
+ console.log(" npx schemantic generate --file ./openapi-schema.json");
281
+ console.log("\n # Custom output directory");
282
+ console.log(" npx schemantic generate --url http://localhost:8000/openapi.json --output ./src/api");
283
+ console.log("\nāš›ļø React Integration:");
284
+ console.log(" # Generate with React hooks");
285
+ console.log(" npx schemantic generate --url http://localhost:8000/openapi.json --hooks");
286
+ console.log("\nšŸŽ›ļø Interactive Mode:");
287
+ console.log(" npx schemantic generate --interactive");
288
+ console.log("\nāš™ļø Configuration:");
289
+ console.log(" # Initialize configuration");
290
+ console.log(" npx schemantic init");
291
+ console.log("\n # Use configuration file");
292
+ console.log(" npx schemantic generate --config ./Schemantic.config.json");
293
+ console.log("\nāœ… Validation:");
294
+ console.log(" # Validate schema");
295
+ console.log(" npx schemantic validate --url http://localhost:8000/openapi.json");
296
+ console.log("\nļæ½ Advanced:");
297
+ console.log(" # Custom naming and filtering");
298
+ console.log(" npx schemantic generate --url http://localhost:8000/openapi.json \\");
299
+ console.log(" --naming PascalCase --prefix MyAPI --exclude-paths '/health,/docs'");
300
+ console.log("\nšŸ“– For complete documentation:");
301
+ console.log(" https://github.com/Cstannahill/schemantic#readme");
302
+ console.log("\nšŸ’” Get help for specific commands:");
303
+ console.log(" npx schemantic help generate");
304
+ console.log(" npx schemantic generate --help");
305
+ }
306
+ }
307
+ /**
308
+ * Load configuration from options
309
+ */
310
+ async loadConfiguration(source, options = {}) {
311
+ let config = { ...core_1.DEFAULT_CONFIG };
312
+ // Load from config file if specified
313
+ if (options.config) {
314
+ const configFile = await this.loadConfigFile(options.config);
315
+ config = { ...config, ...configFile };
316
+ }
317
+ // Handle source parameter (URL or file path)
318
+ if (source) {
319
+ if (source.startsWith("http://") || source.startsWith("https://")) {
320
+ config.schemaUrl = source;
321
+ }
322
+ else {
323
+ config.schemaFile = source;
324
+ }
325
+ }
326
+ // Override with command line options
327
+ if (options.url) {
328
+ config.schemaUrl = options.url;
329
+ }
330
+ if (options.file) {
331
+ config.schemaFile = options.file;
332
+ }
333
+ if (options.output) {
334
+ config.outputDir = options.output;
335
+ }
336
+ if (options.types) {
337
+ config.generateTypes = true;
338
+ }
339
+ if (options.client) {
340
+ config.generateApiClient = true;
341
+ }
342
+ if (options.hooks) {
343
+ config.generateHooks = true;
344
+ }
345
+ if (options.strict !== undefined) {
346
+ config.useStrictTypes = options.strict;
347
+ }
348
+ if (options.naming) {
349
+ config.namingConvention = options.naming;
350
+ }
351
+ if (options.prefix) {
352
+ config.typePrefix = options.prefix;
353
+ }
354
+ if (options.suffix) {
355
+ config.typeSuffix = options.suffix;
356
+ }
357
+ if (options.excludePaths) {
358
+ config.excludePaths = options.excludePaths.split(",");
359
+ }
360
+ if (options.includePaths) {
361
+ config.includePaths = options.includePaths.split(",");
362
+ }
363
+ if (options.excludeSchemas) {
364
+ config.excludeSchemas = options.excludeSchemas.split(",");
365
+ }
366
+ if (options.includeSchemas) {
367
+ config.includeSchemas = options.includeSchemas.split(",");
368
+ }
369
+ if (options.plugins) {
370
+ config.plugins = options.plugins.split(",").map((name) => ({
371
+ name: name.trim(),
372
+ enabled: true,
373
+ }));
374
+ }
375
+ // Validate required fields
376
+ if (!config.schemaUrl && !config.schemaFile && !config.schemaData) {
377
+ throw new Error("Either source parameter, --url, --file, or schema data must be provided");
378
+ }
379
+ if (!config.outputDir) {
380
+ throw new Error("Output directory must be specified");
381
+ }
382
+ return config;
383
+ }
384
+ /**
385
+ * Load configuration file
386
+ */
387
+ async loadConfigFile(filePath) {
388
+ try {
389
+ const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
390
+ const content = await fs.readFile(filePath, "utf-8");
391
+ if (filePath.endsWith(".json")) {
392
+ return JSON.parse(content);
393
+ }
394
+ else if (filePath.endsWith(".js") || filePath.endsWith(".ts")) {
395
+ const module = await Promise.resolve(`${filePath}`).then(s => __importStar(require(s)));
396
+ return module.default || module;
397
+ }
398
+ else {
399
+ throw new Error(`Unsupported configuration file format: ${filePath}`);
400
+ }
401
+ }
402
+ catch (error) {
403
+ throw new Error(`Failed to load configuration file ${filePath}: ${error}`);
404
+ }
405
+ }
406
+ /**
407
+ * Load plugins
408
+ */
409
+ async loadPlugins(config, Schemantic) {
410
+ const pluginManager = Schemantic.getPluginManager();
411
+ // Load built-in plugins
412
+ const builtinPlugins = (0, builtin_1.getBuiltinPlugins)();
413
+ for (const plugin of builtinPlugins) {
414
+ pluginManager.registerPlugin(plugin);
415
+ }
416
+ // Load configured plugins
417
+ if (config.plugins) {
418
+ for (const pluginConfig of config.plugins) {
419
+ if (pluginConfig.enabled) {
420
+ pluginManager.enablePlugin(pluginConfig.name);
421
+ }
422
+ }
423
+ }
424
+ }
425
+ /**
426
+ * Output generation results
427
+ */
428
+ outputResults(result, options) {
429
+ if (options.quiet) {
430
+ return;
431
+ }
432
+ if (result.success) {
433
+ console.log("āœ… Generation completed successfully!");
434
+ console.log(`šŸ“ Generated ${result.generatedFiles.length} files`);
435
+ console.log(`šŸ“Š Statistics: ${result.statistics.totalTypes} types, ${result.statistics.totalEndpoints} endpoints`);
436
+ console.log(`ā±ļø Generation time: ${result.statistics.generationTime}ms`);
437
+ }
438
+ else {
439
+ console.log("āŒ Generation failed!");
440
+ console.log(`🚨 Errors: ${result.errors.length}`);
441
+ for (const error of result.errors) {
442
+ console.log(` - ${error.message}`);
443
+ }
444
+ }
445
+ }
446
+ /**
447
+ * Output validation results
448
+ */
449
+ outputValidationResults(result, options) {
450
+ if (options.quiet) {
451
+ return;
452
+ }
453
+ if (result.isValid) {
454
+ console.log("āœ… Schema validation passed!");
455
+ }
456
+ else {
457
+ console.log("āŒ Schema validation failed!");
458
+ console.log(`🚨 Errors: ${result.errors.length}`);
459
+ for (const error of result.errors) {
460
+ console.log(` - ${error.message}${error.source ? ` (${error.source})` : ""}`);
461
+ }
462
+ }
463
+ if (result.warnings.length > 0) {
464
+ console.log(`āš ļø Warnings: ${result.warnings.length}`);
465
+ for (const warning of result.warnings) {
466
+ console.log(` - ${warning.message}${warning.source ? ` (${warning.source})` : ""}`);
467
+ }
468
+ }
469
+ }
470
+ /**
471
+ * Handle errors
472
+ */
473
+ handleError(error, options) {
474
+ if (options.quiet) {
475
+ process.exit(1);
476
+ }
477
+ console.error("āŒ Error:", error);
478
+ process.exit(1);
479
+ }
480
+ /**
481
+ * Run interactive mode
482
+ */
483
+ async runInteractiveMode() {
484
+ console.log("šŸš€ Schemantic Interactive Mode\n");
485
+ const rl = readline.createInterface({
486
+ input: process.stdin,
487
+ output: process.stdout,
488
+ });
489
+ try {
490
+ const config = { ...core_1.DEFAULT_CONFIG };
491
+ // Get schema source
492
+ const schemaSource = await this.askQuestion(rl, "Enter OpenAPI schema URL or file path: ");
493
+ if (schemaSource.startsWith("http")) {
494
+ config.schemaUrl = schemaSource;
495
+ }
496
+ else {
497
+ config.schemaFile = schemaSource;
498
+ }
499
+ // Get output directory
500
+ const outputDir = await this.askQuestion(rl, "Output directory (default: ./src/generated): ");
501
+ config.outputDir = outputDir || "./src/generated";
502
+ // Get type prefix
503
+ const prefix = await this.askQuestion(rl, "Type prefix (default: API): ");
504
+ config.typePrefix = prefix || "API";
505
+ // Get generation options
506
+ const generateTypes = await this.askYesNo(rl, "Generate types? (Y/n): ");
507
+ config.generateTypes = generateTypes !== false;
508
+ const generateClient = await this.askYesNo(rl, "Generate API client? (Y/n): ");
509
+ config.generateApiClient = generateClient !== false;
510
+ const generateHooks = await this.askYesNo(rl, "Generate React hooks? (y/N): ");
511
+ config.generateHooks = generateHooks === true;
512
+ const strictTypes = await this.askYesNo(rl, "Use strict TypeScript types? (Y/n): ");
513
+ config.useStrictTypes = strictTypes !== false;
514
+ // Create Schemantic instance and generate
515
+ const schemanticInstance = new schemantic_1.Schemantic(config);
516
+ await this.loadPlugins(config, schemanticInstance);
517
+ console.log("\nāš™ļø Generating types and API client...");
518
+ const result = await schemanticInstance.generate();
519
+ this.outputResults(result, {});
520
+ }
521
+ finally {
522
+ rl.close();
523
+ }
524
+ }
525
+ /**
526
+ * Run init interactive mode
527
+ */
528
+ async runInitInteractive(directory, _options) {
529
+ console.log("šŸš€ Schemantic Configuration Initialization\n");
530
+ const rl = readline.createInterface({
531
+ input: process.stdin,
532
+ output: process.stdout,
533
+ });
534
+ try {
535
+ const config = { ...core_1.DEFAULT_CONFIG };
536
+ // Get schema source
537
+ const schemaSource = await this.askQuestion(rl, "Enter default OpenAPI schema URL or file path: ");
538
+ if (schemaSource.startsWith("http")) {
539
+ config.schemaUrl = schemaSource;
540
+ }
541
+ else {
542
+ config.schemaFile = schemaSource;
543
+ }
544
+ // Get output directory
545
+ const outputDir = await this.askQuestion(rl, "Default output directory (default: ./src/generated): ");
546
+ config.outputDir = outputDir || "./src/generated";
547
+ // Get type prefix
548
+ const prefix = await this.askQuestion(rl, "Type prefix (default: API): ");
549
+ config.typePrefix = prefix || "API";
550
+ // Get naming convention
551
+ const naming = await this.askChoice(rl, "Naming convention (camelCase/snake_case/PascalCase): ", ["camelCase", "snake_case", "PascalCase"], "camelCase");
552
+ config.namingConvention = naming;
553
+ // Get generation options
554
+ const generateTypes = await this.askYesNo(rl, "Generate types by default? (Y/n): ");
555
+ config.generateTypes = generateTypes !== false;
556
+ const generateClient = await this.askYesNo(rl, "Generate API client by default? (Y/n): ");
557
+ config.generateApiClient = generateClient !== false;
558
+ const generateHooks = await this.askYesNo(rl, "Generate React hooks by default? (y/N): ");
559
+ config.generateHooks = generateHooks === true;
560
+ const strictTypes = await this.askYesNo(rl, "Use strict TypeScript types by default? (Y/n): ");
561
+ config.useStrictTypes = strictTypes !== false;
562
+ // Save configuration
563
+ await this.saveConfig(directory, config);
564
+ console.log("\nāœ… Configuration saved to Schemantic.config.json");
565
+ }
566
+ finally {
567
+ rl.close();
568
+ }
569
+ }
570
+ /**
571
+ * Create default configuration
572
+ */
573
+ async createDefaultConfig(directory) {
574
+ const config = {
575
+ ...core_1.DEFAULT_CONFIG,
576
+ outputDir: "./src/generated",
577
+ typePrefix: "API",
578
+ generateTypes: true,
579
+ generateApiClient: true,
580
+ generateHooks: false,
581
+ useStrictTypes: true,
582
+ namingConvention: "camelCase",
583
+ typeSuffix: "",
584
+ generateBarrelExports: true,
585
+ useOptionalChaining: true,
586
+ useNullishCoalescing: true,
587
+ preserveComments: true,
588
+ generateIndexFile: true,
589
+ };
590
+ await this.saveConfig(directory, config);
591
+ console.log("āœ… Default configuration created");
592
+ }
593
+ /**
594
+ * Save configuration to file
595
+ */
596
+ async saveConfig(directory, config) {
597
+ const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
598
+ const path = await Promise.resolve().then(() => __importStar(require("path")));
599
+ const configPath = path.join(directory, "Schemantic.config.json");
600
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
601
+ }
602
+ /**
603
+ * Ask a question and return the answer
604
+ */
605
+ askQuestion(rl, question) {
606
+ return new Promise((resolve) => {
607
+ rl.question(question, resolve);
608
+ });
609
+ }
610
+ /**
611
+ * Ask a yes/no question and return boolean
612
+ */
613
+ askYesNo(rl, question) {
614
+ return new Promise((resolve) => {
615
+ rl.question(question, (answer) => {
616
+ const normalized = answer.toLowerCase().trim();
617
+ if (normalized === "" || normalized === "y" || normalized === "yes") {
618
+ resolve(true);
619
+ }
620
+ else {
621
+ resolve(false);
622
+ }
623
+ });
624
+ });
625
+ }
626
+ /**
627
+ * Ask a choice question and return selected option
628
+ */
629
+ askChoice(rl, question, choices, defaultChoice) {
630
+ return new Promise((resolve) => {
631
+ rl.question(question, (answer) => {
632
+ const normalized = answer.toLowerCase().trim();
633
+ if (normalized === "") {
634
+ resolve(defaultChoice);
635
+ }
636
+ else {
637
+ const choice = choices.find((c) => c.toLowerCase() === normalized);
638
+ resolve(choice || defaultChoice);
639
+ }
640
+ });
641
+ });
642
+ }
643
+ /**
644
+ * Run the CLI
645
+ */
646
+ run() {
647
+ this.program.parse();
648
+ }
649
+ }
650
+ exports.SchemanticCli = SchemanticCli;
651
+ // Export CLI class and create instance
652
+ exports.cli = new SchemanticCli();
653
+ // Run CLI if this file is executed directly
654
+ if (require.main === module) {
655
+ exports.cli.run();
656
+ }
657
+ //# sourceMappingURL=index.js.map