@sdk-it/typescript 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,1590 +1,22 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
- }) : x)(function(x) {
10
- if (typeof require !== "undefined")
11
- return require.apply(this, arguments);
12
- throw Error('Dynamic require of "' + x + '" is not supported');
13
- });
14
- var __commonJS = (cb, mod) => function __require2() {
15
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
- };
17
- var __copyProps = (to, from, except, desc) => {
18
- if (from && typeof from === "object" || typeof from === "function") {
19
- for (let key of __getOwnPropNames(from))
20
- if (!__hasOwnProp.call(to, key) && key !== except)
21
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
- }
23
- return to;
24
- };
25
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
- // If the importer is in node compatibility mode or this is not an ESM
27
- // file that has been converted to a CommonJS file using a Babel-
28
- // compatible transform (i.e. "__esModule" has not been set), then set
29
- // "default" to the CommonJS "module.exports" for node compatibility.
30
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
- mod
32
- ));
33
-
34
- // node_modules/pluralize/pluralize.js
35
- var require_pluralize = __commonJS({
36
- "node_modules/pluralize/pluralize.js"(exports, module) {
37
- "use strict";
38
- (function(root, pluralize3) {
39
- if (typeof __require === "function" && typeof exports === "object" && typeof module === "object") {
40
- module.exports = pluralize3();
41
- } else if (typeof define === "function" && define.amd) {
42
- define(function() {
43
- return pluralize3();
44
- });
45
- } else {
46
- root.pluralize = pluralize3();
47
- }
48
- })(exports, function() {
49
- var pluralRules = [];
50
- var singularRules = [];
51
- var uncountables = {};
52
- var irregularPlurals = {};
53
- var irregularSingles = {};
54
- function sanitizeRule(rule) {
55
- if (typeof rule === "string") {
56
- return new RegExp("^" + rule + "$", "i");
57
- }
58
- return rule;
59
- }
60
- function restoreCase(word, token) {
61
- if (word === token)
62
- return token;
63
- if (word === word.toLowerCase())
64
- return token.toLowerCase();
65
- if (word === word.toUpperCase())
66
- return token.toUpperCase();
67
- if (word[0] === word[0].toUpperCase()) {
68
- return token.charAt(0).toUpperCase() + token.substr(1).toLowerCase();
69
- }
70
- return token.toLowerCase();
71
- }
72
- function interpolate(str, args) {
73
- return str.replace(/\$(\d{1,2})/g, function(match, index) {
74
- return args[index] || "";
75
- });
76
- }
77
- function replace(word, rule) {
78
- return word.replace(rule[0], function(match, index) {
79
- var result = interpolate(rule[1], arguments);
80
- if (match === "") {
81
- return restoreCase(word[index - 1], result);
82
- }
83
- return restoreCase(match, result);
84
- });
85
- }
86
- function sanitizeWord(token, word, rules) {
87
- if (!token.length || uncountables.hasOwnProperty(token)) {
88
- return word;
89
- }
90
- var len = rules.length;
91
- while (len--) {
92
- var rule = rules[len];
93
- if (rule[0].test(word))
94
- return replace(word, rule);
95
- }
96
- return word;
97
- }
98
- function replaceWord(replaceMap, keepMap, rules) {
99
- return function(word) {
100
- var token = word.toLowerCase();
101
- if (keepMap.hasOwnProperty(token)) {
102
- return restoreCase(word, token);
103
- }
104
- if (replaceMap.hasOwnProperty(token)) {
105
- return restoreCase(word, replaceMap[token]);
106
- }
107
- return sanitizeWord(token, word, rules);
108
- };
109
- }
110
- function checkWord(replaceMap, keepMap, rules, bool) {
111
- return function(word) {
112
- var token = word.toLowerCase();
113
- if (keepMap.hasOwnProperty(token))
114
- return true;
115
- if (replaceMap.hasOwnProperty(token))
116
- return false;
117
- return sanitizeWord(token, token, rules) === token;
118
- };
119
- }
120
- function pluralize3(word, count, inclusive) {
121
- var pluralized = count === 1 ? pluralize3.singular(word) : pluralize3.plural(word);
122
- return (inclusive ? count + " " : "") + pluralized;
123
- }
124
- pluralize3.plural = replaceWord(
125
- irregularSingles,
126
- irregularPlurals,
127
- pluralRules
128
- );
129
- pluralize3.isPlural = checkWord(
130
- irregularSingles,
131
- irregularPlurals,
132
- pluralRules
133
- );
134
- pluralize3.singular = replaceWord(
135
- irregularPlurals,
136
- irregularSingles,
137
- singularRules
138
- );
139
- pluralize3.isSingular = checkWord(
140
- irregularPlurals,
141
- irregularSingles,
142
- singularRules
143
- );
144
- pluralize3.addPluralRule = function(rule, replacement) {
145
- pluralRules.push([sanitizeRule(rule), replacement]);
146
- };
147
- pluralize3.addSingularRule = function(rule, replacement) {
148
- singularRules.push([sanitizeRule(rule), replacement]);
149
- };
150
- pluralize3.addUncountableRule = function(word) {
151
- if (typeof word === "string") {
152
- uncountables[word.toLowerCase()] = true;
153
- return;
154
- }
155
- pluralize3.addPluralRule(word, "$0");
156
- pluralize3.addSingularRule(word, "$0");
157
- };
158
- pluralize3.addIrregularRule = function(single, plural) {
159
- plural = plural.toLowerCase();
160
- single = single.toLowerCase();
161
- irregularSingles[single] = plural;
162
- irregularPlurals[plural] = single;
163
- };
164
- [
165
- // Pronouns.
166
- ["I", "we"],
167
- ["me", "us"],
168
- ["he", "they"],
169
- ["she", "they"],
170
- ["them", "them"],
171
- ["myself", "ourselves"],
172
- ["yourself", "yourselves"],
173
- ["itself", "themselves"],
174
- ["herself", "themselves"],
175
- ["himself", "themselves"],
176
- ["themself", "themselves"],
177
- ["is", "are"],
178
- ["was", "were"],
179
- ["has", "have"],
180
- ["this", "these"],
181
- ["that", "those"],
182
- // Words ending in with a consonant and `o`.
183
- ["echo", "echoes"],
184
- ["dingo", "dingoes"],
185
- ["volcano", "volcanoes"],
186
- ["tornado", "tornadoes"],
187
- ["torpedo", "torpedoes"],
188
- // Ends with `us`.
189
- ["genus", "genera"],
190
- ["viscus", "viscera"],
191
- // Ends with `ma`.
192
- ["stigma", "stigmata"],
193
- ["stoma", "stomata"],
194
- ["dogma", "dogmata"],
195
- ["lemma", "lemmata"],
196
- ["schema", "schemata"],
197
- ["anathema", "anathemata"],
198
- // Other irregular rules.
199
- ["ox", "oxen"],
200
- ["axe", "axes"],
201
- ["die", "dice"],
202
- ["yes", "yeses"],
203
- ["foot", "feet"],
204
- ["eave", "eaves"],
205
- ["goose", "geese"],
206
- ["tooth", "teeth"],
207
- ["quiz", "quizzes"],
208
- ["human", "humans"],
209
- ["proof", "proofs"],
210
- ["carve", "carves"],
211
- ["valve", "valves"],
212
- ["looey", "looies"],
213
- ["thief", "thieves"],
214
- ["groove", "grooves"],
215
- ["pickaxe", "pickaxes"],
216
- ["passerby", "passersby"]
217
- ].forEach(function(rule) {
218
- return pluralize3.addIrregularRule(rule[0], rule[1]);
219
- });
220
- [
221
- [/s?$/i, "s"],
222
- [/[^\u0000-\u007F]$/i, "$0"],
223
- [/([^aeiou]ese)$/i, "$1"],
224
- [/(ax|test)is$/i, "$1es"],
225
- [/(alias|[^aou]us|t[lm]as|gas|ris)$/i, "$1es"],
226
- [/(e[mn]u)s?$/i, "$1s"],
227
- [/([^l]ias|[aeiou]las|[ejzr]as|[iu]am)$/i, "$1"],
228
- [/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, "$1i"],
229
- [/(alumn|alg|vertebr)(?:a|ae)$/i, "$1ae"],
230
- [/(seraph|cherub)(?:im)?$/i, "$1im"],
231
- [/(her|at|gr)o$/i, "$1oes"],
232
- [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i, "$1a"],
233
- [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i, "$1a"],
234
- [/sis$/i, "ses"],
235
- [/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i, "$1$2ves"],
236
- [/([^aeiouy]|qu)y$/i, "$1ies"],
237
- [/([^ch][ieo][ln])ey$/i, "$1ies"],
238
- [/(x|ch|ss|sh|zz)$/i, "$1es"],
239
- [/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i, "$1ices"],
240
- [/\b((?:tit)?m|l)(?:ice|ouse)$/i, "$1ice"],
241
- [/(pe)(?:rson|ople)$/i, "$1ople"],
242
- [/(child)(?:ren)?$/i, "$1ren"],
243
- [/eaux$/i, "$0"],
244
- [/m[ae]n$/i, "men"],
245
- ["thou", "you"]
246
- ].forEach(function(rule) {
247
- return pluralize3.addPluralRule(rule[0], rule[1]);
248
- });
249
- [
250
- [/s$/i, ""],
251
- [/(ss)$/i, "$1"],
252
- [/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i, "$1fe"],
253
- [/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, "$1f"],
254
- [/ies$/i, "y"],
255
- [/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i, "$1ie"],
256
- [/\b(mon|smil)ies$/i, "$1ey"],
257
- [/\b((?:tit)?m|l)ice$/i, "$1ouse"],
258
- [/(seraph|cherub)im$/i, "$1"],
259
- [/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i, "$1"],
260
- [/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i, "$1sis"],
261
- [/(movie|twelve|abuse|e[mn]u)s$/i, "$1"],
262
- [/(test)(?:is|es)$/i, "$1is"],
263
- [/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, "$1us"],
264
- [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i, "$1um"],
265
- [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i, "$1on"],
266
- [/(alumn|alg|vertebr)ae$/i, "$1a"],
267
- [/(cod|mur|sil|vert|ind)ices$/i, "$1ex"],
268
- [/(matr|append)ices$/i, "$1ix"],
269
- [/(pe)(rson|ople)$/i, "$1rson"],
270
- [/(child)ren$/i, "$1"],
271
- [/(eau)x?$/i, "$1"],
272
- [/men$/i, "man"]
273
- ].forEach(function(rule) {
274
- return pluralize3.addSingularRule(rule[0], rule[1]);
275
- });
276
- [
277
- // Singular words with no plurals.
278
- "adulthood",
279
- "advice",
280
- "agenda",
281
- "aid",
282
- "aircraft",
283
- "alcohol",
284
- "ammo",
285
- "analytics",
286
- "anime",
287
- "athletics",
288
- "audio",
289
- "bison",
290
- "blood",
291
- "bream",
292
- "buffalo",
293
- "butter",
294
- "carp",
295
- "cash",
296
- "chassis",
297
- "chess",
298
- "clothing",
299
- "cod",
300
- "commerce",
301
- "cooperation",
302
- "corps",
303
- "debris",
304
- "diabetes",
305
- "digestion",
306
- "elk",
307
- "energy",
308
- "equipment",
309
- "excretion",
310
- "expertise",
311
- "firmware",
312
- "flounder",
313
- "fun",
314
- "gallows",
315
- "garbage",
316
- "graffiti",
317
- "hardware",
318
- "headquarters",
319
- "health",
320
- "herpes",
321
- "highjinks",
322
- "homework",
323
- "housework",
324
- "information",
325
- "jeans",
326
- "justice",
327
- "kudos",
328
- "labour",
329
- "literature",
330
- "machinery",
331
- "mackerel",
332
- "mail",
333
- "media",
334
- "mews",
335
- "moose",
336
- "music",
337
- "mud",
338
- "manga",
339
- "news",
340
- "only",
341
- "personnel",
342
- "pike",
343
- "plankton",
344
- "pliers",
345
- "police",
346
- "pollution",
347
- "premises",
348
- "rain",
349
- "research",
350
- "rice",
351
- "salmon",
352
- "scissors",
353
- "series",
354
- "sewage",
355
- "shambles",
356
- "shrimp",
357
- "software",
358
- "species",
359
- "staff",
360
- "swine",
361
- "tennis",
362
- "traffic",
363
- "transportation",
364
- "trout",
365
- "tuna",
366
- "wealth",
367
- "welfare",
368
- "whiting",
369
- "wildebeest",
370
- "wildlife",
371
- "you",
372
- /pok[eé]mon$/i,
373
- // Regexes.
374
- /[^aeiou]ese$/i,
375
- // "chinese", "japanese"
376
- /deer$/i,
377
- // "deer", "reindeer"
378
- /fish$/i,
379
- // "fish", "blowfish", "angelfish"
380
- /measles$/i,
381
- /o[iu]s$/i,
382
- // "carnivorous"
383
- /pox$/i,
384
- // "chickpox", "smallpox"
385
- /sheep$/i
386
- ].forEach(pluralize3.addUncountableRule);
387
- return pluralize3;
388
- });
389
- }
390
- });
391
-
392
1
  // packages/typescript/src/lib/generate.ts
393
2
  import { template as template2 } from "lodash-es";
394
- import { readFile, readdir, unlink, writeFile } from "node:fs/promises";
395
- import { join as join2, relative, sep } from "node:path";
3
+ import { readdir } from "node:fs/promises";
4
+ import { join as join2 } from "node:path";
396
5
  import { npmRunPathEnv } from "npm-run-path";
397
- import { spinalcase as spinalcase4 } from "stringcase";
398
- import { methods, pascalcase as pascalcase4 } from "@sdk-it/core";
6
+ import { camelcase as camelcase4, spinalcase as spinalcase3 } from "stringcase";
7
+ import { methods, pascalcase as pascalcase5, toLitObject as toLitObject2 } from "@sdk-it/core";
399
8
  import {
400
- addLeadingSlash,
401
- exist,
9
+ createWriterProxy,
402
10
  getFolderExports,
403
- readFolder,
404
11
  writeFiles
405
12
  } from "@sdk-it/core/file-system.js";
