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.
- package/cli.cjs +104 -41
- package/index.d.ts +10 -1
- package/index.js +78 -31
- 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
|
|
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 =
|
|
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
|
|
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 =
|
|
416
|
-
const filePath =
|
|
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
|
|
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 =
|
|
542
|
-
const filePath =
|
|
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
|
|
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 =
|
|
684
|
-
const filePath =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
1071
|
-
const filePath =
|
|
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
|
|
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 =
|
|
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 =
|
|
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(([
|
|
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:
|
|
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((
|
|
2093
|
+
paths.forEach((path11) => {
|
|
2047
2094
|
let controllerName = "Default";
|
|
2048
|
-
if (
|
|
2049
|
-
controllerName =
|
|
2095
|
+
if (path11.tags && path11.tags.length > 0) {
|
|
2096
|
+
controllerName = path11.tags[0];
|
|
2050
2097
|
} else {
|
|
2051
|
-
const pathParts =
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
2271
|
-
const indexPath =
|
|
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.
|
|
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 =
|
|
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 =
|
|
2386
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
463
|
-
const filePath =
|
|
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
|
|
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 =
|
|
588
|
-
const filePath =
|
|
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
|
|
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 =
|
|
729
|
-
const filePath =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
1114
|
-
const filePath =
|
|
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
|
|
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 =
|
|
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 =
|
|
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(([
|
|
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:
|
|
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((
|
|
2144
|
+
paths.forEach((path10) => {
|
|
2098
2145
|
let controllerName = "Default";
|
|
2099
|
-
if (
|
|
2100
|
-
controllerName =
|
|
2146
|
+
if (path10.tags && path10.tags.length > 0) {
|
|
2147
|
+
controllerName = path10.tags[0];
|
|
2101
2148
|
} else {
|
|
2102
|
-
const pathParts =
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
2322
|
-
const indexPath =
|
|
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.
|
|
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",
|