swagger-typescript-api 13.2.18 → 13.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.0";
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) => {
@@ -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
  }
@@ -1290,7 +1319,6 @@ var SchemaParser = class {
1290
1319
  schemaFormatters;
1291
1320
  schemaUtils;
1292
1321
  templatesWorker;
1293
- schemaWalker;
1294
1322
  typeName;
1295
1323
  schema;
1296
1324
  schemaPath;
@@ -1300,7 +1328,6 @@ var SchemaParser = class {
1300
1328
  this.templatesWorker = schemaParserFabric.templatesWorker;
1301
1329
  this.schemaComponentsMap = schemaParserFabric.schemaComponentsMap;
1302
1330
  this.typeNameFormatter = schemaParserFabric.typeNameFormatter;
1303
- this.schemaWalker = schemaParserFabric.schemaWalker;
1304
1331
  this.schemaFormatters = schemaParserFabric.schemaFormatters;
1305
1332
  this.schemaUtils = schemaParserFabric.schemaUtils;
1306
1333
  this.typeName = typeName || null;
@@ -1350,7 +1377,7 @@ var SchemaParser = class {
1350
1377
  if (!this.typeName && this.schemaUtils.isRefSchema(this.schema)) this.typeName = this.schemaUtils.getSchemaType(this.schema);
1351
1378
  if (this.schema.items && !Array.isArray(this.schema.items) && !this.schema.type) this.schema.type = SCHEMA_TYPES$1.ARRAY;
1352
1379
  if (Array.isArray(this.schema.enum) && this.schema.enum.length === 1 && this.schema.enum[0] == null) {
1353
- consola.debug("invalid enum schema", this.schema);
1380
+ consola$1.debug("invalid enum schema", this.schema);
1354
1381
  this.schema = { type: this.config.Ts.Keyword.Null };
1355
1382
  }
1356
1383
  if ("content" in this.schema && typeof this.schema.content === "object") {
@@ -1395,24 +1422,13 @@ var SchemaParser = class {
1395
1422
  };
1396
1423
  };
1397
1424
 
1398
- //#endregion
1399
- //#region src/util/pascal-case.ts
1400
- function pascalCase(value) {
1401
- return upperFirst(camelCase(value));
1402
- }
1403
-
1404
1425
  //#endregion
1405
1426
  //#region src/schema-parser/schema-utils.ts
1406
1427
  var SchemaUtils = class {
1407
- config;
1408
- schemaComponentsMap;
1409
- typeNameFormatter;
1410
- schemaWalker;
1411
- constructor({ config, schemaComponentsMap, typeNameFormatter, schemaWalker }) {
1428
+ constructor(config, schemaComponentsMap, typeNameFormatter) {
1412
1429
  this.config = config;
1413
1430
  this.schemaComponentsMap = schemaComponentsMap;
1414
1431
  this.typeNameFormatter = typeNameFormatter;
1415
- this.schemaWalker = schemaWalker;
1416
1432
  }
1417
1433
  getRequiredProperties = (schema) => {
1418
1434
  return uniq(schema && Array.isArray(schema.required) && schema.required || []);
@@ -1558,14 +1574,12 @@ var SchemaParserFabric = class {
1558
1574
  schemaFormatters;
1559
1575
  templatesWorker;
1560
1576
  schemaUtils;
1561
- schemaWalker;
1562
- constructor(config, templatesWorker, schemaComponentsMap, typeNameFormatter, schemaWalker) {
1577
+ constructor(config, templatesWorker, schemaComponentsMap, typeNameFormatter) {
1563
1578
  this.config = config;
1564
1579
  this.schemaComponentsMap = schemaComponentsMap;
1565
1580
  this.typeNameFormatter = typeNameFormatter;
1566
1581
  this.templatesWorker = templatesWorker;
1567
- this.schemaWalker = schemaWalker;
1568
- this.schemaUtils = new SchemaUtils(this);
1582
+ this.schemaUtils = new SchemaUtils(this.config, this.schemaComponentsMap, this.typeNameFormatter);
1569
1583
  this.schemaFormatters = new SchemaFormatters(this);
1570
1584
  }
1571
1585
  createSchemaParser = ({ schema, typeName, schemaPath }) => {
@@ -1632,7 +1646,7 @@ var SpecificArgNameResolver = class extends NameResolver {
1632
1646
  constructor(config, reservedNames) {
1633
1647
  super(config, reservedNames, (variants) => {
1634
1648
  const generatedVariant = variants[0] && `${variants[0]}${this.counter++}` || `${this.config.specificArgNameResolverName}${this.counter++}`;
1635
- consola.debug("generated fallback type name for specific arg - ", generatedVariant);
1649
+ consola$1.debug("generated fallback type name for specific arg - ", generatedVariant);
1636
1650
  return generatedVariant;
1637
1651
  });
1638
1652
  }
@@ -1650,12 +1664,7 @@ const CONTENT_KIND = {
1650
1664
  TEXT: "TEXT"
1651
1665
  };
1652
1666
  var SchemaRoutes = class {
1653
- config;
1654
- schemaParserFabric;
1655
1667
  schemaUtils;
1656
- typeNameFormatter;
1657
- schemaComponentsMap;
1658
- templatesWorker;
1659
1668
  FORM_DATA_TYPES = [];
1660
1669
  routes = [];
1661
1670
  hasSecurityRoutes = false;
@@ -1664,10 +1673,10 @@ var SchemaRoutes = class {
1664
1673
  constructor(config, schemaParserFabric, schemaComponentsMap, templatesWorker, typeNameFormatter) {
1665
1674
  this.config = config;
1666
1675
  this.schemaParserFabric = schemaParserFabric;
1667
- this.schemaUtils = this.schemaParserFabric.schemaUtils;
1668
- this.typeNameFormatter = typeNameFormatter;
1669
1676
  this.schemaComponentsMap = schemaComponentsMap;
1670
1677
  this.templatesWorker = templatesWorker;
1678
+ this.typeNameFormatter = typeNameFormatter;
1679
+ this.schemaUtils = this.schemaParserFabric.schemaUtils;
1671
1680
  this.FORM_DATA_TYPES = uniq([this.schemaUtils.getSchemaType({
1672
1681
  type: "string",
1673
1682
  format: "file"
@@ -1676,11 +1685,16 @@ var SchemaRoutes = class {
1676
1685
  format: "binary"
1677
1686
  })]);
1678
1687
  }
1679
- createRequestsMap = (routesByMethod) => {
1688
+ createRequestsMap = (resolvedSwaggerSchema, routesByMethod) => {
1680
1689
  const parameters = get(routesByMethod, "parameters");
1681
1690
  const result = {};
1682
1691
  for (const [method, requestInfo] of Object.entries(routesByMethod)) {
1683
- if (method.startsWith("x-") || ["parameters", "$ref"].includes(method)) continue;
1692
+ if (method.startsWith("x-") || ["parameters"].includes(method)) continue;
1693
+ if (method === "$ref") {
1694
+ const refData = resolvedSwaggerSchema.getRef(requestInfo);
1695
+ if (typeGuard.isObject(refData)) Object.assign(result, this.createRequestsMap(resolvedSwaggerSchema, refData));
1696
+ continue;
1697
+ }
1684
1698
  result[method] = {
1685
1699
  ...requestInfo,
1686
1700
  parameters: compact([...parameters || [], ...requestInfo.parameters || []])
@@ -1695,7 +1709,7 @@ var SchemaRoutes = class {
1695
1709
  for (const match of pathParamMatches || []) {
1696
1710
  const paramName = match.replace(/\{|\}|:/g, "");
1697
1711
  if (!paramName) continue;
1698
- if (paramName.includes("-")) consola.warn("wrong path param name", paramName);
1712
+ if (paramName.includes("-")) consola$1.warn("wrong path param name", paramName);
1699
1713
  pathParams.push({
1700
1714
  $match: match,
1701
1715
  name: camelCase(paramName),
@@ -1716,7 +1730,7 @@ var SchemaRoutes = class {
1716
1730
  for (const match of queryParamMatches) fixedRoute = fixedRoute.replace(match, "");
1717
1731
  const paramNames = uniq(queryParamMatches.join(",").replace(/(\{\?)|(\})|\s/g, "").split(","));
1718
1732
  for (const paramName of paramNames) {
1719
- if (typeof paramName === "string" && paramName.includes("-")) consola.warn("wrong query param name", paramName);
1733
+ if (typeof paramName === "string" && paramName.includes("-")) consola$1.warn("wrong query param name", paramName);
1720
1734
  queryParams.push({
1721
1735
  $match: paramName,
1722
1736
  name: typeof paramName === "string" ? camelCase(paramName) : camelCase(String(paramName)),
@@ -1749,7 +1763,7 @@ var SchemaRoutes = class {
1749
1763
  for (const parameter of parameters || []) {
1750
1764
  const refTypeInfo = this.schemaParserFabric.schemaUtils.getSchemaRefType(parameter);
1751
1765
  let routeParam = null;
1752
- if (refTypeInfo?.rawTypeData.in && refTypeInfo.rawTypeData) {
1766
+ if (!!refTypeInfo?.rawTypeData && typeof refTypeInfo === "object" && refTypeInfo?.rawTypeData.in) {
1753
1767
  if (!routeParams[refTypeInfo.rawTypeData.in]) routeParams[refTypeInfo.rawTypeData.in] = [];
1754
1768
  routeParam = {
1755
1769
  ...refTypeInfo.rawTypeData,
@@ -1819,10 +1833,11 @@ var SchemaRoutes = class {
1819
1833
  }
1820
1834
  return defaultType || this.config.Ts.Keyword.Any;
1821
1835
  };
1822
- getRequestInfoTypes = ({ requestInfos, parsedSchemas, operationId, defaultType }) => {
1836
+ getRequestInfoTypes = ({ requestInfos, parsedSchemas, operationId, defaultType, resolvedSwaggerSchema }) => {
1823
1837
  const result = [];
1824
1838
  for (const [status, requestInfo] of Object.entries(requestInfos || {})) {
1825
1839
  const contentTypes = this.getContentTypes([requestInfo], operationId);
1840
+ const links = this.getRouteLinksFromResponse(resolvedSwaggerSchema, requestInfo, status);
1826
1841
  result.push({
1827
1842
  ...requestInfo || {},
1828
1843
  contentTypes,
@@ -1834,21 +1849,48 @@ var SchemaRoutes = class {
1834
1849
  defaultType
1835
1850
  })),
1836
1851
  description: this.schemaParserFabric.schemaFormatters.formatDescription(requestInfo.description || "", true),
1852
+ links,
1837
1853
  status: Number.isNaN(+status) ? status : +status,
1838
1854
  isSuccess: this.isSuccessStatus(status)
1839
1855
  });
1840
1856
  }
1841
1857
  return result;
1842
1858
  };
1843
- getResponseBodyInfo = (routeInfo, parsedSchemas) => {
1859
+ getRouteLinksFromResponse = (resolvedSwaggerSchema, responseInfo, status) => {
1860
+ const links = get(responseInfo, "links");
1861
+ if (!typeGuard.isObject(links)) return [];
1862
+ return reduce(links, (acc, linkInfo, linkName) => {
1863
+ if (!typeGuard.isObject(linkInfo)) return acc;
1864
+ let normalizedLinkInfo = linkInfo;
1865
+ if (typeof linkInfo.$ref === "string") {
1866
+ const refData = resolvedSwaggerSchema.getRef(linkInfo.$ref);
1867
+ if (typeGuard.isObject(refData)) normalizedLinkInfo = refData;
1868
+ }
1869
+ const operationId = typeof normalizedLinkInfo.operationId === "string" ? normalizedLinkInfo.operationId : void 0;
1870
+ const operationRef = typeof normalizedLinkInfo.operationRef === "string" ? normalizedLinkInfo.operationRef : typeof linkInfo.$ref === "string" ? linkInfo.$ref : void 0;
1871
+ if (!operationId && !operationRef) return acc;
1872
+ const parameters = typeGuard.isObject(normalizedLinkInfo.parameters) ? mapValues(normalizedLinkInfo.parameters, (value) => String(value)) : void 0;
1873
+ acc.push({
1874
+ status: Number.isNaN(+status) ? status : +status,
1875
+ name: String(linkName),
1876
+ operationId,
1877
+ operationRef,
1878
+ parameters
1879
+ });
1880
+ return acc;
1881
+ }, []);
1882
+ };
1883
+ getResponseBodyInfo = (routeInfo, parsedSchemas, resolvedSwaggerSchema) => {
1844
1884
  const { produces, operationId, responses } = routeInfo;
1845
1885
  const contentTypes = this.getContentTypes(responses, [...produces || [], routeInfo["x-accepts"]]);
1846
1886
  const responseInfos = this.getRequestInfoTypes({
1847
1887
  requestInfos: responses,
1848
1888
  parsedSchemas,
1849
1889
  operationId,
1850
- defaultType: this.config.defaultResponseType
1890
+ defaultType: this.config.defaultResponseType,
1891
+ resolvedSwaggerSchema
1851
1892
  });
1893
+ const links = responseInfos.flatMap((responseInfo) => responseInfo.links || []);
1852
1894
  const successResponse = responseInfos.find((response) => response.isSuccess);
1853
1895
  const errorResponses = responseInfos.filter((response) => !response.isSuccess && response.type !== this.config.Ts.Keyword.Any);
1854
1896
  const handleResponseHeaders = (src) => {
@@ -1861,6 +1903,7 @@ var SchemaRoutes = class {
1861
1903
  return {
1862
1904
  contentTypes,
1863
1905
  responses: responseInfos,
1906
+ links,
1864
1907
  success: {
1865
1908
  schema: successResponse,
1866
1909
  type: successResponse?.type || this.config.Ts.Keyword.Any
@@ -2031,11 +2074,11 @@ var SchemaRoutes = class {
2031
2074
  const { routeNameDuplicatesMap, templatesToRender } = this.config;
2032
2075
  const routeNameTemplate = templatesToRender.routeName;
2033
2076
  const routeNameFromTemplate = this.templatesWorker.renderTemplate(routeNameTemplate, { routeInfo: rawRouteInfo });
2034
- const routeName = this.config.hooks.onFormatRouteName(rawRouteInfo, routeNameFromTemplate) || routeNameFromTemplate;
2077
+ const routeName = this.config.hooks.onFormatRouteName?.(rawRouteInfo, routeNameFromTemplate) || routeNameFromTemplate;
2035
2078
  const duplicateIdentifier = `${moduleName}|${routeName}`;
2036
2079
  if (routeNameDuplicatesMap.has(duplicateIdentifier)) {
2037
2080
  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.`);
2081
+ consola$1.warn(`Module "${moduleName}" already has method "${routeName}()".`, `This method has been renamed to "${routeName + routeNameDuplicatesMap.get(duplicateIdentifier)}()" to solve conflict names.`);
2039
2082
  } else routeNameDuplicatesMap.set(duplicateIdentifier, 1);
2040
2083
  const duplicates = routeNameDuplicatesMap.get(duplicateIdentifier);
2041
2084
  const routeNameInfo = {
@@ -2043,10 +2086,10 @@ var SchemaRoutes = class {
2043
2086
  original: routeName,
2044
2087
  duplicate: duplicates > 1
2045
2088
  };
2046
- return this.config.hooks.onCreateRouteName(routeNameInfo, rawRouteInfo) || routeNameInfo;
2089
+ return this.config.hooks.onCreateRouteName?.(routeNameInfo, rawRouteInfo) || routeNameInfo;
2047
2090
  };
2048
- parseRouteInfo = (rawRouteName, routeInfo, method, usageSchema, parsedSchemas) => {
2049
- const { security: globalSecurity } = usageSchema;
2091
+ parseRouteInfo = (rawRouteName, routeInfo, method, resolvedSwaggerSchema, parsedSchemas) => {
2092
+ const { security: globalSecurity } = resolvedSwaggerSchema.usageSchema;
2050
2093
  const { moduleNameIndex, moduleNameFirstTag, extractRequestParams } = this.config;
2051
2094
  const { operationId, requestBody, security, parameters, summary, description, tags, responses, requestBodyName, produces, consumes, ...otherInfo } = routeInfo;
2052
2095
  const { route, pathParams: pathParamsFromRouteName, queryParams: queryParamsFromRouteName } = this.parseRouteName(rawRouteName);
@@ -2063,7 +2106,7 @@ var SchemaRoutes = class {
2063
2106
  description: pathArgSchema.description
2064
2107
  }));
2065
2108
  const pathArgsNames = pathArgs.map((arg) => arg.name);
2066
- const responseBodyInfo = this.getResponseBodyInfo(routeInfo, parsedSchemas);
2109
+ const responseBodyInfo = this.getResponseBodyInfo(routeInfo, parsedSchemas, resolvedSwaggerSchema);
2067
2110
  const rawRouteInfo = {
2068
2111
  ...otherInfo,
2069
2112
  pathArgs,
@@ -2072,6 +2115,7 @@ var SchemaRoutes = class {
2072
2115
  route: rawRouteName,
2073
2116
  moduleName,
2074
2117
  responsesTypes: responseBodyInfo.responses,
2118
+ links: responseBodyInfo.links,
2075
2119
  description,
2076
2120
  tags,
2077
2121
  summary,
@@ -2167,13 +2211,13 @@ var SchemaRoutes = class {
2167
2211
  raw: rawRouteInfo
2168
2212
  };
2169
2213
  };
2170
- attachSchema = ({ usageSchema, parsedSchemas }) => {
2214
+ attachSchema = (resolvedSwaggerSchema, parsedSchemas) => {
2171
2215
  this.config.routeNameDuplicatesMap.clear();
2172
- const pathsEntries = Object.entries(usageSchema.paths || {});
2216
+ const pathsEntries = Object.entries(resolvedSwaggerSchema.usageSchema.paths || {});
2173
2217
  for (const [rawRouteName, routeInfoByMethodsMap] of pathsEntries) {
2174
- const routeInfosMap = this.createRequestsMap(routeInfoByMethodsMap);
2218
+ const routeInfosMap = this.createRequestsMap(resolvedSwaggerSchema, routeInfoByMethodsMap);
2175
2219
  for (const [method, routeInfo] of Object.entries(routeInfosMap)) {
2176
- const parsedRouteInfo = this.parseRouteInfo(rawRouteName, routeInfo, method, usageSchema, parsedSchemas);
2220
+ const parsedRouteInfo = this.parseRouteInfo(rawRouteName, routeInfo, method, resolvedSwaggerSchema, parsedSchemas);
2177
2221
  const processedRouteInfo = this.config.hooks.onCreateRoute(parsedRouteInfo);
2178
2222
  if (processedRouteInfo !== false) {
2179
2223
  const route = processedRouteInfo || parsedRouteInfo;
@@ -2227,30 +2271,353 @@ var SchemaRoutes = class {
2227
2271
  };
2228
2272
 
2229
2273
  //#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) {
2274
+ //#region src/resolved-swagger-schema.ts
2275
+ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2276
+ parsedRefsCache = /* @__PURE__ */ new Map();
2277
+ externalSchemaCache = /* @__PURE__ */ new Map();
2278
+ httpMethodSegments = new Set([
2279
+ "get",
2280
+ "put",
2281
+ "post",
2282
+ "delete",
2283
+ "patch",
2284
+ "options",
2285
+ "head",
2286
+ "trace",
2287
+ "parameters"
2288
+ ]);
2289
+ normalizeRef(ref) {
2290
+ let normalizedRef = ref;
2291
+ normalizedRef = normalizedRef.replace(/\/#(?=\/)/, "#");
2292
+ normalizedRef = normalizedRef.replace(/#(?!\/)/, "#/");
2293
+ return normalizedRef;
2294
+ }
2295
+ createEscapedPathsRefVariant(ref) {
2296
+ const [prefix = "", rawPointer = ""] = this.normalizeRef(ref).split("#");
2297
+ const pointer = rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}`;
2298
+ if (!pointer.startsWith("/paths/") || pointer.startsWith("/paths/~1")) return null;
2299
+ const rest = pointer.slice(7);
2300
+ if (!rest) return null;
2301
+ const parts = rest.split("/");
2302
+ const last = parts.at(-1)?.toLowerCase() || "";
2303
+ const hasTailSegment = this.httpMethodSegments.has(last);
2304
+ const pathParts = hasTailSegment ? parts.slice(0, -1) : parts;
2305
+ const tail = hasTailSegment ? `/${parts.at(-1)}` : "";
2306
+ if (!pathParts.length) return null;
2307
+ return `${prefix}#/paths/${`~1${pathParts.join("/").replace(/\//g, "~1")}`}${tail}`;
2308
+ }
2309
+ isHttpUrl(value) {
2310
+ return /^https?:\/\//i.test(value);
2311
+ }
2312
+ getRemoteRequestHeaders() {
2313
+ return Object.assign({}, this.config.authorizationToken ? { Authorization: this.config.authorizationToken } : {}, this.config.requestOptions?.headers || {});
2314
+ }
2315
+ stripHash(urlOrPath) {
2316
+ return urlOrPath.split("#")[0] || urlOrPath;
2317
+ }
2318
+ extractRefsFromSchema(schema) {
2319
+ const refs = /* @__PURE__ */ new Set();
2320
+ const walk = (node) => {
2321
+ if (!node || typeof node !== "object") return;
2322
+ if (Array.isArray(node)) {
2323
+ for (const item of node) walk(item);
2324
+ return;
2325
+ }
2326
+ const recordNode = node;
2327
+ if (typeof recordNode.$ref === "string") refs.add(recordNode.$ref);
2328
+ for (const value of Object.values(recordNode)) walk(value);
2329
+ };
2330
+ walk(schema);
2331
+ return [...refs];
2332
+ }
2333
+ async fetchRemoteSchemaDocument(url) {
2334
+ try {
2335
+ const response = await fetch(url, { headers: this.getRemoteRequestHeaders() });
2336
+ if (!response.ok) return null;
2337
+ const content = await response.text();
2338
+ try {
2339
+ const parsed = JSON.parse(content);
2340
+ if (parsed && typeof parsed === "object") return parsed;
2341
+ } catch {
2342
+ const parsed = YAML.parse(content);
2343
+ if (parsed && typeof parsed === "object") return parsed;
2344
+ }
2345
+ } catch (e) {
2346
+ consola.debug(e);
2347
+ }
2348
+ return null;
2349
+ }
2350
+ async warmUpRemoteSchemasCache() {
2351
+ if (typeof this.config.url !== "string" || !this.isHttpUrl(this.config.url)) return;
2352
+ const visited = /* @__PURE__ */ new Set();
2353
+ const queue = [this.stripHash(this.config.url)];
2354
+ while (queue.length > 0) {
2355
+ const currentUrl = queue.shift();
2356
+ if (!currentUrl || visited.has(currentUrl)) continue;
2357
+ visited.add(currentUrl);
2358
+ if (this.externalSchemaCache.has(currentUrl)) continue;
2359
+ const schema = await this.fetchRemoteSchemaDocument(currentUrl);
2360
+ if (!schema) continue;
2361
+ this.externalSchemaCache.set(currentUrl, schema);
2362
+ for (const ref of this.extractRefsFromSchema(schema)) {
2363
+ const normalizedRef = this.normalizeRef(ref);
2364
+ if (normalizedRef.startsWith("#")) continue;
2365
+ const [externalPath = ""] = normalizedRef.split("#");
2366
+ if (!externalPath) continue;
2367
+ let absoluteUrl = "";
2368
+ try {
2369
+ absoluteUrl = this.isHttpUrl(externalPath) ? this.stripHash(externalPath) : this.stripHash(new URL(externalPath, currentUrl).toString());
2370
+ } catch (e) {
2371
+ consola.debug(e);
2372
+ }
2373
+ if (absoluteUrl && !visited.has(absoluteUrl)) queue.push(absoluteUrl);
2374
+ }
2375
+ }
2376
+ }
2377
+ collectRemoteAbsoluteRefCandidates(ref) {
2378
+ if (!ref || this.isHttpUrl(ref) || ref.startsWith("#")) return [];
2379
+ const [relativePath = "", rawPointer = ""] = this.normalizeRef(ref).split("#");
2380
+ if (!relativePath) return [];
2381
+ const pointer = rawPointer ? rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}` : "";
2382
+ const bases = /* @__PURE__ */ new Set();
2383
+ if (typeof this.config.url === "string" && this.isHttpUrl(this.config.url)) bases.add(this.config.url);
2384
+ for (const cachedUrl of this.externalSchemaCache.keys()) if (this.isHttpUrl(cachedUrl)) bases.add(cachedUrl);
2385
+ for (const resolver of this.resolvers) try {
2386
+ const resolverPaths = typeof resolver.paths === "function" ? resolver.paths() : [];
2387
+ for (const resolverPath of resolverPaths) if (typeof resolverPath === "string" && this.isHttpUrl(resolverPath)) bases.add(resolverPath);
2388
+ } catch (e) {
2389
+ consola.debug(e);
2390
+ }
2391
+ const results = /* @__PURE__ */ new Set();
2392
+ for (const base of bases) try {
2393
+ const absolutePath = new URL(relativePath, base).toString();
2394
+ results.add(pointer ? `${absolutePath}#${pointer}` : absolutePath);
2395
+ } catch (e) {
2396
+ consola.debug(e);
2397
+ }
2398
+ return [...results];
2399
+ }
2400
+ resolveFromRemoteSchemaCache(absoluteRef) {
2401
+ const [externalPath = "", rawPointer = ""] = this.normalizeRef(absoluteRef).split("#");
2402
+ if (!externalPath || !this.isHttpUrl(externalPath)) return null;
2403
+ const schema = this.externalSchemaCache.get(this.stripHash(externalPath));
2404
+ if (!schema) return null;
2405
+ const pointer = rawPointer ? rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}` : "/";
2406
+ const resolved = this.resolveJsonPointer(schema, pointer);
2407
+ if (resolved == null) return null;
2408
+ return this.absolutizeLocalRefs(resolved, this.stripHash(externalPath));
2409
+ }
2410
+ constructor(config, usageSchema, originalSchema, resolvers) {
2237
2411
  this.config = config;
2238
- this.swaggerSchemaResolver = swaggerSchemaResolver;
2412
+ this.usageSchema = usageSchema;
2413
+ this.originalSchema = originalSchema;
2414
+ this.resolvers = resolvers;
2415
+ this.usageSchema = usageSchema;
2416
+ this.originalSchema = originalSchema;
2417
+ }
2418
+ getRefDetails(ref) {
2419
+ const normalizedRef = this.normalizeRef(ref);
2420
+ if (!this.parsedRefsCache.has(ref)) {
2421
+ const isLocal = normalizedRef.startsWith("#");
2422
+ if (isLocal) this.parsedRefsCache.set(ref, {
2423
+ ref: normalizedRef,
2424
+ isLocal,
2425
+ externalUrlOrPath: null
2426
+ });
2427
+ else {
2428
+ const externalUrlOrPath = normalizedRef.split("#")[0] || "";
2429
+ let externalOpenapiFileName = externalUrlOrPath.replace(/\/$/, "").split("/").at(-1) || "";
2430
+ if (externalOpenapiFileName.endsWith(".json") || externalOpenapiFileName.endsWith(".yaml")) externalOpenapiFileName = externalOpenapiFileName.slice(0, -5);
2431
+ else if (externalOpenapiFileName.endsWith(".yml")) externalOpenapiFileName = externalOpenapiFileName.slice(0, -4);
2432
+ this.parsedRefsCache.set(ref, {
2433
+ ref: normalizedRef,
2434
+ isLocal,
2435
+ externalUrlOrPath,
2436
+ externalOpenapiFileName
2437
+ });
2438
+ }
2439
+ }
2440
+ const cachedRef = this.parsedRefsCache.get(ref);
2441
+ if (cachedRef) return cachedRef;
2442
+ if (normalizedRef.startsWith("#")) return {
2443
+ ref: normalizedRef,
2444
+ isLocal: true,
2445
+ externalUrlOrPath: null
2446
+ };
2447
+ return {
2448
+ ref: normalizedRef,
2449
+ isLocal: false,
2450
+ externalUrlOrPath: normalizedRef.split("#")[0] || null,
2451
+ externalOpenapiFileName: ""
2452
+ };
2453
+ }
2454
+ isLocalRef(ref) {
2455
+ return this.getRefDetails(ref).isLocal;
2456
+ }
2457
+ getRef(ref) {
2458
+ if (!ref) return null;
2459
+ const normalizedRef = this.normalizeRef(ref);
2460
+ const escapedPathsRefVariant = this.createEscapedPathsRefVariant(ref);
2461
+ if (normalizedRef !== ref) {
2462
+ const resolvedByNormalizedRef = this.tryToResolveRef(normalizedRef);
2463
+ if (resolvedByNormalizedRef) return this.normalizeResolvedExternalSchemaRef(normalizedRef, resolvedByNormalizedRef);
2464
+ }
2465
+ if (escapedPathsRefVariant) {
2466
+ const resolvedByEscapedPathsRef = this.tryToResolveRef(escapedPathsRefVariant);
2467
+ if (resolvedByEscapedPathsRef) return this.normalizeResolvedExternalSchemaRef(escapedPathsRefVariant, resolvedByEscapedPathsRef);
2468
+ }
2469
+ const remoteAbsoluteCandidates = this.collectRemoteAbsoluteRefCandidates(ref);
2470
+ for (const remoteAbsoluteRef of remoteAbsoluteCandidates) {
2471
+ const resolvedFromRemoteCache = this.resolveFromRemoteSchemaCache(remoteAbsoluteRef);
2472
+ if (resolvedFromRemoteCache) return resolvedFromRemoteCache;
2473
+ const resolvedByRemoteAbsoluteRef = this.tryToResolveRef(remoteAbsoluteRef);
2474
+ if (resolvedByRemoteAbsoluteRef) return this.normalizeResolvedExternalSchemaRef(remoteAbsoluteRef, resolvedByRemoteAbsoluteRef);
2475
+ }
2476
+ const resolvedByOrigRef = this.tryToResolveRef(ref);
2477
+ if (resolvedByOrigRef) return this.normalizeResolvedExternalSchemaRef(ref, resolvedByOrigRef);
2478
+ if (/#[a-z]/.test(ref)) {
2479
+ const fixedRef = ref.replace(/#[a-z]/, (match) => {
2480
+ const [hashtag, char] = match.split("");
2481
+ return `${hashtag}/${char}`;
2482
+ });
2483
+ const resolvedByFixedRef = this.tryToResolveRef(fixedRef);
2484
+ if (resolvedByFixedRef) return this.normalizeResolvedExternalSchemaRef(fixedRef, resolvedByFixedRef);
2485
+ }
2486
+ return this.tryToResolveRefFromFile(normalizedRef);
2487
+ }
2488
+ tryToResolveRef(ref) {
2489
+ if (!this.resolvers || !ref) return null;
2490
+ for (const resolver of this.resolvers) try {
2491
+ return resolver.get(ref);
2492
+ } catch (e) {
2493
+ consola.debug(e);
2494
+ }
2495
+ return null;
2496
+ }
2497
+ readExternalSchema(filePath) {
2498
+ if (this.externalSchemaCache.has(filePath)) return this.externalSchemaCache.get(filePath) || null;
2499
+ if (!fs.existsSync(filePath)) return null;
2500
+ try {
2501
+ const content = fs.readFileSync(filePath, "utf8");
2502
+ const parsed = JSON.parse(content);
2503
+ this.externalSchemaCache.set(filePath, parsed);
2504
+ return parsed;
2505
+ } catch {
2506
+ try {
2507
+ const content = fs.readFileSync(filePath, "utf8");
2508
+ const parsed = YAML.parse(content);
2509
+ if (parsed && typeof parsed === "object") {
2510
+ this.externalSchemaCache.set(filePath, parsed);
2511
+ return parsed;
2512
+ }
2513
+ } catch (e) {
2514
+ consola.debug(e);
2515
+ }
2516
+ }
2517
+ return null;
2518
+ }
2519
+ resolveJsonPointer(source, pointer) {
2520
+ if (!source || typeof source !== "object") return null;
2521
+ if (!pointer || pointer === "/") return source;
2522
+ const tokens = pointer.replace(/^\/+/, "").split("/").filter(Boolean).map((part) => decodeURIComponent(part.replace(/~1/g, "/").replace(/~0/g, "~")));
2523
+ let current = source;
2524
+ for (const token of tokens) {
2525
+ if (!current || typeof current !== "object") return null;
2526
+ current = current[token];
2527
+ }
2528
+ return current ?? null;
2529
+ }
2530
+ absolutizeLocalRefs(value, externalPath) {
2531
+ if (value == null || typeof value !== "object") return value;
2532
+ const cloneValue = structuredClone(value);
2533
+ const walk = (node) => {
2534
+ if (!node || typeof node !== "object") return;
2535
+ if (Array.isArray(node)) {
2536
+ for (const item of node) walk(item);
2537
+ return;
2538
+ }
2539
+ const recordNode = node;
2540
+ if (typeof recordNode.$ref === "string" && recordNode.$ref.startsWith("#")) recordNode.$ref = `${externalPath}${this.normalizeRef(recordNode.$ref)}`;
2541
+ for (const nested of Object.values(recordNode)) walk(nested);
2542
+ };
2543
+ walk(cloneValue);
2544
+ return cloneValue;
2545
+ }
2546
+ normalizeResolvedExternalSchemaRef(ref, resolved) {
2547
+ const normalizedRef = this.normalizeRef(ref);
2548
+ if (normalizedRef.startsWith("#")) return resolved;
2549
+ const externalPath = normalizedRef.split("#")[0] || "";
2550
+ if (!externalPath) return resolved;
2551
+ return this.absolutizeLocalRefs(resolved, externalPath);
2552
+ }
2553
+ collectExternalRefCandidates(externalPath) {
2554
+ const candidates = /* @__PURE__ */ new Set();
2555
+ if (/^https?:\/\//i.test(externalPath)) return [];
2556
+ if (path.isAbsolute(externalPath)) candidates.add(externalPath);
2557
+ const inputPath = this.config.input;
2558
+ if (typeof inputPath === "string" && inputPath) candidates.add(path.resolve(path.dirname(inputPath), externalPath));
2559
+ for (const resolver of this.resolvers) try {
2560
+ const resolverPaths = typeof resolver.paths === "function" ? resolver.paths() : [];
2561
+ for (const resolverPath of resolverPaths) {
2562
+ if (typeof resolverPath !== "string") continue;
2563
+ if (/^https?:\/\//i.test(resolverPath)) continue;
2564
+ candidates.add(path.resolve(path.dirname(resolverPath), externalPath));
2565
+ }
2566
+ } catch (e) {
2567
+ consola.debug(e);
2568
+ }
2569
+ return [...candidates];
2570
+ }
2571
+ tryToResolveRefFromFile(ref) {
2572
+ if (!ref || ref.startsWith("#")) return null;
2573
+ const [externalPath = "", rawPointer = ""] = ref.split("#");
2574
+ if (!externalPath) return null;
2575
+ const pointer = rawPointer ? rawPointer.startsWith("/") ? rawPointer : `/${rawPointer}` : "/";
2576
+ const candidates = this.collectExternalRefCandidates(externalPath);
2577
+ for (const candidate of candidates) {
2578
+ const schema = this.readExternalSchema(candidate);
2579
+ const resolved = this.resolveJsonPointer(schema, pointer);
2580
+ if (resolved != null) return this.absolutizeLocalRefs(resolved, externalPath);
2581
+ }
2582
+ return null;
2583
+ }
2584
+ static async create(config, usageSchema, originalSchema) {
2585
+ const resolvers = [];
2586
+ const options = {
2587
+ continueOnError: true,
2588
+ mutateInputSchema: true,
2589
+ dereference: {},
2590
+ validate: {
2591
+ schema: false,
2592
+ spec: false
2593
+ },
2594
+ resolve: {
2595
+ external: true,
2596
+ http: {
2597
+ ...config.requestOptions,
2598
+ headers: Object.assign({}, config.authorizationToken ? { Authorization: config.authorizationToken } : {}, config.requestOptions?.headers ?? {})
2599
+ }
2600
+ }
2601
+ };
2602
+ try {
2603
+ resolvers.push(await SwaggerParser.resolve(originalSchema, options));
2604
+ } catch (e) {
2605
+ consola.debug(e);
2606
+ }
2607
+ try {
2608
+ resolvers.push(await SwaggerParser.resolve(usageSchema, options));
2609
+ } catch (e) {
2610
+ consola.debug(e);
2611
+ }
2612
+ try {
2613
+ resolvers.push(await SwaggerParser.resolve(config.url || config.input || config.spec, options));
2614
+ } catch (e) {
2615
+ consola.debug(e);
2616
+ }
2617
+ const resolvedSwaggerSchema = new ResolvedSwaggerSchema(config, usageSchema, originalSchema, resolvers);
2618
+ await resolvedSwaggerSchema.warmUpRemoteSchemasCache();
2619
+ return resolvedSwaggerSchema;
2239
2620
  }
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
2621
  };
2255
2622
 
2256
2623
  //#endregion
@@ -2268,7 +2635,7 @@ var Request = class {
2268
2635
  return await (await fetch(url, requestOptions)).text();
2269
2636
  } catch (error) {
2270
2637
  const message = `error while fetching data from URL "${url}"`;
2271
- consola.error(message, error);
2638
+ consola$1.error(message, error);
2272
2639
  return message;
2273
2640
  }
2274
2641
  }
@@ -2287,10 +2654,15 @@ var SwaggerSchemaResolver = class {
2287
2654
  }
2288
2655
  async create() {
2289
2656
  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 });
2657
+ let swaggerSchemas;
2658
+ if (spec) swaggerSchemas = await this.convertSwaggerObject(spec, { patch });
2659
+ else {
2660
+ const swaggerSchemaFile = await this.fetchSwaggerSchemaFile(input, url, authorizationToken);
2661
+ const swaggerSchemaObject = this.processSwaggerSchemaFile(swaggerSchemaFile);
2662
+ swaggerSchemas = await this.convertSwaggerObject(swaggerSchemaObject, { patch });
2663
+ }
2664
+ this.fixSwaggerSchemas(swaggerSchemas);
2665
+ return ResolvedSwaggerSchema.create(this.config, swaggerSchemas.usageSchema, swaggerSchemas.originalSchema);
2294
2666
  }
2295
2667
  convertSwaggerObject(swaggerSchema, converterOptions) {
2296
2668
  return new Promise((resolve) => {
@@ -2323,12 +2695,12 @@ var SwaggerSchemaResolver = class {
2323
2695
  });
2324
2696
  }
2325
2697
  getSwaggerSchemaByPath = (pathToSwagger) => {
2326
- consola.info(`try to get swagger by path "${pathToSwagger}"`);
2698
+ consola$1.info(`try to get swagger by path "${pathToSwagger}"`);
2327
2699
  return this.fileSystem.getFileContent(pathToSwagger);
2328
2700
  };
2329
2701
  async fetchSwaggerSchemaFile(pathToSwagger, urlToSwagger, authToken) {
2330
2702
  if (this.fileSystem.pathIsExist(pathToSwagger)) return this.getSwaggerSchemaByPath(pathToSwagger);
2331
- consola.info(`try to get swagger by URL "${urlToSwagger}"`);
2703
+ consola$1.info(`try to get swagger by URL "${urlToSwagger}"`);
2332
2704
  return await this.request.download({
2333
2705
  url: urlToSwagger,
2334
2706
  authToken
@@ -2342,7 +2714,26 @@ var SwaggerSchemaResolver = class {
2342
2714
  return YAML.parse(file);
2343
2715
  }
2344
2716
  }
2345
- fixSwaggerSchema({ usageSchema, originalSchema }) {
2717
+ normalizeRefValue(ref) {
2718
+ const refWithoutSlashBeforeHash = ref.split("/#/").join("#/");
2719
+ const hashIndex = refWithoutSlashBeforeHash.indexOf("#");
2720
+ if (hashIndex === -1) return refWithoutSlashBeforeHash;
2721
+ if (refWithoutSlashBeforeHash[hashIndex + 1] === "/") return refWithoutSlashBeforeHash;
2722
+ return `${refWithoutSlashBeforeHash.slice(0, hashIndex + 1)}/${refWithoutSlashBeforeHash.slice(hashIndex + 1)}`;
2723
+ }
2724
+ normalizeRefsInSchema(schema) {
2725
+ if (!schema || typeof schema !== "object") return;
2726
+ if (Array.isArray(schema)) {
2727
+ for (const value of schema) this.normalizeRefsInSchema(value);
2728
+ return;
2729
+ }
2730
+ const objectSchema = schema;
2731
+ if (typeof objectSchema.$ref === "string") objectSchema.$ref = this.normalizeRefValue(objectSchema.$ref);
2732
+ for (const value of Object.values(objectSchema)) this.normalizeRefsInSchema(value);
2733
+ }
2734
+ fixSwaggerSchemas({ usageSchema, originalSchema }) {
2735
+ this.normalizeRefsInSchema(usageSchema);
2736
+ this.normalizeRefsInSchema(originalSchema);
2346
2737
  const usagePaths = get(usageSchema, "paths") || {};
2347
2738
  const originalPaths = get(originalSchema, "paths") || {};
2348
2739
  for (const [route, usagePathObject] of Object.entries(usagePaths)) {
@@ -2351,9 +2742,10 @@ var SwaggerSchemaResolver = class {
2351
2742
  const originalRouteInfo = get(originalPathObject, methodName) || {};
2352
2743
  const usageRouteParams = get(usageRouteInfo, "parameters") || [];
2353
2744
  const originalRouteParams = get(originalRouteInfo, "parameters") || [];
2745
+ const usageAsOpenapiv2 = usageRouteInfo;
2354
2746
  if (typeof usageRouteInfo === "object") {
2355
- usageRouteInfo.consumes = uniq(compact([...usageRouteInfo.consumes || [], ...originalRouteInfo.consumes || []]));
2356
- usageRouteInfo.produces = uniq(compact([...usageRouteInfo.produces || [], ...originalRouteInfo.produces || []]));
2747
+ usageAsOpenapiv2.consumes = uniq(compact([...usageAsOpenapiv2.consumes || [], ...originalRouteInfo.consumes || []]));
2748
+ usageAsOpenapiv2.produces = uniq(compact([...usageAsOpenapiv2.produces || [], ...originalRouteInfo.produces || []]));
2357
2749
  }
2358
2750
  for (const originalRouteParam of originalRouteParams) if (!usageRouteParams.find((param) => originalRouteParam.in === param.in && originalRouteParam.name === param.name)) usageRouteParams.push(originalRouteParam);
2359
2751
  }
@@ -2373,8 +2765,8 @@ var TemplatesWorker = class {
2373
2765
  this.config = config;
2374
2766
  this.fileSystem = fileSystem;
2375
2767
  this.getRenderTemplateData = getRenderTemplateData;
2376
- if (this.config.debug) consola.level = Number.MAX_SAFE_INTEGER;
2377
- if (this.config.silent) consola.level = 0;
2768
+ if (this.config.debug) consola$1.level = Number.MAX_SAFE_INTEGER;
2769
+ if (this.config.silent) consola$1.level = 0;
2378
2770
  }
2379
2771
  getTemplatePaths = (config) => {
2380
2772
  const __dirname = path$1.dirname(url$1.fileURLToPath(import.meta.url));
@@ -2405,19 +2797,19 @@ var TemplatesWorker = class {
2405
2797
  const customFullPath = templatePaths.custom && this.getTemplateFullPath(templatePaths.custom, fileName);
2406
2798
  let fileContent = customFullPath && this.fileSystem.getFileContent(customFullPath);
2407
2799
  if (fileContent) {
2408
- consola.info(`"${name.toLowerCase()}" template found in "${templatePaths.custom}"`);
2800
+ consola$1.info(`"${name.toLowerCase()}" template found in "${templatePaths.custom}"`);
2409
2801
  return fileContent;
2410
2802
  }
2411
2803
  const baseFullPath = this.getTemplateFullPath(templatePaths.base, fileName);
2412
2804
  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()}"`);
2805
+ else if (templatePaths.custom) consola$1.warn("Code generator will use the default template:", `"${name.toLowerCase()}"`, "template not found in", `"${templatePaths.custom}"`);
2806
+ else consola$1.info(`Code generator will use the default template for "${name.toLowerCase()}"`);
2415
2807
  const originalFullPath = this.getTemplateFullPath(templatePaths.original, fileName);
2416
2808
  if (originalFullPath) fileContent = this.fileSystem.getFileContent(originalFullPath);
2417
2809
  return fileContent;
2418
2810
  };
2419
2811
  getTemplates = ({ templatePaths }) => {
2420
- if (templatePaths.custom) consola.info(`try to read templates from directory "${templatePaths.custom}"`);
2812
+ if (templatePaths.custom) consola$1.info(`try to read templates from directory "${templatePaths.custom}"`);
2421
2813
  return this.config.templateInfos.reduce((acc, { name, fileName }) => ({
2422
2814
  ...acc,
2423
2815
  [name]: this.getTemplate(name, fileName)
@@ -2518,7 +2910,7 @@ var TypeNameFormatter = class {
2518
2910
  const typeSuffix = schemaType === "enum-key" ? this.config.enumKeySuffix : this.config.typeSuffix;
2519
2911
  const hashKey = `${typePrefix}_${name}_${typeSuffix}`;
2520
2912
  if (typeof name !== "string") {
2521
- consola.warn("wrong model name", name);
2913
+ consola$1.warn("wrong model name", name);
2522
2914
  return name;
2523
2915
  }
2524
2916
  if (/^(?!\d)([A-Z0-9_]{1,})$/g.test(name)) return compact([
@@ -2528,7 +2920,7 @@ var TypeNameFormatter = class {
2528
2920
  ]).join("_");
2529
2921
  if (this.formattedModelNamesMap.has(hashKey)) return this.formattedModelNamesMap.get(hashKey);
2530
2922
  const formattedName = startCase(`${typePrefix}_${this.fixModelName(name, { type: schemaType })}_${typeSuffix}`).replace(/\s/g, "");
2531
- const formattedResultName = this.config.hooks.onFormatTypeName(formattedName, name, schemaType) || formattedName;
2923
+ const formattedResultName = this.config.hooks.onFormatTypeName?.(formattedName, name, schemaType) || formattedName;
2532
2924
  this.formattedModelNamesMap.set(hashKey, formattedResultName);
2533
2925
  return formattedResultName;
2534
2926
  };
@@ -2570,14 +2962,14 @@ var FileSystem = class {
2570
2962
  if (typeof fs.rmSync === "function") fs.rmSync(path, { recursive: true });
2571
2963
  else fs.rmdirSync(path, { recursive: true });
2572
2964
  } catch (e) {
2573
- consola.debug("failed to remove dir", e);
2965
+ consola$1.debug("failed to remove dir", e);
2574
2966
  }
2575
2967
  };
2576
2968
  createDir = (path) => {
2577
2969
  try {
2578
2970
  fs.mkdirSync(path, { recursive: true });
2579
2971
  } catch (e) {
2580
- consola.debug("failed to create dir", e);
2972
+ consola$1.debug("failed to create dir", e);
2581
2973
  }
2582
2974
  };
2583
2975
  cleanDir = (path) => {
@@ -2627,38 +3019,35 @@ var CodeGenProcess = class {
2627
3019
  fileSystem;
2628
3020
  codeFormatter;
2629
3021
  templatesWorker;
2630
- schemaWalker;
2631
3022
  javascriptTranslator;
3023
+ swaggerRefs;
2632
3024
  constructor(config) {
2633
3025
  this.config = new CodeGenConfig(config);
2634
3026
  this.fileSystem = new FileSystem();
2635
3027
  this.swaggerSchemaResolver = new SwaggerSchemaResolver(this.config, this.fileSystem);
2636
- this.schemaWalker = new SchemaWalker(this.config, this.swaggerSchemaResolver);
2637
3028
  this.schemaComponentsMap = new SchemaComponentsMap(this.config);
2638
3029
  this.typeNameFormatter = new TypeNameFormatter(this.config);
2639
3030
  this.templatesWorker = new TemplatesWorker(this.config, this.fileSystem, this.getRenderTemplateData);
2640
3031
  this.codeFormatter = new CodeFormatter(this.config);
2641
- this.schemaParserFabric = new SchemaParserFabric(this.config, this.templatesWorker, this.schemaComponentsMap, this.typeNameFormatter, this.schemaWalker);
3032
+ this.schemaParserFabric = new SchemaParserFabric(this.config, this.templatesWorker, this.schemaComponentsMap, this.typeNameFormatter);
2642
3033
  this.schemaRoutes = new SchemaRoutes(this.config, this.schemaParserFabric, this.schemaComponentsMap, this.templatesWorker, this.typeNameFormatter);
2643
3034
  this.javascriptTranslator = new JavascriptTranslator(this.config, this.codeFormatter);
2644
3035
  }
2645
3036
  async start() {
2646
3037
  this.config.update({ templatePaths: this.templatesWorker.getTemplatePaths(this.config) });
2647
3038
  this.config.update({ templatesToRender: this.templatesWorker.getTemplates(this.config) });
2648
- const swagger = await this.swaggerSchemaResolver.create();
2649
- this.swaggerSchemaResolver.fixSwaggerSchema(swagger);
3039
+ const resolvedSwaggerSchema = await this.swaggerSchemaResolver.create();
2650
3040
  this.config.update({
2651
- swaggerSchema: swagger.usageSchema,
2652
- originalSchema: swagger.originalSchema
3041
+ resolvedSwaggerSchema,
3042
+ swaggerSchema: resolvedSwaggerSchema.usageSchema,
3043
+ originalSchema: resolvedSwaggerSchema.originalSchema
2653
3044
  });
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;
3045
+ consola$1.info("start generating your typescript api");
3046
+ this.config.update(this.config.hooks.onInit?.(this.config, this) || this.config);
3047
+ if (this.config.swaggerSchema) resolvedSwaggerSchema.usageSchema = this.config.swaggerSchema;
3048
+ if (this.config.originalSchema) resolvedSwaggerSchema.originalSchema = this.config.originalSchema;
2660
3049
  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([
3050
+ 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
3051
  "components",
2663
3052
  componentName,
2664
3053
  typeName
@@ -2670,12 +3059,9 @@ var CodeGenProcess = class {
2670
3059
  schemaComponent.typeData = parsed;
2671
3060
  return parsed;
2672
3061
  });
2673
- this.schemaRoutes.attachSchema({
2674
- usageSchema: swagger.usageSchema,
2675
- parsedSchemas
2676
- });
3062
+ this.schemaRoutes.attachSchema(resolvedSwaggerSchema, parsedSchemas);
2677
3063
  const rawConfiguration = {
2678
- apiConfig: this.createApiConfig(swagger.usageSchema),
3064
+ apiConfig: this.createApiConfig(resolvedSwaggerSchema.usageSchema),
2679
3065
  config: this.config,
2680
3066
  modelTypes: this.collectModelTypes(),
2681
3067
  hasSecurityRoutes: this.schemaRoutes.hasSecurityRoutes,
@@ -2689,14 +3075,14 @@ var CodeGenProcess = class {
2689
3075
  customTranslator: this.config.customTranslator ? new this.config.customTranslator() : null,
2690
3076
  utils: this.getRenderTemplateData().utils
2691
3077
  };
2692
- const configuration = this.config.hooks.onPrepareConfig(rawConfiguration) || rawConfiguration;
3078
+ const configuration = this.config.hooks.onPrepareConfig?.(rawConfiguration) || rawConfiguration;
2693
3079
  if (this.fileSystem.pathIsExist(this.config.output)) {
2694
3080
  if (this.config.cleanOutput) {
2695
- consola.debug("cleaning dir", this.config.output);
3081
+ consola$1.debug("cleaning dir", this.config.output);
2696
3082
  this.fileSystem.cleanDir(this.config.output);
2697
3083
  }
2698
3084
  } else {
2699
- consola.debug(`path ${this.config.output} is not exist. creating dir by this path`);
3085
+ consola$1.debug(`path ${this.config.output} is not exist. creating dir by this path`);
2700
3086
  this.fileSystem.createDir(this.config.output);
2701
3087
  }
2702
3088
  const files = await this.generateOutputFiles({ configuration });
@@ -2707,7 +3093,7 @@ var CodeGenProcess = class {
2707
3093
  content: file.fileContent,
2708
3094
  withPrefix: true
2709
3095
  });
2710
- consola.success("api file", `"${file.fileName}${file.fileExtension}"`, `created in ${this.config.output}`);
3096
+ consola$1.success("api file", `"${file.fileName}${file.fileExtension}"`, `created in ${this.config.output}`);
2711
3097
  }
2712
3098
  return {
2713
3099
  files,
@@ -2852,7 +3238,7 @@ var CodeGenProcess = class {
2852
3238
  const fileName = this.fileSystem.cropExtension(fileNameFull);
2853
3239
  const fileExtension = typescript.Extension.Ts;
2854
3240
  if (configuration.translateToJavaScript) {
2855
- consola.debug("using js translator for", fileName);
3241
+ consola$1.debug("using js translator for", fileName);
2856
3242
  return await this.javascriptTranslator.translate({
2857
3243
  fileName,
2858
3244
  fileExtension,
@@ -2860,14 +3246,14 @@ var CodeGenProcess = class {
2860
3246
  });
2861
3247
  }
2862
3248
  if (configuration.customTranslator) {
2863
- consola.debug("using custom translator for", fileName);
3249
+ consola$1.debug("using custom translator for", fileName);
2864
3250
  return await configuration.customTranslator.translate({
2865
3251
  fileName,
2866
3252
  fileExtension,
2867
3253
  fileContent: content
2868
3254
  });
2869
3255
  }
2870
- consola.debug("generating output for", `${fileName}${fileExtension}`);
3256
+ consola$1.debug("generating output for", `${fileName}${fileExtension}`);
2871
3257
  return [{
2872
3258
  fileName,
2873
3259
  fileExtension,
@@ -2968,10 +3354,10 @@ var TemplatesGenProcess = class {
2968
3354
  this.fileSystem = new FileSystem();
2969
3355
  }
2970
3356
  async start() {
2971
- consola.info("start generating source templates \".ejs\" for code generator");
3357
+ consola$1.info("start generating source templates \".ejs\" for code generator");
2972
3358
  const templates = this.getTemplates();
2973
3359
  if (this.config.output) {
2974
- consola.info("preparing output directory for source templates");
3360
+ consola$1.info("preparing output directory for source templates");
2975
3361
  const outputPath = path.resolve(process.cwd(), this.config.output);
2976
3362
  if (this.fileSystem.pathIsExist(outputPath)) {
2977
3363
  if (this.config.cleanOutput) this.fileSystem.cleanDir(outputPath);
@@ -3003,7 +3389,7 @@ var TemplatesGenProcess = class {
3003
3389
  });
3004
3390
  }
3005
3391
  }
3006
- consola.success(`source templates has been successfully created in "${outputPath}"`);
3392
+ consola$1.success(`source templates has been successfully created in "${outputPath}"`);
3007
3393
  }
3008
3394
  return {
3009
3395
  files: templates,
@@ -3050,11 +3436,11 @@ var TemplatesGenProcess = class {
3050
3436
  //#endregion
3051
3437
  //#region src/commands/generate-templates/index.ts
3052
3438
  async function generateTemplates(config) {
3053
- if (config.debug) consola.level = Number.MAX_SAFE_INTEGER;
3054
- if (config.silent) consola.level = 0;
3439
+ if (config.debug) consola$1.level = Number.MAX_SAFE_INTEGER;
3440
+ if (config.silent) consola$1.level = 0;
3055
3441
  return await new TemplatesGenProcess(config).start();
3056
3442
  }
3057
3443
 
3058
3444
  //#endregion
3059
3445
  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
3446
+ //# sourceMappingURL=generate-templates-BaT2BiRR.mjs.map