ng-openapi 0.0.38 → 0.0.39
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 +102 -41
- package/index.d.ts +10 -1
- package/index.js +77 -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,12 +2021,20 @@ 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);
|
|
@@ -1997,7 +2043,7 @@ var ServiceGenerator = class {
|
|
|
1997
2043
|
extractPaths() {
|
|
1998
2044
|
const paths = [];
|
|
1999
2045
|
const swaggerPaths = this.spec.paths || {};
|
|
2000
|
-
Object.entries(swaggerPaths).forEach(([
|
|
2046
|
+
Object.entries(swaggerPaths).forEach(([path11, pathItem]) => {
|
|
2001
2047
|
const methods = [
|
|
2002
2048
|
"get",
|
|
2003
2049
|
"post",
|
|
@@ -2011,7 +2057,7 @@ var ServiceGenerator = class {
|
|
|
2011
2057
|
if (pathItem[method]) {
|
|
2012
2058
|
const operation = pathItem[method];
|
|
2013
2059
|
paths.push({
|
|
2014
|
-
path:
|
|
2060
|
+
path: path11,
|
|
2015
2061
|
method: method.toUpperCase(),
|
|
2016
2062
|
operationId: operation.operationId,
|
|
2017
2063
|
summary: operation.summary,
|
|
@@ -2043,12 +2089,12 @@ var ServiceGenerator = class {
|
|
|
2043
2089
|
}
|
|
2044
2090
|
groupPathsByController(paths) {
|
|
2045
2091
|
const groups = {};
|
|
2046
|
-
paths.forEach((
|
|
2092
|
+
paths.forEach((path11) => {
|
|
2047
2093
|
let controllerName = "Default";
|
|
2048
|
-
if (
|
|
2049
|
-
controllerName =
|
|
2094
|
+
if (path11.tags && path11.tags.length > 0) {
|
|
2095
|
+
controllerName = path11.tags[0];
|
|
2050
2096
|
} else {
|
|
2051
|
-
const pathParts =
|
|
2097
|
+
const pathParts = path11.path.split("/").filter((p) => p && !p.startsWith("{"));
|
|
2052
2098
|
if (pathParts.length > 1) {
|
|
2053
2099
|
controllerName = pascalCase(pathParts[1]);
|
|
2054
2100
|
}
|
|
@@ -2057,13 +2103,13 @@ var ServiceGenerator = class {
|
|
|
2057
2103
|
if (!groups[controllerName]) {
|
|
2058
2104
|
groups[controllerName] = [];
|
|
2059
2105
|
}
|
|
2060
|
-
groups[controllerName].push(
|
|
2106
|
+
groups[controllerName].push(path11);
|
|
2061
2107
|
});
|
|
2062
2108
|
return groups;
|
|
2063
2109
|
}
|
|
2064
2110
|
generateServiceFile(controllerName, operations, outputDir) {
|
|
2065
2111
|
const fileName = `${camelCase(controllerName)}.service.ts`;
|
|
2066
|
-
const filePath =
|
|
2112
|
+
const filePath = path8.join(outputDir, fileName);
|
|
2067
2113
|
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
2068
2114
|
overwrite: true
|
|
2069
2115
|
});
|
|
@@ -2257,7 +2303,7 @@ return context.set(this.clientContextToken, '${this.config.clientName || "defaul
|
|
|
2257
2303
|
|
|
2258
2304
|
// src/lib/generators/service/service-index.generator.ts
|
|
2259
2305
|
var fs2 = __toESM(require("fs"));
|
|
2260
|
-
var
|
|
2306
|
+
var path9 = __toESM(require("path"));
|
|
2261
2307
|
var ServiceIndexGenerator = class {
|
|
2262
2308
|
static {
|
|
2263
2309
|
__name(this, "ServiceIndexGenerator");
|
|
@@ -2267,8 +2313,8 @@ var ServiceIndexGenerator = class {
|
|
|
2267
2313
|
this.project = project;
|
|
2268
2314
|
}
|
|
2269
2315
|
generateIndex(outputRoot) {
|
|
2270
|
-
const servicesDir =
|
|
2271
|
-
const indexPath =
|
|
2316
|
+
const servicesDir = path9.join(outputRoot, "services");
|
|
2317
|
+
const indexPath = path9.join(servicesDir, "index.ts");
|
|
2272
2318
|
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
2273
2319
|
overwrite: true
|
|
2274
2320
|
});
|
|
@@ -2351,12 +2397,12 @@ async function generateFromConfig(config) {
|
|
|
2351
2397
|
__name(generateFromConfig, "generateFromConfig");
|
|
2352
2398
|
|
|
2353
2399
|
// package.json
|
|
2354
|
-
var version = "0.0.
|
|
2400
|
+
var version = "0.0.38";
|
|
2355
2401
|
|
|
2356
2402
|
// src/lib/cli.ts
|
|
2357
2403
|
var program = new import_commander.Command();
|
|
2358
2404
|
async function loadConfigFile(configPath) {
|
|
2359
|
-
const resolvedPath =
|
|
2405
|
+
const resolvedPath = path10.resolve(configPath);
|
|
2360
2406
|
if (!fs4.existsSync(resolvedPath)) {
|
|
2361
2407
|
throw new Error(`Configuration file not found: ${resolvedPath}`);
|
|
2362
2408
|
}
|
|
@@ -2376,17 +2422,30 @@ async function loadConfigFile(configPath) {
|
|
|
2376
2422
|
}
|
|
2377
2423
|
}
|
|
2378
2424
|
__name(loadConfigFile, "loadConfigFile");
|
|
2425
|
+
function validateInputFile(inputPath) {
|
|
2426
|
+
if (!fs4.existsSync(inputPath)) {
|
|
2427
|
+
throw new Error(`Input file not found: ${inputPath}`);
|
|
2428
|
+
}
|
|
2429
|
+
const extension = path10.extname(inputPath).toLowerCase();
|
|
2430
|
+
const supportedExtensions = [
|
|
2431
|
+
".json",
|
|
2432
|
+
".yaml",
|
|
2433
|
+
".yml"
|
|
2434
|
+
];
|
|
2435
|
+
if (!supportedExtensions.includes(extension)) {
|
|
2436
|
+
throw new Error(`Failed to parse ${extension || "specification"}. Supported formats are .json, .yaml, and .yml.`);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
__name(validateInputFile, "validateInputFile");
|
|
2379
2440
|
async function generateFromOptions(options) {
|
|
2380
2441
|
try {
|
|
2381
2442
|
if (options.config) {
|
|
2382
2443
|
const config = await loadConfigFile(options.config);
|
|
2444
|
+
validateInputFile(path10.resolve(config.input));
|
|
2383
2445
|
await generateFromConfig(config);
|
|
2384
2446
|
} else if (options.input) {
|
|
2385
|
-
const inputPath =
|
|
2386
|
-
|
|
2387
|
-
console.error(`Error: Input file not found: ${inputPath}`);
|
|
2388
|
-
process.exit(1);
|
|
2389
|
-
}
|
|
2447
|
+
const inputPath = path10.resolve(options.input);
|
|
2448
|
+
validateInputFile(inputPath);
|
|
2390
2449
|
const config = {
|
|
2391
2450
|
input: inputPath,
|
|
2392
2451
|
output: options.output || "./src/generated",
|
|
@@ -2410,10 +2469,10 @@ async function generateFromOptions(options) {
|
|
|
2410
2469
|
}
|
|
2411
2470
|
}
|
|
2412
2471
|
__name(generateFromOptions, "generateFromOptions");
|
|
2413
|
-
program.name("ng-openapi").description("Generate Angular services and types from Swagger
|
|
2472
|
+
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
2473
|
await generateFromOptions(options);
|
|
2415
2474
|
});
|
|
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
|
|
2475
|
+
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
2476
|
await generateFromOptions(options);
|
|
2418
2477
|
});
|
|
2419
2478
|
program.on("--help", () => {
|
|
@@ -2421,6 +2480,8 @@ program.on("--help", () => {
|
|
|
2421
2480
|
console.log("Examples:");
|
|
2422
2481
|
console.log(" $ ng-openapi -c ./openapi.config.ts");
|
|
2423
2482
|
console.log(" $ ng-openapi -i ./swagger.json -o ./src/api");
|
|
2483
|
+
console.log(" $ ng-openapi -i ./openapi.yaml -o ./src/api");
|
|
2484
|
+
console.log(" $ ng-openapi -i ./api-spec.yml -o ./src/api");
|
|
2424
2485
|
console.log(" $ ng-openapi generate -c ./openapi.config.ts");
|
|
2425
2486
|
console.log(" $ ng-openapi generate -i ./api.yaml --types-only");
|
|
2426
2487
|
});
|
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,12 +2072,20 @@ 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);
|
|
@@ -2048,7 +2094,7 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
2048
2094
|
extractPaths() {
|
|
2049
2095
|
const paths = [];
|
|
2050
2096
|
const swaggerPaths = this.spec.paths || {};
|
|
2051
|
-
Object.entries(swaggerPaths).forEach(([
|
|
2097
|
+
Object.entries(swaggerPaths).forEach(([path10, pathItem]) => {
|
|
2052
2098
|
const methods = [
|
|
2053
2099
|
"get",
|
|
2054
2100
|
"post",
|
|
@@ -2062,7 +2108,7 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
2062
2108
|
if (pathItem[method]) {
|
|
2063
2109
|
const operation = pathItem[method];
|
|
2064
2110
|
paths.push({
|
|
2065
|
-
path:
|
|
2111
|
+
path: path10,
|
|
2066
2112
|
method: method.toUpperCase(),
|
|
2067
2113
|
operationId: operation.operationId,
|
|
2068
2114
|
summary: operation.summary,
|
|
@@ -2094,12 +2140,12 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
2094
2140
|
}
|
|
2095
2141
|
groupPathsByController(paths) {
|
|
2096
2142
|
const groups = {};
|
|
2097
|
-
paths.forEach((
|
|
2143
|
+
paths.forEach((path10) => {
|
|
2098
2144
|
let controllerName = "Default";
|
|
2099
|
-
if (
|
|
2100
|
-
controllerName =
|
|
2145
|
+
if (path10.tags && path10.tags.length > 0) {
|
|
2146
|
+
controllerName = path10.tags[0];
|
|
2101
2147
|
} else {
|
|
2102
|
-
const pathParts =
|
|
2148
|
+
const pathParts = path10.path.split("/").filter((p) => p && !p.startsWith("{"));
|
|
2103
2149
|
if (pathParts.length > 1) {
|
|
2104
2150
|
controllerName = pascalCase(pathParts[1]);
|
|
2105
2151
|
}
|
|
@@ -2108,13 +2154,13 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
2108
2154
|
if (!groups[controllerName]) {
|
|
2109
2155
|
groups[controllerName] = [];
|
|
2110
2156
|
}
|
|
2111
|
-
groups[controllerName].push(
|
|
2157
|
+
groups[controllerName].push(path10);
|
|
2112
2158
|
});
|
|
2113
2159
|
return groups;
|
|
2114
2160
|
}
|
|
2115
2161
|
generateServiceFile(controllerName, operations, outputDir) {
|
|
2116
2162
|
const fileName = `${camelCase(controllerName)}.service.ts`;
|
|
2117
|
-
const filePath =
|
|
2163
|
+
const filePath = path8.join(outputDir, fileName);
|
|
2118
2164
|
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
2119
2165
|
overwrite: true
|
|
2120
2166
|
});
|
|
@@ -2311,15 +2357,15 @@ var ServiceGenerator = _ServiceGenerator;
|
|
|
2311
2357
|
|
|
2312
2358
|
// src/lib/generators/service/service-index.generator.ts
|
|
2313
2359
|
var fs2 = __toESM(require("fs"));
|
|
2314
|
-
var
|
|
2360
|
+
var path9 = __toESM(require("path"));
|
|
2315
2361
|
var _ServiceIndexGenerator = class _ServiceIndexGenerator {
|
|
2316
2362
|
constructor(project) {
|
|
2317
2363
|
__publicField(this, "project");
|
|
2318
2364
|
this.project = project;
|
|
2319
2365
|
}
|
|
2320
2366
|
generateIndex(outputRoot) {
|
|
2321
|
-
const servicesDir =
|
|
2322
|
-
const indexPath =
|
|
2367
|
+
const servicesDir = path9.join(outputRoot, "services");
|
|
2368
|
+
const indexPath = path9.join(servicesDir, "index.ts");
|
|
2323
2369
|
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
2324
2370
|
overwrite: true
|
|
2325
2371
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ng-openapi",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.39",
|
|
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",
|