@sdk-it/readme 0.21.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.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +394 -0
- package/dist/index.js.map +7 -0
- package/dist/lib/prop.emitter.d.ts +18 -0
- package/dist/lib/prop.emitter.d.ts.map +1 -0
- package/dist/lib/readme.d.ts +6 -0
- package/dist/lib/readme.d.ts.map +1 -0
- package/package.json +28 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
// packages/readme/src/lib/readme.ts
|
|
2
|
+
import { isEmpty as isEmpty2 } from "@sdk-it/core";
|
|
3
|
+
|
|
4
|
+
// packages/spec/dist/lib/operation.js
|
|
5
|
+
import { camelcase } from "stringcase";
|
|
6
|
+
import { followRef, isRef as isRef2 } from "@sdk-it/core/ref.js";
|
|
7
|
+
|
|
8
|
+
// packages/spec/dist/lib/pagination/pagination.js
|
|
9
|
+
import { isRef } from "@sdk-it/core/ref.js";
|
|
10
|
+
import { isEmpty } from "@sdk-it/core/utils.js";
|
|
11
|
+
|
|
12
|
+
// packages/spec/dist/lib/pagination/pagination-result.js
|
|
13
|
+
import pluralize from "pluralize";
|
|
14
|
+
var HAS_MORE_POSITIVE_REGEX_PATTERNS = [
|
|
15
|
+
"\\bhas_?more\\b",
|
|
16
|
+
"\\bhas_?next\\b",
|
|
17
|
+
// e.g., itemsHasNext, items_has_next
|
|
18
|
+
"\\bmore_?items\\b",
|
|
19
|
+
"\\bnext_?page\\b",
|
|
20
|
+
// e.g., userNextPageFlag
|
|
21
|
+
"\\badditional\\b",
|
|
22
|
+
// e.g., hasAdditionalData, additional_results_exist
|
|
23
|
+
"\\bcontinuation\\b",
|
|
24
|
+
// e.g., continuationAvailable, has_continuation_token
|
|
25
|
+
"\\bmore_?results\\b",
|
|
26
|
+
"\\bpage_?available\\b",
|
|
27
|
+
"\\bnext(?:_?(page))?\\b"
|
|
28
|
+
];
|
|
29
|
+
var COMPILED_HAS_MORE_POSITIVE_REGEXES = HAS_MORE_POSITIVE_REGEX_PATTERNS.map((p) => new RegExp(p, "i"));
|
|
30
|
+
var HAS_MORE_INVERTED_REGEX_PATTERNS = [
|
|
31
|
+
"\\bis_?last\\b",
|
|
32
|
+
// e.g., pageIsLast
|
|
33
|
+
"\\blast_?page\\b",
|
|
34
|
+
// e.g., resultsAreLastPage
|
|
35
|
+
"\\bend_?of_?(data|results|list|items|stream)\\b",
|
|
36
|
+
"\\bno_?more_?(items|data|results)?\\b",
|
|
37
|
+
"\\ball_?(items_?)?loaded\\b",
|
|
38
|
+
"\\bis_?complete\\b"
|
|
39
|
+
];
|
|
40
|
+
var COMPILED_HAS_MORE_INVERTED_REGEXES = HAS_MORE_INVERTED_REGEX_PATTERNS.map((p) => new RegExp(p, "i"));
|
|
41
|
+
|
|
42
|
+
// packages/spec/dist/lib/operation.js
|
|
43
|
+
function forEachOperation(config, callback) {
|
|
44
|
+
const result = [];
|
|
45
|
+
for (const [path, pathItem] of Object.entries(config.spec.paths ?? {})) {
|
|
46
|
+
const { parameters = [], ...methods } = pathItem;
|
|
47
|
+
for (const [method, operation] of Object.entries(methods)) {
|
|
48
|
+
const metadata = operation["x-oaiMeta"] ?? {};
|
|
49
|
+
const operationTag = operation.tags?.[0];
|
|
50
|
+
result.push(
|
|
51
|
+
callback(
|
|
52
|
+
{
|
|
53
|
+
name: metadata.name,
|
|
54
|
+
method,
|
|
55
|
+
path,
|
|
56
|
+
groupName: operationTag,
|
|
57
|
+
tag: operationTag
|
|
58
|
+
},
|
|
59
|
+
operation
|
|
60
|
+
)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// packages/readme/src/lib/prop.emitter.ts
|
|
68
|
+
import { followRef as followRef2, isRef as isRef3 } from "@sdk-it/core";
|
|
69
|
+
var PropEmitter = class {
|
|
70
|
+
#spec;
|
|
71
|
+
constructor(spec) {
|
|
72
|
+
this.#spec = spec;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Handle objects (properties)
|
|
76
|
+
*/
|
|
77
|
+
#object(schema) {
|
|
78
|
+
const lines = [];
|
|
79
|
+
const properties = schema.properties || {};
|
|
80
|
+
if (Object.keys(properties).length > 0) {
|
|
81
|
+
lines.push(`**Properties:**`);
|
|
82
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
83
|
+
const isRequired = (schema.required ?? []).includes(propName);
|
|
84
|
+
lines.push(...this.#property(propName, propSchema, isRequired));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (schema.additionalProperties) {
|
|
88
|
+
lines.push(`**Additional Properties:**`);
|
|
89
|
+
if (typeof schema.additionalProperties === "boolean") {
|
|
90
|
+
lines.push(`- Allowed: ${schema.additionalProperties}`);
|
|
91
|
+
} else {
|
|
92
|
+
lines.push(
|
|
93
|
+
...this.handle(schema.additionalProperties).map((l) => ` ${l}`)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return lines;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Format a property with its type and description
|
|
101
|
+
*/
|
|
102
|
+
#property(name, schema, required) {
|
|
103
|
+
const docs = this.handle(schema);
|
|
104
|
+
const rawType = docs[0].replace("**Type:** ", "").replace(" (nullable)", "|null");
|
|
105
|
+
const defaultVal = !isRef3(schema) && schema.default !== void 0 ? ` default: ${JSON.stringify(schema.default)}` : "";
|
|
106
|
+
const reqMark = required ? " required" : "";
|
|
107
|
+
const summary = `- \`${name}\` ${rawType}${reqMark}${defaultVal}:`;
|
|
108
|
+
const detailLines = docs.slice(1).filter((l) => !l.startsWith("**Default:**")).map((l) => ` ${l}`);
|
|
109
|
+
return [summary, ...detailLines];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Handle array schemas
|
|
113
|
+
*/
|
|
114
|
+
#array(schema) {
|
|
115
|
+
const lines = [];
|
|
116
|
+
lines.push(`**Array items:**`);
|
|
117
|
+
if (schema.items) {
|
|
118
|
+
const itemDocs = this.handle(schema.items);
|
|
119
|
+
lines.push(...itemDocs.map((line) => ` ${line}`));
|
|
120
|
+
} else {
|
|
121
|
+
lines.push(` **Type:** \`unknown\``);
|
|
122
|
+
}
|
|
123
|
+
if (schema.minItems !== void 0)
|
|
124
|
+
lines.push(`- Minimum items: ${schema.minItems}`);
|
|
125
|
+
if (schema.maxItems !== void 0)
|
|
126
|
+
lines.push(`- Maximum items: ${schema.maxItems}`);
|
|
127
|
+
if (schema.uniqueItems)
|
|
128
|
+
lines.push(`- Items must be unique.`);
|
|
129
|
+
return lines;
|
|
130
|
+
}
|
|
131
|
+
#ref($ref) {
|
|
132
|
+
const schemaName = $ref.split("/").pop() || "object";
|
|
133
|
+
const resolved = followRef2(this.#spec, $ref);
|
|
134
|
+
const lines = [
|
|
135
|
+
`**Type:** [\`${schemaName}\`](#${schemaName.toLowerCase()})`
|
|
136
|
+
];
|
|
137
|
+
if (resolved.description) {
|
|
138
|
+
lines.push(resolved.description);
|
|
139
|
+
}
|
|
140
|
+
return lines;
|
|
141
|
+
}
|
|
142
|
+
#allOf(schemas) {
|
|
143
|
+
const lines = ["**All of (Intersection):**"];
|
|
144
|
+
schemas.forEach((subSchema, index) => {
|
|
145
|
+
lines.push(`- **Constraint ${index + 1}:**`);
|
|
146
|
+
const subLines = this.handle(subSchema);
|
|
147
|
+
lines.push(...subLines.map((l) => ` ${l}`));
|
|
148
|
+
});
|
|
149
|
+
return lines;
|
|
150
|
+
}
|
|
151
|
+
#anyOf(schemas) {
|
|
152
|
+
const lines = ["**Any of (Union):**"];
|
|
153
|
+
schemas.forEach((subSchema, index) => {
|
|
154
|
+
lines.push(`- **Option ${index + 1}:**`);
|
|
155
|
+
const subLines = this.handle(subSchema);
|
|
156
|
+
lines.push(...subLines.map((l) => ` ${l}`));
|
|
157
|
+
});
|
|
158
|
+
return lines;
|
|
159
|
+
}
|
|
160
|
+
#oneOf(schemas) {
|
|
161
|
+
const lines = ["**One of (Exclusive Union):**"];
|
|
162
|
+
schemas.forEach((subSchema, index) => {
|
|
163
|
+
lines.push(`- **Option ${index + 1}:**`);
|
|
164
|
+
const subLines = this.handle(subSchema);
|
|
165
|
+
lines.push(...subLines.map((l) => ` ${l}`));
|
|
166
|
+
});
|
|
167
|
+
return lines;
|
|
168
|
+
}
|
|
169
|
+
#enum(schema) {
|
|
170
|
+
const lines = [`**Type:** \`${schema.type || "unknown"}\` (enum)`];
|
|
171
|
+
if (schema.description)
|
|
172
|
+
lines.push(schema.description);
|
|
173
|
+
lines.push("**Allowed values:**");
|
|
174
|
+
lines.push(
|
|
175
|
+
...(schema.enum || []).map((val) => `- \`${JSON.stringify(val)}\``)
|
|
176
|
+
);
|
|
177
|
+
if (schema.default !== void 0) {
|
|
178
|
+
lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
|
|
179
|
+
}
|
|
180
|
+
return lines;
|
|
181
|
+
}
|
|
182
|
+
#normal(type, schema, nullable) {
|
|
183
|
+
const lines = [];
|
|
184
|
+
const nullableSuffix = nullable ? " (nullable)" : "";
|
|
185
|
+
const description = schema.description ? [schema.description] : [];
|
|
186
|
+
switch (type) {
|
|
187
|
+
case "string":
|
|
188
|
+
lines.push(
|
|
189
|
+
`**Type:** \`string\`${schema.format ? ` (format: ${schema.format})` : ""}${nullableSuffix}`
|
|
190
|
+
);
|
|
191
|
+
lines.push(...description);
|
|
192
|
+
if (schema.minLength !== void 0)
|
|
193
|
+
lines.push(`- Minimum length: ${schema.minLength}`);
|
|
194
|
+
if (schema.maxLength !== void 0)
|
|
195
|
+
lines.push(`- Maximum length: ${schema.maxLength}`);
|
|
196
|
+
if (schema.pattern !== void 0)
|
|
197
|
+
lines.push(`- Pattern: \`${schema.pattern}\``);
|
|
198
|
+
break;
|
|
199
|
+
case "number":
|
|
200
|
+
case "integer":
|
|
201
|
+
lines.push(
|
|
202
|
+
`**Type:** \`${type}\`${schema.format ? ` (format: ${schema.format})` : ""}${nullableSuffix}`
|
|
203
|
+
);
|
|
204
|
+
lines.push(...description);
|
|
205
|
+
if (schema.minimum !== void 0) {
|
|
206
|
+
const exclusiveMin = typeof schema.exclusiveMinimum === "number";
|
|
207
|
+
lines.push(
|
|
208
|
+
`- Minimum: ${schema.minimum}${exclusiveMin ? " (exclusive)" : ""}`
|
|
209
|
+
);
|
|
210
|
+
if (exclusiveMin) {
|
|
211
|
+
lines.push(
|
|
212
|
+
`- Must be strictly greater than: ${schema.exclusiveMinimum}`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
} else if (typeof schema.exclusiveMinimum === "number") {
|
|
216
|
+
lines.push(
|
|
217
|
+
`- Must be strictly greater than: ${schema.exclusiveMinimum}`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
if (schema.maximum !== void 0) {
|
|
221
|
+
const exclusiveMax = typeof schema.exclusiveMaximum === "number";
|
|
222
|
+
lines.push(
|
|
223
|
+
`- Maximum: ${schema.maximum}${exclusiveMax ? " (exclusive)" : ""}`
|
|
224
|
+
);
|
|
225
|
+
if (exclusiveMax) {
|
|
226
|
+
lines.push(
|
|
227
|
+
`- Must be strictly less than: ${schema.exclusiveMaximum}`
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
} else if (typeof schema.exclusiveMaximum === "number") {
|
|
231
|
+
lines.push(
|
|
232
|
+
`- Must be strictly less than: ${schema.exclusiveMaximum}`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
if (schema.multipleOf !== void 0)
|
|
236
|
+
lines.push(`- Must be a multiple of: ${schema.multipleOf}`);
|
|
237
|
+
break;
|
|
238
|
+
case "boolean":
|
|
239
|
+
lines.push(`**Type:** \`boolean\`${nullableSuffix}`);
|
|
240
|
+
lines.push(...description);
|
|
241
|
+
break;
|
|
242
|
+
case "object":
|
|
243
|
+
lines.push(`**Type:** \`object\`${nullableSuffix}`);
|
|
244
|
+
lines.push(...description);
|
|
245
|
+
lines.push(...this.#object(schema));
|
|
246
|
+
break;
|
|
247
|
+
case "array":
|
|
248
|
+
lines.push(`**Type:** \`array\`${nullableSuffix}`);
|
|
249
|
+
lines.push(...description);
|
|
250
|
+
lines.push(...this.#array(schema));
|
|
251
|
+
break;
|
|
252
|
+
case "null":
|
|
253
|
+
lines.push(`**Type:** \`null\``);
|
|
254
|
+
lines.push(...description);
|
|
255
|
+
break;
|
|
256
|
+
default:
|
|
257
|
+
lines.push(`**Type:** \`${type}\`${nullableSuffix}`);
|
|
258
|
+
lines.push(...description);
|
|
259
|
+
}
|
|
260
|
+
if (schema.default !== void 0) {
|
|
261
|
+
lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
|
|
262
|
+
}
|
|
263
|
+
return lines.filter((l) => l);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Handle schemas by resolving references and delegating to appropriate handler
|
|
267
|
+
*/
|
|
268
|
+
handle(schemaOrRef) {
|
|
269
|
+
if (isRef3(schemaOrRef)) {
|
|
270
|
+
return this.#ref(schemaOrRef.$ref);
|
|
271
|
+
}
|
|
272
|
+
const schema = schemaOrRef;
|
|
273
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
274
|
+
return this.#allOf(schema.allOf);
|
|
275
|
+
}
|
|
276
|
+
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
277
|
+
return this.#anyOf(schema.anyOf);
|
|
278
|
+
}
|
|
279
|
+
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
280
|
+
return this.#oneOf(schema.oneOf);
|
|
281
|
+
}
|
|
282
|
+
if (schema.enum && Array.isArray(schema.enum)) {
|
|
283
|
+
return this.#enum(schema);
|
|
284
|
+
}
|
|
285
|
+
let types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
|
|
286
|
+
let nullable = false;
|
|
287
|
+
if (types.includes("null")) {
|
|
288
|
+
nullable = true;
|
|
289
|
+
types = types.filter((t) => t !== "null");
|
|
290
|
+
}
|
|
291
|
+
if (types.length === 0) {
|
|
292
|
+
if (schema.properties || schema.additionalProperties) {
|
|
293
|
+
types = ["object"];
|
|
294
|
+
} else if (schema.items) {
|
|
295
|
+
types = ["array"];
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (types.length === 0) {
|
|
299
|
+
const lines2 = ["**Type:** `unknown`"];
|
|
300
|
+
if (schema.description)
|
|
301
|
+
lines2.push(schema.description);
|
|
302
|
+
if (schema.default !== void 0)
|
|
303
|
+
lines2.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
|
|
304
|
+
return lines2;
|
|
305
|
+
}
|
|
306
|
+
if (types.length === 1) {
|
|
307
|
+
return this.#normal(types[0], schema, nullable);
|
|
308
|
+
}
|
|
309
|
+
const typeString = types.join(" | ");
|
|
310
|
+
const nullableSuffix = nullable ? " (nullable)" : "";
|
|
311
|
+
const lines = [`**Type:** \`${typeString}\`${nullableSuffix}`];
|
|
312
|
+
if (schema.description)
|
|
313
|
+
lines.push(schema.description);
|
|
314
|
+
if (schema.default !== void 0)
|
|
315
|
+
lines.push(`**Default:** \`${JSON.stringify(schema.default)}\``);
|
|
316
|
+
return lines;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Process a request body and return markdown documentation
|
|
320
|
+
*/
|
|
321
|
+
requestBody(requestBody) {
|
|
322
|
+
if (!requestBody)
|
|
323
|
+
return [];
|
|
324
|
+
const lines = [];
|
|
325
|
+
lines.push(`##### Request Body`);
|
|
326
|
+
if (requestBody.description) {
|
|
327
|
+
lines.push(requestBody.description);
|
|
328
|
+
}
|
|
329
|
+
if (requestBody.required) {
|
|
330
|
+
lines.push(`*This request body is required.*`);
|
|
331
|
+
}
|
|
332
|
+
if (requestBody.content) {
|
|
333
|
+
for (const [contentType, mediaType] of Object.entries(
|
|
334
|
+
requestBody.content
|
|
335
|
+
)) {
|
|
336
|
+
lines.push(`**Content Type:** \`${contentType}\``);
|
|
337
|
+
if (mediaType.schema) {
|
|
338
|
+
const schemaDocs = this.handle(mediaType.schema);
|
|
339
|
+
lines.push(...schemaDocs);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return lines;
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
// packages/readme/src/lib/readme.ts
|
|
348
|
+
function toReadme(spec, generators) {
|
|
349
|
+
const markdown = [];
|
|
350
|
+
const propEmitter = new PropEmitter(spec);
|
|
351
|
+
forEachOperation({ spec }, (entry, operation) => {
|
|
352
|
+
const { method, path, name } = entry;
|
|
353
|
+
spec.components ??= {};
|
|
354
|
+
spec.components.schemas ??= {};
|
|
355
|
+
markdown.push(
|
|
356
|
+
`#### ${name || operation.operationId} | ${`_${method.toUpperCase()} ${path}_`}`
|
|
357
|
+
);
|
|
358
|
+
markdown.push(operation.summary || "");
|
|
359
|
+
const snippet = generators.generateSnippet(entry, operation);
|
|
360
|
+
markdown.push(`##### Example usage`);
|
|
361
|
+
markdown.push(snippet);
|
|
362
|
+
const requestBodyContent = propEmitter.requestBody(operation.requestBody);
|
|
363
|
+
if (requestBodyContent.length > 1) {
|
|
364
|
+
markdown.push(requestBodyContent.join("\n\n"));
|
|
365
|
+
}
|
|
366
|
+
markdown.push(`##### Responses`);
|
|
367
|
+
for (const status in operation.responses) {
|
|
368
|
+
const response = operation.responses[status];
|
|
369
|
+
markdown.push(`<details>`);
|
|
370
|
+
markdown.push(
|
|
371
|
+
`<summary><b>${status}</b> <i>${response.description}</i></summary>`
|
|
372
|
+
);
|
|
373
|
+
if (!isEmpty2(response.content)) {
|
|
374
|
+
for (const [contentType, mediaType] of Object.entries(
|
|
375
|
+
response.content
|
|
376
|
+
)) {
|
|
377
|
+
markdown.push(`
|
|
378
|
+
**Content Type:** \`${contentType}\``);
|
|
379
|
+
if (mediaType.schema) {
|
|
380
|
+
const schemaDocs = propEmitter.handle(mediaType.schema);
|
|
381
|
+
markdown.push(...schemaDocs.map((l) => `
|
|
382
|
+
${l}`));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
markdown.push(`</details>`);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
return markdown.join("\n\n");
|
|
390
|
+
}
|
|
391
|
+
export {
|
|
392
|
+
toReadme
|
|
393
|
+
};
|
|
394
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/readme.ts", "../../spec/src/lib/operation.ts", "../../spec/src/lib/pagination/pagination.ts", "../../spec/src/lib/pagination/pagination-result.ts", "../src/lib/prop.emitter.ts"],
|
|
4
|
+
"sourcesContent": ["import type { OpenAPIObject } from 'openapi3-ts/oas31';\n\nimport { isEmpty } from '@sdk-it/core';\nimport {\n type OperationEntry,\n type TunedOperationObject,\n forEachOperation,\n} from '@sdk-it/spec/operation.js';\n\nimport { PropEmitter } from './prop.emitter.ts';\n\nexport function toReadme(\n spec: OpenAPIObject,\n generators: {\n generateSnippet: (\n entry: OperationEntry,\n operation: TunedOperationObject,\n ) => string;\n },\n) {\n // table of content is the navigation headers in apiref\n const markdown: string[] = [];\n const propEmitter = new PropEmitter(spec);\n\n forEachOperation({ spec }, (entry, operation) => {\n const { method, path, name } = entry;\n spec.components ??= {};\n spec.components.schemas ??= {};\n markdown.push(\n `#### ${name || operation.operationId} | ${`_${method.toUpperCase()} ${path}_`}`,\n );\n markdown.push(operation.summary || '');\n\n const snippet = generators.generateSnippet(entry, operation);\n markdown.push(`##### Example usage`);\n markdown.push(snippet);\n\n // Process request body using the refactored emitter\n const requestBodyContent = propEmitter.requestBody(operation.requestBody);\n if (requestBodyContent.length > 1) {\n // Check if more than just the header was added\n markdown.push(requestBodyContent.join('\\n\\n'));\n }\n\n markdown.push(`##### Responses`);\n for (const status in operation.responses) {\n const response = operation.responses[status];\n // Wrap each response in its own toggle\n markdown.push(`<details>`);\n markdown.push(\n `<summary><b>${status}</b> <i>${response.description}</i></summary>`,\n );\n if (!isEmpty(response.content)) {\n for (const [contentType, mediaType] of Object.entries(\n response.content,\n )) {\n markdown.push(`\\n**Content Type:** \\`${contentType}\\``);\n if (mediaType.schema) {\n const schemaDocs = propEmitter.handle(mediaType.schema);\n // hide emitter output under the toggle\n markdown.push(...schemaDocs.map((l) => `\\n${l}`));\n }\n }\n }\n markdown.push(`</details>`);\n }\n });\n return markdown.join('\\n\\n');\n}\n", "import type {\n ComponentsObject,\n OpenAPIObject,\n OperationObject,\n ParameterLocation,\n ParameterObject,\n PathsObject,\n ReferenceObject,\n RequestBodyObject,\n ResponseObject,\n SchemaObject,\n SecurityRequirementObject,\n} from 'openapi3-ts/oas31';\nimport { camelcase } from 'stringcase';\n\nimport type { Method } from '@sdk-it/core/paths.js';\nimport { followRef, isRef } from '@sdk-it/core/ref.js';\n\nimport {\n type PaginationGuess,\n guessPagination,\n} from './pagination/pagination.js';\n\nexport function augmentSpec(config: GenerateSdkConfig) {\n config.spec.paths ??= {};\n const paths: PathsObject = {};\n for (const [path, pathItem] of Object.entries(config.spec.paths)) {\n const { parameters = [], ...methods } = pathItem;\n\n // Convert Express-style routes (:param) to OpenAPI-style routes ({param})\n const fixedPath = path.replace(/:([^/]+)/g, '{$1}');\n for (const [method, operation] of Object.entries(methods) as [\n Method,\n OperationObject,\n ][]) {\n const formatOperationId = config.operationId ?? defaults.operationId;\n const formatTag = config.tag ?? defaults.tag;\n const operationId = formatOperationId(operation, fixedPath, method);\n const operationTag = formatTag(operation, fixedPath);\n const requestBody = isRef(operation.requestBody)\n ? followRef<RequestBodyObject>(config.spec, operation.requestBody.$ref)\n : operation.requestBody;\n const tunedOperation: TunedOperationObject = {\n ...operation,\n parameters: [...parameters, ...(operation.parameters ?? [])].map(\n (it) =>\n isRef(it) ? followRef<ParameterObject>(config.spec, it.$ref) : it,\n ),\n tags: [operationTag],\n operationId: operationId,\n responses: resolveResponses(config.spec, operation),\n requestBody: requestBody,\n };\n\n tunedOperation['x-pagination'] = toPagination(\n config.spec,\n tunedOperation,\n );\n\n Object.assign(paths, {\n [fixedPath]: {\n ...paths[fixedPath],\n [method]: tunedOperation,\n },\n });\n }\n }\n return { ...config.spec, paths };\n}\n\nexport type OperationPagination = PaginationGuess & {\n items: string;\n};\n\nfunction toPagination(\n spec: OpenAPIObject,\n tunedOperation: TunedOperationObject,\n) {\n if (tunedOperation['x-pagination']) {\n return tunedOperation['x-pagination'];\n }\n const schema = getResponseContentSchema(\n spec,\n tunedOperation.responses['200'],\n 'application/json',\n );\n const pagination = guessPagination(\n tunedOperation,\n tunedOperation.requestBody\n ? getRequestContentSchema(\n spec,\n tunedOperation.requestBody,\n 'application/json',\n )\n : undefined,\n schema,\n );\n if (pagination && pagination.type !== 'none' && schema) {\n // console.dir({\n // [`${method.toUpperCase()} ${fixedPath}`]: {\n // ...pagination,\n // },\n // });\n return pagination;\n }\n return undefined;\n}\n\nfunction getResponseContentSchema(\n spec: OpenAPIObject,\n response: ResponseObject,\n type: string,\n) {\n if (!response) {\n return undefined;\n }\n const content = response.content;\n if (!content) {\n return undefined;\n }\n for (const contentType in content) {\n if (contentType.toLowerCase() === type.toLowerCase()) {\n return isRef(content[contentType].schema)\n ? followRef<SchemaObject>(spec, content[contentType].schema.$ref)\n : content[contentType].schema;\n }\n }\n return undefined;\n}\n\nfunction getRequestContentSchema(\n spec: OpenAPIObject,\n requestBody: RequestBodyObject,\n type: string,\n) {\n const content = requestBody.content;\n if (!content) {\n return undefined;\n }\n for (const contentType in content) {\n if (contentType.toLowerCase() === type.toLowerCase()) {\n return isRef(content[contentType].schema)\n ? followRef<SchemaObject>(spec, content[contentType].schema.$ref)\n : content[contentType].schema;\n }\n }\n return undefined;\n}\n\nexport const defaults: Partial<GenerateSdkConfig> &\n Required<Pick<GenerateSdkConfig, 'operationId' | 'tag'>> = {\n operationId: (operation, path, method) => {\n if (operation.operationId) {\n return camelcase(operation.operationId);\n }\n const metadata = operation['x-oaiMeta'];\n if (metadata && metadata.name) {\n return camelcase(metadata.name);\n }\n return camelcase(\n [method, ...path.replace(/[\\\\/\\\\{\\\\}]/g, ' ').split(' ')]\n .filter(Boolean)\n .join(' ')\n .trim(),\n );\n },\n tag: (operation, path) => {\n return operation.tags?.[0]\n ? sanitizeTag(operation.tags?.[0])\n : determineGenericTag(path, operation);\n },\n};\n\nexport type TunedOperationObject = Omit<\n OperationObject,\n 'operationId' | 'parameters' | 'responses'\n> & {\n operationId: string;\n parameters: ParameterObject[];\n responses: Record<string, ResponseObject>;\n requestBody: RequestBodyObject | undefined;\n};\n\nexport interface OperationEntry {\n name?: string;\n method: string;\n path: string;\n groupName: string;\n tag: string;\n}\nexport type Operation = {\n entry: OperationEntry;\n operation: TunedOperationObject;\n};\n\nfunction resolveResponses(spec: OpenAPIObject, operation: OperationObject) {\n const responses = operation.responses ?? {};\n const resolved: Record<string, ResponseObject> = {};\n for (const status in responses) {\n const response = isRef(responses[status] as ReferenceObject)\n ? followRef<ResponseObject>(spec, responses[status].$ref)\n : (responses[status] as ResponseObject);\n resolved[status] = response;\n }\n return resolved;\n}\n\nexport function forEachOperation<T>(\n config: GenerateSdkConfig,\n callback: (entry: OperationEntry, operation: TunedOperationObject) => T,\n) {\n const result: T[] = [];\n for (const [path, pathItem] of Object.entries(config.spec.paths ?? {})) {\n const { parameters = [], ...methods } = pathItem;\n\n for (const [method, operation] of Object.entries(methods) as [\n string,\n OperationObject,\n ][]) {\n const metadata = operation['x-oaiMeta'] ?? {};\n const operationTag = operation.tags?.[0] as string;\n\n result.push(\n callback(\n {\n name: metadata.name,\n method,\n path: path,\n groupName: operationTag,\n tag: operationTag,\n },\n operation as TunedOperationObject,\n ),\n );\n }\n }\n return result;\n}\n\nexport interface GenerateSdkConfig {\n spec: OpenAPIObject;\n operationId?: (\n operation: OperationObject,\n path: string,\n method: string,\n ) => string;\n tag?: (operation: OperationObject, path: string) => string;\n}\n\n/**\n * Set of reserved TypeScript keywords and common verbs potentially used as tags.\n */\n\nconst reservedKeywords = new Set([\n 'await', // Reserved in async functions\n 'break',\n 'case',\n 'catch',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'else',\n 'enum',\n 'export',\n 'extends',\n 'false',\n 'finally',\n 'for',\n 'function',\n 'if',\n 'implements', // Strict mode\n 'import',\n 'in',\n 'instanceof',\n 'interface', // Strict mode\n 'let', // Strict mode\n 'new',\n 'null',\n 'package', // Strict mode\n 'private', // Strict mode\n 'protected', // Strict mode\n 'public', // Strict mode\n 'return',\n 'static', // Strict mode\n 'super',\n 'switch',\n 'this',\n 'throw',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'while',\n 'with',\n 'yield', // Strict mode / Generator functions\n // 'arguments' is not technically a reserved word, but it's a special identifier within functions\n // and assigning to it or declaring it can cause issues or unexpected behavior.\n 'arguments',\n]);\n\n/**\n * Sanitizes a potential tag name (assumed to be already camelCased)\n * to avoid conflicts with reserved keywords or invalid starting characters (numbers).\n * Appends an underscore if the tag matches a reserved keyword.\n * Prepends an underscore if the tag starts with a number.\n * @param camelCasedTag The potential tag name, already camelCased.\n * @returns The sanitized tag name.\n */\nfunction sanitizeTag(camelCasedTag: string): string {\n // Prepend underscore if starts with a number\n if (/^\\d/.test(camelCasedTag)) {\n return `_${camelCasedTag}`;\n }\n // Append underscore if it's a reserved keyword\n return reservedKeywords.has(camelcase(camelCasedTag))\n ? `${camelCasedTag}_`\n : camelCasedTag;\n}\n\n/**\n * Attempts to determine a generic tag for an OpenAPI operation based on path and operationId.\n * Rules and fallbacks are documented within the code.\n * @param pathString The path string.\n * @param operation The OpenAPI Operation Object.\n * @returns A sanitized, camelCased tag name string.\n */\nexport function determineGenericTag(\n pathString: string,\n operation: OperationObject,\n): string {\n const operationId = operation.operationId || '';\n const VERSION_REGEX = /^[vV]\\d+$/;\n const commonVerbs = new Set([\n // Verbs to potentially strip from operationId prefix\n 'get',\n 'list',\n 'create',\n 'update',\n 'delete',\n 'post',\n 'put',\n 'patch',\n 'do',\n 'send',\n 'add',\n 'remove',\n 'set',\n 'find',\n 'search',\n 'check',\n 'make',\n ]);\n\n const segments = pathString.split('/').filter(Boolean);\n\n const potentialCandidates = segments.filter(\n (segment) =>\n segment &&\n !segment.startsWith('{') &&\n !segment.endsWith('}') &&\n !VERSION_REGEX.test(segment),\n );\n\n // --- Heuristic 1: Last non-'@' path segment ---\n for (let i = potentialCandidates.length - 1; i >= 0; i--) {\n const segment = potentialCandidates[i];\n if (!segment.startsWith('@')) {\n // Sanitize just before returning\n return sanitizeTag(camelcase(segment));\n }\n }\n\n const canFallbackToPathSegment = potentialCandidates.length > 0;\n\n // --- Heuristic 2: OperationId parsing ---\n if (operationId) {\n const lowerOpId = operationId.toLowerCase();\n const parts = operationId\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-zA-Z])(\\d)/g, '$1_$2')\n .replace(/(\\d)([a-zA-Z])/g, '$1_$2')\n .toLowerCase()\n .split(/[_-\\s]+/);\n\n const validParts = parts.filter(Boolean);\n\n // Quick skip: If opId is just a verb and we can use Heuristic 3, prefer that.\n if (\n commonVerbs.has(lowerOpId) &&\n validParts.length === 1 &&\n canFallbackToPathSegment\n ) {\n // Proceed directly to Heuristic 3\n }\n // Only process if there are valid parts and the quick skip didn't happen\n else if (validParts.length > 0) {\n const firstPart = validParts[0];\n const isFirstPartVerb = commonVerbs.has(firstPart);\n\n // Case 2a: Starts with verb, has following parts\n if (isFirstPartVerb && validParts.length > 1) {\n const verbPrefixLength = firstPart.length;\n let nextPartStartIndex = -1;\n if (operationId.length > verbPrefixLength) {\n // Simplified check for next part start\n const charAfterPrefix = operationId[verbPrefixLength];\n if (charAfterPrefix >= 'A' && charAfterPrefix <= 'Z') {\n nextPartStartIndex = verbPrefixLength;\n } else if (charAfterPrefix >= '0' && charAfterPrefix <= '9') {\n nextPartStartIndex = verbPrefixLength;\n } else if (['_', '-'].includes(charAfterPrefix)) {\n nextPartStartIndex = verbPrefixLength + 1;\n } else {\n const match = operationId\n .substring(verbPrefixLength)\n .match(/[A-Z0-9]/);\n if (match && match.index !== undefined) {\n nextPartStartIndex = verbPrefixLength + match.index;\n }\n if (\n nextPartStartIndex === -1 &&\n operationId.length > verbPrefixLength\n ) {\n nextPartStartIndex = verbPrefixLength; // Default guess\n }\n }\n }\n\n if (\n nextPartStartIndex !== -1 &&\n nextPartStartIndex < operationId.length\n ) {\n const remainingOriginalSubstring =\n operationId.substring(nextPartStartIndex);\n const potentialTag = camelcase(remainingOriginalSubstring);\n if (potentialTag) {\n // Sanitize just before returning\n return sanitizeTag(potentialTag);\n }\n }\n\n // Fallback: join remaining lowercased parts\n const potentialTagJoined = camelcase(validParts.slice(1).join('_'));\n if (potentialTagJoined) {\n // Sanitize just before returning\n return sanitizeTag(potentialTagJoined);\n }\n }\n\n // Case 2b: Doesn't start with verb, or only one part (might be verb)\n const potentialTagFull = camelcase(operationId);\n if (potentialTagFull) {\n const isResultSingleVerb = validParts.length === 1 && isFirstPartVerb;\n\n // Avoid returning only a verb if Heuristic 3 is possible\n if (!(isResultSingleVerb && canFallbackToPathSegment)) {\n if (potentialTagFull.length > 0) {\n // Sanitize just before returning\n return sanitizeTag(potentialTagFull);\n }\n }\n }\n\n // Case 2c: Further fallbacks within OpId if above failed/skipped\n const firstPartCamel = camelcase(firstPart);\n if (firstPartCamel) {\n const isFirstPartCamelVerb = commonVerbs.has(firstPartCamel);\n if (\n !isFirstPartCamelVerb ||\n validParts.length === 1 ||\n !canFallbackToPathSegment\n ) {\n // Sanitize just before returning\n return sanitizeTag(firstPartCamel);\n }\n }\n if (\n isFirstPartVerb &&\n validParts.length > 1 &&\n validParts[1] &&\n canFallbackToPathSegment\n ) {\n const secondPartCamel = camelcase(validParts[1]);\n if (secondPartCamel) {\n // Sanitize just before returning\n return sanitizeTag(secondPartCamel);\n }\n }\n } // End if(validParts.length > 0) after quick skip check\n } // End if(operationId)\n\n // --- Heuristic 3: First path segment (stripping '@') ---\n if (potentialCandidates.length > 0) {\n let firstCandidate = potentialCandidates[0];\n if (firstCandidate.startsWith('@')) {\n firstCandidate = firstCandidate.substring(1);\n }\n if (firstCandidate) {\n // Sanitize just before returning\n return sanitizeTag(camelcase(firstCandidate));\n }\n }\n\n // --- Heuristic 4: Default ---\n console.warn(\n `Could not determine a suitable tag for path: ${pathString}, operationId: ${operationId}. Using 'unknown'.`,\n );\n return 'unknown'; // 'unknown' is safe\n}\n\nexport function parseJsonContentType(contentType: string | null | undefined) {\n if (!contentType) {\n return null;\n }\n\n // 1. Trim whitespace\n let mainType = contentType.trim();\n\n // 2. Remove parameters (anything after the first ';')\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n mainType = mainType.substring(0, semicolonIndex).trim(); // Trim potential space before ';'\n }\n\n // 3. Convert to lowercase for case-insensitive comparison\n mainType = mainType.toLowerCase();\n\n if (mainType.endsWith('/json')) {\n return mainType.split('/')[1];\n } else if (mainType.endsWith('+json')) {\n return mainType.split('+')[1];\n }\n return null;\n}\n\n/**\n * Checks if a given content type string represents Server-Sent Events (SSE).\n * Handles case-insensitivity, parameters (like charset), and leading/trailing whitespace.\n *\n * @param contentType The content type string to check (e.g., from a Content-Type header).\n * @returns True if the content type is 'text/event-stream', false otherwise.\n */\nexport function isSseContentType(\n contentType: string | null | undefined,\n): boolean {\n if (!contentType) {\n return false; // Handle null, undefined, or empty string\n }\n\n // 1. Trim whitespace from the input string\n let mainType = contentType.trim();\n\n // 2. Find the position of the first semicolon (if any) to remove parameters\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n // Extract the part before the semicolon and trim potential space\n mainType = mainType.substring(0, semicolonIndex).trim();\n }\n\n // 3. Convert the main type part to lowercase for case-insensitive comparison\n mainType = mainType.toLowerCase();\n\n // 4. Compare against the standard SSE MIME type\n return mainType === 'text/event-stream';\n}\n\nexport function isStreamingContentType(\n contentType: string | null | undefined,\n): boolean {\n return contentType === 'application/octet-stream';\n}\n\nexport function isSuccessStatusCode(statusCode: number | string): boolean {\n statusCode = Number(statusCode);\n return statusCode >= 200 && statusCode < 300;\n}\n\nexport function patchParameters(\n spec: OpenAPIObject,\n objectSchema: SchemaObject,\n operation: TunedOperationObject,\n) {\n const securitySchemes = spec.components?.securitySchemes ?? {};\n const securityOptions = securityToOptions(\n spec,\n operation.security ?? [],\n securitySchemes,\n );\n\n objectSchema.properties ??= {};\n objectSchema.required ??= [];\n for (const param of operation.parameters) {\n if (param.required) {\n objectSchema.required.push(param.name);\n }\n objectSchema.properties[param.name] = isRef(param.schema)\n ? followRef<SchemaObject>(spec, param.schema.$ref)\n : (param.schema ?? { type: 'string' });\n }\n for (const param of securityOptions) {\n objectSchema.required = (objectSchema.required ?? []).filter(\n (name) => name !== param.name,\n );\n objectSchema.properties[param.name] = isRef(param.schema)\n ? followRef<SchemaObject>(spec, param.schema.$ref)\n : (param.schema ?? { type: 'string' });\n }\n}\n\nexport function securityToOptions(\n spec: OpenAPIObject,\n security: SecurityRequirementObject[],\n securitySchemes: ComponentsObject['securitySchemes'],\n staticIn?: ParameterLocation,\n) {\n securitySchemes ??= {};\n const parameters: ParameterObject[] = [];\n for (const it of security) {\n const [name] = Object.keys(it);\n if (!name) {\n // this means the operation doesn't necessarily require security\n continue;\n }\n const schema = isRef(securitySchemes[name])\n ? followRef(spec, securitySchemes[name].$ref)\n : securitySchemes[name];\n\n if (schema.type === 'http') {\n parameters.push({\n in: staticIn ?? 'header',\n name: 'authorization',\n schema: { type: 'string' },\n });\n continue;\n }\n if (schema.type === 'apiKey') {\n if (!schema.in) {\n throw new Error(`apiKey security schema must have an \"in\" field`);\n }\n if (!schema.name) {\n throw new Error(`apiKey security schema must have a \"name\" field`);\n }\n parameters.push({\n in: staticIn ?? (schema.in as ParameterLocation),\n name: schema.name,\n schema: { type: 'string' },\n });\n continue;\n }\n }\n return parameters;\n}\n", "import type { SchemaObject, SchemasObject } from 'openapi3-ts/oas31';\n\nimport { isRef } from '@sdk-it/core/ref.js';\nimport { isEmpty } from '@sdk-it/core/utils.js';\n\nimport type { TunedOperationObject } from '../operation';\nimport { getHasMoreName, getItemsName } from './pagination-result.js';\n\ninterface PaginationResultBase {\n type: 'offset' | 'page' | 'cursor' | 'none';\n}\n\nexport interface OffsetPaginationResult extends PaginationResultBase {\n type: 'offset';\n offsetParamName: string;\n offsetKeyword: string; // The actual part of param name that matched\n limitParamName: string;\n limitKeyword: string; // The actual part of param name that matched\n}\n\nexport interface PagePaginationResult extends PaginationResultBase {\n type: 'page';\n pageNumberParamName: string;\n pageNumberKeyword: string;\n pageSizeParamName: string;\n pageSizeKeyword: string;\n}\n\nexport interface CursorPaginationResult extends PaginationResultBase {\n type: 'cursor';\n cursorParamName: string;\n cursorKeyword: string;\n limitParamName: string;\n limitKeyword: string;\n}\n\nexport interface NoPaginationResult extends PaginationResultBase {\n type: 'none';\n reason: string;\n}\n\nexport type PaginationGuess =\n | ((\n | OffsetPaginationResult\n | PagePaginationResult\n | CursorPaginationResult\n ) & { items: string; hasMore: string })\n | NoPaginationResult;\n\n// --- Keyword Regex Definitions ---\n\nexport const OFFSET_PARAM_REGEXES: RegExp[] = [\n /\\boffset\\b/i,\n /\\bskip\\b/i,\n /\\bstart(?:ing_at|_index)?\\b/i, // e.g., start, starting_at, start_index\n /\\bfrom\\b/i,\n];\n\nexport const GENERIC_LIMIT_PARAM_REGEXES: RegExp[] = [\n /\\blimit\\b/i,\n /\\bcount\\b/i,\n /\\b(?:page_?)?size\\b/i, // e.g., size, page_size, pagesize\n /\\bmax_results\\b/i,\n /\\bnum_results\\b/i,\n /\\bshow\\b/i, // Can sometimes mean limit\n /\\bper_?page\\b/i, // e.g., per_page, perpage\n /\\bper-page\\b/i,\n /\\btake\\b/i,\n];\n\nexport const PAGE_NUMBER_REGEXES: RegExp[] = [\n /^page$/i, // Exact match for \"page\"\n /^p$/i, // Exact match for \"p\" (common shorthand)\n /\\bpage_?(?:number|num|idx|index)\\b/i, // e.g., page_number, pageNumber, page_num, page_idx\n];\n\n// Regexes for parameters indicating page size (when used with page number)\nexport const PAGE_SIZE_REGEXES: RegExp[] = [\n /\\bpage_?size\\b/i, // e.g., page_size, pagesize\n /^size$/i, // Exact \"size\"\n // /\\bsize\\b/i, // Broader \"size\" - can be ambiguous, prefer more specific ones first\n /\\blimit\\b/i, // Limit is often used for page size\n /\\bcount\\b/i, // Count can also be used for page size\n /\\bper_?page\\b/i, // e.g., per_page, perpage\n /\\bper-page\\b/i,\n /\\bnum_?(?:items|records|results)\\b/i, // e.g., num_items, numitems\n /\\bresults_?per_?page\\b/i,\n];\n\n// Regexes for parameters indicating a cursor\nexport const CURSOR_REGEXES: RegExp[] = [\n /\\bcursor\\b/i,\n /\\bafter(?:_?cursor)?\\b/i, // e.g., after, after_cursor\n /\\bbefore(?:_?cursor)?\\b/i, // e.g., before, before_cursor\n /\\b(next|prev|previous)_?(?:page_?)?token\\b/i, // e.g., next_page_token, nextPageToken, prev_token\n /\\b(next|prev|previous)_?cursor\\b/i, // e.g., next_cursor, previousCursor\n /\\bcontinuation(?:_?token)?\\b/i, // e.g., continuation, continuation_token\n /\\bpage(?:_?(token|id))?\\b/i, // e.g., after, after_cursor\n\n /\\bstart_?(?:key|cursor|token|after)\\b/i, // e.g., start_key, startCursor, startToken, startAfter\n];\n\n// Regexes for parameters indicating a limit when used with cursors\nexport const CURSOR_LIMIT_REGEXES: RegExp[] = [\n /\\blimit\\b/i,\n /\\bcount\\b/i,\n /\\bsize\\b/i, // General size\n /\\bfirst\\b/i, // Common in Relay-style cursor pagination (forward pagination)\n /\\blast\\b/i, // Common in Relay-style cursor pagination (backward pagination)\n /\\bpage_?size\\b/i, // Sometimes page_size is used with cursors\n /\\bnum_?(?:items|records|results)\\b/i, // e.g., num_items\n /\\bmax_?items\\b/i,\n /\\btake\\b/i,\n];\n\n// --- Helper Function ---\nfunction findParamAndKeyword(\n queryParams: { name: string }[],\n regexes: RegExp[],\n excludeParamName?: string,\n) {\n for (const param of queryParams) {\n if (param.name === excludeParamName) {\n continue;\n }\n for (const regex of regexes) {\n const match = param.name.match(regex);\n if (match) {\n return { param, keyword: match[0] }; // match[0] is the actual matched substring\n }\n }\n }\n return null;\n}\n\nfunction isOffsetPagination(\n operation: TunedOperationObject,\n parameters: { name: string }[],\n): OffsetPaginationResult | null {\n const offsetMatch = findParamAndKeyword(parameters, OFFSET_PARAM_REGEXES);\n if (!offsetMatch) return null;\n\n const limitMatch = findParamAndKeyword(\n parameters,\n GENERIC_LIMIT_PARAM_REGEXES,\n offsetMatch.param.name,\n );\n if (!limitMatch) return null;\n\n return {\n type: 'offset',\n offsetParamName: offsetMatch.param.name,\n offsetKeyword: offsetMatch.keyword,\n limitParamName: limitMatch.param.name,\n limitKeyword: limitMatch.keyword,\n };\n}\n\nfunction isPagePagination(\n operation: TunedOperationObject,\n): PagePaginationResult | null {\n const queryParams = operation.parameters\n .filter((p) => p.in === 'query')\n .filter(\n (it) => it.schema && !isRef(it.schema) && it.schema.type === 'integer',\n );\n\n if (queryParams.length < 2) return null;\n\n const pageNoMatch = findParamAndKeyword(queryParams, PAGE_NUMBER_REGEXES);\n if (!pageNoMatch) return null;\n\n const pageSizeMatch = findParamAndKeyword(\n queryParams,\n PAGE_SIZE_REGEXES,\n pageNoMatch.param.name,\n );\n if (!pageSizeMatch) return null;\n\n return {\n type: 'page',\n pageNumberParamName: pageNoMatch.param.name,\n pageNumberKeyword: pageNoMatch.keyword,\n pageSizeParamName: pageSizeMatch.param.name,\n pageSizeKeyword: pageSizeMatch.keyword,\n };\n}\n\nfunction isCursorPagination(\n operation: TunedOperationObject,\n): CursorPaginationResult | null {\n const queryParams = operation.parameters.filter((p) => p.in === 'query');\n if (queryParams.length < 2) return null; // Need at least a cursor and a limit-like param\n\n const cursorMatch = findParamAndKeyword(queryParams, CURSOR_REGEXES);\n if (!cursorMatch) return null;\n\n const limitMatch = findParamAndKeyword(\n queryParams,\n CURSOR_LIMIT_REGEXES,\n cursorMatch.param.name,\n );\n if (!limitMatch) return null;\n\n return {\n type: 'cursor',\n cursorParamName: cursorMatch.param.name,\n cursorKeyword: cursorMatch.keyword,\n limitParamName: limitMatch.param.name,\n limitKeyword: limitMatch.keyword,\n };\n}\n\n/**\n * Guesses the pagination strategy of an OpenAPI operation based on its query parameters.\n * It checks for offset, page-based, and cursor-based pagination in that order.\n *\n * @param operation The OpenAPI operation object.\n * @returns A PaginationGuess object indicating the detected type and relevant parameters.\n */\nexport function guessPagination(\n operation: TunedOperationObject,\n body?: SchemaObject,\n response?: SchemaObject,\n): PaginationGuess {\n const bodyParameters =\n body && body.properties\n ? Object.keys(body.properties).map((it) => ({ name: it }))\n : [];\n const parameters = operation.parameters;\n if (isEmpty(operation.parameters) && isEmpty(bodyParameters)) {\n return { type: 'none', reason: 'no parameters' };\n }\n if (!response) {\n return { type: 'none', reason: 'no response' };\n }\n if (!response.properties) {\n return { type: 'none', reason: 'empty response' };\n }\n const properties = response.properties as SchemasObject;\n\n const itemsKey = getItemsName(properties);\n if (!itemsKey) {\n return { type: 'none', reason: 'no items key' };\n }\n const hasMoreKey = getHasMoreName(excludeKey(properties, itemsKey));\n\n if (!hasMoreKey) {\n return { type: 'none', reason: 'no hasMore key' };\n }\n const pagination =\n isOffsetPagination(operation, [...parameters, ...bodyParameters]) ||\n isPagePagination(operation) ||\n isCursorPagination(operation);\n return pagination\n ? { ...pagination, items: itemsKey, hasMore: hasMoreKey }\n : { type: 'none', reason: 'no pagination' };\n}\n\nfunction excludeKey<T extends Record<string, any>>(\n obj: T,\n key: string,\n): Omit<T, typeof key> {\n const { [key]: _, ...rest } = obj;\n return rest;\n}\n", "import type { SchemaObject, SchemasObject } from 'openapi3-ts/oas31';\nimport pluralize from 'pluralize';\n\nconst PRIMARY_TOP_TIER_KEYWORDS: string[] = [\n 'data',\n 'items',\n 'results',\n 'value',\n];\nconst PRIMARY_OTHER_KEYWORDS: string[] = [\n 'records',\n 'content',\n 'list',\n 'payload',\n 'entities',\n 'collection',\n 'users',\n 'products',\n 'orders',\n 'bookings',\n 'articles',\n 'posts',\n 'documents',\n 'events',\n];\nconst SECONDARY_KEYWORDS: string[] = ['entries', 'rows', 'elements'];\n\nconst PLURAL_DEPRIORITIZE_LIST: string[] = [\n 'status',\n 'success',\n 'address',\n 'details',\n 'properties',\n 'params',\n 'headers',\n 'cookies',\n 'series',\n 'links',\n 'meta',\n 'metadata',\n 'statistics',\n 'settings',\n 'options',\n 'permissions',\n 'credentials',\n 'diagnostics',\n 'warnings',\n 'errors',\n 'actions',\n 'attributes',\n 'categories',\n 'features',\n 'includes',\n 'tags',\n];\n\n// For exact matches (normalized: lowercase, no underscores/hyphens)\nconst HAS_MORE_PRIMARY_POSITIVE_EXACT: string[] = [\n 'hasmore',\n 'hasnext',\n 'hasnextpage',\n 'moreitems',\n 'moreitemsavailable',\n 'nextpage',\n 'nextpageexists',\n 'nextpageavailable',\n 'hasadditionalresults',\n 'moreresultsavailable',\n 'canloadmore',\n 'hasadditional',\n 'additionalitems',\n 'fetchmore',\n];\n\nconst HAS_MORE_SECONDARY_POSITIVE_EXACT: string[] = ['more', 'next'];\n\nconst HAS_MORE_PRIMARY_INVERTED_EXACT: string[] = [\n 'islast',\n 'lastpage',\n 'endofresults',\n 'endoflist',\n 'nomoreitems',\n 'nomoredata',\n 'allitemsloaded',\n 'iscomplete',\n 'completed',\n];\n\n// For regex-based sub-phrase matching (tested against original propName, case-insensitive)\n// These regexes look for meaningful phrases, often using word boundaries (\\b)\n// and allowing for optional underscores.\nconst HAS_MORE_POSITIVE_REGEX_PATTERNS: string[] = [\n '\\\\bhas_?more\\\\b',\n '\\\\bhas_?next\\\\b', // e.g., itemsHasNext, items_has_next\n '\\\\bmore_?items\\\\b',\n '\\\\bnext_?page\\\\b', // e.g., userNextPageFlag\n '\\\\badditional\\\\b', // e.g., hasAdditionalData, additional_results_exist\n '\\\\bcontinuation\\\\b', // e.g., continuationAvailable, has_continuation_token\n '\\\\bmore_?results\\\\b',\n '\\\\bpage_?available\\\\b',\n '\\\\bnext(?:_?(page))?\\\\b',\n];\nconst COMPILED_HAS_MORE_POSITIVE_REGEXES: RegExp[] =\n HAS_MORE_POSITIVE_REGEX_PATTERNS.map((p) => new RegExp(p, 'i'));\n\nconst HAS_MORE_INVERTED_REGEX_PATTERNS: string[] = [\n '\\\\bis_?last\\\\b', // e.g., pageIsLast\n '\\\\blast_?page\\\\b', // e.g., resultsAreLastPage\n '\\\\bend_?of_?(data|results|list|items|stream)\\\\b',\n '\\\\bno_?more_?(items|data|results)?\\\\b',\n '\\\\ball_?(items_?)?loaded\\\\b',\n '\\\\bis_?complete\\\\b',\n];\nconst COMPILED_HAS_MORE_INVERTED_REGEXES: RegExp[] =\n HAS_MORE_INVERTED_REGEX_PATTERNS.map((p) => new RegExp(p, 'i'));\n\n/**\n * Tries to guess the name of the property that holds the main list of items\n * within an object schema using a series of heuristics.\n *\n * @param schema The OpenAPI SchemaObject, expected to be of type 'object'.\n * @returns The name of the most likely property containing the items array,\n * or null if no array properties are found in the schema.\n */\nexport function getItemsName(\n properties: Record<string, SchemaObject>,\n): string | null {\n const arrayPropertyNames: string[] = [];\n for (const propName in properties) {\n if (propName in properties) {\n const propSchema = properties[propName] as SchemaObject;\n if (propSchema && propSchema.type === 'array') {\n arrayPropertyNames.push(propName);\n }\n }\n }\n\n // Heuristic 0: No array properties at all.\n if (arrayPropertyNames.length === 0) {\n return null;\n }\n\n // Heuristic 1: Exactly one array property. This is the strongest signal.\n if (arrayPropertyNames.length === 1) {\n return arrayPropertyNames[0];\n }\n\n // Multiple array properties exist. Apply ranked heuristics:\n let bestCandidate: string | null = null;\n let candidateRank = Infinity; // Lower is better\n\n const updateCandidate = (propName: string, rank: number) => {\n if (rank < candidateRank) {\n bestCandidate = propName;\n candidateRank = rank;\n }\n };\n\n for (const propName of arrayPropertyNames) {\n const lowerPropName = propName.toLowerCase();\n\n // Heuristic 2: Top-tier primary keywords (e.g., \"data\", \"items\")\n if (PRIMARY_TOP_TIER_KEYWORDS.includes(lowerPropName)) {\n updateCandidate(propName, 2);\n continue; // Move to next property, this is a strong match for this prop\n }\n\n // Heuristic 3: Other primary keywords\n if (candidateRank > 3 && PRIMARY_OTHER_KEYWORDS.includes(lowerPropName)) {\n updateCandidate(propName, 3);\n continue;\n }\n\n // Heuristic 4: Secondary keywords\n if (candidateRank > 4 && SECONDARY_KEYWORDS.includes(lowerPropName)) {\n updateCandidate(propName, 4);\n continue;\n }\n\n // Heuristic 5: Pluralized name, not on the deprioritize list\n if (\n candidateRank > 5 &&\n pluralize.isPlural(propName) &&\n !PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)\n ) {\n updateCandidate(propName, 5);\n continue;\n }\n\n // Heuristic 6: Pluralized name, IS on the deprioritize list (less preferred plural)\n if (\n candidateRank > 6 &&\n pluralize.isPlural(propName) &&\n PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)\n ) {\n updateCandidate(propName, 6);\n continue;\n }\n }\n\n // If any of the above heuristics found a candidate, return it.\n if (bestCandidate) {\n return bestCandidate;\n }\n\n // Heuristic 7: Fallback - If no keywords or clear plurals,\n // and multiple arrays exist, return the first array property encountered.\n // This ensures we always return a name if arrays are present.\n return arrayPropertyNames[0];\n}\n\nfunction guess(properties: Record<string, SchemaObject>) {\n const booleanPropertyNames: string[] = [];\n for (const propName in properties) {\n if (Object.prototype.hasOwnProperty.call(properties, propName)) {\n const propSchema = properties[propName] as SchemaObject;\n if (\n (propSchema && propSchema.type === 'boolean') ||\n propSchema.type === 'integer'\n ) {\n booleanPropertyNames.push(propName);\n }\n }\n }\n\n if (booleanPropertyNames.length === 0) {\n return null;\n }\n\n if (booleanPropertyNames.length === 1) {\n return booleanPropertyNames[0];\n }\n\n let bestCandidate: string | null = null;\n let candidateRank = Infinity;\n\n const updateCandidate = (propName: string, rank: number) => {\n if (rank < candidateRank) {\n bestCandidate = propName;\n candidateRank = rank;\n }\n };\n\n for (const propName of booleanPropertyNames) {\n const normalizedForExactMatch = propName.toLowerCase().replace(/[-_]/g, '');\n let currentPropRank = Infinity;\n\n // Rank 1: Primary Exact Positive Match\n if (HAS_MORE_PRIMARY_POSITIVE_EXACT.includes(normalizedForExactMatch)) {\n currentPropRank = 1;\n }\n // Rank 2: Secondary Exact Positive Match\n else if (\n HAS_MORE_SECONDARY_POSITIVE_EXACT.includes(normalizedForExactMatch)\n ) {\n currentPropRank = 2;\n }\n // Rank 3: Positive Regex Match (sub-phrase)\n else {\n let foundPositiveRegex = false;\n for (const regex of COMPILED_HAS_MORE_POSITIVE_REGEXES) {\n if (regex.test(propName)) {\n // Test against original propName\n currentPropRank = 3;\n foundPositiveRegex = true;\n break;\n }\n }\n\n // Only proceed to inverted matches if no positive match of any kind (Rank 1, 2, or 3) was found\n if (!foundPositiveRegex) {\n // Rank 4: Primary Exact Inverted Match\n if (HAS_MORE_PRIMARY_INVERTED_EXACT.includes(normalizedForExactMatch)) {\n currentPropRank = 4;\n }\n // Rank 5: Inverted Regex Match (sub-phrase)\n else {\n for (const regex of COMPILED_HAS_MORE_INVERTED_REGEXES) {\n if (regex.test(propName)) {\n // Test against original propName\n currentPropRank = 5;\n break;\n }\n }\n }\n }\n }\n\n updateCandidate(propName, currentPropRank);\n }\n return bestCandidate;\n}\n\n/**\n * Tries to guess the name of a boolean property that indicates if there are more items\n * to fetch (e.g., for pagination).\n *\n * @param schema The OpenAPI SchemaObject, expected to be of type 'object'.\n * @returns The name of the most likely boolean property indicating \"has more\",\n * or null if no suitable boolean property is found.\n */\nexport function getHasMoreName(properties: SchemasObject): string | null {\n const rootGuess = guess(properties);\n if (rootGuess) {\n return rootGuess;\n }\n for (const propName in properties) {\n const propSchema = properties[propName];\n if (propSchema.type === 'object' && propSchema.properties) {\n const nested = getHasMoreName(propSchema.properties as SchemasObject);\n if (nested) {\n return propName + '.' + nested;\n }\n }\n }\n return null;\n}\n", "import type {\n OpenAPIObject,\n ReferenceObject,\n RequestBodyObject,\n SchemaObject,\n} from 'openapi3-ts/oas31';\n\nimport { followRef, isRef } from '@sdk-it/core';\n\n/**\n * PropEmitter handles converting OpenAPI schemas to Markdown documentation\n * Similar structure to ZodDeserializer but for generating markdown props documentation\n */\nexport class PropEmitter {\n #spec: OpenAPIObject;\n\n constructor(spec: OpenAPIObject) {\n this.#spec = spec;\n }\n\n /**\n * Handle objects (properties)\n */\n #object(schema: SchemaObject): string[] {\n const lines: string[] = [];\n const properties = schema.properties || {};\n\n if (Object.keys(properties).length > 0) {\n lines.push(`**Properties:**`);\n\n for (const [propName, propSchema] of Object.entries(properties)) {\n const isRequired = (schema.required ?? []).includes(propName);\n lines.push(...this.#property(propName, propSchema, isRequired));\n }\n }\n\n // Handle additionalProperties\n if (schema.additionalProperties) {\n lines.push(`**Additional Properties:**`);\n if (typeof schema.additionalProperties === 'boolean') {\n lines.push(`- Allowed: ${schema.additionalProperties}`);\n } else {\n // Indent the schema documentation for additional properties\n lines.push(\n ...this.handle(schema.additionalProperties).map((l) => ` ${l}`),\n );\n }\n }\n\n return lines;\n }\n\n /**\n * Format a property with its type and description\n */\n #property(\n name: string,\n schema: SchemaObject | ReferenceObject,\n required: boolean,\n ): string[] {\n // get full docs and extract the type line\n const docs = this.handle(schema);\n const rawType = docs[0]\n .replace('**Type:** ', '')\n .replace(' (nullable)', '|null');\n\n // detect default if present on the schema\n const defaultVal =\n !isRef(schema) && (schema as SchemaObject).default !== undefined\n ? ` default: ${JSON.stringify((schema as SchemaObject).default)}`\n : '';\n\n // build summary line\n const reqMark = required ? ' required' : '';\n const summary = `- \\`${name}\\` ${rawType}${reqMark}${defaultVal}:`;\n\n // assemble final lines (skip the type and any default in details)\n const detailLines = docs\n .slice(1)\n .filter((l) => !l.startsWith('**Default:**'))\n .map((l) => ` ${l}`);\n\n return [summary, ...detailLines];\n }\n\n /**\n * Handle array schemas\n */\n #array(schema: SchemaObject): string[] {\n const lines: string[] = [];\n lines.push(`**Array items:**`);\n\n if (schema.items) {\n // Get documentation for the items schema\n const itemDocs = this.handle(schema.items);\n // Indent item documentation\n lines.push(...itemDocs.map((line) => ` ${line}`));\n } else {\n lines.push(` **Type:** \\`unknown\\``); // Array of unknown items\n }\n // Add array constraints\n if (schema.minItems !== undefined)\n lines.push(`- Minimum items: ${schema.minItems}`);\n if (schema.maxItems !== undefined)\n lines.push(`- Maximum items: ${schema.maxItems}`);\n if (schema.uniqueItems) lines.push(`- Items must be unique.`);\n\n return lines;\n }\n\n #ref($ref: string): string[] {\n const schemaName = $ref.split('/').pop() || 'object';\n const resolved = followRef<SchemaObject>(this.#spec, $ref);\n // Link to the schema definition (assuming heading anchors are generated elsewhere)\n const lines = [\n `**Type:** [\\`${schemaName}\\`](#${schemaName.toLowerCase()})`,\n ];\n if (resolved.description) {\n lines.push(resolved.description);\n }\n // Avoid deep recursion by default, just link and show description.\n // If more detail is needed, the linked definition should provide it.\n return lines;\n }\n\n #allOf(schemas: (SchemaObject | ReferenceObject)[]): string[] {\n const lines = ['**All of (Intersection):**'];\n schemas.forEach((subSchema, index) => {\n lines.push(`- **Constraint ${index + 1}:**`);\n const subLines = this.handle(subSchema);\n lines.push(...subLines.map((l) => ` ${l}`)); // Indent sub-schema docs\n });\n return lines;\n }\n\n #anyOf(schemas: (SchemaObject | ReferenceObject)[]): string[] {\n const lines = ['**Any of (Union):**'];\n schemas.forEach((subSchema, index) => {\n lines.push(`- **Option ${index + 1}:**`);\n const subLines = this.handle(subSchema);\n lines.push(...subLines.map((l) => ` ${l}`));\n });\n return lines;\n }\n\n #oneOf(schemas: (SchemaObject | ReferenceObject)[]): string[] {\n const lines = ['**One of (Exclusive Union):**'];\n schemas.forEach((subSchema, index) => {\n lines.push(`- **Option ${index + 1}:**`);\n const subLines = this.handle(subSchema);\n lines.push(...subLines.map((l) => ` ${l}`));\n });\n return lines;\n }\n\n #enum(schema: SchemaObject): string[] {\n const lines = [`**Type:** \\`${schema.type || 'unknown'}\\` (enum)`];\n if (schema.description) lines.push(schema.description);\n lines.push('**Allowed values:**');\n lines.push(\n ...(schema.enum || []).map((val) => `- \\`${JSON.stringify(val)}\\``),\n );\n if (schema.default !== undefined) {\n lines.push(`**Default:** \\`${JSON.stringify(schema.default)}\\``);\n }\n return lines;\n }\n\n #normal(type: string, schema: SchemaObject, nullable: boolean): string[] {\n const lines: string[] = [];\n const nullableSuffix = nullable ? ' (nullable)' : '';\n const description = schema.description ? [schema.description] : [];\n\n switch (type) {\n case 'string':\n lines.push(\n `**Type:** \\`string\\`${schema.format ? ` (format: ${schema.format})` : ''}${nullableSuffix}`,\n );\n lines.push(...description);\n if (schema.minLength !== undefined)\n lines.push(`- Minimum length: ${schema.minLength}`);\n if (schema.maxLength !== undefined)\n lines.push(`- Maximum length: ${schema.maxLength}`);\n if (schema.pattern !== undefined)\n lines.push(`- Pattern: \\`${schema.pattern}\\``);\n break;\n case 'number':\n case 'integer':\n lines.push(\n `**Type:** \\`${type}\\`${schema.format ? ` (format: ${schema.format})` : ''}${nullableSuffix}`,\n );\n lines.push(...description);\n // Add number constraints (OpenAPI 3.1)\n if (schema.minimum !== undefined) {\n // Check if exclusiveMinimum is a number (OAS 3.1)\n const exclusiveMin = typeof schema.exclusiveMinimum === 'number';\n lines.push(\n `- Minimum: ${schema.minimum}${exclusiveMin ? ' (exclusive)' : ''}`,\n );\n if (exclusiveMin) {\n lines.push(\n `- Must be strictly greater than: ${schema.exclusiveMinimum}`,\n );\n }\n } else if (typeof schema.exclusiveMinimum === 'number') {\n lines.push(\n `- Must be strictly greater than: ${schema.exclusiveMinimum}`,\n );\n }\n\n if (schema.maximum !== undefined) {\n // Check if exclusiveMaximum is a number (OAS 3.1)\n const exclusiveMax = typeof schema.exclusiveMaximum === 'number';\n lines.push(\n `- Maximum: ${schema.maximum}${exclusiveMax ? ' (exclusive)' : ''}`,\n );\n if (exclusiveMax) {\n lines.push(\n `- Must be strictly less than: ${schema.exclusiveMaximum}`,\n );\n }\n } else if (typeof schema.exclusiveMaximum === 'number') {\n lines.push(\n `- Must be strictly less than: ${schema.exclusiveMaximum}`,\n );\n }\n if (schema.multipleOf !== undefined)\n lines.push(`- Must be a multiple of: ${schema.multipleOf}`);\n break;\n case 'boolean':\n lines.push(`**Type:** \\`boolean\\`${nullableSuffix}`);\n lines.push(...description);\n break;\n case 'object':\n lines.push(`**Type:** \\`object\\`${nullableSuffix}`);\n lines.push(...description);\n lines.push(...this.#object(schema));\n break;\n case 'array':\n lines.push(`**Type:** \\`array\\`${nullableSuffix}`);\n lines.push(...description);\n lines.push(...this.#array(schema));\n break;\n case 'null':\n lines.push(`**Type:** \\`null\\``);\n lines.push(...description);\n break;\n default:\n lines.push(`**Type:** \\`${type}\\`${nullableSuffix}`);\n lines.push(...description);\n }\n if (schema.default !== undefined) {\n lines.push(`**Default:** \\`${JSON.stringify(schema.default)}\\``);\n }\n return lines.filter((l) => l); // Filter out empty description lines\n }\n\n /**\n * Handle schemas by resolving references and delegating to appropriate handler\n */\n public handle(schemaOrRef: SchemaObject | ReferenceObject): string[] {\n if (isRef(schemaOrRef)) {\n return this.#ref(schemaOrRef.$ref);\n }\n\n const schema = schemaOrRef;\n\n // Handle composition keywords first\n if (schema.allOf && Array.isArray(schema.allOf)) {\n return this.#allOf(schema.allOf);\n }\n if (schema.anyOf && Array.isArray(schema.anyOf)) {\n return this.#anyOf(schema.anyOf);\n }\n if (schema.oneOf && Array.isArray(schema.oneOf)) {\n return this.#oneOf(schema.oneOf);\n }\n\n // Handle enums\n if (schema.enum && Array.isArray(schema.enum)) {\n return this.#enum(schema);\n }\n\n // Determine type(s) and nullability\n let types = Array.isArray(schema.type)\n ? schema.type\n : schema.type\n ? [schema.type]\n : [];\n let nullable = false; // Default to false\n\n if (types.includes('null')) {\n nullable = true;\n types = types.filter((t) => t !== 'null');\n }\n\n // Infer type if not explicitly set\n if (types.length === 0) {\n if (schema.properties || schema.additionalProperties) {\n types = ['object'];\n } else if (schema.items) {\n types = ['array'];\n }\n // Add other inferences if needed (e.g., based on format)\n }\n\n // If still no type, treat as unknown or any\n if (types.length === 0) {\n const lines = ['**Type:** `unknown`'];\n if (schema.description) lines.push(schema.description);\n if (schema.default !== undefined)\n lines.push(`**Default:** \\`${JSON.stringify(schema.default)}\\``);\n return lines;\n }\n\n // Handle single type (potentially nullable)\n if (types.length === 1) {\n return this.#normal(types[0], schema, nullable);\n }\n\n // Handle union of multiple non-null types (potentially nullable overall)\n const typeString = types.join(' | ');\n const nullableSuffix = nullable ? ' (nullable)' : '';\n const lines = [`**Type:** \\`${typeString}\\`${nullableSuffix}`];\n if (schema.description) lines.push(schema.description);\n if (schema.default !== undefined)\n lines.push(`**Default:** \\`${JSON.stringify(schema.default)}\\``);\n return lines;\n }\n\n /**\n * Process a request body and return markdown documentation\n */\n requestBody(requestBody?: RequestBodyObject): string[] {\n if (!requestBody) return [];\n\n const lines: string[] = [];\n lines.push(`##### Request Body`);\n\n if (requestBody.description) {\n lines.push(requestBody.description);\n }\n if (requestBody.required) {\n lines.push(`*This request body is required.*`);\n }\n\n if (requestBody.content) {\n for (const [contentType, mediaType] of Object.entries(\n requestBody.content,\n )) {\n lines.push(`**Content Type:** \\`${contentType}\\``);\n\n if (mediaType.schema) {\n // Use the main handle method here\n const schemaDocs = this.handle(mediaType.schema);\n lines.push(...schemaDocs); // Add schema docs directly\n }\n }\n }\n\n return lines;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["isEmpty", "isRef", "followRef", "isRef", "lines", "isEmpty"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OpenAPIObject, ReferenceObject, RequestBodyObject, SchemaObject } from 'openapi3-ts/oas31';
|
|
2
|
+
/**
|
|
3
|
+
* PropEmitter handles converting OpenAPI schemas to Markdown documentation
|
|
4
|
+
* Similar structure to ZodDeserializer but for generating markdown props documentation
|
|
5
|
+
*/
|
|
6
|
+
export declare class PropEmitter {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(spec: OpenAPIObject);
|
|
9
|
+
/**
|
|
10
|
+
* Handle schemas by resolving references and delegating to appropriate handler
|
|
11
|
+
*/
|
|
12
|
+
handle(schemaOrRef: SchemaObject | ReferenceObject): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Process a request body and return markdown documentation
|
|
15
|
+
*/
|
|
16
|
+
requestBody(requestBody?: RequestBodyObject): string[];
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=prop.emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop.emitter.d.ts","sourceRoot":"","sources":["../../src/lib/prop.emitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,YAAY,EACb,MAAM,mBAAmB,CAAC;AAI3B;;;GAGG;AACH,qBAAa,WAAW;;gBAGV,IAAI,EAAE,aAAa;IAiP/B;;OAEG;IACI,MAAM,CAAC,WAAW,EAAE,YAAY,GAAG,eAAe,GAAG,MAAM,EAAE;IAsEpE;;OAEG;IACH,WAAW,CAAC,WAAW,CAAC,EAAE,iBAAiB,GAAG,MAAM,EAAE;CA6BvD"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { OpenAPIObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import { type OperationEntry, type TunedOperationObject } from '@sdk-it/spec/operation.js';
|
|
3
|
+
export declare function toReadme(spec: OpenAPIObject, generators: {
|
|
4
|
+
generateSnippet: (entry: OperationEntry, operation: TunedOperationObject) => string;
|
|
5
|
+
}): string;
|
|
6
|
+
//# sourceMappingURL=readme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readme.d.ts","sourceRoot":"","sources":["../../src/lib/readme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,oBAAoB,EAE1B,MAAM,2BAA2B,CAAC;AAInC,wBAAgB,QAAQ,CACtB,IAAI,EAAE,aAAa,EACnB,UAAU,EAAE;IACV,eAAe,EAAE,CACf,KAAK,EAAE,cAAc,EACrB,SAAS,EAAE,oBAAoB,KAC5B,MAAM,CAAC;CACb,UAkDF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sdk-it/readme",
|
|
3
|
+
"version": "0.21.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
"./package.json": "./package.json",
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"!**/*.tsbuildinfo"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"openapi3-ts": "4.4.0",
|
|
25
|
+
"@sdk-it/core": "0.21.0",
|
|
26
|
+
"@sdk-it/spec": "0.21.0"
|
|
27
|
+
}
|
|
28
|
+
}
|