@ps-aux/api-client-gen 0.7.0-rc.3 → 0.7.0-rc.5

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,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var Path = require('path');
3
+ var Path$1 = require('path');
4
4
  var fs$2 = require('fs');
5
5
  var fs = require('fs/promises');
6
+ var Path = require('node:path');
6
7
  var swaggerTypescriptApi = require('swagger-typescript-api');
7
8
  var node_url = require('node:url');
8
9
  var promises = require('node:fs/promises');
9
- var Path$1 = require('node:path');
10
10
  var fs$1 = require('node:fs');
11
11
  var tsToZod = require('ts-to-zod');
12
12
 
@@ -722,6 +722,7 @@ const string$1 = (params) => {
722
722
  const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
723
723
  return new RegExp(`^${regex}$`);
724
724
  };
725
+ const number = /^-?\d+(?:\.\d+)?$/;
725
726
  const boolean$1 = /^(?:true|false)$/i;
726
727
  // regex for string with no uppercase letters
727
728
  const lowercase = /^[^A-Z]*$/;
@@ -1918,6 +1919,122 @@ function handleIntersectionResults(result, left, right) {
1918
1919
  result.value = merged.data;
1919
1920
  return result;
1920
1921
  }
1922
+ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
1923
+ $ZodType.init(inst, def);
1924
+ inst._zod.parse = (payload, ctx) => {
1925
+ const input = payload.value;
1926
+ if (!isPlainObject(input)) {
1927
+ payload.issues.push({
1928
+ expected: "record",
1929
+ code: "invalid_type",
1930
+ input,
1931
+ inst,
1932
+ });
1933
+ return payload;
1934
+ }
1935
+ const proms = [];
1936
+ const values = def.keyType._zod.values;
1937
+ if (values) {
1938
+ payload.value = {};
1939
+ const recordKeys = new Set();
1940
+ for (const key of values) {
1941
+ if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
1942
+ recordKeys.add(typeof key === "number" ? key.toString() : key);
1943
+ const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
1944
+ if (result instanceof Promise) {
1945
+ proms.push(result.then((result) => {
1946
+ if (result.issues.length) {
1947
+ payload.issues.push(...prefixIssues(key, result.issues));
1948
+ }
1949
+ payload.value[key] = result.value;
1950
+ }));
1951
+ }
1952
+ else {
1953
+ if (result.issues.length) {
1954
+ payload.issues.push(...prefixIssues(key, result.issues));
1955
+ }
1956
+ payload.value[key] = result.value;
1957
+ }
1958
+ }
1959
+ }
1960
+ let unrecognized;
1961
+ for (const key in input) {
1962
+ if (!recordKeys.has(key)) {
1963
+ unrecognized = unrecognized ?? [];
1964
+ unrecognized.push(key);
1965
+ }
1966
+ }
1967
+ if (unrecognized && unrecognized.length > 0) {
1968
+ payload.issues.push({
1969
+ code: "unrecognized_keys",
1970
+ input,
1971
+ inst,
1972
+ keys: unrecognized,
1973
+ });
1974
+ }
1975
+ }
1976
+ else {
1977
+ payload.value = {};
1978
+ for (const key of Reflect.ownKeys(input)) {
1979
+ if (key === "__proto__")
1980
+ continue;
1981
+ let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
1982
+ if (keyResult instanceof Promise) {
1983
+ throw new Error("Async schemas not supported in object keys currently");
1984
+ }
1985
+ // Numeric string fallback: if key is a numeric string and failed, retry with Number(key)
1986
+ // This handles z.number(), z.literal([1, 2, 3]), and unions containing numeric literals
1987
+ const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
1988
+ if (checkNumericKey) {
1989
+ const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
1990
+ if (retryResult instanceof Promise) {
1991
+ throw new Error("Async schemas not supported in object keys currently");
1992
+ }
1993
+ if (retryResult.issues.length === 0) {
1994
+ keyResult = retryResult;
1995
+ }
1996
+ }
1997
+ if (keyResult.issues.length) {
1998
+ if (def.mode === "loose") {
1999
+ // Pass through unchanged
2000
+ payload.value[key] = input[key];
2001
+ }
2002
+ else {
2003
+ // Default "strict" behavior: error on invalid key
2004
+ payload.issues.push({
2005
+ code: "invalid_key",
2006
+ origin: "record",
2007
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
2008
+ input: key,
2009
+ path: [key],
2010
+ inst,
2011
+ });
2012
+ }
2013
+ continue;
2014
+ }
2015
+ const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
2016
+ if (result instanceof Promise) {
2017
+ proms.push(result.then((result) => {
2018
+ if (result.issues.length) {
2019
+ payload.issues.push(...prefixIssues(key, result.issues));
2020
+ }
2021
+ payload.value[keyResult.value] = result.value;
2022
+ }));
2023
+ }
2024
+ else {
2025
+ if (result.issues.length) {
2026
+ payload.issues.push(...prefixIssues(key, result.issues));
2027
+ }
2028
+ payload.value[keyResult.value] = result.value;
2029
+ }
2030
+ }
2031
+ }
2032
+ if (proms.length) {
2033
+ return Promise.all(proms).then(() => payload);
2034
+ }
2035
+ return payload;
2036
+ };
2037
+ });
1921
2038
  const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => {
1922
2039
  $ZodType.init(inst, def);
1923
2040
  const values = getEnumValues(def.entries);
@@ -3314,6 +3431,49 @@ const intersectionProcessor = (schema, ctx, json, params) => {
3314
3431
  ];
3315
3432
  json.allOf = allOf;
3316
3433
  };
3434
+ const recordProcessor = (schema, ctx, _json, params) => {
3435
+ const json = _json;
3436
+ const def = schema._zod.def;
3437
+ json.type = "object";
3438
+ // For looseRecord with regex patterns, use patternProperties
3439
+ // This correctly represents "only validate keys matching the pattern" semantics
3440
+ // and composes well with allOf (intersections)
3441
+ const keyType = def.keyType;
3442
+ const keyBag = keyType._zod.bag;
3443
+ const patterns = keyBag?.patterns;
3444
+ if (def.mode === "loose" && patterns && patterns.size > 0) {
3445
+ // Use patternProperties for looseRecord with regex patterns
3446
+ const valueSchema = process(def.valueType, ctx, {
3447
+ ...params,
3448
+ path: [...params.path, "patternProperties", "*"],
3449
+ });
3450
+ json.patternProperties = {};
3451
+ for (const pattern of patterns) {
3452
+ json.patternProperties[pattern.source] = valueSchema;
3453
+ }
3454
+ }
3455
+ else {
3456
+ // Default behavior: use propertyNames + additionalProperties
3457
+ if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
3458
+ json.propertyNames = process(def.keyType, ctx, {
3459
+ ...params,
3460
+ path: [...params.path, "propertyNames"],
3461
+ });
3462
+ }
3463
+ json.additionalProperties = process(def.valueType, ctx, {
3464
+ ...params,
3465
+ path: [...params.path, "additionalProperties"],
3466
+ });
3467
+ }
3468
+ // Add required for keys with discrete values (enum, literal, etc.)
3469
+ const keyValues = keyType._zod.values;
3470
+ if (keyValues) {
3471
+ const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
3472
+ if (validKeyValues.length > 0) {
3473
+ json.required = validKeyValues;
3474
+ }
3475
+ }
3476
+ };
3317
3477
  const nullableProcessor = (schema, ctx, json, params) => {
3318
3478
  const def = schema._zod.def;
3319
3479
  const inner = process(def.innerType, ctx, params);
@@ -3817,6 +3977,21 @@ function intersection(left, right) {
3817
3977
  right: right,
3818
3978
  });
3819
3979
  }