406
-
407
- // packages/readme/dist/index.js
408
- var import_pluralize = __toESM(require_pluralize(), 1);
409
- import { isEmpty as isEmpty2 } from "@sdk-it/core";
410
- import { camelcase } from "stringcase";
411
- import { followRef, isRef as isRef2 } from "@sdk-it/core/ref.js";
412
- import { isRef } from "@sdk-it/core/ref.js";
413
- import { isEmpty } from "@sdk-it/core/utils.js";
414
- import { followRef as followRef2, isRef as isRef3 } from "@sdk-it/core";
415
- var HAS_MORE_POSITIVE_REGEX_PATTERNS = [
416
- "\\bhas_?more\\b",
417
- "\\bhas_?next\\b",
418
- // e.g., itemsHasNext, items_has_next
419
- "\\bmore_?items\\b",
420
- "\\bnext_?page\\b",
421
- // e.g., userNextPageFlag
422
- "\\badditional\\b",
423
- // e.g., hasAdditionalData, additional_results_exist
424
- "\\bcontinuation\\b",
425
- // e.g., continuationAvailable, has_continuation_token
426
- "\\bmore_?results\\b",
427
- "\\bpage_?available\\b",
428
- "\\bnext(?:_?(page))?\\b"
429
- ];
430
- var COMPILED_HAS_MORE_POSITIVE_REGEXES = HAS_MORE_POSITIVE_REGEX_PATTERNS.map((p) => new RegExp(p, "i"));
431
- var HAS_MORE_INVERTED_REGEX_PATTERNS = [
432
- "\\bis_?last\\b",
433
- // e.g., pageIsLast
434
- "\\blast_?page\\b",
435
- // e.g., resultsAreLastPage
436
- "\\bend_?of_?(data|results|list|items|stream)\\b",
437
- "\\bno_?more_?(items|data|results)?\\b",
438
- "\\ball_?(items_?)?loaded\\b",
439
- "\\bis_?complete\\b"
440
- ];
441
- var COMPILED_HAS_MORE_INVERTED_REGEXES = HAS_MORE_INVERTED_REGEX_PATTERNS.map((p) => new RegExp(p, "i"));
442
- function forEachOperation(config, callback) {
443
- const result = [];
444
- for (const [path, pathItem] of Object.entries(config.spec.paths ?? {})) {
445
- const { parameters = [], ...methods2 } = pathItem;
446
- for (const [method, operation] of Object.entries(methods2)) {
447
- const metadata = operation["x-oaiMeta"] ?? {};
448
- const operationTag = operation.tags?.[0];
449
- result.push(
450
- callback(
451
- {
452
- name: metadata.name,
453
- method,
454
- path,
455
- groupName: operationTag,
456
- tag: operationTag
457
- },
458
- operation
459
- )
460
- );
461
- }
462
- }
463
- return result;
464
- }
465
- var PropEmitter = class {
466
- #spec;
467
- constructor(spec) {
468
- this.#spec = spec;
469
- }
470
- /**
471
- * Handle objects (properties)
472
- */
473
- #object(schema) {
474
- const lines = [];
475
- const properties = schema.properties || {};
476
- if (Object.keys(properties).length > 0) {
477
- lines.push(`**Properties:**`);
478
- for (const [propName, propSchema] of Object.entries(properties)) {
479
- const isRequired = (schema.required ?? []).includes(propName);
480
- lines.push(...this.#property(propName, propSchema, isRequired));
481
- }
482
- }
483
- if (schema.additionalProperties) {
484
- lines.push(`**Additional Properties:**`);
485
- if (typeof schema.additionalProperties === "boolean") {
486
- lines.push(`- Allowed: ${schema.additionalProperties}`);
487
- } else {
488
- lines.push(
489
- ...this.handle(schema.additionalProperties).map((l) => ` ${l}`)
490
- );
491
- }
492
- }
493
- return lines;
494
- }
495
- /**
496
- * Format a property with its type and description
497
- */
498
- #property(name, schema, required) {
499
- const docs = this.handle(schema);
500
- const rawType = docs[0].replace("**Type:** ", "").replace(" (nullable)", "|null");
501
- const defaultVal = !isRef3(schema) && schema.default !== void 0 ? ` default: ${JSON.stringify(schema.default)}` : "";
502
- const reqMark = required ? " required" : "";
503
- const summary = `- \`${name}\` ${rawType}${reqMark}${defaultVal}:`;
504
- const detailLines = docs.slice(1).filter((l) => !l.startsWith("**Default:**")).map((l) => ` ${l}`);
505
- return [summary, ...detailLines];
506
- }
507
- /**
508
- * Handle array schemas
509
- */
510
- #array(schema) {
511
- const lines = [];
512
- lines.push(`**Array items:**`);
513
- if (schema.items) {
514
- const itemDocs = this.handle(schema.items);
515
- lines.push(...itemDocs.map((line) => ` ${line}`));
516
- } else {
517
- lines.push(` **Type:** \`unknown\``);
518
- }
519
- if (schema.minItems !== void 0)
520
- lines.push(`- Minimum items: ${schema.minItems}`);
521
- if (schema.maxItems !== void 0)
522
- lines.push(`- Maximum items: ${schema.maxItems}`);
523
- if (schema.uniqueItems)
524
- lines.push(`- Items must be unique.`);
525
- return lines;
526
- }
527
- #ref($ref) {
528
- const schemaName = $ref.split("/").pop() || "object";
529
- const resolved = followRef2(this.#spec, $ref);
530
- const lines = [
531
- `**Type:** [\`${schemaName}\`](#${schemaName.toLowerCase()})`
532
- ];
533
- if (resolved.description) {
534
- lines.push(resolved.description);
535
- }
536
- return lines;
537
- }
538
- #allOf(schemas) {
539
- const lines = ["**All of (Intersection):**"];
540
- schemas.forEach((subSchema, index) => {
541
- lines.push(`- **Constraint ${index + 1}:**`);
542
- const subLines = this.handle(subSchema);
543
- lines.push(...subLines.map((l) => ` ${l}`));
544
- });
545
- return lines;
546
- }
547
- #anyOf(schemas) {
548
- const lines = ["**Any of (Union):**"];
549
- schemas.forEach((subSchema, index) => {
550
- lines.push(`- **Option ${index + 1}:**`);
551
- const subLines = this.handle(subSchema);
552
- lines.push(...subLines.map((l) => ` ${l}`));
553
- });
554
- return lines;
555
- }
556
- #oneOf(schemas) {
557
- const lines = ["**One of (Exclusive Union):**"];
558
- schemas.forEach((subSchema, index) => {
559
- lines.push(`- **Option ${index + 1}:**`);
560
- const subLines = this.handle(subSchema);
561
- lines.push(...subLines.map((l) => ` ${l}`));
562
- });
563
- return lines;
564
- }
565
- #enum(schema) {
566
- const lines = [`**Type:** \`${schema.type || "unknown"}\` (enum)`];
567
- if (schema.description)
568
- lines.push(schema.description);
569
- lines.push("**Allowed values:**");
570
- lines.push(
571
- ...(schema.enum || []).map((val) => `- \`${JSON.stringify(val)}\``)
572
- );
573
- if (schema.default !== void 0) {
574
- lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
575
- }
576
- return lines;
577
- }
578
- #normal(type, schema, nullable) {
579
- const lines = [];
580
- const nullableSuffix = nullable ? " (nullable)" : "";
581
- const description = schema.description ? [schema.description] : [];
582
- switch (type) {
583
- case "string":
584
- lines.push(
585
- `**Type:** \`string\`${schema.format ? ` (format: ${schema.format})` : ""}${nullableSuffix}`
586
- );
587
- lines.push(...description);
588
- if (schema.minLength !== void 0)
589
- lines.push(`- Minimum length: ${schema.minLength}`);
590
- if (schema.maxLength !== void 0)
591
- lines.push(`- Maximum length: ${schema.maxLength}`);
592
- if (schema.pattern !== void 0)
593
- lines.push(`- Pattern: \`${schema.pattern}\``);
594
- break;
595
- case "number":
596
- case "integer":
597
- lines.push(
598
- `**Type:** \`${type}\`${schema.format ? ` (format: ${schema.format})` : ""}${nullableSuffix}`
599
- );
600
- lines.push(...description);
601
- if (schema.minimum !== void 0) {
602
- const exclusiveMin = typeof schema.exclusiveMinimum === "number";
603
- lines.push(
604
- `- Minimum: ${schema.minimum}${exclusiveMin ? " (exclusive)" : ""}`
605
- );
606
- if (exclusiveMin) {
607
- lines.push(
608
- `- Must be strictly greater than: ${schema.exclusiveMinimum}`
609
- );
610
- }
611
- } else if (typeof schema.exclusiveMinimum === "number") {
612
- lines.push(
613
- `- Must be strictly greater than: ${schema.exclusiveMinimum}`
614
- );
615
- }
616
- if (schema.maximum !== void 0) {
617
- const exclusiveMax = typeof schema.exclusiveMaximum === "number";
618
- lines.push(
619
- `- Maximum: ${schema.maximum}${exclusiveMax ? " (exclusive)" : ""}`
620
- );
621
- if (exclusiveMax) {
622
- lines.push(
623
- `- Must be strictly less than: ${schema.exclusiveMaximum}`
624
- );
625
- }
626
- } else if (typeof schema.exclusiveMaximum === "number") {
627
- lines.push(
628
- `- Must be strictly less than: ${schema.exclusiveMaximum}`
629
- );
630
- }
631
- if (schema.multipleOf !== void 0)
632
- lines.push(`- Must be a multiple of: ${schema.multipleOf}`);
633
- break;
634
- case "boolean":
635
- lines.push(`**Type:** \`boolean\`${nullableSuffix}`);
636
- lines.push(...description);
637
- break;
638
- case "object":
639
- lines.push(`**Type:** \`object\`${nullableSuffix}`);
640
- lines.push(...description);
641
- lines.push(...this.#object(schema));
642
- break;
643
- case "array":
644
- lines.push(`**Type:** \`array\`${nullableSuffix}`);
645
- lines.push(...description);
646
- lines.push(...this.#array(schema));
647
- break;
648
- case "null":
649
- lines.push(`**Type:** \`null\``);
650
- lines.push(...description);
651
- break;
652
- default:
653
- lines.push(`**Type:** \`${type}\`${nullableSuffix}`);
654
- lines.push(...description);
655
- }
656
- if (schema.default !== void 0) {
657
- lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
658
- }
659
- return lines.filter((l) => l);
660
- }
661
- /**
662
- * Handle schemas by resolving references and delegating to appropriate handler
663
- */
664
- handle(schemaOrRef) {
665
- if (isRef3(schemaOrRef)) {
666
- return this.#ref(schemaOrRef.$ref);
667
- }
668
- const schema = schemaOrRef;
669
- if (schema.allOf && Array.isArray(schema.allOf)) {
670
- return this.#allOf(schema.allOf);
671
- }
672
- if (schema.anyOf && Array.isArray(schema.anyOf)) {
673
- return this.#anyOf(schema.anyOf);
674
- }
675
- if (schema.oneOf && Array.isArray(schema.oneOf)) {
676
- return this.#oneOf(schema.oneOf);
677
- }
678
- if (schema.enum && Array.isArray(schema.enum)) {
679
- return this.#enum(schema);
680
- }
681
- let types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
682
- let nullable = false;
683
- if (types.includes("null")) {
684
- nullable = true;
685
- types = types.filter((t) => t !== "null");
686
- }
687
- if (types.length === 0) {
688
- if (schema.properties || schema.additionalProperties) {
689
- types = ["object"];
690
- } else if (schema.items) {
691
- types = ["array"];
692
- }
693
- }
694
- if (types.length === 0) {
695
- const lines2 = ["**Type:** `unknown`"];
696
- if (schema.description)
697
- lines2.push(schema.description);
698
- if (schema.default !== void 0)
699
- lines2.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
700
- return lines2;
701
- }
702
- if (types.length === 1) {
703
- return this.#normal(types[0], schema, nullable);
704
- }
705
- const typeString = types.join(" | ");
706
- const nullableSuffix = nullable ? " (nullable)" : "";
707
- const lines = [`**Type:** \`${typeString}\`${nullableSuffix}`];
708
- if (schema.description)
709
- lines.push(schema.description);
710
- if (schema.default !== void 0)
711
- lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
712
- return lines;
713
- }
714
- /**
715
- * Process a request body and return markdown documentation
716
- */
717
- requestBody(requestBody) {
718
- if (!requestBody)
719
- return [];
720
- const lines = [];
721
- lines.push(`##### Request Body`);
722
- if (requestBody.description) {
723
- lines.push(requestBody.description);
724
- }
725
- if (requestBody.required) {
726
- lines.push(`*This request body is required.*`);
727
- }
728
- if (requestBody.content) {
729
- for (const [contentType, mediaType] of Object.entries(
730
- requestBody.content
731
- )) {
732
- lines.push(`**Content Type:** \`${contentType}\``);
733
- if (mediaType.schema) {
734
- const schemaDocs = this.handle(mediaType.schema);
735
- lines.push(...schemaDocs);
736
- }
737
- }
738
- }
739
- return lines;
740
- }
741
- };
742
- function toReadme(spec, generators) {
743
- const markdown = [];
744
- const propEmitter = new PropEmitter(spec);
745
- forEachOperation({ spec }, (entry, operation) => {
746
- const { method, path, name } = entry;
747
- spec.components ??= {};
748
- spec.components.schemas ??= {};
749
- markdown.push(
750
- `#### ${name || operation.operationId} | ${`_${method.toUpperCase()} ${path}_`}`
751
- );
752
- markdown.push(operation.summary || "");
753
- const snippet = generators.generateSnippet(entry, operation);
754
- markdown.push(`##### Example usage`);
755
- markdown.push(snippet);
756
- const requestBodyContent = propEmitter.requestBody(operation.requestBody);
757
- if (requestBodyContent.length > 1) {
758
- markdown.push(requestBodyContent.join("\n\n"));
759
- }
760
- markdown.push(`##### Responses`);
761
- for (const status in operation.responses) {
762
- const response = operation.responses[status];
763
- markdown.push(`<details>`);
764
- markdown.push(
765
- `<summary><b>${status}</b> <i>${response.description}</i></summary>`
766
- );
767
- if (!isEmpty2(response.content)) {
768
- for (const [contentType, mediaType] of Object.entries(
769
- response.content
770
- )) {
771
- markdown.push(`
772
- **Content Type:** \`${contentType}\``);
773
- if (mediaType.schema) {
774
- const schemaDocs = propEmitter.handle(mediaType.schema);
775
- markdown.push(...schemaDocs.map((l) => `
776
- ${l}`));
777
- }
778
- }
779
- }
780
- markdown.push(`</details>`);
781
- }
782
- });
783
- return markdown.join("\n\n");
784
- }
785
-
786
- // packages/spec/dist/lib/operation.js
787
- import { camelcase as camelcase2 } from "stringcase";
788
- import { followRef as followRef3, isRef as isRef5 } from "@sdk-it/core/ref.js";
789
-
790
- // packages/spec/dist/lib/pagination/pagination.js
791
- import { isRef as isRef4 } from "@sdk-it/core/ref.js";
792
- import { isEmpty as isEmpty3 } from "@sdk-it/core/utils.js";
793
-
794
- // packages/spec/dist/lib/pagination/pagination-result.js
795
- var import_pluralize2 = __toESM(require_pluralize(), 1);
796
- var PRIMARY_TOP_TIER_KEYWORDS = [
797
- "data",
798
- "items",
799
- "results",
800
- "value"
801
- ];
802
- var PRIMARY_OTHER_KEYWORDS = [
803
- "records",
804
- "content",
805
- "list",
806
- "payload",
807
- "entities",
808
- "collection",
809
- "users",
810
- "products",
811
- "orders",
812
- "bookings",
813
- "articles",
814
- "posts",
815
- "documents",
816
- "events"
817
- ];
818
- var SECONDARY_KEYWORDS = ["entries", "rows", "elements"];
819
- var PLURAL_DEPRIORITIZE_LIST = [
820
- "status",
821
- "success",
822
- "address",
823
- "details",
824
- "properties",
825
- "params",
826
- "headers",
827
- "cookies",
828
- "series",
829
- "links",
830
- "meta",
831
- "metadata",
832
- "statistics",
833
- "settings",
834
- "options",
835
- "permissions",
836
- "credentials",
837
- "diagnostics",
838
- "warnings",
839
- "errors",
840
- "actions",
841
- "attributes",
842
- "categories",
843
- "features",
844
- "includes",
845
- "tags"
846
- ];
847
- var HAS_MORE_PRIMARY_POSITIVE_EXACT = [
848
- "hasmore",
849
- "hasnext",
850
- "hasnextpage",
851
- "moreitems",
852
- "moreitemsavailable",
853
- "nextpage",
854
- "nextpageexists",
855
- "nextpageavailable",
856
- "hasadditionalresults",
857
- "moreresultsavailable",
858
- "canloadmore",
859
- "hasadditional",
860
- "additionalitems",
861
- "fetchmore"
862
- ];
863
- var HAS_MORE_SECONDARY_POSITIVE_EXACT = ["more", "next"];
864
- var HAS_MORE_PRIMARY_INVERTED_EXACT = [
865
- "islast",
866
- "lastpage",
867
- "endofresults",
868
- "endoflist",
869
- "nomoreitems",
870
- "nomoredata",
871
- "allitemsloaded",
872
- "iscomplete",
873
- "completed"
874
- ];
875
- var HAS_MORE_POSITIVE_REGEX_PATTERNS2 = [
876
- "\\bhas_?more\\b",
877
- "\\bhas_?next\\b",
878
- // e.g., itemsHasNext, items_has_next
879
- "\\bmore_?items\\b",
880
- "\\bnext_?page\\b",
881
- // e.g., userNextPageFlag
882
- "\\badditional\\b",
883
- // e.g., hasAdditionalData, additional_results_exist
884
- "\\bcontinuation\\b",
885
- // e.g., continuationAvailable, has_continuation_token
886
- "\\bmore_?results\\b",
887
- "\\bpage_?available\\b",
888
- "\\bnext(?:_?(page))?\\b"
889
- ];
890
- var COMPILED_HAS_MORE_POSITIVE_REGEXES2 = HAS_MORE_POSITIVE_REGEX_PATTERNS2.map((p) => new RegExp(p, "i"));
891
- var HAS_MORE_INVERTED_REGEX_PATTERNS2 = [
892
- "\\bis_?last\\b",
893
- // e.g., pageIsLast
894
- "\\blast_?page\\b",
895
- // e.g., resultsAreLastPage
896
- "\\bend_?of_?(data|results|list|items|stream)\\b",
897
- "\\bno_?more_?(items|data|results)?\\b",
898
- "\\ball_?(items_?)?loaded\\b",
899
- "\\bis_?complete\\b"
900
- ];
901
- var COMPILED_HAS_MORE_INVERTED_REGEXES2 = HAS_MORE_INVERTED_REGEX_PATTERNS2.map((p) => new RegExp(p, "i"));
902
- function getItemsName(properties) {
903
- const arrayPropertyNames = [];
904
- for (const propName in properties) {
905
- if (propName in properties) {
906
- const propSchema = properties[propName];
907
- if (propSchema && propSchema.type === "array") {
908
- arrayPropertyNames.push(propName);
909
- }
910
- }
911
- }
912
- if (arrayPropertyNames.length === 0) {
913
- return null;
914
- }
915
- if (arrayPropertyNames.length === 1) {
916
- return arrayPropertyNames[0];
917
- }
918
- let bestCandidate = null;
919
- let candidateRank = Infinity;
920
- const updateCandidate = (propName, rank) => {
921
- if (rank < candidateRank) {
922
- bestCandidate = propName;
923
- candidateRank = rank;
924
- }
925
- };
926
- for (const propName of arrayPropertyNames) {
927
- const lowerPropName = propName.toLowerCase();
928
- if (PRIMARY_TOP_TIER_KEYWORDS.includes(lowerPropName)) {
929
- updateCandidate(propName, 2);
930
- continue;
931
- }
932
- if (candidateRank > 3 && PRIMARY_OTHER_KEYWORDS.includes(lowerPropName)) {
933
- updateCandidate(propName, 3);
934
- continue;
935
- }
936
- if (candidateRank > 4 && SECONDARY_KEYWORDS.includes(lowerPropName)) {
937
- updateCandidate(propName, 4);
938
- continue;
939
- }
940
- if (candidateRank > 5 && import_pluralize2.default.isPlural(propName) && !PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)) {
941
- updateCandidate(propName, 5);
942
- continue;
943
- }
944
- if (candidateRank > 6 && import_pluralize2.default.isPlural(propName) && PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)) {
945
- updateCandidate(propName, 6);
946
- continue;
947
- }
948
- }
949
- if (bestCandidate) {
950
- return bestCandidate;
951
- }
952
- return arrayPropertyNames[0];
953
- }
954
- function guess(properties) {
955
- const booleanPropertyNames = [];
956
- for (const propName in properties) {
957
- if (Object.prototype.hasOwnProperty.call(properties, propName)) {
958
- const propSchema = properties[propName];
959
- if (propSchema && propSchema.type === "boolean" || propSchema.type === "integer") {
960
- booleanPropertyNames.push(propName);
961
- }
962
- }
963
- }
964
- if (booleanPropertyNames.length === 0) {
965
- return null;
966
- }
967
- if (booleanPropertyNames.length === 1) {
968
- return booleanPropertyNames[0];
969
- }
970
- let bestCandidate = null;
971
- let candidateRank = Infinity;
972
- const updateCandidate = (propName, rank) => {
973
- if (rank < candidateRank) {
974
- bestCandidate = propName;
975
- candidateRank = rank;
976
- }
977
- };
978
- for (const propName of booleanPropertyNames) {
979
- const normalizedForExactMatch = propName.toLowerCase().replace(/[-_]/g, "");
980
- let currentPropRank = Infinity;
981
- if (HAS_MORE_PRIMARY_POSITIVE_EXACT.includes(normalizedForExactMatch)) {
982
- currentPropRank = 1;
983
- } else if (HAS_MORE_SECONDARY_POSITIVE_EXACT.includes(normalizedForExactMatch)) {
984
- currentPropRank = 2;
985
- } else {
986
- let foundPositiveRegex = false;
987
- for (const regex of COMPILED_HAS_MORE_POSITIVE_REGEXES2) {
988
- if (regex.test(propName)) {
989
- currentPropRank = 3;
990
- foundPositiveRegex = true;
991
- break;
992
- }
993
- }
994
- if (!foundPositiveRegex) {
995
- if (HAS_MORE_PRIMARY_INVERTED_EXACT.includes(normalizedForExactMatch)) {
996
- currentPropRank = 4;
997
- } else {
998
- for (const regex of COMPILED_HAS_MORE_INVERTED_REGEXES2) {
999
- if (regex.test(propName)) {
1000
- currentPropRank = 5;
1001
- break;
1002
- }
1003
- }
1004
- }
1005
- }
1006
- }
1007
- updateCandidate(propName, currentPropRank);
1008
- }
1009
- return bestCandidate;
1010
- }
1011
- function getHasMoreName(properties) {
1012
- const rootGuess = guess(properties);
1013
- if (rootGuess) {
1014
- return rootGuess;
1015
- }
1016
- for (const propName in properties) {
1017
- const propSchema = properties[propName];
1018
- if (propSchema.type === "object" && propSchema.properties) {
1019
- const nested = getHasMoreName(propSchema.properties);
1020
- if (nested) {
1021
- return propName + "." + nested;
1022
- }
1023
- }
1024
- }
1025
- return null;
1026
- }
1027
-
1028
- // packages/spec/dist/lib/pagination/pagination.js
1029
- var OFFSET_PARAM_REGEXES = [
1030
- /\boffset\b/i,
1031
- /\bskip\b/i,
1032
- /\bstart(?:ing_at|_index)?\b/i,
1033
- // e.g., start, starting_at, start_index
1034
- /\bfrom\b/i
1035
- ];
1036
- var GENERIC_LIMIT_PARAM_REGEXES = [
1037
- /\blimit\b/i,
1038
- /\bcount\b/i,
1039
- /\b(?:page_?)?size\b/i,
1040
- // e.g., size, page_size, pagesize
1041
- /\bmax_results\b/i,
1042
- /\bnum_results\b/i,
1043
- /\bshow\b/i,
1044
- // Can sometimes mean limit
1045
- /\bper_?page\b/i,
1046
- // e.g., per_page, perpage
1047
- /\bper-page\b/i,
1048
- /\btake\b/i
1049
- ];
1050
- var PAGE_NUMBER_REGEXES = [
1051
- /^page$/i,
1052
- // Exact match for "page"
1053
- /^p$/i,
1054
- // Exact match for "p" (common shorthand)
1055
- /\bpage_?(?:number|num|idx|index)\b/i
1056
- // e.g., page_number, pageNumber, page_num, page_idx
1057
- ];
1058
- var PAGE_SIZE_REGEXES = [
1059
- /\bpage_?size\b/i,
1060
- // e.g., page_size, pagesize
1061
- /^size$/i,
1062
- // Exact "size"
1063
- // /\bsize\b/i, // Broader "size" - can be ambiguous, prefer more specific ones first
1064
- /\blimit\b/i,
1065
- // Limit is often used for page size
1066
- /\bcount\b/i,
1067
- // Count can also be used for page size
1068
- /\bper_?page\b/i,
1069
- // e.g., per_page, perpage
1070
- /\bper-page\b/i,
1071
- /\bnum_?(?:items|records|results)\b/i,
1072
- // e.g., num_items, numitems
1073
- /\bresults_?per_?page\b/i
1074
- ];
1075
- var CURSOR_REGEXES = [
1076
- /\bcursor\b/i,
1077
- /\bafter(?:_?cursor)?\b/i,
1078
- // e.g., after, after_cursor
1079
- /\bbefore(?:_?cursor)?\b/i,
1080
- // e.g., before, before_cursor
1081
- /\b(next|prev|previous)_?(?:page_?)?token\b/i,
1082
- // e.g., next_page_token, nextPageToken, prev_token
1083
- /\b(next|prev|previous)_?cursor\b/i,
1084
- // e.g., next_cursor, previousCursor
1085
- /\bcontinuation(?:_?token)?\b/i,
1086
- // e.g., continuation, continuation_token
1087
- /\bpage(?:_?(token|id))?\b/i,
1088
- // e.g., after, after_cursor
1089
- /\bstart_?(?:key|cursor|token|after)\b/i
1090
- // e.g., start_key, startCursor, startToken, startAfter
1091
- ];
1092
- var CURSOR_LIMIT_REGEXES = [
1093
- /\blimit\b/i,
1094
- /\bcount\b/i,
1095
- /\bsize\b/i,
1096
- // General size
1097
- /\bfirst\b/i,
1098
- // Common in Relay-style cursor pagination (forward pagination)
1099
- /\blast\b/i,
1100
- // Common in Relay-style cursor pagination (backward pagination)
1101
- /\bpage_?size\b/i,
1102
- // Sometimes page_size is used with cursors
1103
- /\bnum_?(?:items|records|results)\b/i,
1104
- // e.g., num_items
1105
- /\bmax_?items\b/i,
1106
- /\btake\b/i
1107
- ];
1108
- function findParamAndKeyword(queryParams, regexes, excludeParamName) {
1109
- for (const param of queryParams) {
1110
- if (param.name === excludeParamName) {
1111
- continue;
1112
- }
1113
- for (const regex of regexes) {
1114
- const match = param.name.match(regex);
1115
- if (match) {
1116
- return { param, keyword: match[0] };
1117
- }
1118
- }
1119
- }
1120
- return null;
1121
- }
1122
- function isOffsetPagination(operation, parameters) {
1123
- const offsetMatch = findParamAndKeyword(parameters, OFFSET_PARAM_REGEXES);
1124
- if (!offsetMatch)
1125
- return null;
1126
- const limitMatch = findParamAndKeyword(
1127
- parameters,
1128
- GENERIC_LIMIT_PARAM_REGEXES,
1129
- offsetMatch.param.name
1130
- );
1131
- if (!limitMatch)
1132
- return null;
1133
- return {
1134
- type: "offset",
1135
- offsetParamName: offsetMatch.param.name,
1136
- offsetKeyword: offsetMatch.keyword,
1137
- limitParamName: limitMatch.param.name,
1138
- limitKeyword: limitMatch.keyword
1139
- };
1140
- }
1141
- function isPagePagination(operation) {
1142
- const queryParams = operation.parameters.filter((p) => p.in === "query").filter(
1143
- (it) => it.schema && !isRef4(it.schema) && it.schema.type === "integer"
1144
- );
1145
- if (queryParams.length < 2)
1146
- return null;
1147
- const pageNoMatch = findParamAndKeyword(queryParams, PAGE_NUMBER_REGEXES);
1148
- if (!pageNoMatch)
1149
- return null;
1150
- const pageSizeMatch = findParamAndKeyword(
1151
- queryParams,
1152
- PAGE_SIZE_REGEXES,
1153
- pageNoMatch.param.name
1154
- );
1155
- if (!pageSizeMatch)
1156
- return null;
1157
- return {
1158
- type: "page",
1159
- pageNumberParamName: pageNoMatch.param.name,
1160
- pageNumberKeyword: pageNoMatch.keyword,
1161
- pageSizeParamName: pageSizeMatch.param.name,
1162
- pageSizeKeyword: pageSizeMatch.keyword
1163
- };
1164
- }
1165
- function isCursorPagination(operation) {
1166
- const queryParams = operation.parameters.filter((p) => p.in === "query");
1167
- if (queryParams.length < 2)
1168
- return null;
1169
- const cursorMatch = findParamAndKeyword(queryParams, CURSOR_REGEXES);
1170
- if (!cursorMatch)
1171
- return null;
1172
- const limitMatch = findParamAndKeyword(
1173
- queryParams,
1174
- CURSOR_LIMIT_REGEXES,
1175
- cursorMatch.param.name
1176
- );
1177
- if (!limitMatch)
1178
- return null;
1179
- return {
1180
- type: "cursor",
1181
- cursorParamName: cursorMatch.param.name,
1182
- cursorKeyword: cursorMatch.keyword,
1183
- limitParamName: limitMatch.param.name,
1184
- limitKeyword: limitMatch.keyword
1185
- };
1186
- }
1187
- function guessPagination(operation, body, response) {
1188
- const bodyParameters = body && body.properties ? Object.keys(body.properties).map((it) => ({ name: it })) : [];
1189
- const parameters = operation.parameters;
1190
- if (isEmpty3(operation.parameters) && isEmpty3(bodyParameters)) {
1191
- return { type: "none", reason: "no parameters" };
1192
- }
1193
- if (!response) {
1194
- return { type: "none", reason: "no response" };
1195
- }
1196
- if (!response.properties) {
1197
- return { type: "none", reason: "empty response" };
1198
- }
1199
- const properties = response.properties;
1200
- const itemsKey = getItemsName(properties);
1201
- if (!itemsKey) {
1202
- return { type: "none", reason: "no items key" };
1203
- }
1204
- const hasMoreKey = getHasMoreName(excludeKey(properties, itemsKey));
1205
- if (!hasMoreKey) {
1206
- return { type: "none", reason: "no hasMore key" };
1207
- }
1208
- const pagination = isOffsetPagination(operation, [...parameters, ...bodyParameters]) || isPagePagination(operation) || isCursorPagination(operation);
1209
- return pagination ? { ...pagination, items: itemsKey, hasMore: hasMoreKey } : { type: "none", reason: "no pagination" };
1210
- }
1211
- function excludeKey(obj, key) {
1212
- const { [key]: _, ...rest } = obj;
1213
- return rest;
1214
- }
1215
-
1216
- // packages/spec/dist/lib/operation.js
1217
- function augmentSpec(config) {
1218
- config.spec.paths ??= {};
1219
- const paths = {};
1220
- for (const [path, pathItem] of Object.entries(config.spec.paths)) {
1221
- const { parameters = [], ...methods2 } = pathItem;
1222
- const fixedPath = path.replace(/:([^/]+)/g, "{$1}");
1223
- for (const [method, operation] of Object.entries(methods2)) {
1224
- const formatOperationId = config.operationId ?? defaults.operationId;
1225
- const formatTag = config.tag ?? defaults.tag;
1226
- const operationId = formatOperationId(operation, fixedPath, method);
1227
- const operationTag = formatTag(operation, fixedPath);
1228
- const requestBody = isRef5(operation.requestBody) ? followRef3(config.spec, operation.requestBody.$ref) : operation.requestBody;
1229
- const tunedOperation = {
1230
- ...operation,
1231
- parameters: [...parameters, ...operation.parameters ?? []].map(
1232
- (it) => isRef5(it) ? followRef3(config.spec, it.$ref) : it
1233
- ),
1234
- tags: [operationTag],
1235
- operationId,
1236
- responses: resolveResponses(config.spec, operation),
1237
- requestBody
1238
- };
1239
- tunedOperation["x-pagination"] = toPagination(
1240
- config.spec,
1241
- tunedOperation
1242
- );
1243
- Object.assign(paths, {
1244
- [fixedPath]: {
1245
- ...paths[fixedPath],
1246
- [method]: tunedOperation
1247
- }
1248
- });
1249
- }
1250
- }
1251
- return { ...config.spec, paths };
1252
- }
1253
- function toPagination(spec, tunedOperation) {
1254
- if (tunedOperation["x-pagination"]) {
1255
- return tunedOperation["x-pagination"];
1256
- }
1257
- const schema = getResponseContentSchema(
1258
- spec,
1259
- tunedOperation.responses["200"],
1260
- "application/json"
1261
- );
1262
- const pagination = guessPagination(
1263
- tunedOperation,
1264
- tunedOperation.requestBody ? getRequestContentSchema(
1265
- spec,
1266
- tunedOperation.requestBody,
1267
- "application/json"
1268
- ) : void 0,
1269
- schema
1270
- );
1271
- if (pagination && pagination.type !== "none" && schema) {
1272
- return pagination;
1273
- }
1274
- return void 0;
1275
- }
1276
- function getResponseContentSchema(spec, response, type) {
1277
- if (!response) {
1278
- return void 0;
1279
- }
1280
- const content = response.content;
1281
- if (!content) {
1282
- return void 0;
1283
- }
1284
- for (const contentType in content) {
1285
- if (contentType.toLowerCase() === type.toLowerCase()) {
1286
- return isRef5(content[contentType].schema) ? followRef3(spec, content[contentType].schema.$ref) : content[contentType].schema;
1287
- }
1288
- }
1289
- return void 0;
1290
- }
1291
- function getRequestContentSchema(spec, requestBody, type) {
1292
- const content = requestBody.content;
1293
- if (!content) {
1294
- return void 0;
1295
- }
1296
- for (const contentType in content) {
1297
- if (contentType.toLowerCase() === type.toLowerCase()) {
1298
- return isRef5(content[contentType].schema) ? followRef3(spec, content[contentType].schema.$ref) : content[contentType].schema;
1299
- }
1300
- }
1301
- return void 0;
1302
- }
1303
- var defaults = {
1304
- operationId: (operation, path, method) => {
1305
- if (operation.operationId) {
1306
- return camelcase2(operation.operationId);
1307
- }
1308
- const metadata = operation["x-oaiMeta"];
1309
- if (metadata && metadata.name) {
1310
- return camelcase2(metadata.name);
1311
- }
1312
- return camelcase2(
1313
- [method, ...path.replace(/[\\/\\{\\}]/g, " ").split(" ")].filter(Boolean).join(" ").trim()
1314
- );
1315
- },
1316
- tag: (operation, path) => {
1317
- return operation.tags?.[0] ? sanitizeTag(operation.tags?.[0]) : determineGenericTag(path, operation);
1318
- }
1319
- };
1320
- function resolveResponses(spec, operation) {
1321
- const responses = operation.responses ?? {};
1322
- const resolved = {};
1323
- for (const status in responses) {
1324
- const response = isRef5(responses[status]) ? followRef3(spec, responses[status].$ref) : responses[status];
1325
- resolved[status] = response;
1326
- }
1327
- return resolved;
1328
- }
1329
- function forEachOperation2(config, callback) {
1330
- const result = [];
1331
- for (const [path, pathItem] of Object.entries(config.spec.paths ?? {})) {
1332
- const { parameters = [], ...methods2 } = pathItem;
1333
- for (const [method, operation] of Object.entries(methods2)) {
1334
- const metadata = operation["x-oaiMeta"] ?? {};
1335
- const operationTag = operation.tags?.[0];
1336
- result.push(
1337
- callback(
1338
- {
1339
- name: metadata.name,
1340
- method,
1341
- path,
1342
- groupName: operationTag,
1343
- tag: operationTag
1344
- },
1345
- operation
1346
- )
1347
- );
1348
- }
1349
- }
1350
- return result;
1351
- }
1352
- var reservedKeywords = /* @__PURE__ */ new Set([
1353
- "await",
1354
- // Reserved in async functions
1355
- "break",
1356
- "case",
1357
- "catch",
1358
- "class",
1359
- "const",
1360
- "continue",
1361
- "debugger",
1362
- "default",
1363
- "delete",
1364
- "do",
1365
- "else",
1366
- "enum",
1367
- "export",
1368
- "extends",
1369
- "false",
1370
- "finally",
1371
- "for",
1372
- "function",
1373
- "if",
1374
- "implements",
1375
- // Strict mode
1376
- "import",
1377
- "in",
1378
- "instanceof",
1379
- "interface",
1380
- // Strict mode
1381
- "let",
1382
- // Strict mode
1383
- "new",
1384
- "null",
1385
- "package",
1386
- // Strict mode
1387
- "private",
1388
- // Strict mode
1389
- "protected",
1390
- // Strict mode
1391
- "public",
1392
- // Strict mode
1393
- "return",
1394
- "static",
1395
- // Strict mode
1396
- "super",
1397
- "switch",
1398
- "this",
1399
- "throw",
1400
- "true",
1401
- "try",
1402
- "typeof",
1403
- "var",
1404
- "void",
1405
- "while",
1406
- "with",
1407
- "yield",
1408
- // Strict mode / Generator functions
1409
- // 'arguments' is not technically a reserved word, but it's a special identifier within functions
1410
- // and assigning to it or declaring it can cause issues or unexpected behavior.
1411
- "arguments"
1412
- ]);
1413
- function sanitizeTag(camelCasedTag) {
1414
- if (/^\d/.test(camelCasedTag)) {
1415
- return `_${camelCasedTag}`;
1416
- }
1417
- return reservedKeywords.has(camelcase2(camelCasedTag)) ? `${camelCasedTag}_` : camelCasedTag;
1418
- }
1419
- function determineGenericTag(pathString, operation) {
1420
- const operationId = operation.operationId || "";
1421
- const VERSION_REGEX = /^[vV]\d+$/;
1422
- const commonVerbs = /* @__PURE__ */ new Set([
1423
- // Verbs to potentially strip from operationId prefix
1424
- "get",
1425
- "list",
1426
- "create",
1427
- "update",
1428
- "delete",
1429
- "post",
1430
- "put",
1431
- "patch",
1432
- "do",
1433
- "send",
1434
- "add",
1435
- "remove",
1436
- "set",
1437
- "find",
1438
- "search",
1439
- "check",
1440
- "make"
1441
- ]);
1442
- const segments = pathString.split("/").filter(Boolean);
1443
- const potentialCandidates = segments.filter(
1444
- (segment) => segment && !segment.startsWith("{") && !segment.endsWith("}") && !VERSION_REGEX.test(segment)
1445
- );
1446
- for (let i = potentialCandidates.length - 1; i >= 0; i--) {
1447
- const segment = potentialCandidates[i];
1448
- if (!segment.startsWith("@")) {
1449
- return sanitizeTag(camelcase2(segment));
1450
- }
1451
- }
1452
- const canFallbackToPathSegment = potentialCandidates.length > 0;
1453
- if (operationId) {
1454
- const lowerOpId = operationId.toLowerCase();
1455
- const parts = operationId.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").replace(/([a-zA-Z])(\d)/g, "$1_$2").replace(/(\d)([a-zA-Z])/g, "$1_$2").toLowerCase().split(/[_-\s]+/);
1456
- const validParts = parts.filter(Boolean);
1457
- if (commonVerbs.has(lowerOpId) && validParts.length === 1 && canFallbackToPathSegment) {
1458
- } else if (validParts.length > 0) {
1459
- const firstPart = validParts[0];
1460
- const isFirstPartVerb = commonVerbs.has(firstPart);
1461
- if (isFirstPartVerb && validParts.length > 1) {
1462
- const verbPrefixLength = firstPart.length;
1463
- let nextPartStartIndex = -1;
1464
- if (operationId.length > verbPrefixLength) {
1465
- const charAfterPrefix = operationId[verbPrefixLength];
1466
- if (charAfterPrefix >= "A" && charAfterPrefix <= "Z") {
1467
- nextPartStartIndex = verbPrefixLength;
1468
- } else if (charAfterPrefix >= "0" && charAfterPrefix <= "9") {
1469
- nextPartStartIndex = verbPrefixLength;
1470
- } else if (["_", "-"].includes(charAfterPrefix)) {
1471
- nextPartStartIndex = verbPrefixLength + 1;
1472
- } else {
1473
- const match = operationId.substring(verbPrefixLength).match(/[A-Z0-9]/);
1474
- if (match && match.index !== void 0) {
1475
- nextPartStartIndex = verbPrefixLength + match.index;
1476
- }
1477
- if (nextPartStartIndex === -1 && operationId.length > verbPrefixLength) {
1478
- nextPartStartIndex = verbPrefixLength;
1479
- }
1480
- }
1481
- }
1482
- if (nextPartStartIndex !== -1 && nextPartStartIndex < operationId.length) {
1483
- const remainingOriginalSubstring = operationId.substring(nextPartStartIndex);
1484
- const potentialTag = camelcase2(remainingOriginalSubstring);
1485
- if (potentialTag) {
1486
- return sanitizeTag(potentialTag);
1487
- }
1488
- }
1489
- const potentialTagJoined = camelcase2(validParts.slice(1).join("_"));
1490
- if (potentialTagJoined) {
1491
- return sanitizeTag(potentialTagJoined);
1492
- }
1493
- }
1494
- const potentialTagFull = camelcase2(operationId);
1495
- if (potentialTagFull) {
1496
- const isResultSingleVerb = validParts.length === 1 && isFirstPartVerb;
1497
- if (!(isResultSingleVerb && canFallbackToPathSegment)) {
1498
- if (potentialTagFull.length > 0) {
1499
- return sanitizeTag(potentialTagFull);
1500
- }
1501
- }
1502
- }
1503
- const firstPartCamel = camelcase2(firstPart);
1504
- if (firstPartCamel) {
1505
- const isFirstPartCamelVerb = commonVerbs.has(firstPartCamel);
1506
- if (!isFirstPartCamelVerb || validParts.length === 1 || !canFallbackToPathSegment) {
1507
- return sanitizeTag(firstPartCamel);
1508
- }
1509
- }
1510
- if (isFirstPartVerb && validParts.length > 1 && validParts[1] && canFallbackToPathSegment) {
1511
- const secondPartCamel = camelcase2(validParts[1]);
1512
- if (secondPartCamel) {
1513
- return sanitizeTag(secondPartCamel);
1514
- }
1515
- }
1516
- }
1517
- }
1518
- if (potentialCandidates.length > 0) {
1519
- let firstCandidate = potentialCandidates[0];
1520
- if (firstCandidate.startsWith("@")) {
1521
- firstCandidate = firstCandidate.substring(1);
1522
- }
1523
- if (firstCandidate) {
1524
- return sanitizeTag(camelcase2(firstCandidate));
1525
- }
1526
- }
1527
- console.warn(
1528
- `Could not determine a suitable tag for path: ${pathString}, operationId: ${operationId}. Using 'unknown'.`
1529
- );
1530
- return "unknown";
1531
- }
1532
- function patchParameters(spec, objectSchema, operation) {
1533
- const securitySchemes = spec.components?.securitySchemes ?? {};
1534
- const securityOptions = securityToOptions(
1535
- spec,
1536
- operation.security ?? [],
1537
- securitySchemes
1538
- );
1539
- objectSchema.properties ??= {};
1540
- objectSchema.required ??= [];
1541
- for (const param of operation.parameters) {
1542
- if (param.required) {
1543
- objectSchema.required.push(param.name);
1544
- }
1545
- objectSchema.properties[param.name] = isRef5(param.schema) ? followRef3(spec, param.schema.$ref) : param.schema ?? { type: "string" };
1546
- }
1547
- for (const param of securityOptions) {
1548
- objectSchema.required = (objectSchema.required ?? []).filter(
1549
- (name) => name !== param.name
1550
- );
1551
- objectSchema.properties[param.name] = isRef5(param.schema) ? followRef3(spec, param.schema.$ref) : param.schema ?? { type: "string" };
1552
- }
1553
- }
1554
- function securityToOptions(spec, security2, securitySchemes, staticIn) {
1555
- securitySchemes ??= {};
1556
- const parameters = [];
1557
- for (const it of security2) {
1558
- const [name] = Object.keys(it);
1559
- if (!name) {
1560
- continue;
1561
- }
1562
- const schema = isRef5(securitySchemes[name]) ? followRef3(spec, securitySchemes[name].$ref) : securitySchemes[name];
1563
- if (schema.type === "http") {
1564
- parameters.push({
1565
- in: staticIn ?? "header",
1566
- name: "authorization",
1567
- schema: { type: "string" }
1568
- });
1569
- continue;
1570
- }
1571
- if (schema.type === "apiKey") {
1572
- if (!schema.in) {
1573
- throw new Error(`apiKey security schema must have an "in" field`);
1574
- }
1575
- if (!schema.name) {
1576
- throw new Error(`apiKey security schema must have a "name" field`);
1577
- }
1578
- parameters.push({
1579
- in: staticIn ?? schema.in,
1580
- name: schema.name,
1581
- schema: { type: "string" }
1582
- });
1583
- continue;
1584
- }
1585
- }
1586
- return parameters;
1587
- }
13
+ import { toReadme } from "@sdk-it/readme";
14
+ import {
15
+ augmentSpec,
16
+ cleanFiles,
17
+ readWriteMetadata,
18
+ sanitizeTag as sanitizeTag4
19
+ } from "@sdk-it/spec";
1588
20
 
