swagger-typescript-api 13.2.18 → 13.3.1

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.
@@ -1,22 +1,24 @@
1
1
  import { t as __exportAll } from "./chunk-DQk6qfdC.mjs";
2
2
  import * as module from "node:module";
3
- import { consola } from "consola";
3
+ import consola, { consola as consola$1 } from "consola";
4
4
  import * as esToolkit from "es-toolkit";
5
- import { compact, flattenDeep, isEqual, merge, omit, uniq } from "es-toolkit";
5
+ import { compact, flattenDeep, isEqual, mapValues, merge, omit, uniq } from "es-toolkit";
6
6
  import * as esToolkitCompat from "es-toolkit/compat";
7
- import { camelCase, get, startCase, upperFirst } from "es-toolkit/compat";
7
+ import { camelCase, get, reduce, startCase, upperFirst } from "es-toolkit/compat";
8
8
  import * as typescript from "typescript";
9
9
  import * as path$1 from "node:path";
10
10
  import path from "node:path";
11
11
  import { Biome, Distribution } from "@biomejs/js-api";
12
12
  import * as nanoid from "nanoid";
13
+ import { typeGuard } from "yummies/type-guard";
13
14
  import * as crypto from "node:crypto";
14
15
  import * as swagger2openapi from "swagger2openapi";
15
16
  import * as YAML from "yaml";
17
+ import * as fs from "node:fs";
18
+ import SwaggerParser from "@apidevtools/swagger-parser";
16
19
  import * as url$1 from "node:url";
17
20
  import url from "node:url";
18
21
  import { Eta } from "eta";
19
- import * as fs from "node:fs";
20
22
 
21
23
  //#region src/code-formatter.ts
22
24
  var CodeFormatter = class {
@@ -119,7 +121,7 @@ var NameResolver = class {
119
121
  while (usageName === null) {
120
122
  const variant = resolver(variants, extras);
121
123
  if (variant === void 0) {
122
- consola.warn("unable to resolve name. current reserved names: ", ...this.reservedNames);
124
+ consola$1.warn("unable to resolve name. current reserved names: ", ...this.reservedNames);
123
125
  return null;
124
126
  }
125
127
  if (!shouldReserve || !this.isReserved(variant)) usageName = variant;
@@ -135,10 +137,10 @@ var NameResolver = class {
135
137
  shouldReserve && this.reserve([usageName]);
136
138
  return usageName;
137
139
  }
138
- consola.debug("trying to resolve name with using fallback name generator using variants", ...variants);
140
+ consola$1.debug("trying to resolve name with using fallback name generator using variants", ...variants);
139
141
  return this.resolve(variants, this.getFallbackName, extras);
140
142
  }
141
- consola.debug("problem with reserving names. current reserved names: ", ...this.reservedNames);
143
+ consola$1.debug("problem with reserving names. current reserved names: ", ...this.reservedNames);
142
144
  return null;
143
145
  }
144
146
  };
@@ -164,11 +166,11 @@ var ComponentTypeNameResolver = class extends NameResolver {
164
166
  const variantCounter = this.countersByVariant.get(randomVariant) + 1;
165
167
  this.countersByVariant.set(randomVariant, variantCounter);
166
168
  const dirtyResolvedName = `${randomVariant}${variantCounter}`;
167
- consola.debug("generated dirty resolved type name for component - ", dirtyResolvedName);
169
+ consola$1.debug("generated dirty resolved type name for component - ", dirtyResolvedName);
168
170
  return dirtyResolvedName;
169
171
  }
170
172
  const fallbackName = `${this.config.componentTypeNameResolver}${this.fallbackNameCounter++}`;
171
- consola.debug("generated fallback type name for component - ", fallbackName);
173
+ consola$1.debug("generated fallback type name for component - ", fallbackName);
172
174
  return fallbackName;
173
175
  });
174
176
  }
@@ -177,7 +179,7 @@ var ComponentTypeNameResolver = class extends NameResolver {
177
179
  //#endregion
178
180
  //#region package.json
179
181
  var name = "swagger-typescript-api";
180
- var version = "13.2.18";
182
+ var version = "13.3.1";
181
183
  var description = "Generate the API client for Fetch or Axios from an OpenAPI Specification";
182
184
 
183
185
  //#endregion
@@ -338,6 +340,7 @@ var CodeGenConfig = class {
338
340
  onFormatTypeName: (_typeName, _rawTypeName, _schemaType) => {},
339
341
  onFormatRouteName: (_routeInfo, _templateRouteName) => {}
340
342
  };
343
+ resolvedSwaggerSchema;
341
344
  defaultResponseType;
342
345
  singleHttpClient = false;
343
346
  httpClientType = HTTP_CLIENT.FETCH;
@@ -593,11 +596,16 @@ var CodeGenConfig = class {
593
596
  };
594
597
  };
595
598
 
599
+ //#endregion
600
+ //#region src/util/pascal-case.ts
601
+ function pascalCase(value) {
602
+ return upperFirst(camelCase(value));
603
+ }
604
+
596
605
  //#endregion
597
606
  //#region src/schema-components-map.ts
