@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,11 @@
1
- import Path from 'path';
1
+ import Path$1 from 'path';
2
2
  import * as fs from 'fs';
3
- import fs__default from 'fs';
4
3
  import fs$1 from 'fs/promises';
4
+ import Path from 'node:path';
5
5
  import { generateApi } from 'swagger-typescript-api';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { readFile } from 'node:fs/promises';
8
- import Path$1 from 'node:path';
9
- import fs$2 from 'node:fs';
8
+ import fs__default from 'node:fs';
10
9
  import { generate } from 'ts-to-zod';
11
10
 
12
11
  /** A special constant with type `never` */
@@ -701,6 +700,7 @@ const string$1 = (params) => {
701
700
  const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
702
701
  return new RegExp(`^${regex}$`);
703
702
  };
703
+ const number = /^-?\d+(?:\.\d+)?$/;
704
704
  const boolean$1 = /^(?:true|false)$/i;
705
705
  // regex for string with no uppercase letters
706
706
  const lowercase = /^[^A-Z]*$/;
@@ -1897,6 +1897,122 @@ function handleIntersectionResults(result, left, right) {
1897
1897
  result.value = merged.data;
1898
1898
  return result;
1899
1899
  }
1900
+ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
1901
+ $ZodType.init(inst, def);
1902
+ inst._zod.parse = (payload, ctx) => {
1903
+ const input = payload.value;
1904
+ if (!isPlainObject(input)) {
1905
+ payload.issues.push({
1906
+ expected: "record",
1907
+ code: "invalid_type",
1908
+ input,
1909
+ inst,
1910
+ });
1911
+ return payload;
1912
+ }
1913
+ const proms = [];
1914
+ const values = def.keyType._zod.values;
1915
+ if (values) {
1916
+ payload.value = {};
1917
+ const recordKeys = new Set();
1918
+ for (const key of values) {
1919
+ if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
1920
+ recordKeys.add(typeof key === "number" ? key.toString() : key);
1921
+ const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
1922
+ if (result instanceof Promise) {
1923
+ proms.push(result.then((result) => {
1924
+ if (result.issues.length) {
1925
+ payload.issues.push(...prefixIssues(key, result.issues));
1926
+ }
1927
+ payload.value[key] = result.value;
1928
+ }));
1929
+ }
1930
+ else {
1931
+ if (result.issues.length) {
1932
+ payload.issues.push(...prefixIssues(key, result.issues));
1933
+ }
1934
+ payload.value[key] = result.value;
1935
+ }
1936
+ }
1937
+ }
1938
+ let unrecognized;
1939
+ for (const key in input) {
1940
+ if (!recordKeys.has(key)) {
1941
+ unrecognized = unrecognized ?? [];
1942
+ unrecognized.push(key);
1943
+ }
1944
+ }
1945
+ if (unrecognized && unrecognized.length > 0) {
1946
+ payload.issues.push({
1947
+ code: "unrecognized_keys",
1948
+ input,
1949
+ inst,
1950
+ keys: unrecognized,
1951
+ });
1952
+ }
1953
+ }
1954
+ else {
1955
+ payload.value = {};
1956
+ for (const key of Reflect.ownKeys(input)) {
1957
+ if (key === "__proto__")
1958
+ continue;
1959
+ let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
1960
+ if (keyResult instanceof Promise) {
1961
+ throw new Error("Async schemas not supported in object keys currently");
1962
+ }
1963
+ // Numeric string fallback: if key is a numeric string and failed, retry with Number(key)
1964
+ // This handles z.number(), z.literal([1, 2, 3]), and unions containing numeric literals
1965
+ const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
1966
+ if (checkNumericKey) {
1967
+ const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
1968
+ if (retryResult instanceof Promise) {
1969
+ throw new Error("Async schemas not supported in object keys currently");
1970
+ }
1971
+ if (retryResult.issues.length === 0) {
1972
+ keyResult = retryResult;
1973
+ }
1974
+ }
1975
+ if (keyResult.issues.length) {
1976
+ if (def.mode === "loose") {
1977
+ // Pass through unchanged
1978
+ payload.value[key] = input[key];
1979
+ }
1980
+ else {
1981
+ // Default "strict" behavior: error on invalid key
1982
+ payload.issues.push({
1983
+ code: "invalid_key",
1984
+ origin: "record",
1985
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
1986
+ input: key,
1987
+ path: [key],
1988
+ inst,
1989
+ });
1990
+ }
1991
+ continue;
1992
+ }
1993
+ const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
1994
+ if (result instanceof Promise) {
1995
+ proms.push(result.then((result) => {
1996
+ if (result.issues.length) {
1997
+ payload.issues.push(...prefixIssues(key, result.issues));
1998
+ }
1999
+ payload.value[keyResult.value] = result.value;
2000
+ }));
2001
+ }
2002
+ else {
2003
+ if (result.issues.length) {
2004
+ payload.issues.push(...prefixIssues(key, result.issues));
2005
+ }
2006
+ payload.value[keyResult.value] = result.value;
2007
+ }
2008
+ }
2009
+ }
2010
+ if (proms.length) {
2011
+ return Promise.all(proms).then(() => payload);
2012
+ }
2013
+ return payload;
2014
+ };
2015
+ });
1900
2016
  const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => {
1901
2017
  $ZodType.init(inst, def);
1902
2018
  const values = getEnumValues(def.entries);
@@ -3293,6 +3409,49 @@ const intersectionProcessor = (schema, ctx, json, params) => {
3293
3409
  ];
3294
3410
  json.allOf = allOf;
3295
3411
  };
3412
+ const recordProcessor = (schema, ctx, _json, params) => {
3413
+ const json = _json;
3414
+ const def = schema._zod.def;
3415
+ json.type = "object";
3416
+ // For looseRecord with regex patterns, use patternProperties
3417
+ // This correctly represents "only validate keys matching the pattern" semantics
3418
+ // and composes well with allOf (intersections)
3419
+ const keyType = def.keyType;
3420
+ const keyBag = keyType._zod.bag;
3421
+ const patterns = keyBag?.patterns;
3422
+ if (def.mode === "loose" && patterns && patterns.size > 0) {
3423
+ // Use patternProperties for looseRecord with regex patterns
3424
+ const valueSchema = process(def.valueType, ctx, {
3425
+ ...params,
3426
+ path: [...params.path, "patternProperties", "*"],
3427
+ });
3428
+ json.patternProperties = {};
3429
+ for (const pattern of patterns) {
3430
+ json.patternProperties[pattern.source] = valueSchema;
3431
+ }
3432
+ }
3433
+ else {
3434
+ // Default behavior: use propertyNames + additionalProperties
3435
+ if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
3436
+ json.propertyNames = process(def.keyType, ctx, {
3437
+ ...params,
3438
+ path: [...params.path, "propertyNames"],
3439
+ });
3440
+ }
3441
+ json.additionalProperties = process(def.valueType, ctx, {
3442
+ ...params,
3443
+ path: [...params.path, "additionalProperties"],
3444
+ });
3445
+ }
3446
+ // Add required for keys with discrete values (enum, literal, etc.)
3447
+ const keyValues = keyType._zod.values;
3448
+ if (keyValues) {
3449
+ const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
3450
+ if (validKeyValues.length > 0) {
3451
+ json.required = validKeyValues;
3452
+ }
3453
+ }
3454
+ };
3296
3455
  const nullableProcessor = (schema, ctx, json, params) => {
3297
3456
  const def = schema._zod.def;
3298
3457
  const inner = process(def.innerType, ctx, params);
@@ -3796,6 +3955,21 @@ function intersection(left, right) {
3796
3955
  right: right,
3797
3956
  });
3798
3957
  }