3980
+ const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => {
3981
+ $ZodRecord.init(inst, def);
3982
+ ZodType.init(inst, def);
3983
+ inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params);
3984
+ inst.keyType = def.keyType;
3985
+ inst.valueType = def.valueType;
3986
+ });
3987
+ function record(keyType, valueType, params) {
3988
+ return new ZodRecord({
3989
+ type: "record",
3990
+ keyType,
3991
+ valueType: valueType,
3992
+ ...normalizeParams(params),
3993
+ });
3994
+ }
3820
3995
  const ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => {
3821
3996
  $ZodEnum.init(inst, def);
3822
3997
  ZodType.init(inst, def);
@@ -4049,8 +4224,19 @@ const vNextOasGeneratorSchema = strictObject({
4049
4224
  unwrap: boolean().default(true),
4050
4225
  withRequestParams: boolean().default(false),
4051
4226
  pathParamsStyle: _enum(["object", "positional"]).default("positional"),
4052
- enumStyle: _enum(["enum", "union"]).default("enum")
4053
- }),
4227
+ enumStyle: _enum(["enum", "union"]).default("enum"),
4228
+ comments: strictObject({
4229
+ enabled: boolean().default(true),
4230
+ operation: strictObject({
4231
+ tags: boolean().default(true),
4232
+ summary: boolean().default(true),
4233
+ description: boolean().default(true)
4234
+ }).prefault({}),
4235
+ schema: strictObject({
4236
+ metadata: boolean().default(true)
4237
+ }).prefault({})
4238
+ }).prefault({})
4239
+ }).prefault({}),
4054
4240
  compat: strictObject({
4055
4241
  uppercaseEnumKeys: boolean(),
4056
4242
  swaggerTsApiRequiredBooleans: boolean()
@@ -4061,7 +4247,7 @@ const legacyOasGeneratorSchema = strictObject({
4061
4247
  ignoreOperationsWithTags: array(string()).optional()
4062
4248
  })
4063
4249
  });