1589
21
  // packages/typescript/src/lib/client.ts
1590
22
  import { toLitObject } from "@sdk-it/core";
@@ -1709,19 +141,188 @@ export class ${spec.name} {
1709
141
  }
1710
142
  }
1711
143
  }
1712
- }`;
144
+ }`;
145
+ };
146
+
147
+ // packages/typescript/src/lib/emitters/interface.ts
148
+ import { followRef, isRef, parseRef, pascalcase } from "@sdk-it/core";
149
+ import { isPrimitiveSchema, sanitizeTag } from "@sdk-it/spec";
150
+ var TypeScriptEmitter = class {
151
+ #spec;
152
+ constructor(spec) {
153
+ this.#spec = spec;
154
+ }
155
+ #stringifyKey = (value) => {
156
+ return `'${value}'`;
157
+ };
158
+ object(schema, required = false) {
159
+ const properties = schema.properties || {};
160
+ const propEntries = Object.entries(properties).map(([key, propSchema]) => {
161
+ const isRequired = (schema.required ?? []).includes(key);
162
+ const tsType = this.handle(propSchema, isRequired);
163
+ return `${this.#stringifyKey(key)}: ${tsType}`;
164
+ });
165
+ if (schema.additionalProperties) {
166
+ if (typeof schema.additionalProperties === "object") {
167
+ const indexType = this.handle(schema.additionalProperties, true);
168
+ propEntries.push(`[key: string]: ${indexType}`);
169
+ } else if (schema.additionalProperties === true) {
170
+ propEntries.push("[key: string]: any");
171
+ }
172
+ }
173
+ return `${propEntries.length ? `{ ${propEntries.join("; ")} }` : "unknown"}`;
174
+ }
175
+ /**
176
+ * Handle arrays (items could be a single schema or a tuple)
177
+ */
178
+ #array(schema, required = false) {
179
+ const { items } = schema;
180
+ if (!items) {
181
+ return "any[]";
182
+ }
183
+ if (Array.isArray(items)) {
184
+ const tupleItems = items.map((sub) => this.handle(sub, true));
185
+ return `[${tupleItems.join(", ")}]`;
186
+ }
187
+ const itemsType = this.handle(items, true);
188
+ return itemsType.length > 1 ? `(${itemsType})[]` : `${itemsType}[]`;
189
+ }
190
+ /**
191
+ * Convert a basic type (string | number | boolean | object | array, etc.) to TypeScript
192
+ */
193
+ normal(type, schema, required = false) {
194
+ switch (type) {
195
+ case "string":
196
+ return this.string(schema, required);
197
+ case "number":
198
+ case "integer":
199
+ return this.number(schema, required);
200
+ case "boolean":
201
+ return appendOptional("boolean", required);
202
+ case "object":
203
+ return this.object(schema, required);
204
+ case "array":
205
+ return this.#array(schema, required);
206
+ case "null":
207
+ return "null";
208
+ default:
209
+ console.warn(`Unknown type: ${type}`);
210
+ return appendOptional("any", required);
211
+ }
212
+ }
213
+ #ref($ref, required) {
214
+ const schemaName = pascalcase(sanitizeTag(parseRef($ref).model));
215
+ const schema = followRef(this.#spec, $ref);
216
+ if (isPrimitiveSchema(schema)) {
217
+ return this.handle(schema, required);
218
+ }
219
+ return `models.${appendOptional(schemaName, required)}`;
220
+ }
221
+ allOf(schemas) {
222
+ const allOfTypes = schemas.map((sub) => this.handle(sub, true));
223
+ return allOfTypes.length > 1 ? `${allOfTypes.join(" & ")}` : allOfTypes[0];
224
+ }
225
+ oneOf(schemas, required) {
226
+ const oneOfTypes = schemas.map((sub) => this.handle(sub, true));
227
+ return appendOptional(
228
+ oneOfTypes.length > 1 ? `${oneOfTypes.join(" | ")}` : oneOfTypes[0],
229
+ required
230
+ );
231
+ }
232
+ anyOf(schemas, required) {
233
+ return this.oneOf(schemas, required);
234
+ }
235
+ enum(values, required) {
236
+ const enumValues = values.map((val) => typeof val === "string" ? `'${val}'` : `${val}`).join(" | ");
237
+ return appendOptional(enumValues, required);
238
+ }
239
+ /**
240
+ * Handle string type with formats
241
+ */
242
+ string(schema, required) {
243
+ let type;
244
+ if (schema.contentEncoding === "binary") {
245
+ return appendOptional("Blob", required);
246
+ }
247
+ switch (schema.format) {
248
+ case "date-time":
249
+ case "datetime":
250
+ case "date":
251
+ type = "Date";
252
+ break;
253
+ case "binary":
254
+ case "byte":
255
+ type = "Blob";
256
+ break;
257
+ case "int64":
258
+ type = "bigint";
259
+ break;
260
+ default:
261
+ type = "string";
262
+ }
263
+ return appendOptional(type, required);
264
+ }
265
+ /**
266
+ * Handle number/integer types with formats
267
+ */
268
+ number(schema, required) {
269
+ const type = schema.format === "int64" ? "bigint" : "number";
270
+ return appendOptional(type, required);
271
+ }
272
+ handle(schema, required) {
273
+ if (isRef(schema)) {
274
+ return this.#ref(schema.$ref, required);
275
+ }
276
+ if (schema.allOf && Array.isArray(schema.allOf)) {
277
+ return this.allOf(schema.allOf);
278
+ }
279
+ if (schema.anyOf && Array.isArray(schema.anyOf)) {
280
+ return this.anyOf(schema.anyOf, required);
281
+ }
282
+ if (schema.oneOf && Array.isArray(schema.oneOf)) {
283
+ return this.oneOf(schema.oneOf, required);
284
+ }
285
+ if (schema.enum && Array.isArray(schema.enum)) {
286
+ return this.enum(schema.enum, required);
287
+ }
288
+ if (schema.const) {
289
+ return this.enum([schema.const], true);
290
+ }
291
+ const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
292
+ if (!types.length) {
293
+ if ("properties" in schema) {
294
+ return this.object(schema, required);
295
+ }
296
+ return appendOptional("any", required);
297
+ }
298
+ if (types.length > 1) {
299
+ const realTypes = types.filter((t) => t !== "null");
300
+ if (realTypes.length === 1 && types.includes("null")) {
301
+ const tsType = this.normal(realTypes[0], schema, false);
302
+ return appendOptional(`${tsType} | null`, required);
303
+ }
304
+ const typeResults = types.map((t) => this.normal(t, schema, false));
305
+ return appendOptional(typeResults.join(" | "), required);
306
+ }
307
+ return this.normal(types[0], schema, required);
308
+ }
1713
309
  };