3958
+ const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => {
3959
+ $ZodRecord.init(inst, def);
3960
+ ZodType.init(inst, def);
3961
+ inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params);
3962
+ inst.keyType = def.keyType;
3963
+ inst.valueType = def.valueType;
3964
+ });
3965
+ function record(keyType, valueType, params) {
3966
+ return new ZodRecord({
3967
+ type: "record",
3968
+ keyType,
3969
+ valueType: valueType,
3970
+ ...normalizeParams(params),
3971
+ });
3972
+ }
3799
3973
  const ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => {
3800
3974
  $ZodEnum.init(inst, def);
3801
3975
  ZodType.init(inst, def);
@@ -4028,8 +4202,19 @@ const vNextOasGeneratorSchema = strictObject({
4028
4202
  unwrap: boolean().default(true),
4029
4203
  withRequestParams: boolean().default(false),
4030
4204
  pathParamsStyle: _enum(["object", "positional"]).default("positional"),
4031
- enumStyle: _enum(["enum", "union"]).default("enum")
4032
- }),
4205
+ enumStyle: _enum(["enum", "union"]).default("enum"),
4206
+ comments: strictObject({
4207
+ enabled: boolean().default(true),
4208
+ operation: strictObject({
4209
+ tags: boolean().default(true),
4210
+ summary: boolean().default(true),
4211
+ description: boolean().default(true)
4212
+ }).prefault({}),
4213
+ schema: strictObject({
4214
+ metadata: boolean().default(true)
4215
+ }).prefault({})
4216
+ }).prefault({})
4217
+ }).prefault({}),
4033
4218
  compat: strictObject({
4034
4219
  uppercaseEnumKeys: boolean(),
4035
4220
  swaggerTsApiRequiredBooleans: boolean()
@@ -4040,7 +4225,7 @@ const legacyOasGeneratorSchema = strictObject({
4040
4225
  ignoreOperationsWithTags: array(string()).optional()
4041
4226
  })
4042
4227
  });
