ng-openapi 0.0.39 → 0.0.40-pr-8-feature-url-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 +185 -45
- package/index.d.ts +7 -2
- package/index.js +162 -32
- package/package.json +1 -1
package/cli.cjs
CHANGED
|
@@ -33,14 +33,18 @@ var fs4 = __toESM(require("fs"));
|
|
|
33
33
|
var fs = __toESM(require("fs"));
|
|
34
34
|
var path = __toESM(require("path"));
|
|
35
35
|
var yaml = __toESM(require("js-yaml"));
|
|
36
|
-
var SwaggerParser = class {
|
|
36
|
+
var SwaggerParser = class _SwaggerParser {
|
|
37
37
|
static {
|
|
38
38
|
__name(this, "SwaggerParser");
|
|
39
39
|
}
|
|
40
40
|
spec;
|
|
41
|
-
constructor(
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
constructor(spec) {
|
|
42
|
+
this.spec = spec;
|
|
43
|
+
}
|
|
44
|
+
static async create(swaggerPathOrUrl) {
|
|
45
|
+
const swaggerContent = await _SwaggerParser.loadContent(swaggerPathOrUrl);
|
|
46
|
+
const spec = _SwaggerParser.parseSpecContent(swaggerContent, swaggerPathOrUrl);
|
|
47
|
+
return new _SwaggerParser(spec);
|
|
44
48
|
}
|
|
45
49
|
getDefinitions() {
|
|
46
50
|
return this.spec.definitions || this.spec.components?.schemas || {};
|
|
@@ -81,17 +85,100 @@ var SwaggerParser = class {
|
|
|
81
85
|
}
|
|
82
86
|
return null;
|
|
83
87
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
static async loadContent(pathOrUrl) {
|
|
89
|
+
if (_SwaggerParser.isUrl(pathOrUrl)) {
|
|
90
|
+
return await _SwaggerParser.fetchUrlContent(pathOrUrl);
|
|
91
|
+
} else {
|
|
92
|
+
return fs.readFileSync(pathOrUrl, "utf8");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
static isUrl(input) {
|
|
96
|
+
try {
|
|
97
|
+
new URL(input);
|
|
98
|
+
return true;
|
|
99
|
+
} catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
static async fetchUrlContent(url) {
|
|
104
|
+
try {
|
|
105
|
+
const response = await fetch(url, {
|
|
106
|
+
method: "GET",
|
|
107
|
+
headers: {
|
|
108
|
+
"Accept": "application/json, application/yaml, text/yaml, text/plain, */*",
|
|
109
|
+
"User-Agent": "ng-openapi"
|
|
110
|
+
},
|
|
111
|
+
// 30 second timeout
|
|
112
|
+
signal: AbortSignal.timeout(3e4)
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
116
|
+
}
|
|
117
|
+
const content = await response.text();
|
|
118
|
+
if (!content || content.trim() === "") {
|
|
119
|
+
throw new Error(`Empty response from URL: ${url}`);
|
|
120
|
+
}
|
|
121
|
+
return content;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
let errorMessage = `Failed to fetch content from URL: ${url}`;
|
|
124
|
+
if (error.name === "AbortError") {
|
|
125
|
+
errorMessage += " - Request timeout (30s)";
|
|
126
|
+
} else if (error.message) {
|
|
127
|
+
errorMessage += ` - ${error.message}`;
|
|
128
|
+
}
|
|
129
|
+
throw new Error(errorMessage);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
static parseSpecContent(content, pathOrUrl) {
|
|
133
|
+
let format;
|
|
134
|
+
if (_SwaggerParser.isUrl(pathOrUrl)) {
|
|
135
|
+
const urlPath = new URL(pathOrUrl).pathname.toLowerCase();
|
|
136
|
+
if (urlPath.endsWith(".json")) {
|
|
137
|
+
format = "json";
|
|
138
|
+
} else if (urlPath.endsWith(".yaml") || urlPath.endsWith(".yml")) {
|
|
139
|
+
format = "yaml";
|
|
140
|
+
} else {
|
|
141
|
+
format = _SwaggerParser.detectFormat(content);
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
const extension = path.extname(pathOrUrl).toLowerCase();
|
|
145
|
+
switch (extension) {
|
|
146
|
+
case ".json":
|
|
147
|
+
format = "json";
|
|
148
|
+
break;
|
|
149
|
+
case ".yaml":
|
|
150
|
+
format = "yaml";
|
|
151
|
+
break;
|
|
152
|
+
case ".yml":
|
|
153
|
+
format = "yml";
|
|
154
|
+
break;
|
|
155
|
+
default:
|
|
156
|
+
format = _SwaggerParser.detectFormat(content);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
switch (format) {
|
|
161
|
+
case "json":
|
|
162
|
+
return JSON.parse(content);
|
|
163
|
+
case "yaml":
|
|
164
|
+
case "yml":
|
|
165
|
+
return yaml.load(content);
|
|
166
|
+
default:
|
|
167
|
+
throw new Error(`Unable to determine format for: ${pathOrUrl}`);
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
throw new Error(`Failed to parse ${format.toUpperCase()} content from: ${pathOrUrl}. Error: ${error instanceof Error ? error.message : error}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
static detectFormat(content) {
|
|
174
|
+
const trimmed = content.trim();
|
|
175
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
176
|
+
return "json";
|
|
94
177
|
}
|
|
178
|
+
if (trimmed.includes("openapi:") || trimmed.includes("swagger:") || trimmed.includes("---") || /^[a-zA-Z][a-zA-Z0-9_]*\s*:/.test(trimmed)) {
|
|
179
|
+
return "yaml";
|
|
180
|
+
}
|
|
181
|
+
return "json";
|
|
95
182
|
}
|
|
96
183
|
};
|
|
97
184
|
|
|
@@ -137,7 +224,7 @@ var BASE_INTERCEPTOR_HEADER_COMMENT = /* @__PURE__ */ __name((clientName) => def
|
|
|
137
224
|
`, "BASE_INTERCEPTOR_HEADER_COMMENT");
|
|
138
225
|
|
|
139
226
|
// src/lib/generators/type/type.generator.ts
|
|
140
|
-
var TypeGenerator = class {
|
|
227
|
+
var TypeGenerator = class _TypeGenerator {
|
|
141
228
|
static {
|
|
142
229
|
__name(this, "TypeGenerator");
|
|
143
230
|
}
|
|
@@ -146,7 +233,7 @@ var TypeGenerator = class {
|
|
|
146
233
|
sourceFile;
|
|
147
234
|
generatedTypes = /* @__PURE__ */ new Set();
|
|
148
235
|
config;
|
|
149
|
-
constructor(
|
|
236
|
+
constructor(parser, outputRoot, config) {
|
|
150
237
|
this.config = config;
|
|
151
238
|
const outputPath = outputRoot + "/models/index.ts";
|
|
152
239
|
this.project = new import_ts_morph.Project({
|
|
@@ -158,15 +245,14 @@ var TypeGenerator = class {
|
|
|
158
245
|
...this.config.compilerOptions
|
|
159
246
|
}
|
|
160
247
|
});
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
248
|
+
this.parser = parser;
|
|
249
|
+
this.sourceFile = this.project.createSourceFile(outputPath, "", {
|
|
250
|
+
overwrite: true
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
static async create(swaggerPathOrUrl, outputRoot, config) {
|
|
254
|
+
const parser = await SwaggerParser.create(swaggerPathOrUrl);
|
|
255
|
+
return new _TypeGenerator(parser, outputRoot, config);
|
|
170
256
|
}
|
|
171
257
|
generate() {
|
|
172
258
|
try {
|
|
@@ -2008,7 +2094,7 @@ var ServiceMethodGenerator = class {
|
|
|
2008
2094
|
};
|
|
2009
2095
|
|
|
2010
2096
|
// src/lib/generators/service/service.generator.ts
|
|
2011
|
-
var ServiceGenerator = class {
|
|
2097
|
+
var ServiceGenerator = class _ServiceGenerator {
|
|
2012
2098
|
static {
|
|
2013
2099
|
__name(this, "ServiceGenerator");
|
|
2014
2100
|
}
|
|
@@ -2017,10 +2103,10 @@ var ServiceGenerator = class {
|
|
|
2017
2103
|
spec;
|
|
2018
2104
|
config;
|
|
2019
2105
|
methodGenerator;
|
|
2020
|
-
constructor(
|
|
2106
|
+
constructor(parser, project, config) {
|
|
2021
2107
|
this.config = config;
|
|
2022
2108
|
this.project = project;
|
|
2023
|
-
this.parser =
|
|
2109
|
+
this.parser = parser;
|
|
2024
2110
|
this.spec = this.parser.getSpec();
|
|
2025
2111
|
if (!this.parser.isValidSpec()) {
|
|
2026
2112
|
const versionInfo = this.parser.getSpecVersion();
|
|
@@ -2028,6 +2114,10 @@ var ServiceGenerator = class {
|
|
|
2028
2114
|
}
|
|
2029
2115
|
this.methodGenerator = new ServiceMethodGenerator(config);
|
|
2030
2116
|
}
|
|
2117
|
+
static async create(swaggerPathOrUrl, project, config) {
|
|
2118
|
+
const parser = await SwaggerParser.create(swaggerPathOrUrl);
|
|
2119
|
+
return new _ServiceGenerator(parser, project, config);
|
|
2120
|
+
}
|
|
2031
2121
|
generate(outputRoot) {
|
|
2032
2122
|
const outputDir = path8.join(outputRoot, "services");
|
|
2033
2123
|
const paths = this.extractPaths();
|
|
@@ -2335,12 +2425,36 @@ var ServiceIndexGenerator = class {
|
|
|
2335
2425
|
|
|
2336
2426
|
// src/lib/core/generator.ts
|
|
2337
2427
|
var fs3 = __toESM(require("fs"));
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2428
|
+
function isUrl(input) {
|
|
2429
|
+
try {
|
|
2430
|
+
new URL(input);
|
|
2431
|
+
return true;
|
|
2432
|
+
} catch {
|
|
2433
|
+
return false;
|
|
2341
2434
|
}
|
|
2435
|
+
}
|
|
2436
|
+
__name(isUrl, "isUrl");
|
|
2437
|
+
function validateInput(input) {
|
|
2438
|
+
if (isUrl(input)) {
|
|
2439
|
+
const url = new URL(input);
|
|
2440
|
+
if (![
|
|
2441
|
+
"http:",
|
|
2442
|
+
"https:"
|
|
2443
|
+
].includes(url.protocol)) {
|
|
2444
|
+
throw new Error(`Unsupported URL protocol: ${url.protocol}. Only HTTP and HTTPS are supported.`);
|
|
2445
|
+
}
|
|
2446
|
+
} else {
|
|
2447
|
+
if (!fs3.existsSync(input)) {
|
|
2448
|
+
throw new Error(`Input file not found: ${input}`);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
__name(validateInput, "validateInput");
|
|
2453
|
+
async function generateFromConfig(config) {
|
|
2454
|
+
validateInput(config.input);
|
|
2342
2455
|
const outputPath = config.output;
|
|
2343
2456
|
const generateServices = config.options.generateServices ?? true;
|
|
2457
|
+
const inputType = isUrl(config.input) ? "URL" : "file";
|
|
2344
2458
|
if (!fs3.existsSync(outputPath)) {
|
|
2345
2459
|
fs3.mkdirSync(outputPath, {
|
|
2346
2460
|
recursive: true
|
|
@@ -2356,7 +2470,8 @@ async function generateFromConfig(config) {
|
|
|
2356
2470
|
...config.compilerOptions
|
|
2357
2471
|
}
|
|
2358
2472
|
});
|
|
2359
|
-
|
|
2473
|
+
console.log(`\u{1F4E1} Processing OpenAPI specification from ${inputType}: ${config.input}`);
|
|
2474
|
+
const typeGenerator = await TypeGenerator.create(config.input, outputPath, config);
|
|
2360
2475
|
typeGenerator.generate();
|
|
2361
2476
|
console.log(`\u2705 TypeScript interfaces generated`);
|
|
2362
2477
|
if (generateServices) {
|
|
@@ -2368,7 +2483,7 @@ async function generateFromConfig(config) {
|
|
|
2368
2483
|
}
|
|
2369
2484
|
const fileDownloadHelper = new FileDownloadGenerator(project);
|
|
2370
2485
|
fileDownloadHelper.generate(outputPath);
|
|
2371
|
-
const serviceGenerator =
|
|
2486
|
+
const serviceGenerator = await ServiceGenerator.create(config.input, project, config);
|
|
2372
2487
|
serviceGenerator.generate(outputPath);
|
|
2373
2488
|
const indexGenerator = new ServiceIndexGenerator(project);
|
|
2374
2489
|
indexGenerator.generateIndex(outputPath);
|
|
@@ -2380,14 +2495,19 @@ async function generateFromConfig(config) {
|
|
|
2380
2495
|
}
|
|
2381
2496
|
const mainIndexGenerator = new MainIndexGenerator(project, config);
|
|
2382
2497
|
mainIndexGenerator.generateMainIndex(outputPath);
|
|
2498
|
+
const sourceInfo = `from ${inputType}: ${config.input}`;
|
|
2383
2499
|
if (config.clientName) {
|
|
2384
|
-
console.log(`\u{1F389} ${config.clientName} Generation completed successfully
|
|
2500
|
+
console.log(`\u{1F389} ${config.clientName} Generation completed successfully ${sourceInfo} -> ${outputPath}`);
|
|
2385
2501
|
} else {
|
|
2386
|
-
console.log(
|
|
2502
|
+
console.log(`\u{1F389} Generation completed successfully ${sourceInfo} -> ${outputPath}`);
|
|
2387
2503
|
}
|
|
2388
2504
|
} catch (error) {
|
|
2389
2505
|
if (error instanceof Error) {
|
|
2390
2506
|
console.error("\u274C Error during generation:", error.message);
|
|
2507
|
+
if (error.message.includes("fetch") || error.message.includes("Failed to fetch")) {
|
|
2508
|
+
console.error("\u{1F4A1} Tip: Make sure the URL is accessible and returns a valid OpenAPI/Swagger specification");
|
|
2509
|
+
console.error("\u{1F4A1} Alternative: Download the specification file locally and use the file path instead");
|
|
2510
|
+
}
|
|
2391
2511
|
} else {
|
|
2392
2512
|
console.error("\u274C Unknown error during generation:", error);
|
|
2393
2513
|
}
|
|
@@ -2397,7 +2517,7 @@ async function generateFromConfig(config) {
|
|
|
2397
2517
|
__name(generateFromConfig, "generateFromConfig");
|
|
2398
2518
|
|
|
2399
2519
|
// package.json
|
|
2400
|
-
var version = "0.0.
|
|
2520
|
+
var version = "0.0.39";
|
|
2401
2521
|
|
|
2402
2522
|
// src/lib/cli.ts
|
|
2403
2523
|
var program = new import_commander.Command();
|
|
@@ -2422,7 +2542,26 @@ async function loadConfigFile(configPath) {
|
|
|
2422
2542
|
}
|
|
2423
2543
|
}
|
|
2424
2544
|
__name(loadConfigFile, "loadConfigFile");
|
|
2425
|
-
function
|
|
2545
|
+
function isUrl2(input) {
|
|
2546
|
+
try {
|
|
2547
|
+
new URL(input);
|
|
2548
|
+
return true;
|
|
2549
|
+
} catch {
|
|
2550
|
+
return false;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
__name(isUrl2, "isUrl");
|
|
2554
|
+
function validateInput2(inputPath) {
|
|
2555
|
+
if (isUrl2(inputPath)) {
|
|
2556
|
+
const url = new URL(inputPath);
|
|
2557
|
+
if (![
|
|
2558
|
+
"http:",
|
|
2559
|
+
"https:"
|
|
2560
|
+
].includes(url.protocol)) {
|
|
2561
|
+
throw new Error(`Unsupported URL protocol: ${url.protocol}. Only HTTP and HTTPS are supported.`);
|
|
2562
|
+
}
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2426
2565
|
if (!fs4.existsSync(inputPath)) {
|
|
2427
2566
|
throw new Error(`Input file not found: ${inputPath}`);
|
|
2428
2567
|
}
|
|
@@ -2436,18 +2575,17 @@ function validateInputFile(inputPath) {
|
|
|
2436
2575
|
throw new Error(`Failed to parse ${extension || "specification"}. Supported formats are .json, .yaml, and .yml.`);
|
|
2437
2576
|
}
|
|
2438
2577
|
}
|
|
2439
|
-
__name(
|
|
2578
|
+
__name(validateInput2, "validateInput");
|
|
2440
2579
|
async function generateFromOptions(options) {
|
|
2441
2580
|
try {
|
|
2442
2581
|
if (options.config) {
|
|
2443
2582
|
const config = await loadConfigFile(options.config);
|
|
2444
|
-
|
|
2583
|
+
validateInput2(config.input);
|
|
2445
2584
|
await generateFromConfig(config);
|
|
2446
2585
|
} else if (options.input) {
|
|
2447
|
-
|
|
2448
|
-
validateInputFile(inputPath);
|
|
2586
|
+
validateInput2(options.input);
|
|
2449
2587
|
const config = {
|
|
2450
|
-
input:
|
|
2588
|
+
input: options.input,
|
|
2451
2589
|
output: options.output || "./src/generated",
|
|
2452
2590
|
options: {
|
|
2453
2591
|
dateType: options.dateType || "Date",
|
|
@@ -2469,10 +2607,10 @@ async function generateFromOptions(options) {
|
|
|
2469
2607
|
}
|
|
2470
2608
|
}
|
|
2471
2609
|
__name(generateFromOptions, "generateFromOptions");
|
|
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
|
|
2610
|
+
program.name("ng-openapi").description("Generate Angular services and types from OpenAPI/Swagger specifications (JSON, YAML, YML) from files or URLs").version(version).option("-c, --config <path>", "Path to configuration file").option("-i, --input <path>", "Path or URL to OpenAPI/Swagger specification (.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) => {
|
|
2473
2611
|
await generateFromOptions(options);
|
|
2474
2612
|
});
|
|
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
|
|
2613
|
+
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 or URL to OpenAPI/Swagger specification (.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) => {
|
|
2476
2614
|
await generateFromOptions(options);
|
|
2477
2615
|
});
|
|
2478
2616
|
program.on("--help", () => {
|
|
@@ -2482,8 +2620,10 @@ program.on("--help", () => {
|
|
|
2482
2620
|
console.log(" $ ng-openapi -i ./swagger.json -o ./src/api");
|
|
2483
2621
|
console.log(" $ ng-openapi -i ./openapi.yaml -o ./src/api");
|
|
2484
2622
|
console.log(" $ ng-openapi -i ./api-spec.yml -o ./src/api");
|
|
2623
|
+
console.log(" $ ng-openapi -i https://api.example.com/openapi.json -o ./src/api");
|
|
2624
|
+
console.log(" $ ng-openapi -i https://petstore.swagger.io/v2/swagger.json -o ./src/api");
|
|
2485
2625
|
console.log(" $ ng-openapi generate -c ./openapi.config.ts");
|
|
2486
|
-
console.log(" $ ng-openapi generate -i
|
|
2626
|
+
console.log(" $ ng-openapi generate -i https://api.example.com/swagger.yaml --types-only");
|
|
2487
2627
|
});
|
|
2488
2628
|
program.parse();
|
|
2489
2629
|
//# sourceMappingURL=cli.cjs.map
|
package/index.d.ts
CHANGED
|
@@ -164,7 +164,8 @@ type EnumValueObject = {
|
|
|
164
164
|
|
|
165
165
|
declare class SwaggerParser {
|
|
166
166
|
private readonly spec;
|
|
167
|
-
constructor(
|
|
167
|
+
private constructor();
|
|
168
|
+
static create(swaggerPathOrUrl: string): Promise<SwaggerParser>;
|
|
168
169
|
getDefinitions(): Record<string, SwaggerDefinition>;
|
|
169
170
|
getDefinition(name: string): SwaggerDefinition | undefined;
|
|
170
171
|
resolveReference(ref: string): SwaggerDefinition | undefined;
|
|
@@ -176,7 +177,11 @@ declare class SwaggerParser {
|
|
|
176
177
|
type: "swagger" | "openapi";
|
|
177
178
|
version: string;
|
|
178
179
|
} | null;
|
|
179
|
-
private
|
|
180
|
+
private static loadContent;
|
|
181
|
+
private static isUrl;
|
|
182
|
+
private static fetchUrlContent;
|
|
183
|
+
private static parseSpecContent;
|
|
184
|
+
private static detectFormat;
|
|
180
185
|
}
|
|
181
186
|
|
|
182
187
|
/**
|
package/index.js
CHANGED
|
@@ -83,10 +83,16 @@ var fs = __toESM(require("fs"));
|
|
|
83
83
|
var path = __toESM(require("path"));
|
|
84
84
|
var yaml = __toESM(require("js-yaml"));
|
|
85
85
|
var _SwaggerParser = class _SwaggerParser {
|
|
86
|
-
constructor(
|
|
86
|
+
constructor(spec) {
|
|
87
87
|
__publicField(this, "spec");
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
this.spec = spec;
|
|
89
|
+
}
|
|
90
|
+
static create(swaggerPathOrUrl) {
|
|
91
|
+
return __async(this, null, function* () {
|
|
92
|
+
const swaggerContent = yield _SwaggerParser.loadContent(swaggerPathOrUrl);
|
|
93
|
+
const spec = _SwaggerParser.parseSpecContent(swaggerContent, swaggerPathOrUrl);
|
|
94
|
+
return new _SwaggerParser(spec);
|
|
95
|
+
});
|
|
90
96
|
}
|
|
91
97
|
getDefinitions() {
|
|
92
98
|
var _a;
|
|
@@ -128,18 +134,105 @@ var _SwaggerParser = class _SwaggerParser {
|
|
|
128
134
|
}
|
|
129
135
|
return null;
|
|
130
136
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
static loadContent(pathOrUrl) {
|
|
138
|
+
return __async(this, null, function* () {
|
|
139
|
+
if (_SwaggerParser.isUrl(pathOrUrl)) {
|
|
140
|
+
return yield _SwaggerParser.fetchUrlContent(pathOrUrl);
|
|
141
|
+
} else {
|
|
142
|
+
return fs.readFileSync(pathOrUrl, "utf8");
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
static isUrl(input) {
|
|
147
|
+
try {
|
|
148
|
+
new URL(input);
|
|
149
|
+
return true;
|
|
150
|
+
} catch (e) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
static fetchUrlContent(url) {
|
|
155
|
+
return __async(this, null, function* () {
|
|
156
|
+
try {
|
|
157
|
+
const response = yield fetch(url, {
|
|
158
|
+
method: "GET",
|
|
159
|
+
headers: {
|
|
160
|
+
"Accept": "application/json, application/yaml, text/yaml, text/plain, */*",
|
|
161
|
+
"User-Agent": "ng-openapi"
|
|
162
|
+
},
|
|
163
|
+
// 30 second timeout
|
|
164
|
+
signal: AbortSignal.timeout(3e4)
|
|
165
|
+
});
|
|
166
|
+
if (!response.ok) {
|
|
167
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
168
|
+
}
|
|
169
|
+
const content = yield response.text();
|
|
170
|
+
if (!content || content.trim() === "") {
|
|
171
|
+
throw new Error(`Empty response from URL: ${url}`);
|
|
172
|
+
}
|
|
173
|
+
return content;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
let errorMessage = `Failed to fetch content from URL: ${url}`;
|
|
176
|
+
if (error.name === "AbortError") {
|
|
177
|
+
errorMessage += " - Request timeout (30s)";
|
|
178
|
+
} else if (error.message) {
|
|
179
|
+
errorMessage += ` - ${error.message}`;
|
|
180
|
+
}
|
|
181
|
+
throw new Error(errorMessage);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
static parseSpecContent(content, pathOrUrl) {
|
|
186
|
+
let format;
|
|
187
|
+
if (_SwaggerParser.isUrl(pathOrUrl)) {
|
|
188
|
+
const urlPath = new URL(pathOrUrl).pathname.toLowerCase();
|
|
189
|
+
if (urlPath.endsWith(".json")) {
|
|
190
|
+
format = "json";
|
|
191
|
+
} else if (urlPath.endsWith(".yaml") || urlPath.endsWith(".yml")) {
|
|
192
|
+
format = "yaml";
|
|
193
|
+
} else {
|
|
194
|
+
format = _SwaggerParser.detectFormat(content);
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
const extension = path.extname(pathOrUrl).toLowerCase();
|
|
198
|
+
switch (extension) {
|
|
199
|
+
case ".json":
|
|
200
|
+
format = "json";
|
|
201
|
+
break;
|
|
202
|
+
case ".yaml":
|
|
203
|
+
format = "yaml";
|
|
204
|
+
break;
|
|
205
|
+
case ".yml":
|
|
206
|
+
format = "yml";
|
|
207
|
+
break;
|
|
208
|
+
default:
|
|
209
|
+
format = _SwaggerParser.detectFormat(content);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
switch (format) {
|
|
214
|
+
case "json":
|
|
215
|
+
return JSON.parse(content);
|
|
216
|
+
case "yaml":
|
|
217
|
+
case "yml":
|
|
218
|
+
return yaml.load(content);
|
|
219
|
+
default:
|
|
220
|
+
throw new Error(`Unable to determine format for: ${pathOrUrl}`);
|
|
221
|
+
}
|
|
222
|
+
} catch (error) {
|
|
223
|
+
throw new Error(`Failed to parse ${format.toUpperCase()} content from: ${pathOrUrl}. Error: ${error instanceof Error ? error.message : error}`);
|
|
141
224
|
}
|
|
142
225
|
}
|
|
226
|
+
static detectFormat(content) {
|
|
227
|
+
const trimmed = content.trim();
|
|
228
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
229
|
+
return "json";
|
|
230
|
+
}
|
|
231
|
+
if (trimmed.includes("openapi:") || trimmed.includes("swagger:") || trimmed.includes("---") || /^[a-zA-Z][a-zA-Z0-9_]*\s*:/.test(trimmed)) {
|
|
232
|
+
return "yaml";
|
|
233
|
+
}
|
|
234
|
+
return "json";
|
|
235
|
+
}
|
|
143
236
|
};
|
|
144
237
|
__name(_SwaggerParser, "SwaggerParser");
|
|
145
238
|
var SwaggerParser = _SwaggerParser;
|
|
@@ -187,7 +280,7 @@ var BASE_INTERCEPTOR_HEADER_COMMENT = /* @__PURE__ */ __name((clientName) => def
|
|
|
187
280
|
|
|
188
281
|
// src/lib/generators/type/type.generator.ts
|
|
189
282
|
var _TypeGenerator = class _TypeGenerator {
|
|
190
|
-
constructor(
|
|
283
|
+
constructor(parser, outputRoot, config) {
|
|
191
284
|
__publicField(this, "project");
|
|
192
285
|
__publicField(this, "parser");
|
|
193
286
|
__publicField(this, "sourceFile");
|
|
@@ -203,15 +296,16 @@ var _TypeGenerator = class _TypeGenerator {
|
|
|
203
296
|
strict: true
|
|
204
297
|
}, this.config.compilerOptions)
|
|
205
298
|
});
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
299
|
+
this.parser = parser;
|
|
300
|
+
this.sourceFile = this.project.createSourceFile(outputPath, "", {
|
|
301
|
+
overwrite: true
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
static create(swaggerPathOrUrl, outputRoot, config) {
|
|
305
|
+
return __async(this, null, function* () {
|
|
306
|
+
const parser = yield SwaggerParser.create(swaggerPathOrUrl);
|
|
307
|
+
return new _TypeGenerator(parser, outputRoot, config);
|
|
308
|
+
});
|
|
215
309
|
}
|
|
216
310
|
generate() {
|
|
217
311
|
try {
|
|
@@ -2063,7 +2157,7 @@ var ServiceMethodGenerator = _ServiceMethodGenerator;
|
|
|
2063
2157
|
|
|
2064
2158
|
// src/lib/generators/service/service.generator.ts
|
|
2065
2159
|
var _ServiceGenerator = class _ServiceGenerator {
|
|
2066
|
-
constructor(
|
|
2160
|
+
constructor(parser, project, config) {
|
|
2067
2161
|
__publicField(this, "project");
|
|
2068
2162
|
__publicField(this, "parser");
|
|
2069
2163
|
__publicField(this, "spec");
|
|
@@ -2071,7 +2165,7 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
2071
2165
|
__publicField(this, "methodGenerator");
|
|
2072
2166
|
this.config = config;
|
|
2073
2167
|
this.project = project;
|
|
2074
|
-
this.parser =
|
|
2168
|
+
this.parser = parser;
|
|
2075
2169
|
this.spec = this.parser.getSpec();
|
|
2076
2170
|
if (!this.parser.isValidSpec()) {
|
|
2077
2171
|
const versionInfo = this.parser.getSpecVersion();
|
|
@@ -2079,6 +2173,12 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
2079
2173
|
}
|
|
2080
2174
|
this.methodGenerator = new ServiceMethodGenerator(config);
|
|
2081
2175
|
}
|
|
2176
|
+
static create(swaggerPathOrUrl, project, config) {
|
|
2177
|
+
return __async(this, null, function* () {
|
|
2178
|
+
const parser = yield SwaggerParser.create(swaggerPathOrUrl);
|
|
2179
|
+
return new _ServiceGenerator(parser, project, config);
|
|
2180
|
+
});
|
|
2181
|
+
}
|
|
2082
2182
|
generate(outputRoot) {
|
|
2083
2183
|
const outputDir = path8.join(outputRoot, "services");
|
|
2084
2184
|
const paths = this.extractPaths();
|
|
@@ -2388,14 +2488,38 @@ var ServiceIndexGenerator = _ServiceIndexGenerator;
|
|
|
2388
2488
|
|
|
2389
2489
|
// src/lib/core/generator.ts
|
|
2390
2490
|
var fs3 = __toESM(require("fs"));
|
|
2491
|
+
function isUrl(input) {
|
|
2492
|
+
try {
|
|
2493
|
+
new URL(input);
|
|
2494
|
+
return true;
|
|
2495
|
+
} catch (e) {
|
|
2496
|
+
return false;
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
__name(isUrl, "isUrl");
|
|
2500
|
+
function validateInput(input) {
|
|
2501
|
+
if (isUrl(input)) {
|
|
2502
|
+
const url = new URL(input);
|
|
2503
|
+
if (![
|
|
2504
|
+
"http:",
|
|
2505
|
+
"https:"
|
|
2506
|
+
].includes(url.protocol)) {
|
|
2507
|
+
throw new Error(`Unsupported URL protocol: ${url.protocol}. Only HTTP and HTTPS are supported.`);
|
|
2508
|
+
}
|
|
2509
|
+
} else {
|
|
2510
|
+
if (!fs3.existsSync(input)) {
|
|
2511
|
+
throw new Error(`Input file not found: ${input}`);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
__name(validateInput, "validateInput");
|
|
2391
2516
|
function generateFromConfig(config) {
|
|
2392
2517
|
return __async(this, null, function* () {
|
|
2393
2518
|
var _a;
|
|
2394
|
-
|
|
2395
|
-
throw new Error(`Input file not found: ${config.input}`);
|
|
2396
|
-
}
|
|
2519
|
+
validateInput(config.input);
|
|
2397
2520
|
const outputPath = config.output;
|
|
2398
2521
|
const generateServices = (_a = config.options.generateServices) != null ? _a : true;
|
|
2522
|
+
const inputType = isUrl(config.input) ? "URL" : "file";
|
|
2399
2523
|
if (!fs3.existsSync(outputPath)) {
|
|
2400
2524
|
fs3.mkdirSync(outputPath, {
|
|
2401
2525
|
recursive: true
|
|
@@ -2410,7 +2534,8 @@ function generateFromConfig(config) {
|
|
|
2410
2534
|
strict: true
|
|
2411
2535
|
}, config.compilerOptions)
|
|
2412
2536
|
});
|
|
2413
|
-
|
|
2537
|
+
console.log(`\u{1F4E1} Processing OpenAPI specification from ${inputType}: ${config.input}`);
|
|
2538
|
+
const typeGenerator = yield TypeGenerator.create(config.input, outputPath, config);
|
|
2414
2539
|
typeGenerator.generate();
|
|
2415
2540
|
console.log(`\u2705 TypeScript interfaces generated`);
|
|
2416
2541
|
if (generateServices) {
|
|
@@ -2422,7 +2547,7 @@ function generateFromConfig(config) {
|
|
|
2422
2547
|
}
|
|
2423
2548
|
const fileDownloadHelper = new FileDownloadGenerator(project);
|
|
2424
2549
|
fileDownloadHelper.generate(outputPath);
|
|
2425
|
-
const serviceGenerator =
|
|
2550
|
+
const serviceGenerator = yield ServiceGenerator.create(config.input, project, config);
|
|
2426
2551
|
serviceGenerator.generate(outputPath);
|
|
2427
2552
|
const indexGenerator = new ServiceIndexGenerator(project);
|
|
2428
2553
|
indexGenerator.generateIndex(outputPath);
|
|
@@ -2434,14 +2559,19 @@ function generateFromConfig(config) {
|
|
|
2434
2559
|
}
|
|
2435
2560
|
const mainIndexGenerator = new MainIndexGenerator(project, config);
|
|
2436
2561
|
mainIndexGenerator.generateMainIndex(outputPath);
|
|
2562
|
+
const sourceInfo = `from ${inputType}: ${config.input}`;
|
|
2437
2563
|
if (config.clientName) {
|
|
2438
|
-
console.log(`\u{1F389} ${config.clientName} Generation completed successfully
|
|
2564
|
+
console.log(`\u{1F389} ${config.clientName} Generation completed successfully ${sourceInfo} -> ${outputPath}`);
|
|
2439
2565
|
} else {
|
|
2440
|
-
console.log(
|
|
2566
|
+
console.log(`\u{1F389} Generation completed successfully ${sourceInfo} -> ${outputPath}`);
|
|
2441
2567
|
}
|
|
2442
2568
|
} catch (error) {
|
|
2443
2569
|
if (error instanceof Error) {
|
|
2444
2570
|
console.error("\u274C Error during generation:", error.message);
|
|
2571
|
+
if (error.message.includes("fetch") || error.message.includes("Failed to fetch")) {
|
|
2572
|
+
console.error("\u{1F4A1} Tip: Make sure the URL is accessible and returns a valid OpenAPI/Swagger specification");
|
|
2573
|
+
console.error("\u{1F4A1} Alternative: Download the specification file locally and use the file path instead");
|
|
2574
|
+
}
|
|
2445
2575
|
} else {
|
|
2446
2576
|
console.error("\u274C Unknown error during generation:", error);
|
|
2447
2577
|
}
|