310
+ function appendOptional(type, isRequired) {
311
+ return isRequired ? type : `${type} | undefined`;
312
+ }
1714
313
 
1715
314
  // packages/typescript/src/lib/generator.ts
1716
315
  import { merge, template } from "lodash-es";
1717
316
  import { join } from "node:path";
1718
- import { camelcase as camelcase4, pascalcase as pascalcase2, spinalcase as spinalcase2 } from "stringcase";
1719
- import { followRef as followRef7, isEmpty as isEmpty4, isRef as isRef10 } from "@sdk-it/core";
317
+ import { camelcase as camelcase2, spinalcase } from "stringcase";
318
+ import { followRef as followRef4, isEmpty as isEmpty2, isRef as isRef4, resolveRef } from "@sdk-it/core";
319
+ import { forEachOperation } from "@sdk-it/spec";
1720
320
 
1721
321
  // packages/typescript/src/lib/emitters/zod.ts
1722
- import { cleanRef, followRef as followRef4, isRef as isRef6 } from "@sdk-it/core";
322
+ import { followRef as followRef2, isRef as isRef2, parseRef as parseRef2, pascalcase as pascalcase2 } from "@sdk-it/core";
323
+ import { isPrimitiveSchema as isPrimitiveSchema2, sanitizeTag as sanitizeTag2 } from "@sdk-it/spec";
1723
324
  var ZodEmitter = class {
1724
- generatedRefs = /* @__PURE__ */ new Set();
325
+ #generatedRefs = /* @__PURE__ */ new Set();
1725
326
  #spec;
1726
327
  #onRef;
1727
328
  constructor(spec, onRef) {
@@ -1748,25 +349,21 @@ var ZodEmitter = class {
1748
349
  }
1749
350
  return `z.object({${propEntries.join(", ")}})${additionalProps}`;
1750
351
  }
1751
- /**
1752
- * Handle arrays (items could be a single schema or a tuple (array of schemas)).
1753
- * In JSON Schema 2020-12, `items` can be an array → tuple style.
1754
- */
1755
- array(schema, required = false) {
352
+ #array(schema, required = false) {
1756
353
  const { items } = schema;
1757
354
  if (!items) {
1758
- return `z.array(z.unknown())${appendOptional(required)}`;
355
+ return `z.array(z.unknown())${appendOptional2(required)}`;
1759
356
  }
1760
357
  if (Array.isArray(items)) {
1761
358
  const tupleItems = items.map((sub) => this.handle(sub, true));
1762
359
  const base = `z.tuple([${tupleItems.join(", ")}])`;
1763
- return `${base}${appendOptional(required)}`;
360
+ return `${base}${appendOptional2(required)}`;
1764
361
  }
1765
362
  const itemsSchema = this.handle(items, true);
1766
- return `z.array(${itemsSchema})${appendOptional(required)}`;
363
+ return `z.array(${itemsSchema})${this.#suffixes(JSON.stringify(schema.default), required, false)}`;
1767
364
  }
1768
365
  #suffixes = (defaultValue, required, nullable) => {
1769
- return `${nullable ? ".nullable()" : ""}${appendDefault(defaultValue)}${appendOptional(required)}`;
366
+ return `${nullable ? ".nullable()" : ""}${appendDefault(defaultValue)}${appendOptional2(required)}`;
1770
367
  };