4043
- const configSchema = strictObject({
4228
+ const profileConfigSchema = strictObject({
4044
4229
  srcSpec: string().trim().min(1),
4045
4230
  dstDir: string().trim().min(1),
4046
4231
  apiName: string().trim().min(1),
@@ -4058,6 +4243,8 @@ const configSchema = strictObject({
4058
4243
  localDateTimes: boolean().optional()
4059
4244
  }).optional()
4060
4245
  });
4246
+ const configSchema = record(string(), profileConfigSchema);
4247
+ const defineConfig = (config) => config;
4061
4248
  const parseConfig = (userConfig, filePath) => {
4062
4249
  const parsed = configSchema.safeParse(userConfig);
4063
4250
  if (parsed.success) return parsed.data;
@@ -4065,6 +4252,13 @@ const parseConfig = (userConfig, filePath) => {
4065
4252
  cause: parsed.error
4066
4253
  });
4067
4254
  };
4255
+ const parseProfileConfig = (userConfig, filePath) => {
4256
+ const parsed = profileConfigSchema.safeParse(userConfig);
4257
+ if (parsed.success) return parsed.data;
4258
+ throw new Error(`Invalid config at ${filePath}: ${parsed.error.message}`, {
4259
+ cause: parsed.error
4260
+ });
4261
+ };
4068
4262
 
4069
4263
  const downloadSpec = async (path, url) => {
4070
4264
  let response;
@@ -4085,6 +4279,34 @@ const downloadSpec = async (path, url) => {
4085
4279
  await fs$1.writeFile(path, content);
4086
4280
  };
4087
4281
 
4282
+ const EMPTY_LINE_MARKER = "/*__EMPTY_LINE_MARKER__*/";
4283
+
4284
+ var __defProp$b = Object.defineProperty;
4285
+ var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4286
+ var __publicField$b = (obj, key, value) => __defNormalProp$b(obj, key + "" , value);
4287
+ const EMPTY_LINE_MARKER_LINE = new RegExp(
4288
+ `\\n[\\t ]*${EMPTY_LINE_MARKER.replaceAll("/", "\\/").replaceAll(
4289
+ "*",
4290
+ "\\*"
4291
+ )}\\n`,
4292
+ "g"
4293
+ );
4294
+ class CodeFormatter {
4295
+ constructor(opts) {
4296
+ this.opts = opts;
4297
+ __publicField$b(this, "format", async (code) => {
4298
+ const filePath = Path.resolve(this.opts.resolveConfFrom, "generated.ts");
4299
+ const prettier = await import('prettier');
4300
+ const prettierConfig = await prettier.resolveConfig(filePath) ?? {};
4301
+ const formattedCode = await prettier.format(code, {
4302
+ ...prettierConfig,
4303
+ filepath: filePath
4304
+ });
4305
+ return formattedCode.replaceAll(EMPTY_LINE_MARKER_LINE, "\n\n");
4306
+ });
4307
+ }
4308
+ }
4309
+
4088
4310
  const toPascalCaseIdentifier = (str) => {
4089
4311
  const words = str.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean);
4090
4312
  const pascalCase = words.map((word) => word[0].toUpperCase() + word.substring(1)).join("");
@@ -4105,6 +4327,12 @@ const groupBy = (values, getKey) => {
4105
4327
  }
4106
4328
  return groups;
4107
4329
  };
4330
+ const findRelativePath = (src, dst) => {
4331
+ const relativePath = Path$1.relative(Path$1.dirname(src), dst);
4332
+ const withoutExtension = relativePath.replace(/\.ts$/u, "");
4333
+ const normalizedPath = withoutExtension.split(Path$1.sep).join("/");
4334
+ return normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`;
4335
+ };
4108
4336
 
4109
4337
  const generateOpenApiClient = async (inputFile, {
4110
4338
  name,
@@ -4113,7 +4341,7 @@ const generateOpenApiClient = async (inputFile, {
4113
4341
  }, log) => {
4114
4342
  log(`Will generate API client name=${name} to ${outputDir}`);
4115
4343
  const fileName = "index";
4116
- const dstFile = Path.join(outputDir, `${fileName}.ts`);
4344
+ const dstFile = Path$1.join(outputDir, `${fileName}.ts`);
4117
4345
  const prettier = await import('prettier');
4118
4346
  const prettierConfig = await prettier.resolveConfig(dstFile) ?? {};
4119
4347
  const prettierConfigForGenerator = {
@@ -4157,12 +4385,12 @@ const generateOpenApiClient = async (inputFile, {
4157
4385
  return { types: dstFile, promiseWrapper: [dstFile] };
4158
4386
  };
4159
4387
  const getThisScriptDirname = () => {
4160
- return Path.dirname(fileURLToPath(import.meta.url));
4388
+ return Path$1.dirname(fileURLToPath(import.meta.url));
4161
4389
  };
4162
4390
  const getTemplatesDir = () => {
4163
4391
  const currentDir = getThisScriptDirname();
4164
- const templatesRelativePath = Path.basename(currentDir) === "dist" ? "../templates" : "../../../templates";
4165
- return Path.resolve(currentDir, templatesRelativePath);
4392
+ const templatesRelativePath = Path$1.basename(currentDir) === "dist" ? "../templates" : "../../../templates";
4393
+ return Path$1.resolve(currentDir, templatesRelativePath);
4166
4394
  };
4167
4395
 
4168
4396
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -4219,9 +4447,9 @@ const resolveLocalRef = (root, ref) => {
4219
4447
  return current;
4220
4448
  };
4221
4449
 
4222
- var __defProp$9 = Object.defineProperty;
4223
- var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4224
- var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, key + "" , value);
4450
+ var __defProp$a = Object.defineProperty;
4451
+ var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4452
+ var __publicField$a = (obj, key, value) => __defNormalProp$a(obj, key + "" , value);
4225
4453
  const PARAMETER_LOCATIONS = [
4226
4454
  "path",
4227
4455
  "query",
@@ -4247,7 +4475,7 @@ const mergeParameters = (base, override) => {
4247
4475
  class OpenApiNormalizer {
4248
4476
  constructor(doc) {
4249
4477
  this.doc = doc;
4250
- __publicField$9(this, "problems", []);
4478
+ __publicField$a(this, "problems", []);
4251
4479
  }
4252
4480
  load() {
4253
4481
  const info = readRecord(this.doc, "info");
@@ -4590,23 +4818,24 @@ const syntheticOperationId = (method, path) => {
4590
4818
  return `_${compact}`;
4591
4819
  };
4592
4820
 
4593
- var __defProp$8 = Object.defineProperty;
4594
- var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4595
- var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
4821
+ var __defProp$9 = Object.defineProperty;
4822
+ var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4823
+ var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
4596
4824
  class TsCodegen {
4597
- constructor(typeExprCodegen) {
4825
+ constructor(typeExprCodegen, docRenderer) {
4598
4826
  this.typeExprCodegen = typeExprCodegen;
4599
- __publicField$8(this, "usedTypeRefs", []);
4600
- __publicField$8(this, "usedTypeRefKeys", /* @__PURE__ */ new Set());
4601
- __publicField$8(this, "typeExpr", (typeExpr) => {
4827
+ __publicField$9(this, "usedTypeRefs", []);
4828
+ __publicField$9(this, "usedTypeRefKeys", /* @__PURE__ */ new Set());
4829
+ __publicField$9(this, "docRenderer");
4830
+ __publicField$9(this, "typeExpr", (typeExpr) => {
4602
4831
  this.collectTypeRefsFromExpr(typeExpr);
4603
4832
  return this.typeExprCodegen.toCode(typeExpr).code;
4604
4833
  });
4605
- __publicField$8(this, "declaration", (name, declaration) => {
4834
+ __publicField$9(this, "declaration", (name, declaration, options = {}) => {
4606
4835
  this.collectTypeRefsFromDeclaration(declaration);
4607
- return this.toDeclarationCode(name, declaration);
4836
+ return this.toDeclarationCode(name, declaration, options);
4608
4837
  });
4609
- __publicField$8(this, "toChunk", (name, code, exports$1) => {
4838
+ __publicField$9(this, "toChunk", (name, code, exports$1) => {
4610
4839
  const exportedSymbols = new Set(exports$1);
4611
4840
  const refs = this.getTypeRefs().filter((ref) => {
4612
4841
  return ref.kind !== "internal" || !exportedSymbols.has(ref.name);
@@ -4618,17 +4847,25 @@ class TsCodegen {
4618
4847
  refs
4619
4848
  };
4620
4849
  });
4621
- __publicField$8(this, "getTypeRefs", () => {
4850
+ __publicField$9(this, "getTypeRefs", () => {
4622
4851
  return this.usedTypeRefs.map((ref) => ({ ...ref }));
4623
4852
  });
4624
- __publicField$8(this, "toDeclarationCode", (name, declaration) => {
4853
+ __publicField$9(this, "toDeclarationCode", (name, d, o) => {
4854
+ let code = this.toDeclarationBodyCode(name, d);
4855
+ if (o.exported) {
4856
+ code = `export ${code}`;
4857
+ }
4858
+ return this.addDoc(code, d.doc);
4859
+ });
4860
+ __publicField$9(this, "toDeclarationBodyCode", (name, declaration) => {
4625
4861
  switch (declaration.kind) {
4626
4862
  case "typeAlias":
4627
4863
  return `type ${name} = ${this.typeExprCodegen.toCode(declaration.typeExpr).code}`;
4628
4864
  case "enum": {
4629
- const members = declaration.members.map(
4630
- (member) => ` ${member.name} = ${JSON.stringify(member.value)}`
4631
- ).join(",\n");
4865
+ const members = declaration.members.map((member) => {
4866
+ const code = `${member.name} = ${JSON.stringify(member.value)}`;
4867
+ return this.addDoc(code, member.doc);
4868
+ }).join(",\n");
4632
4869
  return `enum ${name} {
4633
4870
  ${members}
4634
4871
  }`;
@@ -4641,6 +4878,13 @@ ${members}
4641
4878
  }
4642
4879
  }
4643
4880
  });
4881
+ __publicField$9(this, "addDoc", (code, doc) => {
4882
+ if (!doc) return code;
4883
+ const rendered = this.docRenderer.render(doc);
4884
+ return rendered ? `${rendered}
4885
+ ${code}` : code;
4886
+ });
4887
+ this.docRenderer = docRenderer;
4644
4888
  }
4645
4889
  collectTypeRef(typeRef) {
4646
4890
  if (typeRef.kind === "builtin") return;
@@ -4766,12 +5010,13 @@ const toTsPropertyKey = (value) => {
4766
5010
  return isTsIdentifier(value) ? value : JSON.stringify(value);
4767
5011
  };
4768
5012
 
4769
- var __defProp$7 = Object.defineProperty;
4770
- var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4771
- var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
5013
+ var __defProp$8 = Object.defineProperty;
5014
+ var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5015
+ var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
4772
5016
  class TypeExprCodegen {
4773
- constructor() {
4774
- __publicField$7(this, "toCode", (typeExpr) => {
5017
+ constructor(docRenderer) {
5018
+ __publicField$8(this, "docRenderer");
5019
+ __publicField$8(this, "toCode", (typeExpr) => {
4775
5020
  switch (typeExpr.kind) {
4776
5021
  case "reference":
4777
5022
  return this.toReferenceCode(typeExpr);
@@ -4787,7 +5032,7 @@ class TypeExprCodegen {
4787
5032
  }
4788
5033
  }
4789
5034
  });
4790
- __publicField$7(this, "toReferenceCode", (typeExpr) => {
5035
+ __publicField$8(this, "toReferenceCode", (typeExpr) => {
4791
5036
  if (!typeExpr.typeArgs?.length) {
4792
5037
  return {
4793
5038
  code: typeExpr.ref.name,
@@ -4800,7 +5045,7 @@ class TypeExprCodegen {
4800
5045
  ref: typeExpr.ref
4801
5046
  };
4802
5047
  });
4803
- __publicField$7(this, "toInlineCode", (expr) => {
5048
+ __publicField$8(this, "toInlineCode", (expr) => {
4804
5049
  switch (expr.node) {
4805
5050
  case "scalar":
4806
5051
  return expr.name === "integer" ? "number" : expr.name;
@@ -4825,55 +5070,66 @@ class TypeExprCodegen {
4825
5070
  }
4826
5071
  }
4827
5072
  });
4828
- __publicField$7(this, "toIntersectionMemberCode", (typeExpr) => {
5073
+ __publicField$8(this, "toIntersectionMemberCode", (typeExpr) => {
4829
5074
  const rendered = this.toCode(typeExpr).code;
4830
5075
  return this.isUnion(typeExpr) ? `(${rendered})` : rendered;
4831
5076
  });
4832
- __publicField$7(this, "toArrayElementCode", (typeExpr) => {
5077
+ __publicField$8(this, "toArrayElementCode", (typeExpr) => {
4833
5078
  const rendered = this.toCode(typeExpr).code;
4834
5079
  return this.needsGroupingForArrayElement(typeExpr) ? `(${rendered})` : rendered;
4835
5080
  });
4836
- __publicField$7(this, "isUnion", (typeExpr) => {
5081
+ __publicField$8(this, "isUnion", (typeExpr) => {
4837
5082
  return typeExpr.kind === "inline" && typeExpr.expr.node === "union";
4838
5083
  });
4839
- __publicField$7(this, "needsGroupingForArrayElement", (typeExpr) => {
5084
+ __publicField$8(this, "needsGroupingForArrayElement", (typeExpr) => {
4840
5085
  return typeExpr.kind === "inline" && (typeExpr.expr.node === "union" || typeExpr.expr.node === "intersection");
4841
5086
  });
4842
- __publicField$7(this, "toLiteralCode", (value) => {
5087
+ __publicField$8(this, "toLiteralCode", (value) => {
4843
5088
  if (value === null) return "null";
4844
5089
  return JSON.stringify(value);
4845
5090
  });
4846
- __publicField$7(this, "toObjectCode", (properties, additionalProperties) => {
5091
+ __publicField$8(this, "toObjectCode", (properties, additionalProperties) => {
4847
5092
  const members = properties.map(
4848
5093
  (property) => this.toPropertyCode(property)
4849
5094
  );
4850
5095
  if (additionalProperties === true) {
4851
- members.push("[key: string]: unknown");
5096
+ members.push("[key: string]: unknown;");
4852
5097
  } else if (additionalProperties !== void 0 && additionalProperties !== false) {
4853
5098
  members.push(
4854
- `[key: string]: ${this.toCode(additionalProperties).code}`
5099
+ `[key: string]: ${this.toCode(additionalProperties).code};`
4855
5100
  );
4856
5101
  }
4857
- if (!members.length) return "{}";
4858
- return `{ ${members.join("; ")} }`;
5102
+ return `{
5103
+ ${members.join("\n")}
5104
+ }`;
4859
5105
  });
4860
- __publicField$7(this, "toPropertyCode", (property) => {
5106
+ __publicField$8(this, "toPropertyCode", (property) => {
4861
5107
  const name = toTsPropertyKey(property.name);
4862
5108
  const optional = property.required ? "" : "?";
4863
- return `${name}${optional}: ${this.toCode(property.typeExpr).code}`;
4864
- });
5109
+ const propertyCode = `${name}${optional}: ${this.toCode(property.typeExpr).code}`;
5110
+ const docCode = property.doc ? this.docRenderer.render(property.doc, {
5111
+ compactText: true
5112
+ }) : "";
5113
+ const renderedProperty = `${propertyCode};`;
5114
+ return docCode ? `${docCode}
5115
+ ${renderedProperty}` : renderedProperty;
5116
+ });
5117
+ this.docRenderer = docRenderer;
4865
5118
  }
4866
5119
  }
4867
5120
 
4868
- var __defProp$6 = Object.defineProperty;
4869
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4870
- var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
5121
+ var __defProp$7 = Object.defineProperty;
5122
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5123
+ var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
4871
5124
  class TsCodegenFactory {
4872
- constructor() {
4873
- __publicField$6(this, "typeExprCodegen", new TypeExprCodegen());
4874
- __publicField$6(this, "forNewChunk", () => {
4875
- return new TsCodegen(this.typeExprCodegen);
4876
- });
5125
+ constructor(docRenderer) {
5126
+ __publicField$7(this, "typeExprCodegen");
5127
+ __publicField$7(this, "docRenderer");
5128
+ __publicField$7(this, "forNewChunk", () => {
5129
+ return new TsCodegen(this.typeExprCodegen, this.docRenderer);
5130
+ });
5131
+ this.docRenderer = docRenderer;
5132
+ this.typeExprCodegen = new TypeExprCodegen(this.docRenderer);
4877
5133
  }
4878
5134
  }
4879
5135
 
@@ -4922,13 +5178,13 @@ const isReservedWord = (value) => {
4922
5178
  return RESERVED_WORDS.has(value);
4923
5179
  };
4924
5180
 
4925
- var __defProp$5 = Object.defineProperty;
4926
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4927
- var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
5181
+ var __defProp$6 = Object.defineProperty;
5182
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5183
+ var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
4928
5184
  class ParamsConstructor {
4929
5185
  constructor(options) {
4930
5186
  this.options = options;
4931
- __publicField$5(this, "process", (params, httpPath) => {
5187
+ __publicField$6(this, "process", (params, httpPath) => {
4932
5188
  const pathParamSpec = validatePathParams(params, httpPath);
4933
5189
  const pathParamBindings = pathParamSpec?.bindings;
4934
5190
  const funParams = params.flatMap(
@@ -4948,7 +5204,7 @@ class ParamsConstructor {
4948
5204
  hasQuery
4949
5205
  };
4950
5206
  });
4951
- __publicField$5(this, "renderOperationParams", (param, pathParamSpec) => {
5207
+ __publicField$6(this, "renderOperationParams", (param, pathParamSpec) => {
4952
5208
  if (param.kind !== "path" || !pathParamSpec) {
4953
5209
  return [
4954
5210
  {
@@ -4972,7 +5228,7 @@ class ParamsConstructor {
4972
5228
  }
4973
5229
  ];
4974
5230
  });
4975
- __publicField$5(this, "renderPathTemplateLiteral", (path, pathParamVarName, pathParamBindings) => {
5231
+ __publicField$6(this, "renderPathTemplateLiteral", (path, pathParamVarName, pathParamBindings) => {
4976
5232
  const escapedPath = path.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
4977
5233
  const pathWithParams = escapedPath.replace(
4978
5234
  /\{([^}]+)\}/g,
@@ -4986,7 +5242,7 @@ class ParamsConstructor {
4986
5242
  );
4987
5243
  return `\`${pathWithParams}\``;
4988
5244
  });
