@sdk-it/cli 0.46.3 → 0.46.4

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/bin.js CHANGED
@@ -2,13 +2,9 @@
2
2
 
3
3
  // packages/cli/src/lib/cli.ts
4
4
  import { Command as Command7, program } from "commander";
5
- import { readJson as readJson2 } from "@sdk-it/core/file-system.js";
6
5
 
7
6
  // packages/cli/src/lib/commands/init.ts
8
- import { checkbox, confirm, input, select } from "@inquirer/prompts";
9
7
  import { Command } from "commander";
10
- import { writeFile as writeFile4 } from "node:fs/promises";
11
- import { resolve as resolve6 } from "node:path";
12
8
 
13
9
  // packages/cli/src/lib/project.ts
14
10
  import { resolve as resolve3 } from "node:path";
@@ -34,6 +30,8 @@ async function analyzeProject(tsconfig, config) {
34
30
  }
35
31
  const { paths, components } = await analyze(tsconfig, {
36
32
  responseAnalyzer: honoResponseAnalyzer,
33
+ securitySchemes: config.securitySchemes,
34
+ middlewareSecurity: config.middlewareSecurity,
37
35
  ...prisma ? {
38
36
  imports: prisma.imports,
39
37
  typesMap: {
@@ -236,9 +234,16 @@ ${ts3.formatDiagnosticsWithColorAndContext(
236
234
  }
237
235
  async function synchronizeGeneratedManifest(output, packageName) {
238
236
  const manifestPath = join2(output, "package.json");
239
- const manifest = JSON.parse(
240
- await readFile2(manifestPath, "utf8")
237
+ const manifest = generatedPackageManifest(
238
+ packageName,
239
+ JSON.parse(
240
+ await readFile2(manifestPath, "utf8")
241
+ )
241
242
  );
243
+ await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
244
+ `);
245
+ }
246
+ function generatedPackageManifest(packageName, manifest) {
242
247
  Object.assign(manifest, {
243
248
  name: packageName,
244
249
  version: "0.0.1",
@@ -262,8 +267,7 @@ async function synchronizeGeneratedManifest(output, packageName) {
262
267
  "fast-content-type-parse": "^3.0.0",
263
268
  zod: "^4.3.0"
264
269
  };
265
- await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
266
- `);
270
+ return manifest;
267
271
  }
268
272
 
269
273
  // packages/cli/src/lib/project/output.ts
@@ -284,8 +288,8 @@ async function writeProjectClient(openapi, config) {
284
288
  }
285
289
 
286
290
  // packages/cli/src/lib/project/config.ts
287
- import { access as access2, readFile as readFile3, stat, writeFile as writeFile3 } from "node:fs/promises";
288
- import { dirname, join as join4, relative as relative2, resolve as resolve2 } from "node:path";
291
+ import { access as access2, mkdir, readFile as readFile3, stat, writeFile as writeFile3 } from "node:fs/promises";
292
+ import { basename, dirname, join as join4, relative as relative2, resolve as resolve2 } from "node:path";
289
293
  import { pathToFileURL } from "node:url";
290
294
  async function loadProjectConfig(options = {}) {
291
295
  const cwd = resolve2(options.cwd ?? process.cwd());
@@ -301,21 +305,41 @@ async function loadProjectConfig(options = {}) {
301
305
  return {
302
306
  ...config,
303
307
  tsconfig: resolve2(directory, config.tsconfig),
304
- output: resolve2(directory, config.output ?? ".sdk-it")
308
+ output: resolve2(directory, config.output ?? ".sdk-it"),
309
+ ...config.middlewareSecurity ? {
310
+ middlewareSecurity: config.middlewareSecurity.map((rule) => ({
311
+ ...rule,
312
+ middleware: {
313
+ ...rule.middleware,
314
+ from: resolve2(directory, rule.middleware.from)
315
+ }
316
+ }))
317
+ } : {}
305
318
  };
306
319
  }
307
320
  async function initializeProject(options) {
308
321
  const cwd = resolve2(options.cwd ?? process.cwd());
309
- const configPath = join4(cwd, "sdk-it.config.ts");
310
322
  const tsconfigPath = resolve2(cwd, options.tsconfig);
311
323
  await validateTsconfig(tsconfigPath);
312
- const tsconfig = relative2(cwd, tsconfigPath).replaceAll("\\", "/");
324
+ const projectDirectory = dirname(tsconfigPath);
325
+ const configPath = join4(projectDirectory, "sdk-it.config.ts");
326
+ const { directory: workspaceDirectory, manifest } = await findWorkspace(projectDirectory);
327
+ const packageName = generatedPackageName(
328
+ manifest.name,
329
+ projectDirectory,
330
+ workspaceDirectory
331
+ );
332
+ const tsconfig = relative2(projectDirectory, tsconfigPath).replaceAll(
333
+ "\\",
334
+ "/"
335
+ );
313
336
  const relativeTsconfig = tsconfig.startsWith(".") ? tsconfig : `./${tsconfig}`;
314
337
  const configSource = `import { defineConfig } from '@sdk-it/cli';
315
338
 
316
339
  export default defineConfig({
317
340
  tsconfig: '${relativeTsconfig}',
318
- });
341
+ ${projectDirectory === workspaceDirectory ? "" : ` packageName: '${packageName}',
342
+ `}});
319
343
  `;
320
344
  const existingConfig = await readOptionalFile2(configPath);
321
345
  if (existingConfig !== void 0 && existingConfig !== configSource) {
@@ -323,43 +347,96 @@ export default defineConfig({
323
347
  `${configPath} already exists with different settings. Review it before replacing the file.`
324
348
  );
325
349
  }
326
- const packagePath = join4(cwd, "package.json");
327
- const manifest = JSON.parse(
328
- await readFile3(packagePath, "utf8")
350
+ const output = join4(projectDirectory, ".sdk-it");
351
+ const manifestPath = join4(output, "package.json");
352
+ const existingManifest = await readOptionalFile2(manifestPath);
353
+ const generatedManifest = generatedPackageManifest(
354
+ packageName,
355
+ existingManifest ? JSON.parse(existingManifest) : {}
356
+ );
357
+ const generatedManifestSource = `${JSON.stringify(generatedManifest, null, 2)}
358
+ `;
359
+ const workspacePath = relative2(workspaceDirectory, output).replaceAll(
360
+ "\\",
361
+ "/"
329
362
  );
330
- const manifestChanged = addGeneratedWorkspace(manifest);
331
- const gitignorePath = join4(cwd, ".gitignore");
363
+ const manifestChanged = addGeneratedWorkspace(manifest, workspacePath);
364
+ const gitignorePath = join4(workspaceDirectory, ".gitignore");
332
365
  const gitignore = await readOptionalFile2(gitignorePath) ?? "";
333
- if (!ignoresGeneratedWorkspace(gitignore)) {
334
- const prefix = gitignore.length > 0 && !gitignore.endsWith("\n") ? "\n" : "";
335
- await writeFile3(gitignorePath, `${gitignore}${prefix}.sdk-it/
336
- `);
366
+ const updatedGitignore = withGeneratedWorkspaceIgnore(
367
+ gitignore,
368
+ workspacePath
369
+ );
370
+ if (updatedGitignore !== gitignore) {
371
+ await writeFile3(gitignorePath, updatedGitignore);
337
372
  }
338
373
  if (manifestChanged) {
339
- await writeFile3(packagePath, `${JSON.stringify(manifest, null, 2)}
340
- `);
374
+ await writeFile3(
375
+ join4(workspaceDirectory, "package.json"),
376
+ `${JSON.stringify(manifest, null, 2)}
377
+ `
378
+ );
341
379
  }
342
380
  if (existingConfig === void 0) {
343
381
  await writeFile3(configPath, configSource);
344
382
  }
383
+ if (existingManifest !== generatedManifestSource) {
384
+ await mkdir(output, { recursive: true });
385
+ await writeFile3(manifestPath, generatedManifestSource);
386
+ }
345
387
  }
346
- function addGeneratedWorkspace(manifest) {
388
+ function addGeneratedWorkspace(manifest, workspace) {
347
389
  const workspaces = manifest.workspaces;
348
390
  if (Array.isArray(workspaces)) {
349
- if (workspaces.includes(".sdk-it")) return false;
350
- workspaces.push(".sdk-it");
391
+ if (workspaces.includes(workspace)) return false;
392
+ workspaces.push(workspace);
351
393
  return true;
352
394
  }
353
395
  if (workspaces && Array.isArray(workspaces.packages)) {
354
- if (workspaces.packages.includes(".sdk-it")) return false;
355
- workspaces.packages.push(".sdk-it");
396
+ if (workspaces.packages.includes(workspace)) return false;
397
+ workspaces.packages.push(workspace);
356
398
  return true;
357
399
  }
358
- manifest.workspaces = [".sdk-it"];
400
+ manifest.workspaces = [workspace];
359
401
  return true;
360
402
  }
361
- function ignoresGeneratedWorkspace(gitignore) {
362
- return gitignore.split(/\r?\n/).some((line) => line.trim() === ".sdk-it/" || line.trim() === ".sdk-it");
403
+ function withGeneratedWorkspaceIgnore(gitignore, workspace) {
404
+ const patterns = [
405
+ `!${workspace}/`,
406
+ `${workspace}/*`,
407
+ `!${workspace}/package.json`
408
+ ];
409
+ const lines = gitignore.split(/\r?\n/).filter((line) => !patterns.includes(line.trim()));
410
+ while (lines.at(-1) === "") lines.pop();
411
+ return `${lines.length ? `${lines.join("\n")}
412
+ ` : ""}${patterns.join("\n")}
413
+ `;
414
+ }
415
+ async function findWorkspace(start) {
416
+ let directory = start;
417
+ let nearest;
418
+ while (true) {
419
+ const source = await readOptionalFile2(join4(directory, "package.json"));
420
+ if (source) {
421
+ const candidate = {
422
+ directory,
423
+ manifest: JSON.parse(source)
424
+ };
425
+ nearest ??= candidate;
426
+ if (candidate.manifest.workspaces !== void 0) return candidate;
427
+ }
428
+ const parent = dirname(directory);
429
+ if (parent === directory) break;
430
+ directory = parent;
431
+ }
432
+ if (nearest) return nearest;
433
+ throw new Error(`Could not find a package.json from ${start}.`);
434
+ }
435
+ function generatedPackageName(workspaceName, projectDirectory, workspaceDirectory) {
436
+ if (projectDirectory === workspaceDirectory) return "@sdk-it/client";
437
+ const project = basename(projectDirectory).toLowerCase().replace(/[^a-z0-9._-]+/g, "-");
438
+ const scope = workspaceName?.match(/^@([^/]+)\//)?.[1];
439
+ return scope ? `@${scope}/${project}-client` : `${project}-client`;
363
440
  }
364
441
  async function validateTsconfig(path) {
365
442
  try {
@@ -407,447 +484,16 @@ async function generateProject(config) {
407
484
  await writeProjectClient(openapi, config);
408
485
  }
409
486
 
410
- // packages/cli/src/lib/commands/find-framework.ts
411
- import { resolve as resolve4 } from "node:path";
412
- import { exist } from "@sdk-it/core/file-system.js";
413
- var monorepoIndicators = {
414
- lerna: () => exist(resolve4(process.cwd(), "lerna.json")),
415
- nx: () => exist(resolve4(process.cwd(), "nx.json")),
416
- pnpm: () => exist(resolve4(process.cwd(), "pnpm-workspace.yaml")),
417
- rush: () => exist(resolve4(process.cwd(), "rush.json"))
418
- };
419
- async function detectMonorepo() {
420
- for (const [indicator, check] of Object.entries(monorepoIndicators)) {
421
- if (await check()) {
422
- return indicator;
423
- }
424
- }
425
- return void 0;
426
- }
427
-
428
- // packages/cli/src/lib/commands/find-spec-file.ts
429
- import { resolve as resolve5 } from "node:path";
430
- import { exist as exist2 } from "@sdk-it/core/file-system.js";
431
- async function findSpecFile() {
432
- const commonNames = [
433
- "openapi.json",
434
- "openapi.yaml",
435
- "openapi.yml",
436
- "swagger.json",
437
- "swagger.yaml",
438
- "swagger.yml",
439
- "api.json",
440
- "api.yaml",
441
- "api.yml",
442
- "spec.json",
443
- "spec.yaml",
444
- "spec.yml",
445
- "schema.json",
446
- "schema.yaml",
447
- "schema.yml"
448
- ];
449
- for (const name of commonNames) {
450
- if (await exist2(resolve5(process.cwd(), name))) {
451
- return `./${name}`;
452
- }
453
- }
454
- return void 0;
455
- }
456
-
457
- // packages/cli/src/lib/commands/guess-default-package-name.ts
458
- import { join as join5 } from "node:path";
459
- import { readJson } from "@sdk-it/core/file-system.js";
460
- async function guessTypescriptPackageName(consideringMultipleGenerator) {
461
- try {
462
- const packageJson = await readJson(
463
- join5(process.cwd(), "package.json")
464
- );
465
- if (packageJson.name) {
466
- const match = packageJson.name.match(/^@([^/]+)/);
467
- if (match) {
468
- const scope = match[1];
469
- return consideringMultipleGenerator ? `@${scope}/ts-sdk` : `@${scope}/sdk`;
470
- }
471
- }
472
- } catch {
473
- }
474
- return consideringMultipleGenerator ? "ts-sdk" : "sdk";
475
- }
476
-
477
487
  // packages/cli/src/lib/commands/init.ts
478
- var specInput = async (defaultValue) => {
479
- return input({
480
- message: "OpenAPI or Postman specification file path:",
481
- default: defaultValue || "./openapi.json"
482
- });
483
- };
484
- var generatorConfigs = {
485
- typescript: {
486
- name: async (isMultipleGenerators = false) => {
487
- const defaultName = await guessTypescriptPackageName(isMultipleGenerators);
488
- return input({
489
- message: "SDK package name:",
490
- default: defaultName
491
- });
492
- },
493
- spec: specInput,
494
- output: async () => {
495
- let defaultValue = "./ts-sdk";
496
- const monorepo = await detectMonorepo();
497
- if (monorepo === "nx") {
498
- defaultValue = "./packages/ts-sdk";
499
- }
500
- return await input({
501
- message: "Output directory:",
502
- default: defaultValue
503
- });
504
- },
505
- mode: async () => {
506
- const options = {
507
- mode: "full",
508
- install: false
509
- };
510
- options.mode = await select({
511
- message: "Generation mode:",
512
- choices: [
513
- {
514
- name: "Full (generates package.json and tsconfig.json)",
515
- value: "full"
516
- },
517
- {
518
- name: "Minimal (generates only the client TypeScript files)",
519
- value: "minimal"
520
- }
521
- ],
522
- default: options.mode
523
- });
524
- if (options.mode === "full") {
525
- const installDeps = await confirm({
526
- message: "Install dependencies automatically?",
527
- default: true
528
- });
529
- options.install = installDeps;
530
- }
531
- return options;
532
- },
533
- pagination: async () => {
534
- let pagination = {
535
- guess: false
536
- };
537
- const result = await confirm({
538
- message: "Enable pagination support?",
539
- default: false
540
- });
541
- if (result) {
542
- pagination.guess = await confirm({
543
- message: "Would you like to guess pagination parameters?",
544
- default: false
545
- });
546
- } else {
547
- pagination = false;
548
- }
549
- return pagination;
550
- },
551
- readme: () => confirm({
552
- message: "Generate README file?",
553
- default: true
554
- }),
555
- defaultFormatter: () => confirm({
556
- message: "Use default formatter (prettier)?",
557
- default: true
558
- }),
559
- framework: () => input({
560
- message: "Framework integrating with the SDK (optional):"
561
- }),
562
- formatter: () => input({
563
- message: 'Custom formatter command (optional, e.g., "prettier $SDK_IT_OUTPUT --write"):'
564
- })
565
- },
566
- python: {
567
- name: () => input({
568
- message: "SDK package name:",
569
- default: "my-python-sdk"
570
- }),
571
- spec: specInput,
572
- output: () => input({
573
- message: "Output directory:",
574
- default: "./python-sdk"
575
- }),
576
- mode: async () => {
577
- const isMonorepo = await detectMonorepo();
578
- return select({
579
- message: "Generation mode:",
580
- choices: [
581
- {
582
- name: "Full (generates complete project structure)",
583
- value: "full"
584
- },
585
- {
586
- name: "Minimal (generates only the client files)",
587
- value: "minimal"
588
- }
589
- ],
590
- default: isMonorepo ? "full" : "full"
591
- // Default to full, especially for monorepos
592
- }).then((value) => value);
593
- },
594
- formatter: () => input({
595
- message: 'Custom formatter command (optional, e.g., "black $SDK_IT_OUTPUT" or "ruff format $SDK_IT_OUTPUT"):'
596
- })
597
- },
598
- dart: {
599
- name: () => input({
600
- message: "SDK package name:",
601
- default: "my-dart-sdk"
602
- }),
603
- spec: specInput,
604
- output: () => input({
605
- message: "Output directory:",
606
- default: "./dart-sdk"
607
- }),
608
- mode: async () => {
609
- const isMonorepo = await detectMonorepo();
610
- return select({
611
- message: "Generation mode:",
612
- choices: [
613
- {
614
- name: "Full (generates complete project structure)",
615
- value: "full"
616
- },
617
- {
618
- name: "Minimal (generates only the client files)",
619
- value: "minimal"
620
- }
621
- ],
622
- default: isMonorepo ? "full" : "full"
623
- // Default to full, especially for monorepos
624
- }).then((value) => value);
625
- },
626
- pagination: async () => {
627
- let pagination = {
628
- guess: false
629
- };
630
- const result = await confirm({
631
- message: "Enable pagination support?",
632
- default: false
633
- });
634
- if (result) {
635
- pagination.guess = await confirm({
636
- message: "Would you like to guess pagination parameters?",
637
- default: false
638
- });
639
- } else {
640
- pagination = false;
641
- }
642
- return pagination;
643
- }
644
- }
645
- };
646
- var init = new Command("init").description("Initialize SDK-IT configuration interactively").option("--project <tsconfig>", "Initialize from a backend tsconfig").action(async (options) => {
647
- if (options.project) {
648
- await initializeProject({ tsconfig: options.project });
649
- console.log("SDK-IT project configuration initialized.");
650
- return;
651
- }
652
- console.log("Welcome to SDK-IT! Let's set up your configuration.\n");
653
- const possibleSpecFile = await findSpecFile();
654
- const monorepo = await detectMonorepo();
655
- if (possibleSpecFile) {
656
- console.log(`\u{1F50D} Auto-detected API specification: ${possibleSpecFile}`);
657
- }
658
- if (monorepo) {
659
- console.log(`\u{1F4E6} Detected monorepo setup`);
660
- }
661
- if (possibleSpecFile || monorepo) {
662
- console.log("");
663
- }
664
- const config = {
665
- generators: {}
666
- };
667
- const generators = await checkbox({
668
- message: "Which SDK generators would you like to configure?",
669
- loop: false,
670
- instructions: false,
671
- required: true,
672
- choices: [
673
- { name: "TypeScript", value: "typescript" },
674
- { name: "Python", value: "python" },
675
- { name: "Dart", value: "dart" }
676
- ]
677
- });
678
- for (const generator of generators) {
679
- console.log(`
680
- Configuring ${generator} generator:`);
681
- if (generator === "typescript") {
682
- const tsConfig = generatorConfigs.typescript;
683
- const isMultipleGenerators = generators.length > 1;
684
- const generatorConfig = {
685
- spec: await tsConfig.spec(possibleSpecFile),
686
- output: await tsConfig.output(),
687
- name: await tsConfig.name(isMultipleGenerators),
688
- defaultFormatter: await tsConfig.defaultFormatter(),
689
- readme: await tsConfig.readme(),
690
- pagination: await tsConfig.pagination(),
691
- ...await tsConfig.mode()
692
- };
693
- const customFramework = await tsConfig.framework();
694
- if (customFramework) {
695
- generatorConfig.framework = customFramework;
696
- }
697
- const customFormatter = await tsConfig.formatter();
698
- if (customFormatter) {
699
- generatorConfig.formatter = customFormatter;
700
- }
701
- config.generators.typescript = generatorConfig;
702
- } else if (generator === "python") {
703
- config.generators.python = {
704
- spec: await generatorConfigs.python.spec(),
705
- output: await generatorConfigs.python.output(),
706
- mode: await generatorConfigs.python.mode(),
707
- name: await generatorConfigs.python.name()
708
- };
709
- } else if (generator === "dart") {
710
- config.generators.dart = {
711
- spec: await generatorConfigs.dart.spec(),
712
- output: await generatorConfigs.dart.output(),
713
- mode: await generatorConfigs.dart.mode(),
714
- name: await generatorConfigs.dart.name(),
715
- pagination: await generatorConfigs.dart.pagination()
716
- };
717
- }
718
- }
719
- const generateReadme = await confirm({
720
- message: "\nGenerate README documentation?",
721
- default: true
722
- });
723
- if (generateReadme) {
724
- const readmeSpec = await input({
725
- message: "OpenAPI specification for README:",
726
- default: config.generators.typescript?.spec || possibleSpecFile || "./openapi.yaml"
727
- });
728
- const readmeOutput = await input({
729
- message: "README output file:",
730
- default: "./README.md"
731
- });
732
- config.readme = {
733
- spec: readmeSpec,
734
- output: readmeOutput
735
- };
736
- }
737
- const generateApiRef = await confirm({
738
- message: "\nGenerate API reference documentation?",
739
- default: false
740
- });
741
- if (generateApiRef) {
742
- const autoDetected = await findSpecFile();
743
- const apirefSpec = await input({
744
- message: "OpenAPI specification for API reference:",
745
- default: config.generators.typescript?.spec || autoDetected || "./openapi.yaml"
746
- });
747
- const apirefOutput = await input({
748
- message: "API reference output directory:",
749
- default: "./docs"
750
- });
751
- config.apiref = {
752
- spec: apirefSpec,
753
- output: apirefOutput
754
- };
755
- }
756
- const configPath = resolve6(process.cwd(), "sdk-it.json");
757
- await writeFile4(configPath, JSON.stringify(config, null, 2));
758
- console.log(`
759
- \u2705 Configuration saved to ${configPath}`);
760
- console.log("\n\u{1F680} Next Steps:\n");
761
- console.log("1. Generate your SDK(s):");
762
- console.log(" npx @sdk-it/cli");
763
- if (config.generators.typescript) {
764
- console.log("2. Integrate TypeScript SDK:");
765
- const importName = config.generators.typescript.name.replace(
766
- /[^a-zA-Z0-9]/g,
767
- ""
768
- );
769
- const outputDir = config.generators.typescript.output.replace("./", "");
770
- console.log(` import { ${importName} } from './${outputDir}';`);
771
- console.log(` const client = new ${importName}();`);
772
- console.log(` const result = await client.request('GET /users');
773
- `);
774
- }
775
- if (config.generators.python) {
776
- console.log("2. Integrate Python SDK:");
777
- const outputDir = config.generators.python.output.replace("./", "");
778
- console.log(` # Add to your Python path or install locally`);
779
- console.log(` from ${outputDir} import Client`);
780
- console.log(` client = Client()`);
781
- console.log(` result = client.users.list_users()
782
- `);
783
- }
784
- if (config.generators.dart) {
785
- console.log("2. Integrate Dart SDK:");
786
- const outputDir = config.generators.dart.output.replace("./", "");
787
- console.log(` # Add dependency to pubspec.yaml`);
788
- console.log(` import 'package:${outputDir}/client.dart';`);
789
- console.log(` final client = Client();`);
790
- console.log(` final result = await client.users.listUsers();
791
- `);
792
- }
793
- console.log("3. Check generated documentation:");
794
- const outputs = [];
795
- if (config.generators.typescript)
796
- outputs.push(config.generators.typescript.output);
797
- if (config.generators.python) outputs.push(config.generators.python.output);
798
- if (config.generators.dart) outputs.push(config.generators.dart.output);
799
- outputs.forEach((output) => {
800
- if (output) {
801
- console.log(
802
- ` \u{1F4D6} ${output}/README.md - Usage examples and API reference`
803
- );
804
- }
805
- });
806
- if (config.readme) {
807
- console.log(
808
- ` \u{1F4D6} ${config.readme.output} - Generated API documentation`
809
- );
810
- }
811
- if (config.apiref) {
812
- console.log(` \u{1F310} ${config.apiref.output} - Interactive API reference`);
813
- }
814
- console.log("\n4. Useful commands:");
815
- console.log(
816
- " npx @sdk-it/cli # Regenerate SDKs after API changes"
817
- );
818
- console.log(
819
- " npx @sdk-it/cli generate typescript --help # See TypeScript-specific options"
820
- );
821
- console.log(
822
- " npx @sdk-it/cli generate python --help # See Python-specific options"
823
- );
824
- console.log(
825
- " npx @sdk-it/cli generate dart --help # See Dart-specific options"
826
- );
827
- console.log("\n\u{1F4A1} Tips:");
828
- console.log(
829
- " \u2022 Update your API spec and re-run `npx @sdk-it/cli generate` to sync changes"
830
- );
831
- console.log(
832
- " \u2022 Generated SDKs include TypeScript definitions for excellent IDE support"
833
- );
834
- console.log(
835
- " \u2022 Check the README files for authentication and configuration options"
836
- );
837
- console.log("\n\u{1F4DA} Need help?");
838
- console.log(" \u2022 Documentation: https://sdk-it.dev/docs");
839
- console.log(
840
- " \u2022 Examples: https://github.com/JanuaryLabs/sdk-it/tree/main/docs/examples"
841
- );
842
- console.log(" \u2022 Issues: https://github.com/JanuaryLabs/sdk-it/issues");
843
- console.log("\nHappy coding! \u{1F389}\n");
488
+ var init_default = new Command("init").description("Initialize SDK-IT from a backend TypeScript project").requiredOption("--project <tsconfig>", "Backend tsconfig path").action(async ({ project }) => {
489
+ await initializeProject({ tsconfig: project });
490
+ console.log("SDK-IT project configuration initialized.");
844
491
  });
845
- var init_default = init;
846
492
 
847
493
  // packages/cli/src/lib/generators/apiref.ts
848
494
  import { Command as Command2 } from "commander";
849
495
  import { execa } from "execa";
850
- import { dirname as dirname2, join as join6 } from "node:path";
496
+ import { dirname as dirname2, join as join5 } from "node:path";
851
497
 
852
498
  // packages/cli/src/lib/options.ts
853
499
  import { Option } from "commander";
@@ -905,7 +551,7 @@ var apiref_default = new Command2("apiref").description("Generate APIREF").addOp
905
551
  await runApiRef(options.spec, options.output);
906
552
  });
907
553
  function runApiRef(spec, output) {
908
- const packageDir = join6(dirname2(import.meta.url), "..", "..", "apiref");
554
+ const packageDir = join5(dirname2(import.meta.url), "..", "..", "apiref");
909
555
  return execa("nx", ["run", "apiref:build", "--verbose"], {
910
556
  stdio: "inherit",
911
557
  extendEnv: true,
@@ -957,9 +603,14 @@ import { execFile as execFile2, execSync as execSync2 } from "node:child_process
957
603
 
958
604
  // packages/python/dist/index.js
959
605
  import { readdir as readdir2 } from "node:fs/promises";
960
- import { join as join7 } from "node:path";
606
+ import { join as join6 } from "node:path";
961
607
  import { snakecase as snakecase2 } from "stringcase";
962
- import { followRef as followRef2, isEmpty as isEmpty2, isRef as isRef2, pascalcase as pascalcase2 } from "@sdk-it/core";
608
+ import {
609
+ followRef as followRef2,
610
+ isEmpty as isEmpty2,
611
+ isRef as isRef2,
612
+ pascalcase as pascalcase2
613
+ } from "@sdk-it/core";
963
614
  import {
964
615
  createWriterProxy,
965
616
  writeFiles
@@ -2598,7 +2249,7 @@ async function generate3(openapi, settings) {
2598
2249
  const files = await readdir2(folder, { withFileTypes: true });
2599
2250
  return files.map((file) => ({
2600
2251
  fileName: file.name,
2601
- filePath: join7(file.parentPath, file.name),
2252
+ filePath: join6(file.parentPath, file.name),
2602
2253
  isFolder: file.isDirectory()
2603
2254
  }));
2604
2255
  };
@@ -2609,7 +2260,7 @@ async function generate3(openapi, settings) {
2609
2260
  className: `${pascalcase2(entry.tag)}Api`,
2610
2261
  methods: []
2611
2262
  };
2612
- const input2 = toInputs(spec, { entry, operation });
2263
+ const input = toInputs(spec, { entry, operation });
2613
2264
  const response = toOutput(spec, operation);
2614
2265
  const methodName = snakecase2(
2615
2266
  operation.operationId || `${entry.method}_${entry.path.replace(/[^a-zA-Z0-9]/g, "_")}`
@@ -2617,16 +2268,16 @@ async function generate3(openapi, settings) {
2617
2268
  const returnType = response ? response.returnType : "httpx.Response";
2618
2269
  const docstring = operation.summary || operation.description ? ` """${operation.summary || operation.description}"""` : "";
2619
2270
  group.methods.push(`
2620
- async def ${methodName}(self${input2.haveInput ? `, input_data: ${input2.inputName}` : ""}) -> ${returnType}:
2271
+ async def ${methodName}(self${input.haveInput ? `, input_data: ${input.inputName}` : ""}) -> ${returnType}:
2621
2272
  ${docstring}
2622
2273
  config = RequestConfig(
2623
2274
  method='${entry.method.toUpperCase()}',
2624
2275
  url='${entry.path}',
2625
2276
  )
2626
2277
 
2627
- ${input2.haveInput ? "config = input_data.to_request_config(config)" : ""}
2278
+ ${input.haveInput ? "config = input_data.to_request_config(config)" : ""}
2628
2279
 
2629
- response = await self.dispatcher.${input2.contentType}(config)
2280
+ response = await self.dispatcher.${input.contentType}(config)
2630
2281
  ${response ? `return await self.receiver.json(response, ${response.successModel || "None"}, ${response.errorModel || "None"})` : "return response"}
2631
2282
  `);
2632
2283
  });
@@ -2793,19 +2444,19 @@ python-dateutil>=2.8.0
2793
2444
  }
2794
2445
  await settings.writer(output, {
2795
2446
  "models/__init__.py": await generateModuleInit(
2796
- join7(output, "models"),
2447
+ join6(output, "models"),
2797
2448
  settings.readFolder
2798
2449
  ),
2799
2450
  "inputs/__init__.py": await generateModuleInit(
2800
- join7(output, "inputs"),
2451
+ join6(output, "inputs"),
2801
2452
  settings.readFolder
2802
2453
  ),
2803
2454
  "outputs/__init__.py": await generateModuleInit(
2804
- join7(output, "outputs"),
2455
+ join6(output, "outputs"),
2805
2456
  settings.readFolder
2806
2457
  ),
2807
2458
  "api/__init__.py": await generateModuleInit(
2808
- join7(output, "api"),
2459
+ join6(output, "api"),
2809
2460
  settings.readFolder
2810
2461
  ),
2811
2462
  "http/__init__.py": `"""HTTP utilities."""
@@ -3010,7 +2661,7 @@ async function runPython(options) {
3010
2661
 
3011
2662
  // packages/cli/src/lib/generators/readme.ts
3012
2663
  import { Command as Command5 } from "commander";
3013
- import { writeFile as writeFile5 } from "node:fs/promises";
2664
+ import { writeFile as writeFile4 } from "node:fs/promises";
3014
2665
  import { toReadme } from "@sdk-it/readme";
3015
2666
  import { loadSpec as loadSpec3, toIR as toIR3 } from "@sdk-it/spec";
3016
2667
  var readme_default = new Command5("readme").description("Generate README").addOption(specOption.makeOptionMandatory(true)).addOption(outputOption.makeOptionMandatory(true)).action(async (options) => {
@@ -3019,7 +2670,7 @@ var readme_default = new Command5("readme").description("Generate README").addOp
3019
2670
  async function runReadme(specFile, output) {
3020
2671
  const spec = await toIR3({ spec: await loadSpec3(specFile) });
3021
2672
  const content = toReadme(spec);
3022
- await writeFile5(output, content, "utf-8");
2673
+ await writeFile4(output, content, "utf-8");
3023
2674
  }
3024
2675
 
3025
2676
  // packages/cli/src/lib/generators/typescript.ts
@@ -3028,7 +2679,7 @@ import { publish } from "libnpmpublish";
3028
2679
  import { execFile as execFile3, execSync as execSync3, spawnSync } from "node:child_process";
3029
2680
  import { readFile as readFile4 } from "node:fs/promises";
3030
2681
  import { tmpdir } from "node:os";
3031
- import { join as join8 } from "node:path";
2682
+ import { join as join7 } from "node:path";
3032
2683
  import getAuthToken from "registry-auth-token";
3033
2684
  import { writeFiles as writeFiles2 } from "@sdk-it/core/file-system.js";
3034
2685
  import { loadSpec as loadSpec4 } from "@sdk-it/spec";
@@ -3123,7 +2774,7 @@ async function emitLocal(spec, options) {
3123
2774
  async function emitRemote(spec, options) {
3124
2775
  const registry = options.publish === "npm" ? "https://registry.npmjs.org/" : options.publish === "github" ? "https://npm.pkg.github.com/" : options.publish;
3125
2776
  console.log("Publishing to registry:", registry);
3126
- const path = join8(tmpdir(), crypto.randomUUID());
2777
+ const path = join7(tmpdir(), crypto.randomUUID());
3127
2778
  await emitLocal(spec, {
3128
2779
  ...options,
3129
2780
  output: path,
@@ -3131,7 +2782,7 @@ async function emitRemote(spec, options) {
3131
2782
  mode: "full"
3132
2783
  });
3133
2784
  const manifest = JSON.parse(
3134
- await readFile4(join8(path, "package.json"), "utf-8")
2785
+ await readFile4(join7(path, "package.json"), "utf-8")
3135
2786
  );
3136
2787
  const registryUrl = new URL(registry);
3137
2788
  const npmrc = process.env.NPM_TOKEN ? {
@@ -3148,7 +2799,7 @@ async function emitRemote(spec, options) {
3148
2799
  }
3149
2800
  const packResult = execSync3("npm pack --pack-destination .", { cwd: path });
3150
2801
  const [tgzName] = packResult.toString().trim().split("\n");
3151
- await publish(manifest, await readFile4(join8(path, tgzName)), {
2802
+ await publish(manifest, await readFile4(join7(path, tgzName)), {
3152
2803
  registry,
3153
2804
  defaultTag: "latest",
3154
2805
  forceAuth: {
@@ -3161,65 +2812,9 @@ async function emitRemote(spec, options) {
3161
2812
 
3162
2813
  // packages/cli/src/lib/cli.ts
3163
2814
  var generate5 = new Command7("generate").description("Generate SDKs from configuration or OpenAPI").option("-c, --config <path>", "Path to an SDK-IT configuration file").action(async (options) => {
3164
- if (!options.config || options.config.endsWith(".ts")) {
3165
- try {
3166
- const config2 = await loadProjectConfig({ config: options.config });
3167
- await generateProject(config2);
3168
- console.log("Client generated successfully!");
3169
- return;
3170
- } catch (error) {
3171
- if (options.config || !(error instanceof Error) || !error.message.startsWith("Could not find sdk-it.config.ts")) {
3172
- throw error;
3173
- }
3174
- }
3175
- }
3176
- options.config ??= "sdk-it.json";
3177
- const config = await readJson2(options.config);
3178
- const promises = [];
3179
- if (config.generators?.typescript) {
3180
- promises.push(
3181
- runTypescript({
3182
- spec: config.generators.typescript.spec,
3183
- output: config.generators.typescript.output,
3184
- mode: config.generators.typescript.mode,
3185
- name: config.generators.typescript.name,
3186
- useTsExtension: config.generators.typescript.useTsExtension ?? true,
3187
- install: config.generators.typescript.install ?? false,
3188
- verbose: false,
3189
- defaultFormatter: config.generators.typescript.defaultFormatter ?? true,
3190
- readme: config.generators.typescript.readme ?? true,
3191
- pagination: config.generators.typescript.pagination
3192
- })
3193
- );
3194
- }
3195
- if (config.generators?.python) {
3196
- promises.push(
3197
- runPython({
3198
- spec: config.generators.python.spec,
3199
- output: config.generators.python.output,
3200
- mode: config.generators.python.mode,
3201
- name: config.generators.python.name,
3202
- verbose: false
3203
- })
3204
- );
3205
- }
3206
- if (config.generators?.dart) {
3207
- promises.push(
3208
- runDart({
3209
- spec: config.generators.dart.spec,
3210
- output: config.generators.dart.output,
3211
- mode: config.generators.dart.mode,
3212
- name: config.generators.dart.name,
3213
- verbose: false,
3214
- pagination: config.generators.dart.pagination
3215
- })
3216
- );
3217
- }
3218
- if (config.readme) {
3219
- promises.push(runReadme(config.readme.spec, config.readme.output));
3220
- }
3221
- await Promise.all(promises);
3222
- console.log("All configured generators completed successfully!");
2815
+ const config = await loadProjectConfig({ config: options.config });
2816
+ await generateProject(config);
2817
+ console.log("Client generated successfully!");
3223
2818
  }).addCommand(typescript_default).addCommand(python_default).addCommand(dart_default).addCommand(apiref_default).addCommand(readme_default);
3224
2819
  var cli = program.name("sdk-it").description(`CLI tool to interact with SDK-IT.`).addCommand(generate5, { isDefault: true }).addCommand(init_default).addCommand(
3225
2820
  new Command7("_internal").action(() => {