598
607
  var SchemaComponentsMap = class {
599
608
  _data = [];
600
- config;
601
609
  constructor(config) {
602
610
  this.config = config;
603
611
  }
@@ -610,18 +618,27 @@ var SchemaComponentsMap = class {
610
618
  parseRef = (ref) => {
611
619
  return ref.split("/");
612
620
  };
613
- createComponent($ref, rawTypeData) {
621
+ createComponentDraft($ref, rawTypeData) {
622
+ if (typeGuard.isObject(rawTypeData) && rawTypeData.typeName && rawTypeData.rawTypeData && rawTypeData.$ref) return rawTypeData;
614
623
  const parsed = this.parseRef($ref);
615
- const componentSchema = {
624
+ const [, rawPointer = ""] = $ref.split("#");
625
+ const pointerParts = (rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}`).split("/").filter(Boolean);
626
+ const typeName = pointerParts.at(-1) || parsed.at(-1) || "Unknown";
627
+ const rawComponentName = pointerParts.at(-2) || parsed[parsed.length - 2] || "schemas";
628
+ return {
616
629
  $ref,
617
- typeName: parsed[parsed.length - 1],
630
+ typeName,
618
631
  rawTypeData,
619
- componentName: parsed[parsed.length - 2],
632
+ componentName: rawComponentName === "definitions" ? "schemas" : rawComponentName,
620
633
  typeData: null
621
634
  };
635
+ }
636
+ createComponent($ref, rawTypeData, addAtStart) {
637
+ const componentSchema = this.createComponentDraft($ref, rawTypeData);
622
638
  const usageComponent = this.config.hooks.onCreateComponent(componentSchema) || componentSchema;
623
639
  const refIndex = this._data.findIndex((c) => c.$ref === $ref);
624
- if (refIndex === -1) this._data.push(usageComponent);
640
+ if (refIndex === -1) if (addAtStart) this._data.unshift(usageComponent);
641
+ else this._data.push(usageComponent);
625
642
  else this._data[refIndex] = usageComponent;
626
643
  return usageComponent;
627
644
  }
@@ -632,7 +649,19 @@ var SchemaComponentsMap = class {
632
649
  return this._data.filter((it) => componentNames.some((componentName) => it.$ref.startsWith(`#/components/${componentName}`)));
633
650
  }
634
651
  get = ($ref) => {
635
- return this._data.find((c) => c.$ref === $ref) || null;
652
+ const localFound = this._data.find((c) => c.$ref === $ref) || null;
653
+ if (localFound != null) return localFound;
654
+ const { resolvedSwaggerSchema } = this.config;
655
+ if (resolvedSwaggerSchema.isLocalRef($ref)) return null;
656
+ const foundByRef = resolvedSwaggerSchema.getRef($ref);
657
+ const refDetails = resolvedSwaggerSchema.getRefDetails($ref);
658
+ if (foundByRef != null) {
659
+ const componentDraft = this.createComponentDraft($ref, foundByRef);
660
+ componentDraft.typeName = this.config.hooks.onFormatExternalTypeName?.(componentDraft.typeName, refDetails) || componentDraft.typeName;
661
+ if (this._data.some((component) => component.typeName === componentDraft.typeName)) componentDraft.typeName = this.config.hooks.onFixDuplicateExternalTypeName?.(componentDraft.typeName, refDetails, this._data.map((it) => it.typeName)) ?? `${pascalCase(refDetails.externalOpenapiFileName || "External")}${componentDraft.typeName}`;
662
+ return this.createComponent($ref, componentDraft);
663
+ }
664
+ return null;
636
665
  };
637
666
  enumsFirst() {
638
667
  this._data.sort((a, b) => {
@@ -918,7 +947,7 @@ var DiscriminatorSchemaParser = class extends MonoSchemaParser {
918
947
  const mappingUsageKey = mappingPropertySchemaEnumKeysMap[mappingKey] || ts.StringValue(mappingKey);
919
948
  if (ableToCreateMappingType) return ts.TypeWithGeneric(mappingTypeName, [mappingUsageKey, content]);
920
949
  return ts.ExpressionGroup(ts.IntersectionType([ts.ObjectWrapper(ts.TypeField({
921
- key: discriminator.propertyName,
950
+ key: ts.StringValue(discriminator.propertyName),
922
951
  value: mappingUsageKey
923
952
  })), content]));
924
953
  };
@@ -1015,7 +1044,7 @@ var EnumKeyResolver = class extends NameResolver {
1015
1044
  constructor(config, reservedNames) {
1016
1045
  super(config, reservedNames, (variants) => {
1017
1046
  const generatedVariant = variants[0] && `${variants[0]}${this.counter++}` || `${this.config.enumKeyResolverName}${this.counter++}`;
1018
- consola.debug("generated fallback type name for enum key - ", generatedVariant);
1047
+ consola$1.debug("generated fallback type name for enum key - ", generatedVariant);
1019
1048
  return generatedVariant;
1020
1049
  });
1021
1050
  }
@@ -1216,7 +1245,12 @@ var PrimitiveSchemaParser = class extends MonoSchemaParser {
1216
1245
  }
1217
1246
  if (Array.isArray(type) && type.length) contentType = this.schemaParser._complexSchemaParsers.oneOf({
1218
1247
  ...typeof this.schema === "object" ? this.schema : {},
1219
- oneOf: type.map((type) => ({ type }))
1248
+ oneOf: type.map((t) => {
1249
+ const branch = { type: t };
1250
+ Object.assign(branch, this.schema);
1251
+ branch.type = t;
1252
+ return branch;
1253
+ })
1220
1254
  });
1221
1255
  if (Array.isArray(items) && type === SCHEMA_TYPES$1.ARRAY) contentType = this.config.Ts.Tuple(items.map((item) => this.schemaParserFabric.createSchemaParser({
1222
1256
  schema: item,
@@ -1290,7 +1324,6 @@ var SchemaParser = class {
1290
1324
  schemaFormatters;
1291
1325
  schemaUtils;
1292
1326
  templatesWorker;
1293
- schemaWalker;
1294
1327
  typeName;
1295
1328
  schema;
1296
1329
  schemaPath;
@@ -1300,7 +1333,6 @@ var SchemaParser = class {
1300
1333
  this.templatesWorker = schemaParserFabric.templatesWorker;
1301
1334
  this.schemaComponentsMap = schemaParserFabric.schemaComponentsMap;
1302
1335
  this.typeNameFormatter = schemaParserFabric.typeNameFormatter;
1303
- this.schemaWalker = schemaParserFabric.schemaWalker;
1304
1336
  this.schemaFormatters = schemaParserFabric.schemaFormatters;
1305
1337
  this.schemaUtils = schemaParserFabric.schemaUtils;
1306
1338
  this.typeName = typeName || null;
@@ -1350,7 +1382,7 @@ var SchemaParser = class {
1350
1382
  if (!this.typeName && this.schemaUtils.isRefSchema(this.schema)) this.typeName = this.schemaUtils.getSchemaType(this.schema);
1351
1383
  if (this.schema.items && !Array.isArray(this.schema.items) && !this.schema.type) this.schema.type = SCHEMA_TYPES$1.ARRAY;
1352
1384
  if (Array.isArray(this.schema.enum) && this.schema.enum.length === 1 && this.schema.enum[0] == null) {
1353
- consola.debug("invalid enum schema", this.schema);
1385
+ consola$1.debug("invalid enum schema", this.schema);
1354
1386
  this.schema = { type: this.config.Ts.Keyword.Null };
1355
1387
  }
1356
1388
  if ("content" in this.schema && typeof this.schema.content === "object") {
@@ -1395,24 +1427,13 @@ var SchemaParser = class {
1395
1427
  };
1396
1428
  };
1397
1429
 
1398
- //#endregion
1399
- //#region src/util/pascal-case.ts
1400
- function pascalCase(value) {
1401
- return upperFirst(camelCase(value));
1402
- }
1403
-
1404
1430
  //#endregion
1405
1431
  //#region src/schema-parser/schema-utils.ts
1406
1432
  var SchemaUtils = class {
1407
- config;
1408
- schemaComponentsMap;
1409
- typeNameFormatter;
1410
- schemaWalker;
1411
- constructor({ config, schemaComponentsMap, typeNameFormatter, schemaWalker }) {
1433
+ constructor(config, schemaComponentsMap, typeNameFormatter) {
1412
1434
  this.config = config;
1413
1435
  this.schemaComponentsMap = schemaComponentsMap;
1414
1436
  this.typeNameFormatter = typeNameFormatter;
1415
- this.schemaWalker = schemaWalker;
1416
1437
  }
1417
1438
  getRequiredProperties = (schema) => {
1418
1439
  return uniq(schema && Array.isArray(schema.required) && schema.required || []);
@@ -1558,14 +1579,12 @@ var SchemaParserFabric = class {
1558
1579
  schemaFormatters;
1559
1580
  templatesWorker;
1560
1581
  schemaUtils;
1561
- schemaWalker;
1562
- constructor(config, templatesWorker, schemaComponentsMap, typeNameFormatter, schemaWalker) {
1582
+ constructor(config, templatesWorker, schemaComponentsMap, typeNameFormatter) {
1563
1583
  this.config = config;
1564
1584
  this.schemaComponentsMap = schemaComponentsMap;
1565
1585
  this.typeNameFormatter = typeNameFormatter;
1566
1586
  this.templatesWorker = templatesWorker;
1567
- this.schemaWalker = schemaWalker;
1568
- this.schemaUtils = new SchemaUtils(this);
1587
+ this.schemaUtils = new SchemaUtils(this.config, this.schemaComponentsMap, this.typeNameFormatter);
1569
1588
  this.schemaFormatters = new SchemaFormatters(this);
1570
1589
  }
1571
1590
  createSchemaParser = ({ schema, typeName, schemaPath }) => {
@@ -1632,7 +1651,7 @@ var SpecificArgNameResolver = class extends NameResolver {
1632
1651
  constructor(config, reservedNames) {
1633
1652
  super(config, reservedNames, (variants) => {
1634
1653
  const generatedVariant = variants[0] && `${variants[0]}${this.counter++}` || `${this.config.specificArgNameResolverName}${this.counter++}`;
1635
- consola.debug("generated fallback type name for specific arg - ", generatedVariant);
1654
+ consola$1.debug("generated fallback type name for specific arg - ", generatedVariant);
1636
1655
  return generatedVariant;
1637
1656
  });
1638
1657
  }
@@ -1650,12 +1669,7 @@ const CONTENT_KIND = {
1650
1669
  TEXT: "TEXT"
1651
1670
  };
1652
1671
  var SchemaRoutes = class {
1653
- config;
1654
- schemaParserFabric;
1655
1672
  schemaUtils;
1656
- typeNameFormatter;
1657
- schemaComponentsMap;
1658
- templatesWorker;
1659
1673
  FORM_DATA_TYPES = [];
1660
1674
  routes = [];
1661
1675
  hasSecurityRoutes = false;
@@ -1664,10 +1678,10 @@ var SchemaRoutes = class {
1664
1678
  constructor(config, schemaParserFabric, schemaComponentsMap, templatesWorker, typeNameFormatter) {
1665
1679
  this.config = config;
1666
1680
  this.schemaParserFabric = schemaParserFabric;
1667
- this.schemaUtils = this.schemaParserFabric.schemaUtils;
1668
- this.typeNameFormatter = typeNameFormatter;
1669
1681
  this.schemaComponentsMap = schemaComponentsMap;
1670
1682
  this.templatesWorker = templatesWorker;
1683
+ this.typeNameFormatter = typeNameFormatter;
1684
+ this.schemaUtils = this.schemaParserFabric.schemaUtils;
1671
1685
  this.FORM_DATA_TYPES = uniq([this.schemaUtils.getSchemaType({
1672
1686
  type: "string",
1673
1687
  format: "file"
@@ -1676,11 +1690,16 @@ var SchemaRoutes = class {
1676
1690
  format: "binary"
1677
1691
  })]);
1678
1692
  }
1679
- createRequestsMap = (routesByMethod) => {
1693
+ createRequestsMap = (resolvedSwaggerSchema, routesByMethod) => {
1680
1694
  const parameters = get(routesByMethod, "parameters");
1681
1695
  const result = {};
1682
1696
  for (const [method, requestInfo] of Object.entries(routesByMethod)) {
1683
- if (method.startsWith("x-") || ["parameters", "$ref"].includes(method)) continue;
1697
+ if (method.startsWith("x-") || ["parameters"].includes(method)) continue;
1698
+ if (method === "$ref") {
1699
+ const refData = resolvedSwaggerSchema.getRef(requestInfo);
1700
+ if (typeGuard.isObject(refData)) Object.assign(result, this.createRequestsMap(resolvedSwaggerSchema, refData));
1701
+ continue;
1702
+ }
1684
1703
  result[method] = {
1685
1704
  ...requestInfo,
1686
1705
  parameters: compact([...parameters || [], ...requestInfo.parameters || []])
@@ -1695,7 +1714,7 @@ var SchemaRoutes = class {
1695
1714
  for (const match of pathParamMatches || []) {
1696
1715
  const paramName = match.replace(/\{|\}|:/g, "");
1697
1716
  if (!paramName) continue;
1698
- if (paramName.includes("-")) consola.warn("wrong path param name", paramName);
1717
+ if (paramName.includes("-")) consola$1.warn("wrong path param name", paramName);
1699
1718
  pathParams.push({
1700
1719
  $match: match,
1701
1720
  name: camelCase(paramName),
@@ -1716,7 +1735,7 @@ var SchemaRoutes = class {
1716
1735
  for (const match of queryParamMatches) fixedRoute = fixedRoute.replace(match, "");
1717
1736
  const paramNames = uniq(queryParamMatches.join(",").replace(/(\{\?)|(\})|\s/g, "").split(","));
1718
1737
  for (const paramName of paramNames) {
1719
- if (typeof paramName === "string" && paramName.includes("-")) consola.warn("wrong query param name", paramName);
1738
+ if (typeof paramName === "string" && paramName.includes("-")) consola$1.warn("wrong query param name", paramName);
1720
1739
  queryParams.push({
1721
1740
  $match: paramName,
1722
1741
  name: typeof paramName === "string" ? camelCase(paramName) : camelCase(String(paramName)),
@@ -1749,7 +1768,7 @@ var SchemaRoutes = class {
1749
1768
  for (const parameter of parameters || []) {
1750
1769
  const refTypeInfo = this.schemaParserFabric.schemaUtils.getSchemaRefType(parameter);
1751
1770
  let routeParam = null;
1752
- if (refTypeInfo?.rawTypeData.in && refTypeInfo.rawTypeData) {
1771
+ if (!!refTypeInfo?.rawTypeData && typeof refTypeInfo === "object" && refTypeInfo?.rawTypeData.in) {
1753
1772
  if (!routeParams[refTypeInfo.rawTypeData.in]) routeParams[refTypeInfo.rawTypeData.in] = [];
1754
1773
  routeParam = {
1755
1774
  ...refTypeInfo.rawTypeData,
@@ -1819,10 +1838,11 @@ var SchemaRoutes = class {
1819
1838
  }
1820
1839
  return defaultType || this.config.Ts.Keyword.Any;
1821
1840
  };
1822
- getRequestInfoTypes = ({ requestInfos, parsedSchemas, operationId, defaultType }) => {
1841
+ getRequestInfoTypes = ({ requestInfos, parsedSchemas, operationId, defaultType, resolvedSwaggerSchema }) => {
1823
1842
  const result = [];
1824
1843
  for (const [status, requestInfo] of Object.entries(requestInfos || {})) {
1825
1844
  const contentTypes = this.getContentTypes([requestInfo], operationId);
1845
+ const links = this.getRouteLinksFromResponse(resolvedSwaggerSchema, requestInfo, status);
1826
1846
  result.push({
1827
1847
  ...requestInfo || {},
1828
1848
  contentTypes,
@@ -1834,21 +1854,48 @@ var SchemaRoutes = class {
1834
1854
  defaultType
1835
1855
  })),
1836
1856
  description: this.schemaParserFabric.schemaFormatters.formatDescription(requestInfo.description || "", true),
1857
+ links,
1837
1858
  status: Number.isNaN(+status) ? status : +status,
1838
1859
  isSuccess: this.isSuccessStatus(status)
1839
1860
  });
1840
1861
  }
1841
1862
  return result;
1842
1863
  };
1843
- getResponseBodyInfo = (routeInfo, parsedSchemas) => {
1864
+ getRouteLinksFromResponse = (resolvedSwaggerSchema, responseInfo, status) => {
1865
+ const links = get(responseInfo, "links");
1866
+ if (!typeGuard.isObject(links)) return [];
1867
+ return reduce(links, (acc, linkInfo, linkName) => {
1868
+ if (!typeGuard.isObject(linkInfo)) return acc;
1869
+ let normalizedLinkInfo = linkInfo;
1870
+ if (typeof linkInfo.$ref === "string") {
1871
+ const refData = resolvedSwaggerSchema.getRef(linkInfo.$ref);
1872
+ if (typeGuard.isObject(refData)) normalizedLinkInfo = refData;
1873
+ }
1874
+ const operationId = typeof normalizedLinkInfo.operationId === "string" ? normalizedLinkInfo.operationId : void 0;
1875
+ const operationRef = typeof normalizedLinkInfo.operationRef === "string" ? normalizedLinkInfo.operationRef : typeof linkInfo.$ref === "string" ? linkInfo.$ref : void 0;
1876
+ if (!operationId && !operationRef) return acc;
1877
+ const parameters = typeGuard.isObject(normalizedLinkInfo.parameters) ? mapValues(normalizedLinkInfo.parameters, (value) => String(value)) : void 0;
1878
+ acc.push({
1879
+ status: Number.isNaN(+status) ? status : +status,
1880
+ name: String(linkName),
1881
+ operationId,
1882
+ operationRef,
1883
+ parameters
1884
+ });
1885
+ return acc;
1886
+ }, []);
1887
+ };
1888
+ getResponseBodyInfo = (routeInfo, parsedSchemas, resolvedSwaggerSchema) => {
1844
1889
  const { produces, operationId, responses } = routeInfo;
1845
1890
  const contentTypes = this.getContentTypes(responses, [...produces || [], routeInfo["x-accepts"]]);
1846
1891
  const responseInfos = this.getRequestInfoTypes({
1847
1892
  requestInfos: responses,
1848
1893
  parsedSchemas,
1849
1894
  operationId,
1850
- defaultType: this.config.defaultResponseType
1895
+ defaultType: this.config.defaultResponseType,
1896
+ resolvedSwaggerSchema
1851
1897
  });
1898
+ const links = responseInfos.flatMap((responseInfo) => responseInfo.links || []);
1852
1899
  const successResponse = responseInfos.find((response) => response.isSuccess);
1853
1900
  const errorResponses = responseInfos.filter((response) => !response.isSuccess && response.type !== this.config.Ts.Keyword.Any);
1854
1901
  const handleResponseHeaders = (src) => {
@@ -1861,6 +1908,7 @@ var SchemaRoutes = class {
1861
1908
  return {
1862
1909
  contentTypes,
1863
1910
  responses: responseInfos,
1911
+ links,
1864
1912
  success: {
1865
1913
  schema: successResponse,
1866
1914
  type: successResponse?.type || this.config.Ts.Keyword.Any
@@ -2031,11 +2079,11 @@ var SchemaRoutes = class {
2031
2079
  const { routeNameDuplicatesMap, templatesToRender } = this.config;
2032
2080
  const routeNameTemplate = templatesToRender.routeName;
2033
2081
  const routeNameFromTemplate = this.templatesWorker.renderTemplate(routeNameTemplate, { routeInfo: rawRouteInfo });
2034
- const routeName = this.config.hooks.onFormatRouteName(rawRouteInfo, routeNameFromTemplate) || routeNameFromTemplate;
2082
+ const routeName = this.config.hooks.onFormatRouteName?.(rawRouteInfo, routeNameFromTemplate) || routeNameFromTemplate;
2035
2083
  const duplicateIdentifier = `${moduleName}|${routeName}`;
2036
2084
  if (routeNameDuplicatesMap.has(duplicateIdentifier)) {
2037
2085
  routeNameDuplicatesMap.set(duplicateIdentifier, routeNameDuplicatesMap.get(duplicateIdentifier) + 1);
2038
- consola.warn(`Module "${moduleName}" already has method "${routeName}()".`, `This method has been renamed to "${routeName + routeNameDuplicatesMap.get(duplicateIdentifier)}()" to solve conflict names.`);
2086
+ consola$1.warn(`Module "${moduleName}" already has method "${routeName}()".`, `This method has been renamed to "${routeName + routeNameDuplicatesMap.get(duplicateIdentifier)}()" to solve conflict names.`);
2039
2087
  } else routeNameDuplicatesMap.set(duplicateIdentifier, 1);
2040
2088
  const duplicates = routeNameDuplicatesMap.get(duplicateIdentifier);
2041
2089
  const routeNameInfo = {
@@ -2043,10 +2091,10 @@ var SchemaRoutes = class {
2043
2091
  original: routeName,
2044
2092
  duplicate: duplicates > 1
2045
2093
  };
2046
- return this.config.hooks.onCreateRouteName(routeNameInfo, rawRouteInfo) || routeNameInfo;
2094
+ return this.config.hooks.onCreateRouteName?.(routeNameInfo, rawRouteInfo) || routeNameInfo;
2047
2095
  };
2048
- parseRouteInfo = (rawRouteName, routeInfo, method, usageSchema, parsedSchemas) => {
2049
- const { security: globalSecurity } = usageSchema;
2096
+ parseRouteInfo = (rawRouteName, routeInfo, method, resolvedSwaggerSchema, parsedSchemas) => {
2097
+ const { security: globalSecurity } = resolvedSwaggerSchema.usageSchema;
2050
2098
  const { moduleNameIndex, moduleNameFirstTag, extractRequestParams } = this.config;
2051
2099
  const { operationId, requestBody, security, parameters, summary, description, tags, responses, requestBodyName, produces, consumes, ...otherInfo } = routeInfo;
2052
2100
  const { route, pathParams: pathParamsFromRouteName, queryParams: queryParamsFromRouteName } = this.parseRouteName(rawRouteName);
@@ -2063,7 +2111,7 @@ var SchemaRoutes = class {
2063
2111
  description: pathArgSchema.description
2064
2112
  }));
2065
2113
  const pathArgsNames = pathArgs.map((arg) => arg.name);
2066
- const responseBodyInfo = this.getResponseBodyInfo(routeInfo, parsedSchemas);
2114
+ const responseBodyInfo = this.getResponseBodyInfo(routeInfo, parsedSchemas, resolvedSwaggerSchema);
2067
2115
  const rawRouteInfo = {
2068
2116
  ...otherInfo,
2069
2117
  pathArgs,
@@ -2072,6 +2120,7 @@ var SchemaRoutes = class {
2072
2120
  route: rawRouteName,
2073
2121
  moduleName,
2074
2122
  responsesTypes: responseBodyInfo.responses,
2123
+ links: responseBodyInfo.links,
2075
2124
  description,
2076
2125
  tags,
2077
2126
  summary,
@@ -2167,13 +2216,13 @@ var SchemaRoutes = class {
2167
2216
  raw: rawRouteInfo
2168
2217
  };
2169
2218
  };
2170
- attachSchema = ({ usageSchema, parsedSchemas }) => {
2219
+ attachSchema = (resolvedSwaggerSchema, parsedSchemas) => {
2171
2220
  this.config.routeNameDuplicatesMap.clear();
2172
- const pathsEntries = Object.entries(usageSchema.paths || {});
2221
+ const pathsEntries = Object.entries(resolvedSwaggerSchema.usageSchema.paths || {});
2173
2222
  for (const [rawRouteName, routeInfoByMethodsMap] of pathsEntries) {
2174
- const routeInfosMap = this.createRequestsMap(routeInfoByMethodsMap);
2223
+ const routeInfosMap = this.createRequestsMap(resolvedSwaggerSchema, routeInfoByMethodsMap);
2175
2224
  for (const [method, routeInfo] of Object.entries(routeInfosMap)) {
2176
- const parsedRouteInfo = this.parseRouteInfo(rawRouteName, routeInfo, method, usageSchema, parsedSchemas);
2225
+ const parsedRouteInfo = this.parseRouteInfo(rawRouteName, routeInfo, method, resolvedSwaggerSchema, parsedSchemas);
2177
2226
  const processedRouteInfo = this.config.hooks.onCreateRoute(parsedRouteInfo);
2178
2227
  if (processedRouteInfo !== false) {
2179
2228
  const route = processedRouteInfo || parsedRouteInfo;
@@ -2227,30 +2276,353 @@ var SchemaRoutes = class {
2227
2276
  };
2228
2277
 
2229
2278
  //#endregion
2230
- //#region src/schema-walker.ts
2231
- var SchemaWalker = class {
2232
- config;
2233
- swaggerSchemaResolver;
2234
- schemas = /* @__PURE__ */ new Map();
2235
- caches = /* @__PURE__ */ new Map();
2236
- constructor(config, swaggerSchemaResolver) {
2279
+ //#region src/resolved-swagger-schema.ts
2280
+ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2281
+ parsedRefsCache = /* @__PURE__ */ new Map();
2282
+ externalSchemaCache = /* @__PURE__ */ new Map();
2283
+ httpMethodSegments = new Set([
2284
+ "get",
2285
+ "put",
2286
+ "post",
2287
+ "delete",
2288
+ "patch",
2289
+ "options",
2290
+ "head",
2291
+ "trace",
2292
+ "parameters"
2293
+ ]);
2294
+ normalizeRef(ref) {
2295
+ let normalizedRef = ref;
2296
+ normalizedRef = normalizedRef.replace(/\/#(?=\/)/, "#");
2297
+ normalizedRef = normalizedRef.replace(/#(?!\/)/, "#/");
2298
+ return normalizedRef;
2299
+ }
2300
+ createEscapedPathsRefVariant(ref) {
2301
+ const [prefix = "", rawPointer = ""] = this.normalizeRef(ref).split("#");
2302
+ const pointer = rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}`;
2303
+ if (!pointer.startsWith("/paths/") || pointer.startsWith("/paths/~1")) return null;
2304
+ const rest = pointer.slice(7);
2305
+ if (!rest) return null;
2306
+ const parts = rest.split("/");
2307
+ const last = parts.at(-1)?.toLowerCase() || "";
2308
+ const hasTailSegment = this.httpMethodSegments.has(last);
2309
+ const pathParts = hasTailSegment ? parts.slice(0, -1) : parts;
2310
+ const tail = hasTailSegment ? `/${parts.at(-1)}` : "";
2311
+ if (!pathParts.length) return null;
2312
+ return `${prefix}#/paths/${`~1${pathParts.join("/").replace(/\//g, "~1")}`}${tail}`;
2313
+ }
2314
+ isHttpUrl(value) {
2315
+ return /^https?:\/\//i.test(value);
2316
+ }
2317
+ getRemoteRequestHeaders() {
2318
+ return Object.assign({}, this.config.authorizationToken ? { Authorization: this.config.authorizationToken } : {}, this.config.requestOptions?.headers || {});
2319
+ }
2320
+ stripHash(urlOrPath) {
2321
+ return urlOrPath.split("#")[0] || urlOrPath;
2322
+ }
2323
+ extractRefsFromSchema(schema) {
2324
+ const refs = /* @__PURE__ */ new Set();
2325
+ const walk = (node) => {
2326
+ if (!node || typeof node !== "object") return;
2327
+ if (Array.isArray(node)) {
2328
+ for (const item of node) walk(item);
2329
+ return;
2330
+ }
2331
+ const recordNode = node;
2332
+ if (typeof recordNode.$ref === "string") refs.add(recordNode.$ref);
2333
+ for (const value of Object.values(recordNode)) walk(value);
2334
+ };
2335
+ walk(schema);
2336
+ return [...refs];
2337
+ }
2338
+ async fetchRemoteSchemaDocument(url) {
2339
+ try {
2340
+ const response = await fetch(url, { headers: this.getRemoteRequestHeaders() });
2341
+ if (!response.ok) return null;
2342
+ const content = await response.text();
2343
+ try {
2344
+ const parsed = JSON.parse(content);
2345
+ if (parsed && typeof parsed === "object") return parsed;
2346
+ } catch {
2347
+ const parsed = YAML.parse(content);
2348
+ if (parsed && typeof parsed === "object") return parsed;
2349
+ }
2350
+ } catch (e) {
2351
+ consola.debug(e);
2352
+ }
2353
+ return null;
2354
+ }
2355
+ async warmUpRemoteSchemasCache() {
2356
+ if (typeof this.config.url !== "string" || !this.isHttpUrl(this.config.url)) return;
2357
+ const visited = /* @__PURE__ */ new Set();
2358
+ const queue = [this.stripHash(this.config.url)];
2359
+ while (queue.length > 0) {
2360
+ const currentUrl = queue.shift();
2361
+ if (!currentUrl || visited.has(currentUrl)) continue;
2362
+ visited.add(currentUrl);
2363
+ if (this.externalSchemaCache.has(currentUrl)) continue;
2364
+ const schema = await this.fetchRemoteSchemaDocument(currentUrl);
2365
+ if (!schema) continue;
2366
+ this.externalSchemaCache.set(currentUrl, schema);
2367
+ for (const ref of this.extractRefsFromSchema(schema)) {
2368
+ const normalizedRef = this.normalizeRef(ref);
2369
+ if (normalizedRef.startsWith("#")) continue;
2370
+ const [externalPath = ""] = normalizedRef.split("#");
2371
+ if (!externalPath) continue;
2372
+ let absoluteUrl = "";
2373
+ try {
2374
+ absoluteUrl = this.isHttpUrl(externalPath) ? this.stripHash(externalPath) : this.stripHash(new URL(externalPath, currentUrl).toString());
2375
+ } catch (e) {
2376
+ consola.debug(e);
2377
+ }
2378
+ if (absoluteUrl && !visited.has(absoluteUrl)) queue.push(absoluteUrl);
2379
+ }
2380
+ }
2381
+ }
2382
+ collectRemoteAbsoluteRefCandidates(ref) {
2383
+ if (!ref || this.isHttpUrl(ref) || ref.startsWith("#")) return [];
2384
+ const [relativePath = "", rawPointer = ""] = this.normalizeRef(ref).split("#");
2385
+ if (!relativePath) return [];
2386
+ const pointer = rawPointer ? rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}` : "";
2387
+ const bases = /* @__PURE__ */ new Set();
2388
+ if (typeof this.config.url === "string" && this.isHttpUrl(this.config.url)) bases.add(this.config.url);
2389
+ for (const cachedUrl of this.externalSchemaCache.keys()) if (this.isHttpUrl(cachedUrl)) bases.add(cachedUrl);
2390
+ for (const resolver of this.resolvers) try {
2391
+ const resolverPaths = typeof resolver.paths === "function" ? resolver.paths() : [];
2392
+ for (const resolverPath of resolverPaths) if (typeof resolverPath === "string" && this.isHttpUrl(resolverPath)) bases.add(resolverPath);
2393
+ } catch (e) {
2394
+ consola.debug(e);
2395
+ }
2396
+ const results = /* @__PURE__ */ new Set();
2397
+ for (const base of bases) try {
2398
+ const absolutePath = new URL(relativePath, base).toString();
2399
+ results.add(pointer ? `${absolutePath}#${pointer}` : absolutePath);
2400
+ } catch (e) {
2401
+ consola.debug(e);
2402
+ }
2403
+ return [...results];
2404
+ }
2405
+ resolveFromRemoteSchemaCache(absoluteRef) {
2406
+ const [externalPath = "", rawPointer = ""] = this.normalizeRef(absoluteRef).split("#");
2407
+ if (!externalPath || !this.isHttpUrl(externalPath)) return null;
2408
+ const schema = this.externalSchemaCache.get(this.stripHash(externalPath));
2409
+ if (!schema) return null;
2410
+ const pointer = rawPointer ? rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}` : "/";
2411
+ const resolved = this.resolveJsonPointer(schema, pointer);
2412
+ if (resolved == null) return null;
2413
+ return this.absolutizeLocalRefs(resolved, this.stripHash(externalPath));
2414
+ }
2415
+ constructor(config, usageSchema, originalSchema, resolvers) {
2237
2416
  this.config = config;
2238
- this.swaggerSchemaResolver = swaggerSchemaResolver;
2417
+ this.usageSchema = usageSchema;
2418
+ this.originalSchema = originalSchema;
2419
+ this.resolvers = resolvers;
2420
+ this.usageSchema = usageSchema;
2421
+ this.originalSchema = originalSchema;
2422
+ }
2423
+ getRefDetails(ref) {
2424
+ const normalizedRef = this.normalizeRef(ref);
2425
+ if (!this.parsedRefsCache.has(ref)) {
2426
+ const isLocal = normalizedRef.startsWith("#");
2427
+ if (isLocal) this.parsedRefsCache.set(ref, {
2428
+ ref: normalizedRef,
2429
+ isLocal,
2430
+ externalUrlOrPath: null
2431
+ });
2432
+ else {
2433
+ const externalUrlOrPath = normalizedRef.split("#")[0] || "";
2434
+ let externalOpenapiFileName = externalUrlOrPath.replace(/\/$/, "").split("/").at(-1) || "";
2435
+ if (externalOpenapiFileName.endsWith(".json") || externalOpenapiFileName.endsWith(".yaml")) externalOpenapiFileName = externalOpenapiFileName.slice(0, -5);
2436
+ else if (externalOpenapiFileName.endsWith(".yml")) externalOpenapiFileName = externalOpenapiFileName.slice(0, -4);
2437
+ this.parsedRefsCache.set(ref, {
2438
+ ref: normalizedRef,
2439
+ isLocal,
2440
+ externalUrlOrPath,
2441
+ externalOpenapiFileName
2442
+ });
2443
+ }
2444
+ }
2445
+ const cachedRef = this.parsedRefsCache.get(ref);
2446
+ if (cachedRef) return cachedRef;
2447
+ if (normalizedRef.startsWith("#")) return {
2448
+ ref: normalizedRef,
2449
+ isLocal: true,
2450
+ externalUrlOrPath: null
2451
+ };
2452
+ return {
2453
+ ref: normalizedRef,
2454
+ isLocal: false,
2455
+ externalUrlOrPath: normalizedRef.split("#")[0] || null,
2456
+ externalOpenapiFileName: ""
2457
+ };
2458
+ }
2459
+ isLocalRef(ref) {
2460
+ return this.getRefDetails(ref).isLocal;
2461
+ }
2462
+ getRef(ref) {
2463
+ if (!ref) return null;
2464
+ const normalizedRef = this.normalizeRef(ref);
2465
+ const escapedPathsRefVariant = this.createEscapedPathsRefVariant(ref);
2466
+ if (normalizedRef !== ref) {
2467
+ const resolvedByNormalizedRef = this.tryToResolveRef(normalizedRef);
2468
+ if (resolvedByNormalizedRef) return this.normalizeResolvedExternalSchemaRef(normalizedRef, resolvedByNormalizedRef);
2469
+ }
2470
+ if (escapedPathsRefVariant) {
2471
+ const resolvedByEscapedPathsRef = this.tryToResolveRef(escapedPathsRefVariant);
2472
+ if (resolvedByEscapedPathsRef) return this.normalizeResolvedExternalSchemaRef(escapedPathsRefVariant, resolvedByEscapedPathsRef);
2473
+ }
2474
+ const remoteAbsoluteCandidates = this.collectRemoteAbsoluteRefCandidates(ref);
2475
+ for (const remoteAbsoluteRef of remoteAbsoluteCandidates) {
2476
+ const resolvedFromRemoteCache = this.resolveFromRemoteSchemaCache(remoteAbsoluteRef);
2477
+ if (resolvedFromRemoteCache) return resolvedFromRemoteCache;
2478
+ const resolvedByRemoteAbsoluteRef = this.tryToResolveRef(remoteAbsoluteRef);
2479
+ if (resolvedByRemoteAbsoluteRef) return this.normalizeResolvedExternalSchemaRef(remoteAbsoluteRef, resolvedByRemoteAbsoluteRef);
2480
+ }
2481
+ const resolvedByOrigRef = this.tryToResolveRef(ref);
2482
+ if (resolvedByOrigRef) return this.normalizeResolvedExternalSchemaRef(ref, resolvedByOrigRef);
2483
+ if (/#[a-z]/.test(ref)) {
2484
+ const fixedRef = ref.replace(/#[a-z]/, (match) => {
2485
+ const [hashtag, char] = match.split("");
2486
+ return `${hashtag}/${char}`;
2487
+ });
2488
+ const resolvedByFixedRef = this.tryToResolveRef(fixedRef);
2489
+ if (resolvedByFixedRef) return this.normalizeResolvedExternalSchemaRef(fixedRef, resolvedByFixedRef);
2490
+ }
2491
+ return this.tryToResolveRefFromFile(normalizedRef);
2492
+ }
2493
+ tryToResolveRef(ref) {
2494
+ if (!this.resolvers || !ref) return null;
2495
+ for (const resolver of this.resolvers) try {
2496
+ return resolver.get(ref);
2497
+ } catch (e) {
2498
+ consola.debug(e);
2499
+ }
2500
+ return null;
2501
+ }
2502
+ readExternalSchema(filePath) {
2503
+ if (this.externalSchemaCache.has(filePath)) return this.externalSchemaCache.get(filePath) || null;
2504
+ if (!fs.existsSync(filePath)) return null;
2505
+ try {
2506
+ const content = fs.readFileSync(filePath, "utf8");
2507
+ const parsed = JSON.parse(content);
2508
+ this.externalSchemaCache.set(filePath, parsed);
2509
+ return parsed;
2510
+ } catch {
2511
+ try {
2512
+ const content = fs.readFileSync(filePath, "utf8");
2513
+ const parsed = YAML.parse(content);
2514
+ if (parsed && typeof parsed === "object") {
2515
+ this.externalSchemaCache.set(filePath, parsed);
2516
+ return parsed;
2517
+ }
2518
+ } catch (e) {
2519
+ consola.debug(e);
2520
+ }
2521
+ }
2522
+ return null;
2523
+ }
2524
+ resolveJsonPointer(source, pointer) {
2525
+ if (!source || typeof source !== "object") return null;
2526
+ if (!pointer || pointer === "/") return source;
2527
+ const tokens = pointer.replace(/^\/+/, "").split("/").filter(Boolean).map((part) => decodeURIComponent(part.replace(/~1/g, "/").replace(/~0/g, "~")));
2528
+ let current = source;
2529
+ for (const token of tokens) {
2530
+ if (!current || typeof current !== "object") return null;
2531
+ current = current[token];
2532
+ }
2533
+ return current ?? null;
2534
+ }
2535
+ absolutizeLocalRefs(value, externalPath) {
2536
+ if (value == null || typeof value !== "object") return value;
2537
+ const cloneValue = structuredClone(value);
2538
+ const walk = (node) => {
2539
+ if (!node || typeof node !== "object") return;
2540
+ if (Array.isArray(node)) {
2541
+ for (const item of node) walk(item);
2542
+ return;
2543
+ }
2544
+ const recordNode = node;
2545
+ if (typeof recordNode.$ref === "string" && recordNode.$ref.startsWith("#")) recordNode.$ref = `${externalPath}${this.normalizeRef(recordNode.$ref)}`;
2546
+ for (const nested of Object.values(recordNode)) walk(nested);
2547
+ };
2548
+ walk(cloneValue);
2549
+ return cloneValue;
2550
+ }
2551
+ normalizeResolvedExternalSchemaRef(ref, resolved) {
2552
+ const normalizedRef = this.normalizeRef(ref);
2553
+ if (normalizedRef.startsWith("#")) return resolved;
2554
+ const externalPath = normalizedRef.split("#")[0] || "";
2555
+ if (!externalPath) return resolved;
2556
+ return this.absolutizeLocalRefs(resolved, externalPath);
2557
+ }
2558
+ collectExternalRefCandidates(externalPath) {
2559
+ const candidates = /* @__PURE__ */ new Set();
2560
+ if (/^https?:\/\//i.test(externalPath)) return [];
2561
+ if (path.isAbsolute(externalPath)) candidates.add(externalPath);
2562
+ const inputPath = this.config.input;
2563
+ if (typeof inputPath === "string" && inputPath) candidates.add(path.resolve(path.dirname(inputPath), externalPath));
2564
+ for (const resolver of this.resolvers) try {
2565
+ const resolverPaths = typeof resolver.paths === "function" ? resolver.paths() : [];
2566
+ for (const resolverPath of resolverPaths) {
2567
+ if (typeof resolverPath !== "string") continue;
2568
+ if (/^https?:\/\//i.test(resolverPath)) continue;
2569
+ candidates.add(path.resolve(path.dirname(resolverPath), externalPath));
2570
+ }
2571
+ } catch (e) {
2572
+ consola.debug(e);
2573
+ }
2574
+ return [...candidates];
2575
+ }
2576
+ tryToResolveRefFromFile(ref) {
2577
+ if (!ref || ref.startsWith("#")) return null;
2578
+ const [externalPath = "", rawPointer = ""] = ref.split("#");
2579
+ if (!externalPath) return null;
2580
+ const pointer = rawPointer ? rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}` : "/";
2581
+ const candidates = this.collectExternalRefCandidates(externalPath);
2582
+ for (const candidate of candidates) {
2583
+ const schema = this.readExternalSchema(candidate);
2584
+ const resolved = this.resolveJsonPointer(schema, pointer);
2585
+ if (resolved != null) return this.absolutizeLocalRefs(resolved, externalPath);
2586
+ }
2587
+ return null;
2588
+ }
2589
+ static async create(config, usageSchema, originalSchema) {
2590
+ const resolvers = [];
2591
+ const options = {
2592
+ continueOnError: true,
2593
+ mutateInputSchema: true,
2594
+ dereference: {},
2595
+ validate: {
2596
+ schema: false,
2597
+ spec: false
2598
+ },
2599
+ resolve: {
2600
+ external: true,
2601
+ http: {
2602
+ ...config.requestOptions,
2603
+ headers: Object.assign({}, config.authorizationToken ? { Authorization: config.authorizationToken } : {}, config.requestOptions?.headers ?? {})
2604
+ }
2605
+ }
2606
+ };
2607
+ try {
2608
+ resolvers.push(await SwaggerParser.resolve(originalSchema, options));
2609
+ } catch (e) {
2610
+ consola.debug(e);
2611
+ }
2612
+ try {
2613
+ resolvers.push(await SwaggerParser.resolve(usageSchema, options));
2614
+ } catch (e) {
2615
+ consola.debug(e);
2616
+ }
2617
+ try {
2618
+ resolvers.push(await SwaggerParser.resolve(config.url || config.input || config.spec, options));
2619
+ } catch (e) {
2620
+ consola.debug(e);
2621
+ }
2622
+ const resolvedSwaggerSchema = new ResolvedSwaggerSchema(config, usageSchema, originalSchema, resolvers);
2623
+ await resolvedSwaggerSchema.warmUpRemoteSchemasCache();
2624
+ return resolvedSwaggerSchema;
2239
2625
  }
2240
- addSchema = (name, schema) => {
2241
- this.schemas.set(name, structuredClone(schema));
2242
- };
2243
- _isLocalRef = (ref) => {
2244
- return ref.startsWith("#");
2245
- };
2246
- _isRemoteRef = (ref) => {
2247
- return ref.startsWith("http://") || ref.startsWith("https://");
2248
- };
2249
- _getRefDataFromSchema = (schema, ref) => {
2250
- const refData = get(schema, ref.replace("#", "").split("/"));
2251
- if (refData) this.caches.set(ref, refData);
2252
- return refData;
2253
- };
2254
2626
  };
2255
2627
 
2256
2628
  //#endregion
@@ -2268,7 +2640,7 @@ var Request = class {
2268
2640
  return await (await fetch(url, requestOptions)).text();
2269
2641
  } catch (error) {
2270
2642
  const message = `error while fetching data from URL "${url}"`;
2271
- consola.error(message, error);
2643
+ consola$1.error(message, error);
2272
2644
  return message;
2273
2645
  }
2274
2646
  }
@@ -2287,10 +2659,15 @@ var SwaggerSchemaResolver = class {
2287
2659
  }
2288
2660
  async create() {
2289
2661
  const { spec, patch, input, url, authorizationToken } = this.config;
2290
- if (spec) return await this.convertSwaggerObject(spec, { patch });
2291
- const swaggerSchemaFile = await this.fetchSwaggerSchemaFile(input, url, authorizationToken);
2292
- const swaggerSchemaObject = this.processSwaggerSchemaFile(swaggerSchemaFile);
2293
- return await this.convertSwaggerObject(swaggerSchemaObject, { patch });
2662
+ let swaggerSchemas;
2663
+ if (spec) swaggerSchemas = await this.convertSwaggerObject(spec, { patch });
2664
+ else {
2665
+ const swaggerSchemaFile = await this.fetchSwaggerSchemaFile(input, url, authorizationToken);
2666
+ const swaggerSchemaObject = this.processSwaggerSchemaFile(swaggerSchemaFile);
2667
+ swaggerSchemas = await this.convertSwaggerObject(swaggerSchemaObject, { patch });
2668
+ }
2669
+ this.fixSwaggerSchemas(swaggerSchemas);
2670
+ return ResolvedSwaggerSchema.create(this.config, swaggerSchemas.usageSchema, swaggerSchemas.originalSchema);
2294
2671
  }
2295
2672
  convertSwaggerObject(swaggerSchema, converterOptions) {
2296
2673
  return new Promise((resolve) => {
@@ -2323,12 +2700,12 @@ var SwaggerSchemaResolver = class {
2323
2700
  });
2324
2701
  }
2325
2702
  getSwaggerSchemaByPath = (pathToSwagger) => {
2326
- consola.info(`try to get swagger by path "${pathToSwagger}"`);
2703
+ consola$1.info(`try to get swagger by path "${pathToSwagger}"`);
2327
2704
  return this.fileSystem.getFileContent(pathToSwagger);
2328
2705
  };
2329
2706
  async fetchSwaggerSchemaFile(pathToSwagger, urlToSwagger, authToken) {
2330
2707
  if (this.fileSystem.pathIsExist(pathToSwagger)) return this.getSwaggerSchemaByPath(pathToSwagger);
2331
- consola.info(`try to get swagger by URL "${urlToSwagger}"`);
2708
+ consola$1.info(`try to get swagger by URL "${urlToSwagger}"`);
2332
2709
  return await this.request.download({
2333
2710
  url: urlToSwagger,
2334
2711
  authToken
@@ -2342,7 +2719,26 @@ var SwaggerSchemaResolver = class {
2342
2719
  return YAML.parse(file);
2343
2720
  }
2344
2721
  }
2345
- fixSwaggerSchema({ usageSchema, originalSchema }) {
2722
+ normalizeRefValue(ref) {
2723
+ const refWithoutSlashBeforeHash = ref.split("/#/").join("#/");
2724
+ const hashIndex = refWithoutSlashBeforeHash.indexOf("#");
2725
+ if (hashIndex === -1) return refWithoutSlashBeforeHash;
2726
+ if (refWithoutSlashBeforeHash[hashIndex + 1] === "/") return refWithoutSlashBeforeHash;
2727
+ return `${refWithoutSlashBeforeHash.slice(0, hashIndex + 1)}/${refWithoutSlashBeforeHash.slice(hashIndex + 1)}`;
2728
+ }
2729
+ normalizeRefsInSchema(schema) {
2730
+ if (!schema || typeof schema !== "object") return;
2731
+ if (Array.isArray(schema)) {
2732
+ for (const value of schema) this.normalizeRefsInSchema(value);
2733
+ return;
2734
+ }
2735
+ const objectSchema = schema;
2736
+ if (typeof objectSchema.$ref === "string") objectSchema.$ref = this.normalizeRefValue(objectSchema.$ref);
2737
+ for (const value of Object.values(objectSchema)) this.normalizeRefsInSchema(value);
2738
+ }
2739
+ fixSwaggerSchemas({ usageSchema, originalSchema }) {
2740
+ this.normalizeRefsInSchema(usageSchema);
2741
+ this.normalizeRefsInSchema(originalSchema);
2346
2742
  const usagePaths = get(usageSchema, "paths") || {};
2347
2743
  const originalPaths = get(originalSchema, "paths") || {};
2348
2744
  for (const [route, usagePathObject] of Object.entries(usagePaths)) {
@@ -2351,9 +2747,10 @@ var SwaggerSchemaResolver = class {
2351
2747
  const originalRouteInfo = get(originalPathObject, methodName) || {};
2352
2748
  const usageRouteParams = get(usageRouteInfo, "parameters") || [];
2353
2749
  const originalRouteParams = get(originalRouteInfo, "parameters") || [];
2750
+ const usageAsOpenapiv2 = usageRouteInfo;
2354
2751
  if (typeof usageRouteInfo === "object") {
2355
- usageRouteInfo.consumes = uniq(compact([...usageRouteInfo.consumes || [], ...originalRouteInfo.consumes || []]));
2356
- usageRouteInfo.produces = uniq(compact([...usageRouteInfo.produces || [], ...originalRouteInfo.produces || []]));
2752
+ usageAsOpenapiv2.consumes = uniq(compact([...usageAsOpenapiv2.consumes || [], ...originalRouteInfo.consumes || []]));
2753
+ usageAsOpenapiv2.produces = uniq(compact([...usageAsOpenapiv2.produces || [], ...originalRouteInfo.produces || []]));
2357
2754
  }
2358
2755
  for (const originalRouteParam of originalRouteParams) if (!usageRouteParams.find((param) => originalRouteParam.in === param.in && originalRouteParam.name === param.name)) usageRouteParams.push(originalRouteParam);
2359
2756
  }
@@ -2373,8 +2770,8 @@ var TemplatesWorker = class {
2373
2770
  this.config = config;
2374
2771
  this.fileSystem = fileSystem;
2375
2772
  this.getRenderTemplateData = getRenderTemplateData;
2376
- if (this.config.debug) consola.level = Number.MAX_SAFE_INTEGER;
2377
- if (this.config.silent) consola.level = 0;
2773
+ if (this.config.debug) consola$1.level = Number.MAX_SAFE_INTEGER;
2774
+ if (this.config.silent) consola$1.level = 0;
2378
2775
  }
2379
2776
  getTemplatePaths = (config) => {
2380
2777
  const __dirname = path$1.dirname(url$1.fileURLToPath(import.meta.url));
@@ -2405,19 +2802,19 @@ var TemplatesWorker = class {
2405
2802
  const customFullPath = templatePaths.custom && this.getTemplateFullPath(templatePaths.custom, fileName);
2406
2803
  let fileContent = customFullPath && this.fileSystem.getFileContent(customFullPath);
2407
2804
  if (fileContent) {
2408
- consola.info(`"${name.toLowerCase()}" template found in "${templatePaths.custom}"`);
2805
+ consola$1.info(`"${name.toLowerCase()}" template found in "${templatePaths.custom}"`);
2409
2806
  return fileContent;
2410
2807
  }
2411
2808
  const baseFullPath = this.getTemplateFullPath(templatePaths.base, fileName);
2412
2809
  if (baseFullPath) fileContent = this.fileSystem.getFileContent(baseFullPath);
2413
- else if (templatePaths.custom) consola.warn("Code generator will use the default template:", `"${name.toLowerCase()}"`, "template not found in", `"${templatePaths.custom}"`);
2414
- else consola.info(`Code generator will use the default template for "${name.toLowerCase()}"`);
2810
+ else if (templatePaths.custom) consola$1.warn("Code generator will use the default template:", `"${name.toLowerCase()}"`, "template not found in", `"${templatePaths.custom}"`);
2811
+ else consola$1.info(`Code generator will use the default template for "${name.toLowerCase()}"`);
2415
2812
  const originalFullPath = this.getTemplateFullPath(templatePaths.original, fileName);
2416
2813
  if (originalFullPath) fileContent = this.fileSystem.getFileContent(originalFullPath);
2417
2814
  return fileContent;
2418
2815
  };
2419
2816
  getTemplates = ({ templatePaths }) => {
2420
- if (templatePaths.custom) consola.info(`try to read templates from directory "${templatePaths.custom}"`);
2817
+ if (templatePaths.custom) consola$1.info(`try to read templates from directory "${templatePaths.custom}"`);
2421
2818
  return this.config.templateInfos.reduce((acc, { name, fileName }) => ({
2422
2819
  ...acc,
2423
2820
  [name]: this.getTemplate(name, fileName)
@@ -2518,7 +2915,7 @@ var TypeNameFormatter = class {
2518
2915
  const typeSuffix = schemaType === "enum-key" ? this.config.enumKeySuffix : this.config.typeSuffix;
2519
2916
  const hashKey = `${typePrefix}_${name}_${typeSuffix}`;
2520
2917
  if (typeof name !== "string") {
2521
- consola.warn("wrong model name", name);
2918
+ consola$1.warn("wrong model name", name);
2522
2919
  return name;
2523
2920
  }
2524
2921
  if (/^(?!\d)([A-Z0-9_]{1,})$/g.test(name)) return compact([
@@ -2528,7 +2925,7 @@ var TypeNameFormatter = class {
2528
2925
  ]).join("_");
2529
2926
  if (this.formattedModelNamesMap.has(hashKey)) return this.formattedModelNamesMap.get(hashKey);
2530
2927
  const formattedName = startCase(`${typePrefix}_${this.fixModelName(name, { type: schemaType })}_${typeSuffix}`).replace(/\s/g, "");
2531
- const formattedResultName = this.config.hooks.onFormatTypeName(formattedName, name, schemaType) || formattedName;
2928
+ const formattedResultName = this.config.hooks.onFormatTypeName?.(formattedName, name, schemaType) || formattedName;
2532
2929
  this.formattedModelNamesMap.set(hashKey, formattedResultName);
2533
2930
  return formattedResultName;
2534
2931
  };
@@ -2570,14 +2967,14 @@ var FileSystem = class {
2570
2967
  if (typeof fs.rmSync === "function") fs.rmSync(path, { recursive: true });
2571
2968
  else fs.rmdirSync(path, { recursive: true });
2572
2969
  } catch (e) {
2573
- consola.debug("failed to remove dir", e);
2970
+ consola$1.debug("failed to remove dir", e);
2574
2971
  }
2575
2972
  };
2576
2973
  createDir = (path) => {
2577
2974
  try {
2578
2975
  fs.mkdirSync(path, { recursive: true });
2579
2976
  } catch (e) {
2580
- consola.debug("failed to create dir", e);
2977
+ consola$1.debug("failed to create dir", e);
2581
2978
  }
2582
2979
  };
2583
2980
  cleanDir = (path) => {
@@ -2627,38 +3024,35 @@ var CodeGenProcess = class {
2627
3024
  fileSystem;
2628
3025
  codeFormatter;
2629
3026
  templatesWorker;
2630
- schemaWalker;
2631
3027
  javascriptTranslator;
3028
+ swaggerRefs;
2632
3029
  constructor(config) {
2633
3030
  this.config = new CodeGenConfig(config);
2634
3031
  this.fileSystem = new FileSystem();
2635
3032
  this.swaggerSchemaResolver = new SwaggerSchemaResolver(this.config, this.fileSystem);
2636
- this.schemaWalker = new SchemaWalker(this.config, this.swaggerSchemaResolver);
2637
3033
  this.schemaComponentsMap = new SchemaComponentsMap(this.config);
2638
3034
  this.typeNameFormatter = new TypeNameFormatter(this.config);
2639
3035
  this.templatesWorker = new TemplatesWorker(this.config, this.fileSystem, this.getRenderTemplateData);
2640
3036
  this.codeFormatter = new CodeFormatter(this.config);
2641
- this.schemaParserFabric = new SchemaParserFabric(this.config, this.templatesWorker, this.schemaComponentsMap, this.typeNameFormatter, this.schemaWalker);
3037
+ this.schemaParserFabric = new SchemaParserFabric(this.config, this.templatesWorker, this.schemaComponentsMap, this.typeNameFormatter);
2642
3038
  this.schemaRoutes = new SchemaRoutes(this.config, this.schemaParserFabric, this.schemaComponentsMap, this.templatesWorker, this.typeNameFormatter);
2643
3039
  this.javascriptTranslator = new JavascriptTranslator(this.config, this.codeFormatter);
2644
3040
  }
2645
3041
  async start() {
2646
3042
  this.config.update({ templatePaths: this.templatesWorker.getTemplatePaths(this.config) });
2647
3043
  this.config.update({ templatesToRender: this.templatesWorker.getTemplates(this.config) });
2648
- const swagger = await this.swaggerSchemaResolver.create();
2649
- this.swaggerSchemaResolver.fixSwaggerSchema(swagger);
3044
+ const resolvedSwaggerSchema = await this.swaggerSchemaResolver.create();
2650
3045
  this.config.update({
2651
- swaggerSchema: swagger.usageSchema,
2652
- originalSchema: swagger.originalSchema
3046
+ resolvedSwaggerSchema,
3047
+ swaggerSchema: resolvedSwaggerSchema.usageSchema,
3048
+ originalSchema: resolvedSwaggerSchema.originalSchema
2653
3049
  });
2654
- this.schemaWalker.addSchema("$usage", swagger.usageSchema);
2655
- this.schemaWalker.addSchema("$original", swagger.originalSchema);
2656
- consola.info("start generating your typescript api");
2657
- this.config.update(this.config.hooks.onInit(this.config, this) || this.config);
2658
- if (this.config.swaggerSchema) swagger.usageSchema = this.config.swaggerSchema;
2659
- if (this.config.originalSchema) swagger.originalSchema = this.config.originalSchema;
3050
+ consola$1.info("start generating your typescript api");
3051
+ this.config.update(this.config.hooks.onInit?.(this.config, this) || this.config);
3052
+ if (this.config.swaggerSchema) resolvedSwaggerSchema.usageSchema = this.config.swaggerSchema;
3053
+ if (this.config.originalSchema) resolvedSwaggerSchema.originalSchema = this.config.originalSchema;
2660
3054
  this.schemaComponentsMap.clear();
2661
- for (const [componentName, component] of Object.entries(swagger.usageSchema.components || {})) for (const [typeName, rawTypeData] of Object.entries(component)) this.schemaComponentsMap.createComponent(this.schemaComponentsMap.createRef([
3055
+ for (const [componentName, component] of Object.entries(resolvedSwaggerSchema.usageSchema.components || {})) for (const [typeName, rawTypeData] of Object.entries(component)) this.schemaComponentsMap.createComponent(this.schemaComponentsMap.createRef([
2662
3056
  "components",
2663
3057
  componentName,
2664
3058
  typeName
@@ -2670,12 +3064,9 @@ var CodeGenProcess = class {
2670
3064
  schemaComponent.typeData = parsed;
2671
3065
  return parsed;
2672
3066
  });
2673
- this.schemaRoutes.attachSchema({
2674
- usageSchema: swagger.usageSchema,
2675
- parsedSchemas
2676
- });
3067
+ this.schemaRoutes.attachSchema(resolvedSwaggerSchema, parsedSchemas);
2677
3068
  const rawConfiguration = {
2678
- apiConfig: this.createApiConfig(swagger.usageSchema),
3069
+ apiConfig: this.createApiConfig(resolvedSwaggerSchema.usageSchema),
2679
3070
  config: this.config,
2680
3071
  modelTypes: this.collectModelTypes(),
2681
3072
  hasSecurityRoutes: this.schemaRoutes.hasSecurityRoutes,
@@ -2689,14 +3080,14 @@ var CodeGenProcess = class {
2689
3080
  customTranslator: this.config.customTranslator ? new this.config.customTranslator() : null,
2690
3081
  utils: this.getRenderTemplateData().utils
2691
3082
  };
2692
- const configuration = this.config.hooks.onPrepareConfig(rawConfiguration) || rawConfiguration;
3083
+ const configuration = this.config.hooks.onPrepareConfig?.(rawConfiguration) || rawConfiguration;
2693
3084
  if (this.fileSystem.pathIsExist(this.config.output)) {
2694
3085
  if (this.config.cleanOutput) {
2695
- consola.debug("cleaning dir", this.config.output);
3086
+ consola$1.debug("cleaning dir", this.config.output);
2696
3087
  this.fileSystem.cleanDir(this.config.output);
2697
3088
  }
2698
3089
  } else {
2699
- consola.debug(`path ${this.config.output} is not exist. creating dir by this path`);
3090
+ consola$1.debug(`path ${this.config.output} is not exist. creating dir by this path`);
2700
3091
  this.fileSystem.createDir(this.config.output);
2701
3092
  }
2702
3093
  const files = await this.generateOutputFiles({ configuration });
@@ -2707,7 +3098,7 @@ var CodeGenProcess = class {
2707
3098
  content: file.fileContent,
2708
3099
  withPrefix: true
2709
3100
  });
2710
- consola.success("api file", `"${file.fileName}${file.fileExtension}"`, `created in ${this.config.output}`);
3101
+ consola$1.success("api file", `"${file.fileName}${file.fileExtension}"`, `created in ${this.config.output}`);
2711
3102
  }
2712
3103
  return {
2713
3104
  files,
@@ -2852,7 +3243,7 @@ var CodeGenProcess = class {
2852
3243
  const fileName = this.fileSystem.cropExtension(fileNameFull);
2853
3244
  const fileExtension = typescript.Extension.Ts;
2854
3245
  if (configuration.translateToJavaScript) {
2855
- consola.debug("using js translator for", fileName);
3246
+ consola$1.debug("using js translator for", fileName);
2856
3247
  return await this.javascriptTranslator.translate({
2857
3248
  fileName,
2858
3249
  fileExtension,
@@ -2860,14 +3251,14 @@ var CodeGenProcess = class {
2860
3251
  });
2861
3252
  }
2862
3253
  if (configuration.customTranslator) {
2863
- consola.debug("using custom translator for", fileName);
3254
+ consola$1.debug("using custom translator for", fileName);
2864
3255
  return await configuration.customTranslator.translate({
2865
3256
  fileName,
2866
3257
  fileExtension,
2867
3258
  fileContent: content
2868
3259
  });
2869
3260
  }
2870
- consola.debug("generating output for", `${fileName}${fileExtension}`);
3261
+ consola$1.debug("generating output for", `${fileName}${fileExtension}`);
2871
3262
  return [{
2872
3263
  fileName,
2873
3264
  fileExtension,
@@ -2968,10 +3359,10 @@ var TemplatesGenProcess = class {
2968
3359
  this.fileSystem = new FileSystem();
2969
3360
  }
2970
3361
  async start() {
2971
- consola.info("start generating source templates \".ejs\" for code generator");
3362
+ consola$1.info("start generating source templates \".ejs\" for code generator");
2972
3363
  const templates = this.getTemplates();
2973
3364
  if (this.config.output) {
2974
- consola.info("preparing output directory for source templates");
3365
+ consola$1.info("preparing output directory for source templates");
2975
3366
  const outputPath = path.resolve(process.cwd(), this.config.output);
2976
3367
  if (this.fileSystem.pathIsExist(outputPath)) {
2977
3368
  if (this.config.cleanOutput) this.fileSystem.cleanDir(outputPath);
@@ -3003,7 +3394,7 @@ var TemplatesGenProcess = class {
3003
3394
  });
3004
3395
  }
3005
3396
  }
3006
- consola.success(`source templates has been successfully created in "${outputPath}"`);
3397
+ consola$1.success(`source templates has been successfully created in "${outputPath}"`);
3007
3398
  }
3008
3399
  return {
3009
3400
  files: templates,
@@ -3050,11 +3441,11 @@ var TemplatesGenProcess = class {
3050
3441
  //#endregion
3051
3442
  //#region src/commands/generate-templates/index.ts
3052
3443
  async function generateTemplates(config) {
3053
- if (config.debug) consola.level = Number.MAX_SAFE_INTEGER;
3054
- if (config.silent) consola.level = 0;
3444
+ if (config.debug) consola$1.level = Number.MAX_SAFE_INTEGER;
3445
+ if (config.silent) consola$1.level = 0;
3055
3446
  return await new TemplatesGenProcess(config).start();
3056
3447
  }
3057
3448
 
3058
3449
  //#endregion
3059
3450
  export { CodeGenProcess as a, constants_exports as c, version as d, SCHEMA_TYPES as i, description as l, TemplatesGenConfig as n, CodeGenConfig as o, RequestContentKind as r, HTTP_CLIENT as s, generateTemplates as t, name as u };
3060
- //# sourceMappingURL=generate-templates-DGQlyLhe.mjs.map
3451
+ //# sourceMappingURL=generate-templates-P84KxC-K.mjs.map