4989
- __publicField$5(this, "renderPathParamDestructuring", (pathParamBindings) => {
5245
+ __publicField$6(this, "renderPathParamDestructuring", (pathParamBindings) => {
4990
5246
  const members = Object.entries(pathParamBindings).map(
4991
5247
  ([paramName, binding]) => {
4992
5248
  const key = toTsPropertyKey(paramName);
@@ -4995,7 +5251,7 @@ class ParamsConstructor {
4995
5251
  );
4996
5252
  return `{ ${members.join(", ")} }`;
4997
5253
  });
4998
- __publicField$5(this, "paramName", (p) => {
5254
+ __publicField$6(this, "paramName", (p) => {
4999
5255
  switch (p.kind) {
5000
5256
  case "body":
5001
5257
  return this.options.paramNames.body;
@@ -5107,19 +5363,25 @@ const validatePathParams = (params, httpPath) => {
5107
5363
  };
5108
5364
  };
5109
5365
 
5110
- const EMPTY_LINE_MARKER = "/*__EMPTY_LINE_MARKER__*/";
5366
+ const indentBlock = (value, indent) => {
5367
+ if (!value || !indent) {
5368
+ return value;
5369
+ }
5370
+ return value.split("\n").map((line) => `${indent}${line}`).join("\n");
5371
+ };
5111
5372
 
5112
- var __defProp$4 = Object.defineProperty;
5113
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5114
- var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
5373
+ var __defProp$5 = Object.defineProperty;
5374
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5375
+ var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
5115
5376
  const REQUEST_PARAMS_TYPE = "RequestParams";
5116
5377
  const REQUEST_PARAMS_DEFAULT = "never";
5117
5378
  const REQUEST_PARAMS_ARG = "params";
5118
5379
  class ApiClientCodegen {
5119
- constructor(opts, tsCodegenFactory) {
5380
+ constructor(opts, tsCodegenFactory, docRenderer) {
5120
5381
  this.opts = opts;
5121
5382
  this.tsCodegenFactory = tsCodegenFactory;
5122
- __publicField$4(this, "generate", (apiName, operations) => {
5383
+ this.docRenderer = docRenderer;
5384
+ __publicField$5(this, "generate", (apiName, operations, doc) => {
5123
5385
  const tsCodegen = this.tsCodegenFactory.forNewChunk();
5124
5386
  const httpClientType = tsCodegen.typeExpr(this.opts.httpClient.typeName);
5125
5387
  let clientType = httpClientType;
@@ -5129,16 +5391,18 @@ class ApiClientCodegen {
5129
5391
  classTypeParams = `<${REQUEST_PARAMS_TYPE} = ${REQUEST_PARAMS_DEFAULT}>`;
5130
5392
  }
5131
5393
  const methodsCode = Array.isArray(operations) ? this.opsCode(tsCodegen, operations) : this.groupsOpsCode(tsCodegen, operations);
5394
+ const classDocCode = this.renderApiClientDoc(doc, "");
5132
5395
  const code = `
5133
- export class ${apiName}${classTypeParams} {
5134
- constructor(private readonly client: ${clientType}) {}
5396
+ ${classDocCode ? `${classDocCode}
5397
+ ` : ""}export class ${apiName}${classTypeParams} {
5398
+ constructor(private readonly http: ${clientType}) {}
5135
5399
 
5136
5400
  ${methodsCode}
5137
5401
  }
5138
5402
  `;
5139
5403
  return tsCodegen.toChunk("api", code, [apiName]);
5140
5404
  });
5141
- __publicField$4(this, "groupsOpsCode", (codegen, groupedOps) => Object.entries(groupedOps).map(([groupName, ops]) => {
5405
+ __publicField$5(this, "groupsOpsCode", (codegen, groupedOps) => Object.entries(groupedOps).map(([groupName, ops]) => {
5142
5406
  const methodsCode = this.opsCode(codegen, ops, "object");
5143
5407
  return `
5144
5408
  ${toTsPropertyKey(groupName)} = {
@@ -5146,14 +5410,14 @@ class ApiClientCodegen {
5146
5410
  }
5147
5411
  `;
5148
5412
  }).join("\n\n"));
5149
- __publicField$4(this, "opsCode", (codegen, operations, target = "class") => {
5413
+ __publicField$5(this, "opsCode", (codegen, operations, target = "class") => {
5150
5414
  const separator = target === "object" ? `,
5151
5415
  ${EMPTY_LINE_MARKER}
5152
5416
  ` : "\n\n";
5153
5417
  const methodsCode = operations.map((op) => this.renderOp(op, codegen, target)).join(separator);
5154
5418
  return methodsCode;
5155
5419
  });
5156
- __publicField$4(this, "renderOp", (op, tsCodegen, target) => {
5420
+ __publicField$5(this, "renderOp", (op, tsCodegen, target) => {
5157
5421
  const { signature: sig, http } = op;
5158
5422
  const invocationVars = this.opts.httpClient.invocation.vars;
5159
5423
  const paramNames = {
@@ -5179,6 +5443,7 @@ ${EMPTY_LINE_MARKER}
5179
5443
  const responseType = tsCodegen.typeExpr(sig.returnType);
5180
5444
  const returnType = this.wrapInResponseWrapper(sig.returnType, tsCodegen);
5181
5445
  return this.renderFunctionCode({
5446
+ doc: sig.doc,
5182
5447
  funName: sig.name,
5183
5448
  responseType,
5184
5449
  returnType,
@@ -5194,13 +5459,14 @@ ${EMPTY_LINE_MARKER}
5194
5459
  target
5195
5460
  });
5196
5461
  });
5197
- __publicField$4(this, "wrapInResponseWrapper", (typeExpr, tsCodegen) => {
5462
+ __publicField$5(this, "wrapInResponseWrapper", (typeExpr, tsCodegen) => {
5198
5463
  return tsCodegen.typeExpr({
5199
5464
  ...this.opts.httpClient.responseWrapper,
5200
5465
  typeArgs: [typeExpr]
5201
5466
  });
5202
5467
  });
5203
- __publicField$4(this, "renderFunctionCode", ({
5468
+ __publicField$5(this, "renderFunctionCode", ({
5469
+ doc,
5204
5470
  funName,
5205
5471
  responseType,
5206
5472
  returnType,
@@ -5232,9 +5498,74 @@ ${EMPTY_LINE_MARKER}
5232
5498
  invocation = invocation.replaceAll("\n", "");
5233
5499
  const operator = target === "object" ? ":" : "=";
5234
5500
  const returnTypeCode = this.opts.httpClient.inferMethodReturnType ? "" : `:${returnType}`;
5235
- return `${funName} ${operator} (${params})${returnTypeCode} =>
5236
- this.client${invocation}
5501
+ const functionCode = `${funName} ${operator} (${params})${returnTypeCode} =>
5502
+ this.http${invocation}
5237
5503
  `;
5504
+ const docCode = this.renderOperationDoc(
5505
+ doc,
5506
+ this.opts.comments,
5507
+ target === "object" ? " " : " "
5508
+ );
5509
+ return docCode ? `${docCode}
5510
+ ${functionCode}` : functionCode;
5511
+ });
5512
+ __publicField$5(this, "renderOperationDoc", (doc, comments, indent = "") => {
5513
+ if (!doc) return null;
5514
+ return indentBlock(this.docRenderer.render(this.toTsDoc(doc)), indent);
5515
+ });
5516
+ __publicField$5(this, "renderApiClientDoc", (doc, indent = "") => {
5517
+ if (!doc) return "";
5518
+ return indentBlock(
5519
+ this.docRenderer.render({
5520
+ nodes: [
5521
+ {
5522
+ key: "title",
5523
+ value: doc.title
5524
+ },
5525
+ {
5526
+ key: "version",
5527
+ value: doc.version
5528
+ },
5529
+ ...doc.description ? [doc.description] : []
5530
+ ]
5531
+ }),
5532
+ indent
5533
+ );
5534
+ });
5535
+ __publicField$5(this, "toTsDoc", (doc) => {
5536
+ const nodes = [
5537
+ {
5538
+ key: "id",
5539
+ value: doc.id
5540
+ }
5541
+ ];
5542
+ const comms = this.opts.comments;
5543
+ if ((comms.summary ?? true) && doc.summary) {
5544
+ nodes.push({
5545
+ key: "summary",
5546
+ value: doc.summary
5547
+ });
5548
+ }
5549
+ if ((comms.description ?? true) && doc.description) {
5550
+ nodes.push({
5551
+ key: "description",
5552
+ value: doc.description
5553
+ });
5554
+ }
5555
+ nodes.push({
5556
+ key: "request",
5557
+ value: doc.request
5558
+ });
5559
+ if ((comms.tags ?? true) && doc.tags.length) {
5560
+ nodes.push({
5561
+ key: "tags",
5562
+ value: doc.tags.join(", ")
5563
+ });
5564
+ }
5565
+ return {
5566
+ deprecated: doc.deprecated,
5567
+ nodes
5568
+ };
5238
5569
  });
5239
5570
  }
5240
5571
  }
@@ -5403,21 +5734,102 @@ const provideHttpClientCode = (gen, opts) => gen.toChunk(
5403
5734
  ["HttpRequest", "HttpResponse", "HttpClient"]
5404
5735
  );
5405
5736
 
5737
+ var __defProp$4 = Object.defineProperty;
5738
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5739
+ var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
5740
+ class TsDocRenderer {
5741
+ constructor(options) {
5742
+ this.options = options;
5743
+ __publicField$4(this, "render", (doc, options = {}) => {
5744
+ if (!this.options.enabled) return "";
5745
+ const lines = [];
5746
+ this.appendNodes(lines, doc.nodes, options);
5747
+ if (doc.deprecated) {
5748
+ this.appendDeprecated(lines, { separate: lines.length > 0 });
5749
+ }
5750
+ return this.renderComment(lines);
5751
+ });
5752
+ __publicField$4(this, "renderComment", (lines) => {
5753
+ if (!this.options.enabled) return "";
5754
+ if (!lines.length) return "";
5755
+ if (lines.length === 1) {
5756
+ return `/** ${lines[0]} */`;
5757
+ }
5758
+ const body = lines.map((line) => line ? ` * ${line}` : " *").join("\n");
5759
+ return `/**
5760
+ ${body}
5761
+ */`;
5762
+ });
5763
+ __publicField$4(this, "appendDocText", (lines, value) => {
5764
+ const normalized = this.normalizeLines(value);
5765
+ if (!normalized.length) return;
5766
+ if (lines.length > 0) {
5767
+ lines.push("");
5768
+ }
5769
+ lines.push(...normalized);
5770
+ });
5771
+ __publicField$4(this, "appendField", (lines, key, value) => {
5772
+ const normalized = this.normalizeLines(value);
5773
+ if (!normalized.length) return;
5774
+ lines.push(`@${key} ${normalized[0]}`.trimEnd());
5775
+ lines.push(...normalized.slice(1));
5776
+ });
5777
+ __publicField$4(this, "appendDeprecated", (lines, options) => {
5778
+ if (options.separate) {
5779
+ lines.push("");
5780
+ }
5781
+ lines.push("@deprecated");
5782
+ });
5783
+ __publicField$4(this, "appendNodes", (lines, nodes = [], options = {}) => {
5784
+ nodes.forEach((node) => {
5785
+ if (typeof node === "string") {
5786
+ if (options.compactText) {
5787
+ lines.push(...this.normalizeNonEmptyLines(node));
5788
+ return;
5789
+ }
5790
+ this.appendDocText(lines, node);
5791
+ return;
5792
+ }
5793
+ this.appendField(lines, node.key, node.value);
5794
+ });
5795
+ });
5796
+ __publicField$4(this, "normalizeLines", (value) => {
5797
+ const trimmed = value?.trim();
5798
+ if (!trimmed) return [];
5799
+ return trimmed.split(/\r?\n/u).map((line) => line.trimEnd().replaceAll("*/", "*\\/"));
5800
+ });
5801
+ __publicField$4(this, "normalizeNonEmptyLines", (value) => this.normalizeLines(value).filter((line) => line.length > 0));
5802
+ }
5803
+ }
5804
+
5406
5805
  const generateTsCode = (clientName, projectResult, opts) => {
5407
- const tsCodegenFac = new TsCodegenFactory();
5806
+ const docRenderer = new TsDocRenderer({
5807
+ enabled: opts.comments.enabled
5808
+ });
5809
+ const tsCodegenFac = new TsCodegenFactory(docRenderer);
5408
5810
  const { schemaDefinitions } = projectResult;
5409
5811
  const types = [...schemaDefinitions].sort((a, b) => a.name.localeCompare(b.name)).map((def) => {
5410
5812
  const cg = tsCodegenFac.forNewChunk();
5411
- const code = `export ${cg.declaration(def.name, def.declaration)}`;
5813
+ const code = cg.declaration(def.name, def.declaration, {
5814
+ exported: true
5815
+ });
5412
5816
  return cg.toChunk(def.name, code, [def.name]);
5413
5817
  });
5414
5818
  const clientCodegen = new ApiClientCodegen(
5415
- { httpClient: promiseHttpClientCodegenSpec(), ...opts },
5416
- tsCodegenFac
5819
+ {
5820
+ httpClient: promiseHttpClientCodegenSpec(),
5821
+ comments: opts.comments.operation,
5822
+ unwrap: opts.unwrap,
5823
+ pathParamsStyle: opts.pathParamsStyle,
5824
+ withRequestParams: opts.withRequestParams
5825
+ },
5826
+ tsCodegenFac,
5827
+ docRenderer
5417
5828
  );
5418
5829
  const generated = clientCodegen.generate(
5419
5830
  clientName,
5420
- groupsOpsByTag(projectResult.operations)
5831
+ groupsOpsByTag(projectResult.operations),
5832
+ projectResult.api
5421
5833
  );
5422
5834
  const clientChunk = {
5423
5835
  ...generated,
@@ -5627,6 +6039,7 @@ class ToTypeExprConverter {
5627
6039
  }
5628
6040
  return {
5629
6041
  kind: "typeAlias",
6042
+ doc: this.getSchemaDoc(schema),
5630
6043
  typeExpr: this.fromTypeExpr(schema)
5631
6044
  };
5632
6045
  });
@@ -5640,6 +6053,7 @@ class ToTypeExprConverter {
5640
6053
  }
5641
6054
  return {
5642
6055
  kind: "enum",
6056
+ doc: this.getSchemaDoc(schema),
5643
6057
  valueType,
5644
6058
  members: this.toEnumMembers(schema.enum)
5645
6059
  };
@@ -5755,6 +6169,7 @@ class ToTypeExprConverter {
5755
6169
  );
5756
6170
  }
5757
6171
  return {
6172
+ doc: this.getSchemaDoc(propertySchema),
5758
6173
  name,
5759
6174
  required: this.isRequiredProperty(
5760
6175
  name,
@@ -5815,6 +6230,71 @@ class ToTypeExprConverter {
5815
6230
  __publicField$3(this, "isBinaryFileSchema", (schema) => {
5816
6231
  return schema.type === "string" && schema.format === "binary";
5817
6232
  });
6233
+ __publicField$3(this, "getSchemaDoc", (schema) => {
6234
+ const summary = typeof schema.summary === "string" ? schema.summary : void 0;
6235
+ const description = typeof schema.description === "string" ? schema.description : void 0;
6236
+ const deprecated = typeof schema.deprecated === "boolean" ? schema.deprecated : void 0;
6237
+ const annotations = this.getSchemaAnnotations(schema);
6238
+ if (!summary && !description && !deprecated && !annotations.length) {
6239
+ return void 0;
6240
+ }
6241
+ const nodes = [];
6242
+ if (summary) {
6243
+ nodes.push(summary);
6244
+ }
6245
+ if (description) {
6246
+ nodes.push(description);
6247
+ }
6248
+ nodes.push(...annotations);
6249
+ return {
6250
+ deprecated,
6251
+ nodes
6252
+ };
6253
+ });
6254
+ __publicField$3(this, "getSchemaAnnotations", (schema) => {
6255
+ if (this.options.comments?.metadata === false) return [];
6256
+ return [
6257
+ this.annotationNode("format", schema.format),
6258
+ this.annotationNode("min", schema.minimum),
6259
+ this.annotationNode("multipleOf", schema.multipleOf),
6260
+ this.annotationNode("exclusiveMin", schema.exclusiveMinimum),
6261
+ this.annotationNode("max", schema.maximum),
6262
+ this.annotationNode("minLength", schema.minLength),
6263
+ this.annotationNode("maxLength", schema.maxLength),
6264
+ this.annotationNode("exclusiveMax", schema.exclusiveMaximum),
6265
+ this.annotationNode("maxItems", schema.maxItems),
6266
+ this.annotationNode("minItems", schema.minItems),
6267
+ this.annotationNode("uniqueItems", schema.uniqueItems),
6268
+ this.annotationNode(
6269
+ "default",
6270
+ this.stringifyAnnotationValue(schema.default)
6271
+ ),
6272
+ this.annotationNode("pattern", schema.pattern),
6273
+ this.annotationNode(
6274
+ "example",
6275
+ this.stringifyAnnotationValue(schema.example)
6276
+ )
6277
+ ].filter(
6278
+ (value) => value !== void 0
6279
+ );
6280
+ });
6281
+ __publicField$3(this, "annotationNode", (name, value) => {
6282
+ if (value === void 0) return void 0;
6283
+ return {
6284
+ key: name,
6285
+ value: String(value)
6286
+ };
6287
+ });
6288
+ __publicField$3(this, "stringifyAnnotationValue", (value) => {
6289
+ if (value === void 0) return void 0;
6290
+ if (value && typeof value === "object") {
6291
+ return JSON.stringify(value);
6292
+ }
6293
+ if (typeof value === "string") {
6294
+ return JSON.stringify(value);
6295
+ }
6296
+ return String(value);
6297
+ });
5818
6298
  __publicField$3(this, "fromSchemaCore", (schema) => {
5819
6299
  if (this.isUnconstrainedSchema(schema)) {
5820
6300
  return this.scalar("unknown");
@@ -6001,6 +6481,11 @@ class OperationProjector {
6001
6481
  return this.projectOne(operationName, operation);
6002
6482
  });
6003
6483
  return {
6484
+ api: {
6485
+ title: openApi.info.title,
6486
+ version: openApi.info.version,
6487
+ description: openApi.info.description
6488
+ },
6004
6489
  operations,
6005
6490
  schemaDefinitions: this.typeExprConverter.getSchemaDefinitions()
6006
6491
  };
@@ -6017,6 +6502,7 @@ class OperationProjector {
6017
6502
  return {
6018
6503
  op: {
6019
6504
  signature: {
6505
+ doc: this.toOperationDoc(operationName, operation),
6020
6506
  name: operationName,
6021
6507
  parameters,
6022
6508
  returnType: this.projectReturnType(operation)
@@ -6065,6 +6551,7 @@ class OperationProjector {
6065
6551
  });
6066
6552
  __publicField$2(this, "projectParameterGroupTypeExpr", (params) => {
6067
6553
  const properties = Object.entries(params).map(([name, parameter]) => ({
6554
+ doc: this.toParameterDoc(parameter),
6068
6555
  name,
6069
6556
  required: parameter.required,
6070
6557
  typeExpr: this.typeExprConverter.fromTypeExpr(
@@ -6137,45 +6624,38 @@ class OperationProjector {
6137
6624
  __publicField$2(this, "selectResponseSchema", (response) => {
6138
6625
  return getPreferredMediaTypeEntry(response.content).media?.schema;
6139
6626
  });
6627
+ __publicField$2(this, "toParameterDoc", (parameter) => {
6628
+ if (!parameter.description && !parameter.deprecated) {
6629
+ return void 0;
6630
+ }
6631
+ return {
6632
+ deprecated: parameter.deprecated,
6633
+ nodes: parameter.description ? [parameter.description] : []
6634
+ };
6635
+ });
6636
+ __publicField$2(this, "toOperationDoc", (operationName, operation) => {
6637
+ return {
6638
+ id: operationName,
6639
+ request: `${toHttpMethodUpper(operation.method)}:${operation.path}`,
6640
+ summary: operation.summary,
6641
+ description: operation.description,
6642
+ deprecated: operation.deprecated,
6643
+ tags: operation.tags.map((tag) => tag.trim()).filter(Boolean)
6644
+ };
6645
+ });
6140
6646
  }
6141
6647
  }
6142
6648
 
6143
6649
  var __defProp$1 = Object.defineProperty;
6144
6650
  var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6145
- var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, key + "" , value);
6146
- const EMPTY_LINE_MARKER_LINE = new RegExp(
6147
- `\\n[\\t ]*${EMPTY_LINE_MARKER.replaceAll("/", "\\/").replaceAll(
6148
- "*",
6149
- "\\*"
6150
- )}\\n`,
6151
- "g"
6152
- );
6153
- class CodeFormatter {
6154
- constructor(opts) {
6155
- this.opts = opts;
6156
- __publicField$1(this, "format", async (code) => {
6157
- const filePath = Path$1.resolve(this.opts.resolveConfFrom, "generated.ts");
6158
- const prettier = await import('prettier');
6159
- const prettierConfig = await prettier.resolveConfig(filePath) ?? {};
6160
- const formattedCode = await prettier.format(code, {
6161
- ...prettierConfig,
6162
- filepath: filePath
6163
- });
6164
- return formattedCode.replaceAll(EMPTY_LINE_MARKER_LINE, "\n\n");
6165
- });
6166
- }
6167
- }
6168
-
6169
- var __defProp = Object.defineProperty;
6170
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6171
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6651
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
6172
6652
  class CodeWriter {
6173
6653
  constructor(formatter) {
6174
6654
  this.formatter = formatter;
6175
- __publicField(this, "symbolChunkMap", /* @__PURE__ */ new Map());
6176
- __publicField(this, "write", async (dir, chunks) => {
6655
+ __publicField$1(this, "symbolChunkMap", /* @__PURE__ */ new Map());
6656
+ __publicField$1(this, "write", async (dir, chunks) => {
6177
6657
  this.symbolChunkMap = this.createSymbolChunkMap(chunks);
6178
- fs$2.mkdirSync(dir, { recursive: true });
6658
+ fs__default.mkdirSync(dir, { recursive: true });
6179
6659
  for (const chunk of chunks) {
6180
6660
  const imports = this.collectImports(chunk);
6181
6661
  const importStatements = this.genImportStatements(imports);
@@ -6185,10 +6665,10 @@ class CodeWriter {
6185
6665
  let code = importCode + chunk.code;
6186
6666
  code = await this.formatter.format(code);
6187
6667
  code = ensureSingleTrailingNewline(code);
6188
- fs$2.writeFileSync(`${dir}/${chunk.name}.ts`, code, "utf8");
6668
+ fs__default.writeFileSync(`${dir}/${chunk.name}.ts`, code, "utf8");
6189
6669
  }
6190
6670
  });
6191
- __publicField(this, "createSymbolChunkMap", (chunks) => {
6671
+ __publicField$1(this, "createSymbolChunkMap", (chunks) => {
6192
6672
  const map = /* @__PURE__ */ new Map();
6193
6673
  for (const chunk of chunks) {
6194
6674
  for (const exportedSymbol of chunk.exports) {
@@ -6202,7 +6682,7 @@ class CodeWriter {
6202
6682
  }
6203
6683
  return map;
6204
6684
  });
6205
- __publicField(this, "collectImports", (chunk) => {
6685
+ __publicField$1(this, "collectImports", (chunk) => {
6206
6686
  const imports = [];
6207
6687
  for (const ref of chunk.refs) {
6208
6688
  if (ref.kind === "builtin") continue;
@@ -6225,7 +6705,7 @@ class CodeWriter {
6225
6705
  }
6226
6706
  return imports;
6227
6707
  });
6228
- __publicField(this, "genImportStatements", (imports) => {
6708
+ __publicField$1(this, "genImportStatements", (imports) => {
6229
6709
  const symbolsBySource = groupBy(
6230
6710
  imports.map((i) => ({
6231
6711
  name: i.name,
@@ -6238,7 +6718,7 @@ class CodeWriter {
6238
6718
  return `import type { ${sortedSymbols.join(", ")} } from '${source}'`;
6239
6719
  });
6240
6720
  });
6241
- __publicField(this, "importSourcetoString", (src) => {
6721
+ __publicField$1(this, "importSourcetoString", (src) => {
6242
6722
  return "externalModule" in src ? src.externalModule : (
6243
6723
  // TODO generalize later when we have different paths
6244
6724
  `./${src.name}`
@@ -6253,7 +6733,7 @@ class VNextOasClientGenerator {
6253
6733
  this.options = options;
6254
6734
  this.log = log;
6255
6735
  }
6256
- async generate(cmd) {
6736
+ async generate(cmd, formatter) {
6257
6737
  const { inputFile, outputDir, apiName } = cmd;
6258
6738
  this.log(`Will generate API client name=${apiName} to ${outputDir}`);
6259
6739
  const sourceSchema = await loadSourceSchema(inputFile);
@@ -6262,6 +6742,7 @@ class VNextOasClientGenerator {
6262
6742
  const projectResult = new OperationProjector({
6263
6743
  includeAllSchema: this.options.selection?.allSchemas === true,
6264
6744
  typeExtraction: {
6745
+ comments: this.options.codegen.comments.schema,
6265
6746
  enumStyle: this.options.codegen.enumStyle,
6266
6747
  uppercaseEnumKeys: this.options.compat?.uppercaseEnumKeys,
6267
6748
  swaggerTsApiRequiredBooleans: this.options.compat?.swaggerTsApiRequiredBooleans
@@ -6273,12 +6754,9 @@ class VNextOasClientGenerator {
6273
6754
  projectResult,
6274
6755
  this.options.codegen
6275
6756
  );
6276
- const codeFormatter = new CodeFormatter({
6277
- resolveConfFrom: outputDir
6278
- });
6279
- const writer = new CodeWriter(codeFormatter);
6757
+ const writer = new CodeWriter(formatter);
6280
6758
  await writer.write(outputDir, chunks.all);
6281
- const tsFilePath = (name) => Path.join(outputDir, `${name}.ts`);
6759
+ const tsFilePath = (name) => Path$1.join(outputDir, `${name}.ts`);
6282
6760
  return {
6283
6761
  promiseWrapper: chunks.promiseWrappersNames.map(tsFilePath),
6284
6762
  types: tsFilePath(chunks.typesName)
@@ -6344,7 +6822,7 @@ const toErrorMessage = (error) => {
6344
6822
  return error instanceof Error ? error.message : String(error);
6345
6823
  };
6346
6824
 
6347
- const generateOpenApiModel = async (spectPath, config, log) => {
6825
+ const generateOpenApiModel = async (spectPath, config, log, codeFormatter) => {
6348
6826
  let outFiles;
6349
6827
  const { openApiGenerator, responseWrapper } = config;
6350
6828
  if ("legacy" in openApiGenerator) {
@@ -6361,11 +6839,14 @@ const generateOpenApiModel = async (spectPath, config, log) => {
6361
6839
  outFiles = await new VNextOasClientGenerator(
6362
6840
  openApiGenerator,
6363
6841
  log
6364
- ).generate({
6365
- inputFile: spectPath,
6366
- apiName: config.apiName,
6367
- outputDir: config.dstDir
6368
- });
6842
+ ).generate(
6843
+ {
6844
+ inputFile: spectPath,
6845
+ apiName: config.apiName,
6846
+ outputDir: config.dstDir
6847
+ },
6848
+ codeFormatter
6849
+ );
6369
6850
  }
6370
6851
  if (responseWrapper) {
6371
6852
  await modifyHttpClientAsyncWrapper(
@@ -6454,46 +6935,51 @@ const findMatchingBrace = (code, openBraceIndex) => {
6454
6935
  return -1;
6455
6936
  };
6456
6937
 
6457
- const generateSchemas = async (inputFile, outputFile, opts = {}) => {
6458
- const code = fs__default.readFileSync(inputFile).toString();
6459
- const { getZodSchemasFile } = generate({
6460
- sourceText: removeGenericTypes(code)
6461
- });
6462
- let f = getZodSchemasFile(getModuleImportPath(inputFile, outputFile));
6463
- f = f.replaceAll(".optional()", ".nullable()");
6464
- if (opts.localDateTimes) {
6465
- f = f.replaceAll(
6466
- "z.string().datetime()",
6467
- "z.string().datetime({local: true})"
6468
- );
6938
+ var __defProp = Object.defineProperty;
6939
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6940
+ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
6941
+ class ZodSchemaGenerator {
6942
+ constructor(codeFormatter) {
6943
+ this.codeFormatter = codeFormatter;
6944
+ __publicField(this, "generate", async ({
6945
+ sourceText,
6946
+ moduleImportPath,
6947
+ options = {}
6948
+ }) => {
6949
+ const { getZodSchemasFile } = generate({
6950
+ sourceText: removeGenericTypes(sourceText)
6951
+ });
6952
+ let generated = getZodSchemasFile(moduleImportPath);
6953
+ generated = generated.replaceAll(".optional()", ".nullable()");
6954
+ generated = generated.replaceAll(".int64()", ".int()");
6955
+ if (options.localDateTimes) {
6956
+ generated = generated.replaceAll(
6957
+ "z.string().datetime()",
6958
+ "z.string().datetime({local: true})"
6959
+ );
6960
+ }
6961
+ return this.codeFormatter.format(generated);
6962
+ });
6469
6963
  }
6470
- const prettier = await import('prettier');
6471
- const prettierConfig = await prettier.resolveConfig(outputFile) ?? {};
6472
- const formatted = await prettier.format(f, {
6473
- ...prettierConfig,
6474
- filepath: outputFile
6475
- });
6476
- fs__default.writeFileSync(outputFile, formatted);
6477
- };
6478
- const getModuleImportPath = (inputFile, outputFile) => {
6479
- const sourceDir = Path.dirname(outputFile);
6480
- const relativePath = Path.relative(sourceDir, inputFile);
6481
- const withoutExtension = relativePath.replace(/\.ts$/u, "");
6482
- const normalizedPath = withoutExtension.split(Path.sep).join("/");
6483
- return normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`;
6484
- };
6964
+ }
6485
6965
 
6486
6966
  const generateApiClient = async (params, configFilePath, log = console.log) => {
6487
- const config = parseConfig(params, configFilePath);
6967
+ const config = parseProfileConfig(params, configFilePath);
6968
+ return generateApiClientFromConfig(config, log);
6969
+ };
6970
+ const generateApiClientFromConfig = async (config, log = console.log) => {
6488
6971
  const { dstDir, apiName, srcSpec, zodSchemas } = config;
6489
- const dir = Path.resolve(dstDir, apiName);
6972
+ const dir = Path$1.resolve(dstDir, apiName);
6490
6973
  if (!fs.existsSync(dir)) {
6491
6974
  log(`Creating dir ${dir}`);
6492
6975
  fs.mkdirSync(dir, {
6493
6976
  recursive: true
6494
6977
  });
6495
6978
  }
6496
- const clientDir = Path.resolve(dir, "client");
6979
+ const clientDir = Path$1.resolve(dir, "client");
6980
+ const formatter = new CodeFormatter({
6981
+ resolveConfFrom: dir
6982
+ });
6497
6983
  const specPath = await getSpecPath(srcSpec, dir, log);
6498
6984
  log(`Cleaning client output dir ${clientDir}`);
6499
6985
  fs.rmSync(clientDir, {
@@ -6509,15 +6995,20 @@ const generateApiClient = async (params, configFilePath, log = console.log) => {
6509
6995
  ...config,
6510
6996
  dstDir: clientDir
6511
6997
  },
6512
- log
6998
+ log,
6999
+ formatter
6513
7000
  );
6514
7001
  if (zodSchemas?.enabled === false) return;
6515
7002
  log("Generating Zod schemas");
6516
- await generateSchemas(
6517
- typesFilePath,
6518
- Path.resolve(dir, "./zod.ts"),
6519
- zodSchemas
6520
- );
7003
+ const zodOutputFile = Path$1.resolve(dir, "./zod.ts");
7004
+ const generator = new ZodSchemaGenerator(formatter);
7005
+ const sourceText = fs.readFileSync(typesFilePath, "utf8");
7006
+ const generated = await generator.generate({
7007
+ sourceText,
7008
+ moduleImportPath: findRelativePath(zodOutputFile, typesFilePath),
7009
+ options: zodSchemas
7010
+ });
7011
+ fs.writeFileSync(zodOutputFile, generated);
6521
7012
  };
6522
7013
  const getSpecPath = async (urlOrPath, dir, log) => {
6523
7014
  if (!urlOrPath.startsWith("http")) {
@@ -6525,10 +7016,10 @@ const getSpecPath = async (urlOrPath, dir, log) => {
6525
7016
  throw new Error(`Spec file ${urlOrPath} does not exists`);
6526
7017
  return urlOrPath;
6527
7018
  }
6528
- const specPath = Path.resolve(dir, `spec.json`);
7019
+ const specPath = Path$1.resolve(dir, `spec.json`);
6529
7020
  log(`Will download the API spec from ${urlOrPath} to ${specPath}`);
6530
7021
  await downloadSpec(specPath, urlOrPath);
6531
7022
  return specPath;
6532
7023
  };
6533
7024
 
6534
- export { generateApiClient as g };
7025
+ export { generateApiClientFromConfig as a, defineConfig as d, generateApiClient as g, parseConfig as p };