swagger-typescript-api 13.2.17 → 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.17";
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
@@ -246,6 +248,17 @@ const SCHEMA_TYPES$1 = {
246
248
  COMPLEX_UNKNOWN: "__unknown"
247
249
  };
248
250
 
251
+ //#endregion
252
+ //#region src/util/object-assign.ts
253
+ const objectAssign = (target, updater) => {
254
+ if (!updater) return;
255
+ const update = typeof updater === "function" ? updater(target) : updater;
256
+ if (!update) return;
257
+ const undefinedKeys = Object.entries(update).filter(([, value]) => value === void 0).map(([key]) => key);
258
+ merge(target, update);
259
+ for (const key of undefinedKeys) target[key] = void 0;
260
+ };
261
+
249
262
  //#endregion
250
263
  //#region src/configuration.ts
251
264
  const TsKeyword = {
@@ -327,6 +340,7 @@ var CodeGenConfig = class {
327
340
  onFormatTypeName: (_typeName, _rawTypeName, _schemaType) => {},
328
341
  onFormatRouteName: (_routeInfo, _templateRouteName) => {}
329
342
  };
343
+ resolvedSwaggerSchema;
330
344
  defaultResponseType;
331
345
  singleHttpClient = false;
332
346
  httpClientType = HTTP_CLIENT.FETCH;
@@ -556,8 +570,8 @@ var CodeGenConfig = class {
556
570
  ];
557
571
  templateExtensions = [".eta", ".ejs"];
558
572
  constructor({ codeGenConstructs, primitiveTypeConstructs, constants, templateInfos, hooks, ...otherConfig }) {
559
- Object.assign(this.Ts, codeGenConstructs);
560
- Object.assign(this.primitiveTypes, primitiveTypeConstructs);
573
+ objectAssign(this.Ts, codeGenConstructs);
574
+ objectAssign(this.primitiveTypes, primitiveTypeConstructs);
561
575
  this.defaultResponseType = this.Ts.Keyword.Void;
562
576
  this.update({
563
577
  ...otherConfig,
@@ -577,16 +591,21 @@ var CodeGenConfig = class {
577
591
  this.componentTypeNameResolver = new ComponentTypeNameResolver(this, []);
578
592
  }
579
593
  update = (update) => {
580
- Object.assign(this, update);
594
+ objectAssign(this, update);
581
595
  if (this.enumNamesAsValues) this.extractEnums = true;
582
596
  };
583
597
  };
584
598
 
599
+ //#endregion
600
+ //#region src/util/pascal-case.ts
601
+ function pascalCase(value) {
602
+ return upperFirst(camelCase(value));
603
+ }
604
+
585
605
  //#endregion
586
606
  //#region src/schema-components-map.ts
587
607
  var SchemaComponentsMap = class {
588
608
  _data = [];
589
- config;
590
609
  constructor(config) {
591
610
  this.config = config;
592
611
  }
@@ -599,18 +618,27 @@ var SchemaComponentsMap = class {
599
618
  parseRef = (ref) => {
600
619
  return ref.split("/");
601
620
  };
602
- createComponent($ref, rawTypeData) {
621
+ createComponentDraft($ref, rawTypeData) {
622
+ if (typeGuard.isObject(rawTypeData) && rawTypeData.typeName && rawTypeData.rawTypeData && rawTypeData.$ref) return rawTypeData;
603
623
  const parsed = this.parseRef($ref);
604
- 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 {
605
629
  $ref,
606
- typeName: parsed[parsed.length - 1],
630
+ typeName,
607
631
  rawTypeData,
608
- componentName: parsed[parsed.length - 2],
632
+ componentName: rawComponentName === "definitions" ? "schemas" : rawComponentName,
609
633
  typeData: null
610
634
  };
635
+ }
636
+ createComponent($ref, rawTypeData, addAtStart) {
637
+ const componentSchema = this.createComponentDraft($ref, rawTypeData);
611
638
  const usageComponent = this.config.hooks.onCreateComponent(componentSchema) || componentSchema;
612
639
  const refIndex = this._data.findIndex((c) => c.$ref === $ref);
613
- if (refIndex === -1) this._data.push(usageComponent);
640
+ if (refIndex === -1) if (addAtStart) this._data.unshift(usageComponent);
641
+ else this._data.push(usageComponent);
614
642
  else this._data[refIndex] = usageComponent;
615
643
  return usageComponent;
616
644
  }
@@ -621,7 +649,19 @@ var SchemaComponentsMap = class {
621
649
  return this._data.filter((it) => componentNames.some((componentName) => it.$ref.startsWith(`#/components/${componentName}`)));
622
650
  }
623
651
  get = ($ref) => {
624
- 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;
625
665
  };
626
666
  enumsFirst() {
627
667
  this._data.sort((a, b) => {
@@ -657,10 +697,14 @@ var SchemaFormatters = class {
657
697
  $content: parsedSchema.content,
658
698
  content: this.config.Ts.UnionType(parsedSchema.content.map(({ value }) => value))
659
699
  };
700
+ const escapedContent = parsedSchema.content.map((item) => ({
701
+ ...item,
702
+ description: item.description ? this.escapeJSDocContent(item.description) : ""
703
+ }));
660
704
  return {
661
705
  ...parsedSchema,
662
706
  $content: parsedSchema.content,
663
- content: this.config.Ts.EnumFieldsWrapper(parsedSchema.content)
707
+ content: this.config.Ts.EnumFieldsWrapper(escapedContent)
664
708
  };
665
709
  },
666
710
  [SCHEMA_TYPES$1.OBJECT]: (parsedSchema) => {
@@ -702,11 +746,16 @@ var SchemaFormatters = class {
702
746
  const schemaType = get(parsedSchema, ["schemaType"]) || get(parsedSchema, ["$parsed", "schemaType"]);
703
747
  return get(this, [formatType, schemaType])?.(parsedSchema) || parsedSchema;
704
748
  };
749
+ escapeJSDocContent = (content) => {
750
+ if (content === void 0) return "";
751
+ return (typeof content === "string" ? content : String(content)).replace(/\*\//g, "*\\/");
752
+ };
705
753
  formatDescription = (description, inline) => {
706
754
  if (!description) return "";
707
- if (!description.includes("\n")) return description;
708
- if (inline) return compact(description.split(/\n/g).map((part) => part.trim())).join(" ");
709
- return description.replace(/\n$/g, "");
755
+ const escapedDescription = this.escapeJSDocContent(description);
756
+ if (!escapedDescription.includes("\n")) return escapedDescription;
757
+ if (inline) return compact(escapedDescription.split(/\n/g).map((part) => part.trim())).join(" ");
758
+ return escapedDescription.replace(/\n$/g, "");
710
759
  };
711
760
  formatObjectContent = (content) => {
712
761
  const fields = [];
@@ -995,7 +1044,7 @@ var EnumKeyResolver = class extends NameResolver {
995
1044
  constructor(config, reservedNames) {
996
1045
  super(config, reservedNames, (variants) => {
997
1046
  const generatedVariant = variants[0] && `${variants[0]}${this.counter++}` || `${this.config.enumKeyResolverName}${this.counter++}`;
998
- consola.debug("generated fallback type name for enum key - ", generatedVariant);
1047
+ consola$1.debug("generated fallback type name for enum key - ", generatedVariant);
999
1048
  return generatedVariant;
1000
1049
  });
1001
1050
  }
@@ -1270,17 +1319,15 @@ var SchemaParser = class {
1270
1319
  schemaFormatters;
1271
1320
  schemaUtils;
1272
1321
  templatesWorker;
1273
- schemaWalker;
1274
1322
  typeName;
1275
1323
  schema;
1276
- schemaPath = [];
1324
+ schemaPath;
1277
1325
  constructor(schemaParserFabric, { typeName, schema, schemaPath } = {}) {
1278
1326
  this.schemaParserFabric = schemaParserFabric;
1279
1327
  this.config = schemaParserFabric.config;
1280
1328
  this.templatesWorker = schemaParserFabric.templatesWorker;
1281
1329
  this.schemaComponentsMap = schemaParserFabric.schemaComponentsMap;
1282
1330
  this.typeNameFormatter = schemaParserFabric.typeNameFormatter;
1283
- this.schemaWalker = schemaParserFabric.schemaWalker;
1284
1331
  this.schemaFormatters = schemaParserFabric.schemaFormatters;
1285
1332
  this.schemaUtils = schemaParserFabric.schemaUtils;
1286
1333
  this.typeName = typeName || null;
@@ -1330,7 +1377,7 @@ var SchemaParser = class {
1330
1377
  if (!this.typeName && this.schemaUtils.isRefSchema(this.schema)) this.typeName = this.schemaUtils.getSchemaType(this.schema);
1331
1378
  if (this.schema.items && !Array.isArray(this.schema.items) && !this.schema.type) this.schema.type = SCHEMA_TYPES$1.ARRAY;
1332
1379
  if (Array.isArray(this.schema.enum) && this.schema.enum.length === 1 && this.schema.enum[0] == null) {
1333
- consola.debug("invalid enum schema", this.schema);
1380
+ consola$1.debug("invalid enum schema", this.schema);
1334
1381
  this.schema = { type: this.config.Ts.Keyword.Null };
1335
1382
  }
1336
1383
  if ("content" in this.schema && typeof this.schema.content === "object") {
@@ -1375,24 +1422,13 @@ var SchemaParser = class {
1375
1422
  };
1376
1423
  };
1377
1424
 
1378
- //#endregion
1379
- //#region src/util/pascal-case.ts
1380
- function pascalCase(value) {
1381
- return upperFirst(camelCase(value));
1382
- }
1383
-
1384
1425
  //#endregion
1385
1426
  //#region src/schema-parser/schema-utils.ts
1386
1427
  var SchemaUtils = class {
1387
- config;
1388
- schemaComponentsMap;
1389
- typeNameFormatter;
1390
- schemaWalker;
1391
- constructor({ config, schemaComponentsMap, typeNameFormatter, schemaWalker }) {
1428
+ constructor(config, schemaComponentsMap, typeNameFormatter) {
1392
1429
  this.config = config;
1393
1430
  this.schemaComponentsMap = schemaComponentsMap;
1394
1431
  this.typeNameFormatter = typeNameFormatter;
1395
- this.schemaWalker = schemaWalker;
1396
1432
  }
1397
1433
  getRequiredProperties = (schema) => {
1398
1434
  return uniq(schema && Array.isArray(schema.required) && schema.required || []);
@@ -1538,14 +1574,12 @@ var SchemaParserFabric = class {
1538
1574
  schemaFormatters;
1539
1575
  templatesWorker;
1540
1576
  schemaUtils;
1541
- schemaWalker;
1542
- constructor(config, templatesWorker, schemaComponentsMap, typeNameFormatter, schemaWalker) {
1577
+ constructor(config, templatesWorker, schemaComponentsMap, typeNameFormatter) {
1543
1578
  this.config = config;
1544
1579
  this.schemaComponentsMap = schemaComponentsMap;
1545
1580
  this.typeNameFormatter = typeNameFormatter;
1546
1581
  this.templatesWorker = templatesWorker;
1547
- this.schemaWalker = schemaWalker;
1548
- this.schemaUtils = new SchemaUtils(this);
1582
+ this.schemaUtils = new SchemaUtils(this.config, this.schemaComponentsMap, this.typeNameFormatter);
1549
1583
  this.schemaFormatters = new SchemaFormatters(this);
1550
1584
  }
1551
1585
  createSchemaParser = ({ schema, typeName, schemaPath }) => {
@@ -1612,7 +1646,7 @@ var SpecificArgNameResolver = class extends NameResolver {
1612
1646
  constructor(config, reservedNames) {
1613
1647
  super(config, reservedNames, (variants) => {
1614
1648
  const generatedVariant = variants[0] && `${variants[0]}${this.counter++}` || `${this.config.specificArgNameResolverName}${this.counter++}`;
1615
- consola.debug("generated fallback type name for specific arg - ", generatedVariant);
1649
+ consola$1.debug("generated fallback type name for specific arg - ", generatedVariant);
1616
1650
  return generatedVariant;
1617
1651
  });
1618
1652
  }
@@ -1630,12 +1664,7 @@ const CONTENT_KIND = {
1630
1664
  TEXT: "TEXT"
1631
1665
  };
1632
1666
  var SchemaRoutes = class {
1633
- config;
1634
- schemaParserFabric;
1635
1667
  schemaUtils;
1636
- typeNameFormatter;
1637
- schemaComponentsMap;
1638
- templatesWorker;
1639
1668
  FORM_DATA_TYPES = [];
1640
1669
  routes = [];
1641
1670
  hasSecurityRoutes = false;
@@ -1644,10 +1673,10 @@ var SchemaRoutes = class {
1644
1673
  constructor(config, schemaParserFabric, schemaComponentsMap, templatesWorker, typeNameFormatter) {
1645
1674
  this.config = config;
1646
1675
  this.schemaParserFabric = schemaParserFabric;
1647
- this.schemaUtils = this.schemaParserFabric.schemaUtils;
1648
- this.typeNameFormatter = typeNameFormatter;
1649
1676
  this.schemaComponentsMap = schemaComponentsMap;
1650
1677
  this.templatesWorker = templatesWorker;
1678
+ this.typeNameFormatter = typeNameFormatter;
1679
+ this.schemaUtils = this.schemaParserFabric.schemaUtils;
1651
1680
  this.FORM_DATA_TYPES = uniq([this.schemaUtils.getSchemaType({
1652
1681
  type: "string",
1653
1682
  format: "file"
@@ -1656,11 +1685,16 @@ var SchemaRoutes = class {
1656
1685
  format: "binary"
1657
1686
  })]);
1658
1687
  }
1659
- createRequestsMap = (routesByMethod) => {
1688
+ createRequestsMap = (resolvedSwaggerSchema, routesByMethod) => {
1660
1689
  const parameters = get(routesByMethod, "parameters");
1661
1690
  const result = {};
1662
1691
  for (const [method, requestInfo] of Object.entries(routesByMethod)) {
1663
- 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
+ }
1664
1698
  result[method] = {
1665
1699
  ...requestInfo,
1666
1700
  parameters: compact([...parameters || [], ...requestInfo.parameters || []])
@@ -1675,7 +1709,7 @@ var SchemaRoutes = class {
1675
1709
  for (const match of pathParamMatches || []) {
1676
1710
  const paramName = match.replace(/\{|\}|:/g, "");
1677
1711
  if (!paramName) continue;
1678
- if (paramName.includes("-")) consola.warn("wrong path param name", paramName);
1712
+ if (paramName.includes("-")) consola$1.warn("wrong path param name", paramName);
1679
1713
  pathParams.push({
1680
1714
  $match: match,
1681
1715
  name: camelCase(paramName),
@@ -1696,7 +1730,7 @@ var SchemaRoutes = class {
1696
1730
  for (const match of queryParamMatches) fixedRoute = fixedRoute.replace(match, "");
1697
1731
  const paramNames = uniq(queryParamMatches.join(",").replace(/(\{\?)|(\})|\s/g, "").split(","));
1698
1732
  for (const paramName of paramNames) {
1699
- 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);
1700
1734
  queryParams.push({
1701
1735
  $match: paramName,
1702
1736
  name: typeof paramName === "string" ? camelCase(paramName) : camelCase(String(paramName)),
@@ -1729,7 +1763,7 @@ var SchemaRoutes = class {
1729
1763
  for (const parameter of parameters || []) {
1730
1764
  const refTypeInfo = this.schemaParserFabric.schemaUtils.getSchemaRefType(parameter);
1731
1765
  let routeParam = null;
1732
- if (refTypeInfo?.rawTypeData.in && refTypeInfo.rawTypeData) {
1766
+ if (!!refTypeInfo?.rawTypeData && typeof refTypeInfo === "object" && refTypeInfo?.rawTypeData.in) {
1733
1767
  if (!routeParams[refTypeInfo.rawTypeData.in]) routeParams[refTypeInfo.rawTypeData.in] = [];
1734
1768
  routeParam = {
1735
1769
  ...refTypeInfo.rawTypeData,
@@ -1799,10 +1833,11 @@ var SchemaRoutes = class {
1799
1833
  }
1800
1834
  return defaultType || this.config.Ts.Keyword.Any;
1801
1835
  };
1802
- getRequestInfoTypes = ({ requestInfos, parsedSchemas, operationId, defaultType }) => {
1836
+ getRequestInfoTypes = ({ requestInfos, parsedSchemas, operationId, defaultType, resolvedSwaggerSchema }) => {
1803
1837
  const result = [];
1804
1838
  for (const [status, requestInfo] of Object.entries(requestInfos || {})) {
1805
1839
  const contentTypes = this.getContentTypes([requestInfo], operationId);
1840
+ const links = this.getRouteLinksFromResponse(resolvedSwaggerSchema, requestInfo, status);
1806
1841
  result.push({
1807
1842
  ...requestInfo || {},
1808
1843
  contentTypes,
@@ -1814,21 +1849,48 @@ var SchemaRoutes = class {
1814
1849
  defaultType
1815
1850
  })),
1816
1851
  description: this.schemaParserFabric.schemaFormatters.formatDescription(requestInfo.description || "", true),
1852
+ links,
1817
1853
  status: Number.isNaN(+status) ? status : +status,
1818
1854
  isSuccess: this.isSuccessStatus(status)
1819
1855
  });
1820
1856
  }
1821
1857
  return result;
1822
1858
  };
1823
- 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) => {
1824
1884
  const { produces, operationId, responses } = routeInfo;
1825
1885
  const contentTypes = this.getContentTypes(responses, [...produces || [], routeInfo["x-accepts"]]);
1826
1886
  const responseInfos = this.getRequestInfoTypes({
1827
1887
  requestInfos: responses,
1828
1888
  parsedSchemas,
1829
1889
  operationId,
1830
- defaultType: this.config.defaultResponseType
1890
+ defaultType: this.config.defaultResponseType,
1891
+ resolvedSwaggerSchema
1831
1892
  });
1893
+ const links = responseInfos.flatMap((responseInfo) => responseInfo.links || []);
1832
1894
  const successResponse = responseInfos.find((response) => response.isSuccess);
1833
1895
  const errorResponses = responseInfos.filter((response) => !response.isSuccess && response.type !== this.config.Ts.Keyword.Any);
1834
1896
  const handleResponseHeaders = (src) => {
@@ -1841,6 +1903,7 @@ var SchemaRoutes = class {
1841
1903
  return {
1842
1904
  contentTypes,
1843
1905
  responses: responseInfos,
1906
+ links,
1844
1907
  success: {
1845
1908
  schema: successResponse,
1846
1909
  type: successResponse?.type || this.config.Ts.Keyword.Any
@@ -2011,11 +2074,11 @@ var SchemaRoutes = class {
2011
2074
  const { routeNameDuplicatesMap, templatesToRender } = this.config;
2012
2075
  const routeNameTemplate = templatesToRender.routeName;
2013
2076
  const routeNameFromTemplate = this.templatesWorker.renderTemplate(routeNameTemplate, { routeInfo: rawRouteInfo });
2014
- const routeName = this.config.hooks.onFormatRouteName(rawRouteInfo, routeNameFromTemplate) || routeNameFromTemplate;
2077
+ const routeName = this.config.hooks.onFormatRouteName?.(rawRouteInfo, routeNameFromTemplate) || routeNameFromTemplate;
2015
2078
  const duplicateIdentifier = `${moduleName}|${routeName}`;
2016
2079
  if (routeNameDuplicatesMap.has(duplicateIdentifier)) {
2017
2080
  routeNameDuplicatesMap.set(duplicateIdentifier, routeNameDuplicatesMap.get(duplicateIdentifier) + 1);
2018
- 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.`);
2019
2082
  } else routeNameDuplicatesMap.set(duplicateIdentifier, 1);
2020
2083
  const duplicates = routeNameDuplicatesMap.get(duplicateIdentifier);
2021
2084
  const routeNameInfo = {
@@ -2023,10 +2086,10 @@ var SchemaRoutes = class {
2023
2086
  original: routeName,
2024
2087
  duplicate: duplicates > 1
2025
2088
  };
2026
- return this.config.hooks.onCreateRouteName(routeNameInfo, rawRouteInfo) || routeNameInfo;
2089
+ return this.config.hooks.onCreateRouteName?.(routeNameInfo, rawRouteInfo) || routeNameInfo;
2027
2090
  };
2028
- parseRouteInfo = (rawRouteName, routeInfo, method, usageSchema, parsedSchemas) => {
2029
- const { security: globalSecurity } = usageSchema;
2091
+ parseRouteInfo = (rawRouteName, routeInfo, method, resolvedSwaggerSchema, parsedSchemas) => {
2092
+ const { security: globalSecurity } = resolvedSwaggerSchema.usageSchema;
2030
2093
  const { moduleNameIndex, moduleNameFirstTag, extractRequestParams } = this.config;
2031
2094
  const { operationId, requestBody, security, parameters, summary, description, tags, responses, requestBodyName, produces, consumes, ...otherInfo } = routeInfo;
2032
2095
  const { route, pathParams: pathParamsFromRouteName, queryParams: queryParamsFromRouteName } = this.parseRouteName(rawRouteName);
@@ -2043,7 +2106,7 @@ var SchemaRoutes = class {
2043
2106
  description: pathArgSchema.description
2044
2107
  }));
2045
2108
  const pathArgsNames = pathArgs.map((arg) => arg.name);
2046
- const responseBodyInfo = this.getResponseBodyInfo(routeInfo, parsedSchemas);
2109
+ const responseBodyInfo = this.getResponseBodyInfo(routeInfo, parsedSchemas, resolvedSwaggerSchema);
2047
2110
  const rawRouteInfo = {
2048
2111
  ...otherInfo,
2049
2112
  pathArgs,
@@ -2052,6 +2115,7 @@ var SchemaRoutes = class {
2052
2115
  route: rawRouteName,
2053
2116
  moduleName,
2054
2117
  responsesTypes: responseBodyInfo.responses,
2118
+ links: responseBodyInfo.links,
2055
2119
  description,
2056
2120
  tags,
2057
2121
  summary,
@@ -2147,13 +2211,13 @@ var SchemaRoutes = class {
2147
2211
  raw: rawRouteInfo
2148
2212
  };
2149
2213
  };
2150
- attachSchema = ({ usageSchema, parsedSchemas }) => {
2214
+ attachSchema = (resolvedSwaggerSchema, parsedSchemas) => {
2151
2215
  this.config.routeNameDuplicatesMap.clear();
2152
- const pathsEntries = Object.entries(usageSchema.paths || {});
2216
+ const pathsEntries = Object.entries(resolvedSwaggerSchema.usageSchema.paths || {});
2153
2217
  for (const [rawRouteName, routeInfoByMethodsMap] of pathsEntries) {
2154
- const routeInfosMap = this.createRequestsMap(routeInfoByMethodsMap);
2218
+ const routeInfosMap = this.createRequestsMap(resolvedSwaggerSchema, routeInfoByMethodsMap);
2155
2219
  for (const [method, routeInfo] of Object.entries(routeInfosMap)) {
2156
- const parsedRouteInfo = this.parseRouteInfo(rawRouteName, routeInfo, method, usageSchema, parsedSchemas);
2220
+ const parsedRouteInfo = this.parseRouteInfo(rawRouteName, routeInfo, method, resolvedSwaggerSchema, parsedSchemas);
2157
2221
  const processedRouteInfo = this.config.hooks.onCreateRoute(parsedRouteInfo);
2158
2222
  if (processedRouteInfo !== false) {
2159
2223
  const route = processedRouteInfo || parsedRouteInfo;
@@ -2207,30 +2271,353 @@ var SchemaRoutes = class {
2207
2271
  };
2208
2272
 
2209
2273
  //#endregion
2210
- //#region src/schema-walker.ts
2211
- var SchemaWalker = class {
2212
- config;
2213
- swaggerSchemaResolver;
2214
- schemas = /* @__PURE__ */ new Map();
2215
- caches = /* @__PURE__ */ new Map();
2216
- 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) {
2217
2411
  this.config = config;
2218
- 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;
2219
2620
  }
2220
- addSchema = (name, schema) => {
2221
- this.schemas.set(name, structuredClone(schema));
2222
- };
2223
- _isLocalRef = (ref) => {
2224
- return ref.startsWith("#");
2225
- };
2226
- _isRemoteRef = (ref) => {
2227
- return ref.startsWith("http://") || ref.startsWith("https://");
2228
- };
2229
- _getRefDataFromSchema = (schema, ref) => {
2230
- const refData = get(schema, ref.replace("#", "").split("/"));
2231
- if (refData) this.caches.set(ref, refData);
2232
- return refData;
2233
- };
2234
2621
  };
2235
2622
 
2236
2623
  //#endregion
@@ -2248,7 +2635,7 @@ var Request = class {
2248
2635
  return await (await fetch(url, requestOptions)).text();
2249
2636
  } catch (error) {
2250
2637
  const message = `error while fetching data from URL "${url}"`;
2251
- consola.error(message, error);
2638
+ consola$1.error(message, error);
2252
2639
  return message;
2253
2640
  }
2254
2641
  }
@@ -2267,10 +2654,15 @@ var SwaggerSchemaResolver = class {
2267
2654
  }
2268
2655
  async create() {
2269
2656
  const { spec, patch, input, url, authorizationToken } = this.config;
2270
- if (spec) return await this.convertSwaggerObject(spec, { patch });
2271
- const swaggerSchemaFile = await this.fetchSwaggerSchemaFile(input, url, authorizationToken);
2272
- const swaggerSchemaObject = this.processSwaggerSchemaFile(swaggerSchemaFile);
2273
- 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);
2274
2666
  }
2275
2667
  convertSwaggerObject(swaggerSchema, converterOptions) {
2276
2668
  return new Promise((resolve) => {
@@ -2303,12 +2695,12 @@ var SwaggerSchemaResolver = class {
2303
2695
  });
2304
2696
  }
2305
2697
  getSwaggerSchemaByPath = (pathToSwagger) => {
2306
- consola.info(`try to get swagger by path "${pathToSwagger}"`);
2698
+ consola$1.info(`try to get swagger by path "${pathToSwagger}"`);
2307
2699
  return this.fileSystem.getFileContent(pathToSwagger);
2308
2700
  };
2309
2701
  async fetchSwaggerSchemaFile(pathToSwagger, urlToSwagger, authToken) {
2310
2702
  if (this.fileSystem.pathIsExist(pathToSwagger)) return this.getSwaggerSchemaByPath(pathToSwagger);
2311
- consola.info(`try to get swagger by URL "${urlToSwagger}"`);
2703
+ consola$1.info(`try to get swagger by URL "${urlToSwagger}"`);
2312
2704
  return await this.request.download({
2313
2705
  url: urlToSwagger,
2314
2706
  authToken
@@ -2322,7 +2714,26 @@ var SwaggerSchemaResolver = class {
2322
2714
  return YAML.parse(file);
2323
2715
  }
2324
2716
  }
2325
- 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);
2326
2737
  const usagePaths = get(usageSchema, "paths") || {};
2327
2738
  const originalPaths = get(originalSchema, "paths") || {};
2328
2739
  for (const [route, usagePathObject] of Object.entries(usagePaths)) {
@@ -2331,9 +2742,10 @@ var SwaggerSchemaResolver = class {
2331
2742
  const originalRouteInfo = get(originalPathObject, methodName) || {};
2332
2743
  const usageRouteParams = get(usageRouteInfo, "parameters") || [];
2333
2744
  const originalRouteParams = get(originalRouteInfo, "parameters") || [];
2745
+ const usageAsOpenapiv2 = usageRouteInfo;
2334
2746
  if (typeof usageRouteInfo === "object") {
2335
- usageRouteInfo.consumes = uniq(compact([...usageRouteInfo.consumes || [], ...originalRouteInfo.consumes || []]));
2336
- 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 || []]));
2337
2749
  }
2338
2750
  for (const originalRouteParam of originalRouteParams) if (!usageRouteParams.find((param) => originalRouteParam.in === param.in && originalRouteParam.name === param.name)) usageRouteParams.push(originalRouteParam);
2339
2751
  }
@@ -2353,8 +2765,8 @@ var TemplatesWorker = class {
2353
2765
  this.config = config;
2354
2766
  this.fileSystem = fileSystem;
2355
2767
  this.getRenderTemplateData = getRenderTemplateData;
2356
- if (this.config.debug) consola.level = Number.MAX_SAFE_INTEGER;
2357
- 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;
2358
2770
  }
2359
2771
  getTemplatePaths = (config) => {
2360
2772
  const __dirname = path$1.dirname(url$1.fileURLToPath(import.meta.url));
@@ -2385,19 +2797,19 @@ var TemplatesWorker = class {
2385
2797
  const customFullPath = templatePaths.custom && this.getTemplateFullPath(templatePaths.custom, fileName);
2386
2798
  let fileContent = customFullPath && this.fileSystem.getFileContent(customFullPath);
2387
2799
  if (fileContent) {
2388
- consola.info(`"${name.toLowerCase()}" template found in "${templatePaths.custom}"`);
2800
+ consola$1.info(`"${name.toLowerCase()}" template found in "${templatePaths.custom}"`);
2389
2801
  return fileContent;
2390
2802
  }
2391
2803
  const baseFullPath = this.getTemplateFullPath(templatePaths.base, fileName);
2392
2804
  if (baseFullPath) fileContent = this.fileSystem.getFileContent(baseFullPath);
2393
- else if (templatePaths.custom) consola.warn("Code generator will use the default template:", `"${name.toLowerCase()}"`, "template not found in", `"${templatePaths.custom}"`);
2394
- 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()}"`);
2395
2807
  const originalFullPath = this.getTemplateFullPath(templatePaths.original, fileName);
2396
2808
  if (originalFullPath) fileContent = this.fileSystem.getFileContent(originalFullPath);
2397
2809
  return fileContent;
2398
2810
  };
2399
2811
  getTemplates = ({ templatePaths }) => {
2400
- 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}"`);
2401
2813
  return this.config.templateInfos.reduce((acc, { name, fileName }) => ({
2402
2814
  ...acc,
2403
2815
  [name]: this.getTemplate(name, fileName)
@@ -2498,7 +2910,7 @@ var TypeNameFormatter = class {
2498
2910
  const typeSuffix = schemaType === "enum-key" ? this.config.enumKeySuffix : this.config.typeSuffix;
2499
2911
  const hashKey = `${typePrefix}_${name}_${typeSuffix}`;
2500
2912
  if (typeof name !== "string") {
2501
- consola.warn("wrong model name", name);
2913
+ consola$1.warn("wrong model name", name);
2502
2914
  return name;
2503
2915
  }
2504
2916
  if (/^(?!\d)([A-Z0-9_]{1,})$/g.test(name)) return compact([
@@ -2508,7 +2920,7 @@ var TypeNameFormatter = class {
2508
2920
  ]).join("_");
2509
2921
  if (this.formattedModelNamesMap.has(hashKey)) return this.formattedModelNamesMap.get(hashKey);
2510
2922
  const formattedName = startCase(`${typePrefix}_${this.fixModelName(name, { type: schemaType })}_${typeSuffix}`).replace(/\s/g, "");
2511
- const formattedResultName = this.config.hooks.onFormatTypeName(formattedName, name, schemaType) || formattedName;
2923
+ const formattedResultName = this.config.hooks.onFormatTypeName?.(formattedName, name, schemaType) || formattedName;
2512
2924
  this.formattedModelNamesMap.set(hashKey, formattedResultName);
2513
2925
  return formattedResultName;
2514
2926
  };
@@ -2550,14 +2962,14 @@ var FileSystem = class {
2550
2962
  if (typeof fs.rmSync === "function") fs.rmSync(path, { recursive: true });
2551
2963
  else fs.rmdirSync(path, { recursive: true });
2552
2964
  } catch (e) {
2553
- consola.debug("failed to remove dir", e);
2965
+ consola$1.debug("failed to remove dir", e);
2554
2966
  }
2555
2967
  };
2556
2968
  createDir = (path) => {
2557
2969
  try {
2558
2970
  fs.mkdirSync(path, { recursive: true });
2559
2971
  } catch (e) {
2560
- consola.debug("failed to create dir", e);
2972
+ consola$1.debug("failed to create dir", e);
2561
2973
  }
2562
2974
  };
2563
2975
  cleanDir = (path) => {
@@ -2607,38 +3019,35 @@ var CodeGenProcess = class {
2607
3019
  fileSystem;
2608
3020
  codeFormatter;
2609
3021
  templatesWorker;
2610
- schemaWalker;
2611
3022
  javascriptTranslator;
3023
+ swaggerRefs;
2612
3024
  constructor(config) {
2613
3025
  this.config = new CodeGenConfig(config);
2614
3026
  this.fileSystem = new FileSystem();
2615
3027
  this.swaggerSchemaResolver = new SwaggerSchemaResolver(this.config, this.fileSystem);
2616
- this.schemaWalker = new SchemaWalker(this.config, this.swaggerSchemaResolver);
2617
3028
  this.schemaComponentsMap = new SchemaComponentsMap(this.config);
2618
3029
  this.typeNameFormatter = new TypeNameFormatter(this.config);
2619
3030
  this.templatesWorker = new TemplatesWorker(this.config, this.fileSystem, this.getRenderTemplateData);
2620
3031
  this.codeFormatter = new CodeFormatter(this.config);
2621
- 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);
2622
3033
  this.schemaRoutes = new SchemaRoutes(this.config, this.schemaParserFabric, this.schemaComponentsMap, this.templatesWorker, this.typeNameFormatter);
2623
3034
  this.javascriptTranslator = new JavascriptTranslator(this.config, this.codeFormatter);
2624
3035
  }
2625
3036
  async start() {
2626
3037
  this.config.update({ templatePaths: this.templatesWorker.getTemplatePaths(this.config) });
2627
3038
  this.config.update({ templatesToRender: this.templatesWorker.getTemplates(this.config) });
2628
- const swagger = await this.swaggerSchemaResolver.create();
2629
- this.swaggerSchemaResolver.fixSwaggerSchema(swagger);
3039
+ const resolvedSwaggerSchema = await this.swaggerSchemaResolver.create();
2630
3040
  this.config.update({
2631
- swaggerSchema: swagger.usageSchema,
2632
- originalSchema: swagger.originalSchema
3041
+ resolvedSwaggerSchema,
3042
+ swaggerSchema: resolvedSwaggerSchema.usageSchema,
3043
+ originalSchema: resolvedSwaggerSchema.originalSchema
2633
3044
  });
2634
- this.schemaWalker.addSchema("$usage", swagger.usageSchema);
2635
- this.schemaWalker.addSchema("$original", swagger.originalSchema);
2636
- consola.info("start generating your typescript api");
2637
- this.config.update(this.config.hooks.onInit(this.config, this) || this.config);
2638
- if (this.config.swaggerSchema) swagger.usageSchema = this.config.swaggerSchema;
2639
- 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;
2640
3049
  this.schemaComponentsMap.clear();
2641
- 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([
2642
3051
  "components",
2643
3052
  componentName,
2644
3053
  typeName
@@ -2650,12 +3059,9 @@ var CodeGenProcess = class {
2650
3059
  schemaComponent.typeData = parsed;
2651
3060
  return parsed;
2652
3061
  });
2653
- this.schemaRoutes.attachSchema({
2654
- usageSchema: swagger.usageSchema,
2655
- parsedSchemas
2656
- });
3062
+ this.schemaRoutes.attachSchema(resolvedSwaggerSchema, parsedSchemas);
2657
3063
  const rawConfiguration = {
2658
- apiConfig: this.createApiConfig(swagger.usageSchema),
3064
+ apiConfig: this.createApiConfig(resolvedSwaggerSchema.usageSchema),
2659
3065
  config: this.config,
2660
3066
  modelTypes: this.collectModelTypes(),
2661
3067
  hasSecurityRoutes: this.schemaRoutes.hasSecurityRoutes,
@@ -2669,14 +3075,14 @@ var CodeGenProcess = class {
2669
3075
  customTranslator: this.config.customTranslator ? new this.config.customTranslator() : null,
2670
3076
  utils: this.getRenderTemplateData().utils
2671
3077
  };
2672
- const configuration = this.config.hooks.onPrepareConfig(rawConfiguration) || rawConfiguration;
3078
+ const configuration = this.config.hooks.onPrepareConfig?.(rawConfiguration) || rawConfiguration;
2673
3079
  if (this.fileSystem.pathIsExist(this.config.output)) {
2674
3080
  if (this.config.cleanOutput) {
2675
- consola.debug("cleaning dir", this.config.output);
3081
+ consola$1.debug("cleaning dir", this.config.output);
2676
3082
  this.fileSystem.cleanDir(this.config.output);
2677
3083
  }
2678
3084
  } else {
2679
- 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`);
2680
3086
  this.fileSystem.createDir(this.config.output);
2681
3087
  }
2682
3088
  const files = await this.generateOutputFiles({ configuration });
@@ -2687,7 +3093,7 @@ var CodeGenProcess = class {
2687
3093
  content: file.fileContent,
2688
3094
  withPrefix: true
2689
3095
  });
2690
- 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}`);
2691
3097
  }
2692
3098
  return {
2693
3099
  files,
@@ -2703,6 +3109,7 @@ var CodeGenProcess = class {
2703
3109
  utils: {
2704
3110
  Ts: this.config.Ts,
2705
3111
  formatDescription: this.schemaParserFabric.schemaFormatters.formatDescription,
3112
+ escapeJSDocContent: this.schemaParserFabric.schemaFormatters.escapeJSDocContent,
2706
3113
  internalCase: camelCase,
2707
3114
  classNameCase: pascalCase,
2708
3115
  pascalCase,
@@ -2831,7 +3238,7 @@ var CodeGenProcess = class {
2831
3238
  const fileName = this.fileSystem.cropExtension(fileNameFull);
2832
3239
  const fileExtension = typescript.Extension.Ts;
2833
3240
  if (configuration.translateToJavaScript) {
2834
- consola.debug("using js translator for", fileName);
3241
+ consola$1.debug("using js translator for", fileName);
2835
3242
  return await this.javascriptTranslator.translate({
2836
3243
  fileName,
2837
3244
  fileExtension,
@@ -2839,14 +3246,14 @@ var CodeGenProcess = class {
2839
3246
  });
2840
3247
  }
2841
3248
  if (configuration.customTranslator) {
2842
- consola.debug("using custom translator for", fileName);
3249
+ consola$1.debug("using custom translator for", fileName);
2843
3250
  return await configuration.customTranslator.translate({
2844
3251
  fileName,
2845
3252
  fileExtension,
2846
3253
  fileContent: content
2847
3254
  });
2848
3255
  }
2849
- consola.debug("generating output for", `${fileName}${fileExtension}`);
3256
+ consola$1.debug("generating output for", `${fileName}${fileExtension}`);
2850
3257
  return [{
2851
3258
  fileName,
2852
3259
  fileExtension,
@@ -2920,7 +3327,7 @@ var TemplatesGenConfig = class {
2920
3327
  this.update(config);
2921
3328
  }
2922
3329
  update = (update) => {
2923
- Object.assign(this, update);
3330
+ objectAssign(this, update);
2924
3331
  };
2925
3332
  };
2926
3333
 
@@ -2947,10 +3354,10 @@ var TemplatesGenProcess = class {
2947
3354
  this.fileSystem = new FileSystem();
2948
3355
  }
2949
3356
  async start() {
2950
- consola.info("start generating source templates \".ejs\" for code generator");
3357
+ consola$1.info("start generating source templates \".ejs\" for code generator");
2951
3358
  const templates = this.getTemplates();
2952
3359
  if (this.config.output) {
2953
- consola.info("preparing output directory for source templates");
3360
+ consola$1.info("preparing output directory for source templates");
2954
3361
  const outputPath = path.resolve(process.cwd(), this.config.output);
2955
3362
  if (this.fileSystem.pathIsExist(outputPath)) {
2956
3363
  if (this.config.cleanOutput) this.fileSystem.cleanDir(outputPath);
@@ -2982,7 +3389,7 @@ var TemplatesGenProcess = class {
2982
3389
  });
2983
3390
  }
2984
3391
  }
2985
- consola.success(`source templates has been successfully created in "${outputPath}"`);
3392
+ consola$1.success(`source templates has been successfully created in "${outputPath}"`);
2986
3393
  }
2987
3394
  return {
2988
3395
  files: templates,
@@ -3029,11 +3436,11 @@ var TemplatesGenProcess = class {
3029
3436
  //#endregion
3030
3437
  //#region src/commands/generate-templates/index.ts
3031
3438
  async function generateTemplates(config) {
3032
- if (config.debug) consola.level = Number.MAX_SAFE_INTEGER;
3033
- 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;
3034
3441
  return await new TemplatesGenProcess(config).start();
3035
3442
  }
3036
3443
 
3037
3444
  //#endregion
3038
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 };
3039
- //# sourceMappingURL=generate-templates-BO-5CKCm.mjs.map
3446
+ //# sourceMappingURL=generate-templates-BaT2BiRR.mjs.map