4064
- const configSchema = strictObject({
4250
+ const profileConfigSchema = strictObject({
4065
4251
  srcSpec: string().trim().min(1),
4066
4252
  dstDir: string().trim().min(1),
4067
4253
  apiName: string().trim().min(1),
@@ -4079,6 +4265,8 @@ const configSchema = strictObject({
4079
4265
  localDateTimes: boolean().optional()
4080
4266
  }).optional()
4081
4267
  });
4268
+ const configSchema = record(string(), profileConfigSchema);
4269
+ const defineConfig = (config) => config;
4082
4270
  const parseConfig = (userConfig, filePath) => {
4083
4271
  const parsed = configSchema.safeParse(userConfig);
4084
4272
  if (parsed.success) return parsed.data;
@@ -4086,6 +4274,13 @@ const parseConfig = (userConfig, filePath) => {
4086
4274
  cause: parsed.error
4087
4275
  });
4088
4276
  };
4277
+ const parseProfileConfig = (userConfig, filePath) => {
4278
+ const parsed = profileConfigSchema.safeParse(userConfig);
4279
+ if (parsed.success) return parsed.data;
4280
+ throw new Error(`Invalid config at ${filePath}: ${parsed.error.message}`, {
4281
+ cause: parsed.error
4282
+ });
4283
+ };
4089
4284
 
4090
4285
  const downloadSpec = async (path, url) => {
4091
4286
  let response;
@@ -4106,6 +4301,34 @@ const downloadSpec = async (path, url) => {
4106
4301
  await fs.writeFile(path, content);
4107
4302
  };
4108
4303
 
4304
+ const EMPTY_LINE_MARKER = "/*__EMPTY_LINE_MARKER__*/";
4305
+
4306
+ var __defProp$b = Object.defineProperty;
4307
+ var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4308
+ var __publicField$b = (obj, key, value) => __defNormalProp$b(obj, key + "" , value);
4309
+ const EMPTY_LINE_MARKER_LINE = new RegExp(
4310
+ `\\n[\\t ]*${EMPTY_LINE_MARKER.replaceAll("/", "\\/").replaceAll(
4311
+ "*",
4312
+ "\\*"
4313
+ )}\\n`,
4314
+ "g"
4315
+ );
4316
+ class CodeFormatter {
4317
+ constructor(opts) {
4318
+ this.opts = opts;
4319
+ __publicField$b(this, "format", async (code) => {
4320
+ const filePath = Path.resolve(this.opts.resolveConfFrom, "generated.ts");
4321
+ const prettier = await import('prettier');
4322
+ const prettierConfig = await prettier.resolveConfig(filePath) ?? {};
4323
+ const formattedCode = await prettier.format(code, {
4324
+ ...prettierConfig,
4325
+ filepath: filePath
4326
+ });
4327
+ return formattedCode.replaceAll(EMPTY_LINE_MARKER_LINE, "\n\n");
4328
+ });
4329
+ }
4330
+ }
4331
+
4109
4332
  const toPascalCaseIdentifier = (str) => {
4110
4333
  const words = str.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean);
4111
4334
  const pascalCase = words.map((word) => word[0].toUpperCase() + word.substring(1)).join("");
@@ -4126,6 +4349,12 @@ const groupBy = (values, getKey) => {
4126
4349
  }
4127
4350
  return groups;
4128
4351
  };
4352
+ const findRelativePath = (src, dst) => {
4353
+ const relativePath = Path$1.relative(Path$1.dirname(src), dst);
4354
+ const withoutExtension = relativePath.replace(/\.ts$/u, "");
4355
+ const normalizedPath = withoutExtension.split(Path$1.sep).join("/");
4356
+ return normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`;
4357
+ };
4129
4358
 
4130
4359
  const generateOpenApiClient = async (inputFile, {
4131
4360
  name,
@@ -4134,7 +4363,7 @@ const generateOpenApiClient = async (inputFile, {
4134
4363
  }, log) => {
4135
4364
  log(`Will generate API client name=${name} to ${outputDir}`);
4136
4365
  const fileName = "index";
4137
- const dstFile = Path.join(outputDir, `${fileName}.ts`);
4366
+ const dstFile = Path$1.join(outputDir, `${fileName}.ts`);
4138
4367
  const prettier = await import('prettier');
4139
4368
  const prettierConfig = await prettier.resolveConfig(dstFile) ?? {};
4140
4369
  const prettierConfigForGenerator = {
@@ -4178,12 +4407,12 @@ const generateOpenApiClient = async (inputFile, {
4178
4407
  return { types: dstFile, promiseWrapper: [dstFile] };
4179
4408
  };
4180
4409
  const getThisScriptDirname = () => {
4181
- return Path.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('generateApiClient.cjs', document.baseURI).href))));
4410
+ return Path$1.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('generateApiClient.cjs', document.baseURI).href))));
4182
4411
  };
4183
4412
  const getTemplatesDir = () => {
4184
4413
  const currentDir = getThisScriptDirname();
4185
- const templatesRelativePath = Path.basename(currentDir) === "dist" ? "../templates" : "../../../templates";
4186
- return Path.resolve(currentDir, templatesRelativePath);
4414
+ const templatesRelativePath = Path$1.basename(currentDir) === "dist" ? "../templates" : "../../../templates";
4415
+ return Path$1.resolve(currentDir, templatesRelativePath);
4187
4416
  };
4188
4417
 
4189
4418
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -4240,9 +4469,9 @@ const resolveLocalRef = (root, ref) => {
4240
4469
  return current;
4241
4470
  };
4242
4471
 
4243
- var __defProp$9 = Object.defineProperty;
4244
- var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4245
- var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, key + "" , value);
4472
+ var __defProp$a = Object.defineProperty;
4473
+ var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4474
+ var __publicField$a = (obj, key, value) => __defNormalProp$a(obj, key + "" , value);
4246
4475
  const PARAMETER_LOCATIONS = [
4247
4476
  "path",
4248
4477
  "query",
@@ -4268,7 +4497,7 @@ const mergeParameters = (base, override) => {
4268
4497
  class OpenApiNormalizer {
4269
4498
  constructor(doc) {
4270
4499
  this.doc = doc;
4271
- __publicField$9(this, "problems", []);
4500
+ __publicField$a(this, "problems", []);
4272
4501
  }
4273
4502
  load() {
4274
4503
  const info = readRecord(this.doc, "info");
@@ -4611,23 +4840,24 @@ const syntheticOperationId = (method, path) => {
4611
4840
  return `_${compact}`;
4612
4841
  };
4613
4842
 
4614
- var __defProp$8 = Object.defineProperty;
4615
- var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4616
- var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
4843
+ var __defProp$9 = Object.defineProperty;
4844
+ var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4845
+ var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
4617
4846
  class TsCodegen {
4618
- constructor(typeExprCodegen) {
4847
+ constructor(typeExprCodegen, docRenderer) {
4619
4848
  this.typeExprCodegen = typeExprCodegen;
4620
- __publicField$8(this, "usedTypeRefs", []);
4621
- __publicField$8(this, "usedTypeRefKeys", /* @__PURE__ */ new Set());
4622
- __publicField$8(this, "typeExpr", (typeExpr) => {
4849
+ __publicField$9(this, "usedTypeRefs", []);
4850
+ __publicField$9(this, "usedTypeRefKeys", /* @__PURE__ */ new Set());
4851
+ __publicField$9(this, "docRenderer");
4852
+ __publicField$9(this, "typeExpr", (typeExpr) => {
4623
4853
  this.collectTypeRefsFromExpr(typeExpr);
4624
4854
  return this.typeExprCodegen.toCode(typeExpr).code;
4625
4855
  });
4626
- __publicField$8(this, "declaration", (name, declaration) => {
4856
+ __publicField$9(this, "declaration", (name, declaration, options = {}) => {
4627
4857
  this.collectTypeRefsFromDeclaration(declaration);
4628
- return this.toDeclarationCode(name, declaration);
4858
+ return this.toDeclarationCode(name, declaration, options);
4629
4859
  });
4630
- __publicField$8(this, "toChunk", (name, code, exports$1) => {
4860
+ __publicField$9(this, "toChunk", (name, code, exports$1) => {
4631
4861
  const exportedSymbols = new Set(exports$1);
4632
4862
  const refs = this.getTypeRefs().filter((ref) => {
4633
4863
  return ref.kind !== "internal" || !exportedSymbols.has(ref.name);
@@ -4639,17 +4869,25 @@ class TsCodegen {
4639
4869
  refs
4640
4870
  };
4641
4871
  });
4642
- __publicField$8(this, "getTypeRefs", () => {
4872
+ __publicField$9(this, "getTypeRefs", () => {
4643
4873
  return this.usedTypeRefs.map((ref) => ({ ...ref }));
4644
4874
  });
4645
- __publicField$8(this, "toDeclarationCode", (name, declaration) => {
4875
+ __publicField$9(this, "toDeclarationCode", (name, d, o) => {
4876
+ let code = this.toDeclarationBodyCode(name, d);
4877
+ if (o.exported) {
4878
+ code = `export ${code}`;
4879
+ }
4880
+ return this.addDoc(code, d.doc);
4881
+ });
4882
+ __publicField$9(this, "toDeclarationBodyCode", (name, declaration) => {
4646
4883
  switch (declaration.kind) {
4647
4884
  case "typeAlias":
4648
4885
  return `type ${name} = ${this.typeExprCodegen.toCode(declaration.typeExpr).code}`;
4649
4886
  case "enum": {
4650
- const members = declaration.members.map(
4651
- (member) => ` ${member.name} = ${JSON.stringify(member.value)}`
4652
- ).join(",\n");
4887
+ const members = declaration.members.map((member) => {
4888
+ const code = `${member.name} = ${JSON.stringify(member.value)}`;
4889
+ return this.addDoc(code, member.doc);
4890
+ }).join(",\n");
4653
4891
  return `enum ${name} {
4654
4892
  ${members}
4655
4893
  }`;
@@ -4662,6 +4900,13 @@ ${members}
4662
4900
  }
4663
4901
  }
4664
4902
  });
4903
+ __publicField$9(this, "addDoc", (code, doc) => {
4904
+ if (!doc) return code;
4905
+ const rendered = this.docRenderer.render(doc);
4906
+ return rendered ? `${rendered}
4907
+ ${code}` : code;
4908
+ });
4909
+ this.docRenderer = docRenderer;
4665
4910
  }
4666
4911
  collectTypeRef(typeRef) {
4667
4912
  if (typeRef.kind === "builtin") return;
@@ -4787,12 +5032,13 @@ const toTsPropertyKey = (value) => {
4787
5032
  return isTsIdentifier(value) ? value : JSON.stringify(value);
4788
5033
  };
4789
5034
 
4790
- var __defProp$7 = Object.defineProperty;
4791
- var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4792
- var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
5035
+ var __defProp$8 = Object.defineProperty;
5036
+ var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5037
+ var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
4793
5038
  class TypeExprCodegen {
4794
- constructor() {
4795
- __publicField$7(this, "toCode", (typeExpr) => {
5039
+ constructor(docRenderer) {
5040
+ __publicField$8(this, "docRenderer");
5041
+ __publicField$8(this, "toCode", (typeExpr) => {
4796
5042
  switch (typeExpr.kind) {
4797
5043
  case "reference":
4798
5044
  return this.toReferenceCode(typeExpr);
@@ -4808,7 +5054,7 @@ class TypeExprCodegen {
4808
5054
  }
4809
5055
  }
4810
5056
  });
4811
- __publicField$7(this, "toReferenceCode", (typeExpr) => {
5057
+ __publicField$8(this, "toReferenceCode", (typeExpr) => {
4812
5058
  if (!typeExpr.typeArgs?.length) {
4813
5059
  return {
4814
5060
  code: typeExpr.ref.name,
@@ -4821,7 +5067,7 @@ class TypeExprCodegen {
4821
5067
  ref: typeExpr.ref
4822
5068
  };
4823
5069
  });
4824
- __publicField$7(this, "toInlineCode", (expr) => {
5070
+ __publicField$8(this, "toInlineCode", (expr) => {
4825
5071
  switch (expr.node) {
4826
5072
  case "scalar":
4827
5073
  return expr.name === "integer" ? "number" : expr.name;
@@ -4846,55 +5092,66 @@ class TypeExprCodegen {
4846
5092
  }
4847
5093
  }
4848
5094
  });
4849
- __publicField$7(this, "toIntersectionMemberCode", (typeExpr) => {
5095
+ __publicField$8(this, "toIntersectionMemberCode", (typeExpr) => {
4850
5096
  const rendered = this.toCode(typeExpr).code;
4851
5097
  return this.isUnion(typeExpr) ? `(${rendered})` : rendered;
4852
5098
  });
4853
- __publicField$7(this, "toArrayElementCode", (typeExpr) => {
5099
+ __publicField$8(this, "toArrayElementCode", (typeExpr) => {
4854
5100
  const rendered = this.toCode(typeExpr).code;
4855
5101
  return this.needsGroupingForArrayElement(typeExpr) ? `(${rendered})` : rendered;
4856
5102
  });
4857
- __publicField$7(this, "isUnion", (typeExpr) => {
5103
+ __publicField$8(this, "isUnion", (typeExpr) => {
4858
5104
  return typeExpr.kind === "inline" && typeExpr.expr.node === "union";
4859
5105
  });
4860
- __publicField$7(this, "needsGroupingForArrayElement", (typeExpr) => {
5106
+ __publicField$8(this, "needsGroupingForArrayElement", (typeExpr) => {
4861
5107
  return typeExpr.kind === "inline" && (typeExpr.expr.node === "union" || typeExpr.expr.node === "intersection");
4862
5108
  });
4863
- __publicField$7(this, "toLiteralCode", (value) => {
5109
+ __publicField$8(this, "toLiteralCode", (value) => {
4864
5110
  if (value === null) return "null";
4865
5111
  return JSON.stringify(value);
4866
5112
  });
4867
- __publicField$7(this, "toObjectCode", (properties, additionalProperties) => {
5113
+ __publicField$8(this, "toObjectCode", (properties, additionalProperties) => {
4868
5114
  const members = properties.map(
4869
5115
  (property) => this.toPropertyCode(property)
4870
5116
  );
4871
5117
  if (additionalProperties === true) {
4872
- members.push("[key: string]: unknown");
5118
+ members.push("[key: string]: unknown;");
4873
5119
  } else if (additionalProperties !== void 0 && additionalProperties !== false) {
4874
5120
  members.push(
4875
- `[key: string]: ${this.toCode(additionalProperties).code}`
5121
+ `[key: string]: ${this.toCode(additionalProperties).code};`
4876
5122
  );
4877
5123
  }
4878
- if (!members.length) return "{}";
4879
- return `{ ${members.join("; ")} }`;
5124
+ return `{
5125
+ ${members.join("\n")}
5126
+ }`;
4880
5127
  });
4881
- __publicField$7(this, "toPropertyCode", (property) => {
5128
+ __publicField$8(this, "toPropertyCode", (property) => {
4882
5129
  const name = toTsPropertyKey(property.name);
4883
5130
  const optional = property.required ? "" : "?";
4884
- return `${name}${optional}: ${this.toCode(property.typeExpr).code}`;
4885
- });
5131
+ const propertyCode = `${name}${optional}: ${this.toCode(property.typeExpr).code}`;
5132
+ const docCode = property.doc ? this.docRenderer.render(property.doc, {
5133
+ compactText: true
5134
+ }) : "";
5135
+ const renderedProperty = `${propertyCode};`;
5136
+ return docCode ? `${docCode}
5137
+ ${renderedProperty}` : renderedProperty;
5138
+ });
5139
+ this.docRenderer = docRenderer;
4886
5140
  }
4887
5141
  }
4888
5142
 
4889
- var __defProp$6 = Object.defineProperty;
4890
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4891
- var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
5143
+ var __defProp$7 = Object.defineProperty;
5144
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5145
+ var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
4892
5146
  class TsCodegenFactory {
4893
- constructor() {
4894
- __publicField$6(this, "typeExprCodegen", new TypeExprCodegen());
4895
- __publicField$6(this, "forNewChunk", () => {
4896
- return new TsCodegen(this.typeExprCodegen);
4897
- });
5147
+ constructor(docRenderer) {
5148
+ __publicField$7(this, "typeExprCodegen");
5149
+ __publicField$7(this, "docRenderer");
5150
+ __publicField$7(this, "forNewChunk", () => {
5151
+ return new TsCodegen(this.typeExprCodegen, this.docRenderer);
5152
+ });
5153
+ this.docRenderer = docRenderer;
5154
+ this.typeExprCodegen = new TypeExprCodegen(this.docRenderer);
4898
5155
  }
4899
5156
  }
4900
5157
 
@@ -4943,13 +5200,13 @@ const isReservedWord = (value) => {
4943
5200
  return RESERVED_WORDS.has(value);
4944
5201
  };
4945
5202
 
4946
- var __defProp$5 = Object.defineProperty;
4947
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4948
- var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
5203
+ var __defProp$6 = Object.defineProperty;
5204
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5205
+ var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
4949
5206
  class ParamsConstructor {
4950
5207
  constructor(options) {
4951
5208
  this.options = options;
4952
- __publicField$5(this, "process", (params, httpPath) => {
5209
+ __publicField$6(this, "process", (params, httpPath) => {
4953
5210
  const pathParamSpec = validatePathParams(params, httpPath);
4954
5211
  const pathParamBindings = pathParamSpec?.bindings;
4955
5212
  const funParams = params.flatMap(
@@ -4969,7 +5226,7 @@ class ParamsConstructor {
4969
5226
  hasQuery
4970
5227
  };
4971
5228
  });
4972
- __publicField$5(this, "renderOperationParams", (param, pathParamSpec) => {
5229
+ __publicField$6(this, "renderOperationParams", (param, pathParamSpec) => {
4973
5230
  if (param.kind !== "path" || !pathParamSpec) {
4974
5231
  return [
4975
5232
  {
@@ -4993,7 +5250,7 @@ class ParamsConstructor {
4993
5250
  }
4994
5251
  ];
4995
5252
  });
4996
- __publicField$5(this, "renderPathTemplateLiteral", (path, pathParamVarName, pathParamBindings) => {
5253
+ __publicField$6(this, "renderPathTemplateLiteral", (path, pathParamVarName, pathParamBindings) => {
4997
5254
  const escapedPath = path.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
4998
5255
  const pathWithParams = escapedPath.replace(
4999
5256
  /\{([^}]+)\}/g,
@@ -5007,7 +5264,7 @@ class ParamsConstructor {
5007
5264
  );
5008
5265
  return `\`${pathWithParams}\``;
5009
5266
  });
