@ng-openapi/http-resource 0.0.11 → 0.0.12
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/index.cjs +48 -205
- package/index.d.ts +2 -3
- package/index.js +48 -205
- package/package.json +1 -1
package/index.cjs
CHANGED
|
@@ -40,12 +40,11 @@ var import_ts_morph = require("ts-morph");
|
|
|
40
40
|
|
|
41
41
|
// ../../shared/src/utils/string.utils.ts
|
|
42
42
|
function camelCase(str2) {
|
|
43
|
-
|
|
44
|
-
return cleaned.charAt(0).toLowerCase() + cleaned.slice(1);
|
|
43
|
+
return str2.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toLowerCase());
|
|
45
44
|
}
|
|
46
45
|
__name(camelCase, "camelCase");
|
|
47
46
|
function pascalCase(str2) {
|
|
48
|
-
return str2.replace(/
|
|
47
|
+
return str2.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toUpperCase());
|
|
49
48
|
}
|
|
50
49
|
__name(pascalCase, "pascalCase");
|
|
51
50
|
|
|
@@ -216,12 +215,12 @@ function extractPaths(swaggerPaths = {}, methods = [
|
|
|
216
215
|
"head"
|
|
217
216
|
]) {
|
|
218
217
|
const paths = [];
|
|
219
|
-
Object.entries(swaggerPaths).forEach(([
|
|
218
|
+
Object.entries(swaggerPaths).forEach(([path3, pathItem]) => {
|
|
220
219
|
methods.forEach((method) => {
|
|
221
220
|
if (pathItem[method]) {
|
|
222
221
|
const operation = pathItem[method];
|
|
223
222
|
paths.push({
|
|
224
|
-
path:
|
|
223
|
+
path: path3,
|
|
225
224
|
method: method.toUpperCase(),
|
|
226
225
|
operationId: operation.operationId,
|
|
227
226
|
summary: operation.summary,
|
|
@@ -369,6 +368,12 @@ function inferResponseTypeFromContentType(contentType) {
|
|
|
369
368
|
__name(inferResponseTypeFromContentType, "inferResponseTypeFromContentType");
|
|
370
369
|
function getResponseType(response, config) {
|
|
371
370
|
const responseType = getResponseTypeFromResponse(response);
|
|
371
|
+
const content = response.content || {};
|
|
372
|
+
for (const [contentType, mediaType] of Object.entries(content)) {
|
|
373
|
+
if (mediaType?.schema) {
|
|
374
|
+
return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
372
377
|
switch (responseType) {
|
|
373
378
|
case "blob":
|
|
374
379
|
return "Blob";
|
|
@@ -376,15 +381,6 @@ function getResponseType(response, config) {
|
|
|
376
381
|
return "ArrayBuffer";
|
|
377
382
|
case "text":
|
|
378
383
|
return "string";
|
|
379
|
-
case "json": {
|
|
380
|
-
const content = response.content || {};
|
|
381
|
-
for (const [contentType, mediaType] of Object.entries(content)) {
|
|
382
|
-
if (inferResponseTypeFromContentType(contentType) === "json" && mediaType?.schema) {
|
|
383
|
-
return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
return "any";
|
|
387
|
-
}
|
|
388
384
|
default:
|
|
389
385
|
return "any";
|
|
390
386
|
}
|
|
@@ -423,10 +419,6 @@ var HTTP_RESOURCE_GENERATOR_HEADER_COMMENT = /* @__PURE__ */ __name((resourceNam
|
|
|
423
419
|
*/
|
|
424
420
|
`, "HTTP_RESOURCE_GENERATOR_HEADER_COMMENT");
|
|
425
421
|
|
|
426
|
-
// ../../shared/src/core/swagger-parser.ts
|
|
427
|
-
var fs = __toESM(require("fs"));
|
|
428
|
-
var path = __toESM(require("path"));
|
|
429
|
-
|
|
430
422
|
// ../../../node_modules/js-yaml/dist/js-yaml.mjs
|
|
431
423
|
function isNothing(subject) {
|
|
432
424
|
return typeof subject === "undefined" || subject === null;
|
|
@@ -3125,168 +3117,8 @@ var safeLoad = renamed("safeLoad", "load");
|
|
|
3125
3117
|
var safeLoadAll = renamed("safeLoadAll", "loadAll");
|
|
3126
3118
|
var safeDump = renamed("safeDump", "dump");
|
|
3127
3119
|
|
|
3128
|
-
// ../../shared/src/utils/functions/is-url.ts
|
|
3129
|
-
function isUrl(input) {
|
|
3130
|
-
try {
|
|
3131
|
-
const url = new URL(input);
|
|
3132
|
-
return [
|
|
3133
|
-
"http:",
|
|
3134
|
-
"https:"
|
|
3135
|
-
].includes(url.protocol);
|
|
3136
|
-
} catch {
|
|
3137
|
-
return false;
|
|
3138
|
-
}
|
|
3139
|
-
}
|
|
3140
|
-
__name(isUrl, "isUrl");
|
|
3141
|
-
|
|
3142
|
-
// ../../shared/src/core/swagger-parser.ts
|
|
3143
|
-
var SwaggerParser = class _SwaggerParser {
|
|
3144
|
-
static {
|
|
3145
|
-
__name(this, "SwaggerParser");
|
|
3146
|
-
}
|
|
3147
|
-
spec;
|
|
3148
|
-
constructor(spec, config) {
|
|
3149
|
-
const isInputValid = config.validateInput?.(spec) ?? true;
|
|
3150
|
-
if (!isInputValid) {
|
|
3151
|
-
throw new Error("Swagger spec is not valid. Check your `validateInput` condition.");
|
|
3152
|
-
}
|
|
3153
|
-
this.spec = spec;
|
|
3154
|
-
}
|
|
3155
|
-
static async create(swaggerPathOrUrl, config) {
|
|
3156
|
-
const swaggerContent = await _SwaggerParser.loadContent(swaggerPathOrUrl);
|
|
3157
|
-
const spec = _SwaggerParser.parseSpecContent(swaggerContent, swaggerPathOrUrl);
|
|
3158
|
-
return new _SwaggerParser(spec, config);
|
|
3159
|
-
}
|
|
3160
|
-
static async loadContent(pathOrUrl) {
|
|
3161
|
-
if (isUrl(pathOrUrl)) {
|
|
3162
|
-
return await _SwaggerParser.fetchUrlContent(pathOrUrl);
|
|
3163
|
-
} else {
|
|
3164
|
-
return fs.readFileSync(pathOrUrl, "utf8");
|
|
3165
|
-
}
|
|
3166
|
-
}
|
|
3167
|
-
static async fetchUrlContent(url) {
|
|
3168
|
-
try {
|
|
3169
|
-
const response = await fetch(url, {
|
|
3170
|
-
method: "GET",
|
|
3171
|
-
headers: {
|
|
3172
|
-
Accept: "application/json, application/yaml, text/yaml, text/plain, */*",
|
|
3173
|
-
"User-Agent": "ng-openapi"
|
|
3174
|
-
},
|
|
3175
|
-
// 30 second timeout
|
|
3176
|
-
signal: AbortSignal.timeout(3e4)
|
|
3177
|
-
});
|
|
3178
|
-
if (!response.ok) {
|
|
3179
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
3180
|
-
}
|
|
3181
|
-
const content = await response.text();
|
|
3182
|
-
if (!content || content.trim() === "") {
|
|
3183
|
-
throw new Error(`Empty response from URL: ${url}`);
|
|
3184
|
-
}
|
|
3185
|
-
return content;
|
|
3186
|
-
} catch (error) {
|
|
3187
|
-
let errorMessage = `Failed to fetch content from URL: ${url}`;
|
|
3188
|
-
if (error.name === "AbortError") {
|
|
3189
|
-
errorMessage += " - Request timeout (30s)";
|
|
3190
|
-
} else if (error.message) {
|
|
3191
|
-
errorMessage += ` - ${error.message}`;
|
|
3192
|
-
}
|
|
3193
|
-
throw new Error(errorMessage);
|
|
3194
|
-
}
|
|
3195
|
-
}
|
|
3196
|
-
static parseSpecContent(content, pathOrUrl) {
|
|
3197
|
-
let format;
|
|
3198
|
-
if (isUrl(pathOrUrl)) {
|
|
3199
|
-
const urlPath = new URL(pathOrUrl).pathname.toLowerCase();
|
|
3200
|
-
if (urlPath.endsWith(".json")) {
|
|
3201
|
-
format = "json";
|
|
3202
|
-
} else if (urlPath.endsWith(".yaml") || urlPath.endsWith(".yml")) {
|
|
3203
|
-
format = "yaml";
|
|
3204
|
-
} else {
|
|
3205
|
-
format = _SwaggerParser.detectFormat(content);
|
|
3206
|
-
}
|
|
3207
|
-
} else {
|
|
3208
|
-
const extension = path.extname(pathOrUrl).toLowerCase();
|
|
3209
|
-
switch (extension) {
|
|
3210
|
-
case ".json":
|
|
3211
|
-
format = "json";
|
|
3212
|
-
break;
|
|
3213
|
-
case ".yaml":
|
|
3214
|
-
format = "yaml";
|
|
3215
|
-
break;
|
|
3216
|
-
case ".yml":
|
|
3217
|
-
format = "yml";
|
|
3218
|
-
break;
|
|
3219
|
-
default:
|
|
3220
|
-
format = _SwaggerParser.detectFormat(content);
|
|
3221
|
-
}
|
|
3222
|
-
}
|
|
3223
|
-
try {
|
|
3224
|
-
switch (format) {
|
|
3225
|
-
case "json":
|
|
3226
|
-
return JSON.parse(content);
|
|
3227
|
-
case "yaml":
|
|
3228
|
-
case "yml":
|
|
3229
|
-
return load(content);
|
|
3230
|
-
default:
|
|
3231
|
-
throw new Error(`Unable to determine format for: ${pathOrUrl}`);
|
|
3232
|
-
}
|
|
3233
|
-
} catch (error) {
|
|
3234
|
-
throw new Error(`Failed to parse ${format.toUpperCase()} content from: ${pathOrUrl}. Error: ${error instanceof Error ? error.message : error}`);
|
|
3235
|
-
}
|
|
3236
|
-
}
|
|
3237
|
-
static detectFormat(content) {
|
|
3238
|
-
const trimmed = content.trim();
|
|
3239
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
3240
|
-
return "json";
|
|
3241
|
-
}
|
|
3242
|
-
if (trimmed.includes("openapi:") || trimmed.includes("swagger:") || trimmed.includes("---") || /^[a-zA-Z][a-zA-Z0-9_]*\s*:/.test(trimmed)) {
|
|
3243
|
-
return "yaml";
|
|
3244
|
-
}
|
|
3245
|
-
return "json";
|
|
3246
|
-
}
|
|
3247
|
-
getDefinitions() {
|
|
3248
|
-
return this.spec.definitions || this.spec.components?.schemas || {};
|
|
3249
|
-
}
|
|
3250
|
-
getDefinition(name) {
|
|
3251
|
-
const definitions = this.getDefinitions();
|
|
3252
|
-
return definitions[name];
|
|
3253
|
-
}
|
|
3254
|
-
resolveReference(ref) {
|
|
3255
|
-
const parts = ref.split("/");
|
|
3256
|
-
const definitionName = parts[parts.length - 1];
|
|
3257
|
-
return this.getDefinition(definitionName);
|
|
3258
|
-
}
|
|
3259
|
-
getAllDefinitionNames() {
|
|
3260
|
-
return Object.keys(this.getDefinitions());
|
|
3261
|
-
}
|
|
3262
|
-
getSpec() {
|
|
3263
|
-
return this.spec;
|
|
3264
|
-
}
|
|
3265
|
-
getPaths() {
|
|
3266
|
-
return this.spec.paths || {};
|
|
3267
|
-
}
|
|
3268
|
-
isValidSpec() {
|
|
3269
|
-
return !!(this.spec.swagger && this.spec.swagger.startsWith("2.") || this.spec.openapi && this.spec.openapi.startsWith("3."));
|
|
3270
|
-
}
|
|
3271
|
-
getSpecVersion() {
|
|
3272
|
-
if (this.spec.swagger) {
|
|
3273
|
-
return {
|
|
3274
|
-
type: "swagger",
|
|
3275
|
-
version: this.spec.swagger
|
|
3276
|
-
};
|
|
3277
|
-
}
|
|
3278
|
-
if (this.spec.openapi) {
|
|
3279
|
-
return {
|
|
3280
|
-
type: "openapi",
|
|
3281
|
-
version: this.spec.openapi
|
|
3282
|
-
};
|
|
3283
|
-
}
|
|
3284
|
-
return null;
|
|
3285
|
-
}
|
|
3286
|
-
};
|
|
3287
|
-
|
|
3288
3120
|
// src/lib/http-resource.generator.ts
|
|
3289
|
-
var
|
|
3121
|
+
var path2 = __toESM(require("path"), 1);
|
|
3290
3122
|
|
|
3291
3123
|
// src/lib/http-resource-method/http-resource-method-body.generator.ts
|
|
3292
3124
|
var HttpResourceMethodBodyGenerator = class {
|
|
@@ -3526,17 +3358,32 @@ var HttpResourceMethodGenerator = class {
|
|
|
3526
3358
|
parameters,
|
|
3527
3359
|
returnType,
|
|
3528
3360
|
statements: methodBody,
|
|
3529
|
-
overloads
|
|
3361
|
+
overloads,
|
|
3362
|
+
docs: operation.description ? [
|
|
3363
|
+
operation.description
|
|
3364
|
+
] : void 0
|
|
3530
3365
|
});
|
|
3531
3366
|
}
|
|
3532
3367
|
generateMethodName(operation) {
|
|
3368
|
+
if (this.config.options.customizeMethodName) {
|
|
3369
|
+
if (operation.operationId == null) {
|
|
3370
|
+
throw new Error(`Operation ID is required for method name customization of operation: (${operation.method}) ${operation.path}`);
|
|
3371
|
+
}
|
|
3372
|
+
return this.config.options.customizeMethodName(operation.operationId);
|
|
3373
|
+
} else {
|
|
3374
|
+
return this.defaultNameGenerator(operation);
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
defaultNameGenerator(operation) {
|
|
3533
3378
|
if (operation.operationId) {
|
|
3534
3379
|
return camelCase(operation.operationId);
|
|
3535
3380
|
}
|
|
3536
|
-
const method = operation.method.toLowerCase();
|
|
3537
|
-
const pathParts = operation.path.split("/").
|
|
3538
|
-
|
|
3539
|
-
|
|
3381
|
+
const method = pascalCase(operation.method.toLowerCase());
|
|
3382
|
+
const pathParts = operation.path.split("/").map((str2) => {
|
|
3383
|
+
return pascalCase(pascalCase(str2).replace(/[^a-zA-Z0-9]/g, ""));
|
|
3384
|
+
});
|
|
3385
|
+
const resource = pathParts.join("") || "resource";
|
|
3386
|
+
return `${camelCase(resource)}${method}`;
|
|
3540
3387
|
}
|
|
3541
3388
|
generateReturnType(operation) {
|
|
3542
3389
|
const response = operation.responses?.["200"] || operation.responses?.["201"] || operation.responses?.["204"];
|
|
@@ -3579,8 +3426,8 @@ var HttpResourceMethodGenerator = class {
|
|
|
3579
3426
|
};
|
|
3580
3427
|
|
|
3581
3428
|
// src/lib/http-resource-index.generator.ts
|
|
3582
|
-
var
|
|
3583
|
-
var
|
|
3429
|
+
var fs = __toESM(require("fs"), 1);
|
|
3430
|
+
var path = __toESM(require("path"), 1);
|
|
3584
3431
|
var HttpResourceIndexGenerator = class {
|
|
3585
3432
|
static {
|
|
3586
3433
|
__name(this, "HttpResourceIndexGenerator");
|
|
@@ -3590,13 +3437,13 @@ var HttpResourceIndexGenerator = class {
|
|
|
3590
3437
|
this.project = project;
|
|
3591
3438
|
}
|
|
3592
3439
|
generateIndex(outputRoot) {
|
|
3593
|
-
const servicesDir =
|
|
3594
|
-
const indexPath =
|
|
3440
|
+
const servicesDir = path.join(outputRoot, "resources");
|
|
3441
|
+
const indexPath = path.join(servicesDir, "index.ts");
|
|
3595
3442
|
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
3596
3443
|
overwrite: true
|
|
3597
3444
|
});
|
|
3598
3445
|
sourceFile.insertText(0, SERVICE_INDEX_GENERATOR_HEADER_COMMENT);
|
|
3599
|
-
const serviceFiles =
|
|
3446
|
+
const serviceFiles = fs.readdirSync(servicesDir).filter((file) => file.endsWith(".resource.ts")).map((file) => file.replace(".resource.ts", ""));
|
|
3600
3447
|
serviceFiles.forEach((serviceName) => {
|
|
3601
3448
|
const className = pascalCase(serviceName) + "Resource";
|
|
3602
3449
|
sourceFile.addExportDeclaration({
|
|
@@ -3612,7 +3459,7 @@ var HttpResourceIndexGenerator = class {
|
|
|
3612
3459
|
};
|
|
3613
3460
|
|
|
3614
3461
|
// src/lib/http-resource.generator.ts
|
|
3615
|
-
var HttpResourceGenerator = class
|
|
3462
|
+
var HttpResourceGenerator = class {
|
|
3616
3463
|
static {
|
|
3617
3464
|
__name(this, "HttpResourceGenerator");
|
|
3618
3465
|
}
|
|
@@ -3634,12 +3481,8 @@ var HttpResourceGenerator = class _HttpResourceGenerator {
|
|
|
3634
3481
|
}
|
|
3635
3482
|
this.methodGenerator = new HttpResourceMethodGenerator(config);
|
|
3636
3483
|
}
|
|
3637
|
-
|
|
3638
|
-
const
|
|
3639
|
-
return new _HttpResourceGenerator(parser, project, config);
|
|
3640
|
-
}
|
|
3641
|
-
generate(outputRoot) {
|
|
3642
|
-
const outputDir = path3.join(outputRoot, "resources");
|
|
3484
|
+
async generate(outputRoot) {
|
|
3485
|
+
const outputDir = path2.join(outputRoot, "resources");
|
|
3643
3486
|
const paths = extractPaths(this.spec.paths, [
|
|
3644
3487
|
"get"
|
|
3645
3488
|
]);
|
|
@@ -3648,19 +3491,19 @@ var HttpResourceGenerator = class _HttpResourceGenerator {
|
|
|
3648
3491
|
return;
|
|
3649
3492
|
}
|
|
3650
3493
|
const controllerGroups = this.groupPathsByController(paths);
|
|
3651
|
-
Object.entries(controllerGroups).
|
|
3494
|
+
await Promise.all(Object.entries(controllerGroups).map(([resourceName, operations]) => {
|
|
3652
3495
|
this.generateServiceFile(resourceName, operations, outputDir);
|
|
3653
|
-
});
|
|
3496
|
+
}));
|
|
3654
3497
|
this.indexGenerator.generateIndex(outputRoot);
|
|
3655
3498
|
}
|
|
3656
3499
|
groupPathsByController(paths) {
|
|
3657
3500
|
const groups = {};
|
|
3658
|
-
paths.forEach((
|
|
3501
|
+
paths.forEach((path3) => {
|
|
3659
3502
|
let controllerName = "Default";
|
|
3660
|
-
if (
|
|
3661
|
-
controllerName =
|
|
3503
|
+
if (path3.tags && path3.tags.length > 0) {
|
|
3504
|
+
controllerName = path3.tags[0];
|
|
3662
3505
|
} else {
|
|
3663
|
-
const pathParts =
|
|
3506
|
+
const pathParts = path3.path.split("/").filter((p) => p && !p.startsWith("{"));
|
|
3664
3507
|
if (pathParts.length > 1) {
|
|
3665
3508
|
controllerName = pascalCase(pathParts[1]);
|
|
3666
3509
|
}
|
|
@@ -3670,13 +3513,13 @@ var HttpResourceGenerator = class _HttpResourceGenerator {
|
|
|
3670
3513
|
if (!groups[controllerName]) {
|
|
3671
3514
|
groups[controllerName] = [];
|
|
3672
3515
|
}
|
|
3673
|
-
groups[controllerName].push(
|
|
3516
|
+
groups[controllerName].push(path3);
|
|
3674
3517
|
});
|
|
3675
3518
|
return groups;
|
|
3676
3519
|
}
|
|
3677
|
-
generateServiceFile(resourceName, operations, outputDir) {
|
|
3520
|
+
async generateServiceFile(resourceName, operations, outputDir) {
|
|
3678
3521
|
const fileName = `${camelCase(resourceName).replace(/Resource/, "")}.resource.ts`;
|
|
3679
|
-
const filePath =
|
|
3522
|
+
const filePath = path2.join(outputDir, fileName);
|
|
3680
3523
|
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
3681
3524
|
overwrite: true
|
|
3682
3525
|
});
|
package/index.d.ts
CHANGED
|
@@ -106,7 +106,7 @@ interface IPluginGenerator {
|
|
|
106
106
|
/**
|
|
107
107
|
* Generate code files
|
|
108
108
|
*/
|
|
109
|
-
generate(outputRoot: string): void
|
|
109
|
+
generate(outputRoot: string): Promise<void>;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
interface GeneratorConfig {
|
|
@@ -145,8 +145,7 @@ declare class HttpResourceGenerator implements IPluginGenerator {
|
|
|
145
145
|
private methodGenerator;
|
|
146
146
|
private indexGenerator;
|
|
147
147
|
constructor(parser: SwaggerParser, project: Project, config: GeneratorConfig);
|
|
148
|
-
|
|
149
|
-
generate(outputRoot: string): void;
|
|
148
|
+
generate(outputRoot: string): Promise<void>;
|
|
150
149
|
private groupPathsByController;
|
|
151
150
|
private generateServiceFile;
|
|
152
151
|
private addImports;
|
package/index.js
CHANGED
|
@@ -6,12 +6,11 @@ import { Scope } from "ts-morph";
|
|
|
6
6
|
|
|
7
7
|
// ../../shared/src/utils/string.utils.ts
|
|
8
8
|
function camelCase(str2) {
|
|
9
|
-
|
|
10
|
-
return cleaned.charAt(0).toLowerCase() + cleaned.slice(1);
|
|
9
|
+
return str2.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toLowerCase());
|
|
11
10
|
}
|
|
12
11
|
__name(camelCase, "camelCase");
|
|
13
12
|
function pascalCase(str2) {
|
|
14
|
-
return str2.replace(/
|
|
13
|
+
return str2.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toUpperCase());
|
|
15
14
|
}
|
|
16
15
|
__name(pascalCase, "pascalCase");
|
|
17
16
|
|
|
@@ -182,12 +181,12 @@ function extractPaths(swaggerPaths = {}, methods = [
|
|
|
182
181
|
"head"
|
|
183
182
|
]) {
|
|
184
183
|
const paths = [];
|
|
185
|
-
Object.entries(swaggerPaths).forEach(([
|
|
184
|
+
Object.entries(swaggerPaths).forEach(([path3, pathItem]) => {
|
|
186
185
|
methods.forEach((method) => {
|
|
187
186
|
if (pathItem[method]) {
|
|
188
187
|
const operation = pathItem[method];
|
|
189
188
|
paths.push({
|
|
190
|
-
path:
|
|
189
|
+
path: path3,
|
|
191
190
|
method: method.toUpperCase(),
|
|
192
191
|
operationId: operation.operationId,
|
|
193
192
|
summary: operation.summary,
|
|
@@ -335,6 +334,12 @@ function inferResponseTypeFromContentType(contentType) {
|
|
|
335
334
|
__name(inferResponseTypeFromContentType, "inferResponseTypeFromContentType");
|
|
336
335
|
function getResponseType(response, config) {
|
|
337
336
|
const responseType = getResponseTypeFromResponse(response);
|
|
337
|
+
const content = response.content || {};
|
|
338
|
+
for (const [contentType, mediaType] of Object.entries(content)) {
|
|
339
|
+
if (mediaType?.schema) {
|
|
340
|
+
return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
338
343
|
switch (responseType) {
|
|
339
344
|
case "blob":
|
|
340
345
|
return "Blob";
|
|
@@ -342,15 +347,6 @@ function getResponseType(response, config) {
|
|
|
342
347
|
return "ArrayBuffer";
|
|
343
348
|
case "text":
|
|
344
349
|
return "string";
|
|
345
|
-
case "json": {
|
|
346
|
-
const content = response.content || {};
|
|
347
|
-
for (const [contentType, mediaType] of Object.entries(content)) {
|
|
348
|
-
if (inferResponseTypeFromContentType(contentType) === "json" && mediaType?.schema) {
|
|
349
|
-
return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
return "any";
|
|
353
|
-
}
|
|
354
350
|
default:
|
|
355
351
|
return "any";
|
|
356
352
|
}
|
|
@@ -389,10 +385,6 @@ var HTTP_RESOURCE_GENERATOR_HEADER_COMMENT = /* @__PURE__ */ __name((resourceNam
|
|
|
389
385
|
*/
|
|
390
386
|
`, "HTTP_RESOURCE_GENERATOR_HEADER_COMMENT");
|
|
391
387
|
|
|
392
|
-
// ../../shared/src/core/swagger-parser.ts
|
|
393
|
-
import * as fs from "fs";
|
|
394
|
-
import * as path from "path";
|
|
395
|
-
|
|
396
388
|
// ../../../node_modules/js-yaml/dist/js-yaml.mjs
|
|
397
389
|
function isNothing(subject) {
|
|
398
390
|
return typeof subject === "undefined" || subject === null;
|
|
@@ -3091,168 +3083,8 @@ var safeLoad = renamed("safeLoad", "load");
|
|
|
3091
3083
|
var safeLoadAll = renamed("safeLoadAll", "loadAll");
|
|
3092
3084
|
var safeDump = renamed("safeDump", "dump");
|
|
3093
3085
|
|
|
3094
|
-
// ../../shared/src/utils/functions/is-url.ts
|
|
3095
|
-
function isUrl(input) {
|
|
3096
|
-
try {
|
|
3097
|
-
const url = new URL(input);
|
|
3098
|
-
return [
|
|
3099
|
-
"http:",
|
|
3100
|
-
"https:"
|
|
3101
|
-
].includes(url.protocol);
|
|
3102
|
-
} catch {
|
|
3103
|
-
return false;
|
|
3104
|
-
}
|
|
3105
|
-
}
|
|
3106
|
-
__name(isUrl, "isUrl");
|
|
3107
|
-
|
|
3108
|
-
// ../../shared/src/core/swagger-parser.ts
|
|
3109
|
-
var SwaggerParser = class _SwaggerParser {
|
|
3110
|
-
static {
|
|
3111
|
-
__name(this, "SwaggerParser");
|
|
3112
|
-
}
|
|
3113
|
-
spec;
|
|
3114
|
-
constructor(spec, config) {
|
|
3115
|
-
const isInputValid = config.validateInput?.(spec) ?? true;
|
|
3116
|
-
if (!isInputValid) {
|
|
3117
|
-
throw new Error("Swagger spec is not valid. Check your `validateInput` condition.");
|
|
3118
|
-
}
|
|
3119
|
-
this.spec = spec;
|
|
3120
|
-
}
|
|
3121
|
-
static async create(swaggerPathOrUrl, config) {
|
|
3122
|
-
const swaggerContent = await _SwaggerParser.loadContent(swaggerPathOrUrl);
|
|
3123
|
-
const spec = _SwaggerParser.parseSpecContent(swaggerContent, swaggerPathOrUrl);
|
|
3124
|
-
return new _SwaggerParser(spec, config);
|
|
3125
|
-
}
|
|
3126
|
-
static async loadContent(pathOrUrl) {
|
|
3127
|
-
if (isUrl(pathOrUrl)) {
|
|
3128
|
-
return await _SwaggerParser.fetchUrlContent(pathOrUrl);
|
|
3129
|
-
} else {
|
|
3130
|
-
return fs.readFileSync(pathOrUrl, "utf8");
|
|
3131
|
-
}
|
|
3132
|
-
}
|
|
3133
|
-
static async fetchUrlContent(url) {
|
|
3134
|
-
try {
|
|
3135
|
-
const response = await fetch(url, {
|
|
3136
|
-
method: "GET",
|
|
3137
|
-
headers: {
|
|
3138
|
-
Accept: "application/json, application/yaml, text/yaml, text/plain, */*",
|
|
3139
|
-
"User-Agent": "ng-openapi"
|
|
3140
|
-
},
|
|
3141
|
-
// 30 second timeout
|
|
3142
|
-
signal: AbortSignal.timeout(3e4)
|
|
3143
|
-
});
|
|
3144
|
-
if (!response.ok) {
|
|
3145
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
3146
|
-
}
|
|
3147
|
-
const content = await response.text();
|
|
3148
|
-
if (!content || content.trim() === "") {
|
|
3149
|
-
throw new Error(`Empty response from URL: ${url}`);
|
|
3150
|
-
}
|
|
3151
|
-
return content;
|
|
3152
|
-
} catch (error) {
|
|
3153
|
-
let errorMessage = `Failed to fetch content from URL: ${url}`;
|
|
3154
|
-
if (error.name === "AbortError") {
|
|
3155
|
-
errorMessage += " - Request timeout (30s)";
|
|
3156
|
-
} else if (error.message) {
|
|
3157
|
-
errorMessage += ` - ${error.message}`;
|
|
3158
|
-
}
|
|
3159
|
-
throw new Error(errorMessage);
|
|
3160
|
-
}
|
|
3161
|
-
}
|
|
3162
|
-
static parseSpecContent(content, pathOrUrl) {
|
|
3163
|
-
let format;
|
|
3164
|
-
if (isUrl(pathOrUrl)) {
|
|
3165
|
-
const urlPath = new URL(pathOrUrl).pathname.toLowerCase();
|
|
3166
|
-
if (urlPath.endsWith(".json")) {
|
|
3167
|
-
format = "json";
|
|
3168
|
-
} else if (urlPath.endsWith(".yaml") || urlPath.endsWith(".yml")) {
|
|
3169
|
-
format = "yaml";
|
|
3170
|
-
} else {
|
|
3171
|
-
format = _SwaggerParser.detectFormat(content);
|
|
3172
|
-
}
|
|
3173
|
-
} else {
|
|
3174
|
-
const extension = path.extname(pathOrUrl).toLowerCase();
|
|
3175
|
-
switch (extension) {
|
|
3176
|
-
case ".json":
|
|
3177
|
-
format = "json";
|
|
3178
|
-
break;
|
|
3179
|
-
case ".yaml":
|
|
3180
|
-
format = "yaml";
|
|
3181
|
-
break;
|
|
3182
|
-
case ".yml":
|
|
3183
|
-
format = "yml";
|
|
3184
|
-
break;
|
|
3185
|
-
default:
|
|
3186
|
-
format = _SwaggerParser.detectFormat(content);
|
|
3187
|
-
}
|
|
3188
|
-
}
|
|
3189
|
-
try {
|
|
3190
|
-
switch (format) {
|
|
3191
|
-
case "json":
|
|
3192
|
-
return JSON.parse(content);
|
|
3193
|
-
case "yaml":
|
|
3194
|
-
case "yml":
|
|
3195
|
-
return load(content);
|
|
3196
|
-
default:
|
|
3197
|
-
throw new Error(`Unable to determine format for: ${pathOrUrl}`);
|
|
3198
|
-
}
|
|
3199
|
-
} catch (error) {
|
|
3200
|
-
throw new Error(`Failed to parse ${format.toUpperCase()} content from: ${pathOrUrl}. Error: ${error instanceof Error ? error.message : error}`);
|
|
3201
|
-
}
|
|
3202
|
-
}
|
|
3203
|
-
static detectFormat(content) {
|
|
3204
|
-
const trimmed = content.trim();
|
|
3205
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
3206
|
-
return "json";
|
|
3207
|
-
}
|
|
3208
|
-
if (trimmed.includes("openapi:") || trimmed.includes("swagger:") || trimmed.includes("---") || /^[a-zA-Z][a-zA-Z0-9_]*\s*:/.test(trimmed)) {
|
|
3209
|
-
return "yaml";
|
|
3210
|
-
}
|
|
3211
|
-
return "json";
|
|
3212
|
-
}
|
|
3213
|
-
getDefinitions() {
|
|
3214
|
-
return this.spec.definitions || this.spec.components?.schemas || {};
|
|
3215
|
-
}
|
|
3216
|
-
getDefinition(name) {
|
|
3217
|
-
const definitions = this.getDefinitions();
|
|
3218
|
-
return definitions[name];
|
|
3219
|
-
}
|
|
3220
|
-
resolveReference(ref) {
|
|
3221
|
-
const parts = ref.split("/");
|
|
3222
|
-
const definitionName = parts[parts.length - 1];
|
|
3223
|
-
return this.getDefinition(definitionName);
|
|
3224
|
-
}
|
|
3225
|
-
getAllDefinitionNames() {
|
|
3226
|
-
return Object.keys(this.getDefinitions());
|
|
3227
|
-
}
|
|
3228
|
-
getSpec() {
|
|
3229
|
-
return this.spec;
|
|
3230
|
-
}
|
|
3231
|
-
getPaths() {
|
|
3232
|
-
return this.spec.paths || {};
|
|
3233
|
-
}
|
|
3234
|
-
isValidSpec() {
|
|
3235
|
-
return !!(this.spec.swagger && this.spec.swagger.startsWith("2.") || this.spec.openapi && this.spec.openapi.startsWith("3."));
|
|
3236
|
-
}
|
|
3237
|
-
getSpecVersion() {
|
|
3238
|
-
if (this.spec.swagger) {
|
|
3239
|
-
return {
|
|
3240
|
-
type: "swagger",
|
|
3241
|
-
version: this.spec.swagger
|
|
3242
|
-
};
|
|
3243
|
-
}
|
|
3244
|
-
if (this.spec.openapi) {
|
|
3245
|
-
return {
|
|
3246
|
-
type: "openapi",
|
|
3247
|
-
version: this.spec.openapi
|
|
3248
|
-
};
|
|
3249
|
-
}
|
|
3250
|
-
return null;
|
|
3251
|
-
}
|
|
3252
|
-
};
|
|
3253
|
-
|
|
3254
3086
|
// src/lib/http-resource.generator.ts
|
|
3255
|
-
import * as
|
|
3087
|
+
import * as path2 from "path";
|
|
3256
3088
|
|
|
3257
3089
|
// src/lib/http-resource-method/http-resource-method-body.generator.ts
|
|
3258
3090
|
var HttpResourceMethodBodyGenerator = class {
|
|
@@ -3492,17 +3324,32 @@ var HttpResourceMethodGenerator = class {
|
|
|
3492
3324
|
parameters,
|
|
3493
3325
|
returnType,
|
|
3494
3326
|
statements: methodBody,
|
|
3495
|
-
overloads
|
|
3327
|
+
overloads,
|
|
3328
|
+
docs: operation.description ? [
|
|
3329
|
+
operation.description
|
|
3330
|
+
] : void 0
|
|
3496
3331
|
});
|
|
3497
3332
|
}
|
|
3498
3333
|
generateMethodName(operation) {
|
|
3334
|
+
if (this.config.options.customizeMethodName) {
|
|
3335
|
+
if (operation.operationId == null) {
|
|
3336
|
+
throw new Error(`Operation ID is required for method name customization of operation: (${operation.method}) ${operation.path}`);
|
|
3337
|
+
}
|
|
3338
|
+
return this.config.options.customizeMethodName(operation.operationId);
|
|
3339
|
+
} else {
|
|
3340
|
+
return this.defaultNameGenerator(operation);
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
defaultNameGenerator(operation) {
|
|
3499
3344
|
if (operation.operationId) {
|
|
3500
3345
|
return camelCase(operation.operationId);
|
|
3501
3346
|
}
|
|
3502
|
-
const method = operation.method.toLowerCase();
|
|
3503
|
-
const pathParts = operation.path.split("/").
|
|
3504
|
-
|
|
3505
|
-
|
|
3347
|
+
const method = pascalCase(operation.method.toLowerCase());
|
|
3348
|
+
const pathParts = operation.path.split("/").map((str2) => {
|
|
3349
|
+
return pascalCase(pascalCase(str2).replace(/[^a-zA-Z0-9]/g, ""));
|
|
3350
|
+
});
|
|
3351
|
+
const resource = pathParts.join("") || "resource";
|
|
3352
|
+
return `${camelCase(resource)}${method}`;
|
|
3506
3353
|
}
|
|
3507
3354
|
generateReturnType(operation) {
|
|
3508
3355
|
const response = operation.responses?.["200"] || operation.responses?.["201"] || operation.responses?.["204"];
|
|
@@ -3545,8 +3392,8 @@ var HttpResourceMethodGenerator = class {
|
|
|
3545
3392
|
};
|
|
3546
3393
|
|
|
3547
3394
|
// src/lib/http-resource-index.generator.ts
|
|
3548
|
-
import * as
|
|
3549
|
-
import * as
|
|
3395
|
+
import * as fs from "fs";
|
|
3396
|
+
import * as path from "path";
|
|
3550
3397
|
var HttpResourceIndexGenerator = class {
|
|
3551
3398
|
static {
|
|
3552
3399
|
__name(this, "HttpResourceIndexGenerator");
|
|
@@ -3556,13 +3403,13 @@ var HttpResourceIndexGenerator = class {
|
|
|
3556
3403
|
this.project = project;
|
|
3557
3404
|
}
|
|
3558
3405
|
generateIndex(outputRoot) {
|
|
3559
|
-
const servicesDir =
|
|
3560
|
-
const indexPath =
|
|
3406
|
+
const servicesDir = path.join(outputRoot, "resources");
|
|
3407
|
+
const indexPath = path.join(servicesDir, "index.ts");
|
|
3561
3408
|
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
3562
3409
|
overwrite: true
|
|
3563
3410
|
});
|
|
3564
3411
|
sourceFile.insertText(0, SERVICE_INDEX_GENERATOR_HEADER_COMMENT);
|
|
3565
|
-
const serviceFiles =
|
|
3412
|
+
const serviceFiles = fs.readdirSync(servicesDir).filter((file) => file.endsWith(".resource.ts")).map((file) => file.replace(".resource.ts", ""));
|
|
3566
3413
|
serviceFiles.forEach((serviceName) => {
|
|
3567
3414
|
const className = pascalCase(serviceName) + "Resource";
|
|
3568
3415
|
sourceFile.addExportDeclaration({
|
|
@@ -3578,7 +3425,7 @@ var HttpResourceIndexGenerator = class {
|
|
|
3578
3425
|
};
|
|
3579
3426
|
|
|
3580
3427
|
// src/lib/http-resource.generator.ts
|
|
3581
|
-
var HttpResourceGenerator = class
|
|
3428
|
+
var HttpResourceGenerator = class {
|
|
3582
3429
|
static {
|
|
3583
3430
|
__name(this, "HttpResourceGenerator");
|
|
3584
3431
|
}
|
|
@@ -3600,12 +3447,8 @@ var HttpResourceGenerator = class _HttpResourceGenerator {
|
|
|
3600
3447
|
}
|
|
3601
3448
|
this.methodGenerator = new HttpResourceMethodGenerator(config);
|
|
3602
3449
|
}
|
|
3603
|
-
|
|
3604
|
-
const
|
|
3605
|
-
return new _HttpResourceGenerator(parser, project, config);
|
|
3606
|
-
}
|
|
3607
|
-
generate(outputRoot) {
|
|
3608
|
-
const outputDir = path3.join(outputRoot, "resources");
|
|
3450
|
+
async generate(outputRoot) {
|
|
3451
|
+
const outputDir = path2.join(outputRoot, "resources");
|
|
3609
3452
|
const paths = extractPaths(this.spec.paths, [
|
|
3610
3453
|
"get"
|
|
3611
3454
|
]);
|
|
@@ -3614,19 +3457,19 @@ var HttpResourceGenerator = class _HttpResourceGenerator {
|
|
|
3614
3457
|
return;
|
|
3615
3458
|
}
|
|
3616
3459
|
const controllerGroups = this.groupPathsByController(paths);
|
|
3617
|
-
Object.entries(controllerGroups).
|
|
3460
|
+
await Promise.all(Object.entries(controllerGroups).map(([resourceName, operations]) => {
|
|
3618
3461
|
this.generateServiceFile(resourceName, operations, outputDir);
|
|
3619
|
-
});
|
|
3462
|
+
}));
|
|
3620
3463
|
this.indexGenerator.generateIndex(outputRoot);
|
|
3621
3464
|
}
|
|
3622
3465
|
groupPathsByController(paths) {
|
|
3623
3466
|
const groups = {};
|
|
3624
|
-
paths.forEach((
|
|
3467
|
+
paths.forEach((path3) => {
|
|
3625
3468
|
let controllerName = "Default";
|
|
3626
|
-
if (
|
|
3627
|
-
controllerName =
|
|
3469
|
+
if (path3.tags && path3.tags.length > 0) {
|
|
3470
|
+
controllerName = path3.tags[0];
|
|
3628
3471
|
} else {
|
|
3629
|
-
const pathParts =
|
|
3472
|
+
const pathParts = path3.path.split("/").filter((p) => p && !p.startsWith("{"));
|
|
3630
3473
|
if (pathParts.length > 1) {
|
|
3631
3474
|
controllerName = pascalCase(pathParts[1]);
|
|
3632
3475
|
}
|
|
@@ -3636,13 +3479,13 @@ var HttpResourceGenerator = class _HttpResourceGenerator {
|
|
|
3636
3479
|
if (!groups[controllerName]) {
|
|
3637
3480
|
groups[controllerName] = [];
|
|
3638
3481
|
}
|
|
3639
|
-
groups[controllerName].push(
|
|
3482
|
+
groups[controllerName].push(path3);
|
|
3640
3483
|
});
|
|
3641
3484
|
return groups;
|
|
3642
3485
|
}
|
|
3643
|
-
generateServiceFile(resourceName, operations, outputDir) {
|
|
3486
|
+
async generateServiceFile(resourceName, operations, outputDir) {
|
|
3644
3487
|
const fileName = `${camelCase(resourceName).replace(/Resource/, "")}.resource.ts`;
|
|
3645
|
-
const filePath =
|
|
3488
|
+
const filePath = path2.join(outputDir, fileName);
|
|
3646
3489
|
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
3647
3490
|
overwrite: true
|
|
3648
3491
|
});
|