nestjs-openapi 0.1.2 → 0.1.4
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/dist/cli.mjs +4 -4
- package/dist/index.d.mts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.mjs +4 -4
- package/dist/internal.d.mts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.mjs +1 -1
- package/dist/shared/{nestjs-openapi.yWMsjl_8.mjs → nestjs-openapi.CUKGdNSM.mjs} +472 -47
- package/dist/shared/{nestjs-openapi.OhsaHu32.d.mts → nestjs-openapi.ClTIhsb-.d.mts} +94 -12
- package/dist/shared/{nestjs-openapi.OhsaHu32.d.ts → nestjs-openapi.ClTIhsb-.d.ts} +94 -12
- package/dist/shared/{nestjs-openapi.CBj9xHZ4.mjs → nestjs-openapi.DRcy130f.mjs} +35 -0
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import 'tsx';
|
|
3
|
-
import { g as generate, e as formatValidationResult } from './shared/nestjs-openapi.
|
|
3
|
+
import { g as generate, e as formatValidationResult } from './shared/nestjs-openapi.CUKGdNSM.mjs';
|
|
4
4
|
import minimist from 'minimist';
|
|
5
5
|
import { relative } from 'node:path';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
7
|
import 'effect';
|
|
8
8
|
import 'node:fs';
|
|
9
|
+
import 'node:crypto';
|
|
9
10
|
import 'ts-morph';
|
|
10
11
|
import 'glob';
|
|
11
12
|
import 'js-yaml';
|
|
12
|
-
import './shared/nestjs-openapi.
|
|
13
|
+
import './shared/nestjs-openapi.DRcy130f.mjs';
|
|
13
14
|
import 'ts-json-schema-generator';
|
|
14
|
-
import 'node:crypto';
|
|
15
15
|
import 'node:url';
|
|
16
16
|
import 'child_process';
|
|
17
17
|
|
|
@@ -117,7 +117,7 @@ const main = async () => {
|
|
|
117
117
|
console.log(` ${formatValidationResult(result.validation)}`);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
-
process.exit(0);
|
|
120
|
+
process.exit(result.validation.valid ? 0 : 1);
|
|
121
121
|
} catch (err) {
|
|
122
122
|
const duration = performance.now() - startTime;
|
|
123
123
|
const message = err instanceof Error ? err.message : String(err);
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, Context, Layer, Option } from 'effect';
|
|
2
|
-
import { C as ConfigNotFoundError, O as OpenApiGeneratorConfig, a as ConfigError, R as ResolvedConfig, P as ProjectError, b as ProjectInitError, E as EntryNotFoundError, M as MethodInfo, c as OpenApiPaths$1 } from './shared/nestjs-openapi.
|
|
3
|
-
export { A as AnalysisError, i as ConfigLoadError, j as ConfigValidationError, G as GenerateOptions, k as GeneratorError, H as HttpMethod, I as InvalidMethodError, e as ParameterLocation, f as ResolvedParameter, h as ReturnTypeInfo, d as generateAsync, g as generateEffect } from './shared/nestjs-openapi.
|
|
2
|
+
import { C as ConfigNotFoundError, O as OpenApiGeneratorConfig, a as ConfigError, R as ResolvedConfig, P as ProjectError, b as ProjectInitError, E as EntryNotFoundError, M as MethodInfo, c as OpenApiPaths$1 } from './shared/nestjs-openapi.ClTIhsb-.mjs';
|
|
3
|
+
export { A as AnalysisError, i as ConfigLoadError, j as ConfigValidationError, G as GenerateOptions, k as GeneratorError, H as HttpMethod, I as InvalidMethodError, e as ParameterLocation, f as ResolvedParameter, h as ReturnTypeInfo, d as generateAsync, g as generateEffect } from './shared/nestjs-openapi.ClTIhsb-.mjs';
|
|
4
4
|
import { DynamicModule } from '@nestjs/common';
|
|
5
5
|
import { Project, SourceFile, ClassDeclaration, MethodDeclaration, Decorator, Symbol, ObjectLiteralExpression, Expression } from 'ts-morph';
|
|
6
6
|
|
|
@@ -275,6 +275,23 @@ interface OptionsConfig {
|
|
|
275
275
|
* Query parameter handling options.
|
|
276
276
|
*/
|
|
277
277
|
readonly query?: QueryOptions;
|
|
278
|
+
/**
|
|
279
|
+
* Schema generation and normalization options.
|
|
280
|
+
*/
|
|
281
|
+
readonly schemas?: SchemaOptions;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Schema generation and normalization options.
|
|
285
|
+
*/
|
|
286
|
+
interface SchemaOptions {
|
|
287
|
+
/**
|
|
288
|
+
* How to handle schema aliases that only redirect via `$ref`.
|
|
289
|
+
* - `"collapse"`: Rewrite refs to the final target schema and remove alias entries
|
|
290
|
+
* - `"preserve"`: Keep alias schemas as-is
|
|
291
|
+
*
|
|
292
|
+
* @default "collapse"
|
|
293
|
+
*/
|
|
294
|
+
readonly aliasRefs?: 'collapse' | 'preserve';
|
|
278
295
|
}
|
|
279
296
|
/**
|
|
280
297
|
* Query parameter handling options.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, Context, Layer, Option } from 'effect';
|
|
2
|
-
import { C as ConfigNotFoundError, O as OpenApiGeneratorConfig, a as ConfigError, R as ResolvedConfig, P as ProjectError, b as ProjectInitError, E as EntryNotFoundError, M as MethodInfo, c as OpenApiPaths$1 } from './shared/nestjs-openapi.
|
|
3
|
-
export { A as AnalysisError, i as ConfigLoadError, j as ConfigValidationError, G as GenerateOptions, k as GeneratorError, H as HttpMethod, I as InvalidMethodError, e as ParameterLocation, f as ResolvedParameter, h as ReturnTypeInfo, d as generateAsync, g as generateEffect } from './shared/nestjs-openapi.
|
|
2
|
+
import { C as ConfigNotFoundError, O as OpenApiGeneratorConfig, a as ConfigError, R as ResolvedConfig, P as ProjectError, b as ProjectInitError, E as EntryNotFoundError, M as MethodInfo, c as OpenApiPaths$1 } from './shared/nestjs-openapi.ClTIhsb-.js';
|
|
3
|
+
export { A as AnalysisError, i as ConfigLoadError, j as ConfigValidationError, G as GenerateOptions, k as GeneratorError, H as HttpMethod, I as InvalidMethodError, e as ParameterLocation, f as ResolvedParameter, h as ReturnTypeInfo, d as generateAsync, g as generateEffect } from './shared/nestjs-openapi.ClTIhsb-.js';
|
|
4
4
|
import { DynamicModule } from '@nestjs/common';
|
|
5
5
|
import { Project, SourceFile, ClassDeclaration, MethodDeclaration, Decorator, Symbol, ObjectLiteralExpression, Expression } from 'ts-morph';
|
|
6
6
|
|
|
@@ -275,6 +275,23 @@ interface OptionsConfig {
|
|
|
275
275
|
* Query parameter handling options.
|
|
276
276
|
*/
|
|
277
277
|
readonly query?: QueryOptions;
|
|
278
|
+
/**
|
|
279
|
+
* Schema generation and normalization options.
|
|
280
|
+
*/
|
|
281
|
+
readonly schemas?: SchemaOptions;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Schema generation and normalization options.
|
|
285
|
+
*/
|
|
286
|
+
interface SchemaOptions {
|
|
287
|
+
/**
|
|
288
|
+
* How to handle schema aliases that only redirect via `$ref`.
|
|
289
|
+
* - `"collapse"`: Rewrite refs to the final target schema and remove alias entries
|
|
290
|
+
* - `"preserve"`: Keep alias schemas as-is
|
|
291
|
+
*
|
|
292
|
+
* @default "collapse"
|
|
293
|
+
*/
|
|
294
|
+
readonly aliasRefs?: 'collapse' | 'preserve';
|
|
278
295
|
}
|
|
279
296
|
/**
|
|
280
297
|
* Query parameter handling options.
|
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
export { c as categorizeBrokenRefs, d as defineConfig, f as findConfigFile, e as formatValidationResult, g as generate, b as loadAndResolveConfig, a as loadConfig, l as loadConfigFromFile, r as resolveConfig, v as validateSpec } from './shared/nestjs-openapi.
|
|
1
|
+
export { c as categorizeBrokenRefs, d as defineConfig, f as findConfigFile, e as formatValidationResult, g as generate, b as loadAndResolveConfig, a as loadConfig, l as loadConfigFromFile, r as resolveConfig, v as validateSpec } from './shared/nestjs-openapi.CUKGdNSM.mjs';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { Module } from '@nestjs/common';
|
|
5
5
|
export { generateAsync, generate as generateEffect } from './internal.mjs';
|
|
6
|
-
import { P as ProjectInitError, E as EntryNotFoundError } from './shared/nestjs-openapi.
|
|
7
|
-
export { a as ConfigLoadError, C as ConfigNotFoundError, b as ConfigValidationError, I as InvalidMethodError, c as getAllControllers, q as getArrayInitializer, o as getControllerMethodInfos, e as getControllerName, d as getControllerPrefix, j as getControllerTags, h as getDecoratorName, k as getHttpDecorator, f as getHttpMethods, m as getMethodInfo, w as getModuleDecoratorArg, z as getModuleMetadata, g as getModules, s as getStringLiteralValue, u as getSymbolFromIdentifier, l as isHttpDecorator, i as isHttpMethod, v as isModuleClass, n as normalizePath, y as resolveArrayOfClasses, x as resolveClassFromExpression, r as resolveClassFromSymbol, t as transformMethod, p as transformMethods } from './shared/nestjs-openapi.
|
|
6
|
+
import { P as ProjectInitError, E as EntryNotFoundError } from './shared/nestjs-openapi.DRcy130f.mjs';
|
|
7
|
+
export { a as ConfigLoadError, C as ConfigNotFoundError, b as ConfigValidationError, I as InvalidMethodError, c as getAllControllers, q as getArrayInitializer, o as getControllerMethodInfos, e as getControllerName, d as getControllerPrefix, j as getControllerTags, h as getDecoratorName, k as getHttpDecorator, f as getHttpMethods, m as getMethodInfo, w as getModuleDecoratorArg, z as getModuleMetadata, g as getModules, s as getStringLiteralValue, u as getSymbolFromIdentifier, l as isHttpDecorator, i as isHttpMethod, v as isModuleClass, n as normalizePath, y as resolveArrayOfClasses, x as resolveClassFromExpression, r as resolveClassFromSymbol, t as transformMethod, p as transformMethods } from './shared/nestjs-openapi.DRcy130f.mjs';
|
|
8
8
|
import { Context, Effect, Layer } from 'effect';
|
|
9
9
|
import { Project } from 'ts-morph';
|
|
10
|
+
import 'node:crypto';
|
|
10
11
|
import 'glob';
|
|
11
12
|
import 'js-yaml';
|
|
12
13
|
import 'ts-json-schema-generator';
|
|
13
|
-
import 'node:crypto';
|
|
14
14
|
import 'node:url';
|
|
15
15
|
import 'child_process';
|
|
16
16
|
|
package/dist/internal.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import 'effect';
|
|
2
|
-
export { G as GenerateOptions, g as generate, d as generateAsync } from './shared/nestjs-openapi.
|
|
2
|
+
export { G as GenerateOptions, g as generate, d as generateAsync } from './shared/nestjs-openapi.ClTIhsb-.mjs';
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import 'effect';
|
|
2
|
-
export { G as GenerateOptions, g as generate, d as generateAsync } from './shared/nestjs-openapi.
|
|
2
|
+
export { G as GenerateOptions, g as generate, d as generateAsync } from './shared/nestjs-openapi.ClTIhsb-.js';
|
package/dist/internal.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect } from 'effect';
|
|
2
2
|
import { Project } from 'ts-morph';
|
|
3
|
-
import { E as EntryNotFoundError, g as getModules, o as getControllerMethodInfos, p as transformMethods } from './shared/nestjs-openapi.
|
|
3
|
+
import { E as EntryNotFoundError, g as getModules, o as getControllerMethodInfos, p as transformMethods } from './shared/nestjs-openapi.DRcy130f.mjs';
|
|
4
4
|
|
|
5
5
|
const generate = (options) => Effect.gen(function* () {
|
|
6
6
|
yield* Effect.logInfo("Starting OpenAPI generation").pipe(
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Schema, Effect, Logger, Layer, LogLevel } from 'effect';
|
|
2
2
|
import { readFileSync, writeFileSync, existsSync, unlinkSync, mkdirSync } from 'node:fs';
|
|
3
|
-
import { join, dirname, resolve } from 'node:path';
|
|
3
|
+
import { join, dirname, resolve, relative } from 'node:path';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
4
5
|
import { Project } from 'ts-morph';
|
|
5
6
|
import { globSync, glob } from 'glob';
|
|
6
7
|
import yaml from 'js-yaml';
|
|
7
|
-
import { C as ConfigNotFoundError, a as ConfigLoadError, b as ConfigValidationError, p as transformMethods, A as extractClassConstraints, B as getRequiredProperties, D as mergeValidationConstraints, E as EntryNotFoundError, g as getModules, o as getControllerMethodInfos } from './nestjs-openapi.
|
|
8
|
+
import { C as ConfigNotFoundError, a as ConfigLoadError, b as ConfigValidationError, p as transformMethods, A as extractClassConstraints, B as getRequiredProperties, D as mergeValidationConstraints, E as EntryNotFoundError, g as getModules, o as getControllerMethodInfos } from './nestjs-openapi.DRcy130f.mjs';
|
|
8
9
|
import { createGenerator } from 'ts-json-schema-generator';
|
|
9
|
-
import { randomUUID } from 'node:crypto';
|
|
10
10
|
import { pathToFileURL } from 'node:url';
|
|
11
11
|
import { execSync } from 'child_process';
|
|
12
12
|
|
|
@@ -450,6 +450,165 @@ const resolveNewSchemaName = (originalName, structureMapping) => {
|
|
|
450
450
|
return originalName;
|
|
451
451
|
};
|
|
452
452
|
|
|
453
|
+
const COMPONENT_SCHEMA_REF_PREFIX = "#/components/schemas/";
|
|
454
|
+
const ALIAS_SCHEMA_KEYS = /* @__PURE__ */ new Set(["$ref", "description"]);
|
|
455
|
+
const extractSchemaRefName = (ref) => ref.startsWith(COMPONENT_SCHEMA_REF_PREFIX) ? ref.slice(COMPONENT_SCHEMA_REF_PREFIX.length) : null;
|
|
456
|
+
const toSchemaRef = (name) => `${COMPONENT_SCHEMA_REF_PREFIX}${name}`;
|
|
457
|
+
const isAliasSchema = (schema) => {
|
|
458
|
+
if (!schema.$ref) return false;
|
|
459
|
+
return Object.keys(schema).every(
|
|
460
|
+
(key) => ALIAS_SCHEMA_KEYS.has(key)
|
|
461
|
+
);
|
|
462
|
+
};
|
|
463
|
+
const rewriteSchemaRefs = (schema, rewriteRef) => {
|
|
464
|
+
const result = { ...schema };
|
|
465
|
+
if (typeof schema.$ref === "string") {
|
|
466
|
+
result["$ref"] = rewriteRef(schema.$ref);
|
|
467
|
+
}
|
|
468
|
+
if (schema.items) {
|
|
469
|
+
result["items"] = rewriteSchemaRefs(schema.items, rewriteRef);
|
|
470
|
+
}
|
|
471
|
+
if (schema.oneOf) {
|
|
472
|
+
result["oneOf"] = schema.oneOf.map(
|
|
473
|
+
(item) => rewriteSchemaRefs(item, rewriteRef)
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
if (schema.anyOf) {
|
|
477
|
+
result["anyOf"] = schema.anyOf.map(
|
|
478
|
+
(item) => rewriteSchemaRefs(item, rewriteRef)
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
if (schema.allOf) {
|
|
482
|
+
result["allOf"] = schema.allOf.map(
|
|
483
|
+
(item) => rewriteSchemaRefs(item, rewriteRef)
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
if (schema.properties) {
|
|
487
|
+
result["properties"] = Object.fromEntries(
|
|
488
|
+
Object.entries(schema.properties).map(([key, propertySchema]) => [
|
|
489
|
+
key,
|
|
490
|
+
rewriteSchemaRefs(propertySchema, rewriteRef)
|
|
491
|
+
])
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
495
|
+
result["additionalProperties"] = rewriteSchemaRefs(
|
|
496
|
+
schema.additionalProperties,
|
|
497
|
+
rewriteRef
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
return result;
|
|
501
|
+
};
|
|
502
|
+
const rewritePathsRefs = (paths, rewriteRef) => Object.fromEntries(
|
|
503
|
+
Object.entries(paths).map(([path, methods]) => [
|
|
504
|
+
path,
|
|
505
|
+
Object.fromEntries(
|
|
506
|
+
Object.entries(methods).map(([method, operation]) => [
|
|
507
|
+
method,
|
|
508
|
+
{
|
|
509
|
+
...operation,
|
|
510
|
+
...operation.parameters && {
|
|
511
|
+
parameters: operation.parameters.map((parameter) => ({
|
|
512
|
+
...parameter,
|
|
513
|
+
schema: rewriteSchemaRefs(parameter.schema, rewriteRef)
|
|
514
|
+
}))
|
|
515
|
+
},
|
|
516
|
+
...operation.requestBody && {
|
|
517
|
+
requestBody: {
|
|
518
|
+
...operation.requestBody,
|
|
519
|
+
content: Object.fromEntries(
|
|
520
|
+
Object.entries(operation.requestBody.content).map(
|
|
521
|
+
([contentType, content]) => [
|
|
522
|
+
contentType,
|
|
523
|
+
{
|
|
524
|
+
...content,
|
|
525
|
+
schema: rewriteSchemaRefs(content.schema, rewriteRef)
|
|
526
|
+
}
|
|
527
|
+
]
|
|
528
|
+
)
|
|
529
|
+
)
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
responses: Object.fromEntries(
|
|
533
|
+
Object.entries(operation.responses).map(([statusCode, response]) => [
|
|
534
|
+
statusCode,
|
|
535
|
+
response.content ? {
|
|
536
|
+
...response,
|
|
537
|
+
content: Object.fromEntries(
|
|
538
|
+
Object.entries(response.content).map(
|
|
539
|
+
([contentType, content]) => [
|
|
540
|
+
contentType,
|
|
541
|
+
{
|
|
542
|
+
...content,
|
|
543
|
+
schema: rewriteSchemaRefs(content.schema, rewriteRef)
|
|
544
|
+
}
|
|
545
|
+
]
|
|
546
|
+
)
|
|
547
|
+
)
|
|
548
|
+
} : response
|
|
549
|
+
])
|
|
550
|
+
)
|
|
551
|
+
}
|
|
552
|
+
])
|
|
553
|
+
)
|
|
554
|
+
])
|
|
555
|
+
);
|
|
556
|
+
const rewriteSchemasRefs = (schemas, rewriteRef) => Object.fromEntries(
|
|
557
|
+
Object.entries(schemas).map(([name, schema]) => [
|
|
558
|
+
name,
|
|
559
|
+
rewriteSchemaRefs(schema, rewriteRef)
|
|
560
|
+
])
|
|
561
|
+
);
|
|
562
|
+
const resolveAliasTargets = (schemas) => {
|
|
563
|
+
const directAliases = /* @__PURE__ */ new Map();
|
|
564
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
565
|
+
if (!isAliasSchema(schema) || !schema.$ref) continue;
|
|
566
|
+
const target = extractSchemaRefName(schema.$ref);
|
|
567
|
+
if (!target) continue;
|
|
568
|
+
directAliases.set(name, target);
|
|
569
|
+
}
|
|
570
|
+
const resolvedAliases = /* @__PURE__ */ new Map();
|
|
571
|
+
const resolveFinalTarget = (start) => {
|
|
572
|
+
const visited = /* @__PURE__ */ new Set([start]);
|
|
573
|
+
let current = start;
|
|
574
|
+
while (true) {
|
|
575
|
+
const next = directAliases.get(current);
|
|
576
|
+
if (!next) return current === start ? null : current;
|
|
577
|
+
if (!(next in schemas)) return null;
|
|
578
|
+
if (visited.has(next)) return null;
|
|
579
|
+
visited.add(next);
|
|
580
|
+
current = next;
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
for (const aliasName of directAliases.keys()) {
|
|
584
|
+
const finalTarget = resolveFinalTarget(aliasName);
|
|
585
|
+
if (!finalTarget || finalTarget === aliasName) continue;
|
|
586
|
+
resolvedAliases.set(aliasName, finalTarget);
|
|
587
|
+
}
|
|
588
|
+
return resolvedAliases;
|
|
589
|
+
};
|
|
590
|
+
const collapseAliasRefs = (paths, schemas) => {
|
|
591
|
+
const aliasTargets = resolveAliasTargets(schemas);
|
|
592
|
+
if (aliasTargets.size === 0) return { paths, schemas };
|
|
593
|
+
const rewriteRef = (ref) => {
|
|
594
|
+
const refName = extractSchemaRefName(ref);
|
|
595
|
+
if (!refName) return ref;
|
|
596
|
+
const finalTarget = aliasTargets.get(refName);
|
|
597
|
+
return finalTarget ? toSchemaRef(finalTarget) : ref;
|
|
598
|
+
};
|
|
599
|
+
const rewrittenPaths = rewritePathsRefs(paths, rewriteRef);
|
|
600
|
+
const rewrittenSchemas = rewriteSchemasRefs(schemas, rewriteRef);
|
|
601
|
+
const collapsedSchemas = Object.fromEntries(
|
|
602
|
+
Object.entries(rewrittenSchemas).filter(
|
|
603
|
+
([name]) => !aliasTargets.has(name)
|
|
604
|
+
)
|
|
605
|
+
);
|
|
606
|
+
return {
|
|
607
|
+
paths: rewrittenPaths,
|
|
608
|
+
schemas: collapsedSchemas
|
|
609
|
+
};
|
|
610
|
+
};
|
|
611
|
+
|
|
453
612
|
const extractReferencedSchemas = (paths) => {
|
|
454
613
|
const refs = /* @__PURE__ */ new Set();
|
|
455
614
|
const extractFromSchema = (schema) => {
|
|
@@ -646,7 +805,11 @@ const createPathFilter = (pathFilter) => {
|
|
|
646
805
|
if (typeof pathFilter === "function") {
|
|
647
806
|
return (method) => pathFilter(method.path);
|
|
648
807
|
}
|
|
649
|
-
|
|
808
|
+
const pattern = new RegExp(pathFilter.source, pathFilter.flags);
|
|
809
|
+
return (method) => {
|
|
810
|
+
pattern.lastIndex = 0;
|
|
811
|
+
return pattern.test(method.path);
|
|
812
|
+
};
|
|
650
813
|
};
|
|
651
814
|
const combineFilters = (filters) => {
|
|
652
815
|
if (filters.length === 0) {
|
|
@@ -678,6 +841,11 @@ const filterMethods = (methods, options) => {
|
|
|
678
841
|
return methods.filter(filter);
|
|
679
842
|
};
|
|
680
843
|
|
|
844
|
+
const NULL_SCHEMA = { type: "null" };
|
|
845
|
+
const schemaIncludesNull = (schema) => {
|
|
846
|
+
if (schema.type === "null") return true;
|
|
847
|
+
return Array.isArray(schema.type) && schema.type.includes("null");
|
|
848
|
+
};
|
|
681
849
|
const transformSchemaToV31 = (schema) => {
|
|
682
850
|
const transformedOneOf = schema.oneOf?.map(transformSchemaToV31);
|
|
683
851
|
const transformedAnyOf = schema.anyOf?.map(transformSchemaToV31);
|
|
@@ -689,19 +857,36 @@ const transformSchemaToV31 = (schema) => {
|
|
|
689
857
|
transformSchemaToV31(value)
|
|
690
858
|
])
|
|
691
859
|
) : void 0;
|
|
692
|
-
const
|
|
693
|
-
const transformedType =
|
|
694
|
-
const
|
|
695
|
-
return {
|
|
860
|
+
const { nullable, ...restWithoutNullable } = schema;
|
|
861
|
+
const transformedType = nullable && typeof schema.type === "string" ? [schema.type, "null"] : schema.type;
|
|
862
|
+
const transformedSchema = {
|
|
696
863
|
...restWithoutNullable,
|
|
697
|
-
type: transformedType,
|
|
864
|
+
...transformedType !== void 0 && { type: transformedType },
|
|
698
865
|
...transformedOneOf && { oneOf: transformedOneOf },
|
|
699
866
|
...transformedAnyOf && { anyOf: transformedAnyOf },
|
|
700
867
|
...transformedAllOf && { allOf: transformedAllOf },
|
|
701
868
|
...transformedItems && { items: transformedItems },
|
|
702
869
|
...transformedProperties && { properties: transformedProperties }
|
|
703
870
|
};
|
|
871
|
+
if (!nullable) return transformedSchema;
|
|
872
|
+
if (schema.type && typeof schema.type === "string") {
|
|
873
|
+
return transformedSchema;
|
|
874
|
+
}
|
|
875
|
+
if (transformedSchema.oneOf) {
|
|
876
|
+
return {
|
|
877
|
+
...transformedSchema,
|
|
878
|
+
oneOf: schemaIncludesNullInVariants(transformedSchema.oneOf) ? transformedSchema.oneOf : [...transformedSchema.oneOf, NULL_SCHEMA]
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
if (transformedSchema.anyOf) {
|
|
882
|
+
return {
|
|
883
|
+
...transformedSchema,
|
|
884
|
+
anyOf: schemaIncludesNullInVariants(transformedSchema.anyOf) ? transformedSchema.anyOf : [...transformedSchema.anyOf, NULL_SCHEMA]
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
return { anyOf: [transformedSchema, NULL_SCHEMA] };
|
|
704
888
|
};
|
|
889
|
+
const schemaIncludesNullInVariants = (variants) => variants.some(schemaIncludesNull);
|
|
705
890
|
const transformSchemasForVersion = (schemas, version) => {
|
|
706
891
|
if (version === "3.0.3") {
|
|
707
892
|
return schemas;
|
|
@@ -966,22 +1151,59 @@ const OpenApiTagConfig = Schema.Struct({
|
|
|
966
1151
|
name: Schema.String,
|
|
967
1152
|
description: Schema.optional(Schema.String)
|
|
968
1153
|
});
|
|
969
|
-
|
|
1154
|
+
Schema.Literal(
|
|
970
1155
|
"apiKey",
|
|
971
1156
|
"http",
|
|
972
1157
|
"oauth2",
|
|
973
1158
|
"openIdConnect"
|
|
974
1159
|
);
|
|
975
1160
|
const SecuritySchemeIn = Schema.Literal("query", "header", "cookie");
|
|
976
|
-
const
|
|
1161
|
+
const OAuth2FlowConfig = Schema.Struct({
|
|
1162
|
+
authorizationUrl: Schema.optional(Schema.String),
|
|
1163
|
+
tokenUrl: Schema.optional(Schema.String),
|
|
1164
|
+
refreshUrl: Schema.optional(Schema.String),
|
|
1165
|
+
scopes: Schema.optional(
|
|
1166
|
+
Schema.Record({ key: Schema.String, value: Schema.String })
|
|
1167
|
+
)
|
|
1168
|
+
});
|
|
1169
|
+
const OAuth2FlowsConfig = Schema.Struct({
|
|
1170
|
+
implicit: Schema.optional(OAuth2FlowConfig),
|
|
1171
|
+
password: Schema.optional(OAuth2FlowConfig),
|
|
1172
|
+
clientCredentials: Schema.optional(OAuth2FlowConfig),
|
|
1173
|
+
authorizationCode: Schema.optional(OAuth2FlowConfig)
|
|
1174
|
+
});
|
|
1175
|
+
const HttpSecuritySchemeConfig = Schema.Struct({
|
|
977
1176
|
name: Schema.String,
|
|
978
|
-
type:
|
|
979
|
-
scheme: Schema.
|
|
1177
|
+
type: Schema.Literal("http"),
|
|
1178
|
+
scheme: Schema.String,
|
|
980
1179
|
bearerFormat: Schema.optional(Schema.String),
|
|
981
|
-
in: Schema.optional(SecuritySchemeIn),
|
|
982
|
-
parameterName: Schema.optional(Schema.String),
|
|
983
1180
|
description: Schema.optional(Schema.String)
|
|
984
1181
|
});
|
|
1182
|
+
const ApiKeySecuritySchemeConfig = Schema.Struct({
|
|
1183
|
+
name: Schema.String,
|
|
1184
|
+
type: Schema.Literal("apiKey"),
|
|
1185
|
+
in: SecuritySchemeIn,
|
|
1186
|
+
parameterName: Schema.String,
|
|
1187
|
+
description: Schema.optional(Schema.String)
|
|
1188
|
+
});
|
|
1189
|
+
const OAuth2SecuritySchemeConfig = Schema.Struct({
|
|
1190
|
+
name: Schema.String,
|
|
1191
|
+
type: Schema.Literal("oauth2"),
|
|
1192
|
+
flows: OAuth2FlowsConfig,
|
|
1193
|
+
description: Schema.optional(Schema.String)
|
|
1194
|
+
});
|
|
1195
|
+
const OpenIdConnectSecuritySchemeConfig = Schema.Struct({
|
|
1196
|
+
name: Schema.String,
|
|
1197
|
+
type: Schema.Literal("openIdConnect"),
|
|
1198
|
+
openIdConnectUrl: Schema.String,
|
|
1199
|
+
description: Schema.optional(Schema.String)
|
|
1200
|
+
});
|
|
1201
|
+
const SecuritySchemeConfig = Schema.Union(
|
|
1202
|
+
HttpSecuritySchemeConfig,
|
|
1203
|
+
ApiKeySecuritySchemeConfig,
|
|
1204
|
+
OAuth2SecuritySchemeConfig,
|
|
1205
|
+
OpenIdConnectSecuritySchemeConfig
|
|
1206
|
+
);
|
|
985
1207
|
const SecurityRequirement = Schema.Record({
|
|
986
1208
|
key: Schema.String,
|
|
987
1209
|
value: Schema.Array(Schema.String)
|
|
@@ -1013,6 +1235,9 @@ const OpenApiConfig = Schema.Struct({
|
|
|
1013
1235
|
const QueryOptionsConfig = Schema.Struct({
|
|
1014
1236
|
style: Schema.optional(Schema.Literal("inline", "ref"))
|
|
1015
1237
|
});
|
|
1238
|
+
const SchemaOptionsConfig = Schema.Struct({
|
|
1239
|
+
aliasRefs: Schema.optional(Schema.Literal("collapse", "preserve"))
|
|
1240
|
+
});
|
|
1016
1241
|
const PathFilterFunction = Schema.declare(
|
|
1017
1242
|
(input) => typeof input === "function",
|
|
1018
1243
|
{
|
|
@@ -1029,6 +1254,7 @@ const OptionsConfig = Schema.Struct({
|
|
|
1029
1254
|
extractValidation: Schema.optional(Schema.Boolean),
|
|
1030
1255
|
excludeDecorators: Schema.optional(Schema.Array(Schema.String)),
|
|
1031
1256
|
query: Schema.optional(QueryOptionsConfig),
|
|
1257
|
+
schemas: Schema.optional(SchemaOptionsConfig),
|
|
1032
1258
|
pathFilter: Schema.optional(PathFilter)
|
|
1033
1259
|
});
|
|
1034
1260
|
const OpenApiGeneratorConfig = Schema.Struct({
|
|
@@ -1047,6 +1273,7 @@ Schema.Struct({
|
|
|
1047
1273
|
excludeDecorators: Schema.Array(Schema.String),
|
|
1048
1274
|
dtoGlob: Schema.Array(Schema.String),
|
|
1049
1275
|
extractValidation: Schema.Boolean,
|
|
1276
|
+
aliasRefs: Schema.Literal("collapse", "preserve"),
|
|
1050
1277
|
basePath: Schema.optional(Schema.String),
|
|
1051
1278
|
pathFilter: Schema.optional(PathFilter),
|
|
1052
1279
|
version: Schema.optional(Schema.String),
|
|
@@ -1088,7 +1315,7 @@ const CONFIG_FILE_NAMES = [
|
|
|
1088
1315
|
"openapi.config.cjs"
|
|
1089
1316
|
];
|
|
1090
1317
|
const DEFAULT_ENTRY$1 = "src/app.module.ts";
|
|
1091
|
-
const DEFAULT_DTO_GLOB = [
|
|
1318
|
+
const DEFAULT_DTO_GLOB$1 = [
|
|
1092
1319
|
"**/*.dto.ts",
|
|
1093
1320
|
"**/*.entity.ts",
|
|
1094
1321
|
"**/*.model.ts",
|
|
@@ -1101,7 +1328,10 @@ const DEFAULT_CONFIG = {
|
|
|
1101
1328
|
},
|
|
1102
1329
|
options: {
|
|
1103
1330
|
excludeDecorators: ["ApiExcludeEndpoint", "ApiExcludeController"],
|
|
1104
|
-
extractValidation: true
|
|
1331
|
+
extractValidation: true,
|
|
1332
|
+
schemas: {
|
|
1333
|
+
aliasRefs: "collapse"
|
|
1334
|
+
}
|
|
1105
1335
|
},
|
|
1106
1336
|
format: "json",
|
|
1107
1337
|
openapi: {
|
|
@@ -1115,8 +1345,7 @@ const DEFAULT_CONFIG = {
|
|
|
1115
1345
|
};
|
|
1116
1346
|
const findConfigFile = (startDir = process.cwd()) => Effect.gen(function* () {
|
|
1117
1347
|
let currentDir = resolve(startDir);
|
|
1118
|
-
|
|
1119
|
-
while (currentDir !== root) {
|
|
1348
|
+
while (true) {
|
|
1120
1349
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
1121
1350
|
const configPath = resolve(currentDir, fileName);
|
|
1122
1351
|
if (existsSync(configPath)) {
|
|
@@ -1205,7 +1434,7 @@ const resolveConfig = (config) => {
|
|
|
1205
1434
|
const rawEntry = files.entry ?? DEFAULT_ENTRY$1;
|
|
1206
1435
|
const entry = Array.isArray(rawEntry) ? rawEntry : [rawEntry];
|
|
1207
1436
|
const rawDtoGlob = files.dtoGlob;
|
|
1208
|
-
const dtoGlob = rawDtoGlob ? Array.isArray(rawDtoGlob) ? rawDtoGlob : [rawDtoGlob] : [...DEFAULT_DTO_GLOB];
|
|
1437
|
+
const dtoGlob = rawDtoGlob ? Array.isArray(rawDtoGlob) ? rawDtoGlob : [rawDtoGlob] : [...DEFAULT_DTO_GLOB$1];
|
|
1209
1438
|
const tsconfig = files.tsconfig;
|
|
1210
1439
|
if (!tsconfig) {
|
|
1211
1440
|
throw new Error("tsconfig is required in files configuration");
|
|
@@ -1218,6 +1447,7 @@ const resolveConfig = (config) => {
|
|
|
1218
1447
|
excludeDecorators: options.excludeDecorators ?? DEFAULT_CONFIG.options.excludeDecorators,
|
|
1219
1448
|
dtoGlob,
|
|
1220
1449
|
extractValidation: options.extractValidation ?? DEFAULT_CONFIG.options.extractValidation,
|
|
1450
|
+
aliasRefs: options.schemas?.aliasRefs ?? DEFAULT_CONFIG.options.schemas.aliasRefs,
|
|
1221
1451
|
basePath: options.basePath,
|
|
1222
1452
|
version: openapi.version,
|
|
1223
1453
|
info: openapi.info,
|
|
@@ -1484,6 +1714,22 @@ function resolveTypeLocationsFast(baseDir, missingTypes) {
|
|
|
1484
1714
|
}
|
|
1485
1715
|
|
|
1486
1716
|
const DEFAULT_ENTRY = "src/app.module.ts";
|
|
1717
|
+
const DEFAULT_DTO_GLOB = [
|
|
1718
|
+
"**/*.dto.ts",
|
|
1719
|
+
"**/*.entity.ts",
|
|
1720
|
+
"**/*.model.ts",
|
|
1721
|
+
"**/*.schema.ts"
|
|
1722
|
+
];
|
|
1723
|
+
const mergeSingleSecurityRequirement = (left, right) => {
|
|
1724
|
+
const merged = {};
|
|
1725
|
+
for (const requirement of [left, right]) {
|
|
1726
|
+
for (const [scheme, scopes] of Object.entries(requirement)) {
|
|
1727
|
+
const existingScopes = merged[scheme] ?? [];
|
|
1728
|
+
merged[scheme] = [.../* @__PURE__ */ new Set([...existingScopes, ...scopes])];
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
return merged;
|
|
1732
|
+
};
|
|
1487
1733
|
const mergeSecurityWithGlobal = (paths, globalSecurity) => {
|
|
1488
1734
|
if (!globalSecurity || globalSecurity.length === 0) {
|
|
1489
1735
|
return paths;
|
|
@@ -1493,23 +1739,17 @@ const mergeSecurityWithGlobal = (paths, globalSecurity) => {
|
|
|
1493
1739
|
const mergedMethods = {};
|
|
1494
1740
|
for (const [method, operation] of Object.entries(methods)) {
|
|
1495
1741
|
if (operation.security && operation.security.length > 0) {
|
|
1496
|
-
const
|
|
1742
|
+
const mergedSecurity = [];
|
|
1497
1743
|
for (const globalReq of globalSecurity) {
|
|
1498
|
-
for (const
|
|
1499
|
-
|
|
1744
|
+
for (const operationReq of operation.security) {
|
|
1745
|
+
mergedSecurity.push(
|
|
1746
|
+
mergeSingleSecurityRequirement(globalReq, operationReq)
|
|
1747
|
+
);
|
|
1500
1748
|
}
|
|
1501
1749
|
}
|
|
1502
|
-
for (const decoratorReq of operation.security) {
|
|
1503
|
-
for (const [scheme, scopes] of Object.entries(decoratorReq)) {
|
|
1504
|
-
merged[scheme] = [...merged[scheme] ?? [], ...scopes];
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
for (const scheme of Object.keys(merged)) {
|
|
1508
|
-
merged[scheme] = [...new Set(merged[scheme])];
|
|
1509
|
-
}
|
|
1510
1750
|
mergedMethods[method] = {
|
|
1511
1751
|
...operation,
|
|
1512
|
-
security:
|
|
1752
|
+
security: mergedSecurity
|
|
1513
1753
|
};
|
|
1514
1754
|
} else {
|
|
1515
1755
|
mergedMethods[method] = operation;
|
|
@@ -1573,6 +1813,131 @@ const findMissingSchemaRefs = (paths, schemas) => {
|
|
|
1573
1813
|
findRefs(paths);
|
|
1574
1814
|
return missing;
|
|
1575
1815
|
};
|
|
1816
|
+
const isGenericSchemaRef = (name) => name.includes("<") && name.endsWith(">");
|
|
1817
|
+
const NON_IMPORTABLE_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
1818
|
+
"string",
|
|
1819
|
+
"number",
|
|
1820
|
+
"boolean",
|
|
1821
|
+
"null",
|
|
1822
|
+
"undefined",
|
|
1823
|
+
"void",
|
|
1824
|
+
"unknown",
|
|
1825
|
+
"any",
|
|
1826
|
+
"never",
|
|
1827
|
+
"object",
|
|
1828
|
+
"true",
|
|
1829
|
+
"false",
|
|
1830
|
+
"Array",
|
|
1831
|
+
"ReadonlyArray",
|
|
1832
|
+
"Record",
|
|
1833
|
+
"Promise",
|
|
1834
|
+
"Partial",
|
|
1835
|
+
"Required",
|
|
1836
|
+
"Pick",
|
|
1837
|
+
"Omit",
|
|
1838
|
+
"Exclude",
|
|
1839
|
+
"Extract",
|
|
1840
|
+
"Readonly",
|
|
1841
|
+
"keyof",
|
|
1842
|
+
"infer",
|
|
1843
|
+
"extends"
|
|
1844
|
+
]);
|
|
1845
|
+
const extractTypeIdentifiers = (typeRef) => {
|
|
1846
|
+
const withoutStringLiterals = typeRef.replace(
|
|
1847
|
+
/'[^']*'|"[^"]*"|`[^`]*`/g,
|
|
1848
|
+
""
|
|
1849
|
+
);
|
|
1850
|
+
const matches = withoutStringLiterals.match(/\b[A-Za-z_$][A-Za-z0-9_$]*\b/g) ?? [];
|
|
1851
|
+
return new Set(
|
|
1852
|
+
matches.filter((name) => !NON_IMPORTABLE_TYPE_NAMES.has(name))
|
|
1853
|
+
);
|
|
1854
|
+
};
|
|
1855
|
+
const toModuleImportPath = (fromDir, filePath) => {
|
|
1856
|
+
const importPath = relative(fromDir, filePath).replace(/\\/g, "/");
|
|
1857
|
+
return importPath.startsWith(".") ? importPath : `./${importPath}`;
|
|
1858
|
+
};
|
|
1859
|
+
const resolveSymbolLocations = (tsconfig, symbolNames) => {
|
|
1860
|
+
if (symbolNames.size === 0) {
|
|
1861
|
+
return /* @__PURE__ */ new Map();
|
|
1862
|
+
}
|
|
1863
|
+
const tsconfigDir = dirname(tsconfig);
|
|
1864
|
+
const resolved = resolveTypeLocationsFast(tsconfigDir, symbolNames);
|
|
1865
|
+
const unresolved = new Set(
|
|
1866
|
+
[...symbolNames].filter((name) => !resolved.has(name))
|
|
1867
|
+
);
|
|
1868
|
+
if (unresolved.size > 0) {
|
|
1869
|
+
const project = createTypeResolverProject(tsconfig);
|
|
1870
|
+
const morphResolved = resolveTypeLocations(project, unresolved);
|
|
1871
|
+
for (const [name, filePath] of morphResolved) {
|
|
1872
|
+
resolved.set(name, filePath);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
return resolved;
|
|
1876
|
+
};
|
|
1877
|
+
const generateMissingGenericSchemas = async (genericRefs, tsconfig, symbolLocations, runEffect) => {
|
|
1878
|
+
if (genericRefs.length === 0) {
|
|
1879
|
+
return { definitions: {} };
|
|
1880
|
+
}
|
|
1881
|
+
const importGroups = /* @__PURE__ */ new Map();
|
|
1882
|
+
const aliases = [];
|
|
1883
|
+
const aliasLines = [];
|
|
1884
|
+
for (const [index, genericRef] of genericRefs.entries()) {
|
|
1885
|
+
const identifiers = [...extractTypeIdentifiers(genericRef)];
|
|
1886
|
+
if (identifiers.length === 0) {
|
|
1887
|
+
continue;
|
|
1888
|
+
}
|
|
1889
|
+
const unresolved = identifiers.filter((name) => !symbolLocations.has(name));
|
|
1890
|
+
if (unresolved.length > 0) {
|
|
1891
|
+
continue;
|
|
1892
|
+
}
|
|
1893
|
+
for (const identifier of identifiers) {
|
|
1894
|
+
const filePath = symbolLocations.get(identifier);
|
|
1895
|
+
if (!filePath) continue;
|
|
1896
|
+
const existing = importGroups.get(filePath) ?? /* @__PURE__ */ new Set();
|
|
1897
|
+
existing.add(identifier);
|
|
1898
|
+
importGroups.set(filePath, existing);
|
|
1899
|
+
}
|
|
1900
|
+
const aliasName = `__MissingGenericRef${index}`;
|
|
1901
|
+
aliases.push({ aliasName, schemaName: genericRef });
|
|
1902
|
+
aliasLines.push(`export type ${aliasName} = ${genericRef};`);
|
|
1903
|
+
}
|
|
1904
|
+
if (aliases.length === 0) {
|
|
1905
|
+
return { definitions: {} };
|
|
1906
|
+
}
|
|
1907
|
+
const tempDir = dirname(tsconfig);
|
|
1908
|
+
const tempFilePath = join(
|
|
1909
|
+
tempDir,
|
|
1910
|
+
`.openapi.missing-generic.${randomUUID()}.ts`
|
|
1911
|
+
);
|
|
1912
|
+
const importLines = [...importGroups.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([filePath, symbols]) => {
|
|
1913
|
+
const importPath = toModuleImportPath(tempDir, filePath);
|
|
1914
|
+
const names = [...symbols].sort().join(", ");
|
|
1915
|
+
return `import type { ${names} } from '${importPath}';`;
|
|
1916
|
+
});
|
|
1917
|
+
writeFileSync(
|
|
1918
|
+
tempFilePath,
|
|
1919
|
+
[...importLines, "", ...aliasLines, ""].join("\n"),
|
|
1920
|
+
"utf-8"
|
|
1921
|
+
);
|
|
1922
|
+
try {
|
|
1923
|
+
const generated = await runEffect(
|
|
1924
|
+
generateSchemasFromFiles([tempFilePath], tsconfig)
|
|
1925
|
+
);
|
|
1926
|
+
const definitions = { ...generated.definitions };
|
|
1927
|
+
for (const { aliasName, schemaName } of aliases) {
|
|
1928
|
+
const resolvedSchema = definitions[schemaName] ?? definitions[aliasName] ?? void 0;
|
|
1929
|
+
if (resolvedSchema) {
|
|
1930
|
+
definitions[schemaName] = resolvedSchema;
|
|
1931
|
+
}
|
|
1932
|
+
delete definitions[aliasName];
|
|
1933
|
+
}
|
|
1934
|
+
return { definitions };
|
|
1935
|
+
} finally {
|
|
1936
|
+
if (existsSync(tempFilePath)) {
|
|
1937
|
+
unlinkSync(tempFilePath);
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
};
|
|
1576
1941
|
const extractValidationConstraints = async (dtoGlobPatterns, basePath, tsconfig, schemas) => {
|
|
1577
1942
|
const absolutePatterns = dtoGlobPatterns.map(
|
|
1578
1943
|
(pattern) => pattern.startsWith("/") ? pattern : join(basePath, pattern)
|
|
@@ -1619,8 +1984,7 @@ const extractValidationConstraints = async (dtoGlobPatterns, basePath, tsconfig,
|
|
|
1619
1984
|
};
|
|
1620
1985
|
const findTsConfig = (startDir) => {
|
|
1621
1986
|
let currentDir = resolve(startDir);
|
|
1622
|
-
|
|
1623
|
-
while (currentDir !== root) {
|
|
1987
|
+
while (true) {
|
|
1624
1988
|
const tsconfigPath = join(currentDir, "tsconfig.json");
|
|
1625
1989
|
if (existsSync(tsconfigPath)) {
|
|
1626
1990
|
return tsconfigPath;
|
|
@@ -1708,6 +2072,7 @@ const generate = async (configPath, overrides) => {
|
|
|
1708
2072
|
);
|
|
1709
2073
|
const files = config.files ?? {};
|
|
1710
2074
|
const options = config.options ?? {};
|
|
2075
|
+
const aliasRefsMode = options.schemas?.aliasRefs ?? "collapse";
|
|
1711
2076
|
const openapi = config.openapi;
|
|
1712
2077
|
const security = openapi.security ?? {};
|
|
1713
2078
|
const rawEntry = files.entry ?? DEFAULT_ENTRY;
|
|
@@ -1715,19 +2080,30 @@ const generate = async (configPath, overrides) => {
|
|
|
1715
2080
|
(e) => resolve(configDir, e)
|
|
1716
2081
|
);
|
|
1717
2082
|
const output = resolve(configDir, config.output);
|
|
1718
|
-
const tsconfig =
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
2083
|
+
const tsconfig = await runEffect(
|
|
2084
|
+
Effect.gen(function* () {
|
|
2085
|
+
const discoveredTsconfig = files.tsconfig ? resolve(configDir, files.tsconfig) : findTsConfig(dirname(entries[0]));
|
|
2086
|
+
if (!discoveredTsconfig) {
|
|
2087
|
+
return yield* Effect.fail(
|
|
2088
|
+
ConfigValidationError.fromIssues(absoluteConfigPath, [
|
|
2089
|
+
"Could not find tsconfig.json. Please specify files.tsconfig in your config file."
|
|
2090
|
+
])
|
|
2091
|
+
);
|
|
2092
|
+
}
|
|
2093
|
+
if (!existsSync(discoveredTsconfig)) {
|
|
2094
|
+
return yield* Effect.fail(
|
|
2095
|
+
ConfigValidationError.fromIssues(absoluteConfigPath, [
|
|
2096
|
+
`tsconfig.json not found at: ${discoveredTsconfig}`
|
|
2097
|
+
])
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
return discoveredTsconfig;
|
|
2101
|
+
}).pipe(Effect.mapError((error) => new Error(error.message)))
|
|
2102
|
+
);
|
|
1727
2103
|
const extractOptions = {
|
|
1728
2104
|
query: options.query
|
|
1729
2105
|
};
|
|
1730
|
-
const dtoGlobArray = files.dtoGlob ? Array.isArray(files.dtoGlob) ? files.dtoGlob : [files.dtoGlob]
|
|
2106
|
+
const dtoGlobArray = files.dtoGlob === void 0 ? [...DEFAULT_DTO_GLOB] : Array.isArray(files.dtoGlob) ? files.dtoGlob : [files.dtoGlob];
|
|
1731
2107
|
const [extractedMethodInfos, initialSchemas] = await Promise.all([
|
|
1732
2108
|
runEffect(
|
|
1733
2109
|
extractMethodInfosEffect(tsconfig, entries, extractOptions).pipe(
|
|
@@ -1739,7 +2115,7 @@ const generate = async (configPath, overrides) => {
|
|
|
1739
2115
|
Effect.mapError((error) => new Error(error.message))
|
|
1740
2116
|
)
|
|
1741
2117
|
),
|
|
1742
|
-
|
|
2118
|
+
runEffect(
|
|
1743
2119
|
generateSchemas({
|
|
1744
2120
|
dtoGlob: dtoGlobArray,
|
|
1745
2121
|
tsconfig,
|
|
@@ -1755,7 +2131,7 @@ const generate = async (configPath, overrides) => {
|
|
|
1755
2131
|
),
|
|
1756
2132
|
Effect.mapError((error) => new Error(error.message))
|
|
1757
2133
|
)
|
|
1758
|
-
)
|
|
2134
|
+
)
|
|
1759
2135
|
]);
|
|
1760
2136
|
const filteredMethodInfos = filterMethods(extractedMethodInfos, {
|
|
1761
2137
|
excludeDecorators: options.excludeDecorators,
|
|
@@ -1776,7 +2152,7 @@ const generate = async (configPath, overrides) => {
|
|
|
1776
2152
|
security.global
|
|
1777
2153
|
);
|
|
1778
2154
|
let schemas = {};
|
|
1779
|
-
if (initialSchemas
|
|
2155
|
+
if (initialSchemas) {
|
|
1780
2156
|
let generatedSchemas = initialSchemas;
|
|
1781
2157
|
const shouldExtractValidation = options.extractValidation !== false;
|
|
1782
2158
|
if (shouldExtractValidation) {
|
|
@@ -1828,6 +2204,50 @@ const generate = async (configPath, overrides) => {
|
|
|
1828
2204
|
...normalizedAdditional.definitions
|
|
1829
2205
|
}
|
|
1830
2206
|
};
|
|
2207
|
+
generatedSchemas = combinedSchemas;
|
|
2208
|
+
mergeResult = mergeSchemas(
|
|
2209
|
+
paths,
|
|
2210
|
+
combinedSchemas
|
|
2211
|
+
);
|
|
2212
|
+
schemas = mergeResult.schemas;
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
const unresolvedAfterFileResolution = findMissingSchemaRefs(
|
|
2216
|
+
paths,
|
|
2217
|
+
schemas
|
|
2218
|
+
);
|
|
2219
|
+
const unresolvedGenericRefs = [...unresolvedAfterFileResolution].filter(
|
|
2220
|
+
isGenericSchemaRef
|
|
2221
|
+
);
|
|
2222
|
+
if (unresolvedGenericRefs.length > 0) {
|
|
2223
|
+
const genericSymbols = /* @__PURE__ */ new Set();
|
|
2224
|
+
for (const ref of unresolvedGenericRefs) {
|
|
2225
|
+
for (const symbol of extractTypeIdentifiers(ref)) {
|
|
2226
|
+
genericSymbols.add(symbol);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
const resolvedGenericSymbols = resolveSymbolLocations(
|
|
2230
|
+
tsconfig,
|
|
2231
|
+
genericSymbols
|
|
2232
|
+
);
|
|
2233
|
+
for (const [name, filePath] of resolvedLocations) {
|
|
2234
|
+
resolvedGenericSymbols.set(name, filePath);
|
|
2235
|
+
}
|
|
2236
|
+
const genericSchemas = await generateMissingGenericSchemas(
|
|
2237
|
+
unresolvedGenericRefs,
|
|
2238
|
+
tsconfig,
|
|
2239
|
+
resolvedGenericSymbols,
|
|
2240
|
+
runEffect
|
|
2241
|
+
);
|
|
2242
|
+
if (Object.keys(genericSchemas.definitions).length > 0) {
|
|
2243
|
+
const normalizedGeneric = normalizeStructureRefs(genericSchemas);
|
|
2244
|
+
const combinedSchemas = {
|
|
2245
|
+
definitions: {
|
|
2246
|
+
...generatedSchemas.definitions,
|
|
2247
|
+
...normalizedGeneric.definitions
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
generatedSchemas = combinedSchemas;
|
|
1831
2251
|
mergeResult = mergeSchemas(
|
|
1832
2252
|
paths,
|
|
1833
2253
|
combinedSchemas
|
|
@@ -1837,6 +2257,11 @@ const generate = async (configPath, overrides) => {
|
|
|
1837
2257
|
}
|
|
1838
2258
|
}
|
|
1839
2259
|
}
|
|
2260
|
+
if (aliasRefsMode === "collapse" && Object.keys(schemas).length > 0) {
|
|
2261
|
+
const collapsed = collapseAliasRefs(paths, schemas);
|
|
2262
|
+
paths = collapsed.paths;
|
|
2263
|
+
schemas = collapsed.schemas;
|
|
2264
|
+
}
|
|
1840
2265
|
const securitySchemes = security.schemes && security.schemes.length > 0 ? buildSecuritySchemes(security.schemes) : void 0;
|
|
1841
2266
|
const hasSchemas = Object.keys(schemas).length > 0;
|
|
1842
2267
|
const hasSecuritySchemes = securitySchemes && Object.keys(securitySchemes).length > 0;
|
|
@@ -252,15 +252,54 @@ declare const OpenApiGeneratorConfig: Schema.Struct<{
|
|
|
252
252
|
description: Schema.optional<typeof Schema.String>;
|
|
253
253
|
}>>>;
|
|
254
254
|
security: Schema.optional<Schema.Struct<{
|
|
255
|
-
schemes: Schema.optional<Schema.Array$<Schema.Struct<{
|
|
255
|
+
schemes: Schema.optional<Schema.Array$<Schema.Union<[Schema.Struct<{
|
|
256
256
|
name: typeof Schema.String;
|
|
257
|
-
type: Schema.Literal<["
|
|
258
|
-
scheme:
|
|
257
|
+
type: Schema.Literal<["http"]>;
|
|
258
|
+
scheme: typeof Schema.String;
|
|
259
259
|
bearerFormat: Schema.optional<typeof Schema.String>;
|
|
260
|
-
in: Schema.optional<Schema.Literal<["query", "header", "cookie"]>>;
|
|
261
|
-
parameterName: Schema.optional<typeof Schema.String>;
|
|
262
260
|
description: Schema.optional<typeof Schema.String>;
|
|
263
|
-
}
|
|
261
|
+
}>, Schema.Struct<{
|
|
262
|
+
name: typeof Schema.String;
|
|
263
|
+
type: Schema.Literal<["apiKey"]>;
|
|
264
|
+
in: Schema.Literal<["query", "header", "cookie"]>;
|
|
265
|
+
parameterName: typeof Schema.String;
|
|
266
|
+
description: Schema.optional<typeof Schema.String>;
|
|
267
|
+
}>, Schema.Struct<{
|
|
268
|
+
name: typeof Schema.String;
|
|
269
|
+
type: Schema.Literal<["oauth2"]>;
|
|
270
|
+
flows: Schema.Struct<{
|
|
271
|
+
implicit: Schema.optional<Schema.Struct<{
|
|
272
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
273
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
274
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
275
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
276
|
+
}>>;
|
|
277
|
+
password: Schema.optional<Schema.Struct<{
|
|
278
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
279
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
280
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
281
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
282
|
+
}>>;
|
|
283
|
+
clientCredentials: Schema.optional<Schema.Struct<{
|
|
284
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
285
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
286
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
287
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
288
|
+
}>>;
|
|
289
|
+
authorizationCode: Schema.optional<Schema.Struct<{
|
|
290
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
291
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
292
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
293
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
294
|
+
}>>;
|
|
295
|
+
}>;
|
|
296
|
+
description: Schema.optional<typeof Schema.String>;
|
|
297
|
+
}>, Schema.Struct<{
|
|
298
|
+
name: typeof Schema.String;
|
|
299
|
+
type: Schema.Literal<["openIdConnect"]>;
|
|
300
|
+
openIdConnectUrl: typeof Schema.String;
|
|
301
|
+
description: Schema.optional<typeof Schema.String>;
|
|
302
|
+
}>]>>>;
|
|
264
303
|
global: Schema.optional<Schema.Array$<Schema.Record$<typeof Schema.String, Schema.Array$<typeof Schema.String>>>>;
|
|
265
304
|
}>>;
|
|
266
305
|
}>;
|
|
@@ -271,6 +310,9 @@ declare const OpenApiGeneratorConfig: Schema.Struct<{
|
|
|
271
310
|
query: Schema.optional<Schema.Struct<{
|
|
272
311
|
style: Schema.optional<Schema.Literal<["inline", "ref"]>>;
|
|
273
312
|
}>>;
|
|
313
|
+
schemas: Schema.optional<Schema.Struct<{
|
|
314
|
+
aliasRefs: Schema.optional<Schema.Literal<["collapse", "preserve"]>>;
|
|
315
|
+
}>>;
|
|
274
316
|
pathFilter: Schema.optional<Schema.Union<[Schema.instanceOf<RegExp>, Schema.declare<(path: string) => boolean, (path: string) => boolean, readonly [], never>]>>;
|
|
275
317
|
}>>;
|
|
276
318
|
}>;
|
|
@@ -283,6 +325,7 @@ declare const ResolvedConfig: Schema.Struct<{
|
|
|
283
325
|
excludeDecorators: Schema.Array$<typeof Schema.String>;
|
|
284
326
|
dtoGlob: Schema.Array$<typeof Schema.String>;
|
|
285
327
|
extractValidation: typeof Schema.Boolean;
|
|
328
|
+
aliasRefs: Schema.Literal<["collapse", "preserve"]>;
|
|
286
329
|
basePath: Schema.optional<typeof Schema.String>;
|
|
287
330
|
pathFilter: Schema.optional<Schema.Union<[Schema.instanceOf<RegExp>, Schema.declare<(path: string) => boolean, (path: string) => boolean, readonly [], never>]>>;
|
|
288
331
|
version: Schema.optional<typeof Schema.String>;
|
|
@@ -304,15 +347,54 @@ declare const ResolvedConfig: Schema.Struct<{
|
|
|
304
347
|
url: typeof Schema.String;
|
|
305
348
|
description: Schema.optional<typeof Schema.String>;
|
|
306
349
|
}>>;
|
|
307
|
-
securitySchemes: Schema.Array$<Schema.Struct<{
|
|
350
|
+
securitySchemes: Schema.Array$<Schema.Union<[Schema.Struct<{
|
|
308
351
|
name: typeof Schema.String;
|
|
309
|
-
type: Schema.Literal<["
|
|
310
|
-
scheme:
|
|
352
|
+
type: Schema.Literal<["http"]>;
|
|
353
|
+
scheme: typeof Schema.String;
|
|
311
354
|
bearerFormat: Schema.optional<typeof Schema.String>;
|
|
312
|
-
in: Schema.optional<Schema.Literal<["query", "header", "cookie"]>>;
|
|
313
|
-
parameterName: Schema.optional<typeof Schema.String>;
|
|
314
355
|
description: Schema.optional<typeof Schema.String>;
|
|
315
|
-
}
|
|
356
|
+
}>, Schema.Struct<{
|
|
357
|
+
name: typeof Schema.String;
|
|
358
|
+
type: Schema.Literal<["apiKey"]>;
|
|
359
|
+
in: Schema.Literal<["query", "header", "cookie"]>;
|
|
360
|
+
parameterName: typeof Schema.String;
|
|
361
|
+
description: Schema.optional<typeof Schema.String>;
|
|
362
|
+
}>, Schema.Struct<{
|
|
363
|
+
name: typeof Schema.String;
|
|
364
|
+
type: Schema.Literal<["oauth2"]>;
|
|
365
|
+
flows: Schema.Struct<{
|
|
366
|
+
implicit: Schema.optional<Schema.Struct<{
|
|
367
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
368
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
369
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
370
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
371
|
+
}>>;
|
|
372
|
+
password: Schema.optional<Schema.Struct<{
|
|
373
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
374
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
375
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
376
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
377
|
+
}>>;
|
|
378
|
+
clientCredentials: Schema.optional<Schema.Struct<{
|
|
379
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
380
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
381
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
382
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
383
|
+
}>>;
|
|
384
|
+
authorizationCode: Schema.optional<Schema.Struct<{
|
|
385
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
386
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
387
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
388
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
389
|
+
}>>;
|
|
390
|
+
}>;
|
|
391
|
+
description: Schema.optional<typeof Schema.String>;
|
|
392
|
+
}>, Schema.Struct<{
|
|
393
|
+
name: typeof Schema.String;
|
|
394
|
+
type: Schema.Literal<["openIdConnect"]>;
|
|
395
|
+
openIdConnectUrl: typeof Schema.String;
|
|
396
|
+
description: Schema.optional<typeof Schema.String>;
|
|
397
|
+
}>]>>;
|
|
316
398
|
securityRequirements: Schema.Array$<Schema.Record$<typeof Schema.String, Schema.Array$<typeof Schema.String>>>;
|
|
317
399
|
tags: Schema.Array$<Schema.Struct<{
|
|
318
400
|
name: typeof Schema.String;
|
|
@@ -252,15 +252,54 @@ declare const OpenApiGeneratorConfig: Schema.Struct<{
|
|
|
252
252
|
description: Schema.optional<typeof Schema.String>;
|
|
253
253
|
}>>>;
|
|
254
254
|
security: Schema.optional<Schema.Struct<{
|
|
255
|
-
schemes: Schema.optional<Schema.Array$<Schema.Struct<{
|
|
255
|
+
schemes: Schema.optional<Schema.Array$<Schema.Union<[Schema.Struct<{
|
|
256
256
|
name: typeof Schema.String;
|
|
257
|
-
type: Schema.Literal<["
|
|
258
|
-
scheme:
|
|
257
|
+
type: Schema.Literal<["http"]>;
|
|
258
|
+
scheme: typeof Schema.String;
|
|
259
259
|
bearerFormat: Schema.optional<typeof Schema.String>;
|
|
260
|
-
in: Schema.optional<Schema.Literal<["query", "header", "cookie"]>>;
|
|
261
|
-
parameterName: Schema.optional<typeof Schema.String>;
|
|
262
260
|
description: Schema.optional<typeof Schema.String>;
|
|
263
|
-
}
|
|
261
|
+
}>, Schema.Struct<{
|
|
262
|
+
name: typeof Schema.String;
|
|
263
|
+
type: Schema.Literal<["apiKey"]>;
|
|
264
|
+
in: Schema.Literal<["query", "header", "cookie"]>;
|
|
265
|
+
parameterName: typeof Schema.String;
|
|
266
|
+
description: Schema.optional<typeof Schema.String>;
|
|
267
|
+
}>, Schema.Struct<{
|
|
268
|
+
name: typeof Schema.String;
|
|
269
|
+
type: Schema.Literal<["oauth2"]>;
|
|
270
|
+
flows: Schema.Struct<{
|
|
271
|
+
implicit: Schema.optional<Schema.Struct<{
|
|
272
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
273
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
274
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
275
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
276
|
+
}>>;
|
|
277
|
+
password: Schema.optional<Schema.Struct<{
|
|
278
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
279
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
280
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
281
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
282
|
+
}>>;
|
|
283
|
+
clientCredentials: Schema.optional<Schema.Struct<{
|
|
284
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
285
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
286
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
287
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
288
|
+
}>>;
|
|
289
|
+
authorizationCode: Schema.optional<Schema.Struct<{
|
|
290
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
291
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
292
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
293
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
294
|
+
}>>;
|
|
295
|
+
}>;
|
|
296
|
+
description: Schema.optional<typeof Schema.String>;
|
|
297
|
+
}>, Schema.Struct<{
|
|
298
|
+
name: typeof Schema.String;
|
|
299
|
+
type: Schema.Literal<["openIdConnect"]>;
|
|
300
|
+
openIdConnectUrl: typeof Schema.String;
|
|
301
|
+
description: Schema.optional<typeof Schema.String>;
|
|
302
|
+
}>]>>>;
|
|
264
303
|
global: Schema.optional<Schema.Array$<Schema.Record$<typeof Schema.String, Schema.Array$<typeof Schema.String>>>>;
|
|
265
304
|
}>>;
|
|
266
305
|
}>;
|
|
@@ -271,6 +310,9 @@ declare const OpenApiGeneratorConfig: Schema.Struct<{
|
|
|
271
310
|
query: Schema.optional<Schema.Struct<{
|
|
272
311
|
style: Schema.optional<Schema.Literal<["inline", "ref"]>>;
|
|
273
312
|
}>>;
|
|
313
|
+
schemas: Schema.optional<Schema.Struct<{
|
|
314
|
+
aliasRefs: Schema.optional<Schema.Literal<["collapse", "preserve"]>>;
|
|
315
|
+
}>>;
|
|
274
316
|
pathFilter: Schema.optional<Schema.Union<[Schema.instanceOf<RegExp>, Schema.declare<(path: string) => boolean, (path: string) => boolean, readonly [], never>]>>;
|
|
275
317
|
}>>;
|
|
276
318
|
}>;
|
|
@@ -283,6 +325,7 @@ declare const ResolvedConfig: Schema.Struct<{
|
|
|
283
325
|
excludeDecorators: Schema.Array$<typeof Schema.String>;
|
|
284
326
|
dtoGlob: Schema.Array$<typeof Schema.String>;
|
|
285
327
|
extractValidation: typeof Schema.Boolean;
|
|
328
|
+
aliasRefs: Schema.Literal<["collapse", "preserve"]>;
|
|
286
329
|
basePath: Schema.optional<typeof Schema.String>;
|
|
287
330
|
pathFilter: Schema.optional<Schema.Union<[Schema.instanceOf<RegExp>, Schema.declare<(path: string) => boolean, (path: string) => boolean, readonly [], never>]>>;
|
|
288
331
|
version: Schema.optional<typeof Schema.String>;
|
|
@@ -304,15 +347,54 @@ declare const ResolvedConfig: Schema.Struct<{
|
|
|
304
347
|
url: typeof Schema.String;
|
|
305
348
|
description: Schema.optional<typeof Schema.String>;
|
|
306
349
|
}>>;
|
|
307
|
-
securitySchemes: Schema.Array$<Schema.Struct<{
|
|
350
|
+
securitySchemes: Schema.Array$<Schema.Union<[Schema.Struct<{
|
|
308
351
|
name: typeof Schema.String;
|
|
309
|
-
type: Schema.Literal<["
|
|
310
|
-
scheme:
|
|
352
|
+
type: Schema.Literal<["http"]>;
|
|
353
|
+
scheme: typeof Schema.String;
|
|
311
354
|
bearerFormat: Schema.optional<typeof Schema.String>;
|
|
312
|
-
in: Schema.optional<Schema.Literal<["query", "header", "cookie"]>>;
|
|
313
|
-
parameterName: Schema.optional<typeof Schema.String>;
|
|
314
355
|
description: Schema.optional<typeof Schema.String>;
|
|
315
|
-
}
|
|
356
|
+
}>, Schema.Struct<{
|
|
357
|
+
name: typeof Schema.String;
|
|
358
|
+
type: Schema.Literal<["apiKey"]>;
|
|
359
|
+
in: Schema.Literal<["query", "header", "cookie"]>;
|
|
360
|
+
parameterName: typeof Schema.String;
|
|
361
|
+
description: Schema.optional<typeof Schema.String>;
|
|
362
|
+
}>, Schema.Struct<{
|
|
363
|
+
name: typeof Schema.String;
|
|
364
|
+
type: Schema.Literal<["oauth2"]>;
|
|
365
|
+
flows: Schema.Struct<{
|
|
366
|
+
implicit: Schema.optional<Schema.Struct<{
|
|
367
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
368
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
369
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
370
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
371
|
+
}>>;
|
|
372
|
+
password: Schema.optional<Schema.Struct<{
|
|
373
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
374
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
375
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
376
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
377
|
+
}>>;
|
|
378
|
+
clientCredentials: Schema.optional<Schema.Struct<{
|
|
379
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
380
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
381
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
382
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
383
|
+
}>>;
|
|
384
|
+
authorizationCode: Schema.optional<Schema.Struct<{
|
|
385
|
+
authorizationUrl: Schema.optional<typeof Schema.String>;
|
|
386
|
+
tokenUrl: Schema.optional<typeof Schema.String>;
|
|
387
|
+
refreshUrl: Schema.optional<typeof Schema.String>;
|
|
388
|
+
scopes: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
|
|
389
|
+
}>>;
|
|
390
|
+
}>;
|
|
391
|
+
description: Schema.optional<typeof Schema.String>;
|
|
392
|
+
}>, Schema.Struct<{
|
|
393
|
+
name: typeof Schema.String;
|
|
394
|
+
type: Schema.Literal<["openIdConnect"]>;
|
|
395
|
+
openIdConnectUrl: typeof Schema.String;
|
|
396
|
+
description: Schema.optional<typeof Schema.String>;
|
|
397
|
+
}>]>>;
|
|
316
398
|
securityRequirements: Schema.Array$<Schema.Record$<typeof Schema.String, Schema.Array$<typeof Schema.String>>>;
|
|
317
399
|
tags: Schema.Array$<Schema.Struct<{
|
|
318
400
|
name: typeof Schema.String;
|
|
@@ -703,6 +703,22 @@ const parseTypeText = (text) => {
|
|
|
703
703
|
const trimmed = text.trim();
|
|
704
704
|
return trimmed.startsWith("{") && trimmed.endsWith("}") ? { type: Option.none(), inline: Option.some(trimmed) } : { type: Option.some(trimmed), inline: Option.none() };
|
|
705
705
|
};
|
|
706
|
+
const getGenericBaseType = (text) => {
|
|
707
|
+
const genericStart = text.indexOf("<");
|
|
708
|
+
return genericStart === -1 ? null : text.slice(0, genericStart).trim();
|
|
709
|
+
};
|
|
710
|
+
const hasAliasedImportCollision = (method, exportedName) => {
|
|
711
|
+
const localNames = /* @__PURE__ */ new Set();
|
|
712
|
+
for (const importDecl of method.getSourceFile().getImportDeclarations()) {
|
|
713
|
+
for (const namedImport of importDecl.getNamedImports()) {
|
|
714
|
+
const aliasNode = namedImport.getAliasNode();
|
|
715
|
+
if (!aliasNode) continue;
|
|
716
|
+
if (namedImport.getName() !== exportedName) continue;
|
|
717
|
+
localNames.add(aliasNode.getText());
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return localNames.size > 1;
|
|
721
|
+
};
|
|
706
722
|
const getReturnTypeInfo = (method) => {
|
|
707
723
|
const returnType = method.getReturnType();
|
|
708
724
|
const awaited = returnType.getAwaitedType?.() ?? returnType;
|
|
@@ -717,6 +733,25 @@ const getReturnTypeInfo = (method) => {
|
|
|
717
733
|
return null;
|
|
718
734
|
};
|
|
719
735
|
let text = getOriginalTypeName() ?? awaited.getText(method);
|
|
736
|
+
const compilerType = awaited.compilerType;
|
|
737
|
+
const aliasName = compilerType.aliasSymbol?.escapedName?.toString();
|
|
738
|
+
if (aliasName && !aliasName.startsWith("__")) {
|
|
739
|
+
const genericBase = getGenericBaseType(text);
|
|
740
|
+
const shouldPreserveLocalAlias = genericBase !== null && genericBase !== aliasName && hasAliasedImportCollision(method, aliasName);
|
|
741
|
+
if (!shouldPreserveLocalAlias) {
|
|
742
|
+
text = genericBase === null ? aliasName : `${aliasName}${text.slice(text.indexOf("<"))}`;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
const symbolName = symbol?.getName();
|
|
746
|
+
if (symbolName && !symbolName.startsWith("__")) {
|
|
747
|
+
const genericBase = getGenericBaseType(text);
|
|
748
|
+
if (genericBase !== null) {
|
|
749
|
+
const shouldPreserveLocalAlias = genericBase !== symbolName && hasAliasedImportCollision(method, symbolName);
|
|
750
|
+
if (!shouldPreserveLocalAlias) {
|
|
751
|
+
text = `${symbolName}${text.slice(text.indexOf("<"))}`;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
720
755
|
const promiseMatch = text.match(/^Promise<(.+)>$/);
|
|
721
756
|
if (promiseMatch) text = promiseMatch[1].trim();
|
|
722
757
|
text = text.replace(/\bimport\([^)]*\)\./g, "");
|
package/package.json
CHANGED