5010
- __publicField$5(this, "renderPathParamDestructuring", (pathParamBindings) => {
5267
+ __publicField$6(this, "renderPathParamDestructuring", (pathParamBindings) => {
5011
5268
  const members = Object.entries(pathParamBindings).map(
5012
5269
  ([paramName, binding]) => {
5013
5270
  const key = toTsPropertyKey(paramName);
@@ -5016,7 +5273,7 @@ class ParamsConstructor {
5016
5273
  );
5017
5274
  return `{ ${members.join(", ")} }`;
5018
5275
  });
5019
- __publicField$5(this, "paramName", (p) => {
5276
+ __publicField$6(this, "paramName", (p) => {
5020
5277
  switch (p.kind) {
5021
5278
  case "body":
5022
5279
  return this.options.paramNames.body;
@@ -5128,19 +5385,25 @@ const validatePathParams = (params, httpPath) => {
5128
5385
  };
5129
5386
  };
5130
5387
 
5131
- const EMPTY_LINE_MARKER = "/*__EMPTY_LINE_MARKER__*/";
5388
+ const indentBlock = (value, indent) => {
5389
+ if (!value || !indent) {
5390
+ return value;
5391
+ }
5392
+ return value.split("\n").map((line) => `${indent}${line}`).join("\n");
5393
+ };
5132
5394
 
5133
- var __defProp$4 = Object.defineProperty;
5134
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5135
- var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
5395
+ var __defProp$5 = Object.defineProperty;
5396
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5397
+ var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
5136
5398
  const REQUEST_PARAMS_TYPE = "RequestParams";
5137
5399
  const REQUEST_PARAMS_DEFAULT = "never";
5138
5400
  const REQUEST_PARAMS_ARG = "params";
5139
5401
  class ApiClientCodegen {
5140
- constructor(opts, tsCodegenFactory) {
5402
+ constructor(opts, tsCodegenFactory, docRenderer) {
5141
5403
  this.opts = opts;
5142
5404
  this.tsCodegenFactory = tsCodegenFactory;
5143
- __publicField$4(this, "generate", (apiName, operations) => {
5405
+ this.docRenderer = docRenderer;
5406
+ __publicField$5(this, "generate", (apiName, operations, doc) => {
5144
5407
  const tsCodegen = this.tsCodegenFactory.forNewChunk();
5145
5408
  const httpClientType = tsCodegen.typeExpr(this.opts.httpClient.typeName);
5146
5409
  let clientType = httpClientType;
@@ -5150,16 +5413,18 @@ class ApiClientCodegen {
5150
5413
  classTypeParams = `<${REQUEST_PARAMS_TYPE} = ${REQUEST_PARAMS_DEFAULT}>`;
5151
5414
  }
5152
5415
  const methodsCode = Array.isArray(operations) ? this.opsCode(tsCodegen, operations) : this.groupsOpsCode(tsCodegen, operations);
5416
+ const classDocCode = this.renderApiClientDoc(doc, "");
5153
5417
  const code = `
5154
- export class ${apiName}${classTypeParams} {
5155
- constructor(private readonly client: ${clientType}) {}
5418
+ ${classDocCode ? `${classDocCode}
5419
+ ` : ""}export class ${apiName}${classTypeParams} {
5420
+ constructor(private readonly http: ${clientType}) {}
5156
5421
 
5157
5422
  ${methodsCode}
5158
5423
  }
5159
5424
  `;
5160
5425
  return tsCodegen.toChunk("api", code, [apiName]);
5161
5426
  });
5162
- __publicField$4(this, "groupsOpsCode", (codegen, groupedOps) => Object.entries(groupedOps).map(([groupName, ops]) => {
5427
+ __publicField$5(this, "groupsOpsCode", (codegen, groupedOps) => Object.entries(groupedOps).map(([groupName, ops]) => {
5163
5428
  const methodsCode = this.opsCode(codegen, ops, "object");
5164
5429
  return `
5165
5430
  ${toTsPropertyKey(groupName)} = {
@@ -5167,14 +5432,14 @@ class ApiClientCodegen {
5167
5432
  }
5168
5433
  `;
5169
5434
  }).join("\n\n"));
5170
- __publicField$4(this, "opsCode", (codegen, operations, target = "class") => {
5435
+ __publicField$5(this, "opsCode", (codegen, operations, target = "class") => {
5171
5436
  const separator = target === "object" ? `,
5172
5437
  ${EMPTY_LINE_MARKER}
5173
5438
  ` : "\n\n";
5174
5439
  const methodsCode = operations.map((op) => this.renderOp(op, codegen, target)).join(separator);
5175
5440
  return methodsCode;
5176
5441
  });
5177
- __publicField$4(this, "renderOp", (op, tsCodegen, target) => {
5442
+ __publicField$5(this, "renderOp", (op, tsCodegen, target) => {
5178
5443
  const { signature: sig, http } = op;
5179
5444
  const invocationVars = this.opts.httpClient.invocation.vars;
5180
5445
  const paramNames = {
@@ -5200,6 +5465,7 @@ ${EMPTY_LINE_MARKER}
5200
5465
  const responseType = tsCodegen.typeExpr(sig.returnType);
5201
5466
  const returnType = this.wrapInResponseWrapper(sig.returnType, tsCodegen);
5202
5467
  return this.renderFunctionCode({
5468
+ doc: sig.doc,
5203
5469
  funName: sig.name,
5204
5470
  responseType,
5205
5471
  returnType,
@@ -5215,13 +5481,14 @@ ${EMPTY_LINE_MARKER}
5215
5481
  target
5216
5482
  });
5217
5483
  });
5218
- __publicField$4(this, "wrapInResponseWrapper", (typeExpr, tsCodegen) => {
5484
+ __publicField$5(this, "wrapInResponseWrapper", (typeExpr, tsCodegen) => {
5219
5485
  return tsCodegen.typeExpr({
5220
5486
  ...this.opts.httpClient.responseWrapper,
5221
5487
  typeArgs: [typeExpr]
5222
5488
  });
5223
5489
  });
5224
- __publicField$4(this, "renderFunctionCode", ({
5490
+ __publicField$5(this, "renderFunctionCode", ({
5491
+ doc,
5225
5492
  funName,
5226
5493
  responseType,
5227
5494
  returnType,
@@ -5253,9 +5520,74 @@ ${EMPTY_LINE_MARKER}
5253
5520
  invocation = invocation.replaceAll("\n", "");
5254
5521
  const operator = target === "object" ? ":" : "=";
5255
5522
  const returnTypeCode = this.opts.httpClient.inferMethodReturnType ? "" : `:${returnType}`;
5256
- return `${funName} ${operator} (${params})${returnTypeCode} =>
5257
- this.client${invocation}
5523
+ const functionCode = `${funName} ${operator} (${params})${returnTypeCode} =>
5524
+ this.http${invocation}
5258
5525
  `;
5526
+ const docCode = this.renderOperationDoc(
5527
+ doc,
5528
+ this.opts.comments,
5529
+ target === "object" ? " " : " "
5530
+ );
5531
+ return docCode ? `${docCode}
5532
+ ${functionCode}` : functionCode;
5533
+ });
5534
+ __publicField$5(this, "renderOperationDoc", (doc, comments, indent = "") => {
5535
+ if (!doc) return null;
5536
+ return indentBlock(this.docRenderer.render(this.toTsDoc(doc)), indent);
5537
+ });
5538
+ __publicField$5(this, "renderApiClientDoc", (doc, indent = "") => {
5539
+ if (!doc) return "";
5540
+ return indentBlock(
5541
+ this.docRenderer.render({
5542
+ nodes: [
5543
+ {
5544
+ key: "title",
5545
+ value: doc.title
5546
+ },
5547
+ {
5548
+ key: "version",
5549
+ value: doc.version
5550
+ },
5551
+ ...doc.description ? [doc.description] : []
5552
+ ]
5553
+ }),
5554
+ indent
5555
+ );
5556
+ });
5557
+ __publicField$5(this, "toTsDoc", (doc) => {
5558
+ const nodes = [
5559
+ {
5560
+ key: "id",
5561
+ value: doc.id
5562
+ }
5563
+ ];
5564
+ const comms = this.opts.comments;
5565
+ if ((comms.summary ?? true) && doc.summary) {
5566
+ nodes.push({
5567
+ key: "summary",
5568
+ value: doc.summary
5569
+ });
5570
+ }
5571
+ if ((comms.description ?? true) && doc.description) {
5572
+ nodes.push({
5573
+ key: "description",
5574
+ value: doc.description
5575
+ });
5576
+ }
5577
+ nodes.push({
5578
+ key: "request",
5579
+ value: doc.request
5580
+ });
5581
+ if ((comms.tags ?? true) && doc.tags.length) {
5582
+ nodes.push({
5583
+ key: "tags",
5584
+ value: doc.tags.join(", ")
5585
+ });
5586
+ }
5587
+ return {
5588
+ deprecated: doc.deprecated,
5589
+ nodes
5590
+ };
5259
5591
  });
5260
5592
  }
5261
5593
  }
@@ -5424,21 +5756,102 @@ const provideHttpClientCode = (gen, opts) => gen.toChunk(
5424
5756
  ["HttpRequest", "HttpResponse", "HttpClient"]
5425
5757
  );
5426
5758
 
5759
+ var __defProp$4 = Object.defineProperty;
5760
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5761
+ var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
5762
+ class TsDocRenderer {
5763
+ constructor(options) {
5764
+ this.options = options;
5765
+ __publicField$4(this, "render", (doc, options = {}) => {
5766
+ if (!this.options.enabled) return "";
5767
+ const lines = [];
5768
+ this.appendNodes(lines, doc.nodes, options);
5769
+ if (doc.deprecated) {
5770
+ this.appendDeprecated(lines, { separate: lines.length > 0 });
5771
+ }
5772
+ return this.renderComment(lines);
5773
+ });
5774
+ __publicField$4(this, "renderComment", (lines) => {
5775
+ if (!this.options.enabled) return "";
5776
+ if (!lines.length) return "";
5777
+ if (lines.length === 1) {
5778
+ return `/** ${lines[0]} */`;
5779
+ }
5780
+ const body = lines.map((line) => line ? ` * ${line}` : " *").join("\n");
5781
+ return `/**
5782
+ ${body}
5783
+ */`;
5784
+ });
5785
+ __publicField$4(this, "appendDocText", (lines, value) => {
5786
+ const normalized = this.normalizeLines(value);
5787
+ if (!normalized.length) return;
5788
+ if (lines.length > 0) {
5789
+ lines.push("");
5790
+ }
5791
+ lines.push(...normalized);
5792
+ });
5793
+ __publicField$4(this, "appendField", (lines, key, value) => {
5794
+ const normalized = this.normalizeLines(value);
5795
+ if (!normalized.length) return;
5796
+ lines.push(`@${key} ${normalized[0]}`.trimEnd());
5797
+ lines.push(...normalized.slice(1));
5798
+ });
5799
+ __publicField$4(this, "appendDeprecated", (lines, options) => {
5800
+ if (options.separate) {
5801
+ lines.push("");
5802
+ }
5803
+ lines.push("@deprecated");
5804
+ });
5805
+ __publicField$4(this, "appendNodes", (lines, nodes = [], options = {}) => {
5806
+ nodes.forEach((node) => {
5807
+ if (typeof node === "string") {
5808
+ if (options.compactText) {
5809
+ lines.push(...this.normalizeNonEmptyLines(node));
5810
+ return;
5811
+ }
5812
+ this.appendDocText(lines, node);
5813
+ return;
5814
+ }
5815
+ this.appendField(lines, node.key, node.value);
5816
+ });
5817
+ });
5818
+ __publicField$4(this, "normalizeLines", (value) => {
5819
+ const trimmed = value?.trim();
5820
+ if (!trimmed) return [];
5821
+ return trimmed.split(/\r?\n/u).map((line) => line.trimEnd().replaceAll("*/", "*\\/"));
5822
+ });
5823
+ __publicField$4(this, "normalizeNonEmptyLines", (value) => this.normalizeLines(value).filter((line) => line.length > 0));
5824
+ }
5825
+ }
5826
+
5427
5827
  const generateTsCode = (clientName, projectResult, opts) => {
5428
- const tsCodegenFac = new TsCodegenFactory();
5828
+ const docRenderer = new TsDocRenderer({
5829
+ enabled: opts.comments.enabled
5830
+ });
5831
+ const tsCodegenFac = new TsCodegenFactory(docRenderer);
5429
5832
  const { schemaDefinitions } = projectResult;
5430
5833
  const types = [...schemaDefinitions].sort((a, b) => a.name.localeCompare(b.name)).map((def) => {
5431
5834
  const cg = tsCodegenFac.forNewChunk();
5432
- const code = `export ${cg.declaration(def.name, def.declaration)}`;
5835
+ const code = cg.declaration(def.name, def.declaration, {
5836
+ exported: true
5837
+ });
5433
5838
  return cg.toChunk(def.name, code, [def.name]);
5434
5839
  });
5435
5840
  const clientCodegen = new ApiClientCodegen(
5436
- { httpClient: promiseHttpClientCodegenSpec(), ...opts },
5437
- tsCodegenFac
5841
+ {
5842
+ httpClient: promiseHttpClientCodegenSpec(),
5843
+ comments: opts.comments.operation,
5844
+ unwrap: opts.unwrap,
5845
+ pathParamsStyle: opts.pathParamsStyle,
5846
+ withRequestParams: opts.withRequestParams
5847
+ },
5848
+ tsCodegenFac,
5849
+ docRenderer
5438
5850
  );
5439
5851
  const generated = clientCodegen.generate(
5440
5852
  clientName,
5441
- groupsOpsByTag(projectResult.operations)
5853
+ groupsOpsByTag(projectResult.operations),
5854
+ projectResult.api
5442
5855
  );
5443
5856
  const clientChunk = {
5444
5857
  ...generated,
@@ -5648,6 +6061,7 @@ class ToTypeExprConverter {
5648
6061
  }
5649
6062
  return {
5650
6063
  kind: "typeAlias",
6064
+ doc: this.getSchemaDoc(schema),
5651
6065
  typeExpr: this.fromTypeExpr(schema)
5652
6066
  };
5653
6067
  });
@@ -5661,6 +6075,7 @@ class ToTypeExprConverter {
5661
6075
  }
5662
6076
  return {
5663
6077
  kind: "enum",
6078
+ doc: this.getSchemaDoc(schema),
5664
6079
  valueType,
5665
6080
  members: this.toEnumMembers(schema.enum)
5666
6081
  };
@@ -5776,6 +6191,7 @@ class ToTypeExprConverter {
5776
6191
  );
5777
6192
  }
5778
6193
  return {
6194
+ doc: this.getSchemaDoc(propertySchema),
5779
6195
  name,
5780
6196
  required: this.isRequiredProperty(
5781
6197
  name,
@@ -5836,6 +6252,71 @@ class ToTypeExprConverter {
5836
6252
  __publicField$3(this, "isBinaryFileSchema", (schema) => {
5837
6253
  return schema.type === "string" && schema.format === "binary";
5838
6254
  });
6255
+ __publicField$3(this, "getSchemaDoc", (schema) => {
6256
+ const summary = typeof schema.summary === "string" ? schema.summary : void 0;
6257
+ const description = typeof schema.description === "string" ? schema.description : void 0;
6258
+ const deprecated = typeof schema.deprecated === "boolean" ? schema.deprecated : void 0;
6259
+ const annotations = this.getSchemaAnnotations(schema);
6260
+ if (!summary && !description && !deprecated && !annotations.length) {
6261
+ return void 0;
6262
+ }
6263
+ const nodes = [];
6264
+ if (summary) {
6265
+ nodes.push(summary);
6266
+ }
6267
+ if (description) {
6268
+ nodes.push(description);
6269
+ }
6270
+ nodes.push(...annotations);
6271
+ return {
6272
+ deprecated,
6273
+ nodes
6274
+ };
6275
+ });
6276
+ __publicField$3(this, "getSchemaAnnotations", (schema) => {
6277
+ if (this.options.comments?.metadata === false) return [];
6278
+ return [
6279
+ this.annotationNode("format", schema.format),
6280
+ this.annotationNode("min", schema.minimum),
6281
+ this.annotationNode("multipleOf", schema.multipleOf),
6282
+ this.annotationNode("exclusiveMin", schema.exclusiveMinimum),
6283
+ this.annotationNode("max", schema.maximum),
6284
+ this.annotationNode("minLength", schema.minLength),
6285
+ this.annotationNode("maxLength", schema.maxLength),
6286
+ this.annotationNode("exclusiveMax", schema.exclusiveMaximum),
6287
+ this.annotationNode("maxItems", schema.maxItems),
6288
+ this.annotationNode("minItems", schema.minItems),
6289
+ this.annotationNode("uniqueItems", schema.uniqueItems),
6290
+ this.annotationNode(
6291
+ "default",
6292
+ this.stringifyAnnotationValue(schema.default)
6293
+ ),
6294
+ this.annotationNode("pattern", schema.pattern),
6295
+ this.annotationNode(
6296
+ "example",
6297
+ this.stringifyAnnotationValue(schema.example)
6298
+ )
6299
+ ].filter(
6300
+ (value) => value !== void 0
6301
+ );
6302
+ });
6303
+ __publicField$3(this, "annotationNode", (name, value) => {
6304
+ if (value === void 0) return void 0;
6305
+ return {
6306
+ key: name,
6307
+ value: String(value)
6308
+ };
6309
+ });
6310
+ __publicField$3(this, "stringifyAnnotationValue", (value) => {
6311
+ if (value === void 0) return void 0;
6312
+ if (value && typeof value === "object") {
6313
+ return JSON.stringify(value);
6314
+ }
6315
+ if (typeof value === "string") {
6316
+ return JSON.stringify(value);
6317
+ }
6318
+ return String(value);
6319
+ });
5839
6320
  __publicField$3(this, "fromSchemaCore", (schema) => {
5840
6321
  if (this.isUnconstrainedSchema(schema)) {
5841
6322
  return this.scalar("unknown");
@@ -6022,6 +6503,11 @@ class OperationProjector {
6022
6503
  return this.projectOne(operationName, operation);
6023
6504
  });
6024
6505
  return {
6506
+ api: {
6507
+ title: openApi.info.title,
6508
+ version: openApi.info.version,
6509
+ description: openApi.info.description
6510
+ },
6025
6511
  operations,
6026
6512
  schemaDefinitions: this.typeExprConverter.getSchemaDefinitions()
6027
6513
  };
@@ -6038,6 +6524,7 @@ class OperationProjector {
6038
6524
  return {
6039
6525
  op: {
6040
6526
  signature: {
6527
+ doc: this.toOperationDoc(operationName, operation),
6041
6528
  name: operationName,
6042
6529
  parameters,
6043
6530
  returnType: this.projectReturnType(operation)
@@ -6086,6 +6573,7 @@ class OperationProjector {
6086
6573
  });
6087
6574
  __publicField$2(this, "projectParameterGroupTypeExpr", (params) => {
6088
6575
  const properties = Object.entries(params).map(([name, parameter]) => ({
6576
+ doc: this.toParameterDoc(parameter),
6089
6577
  name,
6090
6578
  required: parameter.required,
6091
6579
  typeExpr: this.typeExprConverter.fromTypeExpr(
@@ -6158,43 +6646,36 @@ class OperationProjector {
6158
6646
  __publicField$2(this, "selectResponseSchema", (response) => {
6159
6647
  return getPreferredMediaTypeEntry(response.content).media?.schema;
6160
6648
  });
6649
+ __publicField$2(this, "toParameterDoc", (parameter) => {
6650
+ if (!parameter.description && !parameter.deprecated) {
6651
+ return void 0;
6652
+ }
6653
+ return {
6654
+ deprecated: parameter.deprecated,
6655
+ nodes: parameter.description ? [parameter.description] : []
6656
+ };
6657
+ });
6658
+ __publicField$2(this, "toOperationDoc", (operationName, operation) => {
6659
+ return {
6660
+ id: operationName,
6661
+ request: `${toHttpMethodUpper(operation.method)}:${operation.path}`,
6662
+ summary: operation.summary,
6663
+ description: operation.description,
6664
+ deprecated: operation.deprecated,
6665
+ tags: operation.tags.map((tag) => tag.trim()).filter(Boolean)
6666
+ };
6667
+ });
6161
6668
  }
6162
6669
  }
6163
6670
 
6164
6671
  var __defProp$1 = Object.defineProperty;
6165
6672
  var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6166
- var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, key + "" , value);
6167
- const EMPTY_LINE_MARKER_LINE = new RegExp(
6168
- `\\n[\\t ]*${EMPTY_LINE_MARKER.replaceAll("/", "\\/").replaceAll(
6169
- "*",
6170
- "\\*"
6171
- )}\\n`,
6172
- "g"
6173
- );
6174
- class CodeFormatter {
6175
- constructor(opts) {
6176
- this.opts = opts;
6177
- __publicField$1(this, "format", async (code) => {
6178
- const filePath = Path$1.resolve(this.opts.resolveConfFrom, "generated.ts");
6179
- const prettier = await import('prettier');
6180
- const prettierConfig = await prettier.resolveConfig(filePath) ?? {};
6181
- const formattedCode = await prettier.format(code, {
6182
- ...prettierConfig,
6183
- filepath: filePath
6184
- });
6185
- return formattedCode.replaceAll(EMPTY_LINE_MARKER_LINE, "\n\n");
6186
- });
6187
- }
6188
- }
6189
-
6190
- var __defProp = Object.defineProperty;
6191
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6192
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6673
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
6193
6674
  class CodeWriter {
6194
6675
  constructor(formatter) {
6195
6676
  this.formatter = formatter;
6196
- __publicField(this, "symbolChunkMap", /* @__PURE__ */ new Map());
6197
- __publicField(this, "write", async (dir, chunks) => {
6677
+ __publicField$1(this, "symbolChunkMap", /* @__PURE__ */ new Map());
6678
+ __publicField$1(this, "write", async (dir, chunks) => {
6198
6679
  this.symbolChunkMap = this.createSymbolChunkMap(chunks);
6199
6680
  fs$1.mkdirSync(dir, { recursive: true });
6200
6681
  for (const chunk of chunks) {
@@ -6209,7 +6690,7 @@ class CodeWriter {
6209
6690
  fs$1.writeFileSync(`${dir}/${chunk.name}.ts`, code, "utf8");
6210
6691
  }
6211
6692
  });
6212
- __publicField(this, "createSymbolChunkMap", (chunks) => {
6693
+ __publicField$1(this, "createSymbolChunkMap", (chunks) => {
6213
6694
  const map = /* @__PURE__ */ new Map();
6214
6695
  for (const chunk of chunks) {
6215
6696
  for (const exportedSymbol of chunk.exports) {
@@ -6223,7 +6704,7 @@ class CodeWriter {
6223
6704
  }
6224
6705
  return map;
6225
6706
  });
6226
- __publicField(this, "collectImports", (chunk) => {
6707
+ __publicField$1(this, "collectImports", (chunk) => {
6227
6708
  const imports = [];
6228
6709
  for (const ref of chunk.refs) {
6229
6710
  if (ref.kind === "builtin") continue;
@@ -6246,7 +6727,7 @@ class CodeWriter {
6246
6727
  }
6247
6728
  return imports;
6248
6729
  });
6249
- __publicField(this, "genImportStatements", (imports) => {
6730
+ __publicField$1(this, "genImportStatements", (imports) => {
6250
6731
  const symbolsBySource = groupBy(
6251
6732
  imports.map((i) => ({
6252
6733
  name: i.name,
@@ -6259,7 +6740,7 @@ class CodeWriter {
6259
6740
  return `import type { ${sortedSymbols.join(", ")} } from '${source}'`;
6260
6741
  });
6261
6742
  });
6262
- __publicField(this, "importSourcetoString", (src) => {
6743
+ __publicField$1(this, "importSourcetoString", (src) => {
6263
6744
  return "externalModule" in src ? src.externalModule : (
6264
6745
  // TODO generalize later when we have different paths
6265
6746
  `./${src.name}`
@@ -6274,7 +6755,7 @@ class VNextOasClientGenerator {
6274
6755
  this.options = options;
6275
6756
  this.log = log;
6276
6757
  }
6277
- async generate(cmd) {
6758
+ async generate(cmd, formatter) {
6278
6759
  const { inputFile, outputDir, apiName } = cmd;
6279
6760
  this.log(`Will generate API client name=${apiName} to ${outputDir}`);
6280
6761
  const sourceSchema = await loadSourceSchema(inputFile);
@@ -6283,6 +6764,7 @@ class VNextOasClientGenerator {
6283
6764
  const projectResult = new OperationProjector({
6284
6765
  includeAllSchema: this.options.selection?.allSchemas === true,
6285
6766
  typeExtraction: {
6767
+ comments: this.options.codegen.comments.schema,
6286
6768
  enumStyle: this.options.codegen.enumStyle,
6287
6769
  uppercaseEnumKeys: this.options.compat?.uppercaseEnumKeys,
6288
6770
  swaggerTsApiRequiredBooleans: this.options.compat?.swaggerTsApiRequiredBooleans
@@ -6294,12 +6776,9 @@ class VNextOasClientGenerator {
6294
6776
  projectResult,
6295
6777
  this.options.codegen
6296
6778
  );
6297
- const codeFormatter = new CodeFormatter({
6298
- resolveConfFrom: outputDir
6299
- });
6300
- const writer = new CodeWriter(codeFormatter);
6779
+ const writer = new CodeWriter(formatter);
6301
6780
  await writer.write(outputDir, chunks.all);
6302
- const tsFilePath = (name) => Path.join(outputDir, `${name}.ts`);
6781
+ const tsFilePath = (name) => Path$1.join(outputDir, `${name}.ts`);
6303
6782
  return {
6304
6783
  promiseWrapper: chunks.promiseWrappersNames.map(tsFilePath),
6305
6784
  types: tsFilePath(chunks.typesName)
@@ -6365,7 +6844,7 @@ const toErrorMessage = (error) => {
6365
6844
  return error instanceof Error ? error.message : String(error);
6366
6845
  };
6367
6846
 
6368
- const generateOpenApiModel = async (spectPath, config, log) => {
6847
+ const generateOpenApiModel = async (spectPath, config, log, codeFormatter) => {
6369
6848
  let outFiles;
6370
6849
  const { openApiGenerator, responseWrapper } = config;
6371
6850
  if ("legacy" in openApiGenerator) {
@@ -6382,11 +6861,14 @@ const generateOpenApiModel = async (spectPath, config, log) => {
6382
6861
  outFiles = await new VNextOasClientGenerator(
6383
6862
  openApiGenerator,
6384
6863
  log
6385
- ).generate({
6386
- inputFile: spectPath,
6387
- apiName: config.apiName,
6388
- outputDir: config.dstDir
6389
- });
6864
+ ).generate(
6865
+ {
6866
+ inputFile: spectPath,
6867
+ apiName: config.apiName,
6868
+ outputDir: config.dstDir
6869
+ },
6870
+ codeFormatter
6871
+ );
6390
6872
  }
6391
6873
  if (responseWrapper) {
6392
6874
  await modifyHttpClientAsyncWrapper(
@@ -6475,46 +6957,51 @@ const findMatchingBrace = (code, openBraceIndex) => {
6475
6957
  return -1;
6476
6958
  };
6477
6959
 
6478
- const generateSchemas = async (inputFile, outputFile, opts = {}) => {
6479
- const code = fs$2.readFileSync(inputFile).toString();
6480
- const { getZodSchemasFile } = tsToZod.generate({
6481
- sourceText: removeGenericTypes(code)
6482
- });
6483
- let f = getZodSchemasFile(getModuleImportPath(inputFile, outputFile));
6484
- f = f.replaceAll(".optional()", ".nullable()");
6485
- if (opts.localDateTimes) {
6486
- f = f.replaceAll(
6487
- "z.string().datetime()",
6488
- "z.string().datetime({local: true})"
6489
- );
6960
+ var __defProp = Object.defineProperty;
6961
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6962
+ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
6963
+ class ZodSchemaGenerator {
6964
+ constructor(codeFormatter) {
6965
+ this.codeFormatter = codeFormatter;
6966
+ __publicField(this, "generate", async ({
6967
+ sourceText,
6968
+ moduleImportPath,
6969
+ options = {}
6970
+ }) => {
6971
+ const { getZodSchemasFile } = tsToZod.generate({
6972
+ sourceText: removeGenericTypes(sourceText)
6973
+ });
6974
+ let generated = getZodSchemasFile(moduleImportPath);
6975
+ generated = generated.replaceAll(".optional()", ".nullable()");
6976
+ generated = generated.replaceAll(".int64()", ".int()");
6977
+ if (options.localDateTimes) {
6978
+ generated = generated.replaceAll(
6979
+ "z.string().datetime()",
6980
+ "z.string().datetime({local: true})"
6981
+ );
6982
+ }
6983
+ return this.codeFormatter.format(generated);
6984
+ });
6490
6985
  }
6491
- const prettier = await import('prettier');
6492
- const prettierConfig = await prettier.resolveConfig(outputFile) ?? {};
6493
- const formatted = await prettier.format(f, {
6494
- ...prettierConfig,
6495
- filepath: outputFile
6496
- });
6497
- fs$2.writeFileSync(outputFile, formatted);
6498
- };
6499
- const getModuleImportPath = (inputFile, outputFile) => {
6500
- const sourceDir = Path.dirname(outputFile);
6501
- const relativePath = Path.relative(sourceDir, inputFile);
6502
- const withoutExtension = relativePath.replace(/\.ts$/u, "");
6503
- const normalizedPath = withoutExtension.split(Path.sep).join("/");
6504
- return normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`;
6505
- };
6986
+ }
6506
6987
 
6507
6988
  const generateApiClient = async (params, configFilePath, log = console.log) => {
6508
- const config = parseConfig(params, configFilePath);
6989
+ const config = parseProfileConfig(params, configFilePath);
6990
+ return generateApiClientFromConfig(config, log);
6991
+ };
6992
+ const generateApiClientFromConfig = async (config, log = console.log) => {
6509
6993
  const { dstDir, apiName, srcSpec, zodSchemas } = config;
6510
- const dir = Path.resolve(dstDir, apiName);
6994
+ const dir = Path$1.resolve(dstDir, apiName);
6511
6995
  if (!fs__namespace.existsSync(dir)) {
6512
6996
  log(`Creating dir ${dir}`);
6513
6997
  fs__namespace.mkdirSync(dir, {
6514
6998
  recursive: true
6515
6999
  });
6516
7000
  }
6517
- const clientDir = Path.resolve(dir, "client");
7001
+ const clientDir = Path$1.resolve(dir, "client");
7002
+ const formatter = new CodeFormatter({
7003
+ resolveConfFrom: dir
7004
+ });
6518
7005
  const specPath = await getSpecPath(srcSpec, dir, log);
6519
7006
  log(`Cleaning client output dir ${clientDir}`);
6520
7007
  fs__namespace.rmSync(clientDir, {
@@ -6530,15 +7017,20 @@ const generateApiClient = async (params, configFilePath, log = console.log) => {
6530
7017
  ...config,
6531
7018
  dstDir: clientDir
6532
7019
  },
6533
- log
7020
+ log,
7021
+ formatter
6534
7022
  );
6535
7023
  if (zodSchemas?.enabled === false) return;
6536
7024
  log("Generating Zod schemas");
6537
- await generateSchemas(
6538
- typesFilePath,
6539
- Path.resolve(dir, "./zod.ts"),
6540
- zodSchemas
6541
- );
7025
+ const zodOutputFile = Path$1.resolve(dir, "./zod.ts");
7026
+ const generator = new ZodSchemaGenerator(formatter);
7027
+ const sourceText = fs__namespace.readFileSync(typesFilePath, "utf8");
7028
+ const generated = await generator.generate({
7029
+ sourceText,
7030
+ moduleImportPath: findRelativePath(zodOutputFile, typesFilePath),
7031
+ options: zodSchemas
7032
+ });
7033
+ fs__namespace.writeFileSync(zodOutputFile, generated);
6542
7034
  };
6543
7035
  const getSpecPath = async (urlOrPath, dir, log) => {
6544
7036
  if (!urlOrPath.startsWith("http")) {
@@ -6546,10 +7038,13 @@ const getSpecPath = async (urlOrPath, dir, log) => {
6546
7038
  throw new Error(`Spec file ${urlOrPath} does not exists`);
6547
7039
  return urlOrPath;
6548
7040
  }
6549
- const specPath = Path.resolve(dir, `spec.json`);
7041
+ const specPath = Path$1.resolve(dir, `spec.json`);
6550
7042
  log(`Will download the API spec from ${urlOrPath} to ${specPath}`);
6551
7043
  await downloadSpec(specPath, urlOrPath);
6552
7044
  return specPath;
6553
7045
  };
6554
7046
 
7047
+ exports.defineConfig = defineConfig;
6555
7048
  exports.generateApiClient = generateApiClient;
7049
+ exports.generateApiClientFromConfig = generateApiClientFromConfig;
7050
+ exports.parseConfig = parseConfig;