1771
368
  /**
1772
369
  * Convert a basic type (string | number | boolean | object | array, etc.) to Zod.
@@ -1786,55 +383,58 @@ var ZodEmitter = class {
1786
383
  case "object":
1787
384
  return `${this.object(schema)}${this.#suffixes(JSON.stringify(schema.default), required, nullable)}`;
1788
385
  case "array":
1789
- return this.array(schema, required);
386
+ return this.#array(schema, required);
1790
387
  case "null":
1791
- return `z.null()${appendOptional(required)}`;
388
+ return `z.null()${appendOptional2(required)}`;
1792
389
  default:
1793
- return `z.unknown()${appendOptional(required)}`;
390
+ return `z.unknown()${appendOptional2(required)}`;
1794
391
  }
1795
392
  }
1796
- ref($ref, required) {
1797
- const schemaName = cleanRef($ref).split("/").pop();
1798
- if (this.generatedRefs.has(schemaName)) {
393
+ #ref($ref, required) {
394
+ const schemaName = pascalcase2(sanitizeTag2(parseRef2($ref).model));
395
+ const schema = followRef2(this.#spec, $ref);
396
+ if (isPrimitiveSchema2(schema)) {
397
+ const result = this.handle(schema, required);
398
+ this.#onRef?.(schemaName, result);
399
+ return result;
400
+ }
401
+ if (this.#generatedRefs.has(schemaName)) {
1799
402
  return schemaName;
1800
403
  }
1801
- this.generatedRefs.add(schemaName);
1802
- this.#onRef?.(
1803
- schemaName,
1804
- this.handle(followRef4(this.#spec, $ref), required)
1805
- );
404
+ this.#generatedRefs.add(schemaName);
405
+ this.#onRef?.(schemaName, this.handle(schema, required));
1806
406
  return schemaName;
1807
407
  }
408
+ #toIntersection(schemas) {
409
+ const [left, ...right] = schemas;
410
+ if (!right.length) {
411
+ return left;
412
+ }
413
+ return `z.intersection(${left}, ${this.#toIntersection(right)})`;
414
+ }
1808
415
  allOf(schemas, required) {
1809
416
  const allOfSchemas = schemas.map((sub) => this.handle(sub, true));
1810
417
  if (allOfSchemas.length === 0) {
1811
418
  return `z.unknown()`;
1812
419
  }
1813
420
  if (allOfSchemas.length === 1) {
1814
- return `${allOfSchemas[0]}${appendOptional(required)}`;
1815
- }
1816
- return `${this.#toIntersection(allOfSchemas)}${appendOptional(required)}`;
1817
- }
1818
- #toIntersection(schemas) {
1819
- const [left, ...right] = schemas;
1820
- if (!right.length) {
1821
- return left;
421
+ return `${allOfSchemas[0]}${appendOptional2(required)}`;
1822
422
  }
1823
- return `z.intersection(${left}, ${this.#toIntersection(right)})`;
423
+ return `${this.#toIntersection(allOfSchemas)}${appendOptional2(required)}`;
1824
424
  }
1825
425
  anyOf(schemas, required) {
1826
426
  const anyOfSchemas = schemas.map((sub) => this.handle(sub, true));
1827
427
  if (anyOfSchemas.length === 1) {
1828
- return `${anyOfSchemas[0]}${appendOptional(required)}`;
428
+ return `${anyOfSchemas[0]}${appendOptional2(required)}`;
1829
429
  }
1830
- return `z.union([${anyOfSchemas.join(", ")}])${appendOptional(required)}`;
430
+ return `z.union([${anyOfSchemas.join(", ")}])${appendOptional2(required)}`;
1831
431
  }
1832
432
  oneOf(schemas, required) {
1833
433
  const oneOfSchemas = schemas.map((sub) => this.handle(sub, true));
1834
434
  if (oneOfSchemas.length === 1) {
1835
- return `${oneOfSchemas[0]}${appendOptional(required)}`;
435
+ return `${oneOfSchemas[0]}${appendOptional2(required)}`;
1836
436
  }
1837
- return `z.union([${oneOfSchemas.join(", ")}])${appendOptional(required)}`;
437
+ return `z.union([${oneOfSchemas.join(", ")}])${appendOptional2(required)}`;
1838
438
  }
1839
439
  enum(type, values) {
1840
440
  if (values.length === 1) {
@@ -1931,8 +531,8 @@ var ZodEmitter = class {
1931
531
  return { base, defaultValue };
1932
532
  }
1933
533
  handle(schema, required) {
1934
- if (isRef6(schema)) {
1935
- return `${this.ref(schema.$ref, true)}${appendOptional(required)}`;
534
+ if (isRef2(schema)) {
535
+ return `${this.#ref(schema.$ref, true)}${appendOptional2(required)}`;
1936
536
  }
1937
537
  if (schema.allOf && Array.isArray(schema.allOf)) {
1938
538
  return this.allOf(schema.allOf ?? [], required);
@@ -1950,7 +550,7 @@ var ZodEmitter = class {
1950
550
  }
1951
551
  const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
1952
552
  if (!types.length) {
1953
- return `z.unknown()${appendOptional(required)}`;
553
+ return `z.unknown()${appendOptional2(required)}`;
1954
554
  }
1955
555
  if ("nullable" in schema && schema.nullable) {
1956
556
  types.push("null");
@@ -1963,12 +563,12 @@ var ZodEmitter = class {
1963
563
  return this.normal(realTypes[0], schema, required, true);
1964
564
  }
1965
565
  const subSchemas = types.map((t) => this.normal(t, schema, false));
1966
- return `z.union([${subSchemas.join(", ")}])${appendOptional(required)}`;
566
+ return `z.union([${subSchemas.join(", ")}])${appendOptional2(required)}`;
1967
567
  }
1968
568
  return this.normal(types[0], schema, required, false);
1969
569
  }
1970
570
  };
1971
- function appendOptional(isRequired) {
571
+ function appendOptional2(isRequired) {
1972
572
  return isRequired ? "" : ".optional()";
1973
573
  }
1974
574
  function appendDefault(defaultValue) {
@@ -1976,201 +576,46 @@ function appendDefault(defaultValue) {
1976
576
  }
1977
577
 
1978
578
  // packages/typescript/src/lib/sdk.ts
1979
- import { get } from "lodash-es";
1980
- import { camelcase as camelcase3, pascalcase, spinalcase } from "stringcase";
1981
- import { isRef as isRef9, toLitObject as toLitObject2 } from "@sdk-it/core";
1982
-
1983
- // packages/typescript/src/lib/emitters/interface.ts
1984
- import { cleanRef as cleanRef2, followRef as followRef5, isRef as isRef7 } from "@sdk-it/core";
1985
- var TypeScriptEmitter = class {
1986
- generatedRefs = /* @__PURE__ */ new Set();
1987
- #spec;
1988
- #onRef;
1989
- constructor(spec, onRef) {
1990
- this.#spec = spec;
1991
- this.#onRef = onRef;
1992
- }
1993
- #stringifyKey = (value) => {
1994
- return `'${value}'`;
1995
- };
1996
- #isInternal = (schema) => {
1997
- return isRef7(schema) ? false : !!schema["x-internal"];
1998
- };
1999
- /**
2000
- * Handle objects (properties)
2001
- */
2002
- object(schema, required = false) {
2003
- const properties = schema.properties || {};
2004
- const propEntries = Object.entries(properties).map(([key, propSchema]) => {
2005
- const isRequired = (schema.required ?? []).includes(key);
2006
- const tsType = this.handle(propSchema, isRequired);
2007
- return `${this.#isInternal(propSchema) ? key : this.#stringifyKey(key)}: ${tsType}`;
2008
- });
2009
- if (schema.additionalProperties) {
2010
- if (typeof schema.additionalProperties === "object") {
2011
- const indexType = this.handle(schema.additionalProperties, true);
2012
- propEntries.push(`[key: string]: ${indexType}`);
2013
- } else if (schema.additionalProperties === true) {
2014
- propEntries.push("[key: string]: any");
2015
- }
2016
- }
2017
- return `${propEntries.length ? `{ ${propEntries.join("; ")} }` : "unknown"}`;
2018
- }
2019
- /**
2020
- * Handle arrays (items could be a single schema or a tuple)
2021
- */
2022
- array(schema, required = false) {
2023
- const { items } = schema;
2024
- if (!items) {
2025
- return "any[]";
2026
- }
2027
- if (Array.isArray(items)) {
2028
- const tupleItems = items.map((sub) => this.handle(sub, true));
2029
- return `[${tupleItems.join(", ")}]`;
2030
- }
2031
- const itemsType = this.handle(items, true);
2032
- return `${itemsType}[]`;
2033
- }
2034
- /**
2035
- * Convert a basic type (string | number | boolean | object | array, etc.) to TypeScript
2036
- */
2037
- normal(type, schema, required = false) {
2038
- switch (type) {
2039
- case "string":
2040
- return this.string(schema, required);
2041
- case "number":
2042
- case "integer":
2043
- return this.number(schema, required);
2044
- case "boolean":
2045
- return appendOptional2("boolean", required);
2046
- case "object":
2047
- return this.object(schema, required);
2048
- case "array":
2049
- return this.array(schema, required);
2050
- case "null":
2051
- return "null";
2052
- default:
2053
- console.warn(`Unknown type: ${type}`);
2054
- return appendOptional2("any", required);
2055
- }
2056
- }
2057
- ref($ref, required) {
2058
- const schemaName = cleanRef2($ref).split("/").pop();
2059
- if (this.generatedRefs.has(schemaName)) {
2060
- return schemaName;
2061
- }
2062
- this.generatedRefs.add(schemaName);
2063
- this.#onRef?.(
2064
- schemaName,
2065
- this.handle(followRef5(this.#spec, $ref), required)
2066
- );
2067
- return appendOptional2(schemaName, required);
2068
- }
2069
- allOf(schemas) {
2070
- const allOfTypes = schemas.map((sub) => this.handle(sub, true));
2071
- return allOfTypes.length > 1 ? `${allOfTypes.join(" & ")}` : allOfTypes[0];
2072
- }
2073
- anyOf(schemas, required) {
2074
- const anyOfTypes = schemas.map((sub) => this.handle(sub, true));
2075
- return appendOptional2(
2076
- anyOfTypes.length > 1 ? `${anyOfTypes.join(" | ")}` : anyOfTypes[0],
2077
- required
2078
- );
2079
- }
2080
- oneOf(schemas, required) {
2081
- const oneOfTypes = schemas.map((sub) => {
2082
- return this.handle(sub, false);
2083
- });
2084
- return appendOptional2(
2085
- oneOfTypes.length > 1 ? `${oneOfTypes.join(" | ")}` : oneOfTypes[0],
2086
- required
2087
- );
2088
- }
2089
- enum(values, required) {
2090
- const enumValues = values.map((val) => typeof val === "string" ? `'${val}'` : `${val}`).join(" | ");
2091
- return appendOptional2(enumValues, required);
2092
- }
2093
- /**
2094
- * Handle string type with formats
2095
- */
2096
- string(schema, required) {
2097
- let type;
2098
- if (schema.contentEncoding === "binary") {
2099
- return appendOptional2("Blob", required);
2100
- }
2101
- switch (schema.format) {
2102
- case "date-time":
2103
- case "datetime":
2104
- case "date":
2105
- type = "Date";
2106
- break;
2107
- case "binary":
2108
- case "byte":
2109
- type = "Blob";
2110
- break;
2111
- case "int64":
2112
- type = "bigint";
2113
- break;
2114
- default:
2115
- type = "string";
2116
- }
2117
- return appendOptional2(type, required);
2118
- }
2119
- /**
2120
- * Handle number/integer types with formats
2121
- */
2122
- number(schema, required) {
2123
- const type = schema.format === "int64" ? "bigint" : "number";
2124
- return appendOptional2(type, required);
2125
- }
2126
- handle(schema, required) {
2127
- if (isRef7(schema)) {
2128
- return this.ref(schema.$ref, required);
2129
- }
2130
- if (schema.allOf && Array.isArray(schema.allOf)) {
2131
- return this.allOf(schema.allOf);
2132
- }
2133
- if (schema.anyOf && Array.isArray(schema.anyOf)) {
2134
- return this.anyOf(schema.anyOf, required);
2135
- }
2136
- if (schema.oneOf && Array.isArray(schema.oneOf)) {
2137
- return this.oneOf(schema.oneOf, required);
2138
- }
2139
- if (schema.enum && Array.isArray(schema.enum)) {
2140
- return this.enum(schema.enum, required);
2141
- }
2142
- if (schema.const) {
2143
- if (schema["x-internal"]) {
2144
- return `${schema.const}`;
2145
- }
2146
- return this.enum([schema.const], required);
2147
- }
2148
- const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
2149
- if (!types.length) {
2150
- if ("properties" in schema) {
2151
- return this.object(schema, required);
2152
- }
2153
- return appendOptional2("any", required);
2154
- }
2155
- if (types.length > 1) {
2156
- const realTypes = types.filter((t) => t !== "null");
2157
- if (realTypes.length === 1 && types.includes("null")) {
2158
- const tsType = this.normal(realTypes[0], schema, false);
2159
- return appendOptional2(`${tsType} | null`, required);
2160
- }
2161
- const typeResults = types.map((t) => this.normal(t, schema, false));
2162
- return appendOptional2(typeResults.join(" | "), required);
2163
- }
2164
- return this.normal(types[0], schema, required);
2165
- }
579
+ import { camelcase } from "stringcase";
580
+ import { isEmpty, pascalcase as pascalcase3 } from "@sdk-it/core";
581
+ import {
582
+ isErrorStatusCode,
583
+ isStreamingContentType,
584
+ isSuccessStatusCode,
585
+ isTextContentType,
586
+ parseJsonContentType,
587
+ sanitizeTag as sanitizeTag3
588
+ } from "@sdk-it/spec";
589
+
590
+ // packages/typescript/src/lib/status-map.ts
591
+ var status_map_default = {
592
+ "200": "Ok",
593
+ "201": "Created",
594
+ "202": "Accepted",
595
+ "204": "NoContent",
596
+ "400": "BadRequest",
597
+ "401": "Unauthorized",
598
+ "402": "PaymentRequired",
599
+ "403": "Forbidden",
600
+ "404": "NotFound",
601
+ "405": "MethodNotAllowed",
602
+ "406": "NotAcceptable",
603
+ "409": "Conflict",
604
+ "412": "PreconditionFailed",
605
+ "413": "PayloadTooLarge",
606
+ "410": "Gone",
607
+ "422": "UnprocessableEntity",
608
+ "429": "TooManyRequests",
609
+ "500": "InternalServerError",
610
+ "501": "NotImplemented",
611
+ "502": "BadGateway",
612
+ "503": "ServiceUnavailable",
613
+ "504": "GatewayTimeout"
2166
614
  };
2167
- function appendOptional2(type, isRequired) {
2168
- return isRequired ? type : `${type} | undefined`;
2169
- }
2170
615
 
2171
616
  // packages/typescript/src/lib/utils.ts
2172
- import { followRef as followRef6, isRef as isRef8, removeDuplicates } from "@sdk-it/core";
2173
- function securityToOptions2(spec, security2, securitySchemes, staticIn) {
617
+ import { followRef as followRef3, isRef as isRef3, removeDuplicates } from "@sdk-it/core";
618
+ function securityToOptions(spec, security2, securitySchemes, staticIn) {
2174
619
  securitySchemes ??= {};
2175
620
  const options = {};
2176
621
  for (const it of security2) {
@@ -2178,7 +623,7 @@ function securityToOptions2(spec, security2, securitySchemes, staticIn) {
2178
623
  if (!name) {
2179
624
  continue;
2180
625
  }
2181
- const schema = isRef8(securitySchemes[name]) ? followRef6(spec, securitySchemes[name].$ref) : securitySchemes[name];
626
+ const schema = isRef3(securitySchemes[name]) ? followRef3(spec, securitySchemes[name].$ref) : securitySchemes[name];
2182
627
  if (schema.type === "http") {
2183
628
  options["authorization"] = {
2184
629
  in: staticIn ?? "header",
@@ -2213,96 +658,34 @@ function mergeImports(...imports) {
2213
658
  namedImports: []
2214
659
  };
2215
660
  for (const named of it.namedImports) {
2216
- if (!merged[it.moduleSpecifier].namedImports.some(
2217
- (x) => x.name === named.name
2218
- )) {
2219
- merged[it.moduleSpecifier].namedImports.push(named);
2220
- }
2221
- }
2222
- }
2223
- return Object.values(merged);
2224
- }
2225
- function importsToString(...imports) {
2226
- return imports.map((it) => {
2227
- if (it.defaultImport) {
2228
- return `import ${it.defaultImport} from '${it.moduleSpecifier}'`;
2229
- }
2230
- if (it.namespaceImport) {
2231
- return `import * as ${it.namespaceImport} from '${it.moduleSpecifier}'`;
2232
- }
2233
- if (it.namedImports) {
2234
- return `import {${removeDuplicates(it.namedImports, (it2) => it2.name).map((n) => `${n.isTypeOnly ? "type" : ""} ${n.name}`).join(", ")}} from '${it.moduleSpecifier}'`;
2235
- }
2236
- throw new Error(`Invalid import ${JSON.stringify(it)}`);
2237
- });
2238
- }
2239
- function exclude(list, exclude2) {
2240
- return list.filter((it) => !exclude2.includes(it));
2241
- }
2242
- function useImports(content, ...imports) {
2243
- const output = [];
2244
- for (const it of mergeImports(...imports)) {
2245
- const singleImport = it.defaultImport ?? it.namespaceImport;
2246
- if (singleImport && content.includes(singleImport)) {
2247
- output.push(importsToString(it).join("\n"));
2248
- } else if (it.namedImports.length) {
2249
- for (const namedImport of it.namedImports) {
2250
- if (content.includes(namedImport.name)) {
2251
- output.push(importsToString(it).join("\n"));
2252
- }
2253
- }
2254
- }
2255
- }
2256
- return output;
2257
- }
2258
-
2259
- // packages/typescript/src/lib/sdk.ts
2260
- function generateInputs(operationsSet, commonZod, makeImport) {
2261
- const commonImports = commonZod.keys().toArray();
2262
- const inputs = {};
2263
- for (const [name, operations] of Object.entries(operationsSet)) {
2264
- const output = [];
2265
- const imports = /* @__PURE__ */ new Set(['import { z } from "zod";']);
2266
- for (const operation of operations) {
2267
- const schemaName = camelcase3(`${operation.name} schema`);
2268
- const schema = `export const ${schemaName} = ${Object.keys(operation.schemas).length === 1 ? Object.values(operation.schemas)[0] : toLitObject2(operation.schemas)};`;
2269
- const inputContent = schema;
2270
- for (const schema2 of commonImports) {
2271
- if (inputContent.includes(schema2)) {
2272
- imports.add(
2273
- `import { ${schema2} } from './schemas/${makeImport(spinalcase(schema2))}';`
2274
- );
2275
- }
661
+ if (!merged[it.moduleSpecifier].namedImports.some(
662
+ (x) => x.name === named.name
663
+ )) {
664
+ merged[it.moduleSpecifier].namedImports.push(named);
2276
665
  }
2277
- output.push(inputContent);
2278
666
  }
2279
- inputs[`inputs/${spinalcase(name)}.ts`] = [...imports, ...output].join("\n") + "\n";
2280
667
  }
2281
- const schemas = commonZod.entries().reduce((acc, [name, schema]) => {
2282
- const output = [`import { z } from 'zod';`];
2283
- const content = `export const ${name} = ${schema};`;
2284
- for (const schema2 of commonImports) {
2285
- const preciseMatch = new RegExp(`\\b${schema2}\\b`);
2286
- if (preciseMatch.test(content) && schema2 !== name) {
2287
- output.push(
2288
- `import { ${schema2} } from './${makeImport(spinalcase(schema2))}';`
2289
- );
2290
- }
668
+ return Object.values(merged);
669
+ }
670
+ function importsToString(...imports) {
671
+ return imports.map((it) => {
672
+ if (it.defaultImport) {
673
+ return `import ${it.defaultImport} from '${it.moduleSpecifier}'`;
2291
674
  }
2292
- output.push(content);
2293
- return [
2294
- [`inputs/schemas/${spinalcase(name)}.ts`, output.join("\n")],
2295
- ...acc
2296
- ];
2297
- }, []);
2298
- return {
2299
- ...Object.fromEntries(schemas),
2300
- ...inputs
2301
- };
675
+ if (it.namespaceImport) {
676
+ return `import * as ${it.namespaceImport} from '${it.moduleSpecifier}'`;
677
+ }
678
+ if (it.namedImports) {
679
+ return `import {${removeDuplicates(it.namedImports, (it2) => it2.name).map((n) => `${n.isTypeOnly ? "type" : ""} ${n.name}`).join(", ")}} from '${it.moduleSpecifier}'`;
680
+ }
681
+ throw new Error(`Invalid import ${JSON.stringify(it)}`);
682
+ });
2302
683
  }
684
+
685
+ // packages/typescript/src/lib/sdk.ts
2303
686
  function toEndpoint(groupName, spec, specOperation, operation, utils) {
2304
- const schemaName = camelcase3(`${operation.name} schema`);
2305
- const schemaRef = `${camelcase3(groupName)}.${schemaName}`;
687
+ const schemaName = camelcase(`${operation.name} schema`);
688
+ const schemaRef = `${camelcase(groupName)}.${schemaName}`;
2306
689
  const inputHeaders = [];
2307
690
  const inputQuery = [];
2308
691
  const inputBody = [];
@@ -2330,32 +713,13 @@ function toEndpoint(groupName, spec, specOperation, operation, utils) {
2330
713
  }
2331
714
  specOperation.responses ??= {};
2332
715
  const outputs = [];
2333
- const statusesCount = Object.keys(specOperation.responses).filter((status) => {
2334
- const statusCode = +status;
2335
- return statusCode >= 200 && statusCode < 300;
2336
- }).length > 1;
2337
- const responseWithAtLeast200 = statusesCount ? specOperation.responses : Object.assign(
2338
- {
2339
- "200": {
2340
- description: "OK",
2341
- content: {
2342
- "application/json": {
2343
- schema: { type: "object" }
2344
- }
2345
- }
2346
- }
2347
- },
2348
- specOperation.responses
2349
- );
2350
- for (const status in responseWithAtLeast200) {
716
+ for (const status in specOperation.responses) {
2351
717
  const handled = handleResponse(
2352
718
  spec,
2353
719
  operation.name,
2354
720
  status,
2355
- responseWithAtLeast200[status],
2356
- utils,
2357
- true
2358
- // statusesCount,
721
+ specOperation.responses[status],
722
+ utils
2359
723
  );
2360
724
  responses.push(handled);
2361
725
  outputs.push(...handled.outputs);
@@ -2366,7 +730,7 @@ function toEndpoint(groupName, spec, specOperation, operation, utils) {
2366
730
  if (addTypeParser && type !== "json") {
2367
731
  typePrefix = `${type} `;
2368
732
  }
2369
- const endpoint = `${typePrefix}${operation.trigger.method.toUpperCase()} ${operation.trigger.path}`;
733
+ const endpoint = `${typePrefix}${operation.method.toUpperCase()} ${operation.path}`;
2370
734
  schemas.push(
2371
735
  `"${endpoint}": {
2372
736
  schema: ${schemaRef}${addTypeParser ? `.${type}` : ""},
@@ -2398,6 +762,7 @@ function normalOperation(style) {
2398
762
  function paginationOperation(operation, style) {
2399
763
  const pagination = operation["x-pagination"];
2400
764
  const data = `${style?.errorAsValue ? `result[0]${style.outputType === "status" ? "" : ""}` : `${style?.outputType === "default" ? "result.data" : "result.data"}`}`;
765
+ const returnValue = `${style?.errorAsValue ? `[${style?.outputType === "status" ? "new http.Ok(pagination)" : "pagination"}, null]` : `${style?.outputType === "status" ? "new http.Ok(pagination);" : "pagination"}`}`;
2401
766
  if (pagination.type === "offset") {
2402
767
  const sameInputNames = pagination.limitParamName === "limit" && pagination.offsetParamName === "offset";
2403
768
  const initialParams = sameInputNames ? "input" : `{...input, limit: input.${pagination.limitParamName}, offset: input.${pagination.offsetParamName}}`;
@@ -2416,7 +781,7 @@ function paginationOperation(operation, style) {
2416
781
  };
2417
782
  });
2418
783
  await pagination.getNextPage();
2419
- return ${style?.outputType === "status" ? "new http.Ok(pagination);" : "pagination"}
784
+ return ${returnValue}
2420
785
  `;
2421
786
  return style?.errorAsValue ? `{try {${logic}} catch (error) {return [null as never, error] as const;}}}` : `{${logic}}}`;
2422
787
  }
@@ -2440,7 +805,7 @@ function paginationOperation(operation, style) {
2440
805
  };
2441
806
  });
2442
807
  await pagination.getNextPage();
2443
- return ${style?.outputType === "status" ? "new http.Ok(pagination);" : "pagination"}
808
+ return ${returnValue}
2444
809
  `;
2445
810
  return style?.errorAsValue ? `{try {${logic}} catch (error) {return [null as never, error] as const;}}}` : `{${logic}}}`;
2446
811
  }
@@ -2464,36 +829,13 @@ function paginationOperation(operation, style) {
2464
829
  };
2465
830
  });
2466
831
  await pagination.getNextPage();
2467
- return ${style?.outputType === "status" ? "new http.Ok(pagination);" : "pagination"}
832
+ return ${returnValue}
2468
833
  `;
2469
834
  return style?.errorAsValue ? `{try {${logic}} catch (error) {return [null as never, error] as const;}}}` : `{${logic}}}`;
2470
835
  }
2471
836
  return normalOperation(style);
2472
837
  }
2473
- var statusCodeToResponseMap = {
2474
- "200": "Ok",
2475
- "201": "Created",
2476
- "202": "Accepted",
2477
- "204": "NoContent",
2478
- "400": "BadRequest",
2479
- "401": "Unauthorized",
2480
- "402": "PaymentRequired",
2481
- "403": "Forbidden",
2482
- "404": "NotFound",
2483
- "405": "MethodNotAllowed",
2484
- "406": "NotAcceptable",
2485
- "409": "Conflict",
2486
- "413": "PayloadTooLarge",
2487
- "410": "Gone",
2488
- "422": "UnprocessableEntity",
2489
- "429": "TooManyRequests",
2490
- "500": "InternalServerError",
2491
- "501": "NotImplemented",
2492
- "502": "BadGateway",
2493
- "503": "ServiceUnavailable",
2494
- "504": "GatewayTimeout"
2495
- };
2496
- function handleResponse(spec, operationName, status, response, utils, numbered) {
838
+ function handleResponse(spec, operationName, status, response, utils) {
2497
839
  const schemas = {};
2498
840
  const imports = {};
2499
841
  const endpointImports = {
@@ -2507,79 +849,84 @@ function handleResponse(spec, operationName, status, response, utils, numbered)
2507
849
  };
2508
850
  const responses = [];
2509
851
  const outputs = [];
2510
- const typeScriptDeserialzer = new TypeScriptEmitter(
2511
- spec,
2512
- (schemaName, zod) => {
2513
- schemas[schemaName] = zod;
2514
- imports[schemaName] = {
2515
- defaultImport: void 0,
2516
- isTypeOnly: true,
2517
- moduleSpecifier: `../models/${utils.makeImport(schemaName)}`,
2518
- namedImports: [{ isTypeOnly: true, name: schemaName }],
2519
- namespaceImport: void 0
852
+ const typeScriptDeserialzer = new TypeScriptEmitter(spec);
853
+ const statusCode = +status;
854
+ const statusName = `http.${status_map_default[status] || "APIResponse"}`;
855
+ const interfaceName = pascalcase3(sanitizeTag3(response["x-response-name"]));
856
+ let parser = "buffered";
857
+ if (isEmpty(response.content)) {
858
+ responses.push({
859
+ name: interfaceName,
860
+ schema: "void",
861
+ description: response.description
862
+ });
863
+ } else {
864
+ const contentTypeResult = fromContentType(
865
+ spec,
866
+ typeScriptDeserialzer,
867
+ response
868
+ );
869
+ if (!contentTypeResult) {
870
+ throw new Error(
871
+ `No recognizable content type for response ${status} in operation ${operationName}`
872
+ );
873
+ }
874
+ parser = contentTypeResult.parser;
875
+ const responseSchema = contentTypeResult.responseSchema;
876
+ responses.push({
877
+ name: interfaceName,
878
+ schema: responseSchema,
879
+ description: response.description
880
+ });
881
+ if (isErrorStatusCode(statusCode)) {
882
+ endpointImports[status_map_default[status] ?? "APIError"] = {
883
+ moduleSpecifier: utils.makeImport("../http/response"),
884
+ namedImports: [{ name: status_map_default[status] ?? "APIError" }]
2520
885
  };
886
+ } else if (isSuccessStatusCode(statusCode)) {
2521
887
  }
2522
- );
2523
- const statusCode = +status;
2524
- const parser = (response.headers ?? {})["Transfer-Encoding"] ? "chunked" : "buffered";
2525
- const statusName = `http.${statusCodeToResponseMap[status] || "APIResponse"}`;
2526
- const interfaceName = pascalcase(
2527
- operationName + ` output${numbered ? status : ""}`
2528
- );
888
+ }
2529
889
  if (statusCode === 204) {
2530
890
  outputs.push(statusName);
2531
891
  } else {
2532
892
  if (status.endsWith("XX")) {
2533
- outputs.push(`http.APIError<${interfaceName}>`);
893
+ outputs.push(`http.APIError<outputs.${interfaceName}>`);
2534
894
  } else {
2535
895
  outputs.push(
2536
- parser !== "buffered" ? `{type: ${statusName}<${interfaceName}>, parser: ${parser}}` : `${statusName}<${interfaceName}>`
896
+ parser !== "buffered" ? `{type: ${statusName}<outputs.${interfaceName}>, parser: ${parser}}` : `${statusName}<outputs.${interfaceName}>`
2537
897
  );
2538
898
  }
2539
899
  }
2540
- const responseContent = get(response, ["content"]);
2541
- const isJson = responseContent && responseContent["application/json"];
2542
- let responseSchema = parser === "chunked" ? "ReadableStream" : "void";
2543
- if (isJson) {
2544
- const schema = responseContent["application/json"].schema;
2545
- const isObject = !isRef9(schema) && schema.type === "object";
2546
- if (isObject && schema.properties) {
2547
- schema.properties["[http.KIND]"] = {
2548
- "x-internal": true,
2549
- const: `typeof ${statusName}.kind`,
2550
- type: "string"
900
+ return { schemas, imports, endpointImports, responses, outputs };
901
+ }
902
+ function fromContentType(spec, typeScriptDeserialzer, response) {
903
+ if ((response.headers ?? {})["Transfer-Encoding"]) {
904
+ return streamedOutput();
905
+ }
906
+ for (const type in response.content) {
907
+ if (isStreamingContentType(type)) {
908
+ return streamedOutput();
909
+ }
910
+ if (parseJsonContentType(type)) {
911
+ return {
912
+ parser: "buffered",
913
+ responseSchema: response.content[type].schema ? typeScriptDeserialzer.handle(response.content[type].schema, true) : "void"
914
+ };
915
+ }
916
+ if (isTextContentType(type)) {
917
+ return {
918
+ parser: "buffered",
919
+ responseSchema: response.content[type].schema ? typeScriptDeserialzer.handle(response.content[type].schema, true) : "void"
2551
920
  };
2552
- schema.required ??= [];
2553
- schema.required.push("[http.KIND]");
2554
921
  }
2555
- responseSchema = typeScriptDeserialzer.handle(schema, true);
2556
- }
2557
- responses.push({
2558
- name: interfaceName,
2559
- schema: responseSchema,
2560
- description: response.description
2561
- });
2562
- const statusGroup = +status.slice(0, 1);
2563
- if (statusCode >= 400 || statusGroup >= 4) {
2564
- endpointImports[statusCodeToResponseMap[status] ?? "APIError"] = {
2565
- moduleSpecifier: utils.makeImport("../http/response"),
2566
- namedImports: [{ name: statusCodeToResponseMap[status] ?? "APIError" }]
2567
- };
2568
- endpointImports[interfaceName] = {
2569
- isTypeOnly: true,
2570
- moduleSpecifier: `../outputs/${utils.makeImport(spinalcase(operationName))}`,
2571
- namedImports: [{ isTypeOnly: true, name: interfaceName }]
2572
- };
2573
- } else if (statusCode >= 200 && statusCode < 300 || statusCode >= 2 || statusGroup <= 3) {
2574
- endpointImports[interfaceName] = {
2575
- defaultImport: void 0,
2576
- isTypeOnly: true,
2577
- moduleSpecifier: `../outputs/${utils.makeImport(spinalcase(operationName))}`,
2578
- namedImports: [{ isTypeOnly: true, name: interfaceName }],
2579
- namespaceImport: void 0
2580
- };
2581
922
  }
2582
- return { schemas, imports, endpointImports, responses, outputs };
923
+ return streamedOutput();
924
+ }
925
+ function streamedOutput() {
926
+ return {
927
+ parser: "chunked",
928
+ responseSchema: "ReadableStream"
929
+ };
2583
930
  }
2584
931
 
2585
932
  // packages/typescript/src/lib/styles/github/endpoints.txt
@@ -2600,9 +947,8 @@ function generateCode(config) {
2600
947
  });
2601
948
  });
2602
949
  const groups = {};
2603
- const outputs = {};
2604
950
  const endpoints = {};
2605
- forEachOperation2(config, (entry, operation) => {
951
+ forEachOperation(config.spec, (entry, operation) => {
2606
952
  console.log(`Processing ${entry.method} ${entry.path}`);
2607
953
  groups[entry.groupName] ??= [];
2608
954
  endpoints[entry.groupName] ??= [];
@@ -2621,7 +967,7 @@ function generateCode(config) {
2621
967
  additionalProperties[param.name] = param;
2622
968
  }
2623
969
  const securitySchemes = config.spec.components?.securitySchemes ?? {};
2624
- const securityOptions = securityToOptions2(
970
+ const securityOptions = securityToOptions(
2625
971
  config.spec,
2626
972
  operation.security ?? [],
2627
973
  securitySchemes
@@ -2649,67 +995,43 @@ function generateCode(config) {
2649
995
  "application/xml": "xml",
2650
996
  "text/plain": "text"
2651
997
  };
2652
- let outgoingContentType;
2653
- if (!isEmpty4(operation.requestBody)) {
2654
- for (const type in operation.requestBody.content) {
2655
- const ctSchema = isRef10(operation.requestBody.content[type].schema) ? followRef7(
2656
- config.spec,
2657
- operation.requestBody.content[type].schema.$ref
2658
- ) : operation.requestBody.content[type].schema;
2659
- if (!ctSchema) {
2660
- console.warn(
2661
- `Schema not found for ${type} in ${entry.method} ${entry.path}`
2662
- );
2663
- continue;
2664
- }
2665
- let objectSchema = ctSchema;
998
+ let outgoingContentType = "empty";
999
+ for (const type in operation.requestBody.content) {
1000
+ let objectSchema = resolveRef(
1001
+ config.spec,
1002
+ operation.requestBody.content[type].schema
1003
+ );
1004
+ if (type === "application/empty") {
1005
+ objectSchema = {
1006
+ type: "object",
1007
+ // properties: objectSchema['x-properties'],
1008
+ additionalProperties: isEmpty2(objectSchema["x-properties"])
1009
+ };
1010
+ } else {
2666
1011
  if (objectSchema.type !== "object") {
2667
1012
  objectSchema = {
2668
1013
  type: "object",
2669
1014
  required: [operation.requestBody.required ? "$body" : ""],
2670
1015
  properties: {
2671
- $body: ctSchema
1016
+ $body: objectSchema
1017
+ // ...objectSchema['x-properties'],
2672
1018
  }
2673
1019
  };
2674
1020
  }
2675
- const schema = merge({}, objectSchema, {
2676
- required: Object.values(additionalProperties).filter((p) => p.required).map((p) => p.name),
2677
- properties: Object.entries(additionalProperties).reduce(
2678
- (acc, [, p]) => ({
2679
- ...acc,
2680
- [p.name]: p.schema
2681
- }),
2682
- {}
2683
- )
2684
- });
2685
- Object.assign(inputs, bodyInputs(config, objectSchema));
2686
- schemas[shortContenTypeMap[type]] = zodDeserialzer.handle(schema, true);
2687
- }
2688
- if (operation.requestBody.content["application/json"]) {
2689
- outgoingContentType = "json";
2690
- } else if (operation.requestBody.content["application/x-www-form-urlencoded"]) {
2691
- outgoingContentType = "urlencoded";
2692
- } else if (operation.requestBody.content["multipart/form-data"]) {
2693
- outgoingContentType = "formdata";
2694
- } else {
2695
- outgoingContentType = "json";
2696
1021
  }
2697
- } else {
2698
- const properties = Object.entries(additionalProperties).reduce(
2699
- (acc, [, p]) => ({
2700
- ...acc,
2701
- [p.name]: p.schema
2702
- }),
2703
- {}
2704
- );
2705
- schemas[shortContenTypeMap["application/json"]] = zodDeserialzer.handle(
2706
- {
2707
- type: "object",
2708
- required: Object.values(additionalProperties).filter((p) => p.required).map((p) => p.name),
2709
- properties
2710
- },
2711
- true
2712
- );
1022
+ const schema = merge({}, objectSchema, {
1023
+ required: Object.values(additionalProperties).filter((p) => p.required).map((p) => p.name),
1024
+ properties: Object.entries(additionalProperties).reduce((acc, [, p]) => ({ ...acc, [p.name]: p.schema }), {})
1025
+ });
1026
+ Object.assign(inputs, bodyInputs(config.spec, objectSchema));
1027
+ schemas[shortContenTypeMap[type]] = zodDeserialzer.handle(schema, true);
1028
+ }
1029
+ if (operation.requestBody.content["application/json"]) {
1030
+ outgoingContentType = "json";
1031
+ } else if (operation.requestBody.content["application/x-www-form-urlencoded"]) {
1032
+ outgoingContentType = "urlencoded";
1033
+ } else if (operation.requestBody.content["multipart/form-data"]) {
1034
+ outgoingContentType = "formdata";
2713
1035
  }
2714
1036
  const endpoint = toEndpoint(
2715
1037
  entry.groupName,
@@ -2718,78 +1040,30 @@ function generateCode(config) {
2718
1040
  {
2719
1041
  outgoingContentType,
2720
1042
  name: operation.operationId,
2721
- type: "http",
2722
- trigger: entry,
1043
+ method: entry.method,
1044
+ path: entry.path,
2723
1045
  schemas,
2724
1046
  inputs
2725
1047
  },
2726
1048
  { makeImport: config.makeImport, style: config.style }
2727
1049
  );
2728
- const output = [
2729
- `import z from 'zod';`,
2730
- `import type * as http from '${config.makeImport("../http/index")}';`
2731
- ];
2732
- const responses = endpoint.responses.flatMap((it) => it.responses);
2733
- const responsesImports = endpoint.responses.flatMap(
2734
- (it) => Object.values(it.imports)
2735
- );
2736
- if (responses.length) {
2737
- output.push(
2738
- ...responses.map(
2739
- (it) => `${it.description ? `
2740
- /**
2741
- * ${it.description}
2742
- */
2743
- ` : ""} export type ${it.name} = ${it.schema};`
2744
- )
2745
- );
2746
- } else {
2747
- output.push(
2748
- `export type ${pascalcase2(operation.operationId + " output")} = void;`
2749
- );
2750
- }
2751
- output.unshift(...useImports(output.join(""), ...responsesImports));
2752
- outputs[`${spinalcase2(operation.operationId)}.ts`] = output.join("\n");
2753
1050
  endpoints[entry.groupName].push(endpoint);
2754
1051
  groups[entry.groupName].push({
2755
1052
  name: operation.operationId,
2756
- type: "http",
2757
1053
  inputs,
2758
1054
  outgoingContentType,
2759
1055
  schemas,
2760
- trigger: entry
1056
+ method: entry.method,
1057
+ path: entry.path
2761
1058
  });
2762
1059
  });
2763
- const commonSchemas = Object.values(endpoints).reduce(
2764
- (acc, endpoint) => ({
2765
- ...acc,
2766
- ...endpoint.reduce(
2767
- (acc2, { responses }) => ({
2768
- ...acc2,
2769
- ...responses.reduce(
2770
- (acc3, it) => ({ ...acc3, ...it.schemas }),
2771
- {}
2772
- )
2773
- }),
2774
- {}
2775
- )
2776
- }),
2777
- {}
2778
- );
2779
1060
  const allSchemas = Object.keys(endpoints).map((it) => ({
2780
- import: `import ${camelcase4(it)} from './${config.makeImport(spinalcase2(it))}';`,
2781
- use: ` ...${camelcase4(it)}`
1061
+ import: `import ${camelcase2(it)} from './${config.makeImport(spinalcase(it))}';`,
1062
+ use: ` ...${camelcase2(it)}`
2782
1063
  }));
2783
- const imports = [
2784
- 'import z from "zod";',
2785
- `import type { ParseError } from '${config.makeImport("../http/parser")}';`,
2786
- `import type { ServerError } from '${config.makeImport("../http/response")}';`
2787
- ];
2788
1064
  return {
2789
1065
  groups,
2790
- commonSchemas,
2791
1066
  commonZod,
2792
- outputs,
2793
1067
  endpoints: {
2794
1068
  [join("api", "endpoints.ts")]: `
2795
1069
 
@@ -2823,14 +1097,15 @@ ${allSchemas.map((it) => it.use).join(",\n")}
2823
1097
  );
2824
1098
  return [
2825
1099
  [
2826
- join("api", `${spinalcase2(name)}.ts`),
1100
+ join("api", `${spinalcase(name)}.ts`),
2827
1101
  `${[
2828
1102
  ...imps,
2829
1103
  `import z from 'zod';`,
2830
1104
  `import * as http from '${config.makeImport("../http/response")}';`,
1105
+ `import * as outputs from '${config.makeImport("../outputs/index")}';`,
2831
1106
  `import { toRequest, json, urlencoded, empty, formdata, createUrl, type HeadersInit } from '${config.makeImport("../http/request")}';`,
2832
1107
  `import { chunked, buffered } from "${config.makeImport("../http/parse-response")}";`,
2833
- `import * as ${camelcase4(name)} from '../inputs/${config.makeImport(spinalcase2(name))}';`,
1108
+ `import * as ${camelcase2(name)} from '../inputs/${config.makeImport(spinalcase(name))}';`,
2834
1109
  `import { createBaseUrlInterceptor, createHeadersInterceptor, type Interceptor } from '${config.makeImport("../http/interceptors")}';`,
2835
1110
  `import { Dispatcher, fetchType, type InstanceType } from '${config.makeImport("../http/dispatcher")}';`,
2836
1111
  `import { Pagination, OffsetPagination, CursorPagination } from "${config.makeImport("../pagination/index")}";`
@@ -2848,8 +1123,8 @@ ${endpoint.flatMap((it) => it.schemas).join(",\n")}
2848
1123
  };
2849
1124
  }
2850
1125
  function toProps(spec, schemaOrRef, aggregator = []) {
2851
- if (isRef10(schemaOrRef)) {
2852
- const schema = followRef7(spec, schemaOrRef.$ref);
1126
+ if (isRef4(schemaOrRef)) {
1127
+ const schema = followRef4(spec, schemaOrRef.$ref);
2853
1128
  return toProps(spec, schema, aggregator);
2854
1129
  } else if (schemaOrRef.type === "object") {
2855
1130
  for (const [name] of Object.entries(schemaOrRef.properties ?? {})) {
@@ -2878,9 +1153,9 @@ function toProps(spec, schemaOrRef, aggregator = []) {
2878
1153
  console.warn("Unknown schema in body", schemaOrRef);
2879
1154
  return void 0;
2880
1155
  }
2881
- function bodyInputs(config, ctSchema) {
1156
+ function bodyInputs(spec, ctSchema) {
2882
1157
  const props = [];
2883
- toProps(config.spec, ctSchema, props);
1158
+ toProps(spec, ctSchema, props);
2884
1159
  return props.reduce(
2885
1160
  (acc, prop) => ({
2886
1161
  ...acc,
@@ -3140,6 +1415,28 @@ export class Gone<T = { message: string }> extends APIError<T, 410> {
3140
1415
  return typeof value === 'object' && value !== null && KIND in value && value[KIND] === this.kind;
3141
1416
  }
3142
1417
  }
1418
+ export class PreconditionFailed<T = { message: string }> extends APIError<T, 412> {
1419
+ static override readonly kind = Symbol.for('PreconditionFailed');
1420
+ static override status = 412 as const;
1421
+ constructor(data: T) {
1422
+ super(PreconditionFailed.status, data);
1423
+ }
1424
+ static override create<T>(status: number, data: T) {
1425
+ Object.defineProperty(data, KIND, { value: this.kind });
1426
+ return new this(data);
1427
+ }
1428
+
1429
+ static is<T extends { [KIND]: (typeof PreconditionFailed)['kind'] }>(
1430
+ value: unknown,
1431
+ ): value is T {
1432
+ return (
1433
+ typeof value === 'object' &&
1434
+ value !== null &&
1435
+ KIND in value &&
1436
+ value[KIND] === this.kind
1437
+ );
1438
+ }
1439
+ }
3143
1440
  export class UnprocessableEntity<
3144
1441
  T = { message: string; errors?: Record<string, string[]> },
3145
1442
  > extends APIError<T, 422> {
@@ -3291,7 +1588,7 @@ export class GatewayTimeout<T = { message: string }> extends APIError<T, 504> {
3291
1588
  }
3292
1589
 
3293
1590
  export type ClientError =
3294
- | BadRequest<{ message: string }>
1591
+ | BadRequest<unknown>
3295
1592
  | Unauthorized<unknown>
3296
1593
  | PaymentRequired<unknown>
3297
1594
  | Forbidden<unknown>
@@ -3300,6 +1597,9 @@ export type ClientError =
3300
1597
  | NotAcceptable<unknown>
3301
1598
  | Conflict<unknown>
3302
1599
  | Gone<unknown>
1600
+ | PreconditionFailed<unknown>
1601
+ | PayloadTooLarge<unknown>
1602
+ | UnsupportedMediaType<unknown>
3303
1603
  | UnprocessableEntity<unknown>
3304
1604
  | TooManyRequests<unknown>;
3305
1605
 
@@ -3316,8 +1616,7 @@ export type SuccessfulResponse =
3316
1616
  | Ok<unknown>
3317
1617
  | Created<unknown>
3318
1618
  | Accepted<unknown>
3319
- | NoContent;
3320
- `;
1619
+ | NoContent;`;
3321
1620
 
3322
1621
  // packages/typescript/src/lib/paginations/cursor-pagination.txt
3323
1622
  var cursor_pagination_default = "type CursorPaginationParams = {\n cursor?: string;\n};\n\ninterface CursorMetadata extends Metadata {\n nextCursor?: string;\n}\n\ninterface Metadata {\n hasMore?: boolean;\n}\n\ntype PaginationResult<T, M extends CursorMetadata> = {\n data: T[];\n meta: M;\n};\n\ntype FetchFn<T, M extends CursorMetadata> = (\n input: CursorPaginationParams,\n) => Promise<PaginationResult<T, M>>;\n\n/**\n * @experimental\n */\nexport class CursorPagination<T, M extends CursorMetadata> {\n #meta: PaginationResult<T, M>['meta'] | null = null;\n #params: CursorPaginationParams;\n #currentPage: Page<T> | null = null;\n readonly #fetchFn: FetchFn<T, M>;\n\n constructor(\n initialParams: PartialNullable<CursorPaginationParams>,\n fetchFn: FetchFn<T, M>,\n ) {\n this.#fetchFn = fetchFn;\n this.#params = {\n cursor: initialParams.cursor ?? undefined,\n };\n }\n\n async getNextPage() {\n const result = await this.#fetchFn(this.#params);\n this.#currentPage = new Page(result.data);\n this.#meta = result.meta;\n this.#params = {\n ...this.#params,\n cursor: result.meta.nextCursor,\n };\n return this;\n }\n\n getCurrentPage() {\n if (!this.#currentPage) {\n throw new Error(\n 'No page data available. Please call getNextPage() first.',\n );\n }\n return this.#currentPage;\n }\n\n get hasMore() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta.hasMore;\n }\n\n async *[Symbol.asyncIterator]() {\n for await (const page of this.iter()) {\n yield page.getCurrentPage();\n }\n }\n\n async *iter() {\n if (!this.#currentPage) {\n yield await this.getNextPage();\n }\n\n while (this.hasMore) {\n yield await this.getNextPage();\n }\n }\n\n get metadata() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta;\n }\n}\n\nclass Page<T> {\n data: T[];\n constructor(data: T[]) {\n this.data = data;\n }\n}\n\ntype PartialNullable<T> = {\n [K in keyof T]?: T[K] | null;\n};\n";
@@ -3329,11 +1628,15 @@ var offset_pagination_default = "type OffsetPaginationParams = {\n offset: numb
3329
1628
  var page_pagination_default = "type InferPage<T> = T extends Page<infer U> ? U : never;\ntype PaginationParams<P extends number | bigint, S extends number | bigint> = {\n page?: P;\n pageSize?: S;\n};\n\ninterface Metadata {\n hasMore?: boolean;\n}\n\ntype PaginationResult<T, M extends Metadata> = {\n data: T[];\n meta: M;\n};\n\ntype FetchFn<\n T,\n M extends Metadata,\n P extends number | bigint,\n S extends number | bigint,\n> = (input: Partial<PaginationParams<P, S>>) => Promise<PaginationResult<T, M>>;\n\n/**\n * @experimental\n */\nexport class Pagination<\n T,\n M extends Metadata,\n P extends number | bigint,\n S extends number | bigint,\n> {\n #meta: PaginationResult<T, M>['meta'] | null = null;\n #params: PaginationParams<P, S>;\n #currentPage: Page<T> | null = null;\n readonly #fetchFn: FetchFn<T, M, P, S>;\n\n constructor(\n initialParams: Partial<PaginationParams<P, S>>,\n fetchFn: FetchFn<T, M, P, S>,\n ) {\n this.#fetchFn = fetchFn;\n this.#params = { ...initialParams, page: initialParams.page };\n }\n\n async getNextPage() {\n const result = await this.#fetchFn(this.#params);\n this.#currentPage = new Page(result.data);\n this.#meta = result.meta;\n this.#params = {\n ...this.#params,\n page: ((this.#params.page as number) || 0 + 1) as never,\n };\n return this;\n }\n\n getCurrentPage() {\n if (!this.#currentPage) {\n throw new Error(\n 'No page data available. Please call getNextPage() first.',\n );\n }\n return this.#currentPage;\n }\n\n get hasMore() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta.hasMore;\n }\n\n async *[Symbol.asyncIterator]() {\n for await (const page of this.iter()) {\n yield page.getCurrentPage();\n }\n }\n\n async *iter() {\n if (!this.#currentPage) {\n yield await this.getNextPage();\n }\n\n while (this.hasMore) {\n yield await this.getNextPage();\n }\n }\n\n get metadata() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta;\n }\n}\n\nclass Page<T> {\n data: T[];\n constructor(data: T[]) {\n this.data = data;\n }\n}\n";
3330
1629
 
3331
1630
  // packages/typescript/src/lib/typescript-snippet.ts
3332
- import { camelcase as camelcase5, spinalcase as spinalcase3 } from "stringcase";
3333
- import { followRef as followRef9, isEmpty as isEmpty5, isRef as isRef12, pascalcase as pascalcase3 } from "@sdk-it/core";
1631
+ import { camelcase as camelcase3, spinalcase as spinalcase2 } from "stringcase";
1632
+ import { isEmpty as isEmpty3, pascalcase as pascalcase4, resolveRef as resolveRef2 } from "@sdk-it/core";
1633
+ import {
1634
+ patchParameters,
1635
+ securityToOptions as securityToOptions2
1636
+ } from "@sdk-it/spec";
3334
1637
 
3335
1638
  // packages/typescript/src/lib/emitters/snippet.ts
3336
- import { followRef as followRef8, isRef as isRef11 } from "@sdk-it/core";
1639
+ import { followRef as followRef5, isRef as isRef5 } from "@sdk-it/core";
3337
1640
  var SnippetEmitter = class {
3338
1641
  spec;
3339
1642
  generatedRefs = /* @__PURE__ */ new Set();
@@ -3342,12 +1645,12 @@ var SnippetEmitter = class {
3342
1645
  this.spec = spec;
3343
1646
  }
3344
1647
  object(schema) {
3345
- const schemaObj = isRef11(schema) ? followRef8(this.spec, schema.$ref) : schema;
1648
+ const schemaObj = isRef5(schema) ? followRef5(this.spec, schema.$ref) : schema;
3346
1649
  const result = {};
3347
1650
  const properties = schemaObj.properties || {};
3348
1651
  for (const [propName, propSchema] of Object.entries(properties)) {
3349
1652
  const isRequired = (schemaObj.required ?? []).includes(propName);
3350
- const resolvedProp = isRef11(propSchema) ? followRef8(this.spec, propSchema.$ref) : propSchema;
1653
+ const resolvedProp = isRef5(propSchema) ? followRef5(this.spec, propSchema.$ref) : propSchema;
3351
1654
  if (isRequired || resolvedProp.example !== void 0 || resolvedProp.default !== void 0 || Math.random() > 0.5) {
3352
1655
  result[propName] = this.handle(propSchema);
3353
1656
  }
@@ -3360,7 +1663,7 @@ var SnippetEmitter = class {
3360
1663
  return result;
3361
1664
  }
3362
1665
  array(schema) {
3363
- const schemaObj = isRef11(schema) ? followRef8(this.spec, schema.$ref) : schema;
1666
+ const schemaObj = isRef5(schema) ? followRef5(this.spec, schema.$ref) : schema;
3364
1667
  const itemsSchema = schemaObj.items;
3365
1668
  if (!itemsSchema) {
3366
1669
  return [];
@@ -3400,7 +1703,7 @@ var SnippetEmitter = class {
3400
1703
  return "example.com";
3401
1704
  case "binary":
3402
1705
  case "byte":
3403
- return "[binary data]";
1706
+ return `new Blob(['example'], { type: 'text/plain' })`;
3404
1707
  default:
3405
1708
  if (schema.enum && schema.enum.length > 0) {
3406
1709
  return String(schema.enum[0]);
@@ -3448,7 +1751,7 @@ var SnippetEmitter = class {
3448
1751
  return this.cache.get($ref);
3449
1752
  }
3450
1753
  this.cache.set($ref, { _ref: refKey });
3451
- const resolved = followRef8(this.spec, $ref);
1754
+ const resolved = followRef5(this.spec, $ref);
3452
1755
  const result = this.handle(resolved);
3453
1756
  this.cache.set($ref, result);
3454
1757
  return result;
@@ -3477,10 +1780,10 @@ var SnippetEmitter = class {
3477
1780
  return Array.isArray(schema.enum) && schema.enum.length > 0 ? schema.enum[0] : void 0;
3478
1781
  }
3479
1782
  handle(schemaOrRef) {
3480
- if (isRef11(schemaOrRef)) {
1783
+ if (isRef5(schemaOrRef)) {
3481
1784
  return this.ref(schemaOrRef.$ref);
3482
1785
  }
3483
- const schema = isRef11(schemaOrRef) ? followRef8(this.spec, schemaOrRef.$ref) : schemaOrRef;
1786
+ const schema = isRef5(schemaOrRef) ? followRef5(this.spec, schemaOrRef.$ref) : schemaOrRef;
3484
1787
  if (schema.example !== void 0) {
3485
1788
  return schema.example;
3486
1789
  }
@@ -3540,53 +1843,39 @@ var TypeScriptGenerator = class {
3540
1843
  this.#spec = spec;
3541
1844
  this.#settings = settings;
3542
1845
  this.#snippetEmitter = new SnippetEmitter(spec);
3543
- this.#clientName = settings.name?.trim() ? pascalcase3(settings.name) : "Client";
3544
- this.#packageName = settings.name ? `@${spinalcase3(this.#clientName.toLowerCase())}/sdk` : "sdk";
1846
+ this.#clientName = settings.name?.trim() ? pascalcase4(settings.name) : "Client";
1847
+ this.#packageName = settings.name ? `@${spinalcase2(this.#clientName.toLowerCase())}/sdk` : "sdk";
3545
1848
  }
3546
1849
  succinct(entry, operation, values) {
3547
1850
  let payload = "{}";
3548
- if (!isEmpty5(operation.requestBody)) {
1851
+ if (!isEmpty3(operation.requestBody)) {
3549
1852
  const contentTypes = Object.keys(operation.requestBody.content || {});
3550
- if (contentTypes.length > 0) {
3551
- const firstContent = operation.requestBody.content[contentTypes[0]];
3552
- let schema = isRef12(firstContent.schema) ? followRef9(this.#spec, firstContent.schema.$ref) : firstContent.schema;
3553
- if (schema) {
3554
- if (schema.type !== "object") {
3555
- schema = {
3556
- type: "object",
3557
- required: [operation.requestBody.required ? "$body" : ""],
3558
- properties: {
3559
- $body: schema
3560
- }
3561
- };
3562
- }
3563
- const properties = {};
3564
- patchParameters(
3565
- this.#spec,
3566
- { type: "object", properties },
3567
- operation
3568
- );
3569
- const examplePayload = this.#snippetEmitter.handle({
3570
- ...schema,
3571
- properties: Object.assign({}, properties, schema.properties)
3572
- });
3573
- Object.assign(
3574
- examplePayload,
3575
- values.requestBody ?? {},
3576
- values.pathParameters ?? {},
3577
- values.queryParameters ?? {},
3578
- values.headers ?? {},
3579
- values.cookies ?? {}
3580
- );
3581
- payload = JSON.stringify(examplePayload, null, 2);
3582
- }
3583
- }
3584
- } else {
3585
- const properties = {};
3586
- patchParameters(this.#spec, { type: "object", properties }, operation);
1853
+ const schema = resolveRef2(
1854
+ this.#spec,
1855
+ operation.requestBody.content[contentTypes[0]].schema
1856
+ );
3587
1857
  const examplePayload = this.#snippetEmitter.handle({
3588
- properties
1858
+ ...schema,
1859
+ properties: Object.assign({}, schema.properties, schema.properties)
3589
1860
  });
1861
+ Object.assign(
1862
+ examplePayload,
1863
+ values.requestBody ?? {},
1864
+ values.pathParameters ?? {},
1865
+ values.queryParameters ?? {},
1866
+ values.headers ?? {},
1867
+ values.cookies ?? {}
1868
+ );
1869
+ payload = examplePayload;
1870
+ } else {
1871
+ const requestBody = { type: "object", properties: {} };
1872
+ patchParameters(
1873
+ this.#spec,
1874
+ requestBody,
1875
+ operation.parameters,
1876
+ operation.security ?? []
1877
+ );
1878
+ const examplePayload = this.#snippetEmitter.handle(requestBody);
3590
1879
  Object.assign(
3591
1880
  examplePayload,
3592
1881
  values.pathParameters ?? {},
@@ -3594,48 +1883,138 @@ var TypeScriptGenerator = class {
3594
1883
  values.headers ?? {},
3595
1884
  values.cookies ?? {}
3596
1885
  );
3597
- payload = JSON.stringify(examplePayload, null, 2);
1886
+ payload = examplePayload;
1887
+ }
1888
+ payload = JSON.stringify(
1889
+ payload,
1890
+ (key, value) => {
1891
+ if (value?.startsWith && value.startsWith("new")) {
1892
+ return `__REPLACE_${Math.random().toString(36).substring(2, 11)}__${value}__REPLACE_END__`;
1893
+ }
1894
+ return value;
1895
+ },
1896
+ 2
1897
+ ).replace(/"__REPLACE_[^"]*__([^"]*?)__REPLACE_END__"/g, "$1");
1898
+ let successResponse;
1899
+ for (const status in operation.responses) {
1900
+ if (status.startsWith("2")) {
1901
+ successResponse = operation.responses[status];
1902
+ break;
1903
+ }
1904
+ }
1905
+ if (successResponse) {
1906
+ if (successResponse.headers?.["Transfer-Encoding"]) {
1907
+ return this.#httpStreaming(entry, payload);
1908
+ }
1909
+ if (successResponse.content && successResponse.content["application/octet-stream"]) {
1910
+ return this.#streamDownload(entry, payload);
1911
+ }
1912
+ }
1913
+ if (!isEmpty3(operation["x-pagination"])) {
1914
+ return this.#pagination(operation, entry, payload);
3598
1915
  }
3599
- return `const result = await ${camelcase5(this.#clientName)}.request('${entry.method.toUpperCase()} ${entry.path}', ${payload});`;
1916
+ return this.#normal(entry, payload);
3600
1917
  }
3601
- snippet(entry, operation) {
3602
- const payload = this.succinct(entry, operation, {});
3603
- return [
3604
- "```typescript",
3605
- `${this.client()}
3606
- ${payload}
3607
-
3608
- console.log(result.data);
3609
- `,
3610
- "```"
3611
- ].join("\n");
1918
+ #pagination(opeartion, entry, payload) {
1919
+ const pagination = opeartion["x-pagination"];
1920
+ switch (pagination.type) {
1921
+ case "page":
1922
+ return {
1923
+ content: `const result = ${this.#ddd(entry, payload)}`,
1924
+ footer: `for await (const page of result) {
1925
+ console.log(page);
1926
+ }`
1927
+ };
1928
+ case "offset":
1929
+ return {
1930
+ content: `const result = ${this.#ddd(entry, payload)}`,
1931
+ footer: `for await (const page of result) {
1932
+ console.log(page);
1933
+ }`
1934
+ };
1935
+ case "cursor":
1936
+ return {
1937
+ content: `const result = ${this.#ddd(entry, payload)}`,
1938
+ footer: `for await (const page of result) {
1939
+ console.log(page);
1940
+ }`
1941
+ };
1942
+ }
1943
+ return this.#normal(entry, payload);
1944
+ }
1945
+ #normal(entry, payload) {
1946
+ return {
1947
+ content: `const result = ${this.#ddd(entry, payload)};`,
1948
+ footer: "console.log(result.data)"
1949
+ };
1950
+ }
1951
+ #streamDownload(entry, payload) {
1952
+ return {
1953
+ content: `const stream = ${this.#ddd(entry, payload)}`,
1954
+ footer: `await writeFile('./report.pdf', stream);`
1955
+ };
1956
+ }
1957
+ #httpStreaming(entry, payload) {
1958
+ return {
1959
+ content: `const stream = ${this.#ddd(entry, payload)}`,
1960
+ footer: `for await (const chunk of stream) {
1961
+ console.log(chunk);
1962
+ }`
1963
+ };
1964
+ }
1965
+ #ddd(entry, payload) {
1966
+ return `await ${camelcase3(this.#clientName)}.request('${entry.method.toUpperCase()} ${entry.path}', ${payload});`;
1967
+ }
1968
+ snippet(entry, operation, config = {}) {
1969
+ const payload = this.succinct(entry, operation, config);
1970
+ const content = [
1971
+ this.client(),
1972
+ "",
1973
+ payload.content,
1974
+ "",
1975
+ payload.footer
1976
+ ];
1977
+ if (config.frame !== false) {
1978
+ content.unshift("```typescript");
1979
+ content.push("```");
1980
+ }
1981
+ return content.join("\n");
1982
+ }
1983
+ #authentication() {
1984
+ return securityToOptions2(
1985
+ this.#spec,
1986
+ this.#spec.security ?? [],
1987
+ this.#spec.components?.securitySchemes ?? {}
1988
+ );
3612
1989
  }
3613
1990
  client() {
1991
+ const inputs = [
1992
+ `baseUrl: '${this.#spec.servers?.[0]?.url ?? "http://localhost:3000"}'`
1993
+ ];
1994
+ const authOptions = this.#authentication();
1995
+ if (!isEmpty3(authOptions)) {
1996
+ const [firstAuth] = authOptions;
1997
+ inputs.push(`${firstAuth.name}: ${firstAuth.example}`);
1998
+ }
3614
1999
  return `import { ${this.#clientName} } from '${this.#packageName}';
3615
2000
 
3616
- const ${camelcase5(this.#clientName)} = new ${this.#clientName}({
3617
- baseUrl: '${this.#spec.servers?.[0]?.url ?? "http://localhost:3000"}',
2001
+ const ${camelcase3(this.#clientName)} = new ${this.#clientName}({
2002
+ ${inputs.join(",\n ")}
3618
2003
  });`;
3619
2004
  }
3620
2005
  };
2006
+ function generateSnippet(spec, settings, entry, operation, config = {}) {
2007
+ const generator = new TypeScriptGenerator(spec, settings);
2008
+ return generator.snippet(entry, operation, config);
2009
+ }
3621
2010
 
3622
2011
  // packages/typescript/src/lib/generate.ts
3623
- var ALWAYS_AVAILABLE_FILES = [
3624
- /readme\.md$/i,
3625
- // match readme.md, case-insensitive
3626
- /^tsconfig.*\.json$/,
3627
- // match any tsconfig*.json
3628
- /package\.json$/,
3629
- // exact package.json
3630
- /metadata\.json$/
3631
- // exact metadata.json
3632
- ];
3633
2012
  function security(spec) {
3634
2013
  const security2 = spec.security || [];
3635
2014
  const components = spec.components || {};
3636
2015
  const securitySchemes = components.securitySchemes || {};
3637
2016
  const paths = Object.values(spec.paths ?? {});
3638
- const options = securityToOptions2(spec, security2, securitySchemes);
2017
+ const options = securityToOptions(spec, security2, securitySchemes);
3639
2018
  for (const it of paths) {
3640
2019
  for (const method of methods) {
3641
2020
  const operation = it[method];
@@ -3644,7 +2023,7 @@ function security(spec) {
3644
2023
  }
3645
2024
  Object.assign(
3646
2025
  options,
3647
- securityToOptions2(
2026
+ securityToOptions(
3648
2027
  spec,
3649
2028
  operation.security || [],
3650
2029
  securitySchemes,
@@ -3655,13 +2034,16 @@ function security(spec) {
3655
2034
  }
3656
2035
  return options;
3657
2036
  }
3658
- async function generate(spec, settings) {
3659
- spec = "x-sdk-augmented" in spec ? spec : augmentSpec({ spec });
2037
+ async function generate(openapi, settings) {
2038
+ const spec = augmentSpec(
2039
+ { spec: openapi, responses: { flattenErrorResponses: true } },
2040
+ false
2041
+ );
3660
2042
  const generator = new TypeScriptGenerator(spec, settings);
3661
2043
  const style = Object.assign(
3662
2044
  {},
3663
2045
  {
3664
- errorAsValue: true,
2046
+ errorAsValue: false,
3665
2047
  name: "github",
3666
2048
  outputType: "default"
3667
2049
  },
@@ -3669,19 +2051,11 @@ async function generate(spec, settings) {
3669
2051
  );
3670
2052
  const output = settings.mode === "full" ? join2(settings.output, "src") : settings.output;
3671
2053
  settings.useTsExtension ??= true;
3672
- const writtenFiles = /* @__PURE__ */ new Set();
3673
- settings.writer ??= writeFiles;
3674
- const originalWriter = settings.writer;
3675
- settings.writer = async (dir, contents) => {
3676
- await originalWriter(dir, contents);
3677
- for (const file of Object.keys(contents)) {
3678
- if (contents[file] !== null) {
3679
- writtenFiles.add(
3680
- addLeadingSlash(`${relative(settings.output, dir)}/${file}`)
3681
- );
3682
- }
3683
- }
3684
- };
2054
+ const { writer, files: writtenFiles } = createWriterProxy(
2055
+ settings.writer ?? writeFiles,
2056
+ output
2057
+ );
2058
+ settings.writer = writer;
3685
2059
  settings.readFolder ??= async (folder) => {
3686
2060
  const files = await readdir(folder, { withFileTypes: true });
3687
2061
  return files.map((file) => ({
@@ -3693,17 +2067,16 @@ async function generate(spec, settings) {
3693
2067
  const makeImport = (moduleSpecifier) => {
3694
2068
  return settings.useTsExtension ? `${moduleSpecifier}.ts` : moduleSpecifier;
3695
2069
  };
3696
- const { commonSchemas, endpoints, groups, outputs, commonZod } = generateCode(
3697
- {
3698
- spec,
3699
- style,
3700
- makeImport
3701
- }
3702
- );
2070
+ const { endpoints, groups, commonZod } = generateCode({
2071
+ spec,
2072
+ style,
2073
+ makeImport
2074
+ });
3703
2075
  const options = security(spec);
3704
- const clientName = pascalcase4((settings.name || "client").trim());
3705
- const packageName = settings.name ? `@${spinalcase4(settings.name.trim().toLowerCase())}/sdk` : "sdk";
3706
- const inputFiles = generateInputs(groups, commonZod, makeImport);
2076
+ const clientName = pascalcase5((settings.name || "client").trim());
2077
+ const packageName = settings.name ? `@${spinalcase3(settings.name.trim().toLowerCase())}/sdk` : "sdk";
2078
+ const inputs = toInputs(groups, commonZod, makeImport);
2079
+ const models = serializeModels(spec);
3707
2080
  await settings.writer(output, {
3708
2081
  "outputs/.gitkeep": "",
3709
2082
  "inputs/.gitkeep": "",
@@ -3725,8 +2098,6 @@ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputTyp
3725
2098
  import type { RequestConfig, HeadersInit } from './${makeImport("request")}';
3726
2099
  ${interceptors_default}`
3727
2100
  });
3728
- await settings.writer(join2(output, "outputs"), outputs);
3729
- const modelsImports = Object.entries(commonSchemas).map(([name]) => name);
3730
2101
  await settings.writer(output, {
3731
2102
  "client.ts": client_default(
3732
2103
  {
@@ -3737,45 +2108,23 @@ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputTyp
3737
2108
  },
3738
2109
  style
3739
2110
  ),
3740
- ...inputFiles,
3741
- ...endpoints,
3742
- ...Object.fromEntries(
3743
- Object.entries(commonSchemas).map(([name, schema]) => [
3744
- `models/${name}.ts`,
3745
- [
3746
- `import { z } from 'zod';`,
3747
- ...exclude(modelsImports, [name]).map(
3748
- (it) => `import type { ${it} } from './${it}.ts';`
3749
- ),
3750
- `export type ${name} = ${schema};`
3751
- ].join("\n")
3752
- ])
3753
- )
2111
+ ...inputs,
2112
+ ...endpoints
3754
2113
  });
2114
+ await settings.writer(output, models);
3755
2115
  await settings.writer(join2(output, "pagination"), {
3756
2116
  "cursor-pagination.ts": cursor_pagination_default,
3757
2117
  "offset-pagination.ts": offset_pagination_default,
3758
2118
  "page-pagination.ts": page_pagination_default
3759
2119
  });
3760
- const metadata = await readJson(join2(settings.output, "metadata.json"));
3761
- metadata.content.generatedFiles = Array.from(writtenFiles);
3762
- metadata.content.userFiles ??= [];
3763
- await metadata.write(metadata.content);
3764
- if (settings.cleanup !== false && metadata.content.generatedFiles) {
3765
- const generated = metadata.content.generatedFiles;
3766
- const user = metadata.content.userFiles;
3767
- const keep = /* @__PURE__ */ new Set([...generated, ...user]);
3768
- const actualFiles = await readFolder(settings.output, true);
3769
- const toRemove = actualFiles.filter((f) => !keep.has(addLeadingSlash(f))).filter(
3770
- (f) => !ALWAYS_AVAILABLE_FILES.some((pattern) => pattern.test(f))
3771
- );
3772
- for (const file of toRemove) {
3773
- if (file.endsWith(`${sep}index.ts`)) {
3774
- continue;
3775
- }
3776
- const filePath = join2(settings.output, file);
3777
- await unlink(filePath);
3778
- }
2120
+ const metadata = await readWriteMetadata(output, Array.from(writtenFiles));
2121
+ if (settings.cleanup !== false && writtenFiles.size > 0) {
2122
+ await cleanFiles(metadata.content, output, [
2123
+ "/tsconfig*.json",
2124
+ "/package.json",
2125
+ "/metadata.json",
2126
+ "/**/index.ts"
2127
+ ]);
3779
2128
  }
3780
2129
  const folders = [
3781
2130
  getFolderExports(
@@ -3801,17 +2150,13 @@ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputTyp
3801
2150
  settings.useTsExtension,
3802
2151
  ["ts"],
3803
2152
  (dirent) => !["response.ts", "parser.ts"].includes(dirent.fileName)
2153
+ ),
2154
+ getFolderExports(
2155
+ join2(output, "models"),
2156
+ settings.readFolder,
2157
+ settings.useTsExtension
3804
2158
  )
3805
2159
  ];
3806
- if (modelsImports.length) {
3807
- folders.push(
3808
- getFolderExports(
3809
- join2(output, "models"),
3810
- settings.readFolder,
3811
- settings.useTsExtension
3812
- )
3813
- );
3814
- }
3815
2160
  const [outputIndex, inputsIndex, apiIndex, httpIndex, modelsIndex] = await Promise.all(folders);
3816
2161
  await settings.writer(join2(output, "pagination"), {
3817
2162
  "index.ts": await getFolderExports(
@@ -3826,7 +2171,8 @@ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputTyp
3826
2171
  "outputs/index.ts": outputIndex,
3827
2172
  "inputs/index.ts": inputsIndex || null,
3828
2173
  "http/index.ts": httpIndex,
3829
- ...modelsImports.length ? { "models/index.ts": modelsIndex } : {}
2174
+ "models/index.ts": modelsIndex
2175
+ // ...(modelsImports.length ? { 'models/index.ts': modelsIndex } : {}),
3830
2176
  });
3831
2177
  await settings.writer(output, {
3832
2178
  "index.ts": await getFolderExports(
@@ -3907,16 +2253,89 @@ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputTyp
3907
2253
  env: npmRunPathEnv()
3908
2254
  });
3909
2255
  }
3910
- async function readJson(path) {
3911
- const content = await exist(path) ? JSON.parse(await readFile(path, "utf-8")) : { content: {} };
2256
+ function serializeModels(spec) {
2257
+ const filesMap = {};
2258
+ const files = {};
2259
+ for (const [name, schema] of Object.entries(spec.components.schemas)) {
2260
+ const isResponseBody = schema["x-responsebody"];
2261
+ const isRequestBody = schema["x-requestbody"];
2262
+ const responseGroup = schema["x-response-group"];
2263
+ const stream = schema["x-stream"];
2264
+ const folder = isResponseBody ? "outputs" : "models";
2265
+ let typeContent = "ReadableStream";
2266
+ if (!stream) {
2267
+ const serializer = new TypeScriptEmitter(spec);
2268
+ typeContent = serializer.handle(schema, true);
2269
+ }
2270
+ const fileContent = [
2271
+ `
2272
+ ${schema.description ? `
2273
+ /**
2274
+ * ${schema.description}
2275
+ */
2276
+ ` : ""}`,
2277
+ `export type ${pascalcase5(sanitizeTag4(name))} = ${typeContent};`
2278
+ ];
2279
+ const fileName = responseGroup ? join2(folder, `${spinalcase3(responseGroup)}.ts`) : join2(folder, `${spinalcase3(name)}.ts`);
2280
+ filesMap[fileName] ??= [];
2281
+ filesMap[fileName].push(fileContent.join("\n"));
2282
+ }
2283
+ for (const [group, contents] of Object.entries(filesMap)) {
2284
+ let fileContent = contents.join("\n");
2285
+ if (fileContent.includes("models.")) {
2286
+ fileContent = `import type * as models from '../index.ts';
2287
+ ${fileContent}`;
2288
+ }
2289
+ files[group] = fileContent;
2290
+ }
2291
+ return files;
2292
+ }
2293
+ function toInputs(operationsSet, commonZod, makeImport) {
2294
+ const commonImports = commonZod.keys().toArray();
2295
+ const inputs = {};
2296
+ for (const [name, operations] of Object.entries(operationsSet)) {
2297
+ const output = [];
2298
+ const imports = /* @__PURE__ */ new Set(['import { z } from "zod";']);
2299
+ for (const operation of operations) {
2300
+ const schemaName = camelcase4(`${operation.name} schema`);
2301
+ const schema = `export const ${schemaName} = ${Object.keys(operation.schemas).length === 1 ? Object.values(operation.schemas)[0] : toLitObject2(operation.schemas)};`;
2302
+ for (const it of commonImports) {
2303
+ if (schema.includes(it)) {
2304
+ imports.add(
2305
+ `import { ${it} } from './schemas/${makeImport(spinalcase3(it))}';`
2306
+ );
2307
+ }
2308
+ }
2309
+ output.push(schema);
2310
+ }
2311
+ inputs[`inputs/${spinalcase3(name)}.ts`] = [...imports, ...output].join("\n") + "\n";
2312
+ }
2313
+ const schemas = commonZod.entries().reduce((acc, [name, schema]) => {
2314
+ const output = [`import { z } from 'zod';`];
2315
+ const content = `export const ${name} = ${schema};`;
2316
+ for (const schema2 of commonImports) {
2317
+ const preciseMatch = new RegExp(`\\b${schema2}\\b`);
2318
+ if (preciseMatch.test(content) && schema2 !== name) {
2319
+ output.push(
2320
+ `import { ${schema2} } from './${makeImport(spinalcase3(schema2))}';`
2321
+ );
2322
+ }
2323
+ }
2324
+ output.push(content);
2325
+ return [
2326
+ [`inputs/schemas/${spinalcase3(name)}.ts`, output.join("\n")],
2327
+ ...acc
2328
+ ];
2329
+ }, []);
3912
2330
  return {
3913
- content,
3914
- write: (value = content) => writeFile(path, JSON.stringify(value, null, 2), "utf-8")
2331
+ ...Object.fromEntries(schemas),
2332
+ ...inputs
3915
2333
  };
3916
2334
  }
3917
2335
  export {
3918
2336
  TypeScriptGenerator,
3919
2337
  generate,
3920
- readJson
2338
+ generateSnippet,
2339
+ toInputs
3921
2340
  };
3922
2341
  //# sourceMappingURL=index.js.map