ng-openapi 0.0.37 → 0.0.38-pr-7-feature-yaml-support.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 (4) hide show
  1. package/cli.cjs +104 -41
  2. package/index.d.ts +10 -1
  3. package/index.js +78 -31
  4. package/package.json +3 -2
package/cli.cjs CHANGED
@@ -26,11 +26,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
 
27
27
  // src/lib/cli.ts
28
28
  var import_commander = require("commander");
29
- var path9 = __toESM(require("path"));
29
+ var path10 = __toESM(require("path"));
30
30
  var fs4 = __toESM(require("fs"));
31
31
 
32
32
  // src/lib/core/swagger-parser.ts
33
33
  var fs = __toESM(require("fs"));
34
+ var path = __toESM(require("path"));
35
+ var yaml = __toESM(require("js-yaml"));
34
36
  var SwaggerParser = class {
35
37
  static {
36
38
  __name(this, "SwaggerParser");
@@ -38,7 +40,7 @@ var SwaggerParser = class {
38
40
  spec;
39
41
  constructor(swaggerPath) {
40
42
  const swaggerContent = fs.readFileSync(swaggerPath, "utf8");
41
- this.spec = JSON.parse(swaggerContent);
43
+ this.spec = this.parseSpecFile(swaggerContent, swaggerPath);
42
44
  }
43
45
  getDefinitions() {
44
46
  return this.spec.definitions || this.spec.components?.schemas || {};
@@ -55,6 +57,42 @@ var SwaggerParser = class {
55
57
  getAllDefinitionNames() {
56
58
  return Object.keys(this.getDefinitions());
57
59
  }
60
+ getSpec() {
61
+ return this.spec;
62
+ }
63
+ getPaths() {
64
+ return this.spec.paths || {};
65
+ }
66
+ isValidSpec() {
67
+ return !!(this.spec.swagger && this.spec.swagger.startsWith("2.") || this.spec.openapi && this.spec.openapi.startsWith("3."));
68
+ }
69
+ getSpecVersion() {
70
+ if (this.spec.swagger) {
71
+ return {
72
+ type: "swagger",
73
+ version: this.spec.swagger
74
+ };
75
+ }
76
+ if (this.spec.openapi) {
77
+ return {
78
+ type: "openapi",
79
+ version: this.spec.openapi
80
+ };
81
+ }
82
+ return null;
83
+ }
84
+ parseSpecFile(content, filePath) {
85
+ const extension = path.extname(filePath).toLowerCase();
86
+ switch (extension) {
87
+ case ".json":
88
+ return JSON.parse(content);
89
+ case ".yaml":
90
+ case ".yml":
91
+ return yaml.load(content);
92
+ default:
93
+ throw new Error(`Failed to parse ${extension || "specification"} file: ${filePath}. Supported formats are .json, .yaml, and .yml.`);
94
+ }
95
+ }
58
96
  };
59
97
 
60
98
  // src/lib/core/generator.ts
@@ -400,7 +438,7 @@ var TypeGenerator = class {
400
438
 
401
439
  // src/lib/generators/utility/token.generator.ts
402
440
  var import_ts_morph2 = require("ts-morph");
403
- var path = __toESM(require("path"));
441
+ var path2 = __toESM(require("path"));
404
442
  var TokenGenerator = class {
405
443
  static {
406
444
  __name(this, "TokenGenerator");
@@ -412,8 +450,8 @@ var TokenGenerator = class {
412
450
  this.clientName = clientName;
413
451
  }
414
452
  generate(outputDir) {
415
- const tokensDir = path.join(outputDir, "tokens");
416
- const filePath = path.join(tokensDir, "index.ts");
453
+ const tokensDir = path2.join(outputDir, "tokens");
454
+ const filePath = path2.join(tokensDir, "index.ts");
417
455
  const sourceFile = this.project.createSourceFile(filePath, "", {
418
456
  overwrite: true
419
457
  });
@@ -528,7 +566,7 @@ var TokenGenerator = class {
528
566
  };
529
567
 
530
568
  // src/lib/generators/utility/file-download.generator.ts
531
- var path2 = __toESM(require("path"));
569
+ var path3 = __toESM(require("path"));
532
570
  var FileDownloadGenerator = class {
533
571
  static {
534
572
  __name(this, "FileDownloadGenerator");
@@ -538,8 +576,8 @@ var FileDownloadGenerator = class {
538
576
  this.project = project;
539
577
  }
540
578
  generate(outputDir) {
541
- const utilsDir = path2.join(outputDir, "utils");
542
- const filePath = path2.join(utilsDir, "file-download.ts");
579
+ const utilsDir = path3.join(outputDir, "utils");
580
+ const filePath = path3.join(utilsDir, "file-download.ts");
543
581
  const sourceFile = this.project.createSourceFile(filePath, "", {
544
582
  overwrite: true
545
583
  });
@@ -670,7 +708,7 @@ var FileDownloadGenerator = class {
670
708
 
671
709
  // src/lib/generators/utility/date-transformer.generator.ts
672
710
  var import_ts_morph3 = require("ts-morph");
673
- var path3 = __toESM(require("path"));
711
+ var path4 = __toESM(require("path"));
674
712
  var DateTransformerGenerator = class {
675
713
  static {
676
714
  __name(this, "DateTransformerGenerator");
@@ -680,8 +718,8 @@ var DateTransformerGenerator = class {
680
718
  this.project = project;
681
719
  }
682
720
  generate(outputDir) {
683
- const utilsDir = path3.join(outputDir, "utils");
684
- const filePath = path3.join(utilsDir, "date-transformer.ts");
721
+ const utilsDir = path4.join(outputDir, "utils");
722
+ const filePath = path4.join(utilsDir, "date-transformer.ts");
685
723
  const sourceFile = this.project.createSourceFile(filePath, "", {
686
724
  overwrite: true
687
725
  });
@@ -804,7 +842,7 @@ var DateTransformerGenerator = class {
804
842
  };
805
843
 
806
844
  // src/lib/generators/utility/main-index.generator.ts
807
- var path4 = __toESM(require("path"));
845
+ var path5 = __toESM(require("path"));
808
846
  var MainIndexGenerator = class {
809
847
  static {
810
848
  __name(this, "MainIndexGenerator");
@@ -816,7 +854,7 @@ var MainIndexGenerator = class {
816
854
  this.config = config;
817
855
  }
818
856
  generateMainIndex(outputRoot) {
819
- const indexPath = path4.join(outputRoot, "index.ts");
857
+ const indexPath = path5.join(outputRoot, "index.ts");
820
858
  const sourceFile = this.project.createSourceFile(indexPath, "", {
821
859
  overwrite: true
822
860
  });
@@ -848,7 +886,7 @@ var MainIndexGenerator = class {
848
886
  };
849
887
 
850
888
  // src/lib/generators/utility/provider.generator.ts
851
- var path5 = __toESM(require("path"));
889
+ var path6 = __toESM(require("path"));
852
890
  var ProviderGenerator = class {
853
891
  static {
854
892
  __name(this, "ProviderGenerator");
@@ -862,7 +900,7 @@ var ProviderGenerator = class {
862
900
  this.clientName = config.clientName || "default";
863
901
  }
864
902
  generate(outputDir) {
865
- const filePath = path5.join(outputDir, "providers.ts");
903
+ const filePath = path6.join(outputDir, "providers.ts");
866
904
  const sourceFile = this.project.createSourceFile(filePath, "", {
867
905
  overwrite: true
868
906
  });
@@ -1055,7 +1093,7 @@ return makeEnvironmentProviders(providers);`;
1055
1093
 
1056
1094
  // src/lib/generators/utility/base-interceptor.generator.ts
1057
1095
  var import_ts_morph4 = require("ts-morph");
1058
- var path6 = __toESM(require("path"));
1096
+ var path7 = __toESM(require("path"));
1059
1097
  var BaseInterceptorGenerator = class {
1060
1098
  static {
1061
1099
  __name(this, "BaseInterceptorGenerator");
@@ -1067,8 +1105,8 @@ var BaseInterceptorGenerator = class {
1067
1105
  this.#clientName = clientName;
1068
1106
  }
1069
1107
  generate(outputDir) {
1070
- const utilsDir = path6.join(outputDir, "utils");
1071
- const filePath = path6.join(utilsDir, "base-interceptor.ts");
1108
+ const utilsDir = path7.join(outputDir, "utils");
1109
+ const filePath = path7.join(utilsDir, "base-interceptor.ts");
1072
1110
  const sourceFile = this.#project.createSourceFile(filePath, "", {
1073
1111
  overwrite: true
1074
1112
  });
@@ -1187,7 +1225,7 @@ var BaseInterceptorGenerator = class {
1187
1225
 
1188
1226
  // src/lib/generators/service/service.generator.ts
1189
1227
  var import_ts_morph5 = require("ts-morph");
1190
- var path7 = __toESM(require("path"));
1228
+ var path8 = __toESM(require("path"));
1191
1229
 
1192
1230
  // src/lib/utils/string.utils.ts
1193
1231
  function camelCase(str) {
@@ -1983,21 +2021,30 @@ var ServiceGenerator = class {
1983
2021
  this.config = config;
1984
2022
  this.project = project;
1985
2023
  this.parser = new SwaggerParser(swaggerPath);
1986
- this.spec = JSON.parse(require("fs").readFileSync(swaggerPath, "utf8"));
2024
+ this.spec = this.parser.getSpec();
2025
+ if (!this.parser.isValidSpec()) {
2026
+ const versionInfo = this.parser.getSpecVersion();
2027
+ throw new Error(`Invalid or unsupported specification format. Expected OpenAPI 3.x or Swagger 2.x. ${versionInfo ? `Found: ${versionInfo.type} ${versionInfo.version}` : "No version info found"}`);
2028
+ }
1987
2029
  this.methodGenerator = new ServiceMethodGenerator(config);
1988
2030
  }
1989
2031
  generate(outputRoot) {
1990
- const outputDir = path7.join(outputRoot, "services");
2032
+ const outputDir = path8.join(outputRoot, "services");
1991
2033
  const paths = this.extractPaths();
2034
+ if (paths.length === 0) {
2035
+ console.warn("No API paths found in the specification");
2036
+ return;
2037
+ }
1992
2038
  const controllerGroups = this.groupPathsByController(paths);
1993
2039
  Object.entries(controllerGroups).forEach(([controllerName, operations]) => {
1994
2040
  this.generateServiceFile(controllerName, operations, outputDir);
1995
2041
  });
2042
+ console.log(`Generated ${Object.keys(controllerGroups).length} service(s) from ${paths.length} path(s)`);
1996
2043
  }
1997
2044
  extractPaths() {
1998
2045
  const paths = [];
1999
2046
  const swaggerPaths = this.spec.paths || {};
2000
- Object.entries(swaggerPaths).forEach(([path10, pathItem]) => {
2047
+ Object.entries(swaggerPaths).forEach(([path11, pathItem]) => {
2001
2048
  const methods = [
2002
2049
  "get",
2003
2050
  "post",
@@ -2011,7 +2058,7 @@ var ServiceGenerator = class {
2011
2058
  if (pathItem[method]) {
2012
2059
  const operation = pathItem[method];
2013
2060
  paths.push({
2014
- path: path10,
2061
+ path: path11,
2015
2062
  method: method.toUpperCase(),
2016
2063
  operationId: operation.operationId,
2017
2064
  summary: operation.summary,
@@ -2043,12 +2090,12 @@ var ServiceGenerator = class {
2043
2090
  }
2044
2091
  groupPathsByController(paths) {
2045
2092
  const groups = {};
2046
- paths.forEach((path10) => {
2093
+ paths.forEach((path11) => {
2047
2094
  let controllerName = "Default";
2048
- if (path10.tags && path10.tags.length > 0) {
2049
- controllerName = path10.tags[0];
2095
+ if (path11.tags && path11.tags.length > 0) {
2096
+ controllerName = path11.tags[0];
2050
2097
  } else {
2051
- const pathParts = path10.path.split("/").filter((p) => p && !p.startsWith("{"));
2098
+ const pathParts = path11.path.split("/").filter((p) => p && !p.startsWith("{"));
2052
2099
  if (pathParts.length > 1) {
2053
2100
  controllerName = pascalCase(pathParts[1]);
2054
2101
  }
@@ -2057,13 +2104,13 @@ var ServiceGenerator = class {
2057
2104
  if (!groups[controllerName]) {
2058
2105
  groups[controllerName] = [];
2059
2106
  }
2060
- groups[controllerName].push(path10);
2107
+ groups[controllerName].push(path11);
2061
2108
  });
2062
2109
  return groups;
2063
2110
  }
2064
2111
  generateServiceFile(controllerName, operations, outputDir) {
2065
2112
  const fileName = `${camelCase(controllerName)}.service.ts`;
2066
- const filePath = path7.join(outputDir, fileName);
2113
+ const filePath = path8.join(outputDir, fileName);
2067
2114
  const sourceFile = this.project.createSourceFile(filePath, "", {
2068
2115
  overwrite: true
2069
2116
  });
@@ -2257,7 +2304,7 @@ return context.set(this.clientContextToken, '${this.config.clientName || "defaul
2257
2304
 
2258
2305
  // src/lib/generators/service/service-index.generator.ts
2259
2306
  var fs2 = __toESM(require("fs"));
2260
- var path8 = __toESM(require("path"));
2307
+ var path9 = __toESM(require("path"));
2261
2308
  var ServiceIndexGenerator = class {
2262
2309
  static {
2263
2310
  __name(this, "ServiceIndexGenerator");
@@ -2267,8 +2314,8 @@ var ServiceIndexGenerator = class {
2267
2314
  this.project = project;
2268
2315
  }
2269
2316
  generateIndex(outputRoot) {
2270
- const servicesDir = path8.join(outputRoot, "services");
2271
- const indexPath = path8.join(servicesDir, "index.ts");
2317
+ const servicesDir = path9.join(outputRoot, "services");
2318
+ const indexPath = path9.join(servicesDir, "index.ts");
2272
2319
  const sourceFile = this.project.createSourceFile(indexPath, "", {
2273
2320
  overwrite: true
2274
2321
  });
@@ -2351,12 +2398,12 @@ async function generateFromConfig(config) {
2351
2398
  __name(generateFromConfig, "generateFromConfig");
2352
2399
 
2353
2400
  // package.json
2354
- var version = "0.0.36";
2401
+ var version = "0.0.37";
2355
2402
 
2356
2403
  // src/lib/cli.ts
2357
2404
  var program = new import_commander.Command();
2358
2405
  async function loadConfigFile(configPath) {
2359
- const resolvedPath = path9.resolve(configPath);
2406
+ const resolvedPath = path10.resolve(configPath);
2360
2407
  if (!fs4.existsSync(resolvedPath)) {
2361
2408
  throw new Error(`Configuration file not found: ${resolvedPath}`);
2362
2409
  }
@@ -2376,17 +2423,31 @@ async function loadConfigFile(configPath) {
2376
2423
  }
2377
2424
  }
2378
2425
  __name(loadConfigFile, "loadConfigFile");
2426
+ function validateInputFile(inputPath) {
2427
+ if (!fs4.existsSync(inputPath)) {
2428
+ throw new Error(`Input file not found: ${inputPath}`);
2429
+ }
2430
+ const extension = path10.extname(inputPath).toLowerCase();
2431
+ const supportedExtensions = [
2432
+ ".json",
2433
+ ".yaml",
2434
+ ".yml"
2435
+ ];
2436
+ if (!supportedExtensions.includes(extension)) {
2437
+ console.warn(`Warning: File extension '${extension}' is not explicitly supported. Supported extensions: ${supportedExtensions.join(", ")}`);
2438
+ console.warn("The parser will attempt to auto-detect the format.");
2439
+ }
2440
+ }
2441
+ __name(validateInputFile, "validateInputFile");
2379
2442
  async function generateFromOptions(options) {
2380
2443
  try {
2381
2444
  if (options.config) {
2382
2445
  const config = await loadConfigFile(options.config);
2446
+ validateInputFile(path10.resolve(config.input));
2383
2447
  await generateFromConfig(config);
2384
2448
  } else if (options.input) {
2385
- const inputPath = path9.resolve(options.input);
2386
- if (!fs4.existsSync(inputPath)) {
2387
- console.error(`Error: Input file not found: ${inputPath}`);
2388
- process.exit(1);
2389
- }
2449
+ const inputPath = path10.resolve(options.input);
2450
+ validateInputFile(inputPath);
2390
2451
  const config = {
2391
2452
  input: inputPath,
2392
2453
  output: options.output || "./src/generated",
@@ -2410,10 +2471,10 @@ async function generateFromOptions(options) {
2410
2471
  }
2411
2472
  }
2412
2473
  __name(generateFromOptions, "generateFromOptions");
2413
- program.name("ng-openapi").description("Generate Angular services and types from Swagger/OpenAPI spec").version(version).option("-c, --config <path>", "Path to configuration file").option("-i, --input <path>", "Path to Swagger/OpenAPI specification file").option("-o, --output <path>", "Output directory", "./src/generated").option("--types-only", "Generate only TypeScript interfaces").option("--date-type <type>", "Date type to use (string | Date)", "Date").action(async (options) => {
2474
+ program.name("ng-openapi").description("Generate Angular services and types from OpenAPI/Swagger specifications (JSON, YAML, YML)").version(version).option("-c, --config <path>", "Path to configuration file").option("-i, --input <path>", "Path to OpenAPI/Swagger specification file (.json, .yaml, .yml)").option("-o, --output <path>", "Output directory", "./src/generated").option("--types-only", "Generate only TypeScript interfaces").option("--date-type <type>", "Date type to use (string | Date)", "Date").action(async (options) => {
2414
2475
  await generateFromOptions(options);
2415
2476
  });
2416
- program.command("generate").alias("gen").description("Generate code from Swagger specification").option("-c, --config <path>", "Path to configuration file").option("-i, --input <path>", "Path to Swagger/OpenAPI specification file").option("-o, --output <path>", "Output directory", "./src/generated").option("--types-only", "Generate only TypeScript interfaces").option("--date-type <type>", "Date type to use (string | Date)", "Date").action(async (options) => {
2477
+ program.command("generate").alias("gen").description("Generate code from OpenAPI/Swagger specification").option("-c, --config <path>", "Path to configuration file").option("-i, --input <path>", "Path to OpenAPI/Swagger specification file (.json, .yaml, .yml)").option("-o, --output <path>", "Output directory", "./src/generated").option("--types-only", "Generate only TypeScript interfaces").option("--date-type <type>", "Date type to use (string | Date)", "Date").action(async (options) => {
2417
2478
  await generateFromOptions(options);
2418
2479
  });
2419
2480
  program.on("--help", () => {
@@ -2421,6 +2482,8 @@ program.on("--help", () => {
2421
2482
  console.log("Examples:");
2422
2483
  console.log(" $ ng-openapi -c ./openapi.config.ts");
2423
2484
  console.log(" $ ng-openapi -i ./swagger.json -o ./src/api");
2485
+ console.log(" $ ng-openapi -i ./openapi.yaml -o ./src/api");
2486
+ console.log(" $ ng-openapi -i ./api-spec.yml -o ./src/api");
2424
2487
  console.log(" $ ng-openapi generate -c ./openapi.config.ts");
2425
2488
  console.log(" $ ng-openapi generate -i ./api.yaml --types-only");
2426
2489
  });
package/index.d.ts CHANGED
@@ -125,6 +125,7 @@ interface SwaggerDefinition {
125
125
  anyOf?: SwaggerDefinition[];
126
126
  }
127
127
  interface SwaggerSpec {
128
+ openapi: string;
128
129
  swagger: string;
129
130
  info: Info;
130
131
  externalDocs?: ExternalDocs | undefined;
@@ -162,12 +163,20 @@ type EnumValueObject = {
162
163
  };
163
164
 
164
165
  declare class SwaggerParser {
165
- private spec;
166
+ private readonly spec;
166
167
  constructor(swaggerPath: string);
167
168
  getDefinitions(): Record<string, SwaggerDefinition>;
168
169
  getDefinition(name: string): SwaggerDefinition | undefined;
169
170
  resolveReference(ref: string): SwaggerDefinition | undefined;
170
171
  getAllDefinitionNames(): string[];
172
+ getSpec(): SwaggerSpec;
173
+ getPaths(): Record<string, any>;
174
+ isValidSpec(): boolean;
175
+ getSpecVersion(): {
176
+ type: "swagger" | "openapi";
177
+ version: string;
178
+ } | null;
179
+ private parseSpecFile;
171
180
  }
172
181
 
173
182
  /**
package/index.js CHANGED
@@ -80,11 +80,13 @@ module.exports = __toCommonJS(index_exports);
80
80
 
81
81
  // src/lib/core/swagger-parser.ts
82
82
  var fs = __toESM(require("fs"));
83
+ var path = __toESM(require("path"));
84
+ var yaml = __toESM(require("js-yaml"));
83
85
  var _SwaggerParser = class _SwaggerParser {
84
86
  constructor(swaggerPath) {
85
87
  __publicField(this, "spec");
86
88
  const swaggerContent = fs.readFileSync(swaggerPath, "utf8");
87
- this.spec = JSON.parse(swaggerContent);
89
+ this.spec = this.parseSpecFile(swaggerContent, swaggerPath);
88
90
  }
89
91
  getDefinitions() {
90
92
  var _a;
@@ -102,6 +104,42 @@ var _SwaggerParser = class _SwaggerParser {
102
104
  getAllDefinitionNames() {
103
105
  return Object.keys(this.getDefinitions());
104
106
  }
107
+ getSpec() {
108
+ return this.spec;
109
+ }
110
+ getPaths() {
111
+ return this.spec.paths || {};
112
+ }
113
+ isValidSpec() {
114
+ return !!(this.spec.swagger && this.spec.swagger.startsWith("2.") || this.spec.openapi && this.spec.openapi.startsWith("3."));
115
+ }
116
+ getSpecVersion() {
117
+ if (this.spec.swagger) {
118
+ return {
119
+ type: "swagger",
120
+ version: this.spec.swagger
121
+ };
122
+ }
123
+ if (this.spec.openapi) {
124
+ return {
125
+ type: "openapi",
126
+ version: this.spec.openapi
127
+ };
128
+ }
129
+ return null;
130
+ }
131
+ parseSpecFile(content, filePath) {
132
+ const extension = path.extname(filePath).toLowerCase();
133
+ switch (extension) {
134
+ case ".json":
135
+ return JSON.parse(content);
136
+ case ".yaml":
137
+ case ".yml":
138
+ return yaml.load(content);
139
+ default:
140
+ throw new Error(`Failed to parse ${extension || "specification"} file: ${filePath}. Supported formats are .json, .yaml, and .yml.`);
141
+ }
142
+ }
105
143
  };
106
144
  __name(_SwaggerParser, "SwaggerParser");
107
145
  var SwaggerParser = _SwaggerParser;
@@ -450,7 +488,7 @@ var TypeGenerator = _TypeGenerator;
450
488
 
451
489
  // src/lib/generators/utility/token.generator.ts
452
490
  var import_ts_morph2 = require("ts-morph");
453
- var path = __toESM(require("path"));
491
+ var path2 = __toESM(require("path"));
454
492
  var _TokenGenerator = class _TokenGenerator {
455
493
  constructor(project, clientName = "default") {
456
494
  __publicField(this, "project");
@@ -459,8 +497,8 @@ var _TokenGenerator = class _TokenGenerator {
459
497
  this.clientName = clientName;
460
498
  }
461
499
  generate(outputDir) {
462
- const tokensDir = path.join(outputDir, "tokens");
463
- const filePath = path.join(tokensDir, "index.ts");
500
+ const tokensDir = path2.join(outputDir, "tokens");
501
+ const filePath = path2.join(tokensDir, "index.ts");
464
502
  const sourceFile = this.project.createSourceFile(filePath, "", {
465
503
  overwrite: true
466
504
  });
@@ -577,15 +615,15 @@ __name(_TokenGenerator, "TokenGenerator");
577
615
  var TokenGenerator = _TokenGenerator;
578
616
 
579
617
  // src/lib/generators/utility/file-download.generator.ts
580
- var path2 = __toESM(require("path"));
618
+ var path3 = __toESM(require("path"));
581
619
  var _FileDownloadGenerator = class _FileDownloadGenerator {
582
620
  constructor(project) {
583
621
  __publicField(this, "project");
584
622
  this.project = project;
585
623
  }
586
624
  generate(outputDir) {
587
- const utilsDir = path2.join(outputDir, "utils");
588
- const filePath = path2.join(utilsDir, "file-download.ts");
625
+ const utilsDir = path3.join(outputDir, "utils");
626
+ const filePath = path3.join(utilsDir, "file-download.ts");
589
627
  const sourceFile = this.project.createSourceFile(filePath, "", {
590
628
  overwrite: true
591
629
  });
@@ -718,15 +756,15 @@ var FileDownloadGenerator = _FileDownloadGenerator;
718
756
 
719
757
  // src/lib/generators/utility/date-transformer.generator.ts
720
758
  var import_ts_morph3 = require("ts-morph");
721
- var path3 = __toESM(require("path"));
759
+ var path4 = __toESM(require("path"));
722
760
  var _DateTransformerGenerator = class _DateTransformerGenerator {
723
761
  constructor(project) {
724
762
  __publicField(this, "project");
725
763
  this.project = project;
726
764
  }
727
765
  generate(outputDir) {
728
- const utilsDir = path3.join(outputDir, "utils");
729
- const filePath = path3.join(utilsDir, "date-transformer.ts");
766
+ const utilsDir = path4.join(outputDir, "utils");
767
+ const filePath = path4.join(utilsDir, "date-transformer.ts");
730
768
  const sourceFile = this.project.createSourceFile(filePath, "", {
731
769
  overwrite: true
732
770
  });
@@ -851,7 +889,7 @@ __name(_DateTransformerGenerator, "DateTransformerGenerator");
851
889
  var DateTransformerGenerator = _DateTransformerGenerator;
852
890
 
853
891
  // src/lib/generators/utility/main-index.generator.ts
854
- var path4 = __toESM(require("path"));
892
+ var path5 = __toESM(require("path"));
855
893
  var _MainIndexGenerator = class _MainIndexGenerator {
856
894
  constructor(project, config) {
857
895
  __publicField(this, "project");
@@ -860,7 +898,7 @@ var _MainIndexGenerator = class _MainIndexGenerator {
860
898
  this.config = config;
861
899
  }
862
900
  generateMainIndex(outputRoot) {
863
- const indexPath = path4.join(outputRoot, "index.ts");
901
+ const indexPath = path5.join(outputRoot, "index.ts");
864
902
  const sourceFile = this.project.createSourceFile(indexPath, "", {
865
903
  overwrite: true
866
904
  });
@@ -894,7 +932,7 @@ __name(_MainIndexGenerator, "MainIndexGenerator");
894
932
  var MainIndexGenerator = _MainIndexGenerator;
895
933
 
896
934
  // src/lib/generators/utility/provider.generator.ts
897
- var path5 = __toESM(require("path"));
935
+ var path6 = __toESM(require("path"));
898
936
  var _ProviderGenerator = class _ProviderGenerator {
899
937
  constructor(project, config) {
900
938
  __publicField(this, "project");
@@ -905,7 +943,7 @@ var _ProviderGenerator = class _ProviderGenerator {
905
943
  this.clientName = config.clientName || "default";
906
944
  }
907
945
  generate(outputDir) {
908
- const filePath = path5.join(outputDir, "providers.ts");
946
+ const filePath = path6.join(outputDir, "providers.ts");
909
947
  const sourceFile = this.project.createSourceFile(filePath, "", {
910
948
  overwrite: true
911
949
  });
@@ -1100,7 +1138,7 @@ var ProviderGenerator = _ProviderGenerator;
1100
1138
 
1101
1139
  // src/lib/generators/utility/base-interceptor.generator.ts
1102
1140
  var import_ts_morph4 = require("ts-morph");
1103
- var path6 = __toESM(require("path"));
1141
+ var path7 = __toESM(require("path"));
1104
1142
  var _project, _clientName;
1105
1143
  var _BaseInterceptorGenerator = class _BaseInterceptorGenerator {
1106
1144
  constructor(project, clientName = "default") {
@@ -1110,8 +1148,8 @@ var _BaseInterceptorGenerator = class _BaseInterceptorGenerator {
1110
1148
  __privateSet(this, _clientName, clientName);
1111
1149
  }
1112
1150
  generate(outputDir) {
1113
- const utilsDir = path6.join(outputDir, "utils");
1114
- const filePath = path6.join(utilsDir, "base-interceptor.ts");
1151
+ const utilsDir = path7.join(outputDir, "utils");
1152
+ const filePath = path7.join(utilsDir, "base-interceptor.ts");
1115
1153
  const sourceFile = __privateGet(this, _project).createSourceFile(filePath, "", {
1116
1154
  overwrite: true
1117
1155
  });
@@ -1234,7 +1272,7 @@ var BaseInterceptorGenerator = _BaseInterceptorGenerator;
1234
1272
 
1235
1273
  // src/lib/generators/service/service.generator.ts
1236
1274
  var import_ts_morph5 = require("ts-morph");
1237
- var path7 = __toESM(require("path"));
1275
+ var path8 = __toESM(require("path"));
1238
1276
 
1239
1277
  // src/lib/utils/string.utils.ts
1240
1278
  function camelCase(str) {
@@ -2034,21 +2072,30 @@ var _ServiceGenerator = class _ServiceGenerator {
2034
2072
  this.config = config;
2035
2073
  this.project = project;
2036
2074
  this.parser = new SwaggerParser(swaggerPath);
2037
- this.spec = JSON.parse(require("fs").readFileSync(swaggerPath, "utf8"));
2075
+ this.spec = this.parser.getSpec();
2076
+ if (!this.parser.isValidSpec()) {
2077
+ const versionInfo = this.parser.getSpecVersion();
2078
+ throw new Error(`Invalid or unsupported specification format. Expected OpenAPI 3.x or Swagger 2.x. ${versionInfo ? `Found: ${versionInfo.type} ${versionInfo.version}` : "No version info found"}`);
2079
+ }
2038
2080
  this.methodGenerator = new ServiceMethodGenerator(config);
2039
2081
  }
2040
2082
  generate(outputRoot) {
2041
- const outputDir = path7.join(outputRoot, "services");
2083
+ const outputDir = path8.join(outputRoot, "services");
2042
2084
  const paths = this.extractPaths();
2085
+ if (paths.length === 0) {
2086
+ console.warn("No API paths found in the specification");
2087
+ return;
2088
+ }
2043
2089
  const controllerGroups = this.groupPathsByController(paths);
2044
2090
  Object.entries(controllerGroups).forEach(([controllerName, operations]) => {
2045
2091
  this.generateServiceFile(controllerName, operations, outputDir);
2046
2092
  });
2093
+ console.log(`Generated ${Object.keys(controllerGroups).length} service(s) from ${paths.length} path(s)`);
2047
2094
  }
2048
2095
  extractPaths() {
2049
2096
  const paths = [];
2050
2097
  const swaggerPaths = this.spec.paths || {};
2051
- Object.entries(swaggerPaths).forEach(([path9, pathItem]) => {
2098
+ Object.entries(swaggerPaths).forEach(([path10, pathItem]) => {
2052
2099
  const methods = [
2053
2100
  "get",
2054
2101
  "post",
@@ -2062,7 +2109,7 @@ var _ServiceGenerator = class _ServiceGenerator {
2062
2109
  if (pathItem[method]) {
2063
2110
  const operation = pathItem[method];
2064
2111
  paths.push({
2065
- path: path9,
2112
+ path: path10,
2066
2113
  method: method.toUpperCase(),
2067
2114
  operationId: operation.operationId,
2068
2115
  summary: operation.summary,
@@ -2094,12 +2141,12 @@ var _ServiceGenerator = class _ServiceGenerator {
2094
2141
  }
2095
2142
  groupPathsByController(paths) {
2096
2143
  const groups = {};
2097
- paths.forEach((path9) => {
2144
+ paths.forEach((path10) => {
2098
2145
  let controllerName = "Default";
2099
- if (path9.tags && path9.tags.length > 0) {
2100
- controllerName = path9.tags[0];
2146
+ if (path10.tags && path10.tags.length > 0) {
2147
+ controllerName = path10.tags[0];
2101
2148
  } else {
2102
- const pathParts = path9.path.split("/").filter((p) => p && !p.startsWith("{"));
2149
+ const pathParts = path10.path.split("/").filter((p) => p && !p.startsWith("{"));
2103
2150
  if (pathParts.length > 1) {
2104
2151
  controllerName = pascalCase(pathParts[1]);
2105
2152
  }
@@ -2108,13 +2155,13 @@ var _ServiceGenerator = class _ServiceGenerator {
2108
2155
  if (!groups[controllerName]) {
2109
2156
  groups[controllerName] = [];
2110
2157
  }
2111
- groups[controllerName].push(path9);
2158
+ groups[controllerName].push(path10);
2112
2159
  });
2113
2160
  return groups;
2114
2161
  }
2115
2162
  generateServiceFile(controllerName, operations, outputDir) {
2116
2163
  const fileName = `${camelCase(controllerName)}.service.ts`;
2117
- const filePath = path7.join(outputDir, fileName);
2164
+ const filePath = path8.join(outputDir, fileName);
2118
2165
  const sourceFile = this.project.createSourceFile(filePath, "", {
2119
2166
  overwrite: true
2120
2167
  });
@@ -2311,15 +2358,15 @@ var ServiceGenerator = _ServiceGenerator;
2311
2358
 
2312
2359
  // src/lib/generators/service/service-index.generator.ts
2313
2360
  var fs2 = __toESM(require("fs"));
2314
- var path8 = __toESM(require("path"));
2361
+ var path9 = __toESM(require("path"));
2315
2362
  var _ServiceIndexGenerator = class _ServiceIndexGenerator {
2316
2363
  constructor(project) {
2317
2364
  __publicField(this, "project");
2318
2365
  this.project = project;
2319
2366
  }
2320
2367
  generateIndex(outputRoot) {
2321
- const servicesDir = path8.join(outputRoot, "services");
2322
- const indexPath = path8.join(servicesDir, "index.ts");
2368
+ const servicesDir = path9.join(outputRoot, "services");
2369
+ const indexPath = path9.join(servicesDir, "index.ts");
2323
2370
  const sourceFile = this.project.createSourceFile(indexPath, "", {
2324
2371
  overwrite: true
2325
2372
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-openapi",
3
- "version": "0.0.37",
3
+ "version": "0.0.38-pr-7-feature-yaml-support.0",
4
4
  "description": "Generate Angular services and TypeScript types from OpenAPI/Swagger specifications",
5
5
  "keywords": [
6
6
  "angular",
@@ -61,7 +61,8 @@
61
61
  "ts-morph": "^26.0.0",
62
62
  "ts-node": "^10.9.2",
63
63
  "typescript": "^5.8.3",
64
- "@types/swagger-schema-official": "^2.0.25"
64
+ "@types/swagger-schema-official": "^2.0.25",
65
+ "js-yaml": "^4.1.0"
65
66
  },
66
67
  "peerDependencies": {
67
68
  "@angular/core": ">=15",