@oaspect/core 0.1.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 ADDED
@@ -0,0 +1,2585 @@
1
+ // src/refs.ts
2
+ function resolvePointer(spec, ref) {
3
+ if (typeof ref !== "string" || !ref.startsWith("#/")) return void 0;
4
+ return ref.slice(2).split("/").map((part) => part.replace(/~1/g, "/").replace(/~0/g, "~")).reduce((node, key) => node?.[key], spec);
5
+ }
6
+ function refName(ref) {
7
+ return ref.split("/").pop() ?? ref;
8
+ }
9
+ function deref(spec, node) {
10
+ let ref;
11
+ let hops = 0;
12
+ while (node?.$ref && hops++ < 32) {
13
+ ref = node.$ref;
14
+ node = resolvePointer(spec, ref);
15
+ }
16
+ return { node: node ?? {}, ref };
17
+ }
18
+
19
+ // src/schema.ts
20
+ function mergeInto(target, source) {
21
+ for (const [key, value] of Object.entries(source)) {
22
+ if (key === "properties") {
23
+ target.properties = { ...target.properties, ...value };
24
+ } else if (key === "required") {
25
+ target.required = [.../* @__PURE__ */ new Set([...target.required ?? [], ...value])];
26
+ } else {
27
+ target[key] = value;
28
+ }
29
+ }
30
+ }
31
+ function resolveSchema(spec, input) {
32
+ const { node, ref } = deref(spec, input);
33
+ let schema = node;
34
+ let name = ref ? refName(ref) : void 0;
35
+ if (Array.isArray(schema.allOf)) {
36
+ const { allOf, ...rest } = schema;
37
+ const merged = {};
38
+ for (const part of allOf) {
39
+ mergeInto(merged, resolveSchema(spec, part).schema);
40
+ }
41
+ mergeInto(merged, rest);
42
+ if (!name && allOf.length === 1 && allOf[0].$ref) {
43
+ name = refName(allOf[0].$ref);
44
+ }
45
+ schema = merged;
46
+ }
47
+ return { schema, name };
48
+ }
49
+ function inferType(schema) {
50
+ if (schema.type) return Array.isArray(schema.type) ? schema.type.join(" | ") : schema.type;
51
+ if (schema.properties || schema.additionalProperties) return "object";
52
+ if (schema.items) return "array";
53
+ if (schema.oneOf) return "oneOf";
54
+ if (schema.anyOf) return "anyOf";
55
+ return "any";
56
+ }
57
+ function typeLabel(spec, schema, name) {
58
+ const type = inferType(schema);
59
+ if (type === "array" && schema.items) {
60
+ const item = resolveSchema(spec, schema.items);
61
+ return `array<${item.name ?? typeLabel(spec, item.schema)}>`;
62
+ }
63
+ if (type === "object" && name) return name;
64
+ if (schema.format) return `${type}<${schema.format}>`;
65
+ return type;
66
+ }
67
+ function constraintsOf(schema) {
68
+ const list = [];
69
+ const add = (label, value) => value !== void 0 && list.push(`${label} ${value}`);
70
+ add("min length", schema.minLength);
71
+ add("max length", schema.maxLength);
72
+ add(schema.exclusiveMinimum === true ? ">" : "\u2265", schema.minimum);
73
+ add(schema.exclusiveMaximum === true ? "<" : "\u2264", schema.maximum);
74
+ if (typeof schema.exclusiveMinimum === "number") add(">", schema.exclusiveMinimum);
75
+ if (typeof schema.exclusiveMaximum === "number") add("<", schema.exclusiveMaximum);
76
+ add("multiple of", schema.multipleOf);
77
+ add("min items", schema.minItems);
78
+ add("max items", schema.maxItems);
79
+ if (schema.uniqueItems) list.push("unique items");
80
+ return list;
81
+ }
82
+ function childrenOf(spec, schema) {
83
+ const type = inferType(schema);
84
+ if (type === "array" && schema.items) {
85
+ const item = resolveSchema(spec, schema.items);
86
+ return childrenOf(spec, item.schema) ? { kind: "items", ...item } : null;
87
+ }
88
+ if (schema.oneOf || schema.anyOf) {
89
+ const variants = (schema.oneOf ?? schema.anyOf).map((variant) => resolveSchema(spec, variant));
90
+ return { kind: schema.oneOf ? "oneOf" : "anyOf", variants };
91
+ }
92
+ if (schema.properties && Object.keys(schema.properties).length > 0) {
93
+ return { kind: "properties" };
94
+ }
95
+ if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
96
+ const value = resolveSchema(spec, schema.additionalProperties);
97
+ return childrenOf(spec, value.schema) ? { kind: "map", ...value } : null;
98
+ }
99
+ return null;
100
+ }
101
+
102
+ // src/example.ts
103
+ var STRING_FORMATS = {
104
+ "date-time": "2026-01-01T09:00:00Z",
105
+ date: "2026-01-01",
106
+ time: "09:00:00",
107
+ email: "user@example.com",
108
+ uri: "https://example.com",
109
+ url: "https://example.com",
110
+ uuid: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
111
+ ipv4: "192.168.0.1",
112
+ ipv6: "::1",
113
+ password: "********",
114
+ byte: "U3dhZ2dlcg=="
115
+ };
116
+ function exampleFromSchema(spec, input, seen = /* @__PURE__ */ new Set(), depth = 0) {
117
+ if (!input || depth > 8) return void 0;
118
+ const { schema, name } = resolveSchema(spec, input);
119
+ if (name && seen.has(name)) return {};
120
+ const nextSeen = name ? new Set(seen).add(name) : seen;
121
+ if (schema.example !== void 0) return schema.example;
122
+ if (Array.isArray(schema.examples) && schema.examples.length) return schema.examples[0];
123
+ if (schema.default !== void 0) return schema.default;
124
+ if (Array.isArray(schema.enum) && schema.enum.length) return schema.enum[0];
125
+ if (schema.const !== void 0) return schema.const;
126
+ const variants = schema.oneOf ?? schema.anyOf;
127
+ if (variants?.length) return exampleFromSchema(spec, variants[0], nextSeen, depth + 1);
128
+ switch (inferType(schema)) {
129
+ case "object": {
130
+ const result = {};
131
+ for (const [key, value] of Object.entries(schema.properties ?? {})) {
132
+ if (resolveSchema(spec, value).schema.writeOnly) continue;
133
+ result[key] = exampleFromSchema(spec, value, nextSeen, depth + 1);
134
+ }
135
+ if (!schema.properties && typeof schema.additionalProperties === "object") {
136
+ result.key = exampleFromSchema(spec, schema.additionalProperties, nextSeen, depth + 1);
137
+ }
138
+ return result;
139
+ }
140
+ case "array":
141
+ return schema.items ? [exampleFromSchema(spec, schema.items, nextSeen, depth + 1)] : [];
142
+ case "integer":
143
+ return schema.minimum ?? 0;
144
+ case "number":
145
+ return schema.minimum ?? 0;
146
+ case "boolean":
147
+ return true;
148
+ case "string":
149
+ return STRING_FORMATS[schema.format] ?? "string";
150
+ default:
151
+ return null;
152
+ }
153
+ }
154
+ function mediaExample(spec, media) {
155
+ if (!media) return void 0;
156
+ if (media.example !== void 0) return media.example;
157
+ const named = media.examples && Object.values(media.examples)[0];
158
+ if (named) return deref(spec, named).node.value;
159
+ return exampleFromSchema(spec, media.schema);
160
+ }
161
+ function mediaExamples(spec, media) {
162
+ if (!media?.examples) return [];
163
+ return Object.entries(media.examples).map(([key, value]) => {
164
+ const { node } = deref(spec, value);
165
+ return { key, summary: node.summary ?? key, value: node.value };
166
+ });
167
+ }
168
+
169
+ // src/model.ts
170
+ var HTTP_METHODS = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
171
+ function slugify(value) {
172
+ return String(value).toLowerCase().replace(/[{}]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
173
+ }
174
+ var tagAnchor = (name) => `tag/${slugify(name)}`;
175
+ var modelAnchor = (name) => `model/${name}`;
176
+ function operationAnchor(method, path2, operationId) {
177
+ return `operation/${operationId ? slugify(operationId) : `${method}-${slugify(path2)}`}`;
178
+ }
179
+ function mergeParameters(spec, pathParams = [], opParams = []) {
180
+ const byKey = /* @__PURE__ */ new Map();
181
+ for (const raw of [...pathParams, ...opParams]) {
182
+ const { node } = deref(spec, raw);
183
+ if (node.name) byKey.set(`${node.in}:${node.name}`, node);
184
+ }
185
+ return [...byKey.values()];
186
+ }
187
+ function resolveLinks(spec, links = {}) {
188
+ return Object.entries(links).map(([name, raw]) => {
189
+ const { node } = deref(spec, raw);
190
+ return {
191
+ name,
192
+ operationId: node.operationId,
193
+ operationRef: node.operationRef,
194
+ parameters: node.parameters ?? {},
195
+ requestBody: node.requestBody,
196
+ description: node.description ?? ""
197
+ };
198
+ });
199
+ }
200
+ function resolveResponses(spec, responses = {}) {
201
+ return Object.entries(responses).map(([status, raw]) => {
202
+ const { node } = deref(spec, raw);
203
+ return {
204
+ status,
205
+ description: node.description ?? "",
206
+ "x-i18n": node["x-i18n"],
207
+ content: node.content ?? {},
208
+ headers: Object.fromEntries(
209
+ Object.entries(node.headers ?? {}).map(([key, value]) => [key, deref(spec, value).node])
210
+ ),
211
+ links: resolveLinks(spec, node.links)
212
+ };
213
+ });
214
+ }
215
+ function buildOperation(spec, method, path2, pathItem, op, kind, anchorPrefix) {
216
+ const requestBody = op.requestBody ? deref(spec, op.requestBody).node : null;
217
+ const anchor = kind === "operation" ? operationAnchor(method, path2, op.operationId) : `${anchorPrefix}/${slugify(op.operationId ?? `${path2}-${method}`)}`;
218
+ return {
219
+ anchor,
220
+ kind,
221
+ method,
222
+ path: path2,
223
+ summary: op.summary ?? "",
224
+ description: op.description ?? "",
225
+ "x-i18n": op["x-i18n"],
226
+ operationId: op.operationId,
227
+ deprecated: Boolean(op.deprecated),
228
+ tags: op.tags?.length ? op.tags : ["Default"],
229
+ parameters: mergeParameters(spec, pathItem.parameters, op.parameters),
230
+ requestBody,
231
+ responses: resolveResponses(spec, op.responses),
232
+ callbacks: kind === "callback" ? [] : resolveCallbacks(spec, op.callbacks, anchor),
233
+ security: op.security ?? spec.security ?? [],
234
+ servers: op.servers ?? pathItem.servers ?? spec.servers ?? []
235
+ };
236
+ }
237
+ function operationsOf(spec, path2, item, kind, anchorPrefix) {
238
+ const pathItem = deref(spec, item).node;
239
+ return HTTP_METHODS.filter((method) => pathItem[method]).map(
240
+ (method) => buildOperation(spec, method, path2, pathItem, pathItem[method], kind, anchorPrefix)
241
+ );
242
+ }
243
+ function resolveCallbacks(spec, callbacks = {}, parentAnchor) {
244
+ return Object.entries(callbacks).map(([name, raw]) => {
245
+ const { node } = deref(spec, raw);
246
+ const operations = Object.entries(node).filter(([expression]) => !expression.startsWith("x-")).flatMap(([expression, item]) => operationsOf(spec, expression, item, "callback", `${parentAnchor}/callback/${slugify(name)}`));
247
+ return { name, operations };
248
+ });
249
+ }
250
+ function buildModel(spec) {
251
+ const tagMeta = new Map((spec.tags ?? []).map((tag) => [tag.name, tag]));
252
+ const groups = new Map([...tagMeta.keys()].map((name) => [name, []]));
253
+ const operations = [];
254
+ for (const [path2, item] of Object.entries(spec.paths ?? {})) {
255
+ for (const operation of operationsOf(spec, path2, item, "operation", "operation")) {
256
+ operations.push(operation);
257
+ for (const tag of operation.tags) {
258
+ if (!groups.has(tag)) groups.set(tag, []);
259
+ groups.get(tag).push(operation);
260
+ }
261
+ }
262
+ }
263
+ const webhooks = Object.entries(spec.webhooks ?? {}).flatMap(
264
+ ([name, item]) => operationsOf(spec, name, item, "webhook", `webhook/${slugify(name)}`)
265
+ );
266
+ const tags = [...groups.entries()].filter(([, list]) => list.length > 0).map(([name, list]) => ({
267
+ name,
268
+ anchor: tagAnchor(name),
269
+ description: tagMeta.get(name)?.description ?? "",
270
+ // Display name translations go under x-i18n.<locale>.name; `name`
271
+ // stays the grouping key operations refer to.
272
+ "x-i18n": tagMeta.get(name)?.["x-i18n"],
273
+ operations: list
274
+ }));
275
+ const schemas = Object.entries(spec.components?.schemas ?? {}).map(([name, schema]) => ({
276
+ name,
277
+ anchor: modelAnchor(name),
278
+ schema
279
+ }));
280
+ return {
281
+ openapi: spec.openapi ?? spec.swagger ?? "",
282
+ info: spec.info ?? {},
283
+ servers: spec.servers?.length ? spec.servers : [{ url: "/" }],
284
+ securitySchemes: spec.components?.securitySchemes ?? {},
285
+ tags,
286
+ operations,
287
+ webhooks,
288
+ schemas
289
+ };
290
+ }
291
+ function serverUrl(server, values = {}) {
292
+ return server.url.replace(/\{([^}]+)\}/g, (match, key) => values[key] || server.variables?.[key]?.default || match);
293
+ }
294
+ function linkTarget(model, link) {
295
+ if (link.operationId) return model.operations.find((operation) => operation.operationId === link.operationId);
296
+ const match = /^#\/paths\/([^/]+)\/(\w+)$/.exec(link.operationRef ?? "");
297
+ if (!match) return void 0;
298
+ const path2 = match[1].replace(/~1/g, "/").replace(/~0/g, "~");
299
+ return model.operations.find((operation) => operation.path === path2 && operation.method === match[2]);
300
+ }
301
+
302
+ // src/request.ts
303
+ function jsonMediaType(content = {}) {
304
+ const types = Object.keys(content);
305
+ return types.find((type) => /json/i.test(type)) ?? types[0];
306
+ }
307
+ function parameterExample(spec, param) {
308
+ if (param.example !== void 0) return param.example;
309
+ const named = param.examples && Object.values(param.examples)[0];
310
+ if (named?.value !== void 0) return named.value;
311
+ return exampleFromSchema(spec, param.schema);
312
+ }
313
+ function defaultValues(spec, operation) {
314
+ const values = { path: {}, query: {}, header: {}, cookie: {} };
315
+ for (const param of operation.parameters) {
316
+ const example = parameterExample(spec, param);
317
+ const include = param.in === "path" || param.required;
318
+ values[param.in] ??= {};
319
+ values[param.in][param.name] = include && example !== void 0 && example !== null ? String(example) : "";
320
+ }
321
+ return values;
322
+ }
323
+ var isMultipart = (contentType) => /^multipart\/form-data/i.test(contentType ?? "");
324
+ var isBinary = (schema) => schema.type === "string" && (schema.format === "binary" || schema.format === "base64" || Boolean(schema.contentMediaType));
325
+ function defaultForm(spec, media) {
326
+ const { schema } = resolveSchema(spec, media?.schema ?? {});
327
+ const example = mediaExample(spec, media) ?? {};
328
+ const fields = [];
329
+ for (const [name, raw] of Object.entries(schema.properties ?? {})) {
330
+ const property = resolveSchema(spec, raw).schema;
331
+ const items = property.type === "array" && property.items ? resolveSchema(spec, property.items).schema : null;
332
+ if (isBinary(property) || items && isBinary(items)) {
333
+ fields.push({ name, file: { name: `${name}.bin`, type: media?.encoding?.[name]?.contentType } });
334
+ continue;
335
+ }
336
+ const value = example[name];
337
+ for (const entry of Array.isArray(value) ? value : [value]) {
338
+ if (entry === void 0 || entry === null) continue;
339
+ fields.push({ name, value: typeof entry === "object" ? JSON.stringify(entry) : String(entry) });
340
+ }
341
+ }
342
+ return fields;
343
+ }
344
+ function defaultBody(spec, operation) {
345
+ const content = operation.requestBody?.content;
346
+ const type = jsonMediaType(content);
347
+ if (!type) return { contentType: null, body: "" };
348
+ if (isMultipart(type)) return { contentType: type, body: "", form: defaultForm(spec, content[type]) };
349
+ const example = mediaExample(spec, content[type]);
350
+ if (example === void 0) return { contentType: type, body: "" };
351
+ return { contentType: type, body: /x-www-form-urlencoded/i.test(type) ? formEncode(example) : JSON.stringify(example, null, 2) };
352
+ }
353
+ function formEncode(value) {
354
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "";
355
+ const params = new URLSearchParams();
356
+ for (const [key, item] of Object.entries(value)) {
357
+ for (const entry of Array.isArray(item) ? item : [item]) {
358
+ if (entry === void 0 || entry === null) continue;
359
+ params.append(key, typeof entry === "object" ? JSON.stringify(entry) : String(entry));
360
+ }
361
+ }
362
+ return params.toString();
363
+ }
364
+ function buildRequest(operation, { server, values, body, form, contentType, headers = {} }) {
365
+ const base = (server ? serverUrl(server) : "").replace(/\/+$/, "");
366
+ const path2 = operation.path.replace(/\{([^}]+)\}/g, (match, key) => {
367
+ const value = values.path?.[key];
368
+ return value ? encodeURIComponent(value) : match;
369
+ });
370
+ const query = new URLSearchParams();
371
+ for (const [key, value] of Object.entries(values.query ?? {})) {
372
+ if (value !== "") query.append(key, value);
373
+ }
374
+ const search = query.toString();
375
+ const allHeaders = { ...headers };
376
+ for (const [key, value] of Object.entries(values.header ?? {})) {
377
+ if (value !== "") allHeaders[key] = value;
378
+ }
379
+ const cookies = Object.entries(values.cookie ?? {}).filter(([, value]) => value !== "").map(([key, value]) => `${key}=${value}`).join("; ");
380
+ if (cookies) allHeaders.Cookie = cookies;
381
+ const canHaveBody = !["get", "head"].includes(operation.method);
382
+ const multipart = canHaveBody && Boolean(form?.length) && isMultipart(contentType);
383
+ const hasBody = !multipart && canHaveBody && Boolean(body);
384
+ if (hasBody && contentType) allHeaders["Content-Type"] = contentType;
385
+ const request = {
386
+ method: operation.method.toUpperCase(),
387
+ url: `${base}${path2}${search ? `?${search.replace(/%5B/g, "[").replace(/%5D/g, "]")}` : ""}`,
388
+ headers: allHeaders,
389
+ body: hasBody ? body : void 0
390
+ };
391
+ if (multipart) request.form = form;
392
+ return request;
393
+ }
394
+
395
+ // src/multipart.ts
396
+ var dq = (value) => JSON.stringify(String(value));
397
+ var sq = (value) => `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
398
+ var shellQuote = (value) => `'${String(value).replace(/'/g, "'\\''")}'`;
399
+ var psQuote = (value) => `'${String(value).replace(/'/g, "''")}'`;
400
+ var dartQuote = (value) => sq(value).replace(/\$/g, "\\$");
401
+ var kotlinQuote = (value) => dq(value).replace(/\$/g, "\\$");
402
+ var indent = (text, prefix) => text.split("\n").join(`
403
+ ${prefix}`);
404
+ var capitalize = (method) => method.charAt(0) + method.slice(1).toLowerCase();
405
+ var path = (field) => `./${field.file.name}`;
406
+ var fileType = (field) => field.file.type ?? "application/octet-stream";
407
+ var files = (form) => form.filter((field) => field.file);
408
+ var texts = (form) => form.filter((field) => !field.file);
409
+ var headerList = (headers) => Object.entries(headers);
410
+ var jsObject = (value, pad) => indent(JSON.stringify(value, null, 2), pad);
411
+ function parseUrl(url) {
412
+ try {
413
+ return new URL(url);
414
+ } catch {
415
+ return new URL(url, "http://localhost");
416
+ }
417
+ }
418
+ var note = (comment, text) => `${comment} ${text}`;
419
+ function curl({ method, url, headers, form = [] }) {
420
+ const parts = [`curl --request ${method}`, `--url ${shellQuote(url)}`];
421
+ for (const [key, value] of headerList(headers)) parts.push(`--header ${shellQuote(`${key}: ${value}`)}`);
422
+ for (const field of form) {
423
+ parts.push(field.file ? `--form ${shellQuote(`${field.name}=@${path(field)}`)}` : `--form-string ${shellQuote(`${field.name}=${field.value ?? ""}`)}`);
424
+ }
425
+ return parts.join(" \\\n ");
426
+ }
427
+ function httpie({ method, url, headers, form = [] }) {
428
+ const parts = [`http --multipart ${method} ${shellQuote(url)}`];
429
+ for (const [key, value] of headerList(headers)) parts.push(shellQuote(`${key}:${value}`));
430
+ for (const field of form) parts.push(shellQuote(field.file ? `${field.name}@${path(field)}` : `${field.name}=${field.value ?? ""}`));
431
+ return parts.join(" \\\n ");
432
+ }
433
+ function formData(form, node) {
434
+ const lines = ["const form = new FormData();"];
435
+ for (const field of form) {
436
+ if (!field.file) lines.push(`form.append(${dq(field.name)}, ${dq(field.value ?? "")});`);
437
+ else if (node) lines.push(`form.append(${dq(field.name)}, await openAsBlob(${dq(path(field))}), ${dq(field.file.name)});`);
438
+ else lines.push(`form.append(${dq(field.name)}, fileInput.files[0]); // <input type="file" id="fileInput">`);
439
+ }
440
+ return lines;
441
+ }
442
+ var nodeImports = (form) => files(form).length ? ['import { openAsBlob } from "node:fs";', ""] : [];
443
+ function fetchClient(node) {
444
+ return ({ method, url, headers, form = [] }) => {
445
+ const options = [` method: ${dq(method)},`];
446
+ if (headerList(headers).length) options.push(` headers: ${jsObject(headers, " ")},`);
447
+ options.push(" body: form,");
448
+ return [
449
+ ...node ? nodeImports(form) : [],
450
+ ...formData(form, node),
451
+ "",
452
+ `const response = await fetch(${dq(url)}, {`,
453
+ ...options,
454
+ "});",
455
+ "",
456
+ "const data = await response.json();",
457
+ "console.log(data);"
458
+ ].join("\n");
459
+ };
460
+ }
461
+ function axios(node) {
462
+ return ({ method, url, headers, form = [] }) => {
463
+ const options = [` method: ${dq(method)},`, ` url: ${dq(url)},`];
464
+ if (headerList(headers).length) options.push(` headers: ${jsObject(headers, " ")},`);
465
+ options.push(" data: form,");
466
+ return [
467
+ 'import axios from "axios";',
468
+ ...node && files(form).length ? ['import { openAsBlob } from "node:fs";'] : [],
469
+ "",
470
+ ...formData(form, node),
471
+ "",
472
+ "const { data } = await axios.request({",
473
+ ...options,
474
+ "});",
475
+ "",
476
+ "console.log(data);"
477
+ ].join("\n");
478
+ };
479
+ }
480
+ function jquery({ method, url, headers, form = [] }) {
481
+ const options = [` url: ${dq(url)},`, ` method: ${dq(method)},`];
482
+ if (headerList(headers).length) options.push(` headers: ${jsObject(headers, " ")},`);
483
+ options.push(" data: form,", " processData: false,", " contentType: false,");
484
+ return [...formData(form, false), "", "$.ajax({", ...options, "}).done((response) => {", " console.log(response);", "});"].join("\n");
485
+ }
486
+ function xhr({ method, url, headers, form = [] }) {
487
+ return [
488
+ ...formData(form, false),
489
+ "",
490
+ "const xhr = new XMLHttpRequest();",
491
+ `xhr.open(${dq(method)}, ${dq(url)});`,
492
+ ...headerList(headers).map(([key, value]) => `xhr.setRequestHeader(${dq(key)}, ${dq(value)});`),
493
+ "",
494
+ 'xhr.addEventListener("load", () => {',
495
+ " console.log(xhr.responseText);",
496
+ "});",
497
+ "",
498
+ "xhr.send(form);"
499
+ ].join("\n");
500
+ }
501
+ function undici({ method, url, headers, form = [] }) {
502
+ const options = [` method: ${dq(method)},`];
503
+ if (headerList(headers).length) options.push(` headers: ${jsObject(headers, " ")},`);
504
+ options.push(" body: form,");
505
+ return [
506
+ 'import { request, FormData } from "undici";',
507
+ ...files(form).length ? ['import { openAsBlob } from "node:fs";'] : [],
508
+ "",
509
+ ...formData(form, true),
510
+ "",
511
+ `const { statusCode, body } = await request(${dq(url)}, {`,
512
+ ...options,
513
+ "});",
514
+ "",
515
+ "console.log(statusCode, await body.json());"
516
+ ].join("\n");
517
+ }
518
+ var pyString = (value) => JSON.stringify(String(value));
519
+ function pythonClient(library) {
520
+ return ({ method, url, headers, form = [] }) => {
521
+ const lines = [`import ${library}`, "", `url = ${pyString(url)}`];
522
+ const args = [pyString(method), "url"];
523
+ if (headerList(headers).length) {
524
+ lines.push(`headers = {${headerList(headers).map(([key, value]) => `${pyString(key)}: ${pyString(value)}`).join(", ")}}`);
525
+ args.push("headers=headers");
526
+ }
527
+ const grouped = /* @__PURE__ */ new Map();
528
+ for (const field of texts(form)) grouped.set(field.name, [...grouped.get(field.name) ?? [], field.value ?? ""]);
529
+ if (grouped.size) {
530
+ const entries = [...grouped].map(([name, values]) => `${pyString(name)}: ${values.length > 1 ? `[${values.map(pyString).join(", ")}]` : pyString(values[0])}`);
531
+ lines.push(`data = {${entries.join(", ")}}`);
532
+ args.push("data=data");
533
+ }
534
+ const fileFields = files(form);
535
+ lines.push(
536
+ `files = [${fileFields.map((field) => `(${pyString(field.name)}, (${pyString(field.file.name)}, open(${pyString(path(field))}, "rb"), ${pyString(fileType(field))}))`).join(", ")}]`
537
+ );
538
+ args.push("files=files");
539
+ lines.push("", `response = ${library}.request(${args.join(", ")})`, "", "print(response.json())");
540
+ return lines.join("\n");
541
+ };
542
+ }
543
+ function phpCurl({ method, url, headers, form = [] }) {
544
+ const lines = [
545
+ "<?php",
546
+ "",
547
+ "$curl = curl_init();",
548
+ "",
549
+ "curl_setopt_array($curl, [",
550
+ ` CURLOPT_URL => ${sq(url)},`,
551
+ " CURLOPT_RETURNTRANSFER => true,",
552
+ ` CURLOPT_CUSTOMREQUEST => ${sq(method)},`
553
+ ];
554
+ const headerLines = headerList(headers).map(([key, value]) => ` ${sq(`${key}: ${value}`)},`);
555
+ if (headerLines.length) lines.push(" CURLOPT_HTTPHEADER => [", ...headerLines, " ],");
556
+ const names = form.map((field) => field.name);
557
+ if (new Set(names).size !== names.length) {
558
+ lines.splice(1, 0, "", "// PHP arrays cannot repeat a key, so repeated fields keep only their last value; use the Guzzle example for those.");
559
+ }
560
+ lines.push(
561
+ " CURLOPT_POSTFIELDS => [",
562
+ ...form.map(
563
+ (field) => field.file ? ` ${sq(field.name)} => new CURLFile(${sq(path(field))}, ${sq(fileType(field))}, ${sq(field.file.name)}),` : ` ${sq(field.name)} => ${sq(field.value ?? "")},`
564
+ ),
565
+ " ],",
566
+ "]);",
567
+ "",
568
+ "$response = curl_exec($curl);",
569
+ "curl_close($curl);",
570
+ "",
571
+ "echo $response;"
572
+ );
573
+ return lines.join("\n");
574
+ }
575
+ function guzzle({ method, url, headers, form = [] }) {
576
+ const options = [];
577
+ if (headerList(headers).length) {
578
+ options.push(" 'headers' => [", ...headerList(headers).map(([key, value]) => ` ${sq(key)} => ${sq(value)},`), " ],");
579
+ }
580
+ options.push(
581
+ " 'multipart' => [",
582
+ ...form.map(
583
+ (field) => field.file ? ` ['name' => ${sq(field.name)}, 'contents' => fopen(${sq(path(field))}, 'r'), 'filename' => ${sq(field.file.name)}],` : ` ['name' => ${sq(field.name)}, 'contents' => ${sq(field.value ?? "")}],`
584
+ ),
585
+ " ],"
586
+ );
587
+ return [
588
+ "<?php",
589
+ "",
590
+ "require 'vendor/autoload.php';",
591
+ "",
592
+ "$client = new \\GuzzleHttp\\Client();",
593
+ "",
594
+ `$response = $client->request(${sq(method)}, ${sq(url)}, [
595
+ ${options.join("\n")}
596
+ ]);`,
597
+ "",
598
+ "echo $response->getBody();"
599
+ ].join("\n");
600
+ }
601
+ function go({ method, url, headers, form = [] }) {
602
+ const fileFields = files(form);
603
+ const body = [" body := &bytes.Buffer{}", " writer := multipart.NewWriter(body)"];
604
+ for (const field of form) {
605
+ if (!field.file) {
606
+ body.push(` writer.WriteField(${dq(field.name)}, ${dq(field.value ?? "")})`);
607
+ continue;
608
+ }
609
+ const variable = `file${body.length}`;
610
+ body.push(
611
+ "",
612
+ ` ${variable}, err := os.Open(${dq(path(field))})`,
613
+ " if err != nil {",
614
+ " panic(err)",
615
+ " }",
616
+ ` defer ${variable}.Close()`,
617
+ ` part${variable}, _ := writer.CreateFormFile(${dq(field.name)}, ${dq(field.file.name)})`,
618
+ ` io.Copy(part${variable}, ${variable})`
619
+ );
620
+ }
621
+ body.push(" writer.Close()");
622
+ const imports = ['"bytes"', '"fmt"', '"io"', '"mime/multipart"', '"net/http"', ...fileFields.length ? ['"os"'] : []];
623
+ return [
624
+ "package main",
625
+ "",
626
+ "import (",
627
+ ...imports.map((item) => ` ${item}`),
628
+ ")",
629
+ "",
630
+ "func main() {",
631
+ ...body,
632
+ "",
633
+ ` req, _ := http.NewRequest(${dq(method)}, ${dq(url)}, body)`,
634
+ ' req.Header.Set("Content-Type", writer.FormDataContentType())',
635
+ ...headerList(headers).map(([key, value]) => ` req.Header.Add(${dq(key)}, ${dq(value)})`),
636
+ "",
637
+ " res, err := http.DefaultClient.Do(req)",
638
+ " if err != nil {",
639
+ " panic(err)",
640
+ " }",
641
+ " defer res.Body.Close()",
642
+ "",
643
+ " data, _ := io.ReadAll(res.Body)",
644
+ " fmt.Println(string(data))",
645
+ "}"
646
+ ].join("\n");
647
+ }
648
+ function javaOkHttp({ method, url, headers, form = [] }) {
649
+ return [
650
+ "OkHttpClient client = new OkHttpClient();",
651
+ "",
652
+ "RequestBody body = new MultipartBody.Builder()",
653
+ " .setType(MultipartBody.FORM)",
654
+ ...form.map(
655
+ (field) => field.file ? ` .addFormDataPart(${dq(field.name)}, ${dq(field.file.name)}, RequestBody.create(new File(${dq(path(field))}), MediaType.parse(${dq(fileType(field))})))` : ` .addFormDataPart(${dq(field.name)}, ${dq(field.value ?? "")})`
656
+ ),
657
+ " .build();",
658
+ "Request request = new Request.Builder()",
659
+ ` .url(${dq(url)})`,
660
+ ` .method(${dq(method)}, body)`,
661
+ ...headerList(headers).map(([key, value]) => ` .addHeader(${dq(key)}, ${dq(value)})`),
662
+ " .build();",
663
+ "",
664
+ "Response response = client.newCall(request).execute();",
665
+ "System.out.println(response.body().string());"
666
+ ].join("\n");
667
+ }
668
+ function kotlinOkHttp({ method, url, headers, form = [] }) {
669
+ return [
670
+ "val client = OkHttpClient()",
671
+ "",
672
+ "val body = MultipartBody.Builder()",
673
+ " .setType(MultipartBody.FORM)",
674
+ ...form.map(
675
+ (field) => field.file ? ` .addFormDataPart(${kotlinQuote(field.name)}, ${kotlinQuote(field.file.name)}, File(${kotlinQuote(path(field))}).asRequestBody(${kotlinQuote(fileType(field))}.toMediaType()))` : ` .addFormDataPart(${kotlinQuote(field.name)}, ${kotlinQuote(field.value ?? "")})`
676
+ ),
677
+ " .build()",
678
+ "val request = Request.Builder()",
679
+ ` .url(${kotlinQuote(url)})`,
680
+ ` .method(${kotlinQuote(method)}, body)`,
681
+ ...headerList(headers).map(([key, value]) => ` .addHeader(${kotlinQuote(key)}, ${kotlinQuote(value)})`),
682
+ " .build()",
683
+ "",
684
+ "val response = client.newCall(request).execute()",
685
+ "println(response.body?.string())"
686
+ ].join("\n");
687
+ }
688
+ function csharpHttpClient({ method, url, headers, form = [] }) {
689
+ const lines = ["var client = new HttpClient();", "using var form = new MultipartFormDataContent();"];
690
+ for (const field of form) {
691
+ lines.push(
692
+ field.file ? `form.Add(new StreamContent(File.OpenRead(${dq(path(field))})), ${dq(field.name)}, ${dq(field.file.name)});` : `form.Add(new StringContent(${dq(field.value ?? "")}), ${dq(field.name)});`
693
+ );
694
+ }
695
+ lines.push("", "var request = new HttpRequestMessage", "{", ` Method = new HttpMethod(${dq(method)}),`, ` RequestUri = new Uri(${dq(url)}),`);
696
+ if (headerList(headers).length) {
697
+ lines.push(" Headers =", " {", ...headerList(headers).map(([key, value]) => ` { ${dq(key)}, ${dq(value)} },`), " },");
698
+ }
699
+ lines.push(
700
+ " Content = form,",
701
+ "};",
702
+ "",
703
+ "using var response = await client.SendAsync(request);",
704
+ "Console.WriteLine(await response.Content.ReadAsStringAsync());"
705
+ );
706
+ return lines.join("\n");
707
+ }
708
+ function restSharp({ method, url, headers, form = [] }) {
709
+ return [
710
+ "using RestSharp;",
711
+ "",
712
+ `var client = new RestClient(${dq(url)});`,
713
+ `var request = new RestRequest("", Method.${capitalize(method)});`,
714
+ "request.AlwaysMultipartFormData = true;",
715
+ ...headerList(headers).map(([key, value]) => `request.AddHeader(${dq(key)}, ${dq(value)});`),
716
+ ...form.map(
717
+ (field) => field.file ? `request.AddFile(${dq(field.name)}, ${dq(path(field))});` : `request.AddParameter(${dq(field.name)}, ${dq(field.value ?? "")});`
718
+ ),
719
+ "",
720
+ "var response = await client.ExecuteAsync(request);",
721
+ "Console.WriteLine(response.Content);"
722
+ ].join("\n");
723
+ }
724
+ function ruby({ method, url, headers, form = [] }) {
725
+ const lines = ['require "uri"', 'require "net/http"', "", `url = URI(${sq(url)})`, "", "http = Net::HTTP.new(url.host, url.port)"];
726
+ if (parseUrl(url).protocol === "https:") lines.push("http.use_ssl = true");
727
+ lines.push("", `request = Net::HTTP::${capitalize(method)}.new(url)`);
728
+ for (const [key, value] of headerList(headers)) lines.push(`request[${sq(key)}] = ${sq(value)}`);
729
+ const parts = form.map((field) => field.file ? `[${sq(field.name)}, File.open(${sq(path(field))})]` : `[${sq(field.name)}, ${sq(field.value ?? "")}]`);
730
+ lines.push(`request.set_form([${parts.join(", ")}], "multipart/form-data")`, "", "response = http.request(request)", "puts response.read_body");
731
+ return lines.join("\n");
732
+ }
733
+ function swift({ method, url, headers, form = [] }) {
734
+ const lines = [
735
+ "import Foundation",
736
+ "",
737
+ `let url = URL(string: ${dq(url)})!`,
738
+ "var request = URLRequest(url: url)",
739
+ `request.httpMethod = ${dq(method)}`
740
+ ];
741
+ for (const [key, value] of headerList(headers)) lines.push(`request.setValue(${dq(value)}, forHTTPHeaderField: ${dq(key)})`);
742
+ lines.push(
743
+ "",
744
+ 'let boundary = "Boundary-\\(UUID().uuidString)"',
745
+ 'request.setValue("multipart/form-data; boundary=\\(boundary)", forHTTPHeaderField: "Content-Type")',
746
+ "",
747
+ "var body = Data()"
748
+ );
749
+ for (const field of form) {
750
+ const name = JSON.stringify(field.name).slice(1, -1);
751
+ if (field.file) {
752
+ const fileName = JSON.stringify(field.file.name).slice(1, -1);
753
+ lines.push(
754
+ `body.append("--\\(boundary)\\r\\nContent-Disposition: form-data; name=\\"${name}\\"; filename=\\"${fileName}\\"\\r\\nContent-Type: ${fileType(field)}\\r\\n\\r\\n".data(using: .utf8)!)`,
755
+ `body.append(try Data(contentsOf: URL(fileURLWithPath: ${dq(path(field))})))`,
756
+ 'body.append("\\r\\n".data(using: .utf8)!)'
757
+ );
758
+ } else {
759
+ const value = JSON.stringify(field.value ?? "").slice(1, -1);
760
+ lines.push(`body.append("--\\(boundary)\\r\\nContent-Disposition: form-data; name=\\"${name}\\"\\r\\n\\r\\n${value}\\r\\n".data(using: .utf8)!)`);
761
+ }
762
+ }
763
+ lines.push(
764
+ 'body.append("--\\(boundary)--\\r\\n".data(using: .utf8)!)',
765
+ "request.httpBody = body",
766
+ "",
767
+ "let (data, _) = try await URLSession.shared.data(for: request)",
768
+ "print(String(decoding: data, as: UTF8.self))"
769
+ );
770
+ return lines.join("\n");
771
+ }
772
+ function dart({ method, url, headers, form = [] }) {
773
+ const lines = ["import 'package:http/http.dart' as http;", "", "void main() async {"];
774
+ lines.push(` final request = http.MultipartRequest(${dartQuote(method)}, Uri.parse(${dartQuote(url)}));`);
775
+ if (headerList(headers).length) {
776
+ lines.push(" request.headers.addAll({", ...headerList(headers).map(([key, value]) => ` ${dartQuote(key)}: ${dartQuote(value)},`), " });");
777
+ }
778
+ const counts = /* @__PURE__ */ new Map();
779
+ for (const field of texts(form)) counts.set(field.name, (counts.get(field.name) ?? 0) + 1);
780
+ for (const field of form) {
781
+ if (field.file) lines.push(` request.files.add(await http.MultipartFile.fromPath(${dartQuote(field.name)}, ${dartQuote(path(field))}));`);
782
+ else if (counts.get(field.name) > 1) lines.push(` request.files.add(http.MultipartFile.fromString(${dartQuote(field.name)}, ${dartQuote(field.value ?? "")}));`);
783
+ else lines.push(` request.fields[${dartQuote(field.name)}] = ${dartQuote(field.value ?? "")};`);
784
+ }
785
+ lines.push("", " final response = await request.send();", " print(await response.stream.bytesToString());", "}");
786
+ return lines.join("\n");
787
+ }
788
+ function rust({ method, url, headers, form = [] }) {
789
+ const standard = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH", "TRACE"];
790
+ const methodExpr = standard.includes(method) ? `reqwest::Method::${method}` : `reqwest::Method::from_bytes(b${dq(method)})?`;
791
+ return [
792
+ '// reqwest with the "multipart" feature',
793
+ "#[tokio::main]",
794
+ "async fn main() -> Result<(), Box<dyn std::error::Error>> {",
795
+ " let client = reqwest::Client::new();",
796
+ "",
797
+ " let form = reqwest::multipart::Form::new()",
798
+ ...form.map(
799
+ (field) => field.file ? ` .part(${dq(field.name)}, reqwest::multipart::Part::bytes(std::fs::read(${dq(path(field))})?).file_name(${dq(field.file.name)}))` : ` .text(${dq(field.name)}, ${dq(field.value ?? "")})`
800
+ ),
801
+ " ;",
802
+ "",
803
+ " let response = client",
804
+ ` .request(${methodExpr}, ${dq(url)})`,
805
+ ...headerList(headers).map(([key, value]) => ` .header(${dq(key)}, ${dq(value)})`),
806
+ " .multipart(form)",
807
+ " .send()",
808
+ " .await?;",
809
+ "",
810
+ ' println!("{}", response.text().await?);',
811
+ " Ok(())",
812
+ "}"
813
+ ].join("\n");
814
+ }
815
+ function libcurl({ method, url, headers, form = [] }) {
816
+ const lines = [
817
+ "#include <curl/curl.h>",
818
+ "",
819
+ "int main(void) {",
820
+ " CURL *curl = curl_easy_init();",
821
+ "",
822
+ ` curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, ${dq(method)});`,
823
+ ` curl_easy_setopt(curl, CURLOPT_URL, ${dq(url)});`,
824
+ "",
825
+ " struct curl_slist *headers = NULL;",
826
+ ...headerList(headers).map(([key, value]) => ` headers = curl_slist_append(headers, ${dq(`${key}: ${value}`)});`),
827
+ " curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);",
828
+ "",
829
+ " curl_mime *mime = curl_mime_init(curl);",
830
+ " curl_mimepart *part;"
831
+ ];
832
+ for (const field of form) {
833
+ lines.push(" part = curl_mime_addpart(mime);", ` curl_mime_name(part, ${dq(field.name)});`);
834
+ lines.push(field.file ? ` curl_mime_filedata(part, ${dq(path(field))});` : ` curl_mime_data(part, ${dq(field.value ?? "")}, CURL_ZERO_TERMINATED);`);
835
+ }
836
+ lines.push(
837
+ " curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);",
838
+ "",
839
+ " CURLcode ret = curl_easy_perform(curl);",
840
+ "",
841
+ " curl_mime_free(mime);",
842
+ " curl_slist_free_all(headers);",
843
+ " curl_easy_cleanup(curl);",
844
+ " return (int) ret;",
845
+ "}"
846
+ );
847
+ return lines.join("\n");
848
+ }
849
+ function powershell({ method, url, headers, form = [] }) {
850
+ const lines = ["# PowerShell 7+ (-Form)"];
851
+ const args = [`-Uri ${psQuote(url)}`, `-Method ${method}`];
852
+ if (headerList(headers).length) {
853
+ lines.push("$headers = @{", ...headerList(headers).map(([key, value]) => ` ${psQuote(key)} = ${psQuote(value)}`), "}");
854
+ args.push("-Headers $headers");
855
+ }
856
+ const grouped = /* @__PURE__ */ new Map();
857
+ for (const field of form) {
858
+ const value = field.file ? `(Get-Item -Path ${psQuote(path(field))})` : psQuote(field.value ?? "");
859
+ grouped.set(field.name, [...grouped.get(field.name) ?? [], value]);
860
+ }
861
+ lines.push(
862
+ "$form = @{",
863
+ ...[...grouped].map(([name, values]) => ` ${psQuote(name)} = ${values.length > 1 ? `@(${values.join(", ")})` : values[0]}`),
864
+ "}",
865
+ ""
866
+ );
867
+ args.push("-Form $form");
868
+ lines.push(`$response = Invoke-RestMethod ${args.join(" ")}`, "$response | ConvertTo-Json -Depth 10");
869
+ return lines.join("\n");
870
+ }
871
+ var BOUNDARY = "oaspect-boundary";
872
+ function rawHttp({ method, url, headers, form = [] }) {
873
+ const target = parseUrl(url);
874
+ const lines = [`${method} ${target.pathname}${target.search} HTTP/1.1`, `Host: ${target.host}`];
875
+ for (const [key, value] of headerList(headers)) lines.push(`${key}: ${value}`);
876
+ lines.push(`Content-Type: multipart/form-data; boundary=${BOUNDARY}`, "");
877
+ for (const field of form) {
878
+ lines.push(`--${BOUNDARY}`);
879
+ if (field.file) {
880
+ lines.push(`Content-Disposition: form-data; name="${field.name}"; filename="${field.file.name}"`, `Content-Type: ${fileType(field)}`, "", `(contents of ${field.file.name})`);
881
+ } else {
882
+ lines.push(`Content-Disposition: form-data; name="${field.name}"`, "", field.value ?? "");
883
+ }
884
+ }
885
+ lines.push(`--${BOUNDARY}--`);
886
+ return lines.join("\n");
887
+ }
888
+ var MULTIPART_BUILDERS = {
889
+ "shell:curl": curl,
890
+ "shell:wget": () => note("#", "wget cannot send multipart/form-data; use the cURL or HTTPie example."),
891
+ "shell:httpie": httpie,
892
+ "javascript:fetch": fetchClient(false),
893
+ "javascript:axios": axios(false),
894
+ "javascript:jquery": jquery,
895
+ "javascript:xhr": xhr,
896
+ "node:fetch": fetchClient(true),
897
+ "node:axios": axios(true),
898
+ "node:undici": undici,
899
+ "node:http": () => note("//", "node:http has no multipart/form-data encoder; use the fetch or undici example."),
900
+ "python:requests": pythonClient("requests"),
901
+ "python:httpx": pythonClient("httpx"),
902
+ "python:http.client": () => note("#", "http.client has no multipart/form-data encoder; use the requests or httpx example."),
903
+ "php:curl": phpCurl,
904
+ "php:guzzle": guzzle,
905
+ "go:native": go,
906
+ "java:httpclient": () => note("//", "java.net.http has no multipart/form-data encoder; use the OkHttp example."),
907
+ "java:okhttp": javaOkHttp,
908
+ "kotlin:okhttp": kotlinOkHttp,
909
+ "csharp:httpclient": csharpHttpClient,
910
+ "csharp:restsharp": restSharp,
911
+ "ruby:native": ruby,
912
+ "swift:urlsession": swift,
913
+ "dart:http": dart,
914
+ "rust:reqwest": rust,
915
+ "c:libcurl": libcurl,
916
+ "powershell:restmethod": powershell,
917
+ "http:raw": rawHttp
918
+ };
919
+
920
+ // src/snippets.ts
921
+ var dq2 = (value) => JSON.stringify(String(value));
922
+ var sq2 = (value) => `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
923
+ var shellQuote2 = (value) => `'${String(value).replace(/'/g, "'\\''")}'`;
924
+ var psQuote2 = (value) => `'${String(value).replace(/'/g, "''")}'`;
925
+ var dartQuote2 = (value) => sq2(value).replace(/\$/g, "\\$");
926
+ var kotlinQuote2 = (value) => dq2(value).replace(/\$/g, "\\$");
927
+ var indent2 = (text, prefix) => text.split("\n").join(`
928
+ ${prefix}`);
929
+ function parseJson(body) {
930
+ if (body === void 0) return void 0;
931
+ try {
932
+ return JSON.parse(body);
933
+ } catch {
934
+ return void 0;
935
+ }
936
+ }
937
+ var compact = (body) => {
938
+ const json = parseJson(body);
939
+ return json === void 0 ? body : JSON.stringify(json);
940
+ };
941
+ var contentTypeOf = (headers) => Object.entries(headers).find(([key]) => key.toLowerCase() === "content-type")?.[1];
942
+ var withoutContentType = (headers) => Object.fromEntries(Object.entries(headers).filter(([key]) => key.toLowerCase() !== "content-type"));
943
+ function parseUrl2(url) {
944
+ try {
945
+ return new URL(url);
946
+ } catch {
947
+ return new URL(url, "http://localhost");
948
+ }
949
+ }
950
+ var capitalize2 = (method) => method.charAt(0) + method.slice(1).toLowerCase();
951
+ function toPython(value, pad = "") {
952
+ if (value === null) return "None";
953
+ if (value === true) return "True";
954
+ if (value === false) return "False";
955
+ if (typeof value !== "object") return JSON.stringify(value);
956
+ const next = `${pad} `;
957
+ if (Array.isArray(value)) {
958
+ return value.length ? `[
959
+ ${value.map((item) => next + toPython(item, next)).join(",\n")},
960
+ ${pad}]` : "[]";
961
+ }
962
+ const entries = Object.entries(value);
963
+ return entries.length ? `{
964
+ ${entries.map(([key, item]) => `${next}${JSON.stringify(key)}: ${toPython(item, next)}`).join(",\n")},
965
+ ${pad}}` : "{}";
966
+ }
967
+ function toPhp(value, pad = "") {
968
+ if (value === null) return "null";
969
+ if (typeof value === "boolean" || typeof value === "number") return String(value);
970
+ if (typeof value === "string") return sq2(value);
971
+ if (!Array.isArray(value) && Object.keys(value).length === 0) return "(object) []";
972
+ const next = `${pad} `;
973
+ const items = Array.isArray(value) ? value.map((item) => next + toPhp(item, next)) : Object.entries(value).map(([key, item]) => `${next}${sq2(key)} => ${toPhp(item, next)}`);
974
+ return items.length ? `[
975
+ ${items.join(",\n")},
976
+ ${pad}]` : "[]";
977
+ }
978
+ function toRuby(value, pad = "") {
979
+ if (value === null) return "nil";
980
+ if (typeof value === "boolean" || typeof value === "number") return String(value);
981
+ if (typeof value === "string") return sq2(value);
982
+ const next = `${pad} `;
983
+ if (Array.isArray(value)) {
984
+ return value.length ? `[
985
+ ${value.map((item) => next + toRuby(item, next)).join(",\n")}
986
+ ${pad}]` : "[]";
987
+ }
988
+ const entries = Object.entries(value);
989
+ return entries.length ? `{
990
+ ${entries.map(([key, item]) => `${next}${sq2(key)} => ${toRuby(item, next)}`).join(",\n")}
991
+ ${pad}}` : "{}";
992
+ }
993
+ var jsObject2 = (value, pad) => indent2(JSON.stringify(value, null, 2), pad);
994
+ function jsBody(body, pad) {
995
+ const json = parseJson(body);
996
+ return json === void 0 ? dq2(body) : `JSON.stringify(${jsObject2(json, pad)})`;
997
+ }
998
+ function curl2({ method, url, headers, body }) {
999
+ const parts = [`curl --request ${method}`, `--url ${shellQuote2(url)}`];
1000
+ for (const [key, value] of Object.entries(headers)) parts.push(`--header ${shellQuote2(`${key}: ${value}`)}`);
1001
+ if (body !== void 0) parts.push(`--data ${shellQuote2(body)}`);
1002
+ return parts.join(" \\\n ");
1003
+ }
1004
+ function wget({ method, url, headers, body }) {
1005
+ const parts = ["wget --quiet", `--method=${method}`];
1006
+ for (const [key, value] of Object.entries(headers)) parts.push(`--header=${shellQuote2(`${key}: ${value}`)}`);
1007
+ if (body !== void 0) parts.push(`--body-data=${shellQuote2(body)}`);
1008
+ parts.push("--output-document=-", shellQuote2(url));
1009
+ return parts.join(" \\\n ");
1010
+ }
1011
+ function httpie2({ method, url, headers, body }) {
1012
+ const command = `http ${method} ${shellQuote2(url)}`;
1013
+ const parts = [body !== void 0 ? `printf '%s' ${shellQuote2(body)} | ${command}` : command];
1014
+ for (const [key, value] of Object.entries(headers)) parts.push(shellQuote2(`${key}:${value}`));
1015
+ return parts.join(" \\\n ");
1016
+ }
1017
+ function fetchClient2({ method, url, headers, body }) {
1018
+ const options = [` method: ${dq2(method)},`];
1019
+ if (Object.keys(headers).length) options.push(` headers: ${jsObject2(headers, " ")},`);
1020
+ if (body !== void 0) options.push(` body: ${jsBody(body, " ")},`);
1021
+ return [`const response = await fetch(${dq2(url)}, {`, ...options, "});", "", "const data = await response.json();", "console.log(data);"].join("\n");
1022
+ }
1023
+ function axios2({ method, url, headers, body }) {
1024
+ const options = [` method: ${dq2(method)},`, ` url: ${dq2(url)},`];
1025
+ if (Object.keys(headers).length) options.push(` headers: ${jsObject2(headers, " ")},`);
1026
+ if (body !== void 0) {
1027
+ const json = parseJson(body);
1028
+ options.push(` data: ${json === void 0 ? dq2(body) : jsObject2(json, " ")},`);
1029
+ }
1030
+ return ['import axios from "axios";', "", "const { data } = await axios.request({", ...options, "});", "", "console.log(data);"].join("\n");
1031
+ }
1032
+ function jquery2({ method, url, headers, body }) {
1033
+ const options = [` url: ${dq2(url)},`, ` method: ${dq2(method)},`];
1034
+ if (Object.keys(headers).length) options.push(` headers: ${jsObject2(headers, " ")},`);
1035
+ if (body !== void 0) options.push(` data: ${jsBody(body, " ")},`);
1036
+ return ["$.ajax({", ...options, "}).done((response) => {", " console.log(response);", "});"].join("\n");
1037
+ }
1038
+ function xhr2({ method, url, headers, body }) {
1039
+ return [
1040
+ "const xhr = new XMLHttpRequest();",
1041
+ `xhr.open(${dq2(method)}, ${dq2(url)});`,
1042
+ ...Object.entries(headers).map(([key, value]) => `xhr.setRequestHeader(${dq2(key)}, ${dq2(value)});`),
1043
+ "",
1044
+ 'xhr.addEventListener("load", () => {',
1045
+ " console.log(xhr.responseText);",
1046
+ "});",
1047
+ "",
1048
+ body !== void 0 ? `xhr.send(${jsBody(body, "")});` : "xhr.send();"
1049
+ ].join("\n");
1050
+ }
1051
+ function undici2({ method, url, headers, body }) {
1052
+ const options = [` method: ${dq2(method)},`];
1053
+ if (Object.keys(headers).length) options.push(` headers: ${jsObject2(headers, " ")},`);
1054
+ if (body !== void 0) options.push(` body: ${jsBody(body, " ")},`);
1055
+ return [
1056
+ 'import { request } from "undici";',
1057
+ "",
1058
+ `const { statusCode, body } = await request(${dq2(url)}, {`,
1059
+ ...options,
1060
+ "});",
1061
+ "",
1062
+ "console.log(statusCode, await body.json());"
1063
+ ].join("\n");
1064
+ }
1065
+ function nodeHttp({ method, url, headers, body }) {
1066
+ const lib = parseUrl2(url).protocol === "https:" ? "https" : "http";
1067
+ const options = [` method: ${dq2(method)},`];
1068
+ if (Object.keys(headers).length) options.push(` headers: ${jsObject2(headers, " ")},`);
1069
+ return [
1070
+ `import ${lib} from "node:${lib}";`,
1071
+ "",
1072
+ `const req = ${lib}.request(${dq2(url)}, {`,
1073
+ ...options,
1074
+ "}, (res) => {",
1075
+ ' let data = "";',
1076
+ ' res.on("data", (chunk) => (data += chunk));',
1077
+ ' res.on("end", () => console.log(data));',
1078
+ "});",
1079
+ "",
1080
+ ...body !== void 0 ? [`req.write(${jsBody(body, "")});`] : [],
1081
+ "req.end();"
1082
+ ].join("\n");
1083
+ }
1084
+ function pythonClient2(library) {
1085
+ return ({ method, url, headers, body }) => {
1086
+ const json = parseJson(body);
1087
+ const lines = [`import ${library}`, "", `url = ${dq2(url)}`];
1088
+ const args = [dq2(method), "url"];
1089
+ if (Object.keys(headers).length) {
1090
+ lines.push(`headers = ${toPython(headers)}`);
1091
+ args.push("headers=headers");
1092
+ }
1093
+ if (json !== void 0) {
1094
+ lines.push(`payload = ${toPython(json)}`);
1095
+ args.push("json=payload");
1096
+ } else if (body !== void 0) {
1097
+ lines.push(`payload = ${dq2(body)}`);
1098
+ args.push("data=payload");
1099
+ }
1100
+ lines.push("", `response = ${library}.request(${args.join(", ")})`, "", "print(response.json())");
1101
+ return lines.join("\n");
1102
+ };
1103
+ }
1104
+ function pythonHttpClient({ method, url, headers, body }) {
1105
+ const target = parseUrl2(url);
1106
+ const connection = target.protocol === "https:" ? "HTTPSConnection" : "HTTPConnection";
1107
+ const json = parseJson(body);
1108
+ const lines = ["import http.client"];
1109
+ if (json !== void 0) lines.push("import json");
1110
+ lines.push("", `conn = http.client.${connection}(${dq2(target.host)})`);
1111
+ let payload = "None";
1112
+ if (json !== void 0) {
1113
+ lines.push(`payload = json.dumps(${toPython(json)})`);
1114
+ payload = "payload";
1115
+ } else if (body !== void 0) {
1116
+ lines.push(`payload = ${dq2(body)}`);
1117
+ payload = "payload";
1118
+ }
1119
+ lines.push(`headers = ${toPython(headers)}`);
1120
+ lines.push(
1121
+ "",
1122
+ `conn.request(${dq2(method)}, ${dq2(target.pathname + target.search)}, ${payload}, headers)`,
1123
+ "res = conn.getresponse()",
1124
+ "",
1125
+ 'print(res.read().decode("utf-8"))'
1126
+ );
1127
+ return lines.join("\n");
1128
+ }
1129
+ function phpCurl2({ method, url, headers, body }) {
1130
+ const json = parseJson(body);
1131
+ const lines = [
1132
+ "<?php",
1133
+ "",
1134
+ "$curl = curl_init();",
1135
+ "",
1136
+ "curl_setopt_array($curl, [",
1137
+ ` CURLOPT_URL => ${sq2(url)},`,
1138
+ " CURLOPT_RETURNTRANSFER => true,",
1139
+ ` CURLOPT_CUSTOMREQUEST => ${sq2(method)},`
1140
+ ];
1141
+ const headerLines = Object.entries(headers).map(([key, value]) => ` ${sq2(`${key}: ${value}`)},`);
1142
+ if (headerLines.length) lines.push(" CURLOPT_HTTPHEADER => [", ...headerLines, " ],");
1143
+ if (json !== void 0) lines.push(` CURLOPT_POSTFIELDS => json_encode(${toPhp(json, " ")}),`);
1144
+ else if (body !== void 0) lines.push(` CURLOPT_POSTFIELDS => ${sq2(body)},`);
1145
+ lines.push("]);", "", "$response = curl_exec($curl);", "curl_close($curl);", "", "echo $response;");
1146
+ return lines.join("\n");
1147
+ }
1148
+ function guzzle2({ method, url, headers, body }) {
1149
+ const json = parseJson(body);
1150
+ const options = [];
1151
+ const sentHeaders = json !== void 0 ? withoutContentType(headers) : headers;
1152
+ if (Object.keys(sentHeaders).length) options.push(` 'headers' => ${toPhp(sentHeaders, " ")},`);
1153
+ if (json !== void 0) options.push(` 'json' => ${toPhp(json, " ")},`);
1154
+ else if (body !== void 0) options.push(` 'body' => ${sq2(body)},`);
1155
+ return [
1156
+ "<?php",
1157
+ "",
1158
+ "require 'vendor/autoload.php';",
1159
+ "",
1160
+ "$client = new \\GuzzleHttp\\Client();",
1161
+ "",
1162
+ options.length ? `$response = $client->request(${sq2(method)}, ${sq2(url)}, [
1163
+ ${options.join("\n")}
1164
+ ]);` : `$response = $client->request(${sq2(method)}, ${sq2(url)});`,
1165
+ "",
1166
+ "echo $response->getBody();"
1167
+ ].join("\n");
1168
+ }
1169
+ function go2({ method, url, headers, body }) {
1170
+ const hasBody = body !== void 0;
1171
+ const literal = hasBody && !body.includes("`") ? `\`${body}\`` : hasBody ? dq2(body) : "";
1172
+ const imports = ['"fmt"', '"io"', '"net/http"', ...hasBody ? ['"strings"'] : []];
1173
+ return [
1174
+ "package main",
1175
+ "",
1176
+ "import (",
1177
+ ...imports.map((item) => ` ${item}`),
1178
+ ")",
1179
+ "",
1180
+ "func main() {",
1181
+ ...hasBody ? [` payload := strings.NewReader(${literal})`, ""] : [],
1182
+ ` req, _ := http.NewRequest(${dq2(method)}, ${dq2(url)}, ${hasBody ? "payload" : "nil"})`,
1183
+ ...Object.keys(headers).length ? ["", ...Object.entries(headers).map(([key, value]) => ` req.Header.Add(${dq2(key)}, ${dq2(value)})`)] : [],
1184
+ "",
1185
+ " res, err := http.DefaultClient.Do(req)",
1186
+ " if err != nil {",
1187
+ " panic(err)",
1188
+ " }",
1189
+ " defer res.Body.Close()",
1190
+ "",
1191
+ " data, _ := io.ReadAll(res.Body)",
1192
+ " fmt.Println(string(data))",
1193
+ "}"
1194
+ ].join("\n");
1195
+ }
1196
+ var textBlock = (body, pad) => `"""
1197
+ ${pad}${indent2(body, pad)}
1198
+ ${pad}"""`;
1199
+ function javaHttpClient({ method, url, headers, body }) {
1200
+ const publisher = body !== void 0 ? `HttpRequest.BodyPublishers.ofString(${textBlock(body.replace(/\\/g, "\\\\"), " ")})` : "HttpRequest.BodyPublishers.noBody()";
1201
+ return [
1202
+ "import java.net.URI;",
1203
+ "import java.net.http.HttpClient;",
1204
+ "import java.net.http.HttpRequest;",
1205
+ "import java.net.http.HttpResponse;",
1206
+ "",
1207
+ "HttpRequest request = HttpRequest.newBuilder()",
1208
+ ` .uri(URI.create(${dq2(url)}))`,
1209
+ ...Object.entries(headers).map(([key, value]) => ` .header(${dq2(key)}, ${dq2(value)})`),
1210
+ ` .method(${dq2(method)}, ${publisher})`,
1211
+ " .build();",
1212
+ "",
1213
+ "HttpResponse<String> response = HttpClient.newHttpClient()",
1214
+ " .send(request, HttpResponse.BodyHandlers.ofString());",
1215
+ "",
1216
+ "System.out.println(response.body());"
1217
+ ].join("\n");
1218
+ }
1219
+ function javaOkHttp2({ method, url, headers, body }) {
1220
+ const hasBody = body !== void 0;
1221
+ return [
1222
+ "OkHttpClient client = new OkHttpClient();",
1223
+ "",
1224
+ ...hasBody ? [
1225
+ `MediaType mediaType = MediaType.parse(${dq2(contentTypeOf(headers) ?? "text/plain")});`,
1226
+ `RequestBody body = RequestBody.create(${dq2(compact(body))}, mediaType);`
1227
+ ] : [],
1228
+ "Request request = new Request.Builder()",
1229
+ ` .url(${dq2(url)})`,
1230
+ ` .method(${dq2(method)}, ${hasBody ? "body" : "null"})`,
1231
+ ...Object.entries(headers).map(([key, value]) => ` .addHeader(${dq2(key)}, ${dq2(value)})`),
1232
+ " .build();",
1233
+ "",
1234
+ "Response response = client.newCall(request).execute();",
1235
+ "System.out.println(response.body().string());"
1236
+ ].join("\n");
1237
+ }
1238
+ function kotlinOkHttp2({ method, url, headers, body }) {
1239
+ const hasBody = body !== void 0;
1240
+ return [
1241
+ "val client = OkHttpClient()",
1242
+ "",
1243
+ ...hasBody ? [
1244
+ `val mediaType = ${kotlinQuote2(contentTypeOf(headers) ?? "text/plain")}.toMediaType()`,
1245
+ `val body = """
1246
+ ${body.replace(/\$/g, () => "${'$'}")}
1247
+ """.trimIndent().toRequestBody(mediaType)`
1248
+ ] : [],
1249
+ "val request = Request.Builder()",
1250
+ ` .url(${kotlinQuote2(url)})`,
1251
+ ` .method(${kotlinQuote2(method)}, ${hasBody ? "body" : "null"})`,
1252
+ ...Object.entries(headers).map(([key, value]) => ` .addHeader(${kotlinQuote2(key)}, ${kotlinQuote2(value)})`),
1253
+ " .build()",
1254
+ "",
1255
+ "val response = client.newCall(request).execute()",
1256
+ "println(response.body?.string())"
1257
+ ].join("\n");
1258
+ }
1259
+ function csharpHttpClient2({ method, url, headers, body }) {
1260
+ const requestHeaders = Object.entries(withoutContentType(headers));
1261
+ const contentType = contentTypeOf(headers);
1262
+ const lines = [
1263
+ "using System.Net.Http.Headers;",
1264
+ "",
1265
+ "var client = new HttpClient();",
1266
+ "var request = new HttpRequestMessage",
1267
+ "{",
1268
+ ` Method = new HttpMethod(${dq2(method)}),`,
1269
+ ` RequestUri = new Uri(${dq2(url)}),`
1270
+ ];
1271
+ if (requestHeaders.length) {
1272
+ lines.push(" Headers =", " {", ...requestHeaders.map(([key, value]) => ` { ${dq2(key)}, ${dq2(value)} },`), " },");
1273
+ }
1274
+ if (body !== void 0) {
1275
+ lines.push(` Content = new StringContent(${textBlock(body, " ")})`);
1276
+ if (contentType) {
1277
+ lines.push(
1278
+ " {",
1279
+ " Headers =",
1280
+ " {",
1281
+ ` ContentType = new MediaTypeHeaderValue(${dq2(contentType)})`,
1282
+ " }",
1283
+ " }"
1284
+ );
1285
+ }
1286
+ }
1287
+ lines.push(
1288
+ "};",
1289
+ "",
1290
+ "using var response = await client.SendAsync(request);",
1291
+ "Console.WriteLine(await response.Content.ReadAsStringAsync());"
1292
+ );
1293
+ return lines.join("\n");
1294
+ }
1295
+ function restSharp2({ method, url, headers, body }) {
1296
+ const contentType = contentTypeOf(headers) ?? "application/json";
1297
+ return [
1298
+ "using RestSharp;",
1299
+ "",
1300
+ `var client = new RestClient(${dq2(url)});`,
1301
+ `var request = new RestRequest("", Method.${capitalize2(method)});`,
1302
+ ...Object.entries(withoutContentType(headers)).map(([key, value]) => `request.AddHeader(${dq2(key)}, ${dq2(value)});`),
1303
+ ...body !== void 0 ? [`request.AddStringBody(${dq2(compact(body))}, ${dq2(contentType)});`] : [],
1304
+ "",
1305
+ "var response = await client.ExecuteAsync(request);",
1306
+ "Console.WriteLine(response.Content);"
1307
+ ].join("\n");
1308
+ }
1309
+ function ruby2({ method, url, headers, body }) {
1310
+ const json = parseJson(body);
1311
+ const lines = ['require "uri"', 'require "net/http"'];
1312
+ if (json !== void 0) lines.push('require "json"');
1313
+ lines.push("", `url = URI(${sq2(url)})`, "", "http = Net::HTTP.new(url.host, url.port)");
1314
+ if (parseUrl2(url).protocol === "https:") lines.push("http.use_ssl = true");
1315
+ lines.push("", `request = Net::HTTP::${capitalize2(method)}.new(url)`);
1316
+ for (const [key, value] of Object.entries(headers)) lines.push(`request[${sq2(key)}] = ${sq2(value)}`);
1317
+ if (json !== void 0) lines.push(`request.body = JSON.dump(${toRuby(json)})`);
1318
+ else if (body !== void 0) lines.push(`request.body = ${sq2(body)}`);
1319
+ lines.push("", "response = http.request(request)", "puts response.read_body");
1320
+ return lines.join("\n");
1321
+ }
1322
+ function swift2({ method, url, headers, body }) {
1323
+ const lines = ["import Foundation", "", `let url = URL(string: ${dq2(url)})!`, "var request = URLRequest(url: url)", `request.httpMethod = ${dq2(method)}`];
1324
+ const entries = Object.entries(headers);
1325
+ if (entries.length) {
1326
+ lines.push("request.allHTTPHeaderFields = [", ...entries.map(([key, value]) => ` ${dq2(key)}: ${dq2(value)},`), "]");
1327
+ }
1328
+ if (body !== void 0) lines.push(`request.httpBody = """
1329
+ ${body.replace(/\\/g, "\\\\")}
1330
+ """.data(using: .utf8)`);
1331
+ lines.push("", "let (data, _) = try await URLSession.shared.data(for: request)", "print(String(decoding: data, as: UTF8.self))");
1332
+ return lines.join("\n");
1333
+ }
1334
+ function dart2({ method, url, headers, body }) {
1335
+ const entries = Object.entries(headers);
1336
+ const lines = ["import 'package:http/http.dart' as http;", "", "void main() async {"];
1337
+ lines.push(` final request = http.Request(${dartQuote2(method)}, Uri.parse(${dartQuote2(url)}));`);
1338
+ if (entries.length) {
1339
+ lines.push(" request.headers.addAll({", ...entries.map(([key, value]) => ` ${dartQuote2(key)}: ${dartQuote2(value)},`), " });");
1340
+ }
1341
+ if (body !== void 0) lines.push(` request.body = r'''
1342
+ ${body}
1343
+ ''';`);
1344
+ lines.push("", " final response = await request.send();", " print(await response.stream.bytesToString());", "}");
1345
+ return lines.join("\n");
1346
+ }
1347
+ function rust2({ method, url, headers, body }) {
1348
+ const standard = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH", "TRACE"];
1349
+ const methodExpr = standard.includes(method) ? `reqwest::Method::${method}` : `reqwest::Method::from_bytes(b${dq2(method)}).unwrap()`;
1350
+ let hashes = "#";
1351
+ while (body !== void 0 && body.includes(`"${hashes}`)) hashes += "#";
1352
+ return [
1353
+ "#[tokio::main]",
1354
+ "async fn main() -> Result<(), reqwest::Error> {",
1355
+ " let client = reqwest::Client::new();",
1356
+ "",
1357
+ " let response = client",
1358
+ ` .request(${methodExpr}, ${dq2(url)})`,
1359
+ ...Object.entries(headers).map(([key, value]) => ` .header(${dq2(key)}, ${dq2(value)})`),
1360
+ ...body !== void 0 ? [` .body(r${hashes}"${body}"${hashes})`] : [],
1361
+ " .send()",
1362
+ " .await?;",
1363
+ "",
1364
+ ' println!("{}", response.text().await?);',
1365
+ " Ok(())",
1366
+ "}"
1367
+ ].join("\n");
1368
+ }
1369
+ function libcurl2({ method, url, headers, body }) {
1370
+ const entries = Object.entries(headers);
1371
+ return [
1372
+ "#include <curl/curl.h>",
1373
+ "",
1374
+ "int main(void) {",
1375
+ " CURL *curl = curl_easy_init();",
1376
+ "",
1377
+ ` curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, ${dq2(method)});`,
1378
+ ` curl_easy_setopt(curl, CURLOPT_URL, ${dq2(url)});`,
1379
+ "",
1380
+ " struct curl_slist *headers = NULL;",
1381
+ ...entries.map(([key, value]) => ` headers = curl_slist_append(headers, ${dq2(`${key}: ${value}`)});`),
1382
+ " curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);",
1383
+ ...body !== void 0 ? ["", ` curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ${dq2(compact(body))});`] : [],
1384
+ "",
1385
+ " CURLcode ret = curl_easy_perform(curl);",
1386
+ "",
1387
+ " curl_slist_free_all(headers);",
1388
+ " curl_easy_cleanup(curl);",
1389
+ " return (int) ret;",
1390
+ "}"
1391
+ ].join("\n");
1392
+ }
1393
+ function powershell2({ method, url, headers, body }) {
1394
+ const entries = Object.entries(withoutContentType(headers));
1395
+ const contentType = contentTypeOf(headers);
1396
+ const lines = [];
1397
+ const args = [`-Uri ${psQuote2(url)}`, `-Method ${method}`];
1398
+ if (entries.length) {
1399
+ lines.push("$headers = @{", ...entries.map(([key, value]) => ` ${psQuote2(key)} = ${psQuote2(value)}`), "}");
1400
+ args.push("-Headers $headers");
1401
+ }
1402
+ if (contentType) args.push(`-ContentType ${psQuote2(contentType)}`);
1403
+ if (body !== void 0) {
1404
+ lines.push(`$body = @'
1405
+ ${body}
1406
+ '@`);
1407
+ args.push("-Body $body");
1408
+ }
1409
+ if (lines.length) lines.push("");
1410
+ lines.push(`$response = Invoke-RestMethod ${args.join(" ")}`, "$response | ConvertTo-Json -Depth 10");
1411
+ return lines.join("\n");
1412
+ }
1413
+ function rawHttp2({ method, url, headers, body }) {
1414
+ const target = parseUrl2(url);
1415
+ const lines = [`${method} ${target.pathname}${target.search} HTTP/1.1`, `Host: ${target.host}`];
1416
+ for (const [key, value] of Object.entries(headers)) lines.push(`${key}: ${value}`);
1417
+ if (body !== void 0) lines.push(`Content-Length: ${new TextEncoder().encode(body).length}`, "", body);
1418
+ return lines.join("\n");
1419
+ }
1420
+ var LANGUAGES = [
1421
+ {
1422
+ key: "shell",
1423
+ label: "Shell",
1424
+ highlight: "shell",
1425
+ clients: [
1426
+ { key: "curl", label: "cURL", build: curl2 },
1427
+ { key: "wget", label: "Wget", build: wget },
1428
+ { key: "httpie", label: "HTTPie", build: httpie2 }
1429
+ ]
1430
+ },
1431
+ {
1432
+ key: "javascript",
1433
+ label: "JavaScript",
1434
+ highlight: "javascript",
1435
+ clients: [
1436
+ { key: "fetch", label: "fetch", build: fetchClient2 },
1437
+ { key: "axios", label: "Axios", build: axios2 },
1438
+ { key: "jquery", label: "jQuery", build: jquery2 },
1439
+ { key: "xhr", label: "XHR", build: xhr2 }
1440
+ ]
1441
+ },
1442
+ {
1443
+ key: "node",
1444
+ label: "Node.js",
1445
+ highlight: "javascript",
1446
+ clients: [
1447
+ { key: "fetch", label: "fetch", build: fetchClient2 },
1448
+ { key: "axios", label: "Axios", build: axios2 },
1449
+ { key: "undici", label: "undici", build: undici2 },
1450
+ { key: "http", label: "http", build: nodeHttp }
1451
+ ]
1452
+ },
1453
+ {
1454
+ key: "python",
1455
+ label: "Python",
1456
+ highlight: "python",
1457
+ clients: [
1458
+ { key: "requests", label: "requests", build: pythonClient2("requests") },
1459
+ { key: "httpx", label: "httpx", build: pythonClient2("httpx") },
1460
+ { key: "http.client", label: "http.client", build: pythonHttpClient }
1461
+ ]
1462
+ },
1463
+ {
1464
+ key: "php",
1465
+ label: "PHP",
1466
+ highlight: "php",
1467
+ clients: [
1468
+ { key: "curl", label: "cURL", build: phpCurl2 },
1469
+ { key: "guzzle", label: "Guzzle", build: guzzle2 }
1470
+ ]
1471
+ },
1472
+ { key: "go", label: "Go", highlight: "go", clients: [{ key: "native", label: "net/http", build: go2 }] },
1473
+ {
1474
+ key: "java",
1475
+ label: "Java",
1476
+ highlight: "java",
1477
+ clients: [
1478
+ { key: "httpclient", label: "HttpClient", build: javaHttpClient },
1479
+ { key: "okhttp", label: "OkHttp", build: javaOkHttp2 }
1480
+ ]
1481
+ },
1482
+ { key: "kotlin", label: "Kotlin", highlight: "kotlin", clients: [{ key: "okhttp", label: "OkHttp", build: kotlinOkHttp2 }] },
1483
+ {
1484
+ key: "csharp",
1485
+ label: "C#",
1486
+ highlight: "csharp",
1487
+ clients: [
1488
+ { key: "httpclient", label: "HttpClient", build: csharpHttpClient2 },
1489
+ { key: "restsharp", label: "RestSharp", build: restSharp2 }
1490
+ ]
1491
+ },
1492
+ { key: "ruby", label: "Ruby", highlight: "ruby", clients: [{ key: "native", label: "net/http", build: ruby2 }] },
1493
+ { key: "swift", label: "Swift", highlight: "swift", clients: [{ key: "urlsession", label: "URLSession", build: swift2 }] },
1494
+ { key: "dart", label: "Dart", highlight: "dart", clients: [{ key: "http", label: "http", build: dart2 }] },
1495
+ { key: "rust", label: "Rust", highlight: "rust", clients: [{ key: "reqwest", label: "reqwest", build: rust2 }] },
1496
+ { key: "c", label: "C", highlight: "c", clients: [{ key: "libcurl", label: "libcurl", build: libcurl2 }] },
1497
+ {
1498
+ key: "powershell",
1499
+ label: "PowerShell",
1500
+ highlight: "powershell",
1501
+ clients: [{ key: "restmethod", label: "Invoke-RestMethod", build: powershell2 }]
1502
+ },
1503
+ { key: "http", label: "HTTP", highlight: "http", clients: [{ key: "raw", label: "HTTP/1.1", build: rawHttp2 }] }
1504
+ ];
1505
+ var SNIPPET_LANGUAGES = LANGUAGES.map((language) => ({
1506
+ ...language,
1507
+ clients: language.clients.map((client) => {
1508
+ const multipart = MULTIPART_BUILDERS[`${language.key}:${client.key}`];
1509
+ return { ...client, build: (request) => request.form && multipart ? multipart(request) : client.build(request) };
1510
+ })
1511
+ }));
1512
+ function resolveSnippet(selection) {
1513
+ const [languageKey, clientKey] = String(selection ?? "").split(":");
1514
+ const language = SNIPPET_LANGUAGES.find((item) => item.key === languageKey) ?? SNIPPET_LANGUAGES[0];
1515
+ const client = language.clients.find((item) => item.key === clientKey) ?? language.clients[0];
1516
+ return { language, client, selection: `${language.key}:${client.key}` };
1517
+ }
1518
+
1519
+ // src/i18n.ts
1520
+ function localize(node, field, locale) {
1521
+ const translations = node?.["x-i18n"];
1522
+ if (translations && locale) {
1523
+ const target = String(locale).toLowerCase();
1524
+ const base = target.split("-")[0];
1525
+ for (const [tag, values] of Object.entries(translations)) {
1526
+ const normalized = tag.toLowerCase().replace("_", "-");
1527
+ if ((normalized === target || normalized === base) && typeof values?.[field] === "string") return values[field];
1528
+ }
1529
+ }
1530
+ return node?.[field];
1531
+ }
1532
+
1533
+ // src/markdown.ts
1534
+ var FENCE = /^ {0,3}(`{3,}|~{3,})\s*([^\s`]*)[^`]*$/;
1535
+ var LANG_OPEN = /^ {0,3}:{3,}[ \t]*lang[ \t]+([A-Za-z]{2,3}(?:[-_][A-Za-z0-9]+)*(?:[ \t]*,[ \t]*[A-Za-z]{2,3}(?:[-_][A-Za-z0-9]+)*)*)[ \t]*$/;
1536
+ var CONTAINER_OPEN = /^ {0,3}:{3,}[ \t]*\S/;
1537
+ var CONTAINER_CLOSE = /^ {0,3}:{3,}[ \t]*$/;
1538
+ var HEADING = /^ {0,3}(#{1,6})(?:[ \t]+(.*?))?(?:[ \t]+#+)?[ \t]*$/;
1539
+ var THEMATIC_BREAK = /^ {0,3}([-*_])(?:[ \t]*\1){2,}[ \t]*$/;
1540
+ var BLOCKQUOTE = /^ {0,3}> ?/;
1541
+ var LIST_ITEM = /^( *)([-*+]|\d{1,9}[.)])([ \t]+|$)(.*)$/;
1542
+ var TABLE_DELIMITER = /^ {0,3}\|?[ \t]*:?-+:?[ \t]*(\|[ \t]*:?-+:?[ \t]*)*\|?[ \t]*$/;
1543
+ var isBlank = (line) => line.trim() === "";
1544
+ var indentOf = (line) => line.match(/^ */)[0].length;
1545
+ var expandTabs = (line) => line.replace(/\t/g, " ");
1546
+ function splitRow(line) {
1547
+ let row = line.trim();
1548
+ if (row.startsWith("|")) row = row.slice(1);
1549
+ if (row.endsWith("|") && !row.endsWith("\\|")) row = row.slice(0, -1);
1550
+ const cells = [];
1551
+ let current = "";
1552
+ let inCode = false;
1553
+ for (let index = 0; index < row.length; index += 1) {
1554
+ const char = row[index];
1555
+ if (char === "\\" && row[index + 1] === "|") {
1556
+ current += "|";
1557
+ index += 1;
1558
+ } else if (char === "`") {
1559
+ inCode = !inCode;
1560
+ current += char;
1561
+ } else if (char === "|" && !inCode) {
1562
+ cells.push(current.trim());
1563
+ current = "";
1564
+ } else {
1565
+ current += char;
1566
+ }
1567
+ }
1568
+ cells.push(current.trim());
1569
+ return cells;
1570
+ }
1571
+ function isTableStart(lines, index) {
1572
+ return index + 1 < lines.length && lines[index].includes("|") && TABLE_DELIMITER.test(lines[index + 1]) && splitRow(lines[index]).length === splitRow(lines[index + 1]).length;
1573
+ }
1574
+ function parseTable(lines, index) {
1575
+ const header = splitRow(lines[index]);
1576
+ const align = splitRow(lines[index + 1]).map((cell) => {
1577
+ const left = cell.startsWith(":");
1578
+ const right = cell.endsWith(":");
1579
+ return left && right ? "center" : right ? "right" : left ? "left" : null;
1580
+ });
1581
+ const rows = [];
1582
+ let next = index + 2;
1583
+ while (next < lines.length && !isBlank(lines[next]) && lines[next].includes("|")) {
1584
+ const cells = splitRow(lines[next]);
1585
+ rows.push(header.map((_, column) => parseInline(cells[column] ?? "")));
1586
+ next += 1;
1587
+ }
1588
+ return {
1589
+ block: { type: "table", align, header: header.map((cell) => parseInline(cell)), rows },
1590
+ next
1591
+ };
1592
+ }
1593
+ function listMarker(line) {
1594
+ const match = LIST_ITEM.exec(line);
1595
+ if (!match) return null;
1596
+ const [, indent3, marker, spacing, rest] = match;
1597
+ const ordered = /\d/.test(marker);
1598
+ const gap = spacing.length === 0 || spacing.length > 4 ? 1 : spacing.length;
1599
+ return {
1600
+ indent: indent3.length,
1601
+ ordered,
1602
+ bullet: ordered ? marker.slice(-1) : marker,
1603
+ start: ordered ? Number.parseInt(marker, 10) : null,
1604
+ contentOffset: indent3.length + marker.length + gap,
1605
+ firstLine: spacing.length > 4 ? `${" ".repeat(spacing.length - 1)}${rest}` : rest
1606
+ };
1607
+ }
1608
+ function parseList(lines, index) {
1609
+ const first = listMarker(lines[index]);
1610
+ const items = [];
1611
+ let loose = false;
1612
+ let next = index;
1613
+ while (next < lines.length) {
1614
+ const marker = listMarker(lines[next]);
1615
+ if (!marker || marker.ordered !== first.ordered || marker.bullet !== first.bullet || marker.indent >= first.contentOffset) break;
1616
+ const content = [marker.firstLine];
1617
+ next += 1;
1618
+ let sawBlank = false;
1619
+ while (next < lines.length) {
1620
+ const line = lines[next];
1621
+ if (isBlank(line)) {
1622
+ sawBlank = true;
1623
+ content.push("");
1624
+ next += 1;
1625
+ continue;
1626
+ }
1627
+ if (indentOf(line) >= marker.contentOffset) {
1628
+ content.push(line.slice(marker.contentOffset));
1629
+ next += 1;
1630
+ continue;
1631
+ }
1632
+ if (!sawBlank && !listMarker(line) && !startsBlock(lines, next)) {
1633
+ content.push(line.trim());
1634
+ next += 1;
1635
+ continue;
1636
+ }
1637
+ break;
1638
+ }
1639
+ while (content.length && isBlank(content[content.length - 1])) content.pop();
1640
+ if (sawBlank && next < lines.length && listMarker(lines[next])?.bullet === first.bullet) loose = true;
1641
+ if (content.some((line, lineIndex) => isBlank(line) && lineIndex < content.length - 1)) loose = true;
1642
+ let checked = null;
1643
+ const task = /^\[([ xX])\][ \t]+/.exec(content[0]);
1644
+ if (task) {
1645
+ checked = task[1] !== " ";
1646
+ content[0] = content[0].slice(task[0].length);
1647
+ }
1648
+ items.push({ checked, children: parseBlocks(content) });
1649
+ if (sawBlank && !(next < lines.length && listMarker(lines[next]))) break;
1650
+ }
1651
+ return {
1652
+ block: { type: "list", ordered: first.ordered, start: first.start, loose, items },
1653
+ next
1654
+ };
1655
+ }
1656
+ function startsBlock(lines, index) {
1657
+ const line = lines[index];
1658
+ return FENCE.test(line) || LANG_OPEN.test(line) || HEADING.test(line) || THEMATIC_BREAK.test(line) || BLOCKQUOTE.test(line) || isTableStart(lines, index);
1659
+ }
1660
+ function interruptsParagraph(lines, index) {
1661
+ if (startsBlock(lines, index)) return true;
1662
+ const marker = listMarker(lines[index]);
1663
+ return Boolean(marker && marker.firstLine.trim() && (!marker.ordered || marker.start === 1));
1664
+ }
1665
+ function parseBlocks(lines) {
1666
+ const blocks = [];
1667
+ let index = 0;
1668
+ while (index < lines.length) {
1669
+ const line = lines[index];
1670
+ if (isBlank(line)) {
1671
+ index += 1;
1672
+ continue;
1673
+ }
1674
+ const fence = FENCE.exec(line);
1675
+ if (fence) {
1676
+ const [, marker, language] = fence;
1677
+ const indent3 = indentOf(line);
1678
+ const code = [];
1679
+ index += 1;
1680
+ while (index < lines.length) {
1681
+ const closing = lines[index].trim();
1682
+ if (closing.startsWith(marker[0].repeat(marker.length)) && /^[`~]+$/.test(closing)) break;
1683
+ code.push(lines[index].slice(Math.min(indent3, indentOf(lines[index]))));
1684
+ index += 1;
1685
+ }
1686
+ index += 1;
1687
+ blocks.push({ type: "code", language: language.toLowerCase(), text: code.join("\n") });
1688
+ continue;
1689
+ }
1690
+ const lang = LANG_OPEN.exec(line);
1691
+ if (lang) {
1692
+ const inner = [];
1693
+ let depth = 1;
1694
+ index += 1;
1695
+ let inFence = null;
1696
+ while (index < lines.length) {
1697
+ const current = lines[index];
1698
+ const fence2 = FENCE.exec(current);
1699
+ if (fence2 && (!inFence || current.trim().startsWith(inFence))) inFence = inFence ? null : fence2[1];
1700
+ if (!inFence) {
1701
+ if (CONTAINER_OPEN.test(current)) depth += 1;
1702
+ else if (CONTAINER_CLOSE.test(current) && --depth === 0) break;
1703
+ }
1704
+ inner.push(current);
1705
+ index += 1;
1706
+ }
1707
+ index += 1;
1708
+ blocks.push({
1709
+ type: "lang",
1710
+ locales: lang[1].split(",").map((item) => normalizeTag(item)),
1711
+ children: parseBlocks(inner)
1712
+ });
1713
+ continue;
1714
+ }
1715
+ const heading = HEADING.exec(line);
1716
+ if (heading) {
1717
+ blocks.push({ type: "heading", level: heading[1].length, children: parseInline(heading[2] ?? "") });
1718
+ index += 1;
1719
+ continue;
1720
+ }
1721
+ if (THEMATIC_BREAK.test(line)) {
1722
+ blocks.push({ type: "hr" });
1723
+ index += 1;
1724
+ continue;
1725
+ }
1726
+ if (BLOCKQUOTE.test(line)) {
1727
+ const quoted = [];
1728
+ while (index < lines.length && !isBlank(lines[index])) {
1729
+ quoted.push(lines[index].replace(BLOCKQUOTE, ""));
1730
+ index += 1;
1731
+ }
1732
+ blocks.push({ type: "blockquote", children: parseBlocks(quoted) });
1733
+ continue;
1734
+ }
1735
+ if (isTableStart(lines, index)) {
1736
+ const { block, next } = parseTable(lines, index);
1737
+ blocks.push(block);
1738
+ index = next;
1739
+ continue;
1740
+ }
1741
+ if (listMarker(line)) {
1742
+ const { block, next } = parseList(lines, index);
1743
+ blocks.push(block);
1744
+ index = next;
1745
+ continue;
1746
+ }
1747
+ const paragraph = [line.trim()];
1748
+ index += 1;
1749
+ while (index < lines.length && !isBlank(lines[index]) && !interruptsParagraph(lines, index)) {
1750
+ paragraph.push(lines[index].trim());
1751
+ index += 1;
1752
+ }
1753
+ const raw = paragraph.map((text, lineIndex) => {
1754
+ const original = lines[index - paragraph.length + lineIndex];
1755
+ return / {2,}$/.test(original) ? `${text} ` : text;
1756
+ });
1757
+ blocks.push({ type: "paragraph", children: parseInline(raw.join("\n")) });
1758
+ }
1759
+ return blocks;
1760
+ }
1761
+ var PUNCTUATION = /[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]/;
1762
+ var BARE_URL = /^https?:\/\/[^\s<]*[^\s<.,:;"')\]!?*_~]/;
1763
+ var AUTOLINK = /^<((?:https?:\/\/|mailto:)[^\s<>]+)>/;
1764
+ function closingBracket(text, start) {
1765
+ let depth = 0;
1766
+ for (let index = start; index < text.length; index += 1) {
1767
+ const char = text[index];
1768
+ if (char === "\\") index += 1;
1769
+ else if (char === "`") {
1770
+ const end = text.indexOf("`", index + 1);
1771
+ if (end !== -1) index = end;
1772
+ } else if (char === "[") depth += 1;
1773
+ else if (char === "]" && --depth === 0) return index;
1774
+ }
1775
+ return -1;
1776
+ }
1777
+ function linkTarget2(text, start) {
1778
+ if (text[start] !== "(") return null;
1779
+ let index = start + 1;
1780
+ while (text[index] === " ") index += 1;
1781
+ let href = "";
1782
+ if (text[index] === "<") {
1783
+ const end = text.indexOf(">", index);
1784
+ if (end === -1) return null;
1785
+ href = text.slice(index + 1, end);
1786
+ index = end + 1;
1787
+ } else {
1788
+ let depth = 0;
1789
+ while (index < text.length) {
1790
+ const char = text[index];
1791
+ if (char === "\\" && PUNCTUATION.test(text[index + 1] ?? "")) {
1792
+ href += text[index + 1];
1793
+ index += 2;
1794
+ continue;
1795
+ }
1796
+ if (/\s/.test(char)) break;
1797
+ if (char === "(") depth += 1;
1798
+ if (char === ")") {
1799
+ if (depth === 0) break;
1800
+ depth -= 1;
1801
+ }
1802
+ href += char;
1803
+ index += 1;
1804
+ }
1805
+ }
1806
+ while (text[index] === " ") index += 1;
1807
+ let title;
1808
+ const quote = text[index];
1809
+ if (quote === '"' || quote === "'") {
1810
+ const end = text.indexOf(quote, index + 1);
1811
+ if (end === -1) return null;
1812
+ title = text.slice(index + 1, end);
1813
+ index = end + 1;
1814
+ while (text[index] === " ") index += 1;
1815
+ }
1816
+ return text[index] === ")" ? { href, title, end: index + 1 } : null;
1817
+ }
1818
+ function closingDelimiter(text, delimiter, from) {
1819
+ let index = from;
1820
+ while ((index = text.indexOf(delimiter, index)) !== -1) {
1821
+ const before = text[index - 1];
1822
+ const after = text[index + delimiter.length];
1823
+ const doubled = delimiter.length === 1 && (after === delimiter || before === delimiter);
1824
+ const escaped = before === "\\";
1825
+ const intraword = delimiter[0] === "_" && /\w/.test(after ?? "");
1826
+ if (index > from && !/\s/.test(before) && !doubled && !escaped && !intraword) return index;
1827
+ index += doubled ? 2 : 1;
1828
+ }
1829
+ return -1;
1830
+ }
1831
+ function pushText(nodes, value) {
1832
+ const last = nodes[nodes.length - 1];
1833
+ if (last?.type === "text") last.value += value;
1834
+ else nodes.push({ type: "text", value });
1835
+ }
1836
+ function parseInline(text, { links = true } = {}) {
1837
+ const nodes = [];
1838
+ let index = 0;
1839
+ while (index < text.length) {
1840
+ const char = text[index];
1841
+ const rest = text.slice(index);
1842
+ if (char === "\\" && PUNCTUATION.test(text[index + 1] ?? "")) {
1843
+ pushText(nodes, text[index + 1]);
1844
+ index += 2;
1845
+ continue;
1846
+ }
1847
+ if (char === "\n") {
1848
+ const hard = /( {2,}|\\)$/.test(text.slice(0, index));
1849
+ if (hard && nodes[nodes.length - 1]?.type === "text") {
1850
+ const last = nodes[nodes.length - 1];
1851
+ last.value = last.value.replace(/( {2,}|\\)$/, "");
1852
+ }
1853
+ if (hard) nodes.push({ type: "br" });
1854
+ else pushText(nodes, " ");
1855
+ index += 1;
1856
+ continue;
1857
+ }
1858
+ if (char === "`") {
1859
+ const run = /^`+/.exec(rest)[0];
1860
+ const closing = new RegExp(`(?<!\`)${run}(?!\`)`, "g");
1861
+ closing.lastIndex = index + run.length;
1862
+ const match = closing.exec(text);
1863
+ if (match) {
1864
+ let value = text.slice(index + run.length, match.index).replace(/\n/g, " ");
1865
+ if (/^ .* $/.test(value) && value.trim()) value = value.slice(1, -1);
1866
+ nodes.push({ type: "code", value });
1867
+ index = match.index + run.length;
1868
+ } else {
1869
+ pushText(nodes, run);
1870
+ index += run.length;
1871
+ }
1872
+ continue;
1873
+ }
1874
+ if (links && char === "[" || char === "!" && text[index + 1] === "[") {
1875
+ const image = char === "!";
1876
+ const open = image ? index + 1 : index;
1877
+ const close = closingBracket(text, open);
1878
+ const target = close !== -1 ? linkTarget2(text, close + 1) : null;
1879
+ if (target) {
1880
+ const label = text.slice(open + 1, close);
1881
+ nodes.push(
1882
+ image ? { type: "image", src: target.href, alt: label, title: target.title } : { type: "link", href: target.href, title: target.title, children: parseInline(label, { links: false }) }
1883
+ );
1884
+ index = target.end;
1885
+ continue;
1886
+ }
1887
+ }
1888
+ const autolink = links && char === "<" ? AUTOLINK.exec(rest) : null;
1889
+ if (autolink) {
1890
+ nodes.push({ type: "link", href: autolink[1], children: [{ type: "text", value: autolink[1].replace(/^mailto:/, "") }] });
1891
+ index += autolink[0].length;
1892
+ continue;
1893
+ }
1894
+ if (links && char === "h" && !/\w/.test(text[index - 1] ?? "")) {
1895
+ const url = BARE_URL.exec(rest);
1896
+ if (url) {
1897
+ nodes.push({ type: "link", href: url[0], children: [{ type: "text", value: url[0] }] });
1898
+ index += url[0].length;
1899
+ continue;
1900
+ }
1901
+ }
1902
+ const delimiter = ["**", "__", "~~"].find((item) => rest.startsWith(item)) ?? (char === "*" || char === "_" ? char : null);
1903
+ const leftFlanking = delimiter && rest[delimiter.length] && !/\s/.test(rest[delimiter.length]);
1904
+ const wordBefore = /\w/.test(text[index - 1] ?? "");
1905
+ if (delimiter && leftFlanking && !(delimiter[0] === "_" && wordBefore)) {
1906
+ const end = closingDelimiter(text, delimiter, index + delimiter.length);
1907
+ if (end !== -1) {
1908
+ const type = delimiter === "~~" ? "del" : delimiter.length === 2 ? "strong" : "em";
1909
+ nodes.push({ type, children: parseInline(text.slice(index + delimiter.length, end), { links }) });
1910
+ index = end + delimiter.length;
1911
+ continue;
1912
+ }
1913
+ }
1914
+ pushText(nodes, delimiter && !leftFlanking ? delimiter : char);
1915
+ index += delimiter && !leftFlanking ? delimiter.length : 1;
1916
+ }
1917
+ return nodes;
1918
+ }
1919
+ function normalizeTag(tag) {
1920
+ return tag.trim().replace("_", "-").toLowerCase();
1921
+ }
1922
+ function matches(tag, locale) {
1923
+ return tag === locale || tag.split("-")[0] === locale.split("-")[0];
1924
+ }
1925
+ function selectLocale(blocks, locale, fallbacks = ["en"]) {
1926
+ const result = [];
1927
+ let index = 0;
1928
+ while (index < blocks.length) {
1929
+ const block = blocks[index];
1930
+ if (block.type !== "lang") {
1931
+ result.push(block);
1932
+ index += 1;
1933
+ continue;
1934
+ }
1935
+ const group = [];
1936
+ while (index < blocks.length && blocks[index].type === "lang") group.push(blocks[index++]);
1937
+ const target = normalizeTag(locale);
1938
+ const chosen = group.find((item) => item.locales.some((tag) => tag === target)) ?? group.find((item) => item.locales.some((tag) => matches(tag, target))) ?? fallbacks.map((fallback) => group.find((item) => item.locales.some((tag) => matches(tag, normalizeTag(fallback))))).find(Boolean) ?? group[0];
1939
+ result.push({
1940
+ type: "lang-selected",
1941
+ locale: chosen.locales.find((tag) => matches(tag, target)) ?? chosen.locales[0],
1942
+ children: selectLocale(chosen.children, locale, fallbacks)
1943
+ });
1944
+ }
1945
+ return result;
1946
+ }
1947
+ function parseMarkdown(source) {
1948
+ if (!source) return [];
1949
+ return parseBlocks(expandTabs(String(source).replace(/\r\n?/g, "\n")).split("\n"));
1950
+ }
1951
+ function safeUrl(url, { image = false } = {}) {
1952
+ const value = String(url ?? "").trim();
1953
+ if (/^(https?:|\/(?!\/)|#|\.{1,2}\/)/i.test(value)) return value;
1954
+ if (!image && /^mailto:/i.test(value)) return value;
1955
+ if (!/^[a-z][a-z0-9+.-]*:/i.test(value) && !value.startsWith("//")) return value;
1956
+ return null;
1957
+ }
1958
+
1959
+ // src/highlight.ts
1960
+ var STRING_DOUBLE = /"(?:\\.|[^"\\\n])*"/y;
1961
+ var STRING_SINGLE = /'(?:\\.|[^'\\])*'/y;
1962
+ var NUMBER = /-?\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/y;
1963
+ var words = (list) => new RegExp(`\\b(?:${list.join("|")})\\b`, "y");
1964
+ var LANGUAGES2 = {
1965
+ json: [
1966
+ ["key", /"(?:\\.|[^"\\\n])*"(?=\s*:)/y],
1967
+ ["string", STRING_DOUBLE],
1968
+ ["number", NUMBER],
1969
+ ["literal", words(["true", "false", "null"])]
1970
+ ],
1971
+ shell: [
1972
+ ["comment", /#[^\n]*/y],
1973
+ // No escapes inside single quotes in shell; '\'' closes the string, adds
1974
+ // an escaped quote and reopens, so the backslash escape is its own token.
1975
+ ["string", /\\./y],
1976
+ ["string", /'[^']*'/y],
1977
+ ["string", STRING_DOUBLE],
1978
+ ["keyword", /(?<![\w-])(?:curl|wget|http|printf)\b/y],
1979
+ ["attr", /(?<![\w-])--?[a-zA-Z][\w-]*/y],
1980
+ ["variable", /\$\{?\w+\}?/y]
1981
+ ],
1982
+ javascript: [
1983
+ ["comment", /\/\/[^\n]*|\/\*[\s\S]*?\*\//y],
1984
+ ["string", /`(?:\\.|[^`\\])*`/y],
1985
+ ["key", /"(?:\\.|[^"\\\n])*"(?=\s*:)/y],
1986
+ ["string", STRING_DOUBLE],
1987
+ ["string", STRING_SINGLE],
1988
+ ["key", /\b[A-Za-z_$][\w$]*(?=\s*:(?!:))/y],
1989
+ ["keyword", words(["const", "let", "var", "await", "async", "function", "return", "new", "if", "else", "import", "from", "export"])],
1990
+ ["literal", words(["true", "false", "null", "undefined"])],
1991
+ ["function", /\b[A-Za-z_$][\w$]*(?=\s*\()/y],
1992
+ ["number", NUMBER]
1993
+ ],
1994
+ php: [
1995
+ ["comment", /\/\/[^\n]*|#[^\n]*|\/\*[\s\S]*?\*\//y],
1996
+ ["keyword", /<\?php|\?>/y],
1997
+ ["string", STRING_DOUBLE],
1998
+ ["string", STRING_SINGLE],
1999
+ ["variable", /\$\w+/y],
2000
+ ["constant", /\b[A-Z][A-Z0-9_]{2,}\b/y],
2001
+ ["keyword", words(["echo", "return", "new", "function", "if", "else", "use", "array"])],
2002
+ ["literal", words(["true", "false", "null"])],
2003
+ ["function", /\b[A-Za-z_]\w*(?=\s*\()/y],
2004
+ ["number", NUMBER]
2005
+ ],
2006
+ python: [
2007
+ ["comment", /#[^\n]*/y],
2008
+ ["string", STRING_DOUBLE],
2009
+ ["string", STRING_SINGLE],
2010
+ ["keyword", words(["import", "from", "as", "def", "return", "if", "else", "for", "in", "print", "with"])],
2011
+ ["literal", words(["True", "False", "None"])],
2012
+ ["attr", /\b[a-z_]\w*(?==)/y],
2013
+ ["function", /\b[A-Za-z_]\w*(?=\s*\()/y],
2014
+ ["number", NUMBER]
2015
+ ]
2016
+ };
2017
+ var C_COMMENT = /\/\/[^\n]*|\/\*[\s\S]*?\*\//y;
2018
+ var TRIPLE_DOUBLE = /"""[\s\S]*?"""/y;
2019
+ var TYPE = /\b[A-Z][a-z]\w*\b/y;
2020
+ var CALL = /\b[A-Za-z_]\w*(?=\s*\()/y;
2021
+ function cFamily({
2022
+ keywords,
2023
+ literals = ["true", "false", "null"],
2024
+ strings = [],
2025
+ extra = []
2026
+ }) {
2027
+ return [
2028
+ ["comment", C_COMMENT],
2029
+ ...strings.map((regex) => ["string", regex]),
2030
+ ["string", STRING_DOUBLE],
2031
+ ["string", STRING_SINGLE],
2032
+ ...extra,
2033
+ ["keyword", words(keywords)],
2034
+ ["literal", words(literals)],
2035
+ ["function", CALL],
2036
+ ["type", TYPE],
2037
+ ["number", NUMBER]
2038
+ ];
2039
+ }
2040
+ Object.assign(LANGUAGES2, {
2041
+ go: cFamily({
2042
+ keywords: ["package", "import", "func", "var", "const", "if", "else", "return", "defer", "for", "range", "type", "struct", "go", "map", "chan"],
2043
+ literals: ["true", "false", "nil"],
2044
+ strings: [/`[^`]*`/y]
2045
+ }),
2046
+ java: cFamily({
2047
+ keywords: ["import", "package", "new", "public", "private", "class", "static", "void", "final", "var", "return", "throws", "try", "catch"],
2048
+ strings: [TRIPLE_DOUBLE]
2049
+ }),
2050
+ kotlin: cFamily({
2051
+ keywords: ["import", "val", "var", "fun", "return", "if", "else", "class", "object"],
2052
+ strings: [TRIPLE_DOUBLE]
2053
+ }),
2054
+ csharp: cFamily({
2055
+ keywords: ["using", "var", "new", "await", "async", "return", "public", "class", "static", "void"],
2056
+ strings: [TRIPLE_DOUBLE]
2057
+ }),
2058
+ swift: cFamily({
2059
+ keywords: ["import", "let", "var", "try", "await", "func", "return", "if", "else"],
2060
+ literals: ["true", "false", "nil"],
2061
+ strings: [TRIPLE_DOUBLE]
2062
+ }),
2063
+ dart: cFamily({
2064
+ keywords: ["import", "as", "final", "var", "void", "async", "await", "return"],
2065
+ strings: [/r?'''[\s\S]*?'''/y]
2066
+ }),
2067
+ rust: cFamily({
2068
+ keywords: ["use", "let", "mut", "fn", "async", "await", "pub", "struct", "impl", "match", "return"],
2069
+ strings: [/r(#+)"[\s\S]*?"\1/y],
2070
+ extra: [
2071
+ ["attr", /#\[[^\]]*\]/y],
2072
+ ["function", /\b[a-z_]\w*!/y]
2073
+ ]
2074
+ }),
2075
+ c: cFamily({
2076
+ keywords: ["int", "char", "void", "struct", "return", "if", "else", "const", "static"],
2077
+ literals: ["NULL"],
2078
+ extra: [
2079
+ ["keyword", /#\w+(?:\s+<[^>\n]*>)?/y],
2080
+ ["constant", /\b[A-Z][A-Z0-9_]{2,}\b/y]
2081
+ ]
2082
+ }),
2083
+ ruby: [
2084
+ ["comment", /#[^\n]*/y],
2085
+ ["string", STRING_DOUBLE],
2086
+ ["string", STRING_SINGLE],
2087
+ ["literal", /:\w+/y],
2088
+ ["keyword", words(["require", "def", "end", "do", "if", "else", "puts", "return", "new"])],
2089
+ ["literal", words(["true", "false", "nil"])],
2090
+ ["type", TYPE],
2091
+ ["number", NUMBER]
2092
+ ],
2093
+ powershell: [
2094
+ ["comment", /#[^\n]*/y],
2095
+ ["string", /@'[\s\S]*?'@|@"[\s\S]*?"@/y],
2096
+ ["string", /'(?:''|[^'])*'/y],
2097
+ ["string", STRING_DOUBLE],
2098
+ ["literal", /\$(?:true|false|null)\b/y],
2099
+ ["variable", /\$\w+/y],
2100
+ ["function", /\b[A-Z][a-z]+-[A-Z][A-Za-z]+\b/y],
2101
+ ["attr", /(?<![\w-])-[A-Za-z]+/y],
2102
+ ["number", NUMBER]
2103
+ ],
2104
+ // Request line, header names, then JSON-ish body tokens.
2105
+ http: [
2106
+ ["keyword", /^[A-Z]+(?= \S+ HTTP\/)/my],
2107
+ ["attr", /HTTP\/\d(?:\.\d)?/y],
2108
+ ["key", /^[\w-]+(?=:)/my],
2109
+ ["key", /"(?:\\.|[^"\\\n])*"(?=\s*:)/y],
2110
+ ["string", STRING_DOUBLE],
2111
+ ["literal", words(["true", "false", "null"])],
2112
+ ["number", NUMBER]
2113
+ ]
2114
+ });
2115
+ LANGUAGES2.curl = LANGUAGES2.shell;
2116
+ function tokenize(code, language) {
2117
+ const rules = LANGUAGES2[language];
2118
+ if (!rules) return [{ type: null, text: code }];
2119
+ const tokens = [];
2120
+ let plain = "";
2121
+ let index = 0;
2122
+ outer: while (index < code.length) {
2123
+ for (const [type, regex] of rules) {
2124
+ regex.lastIndex = index;
2125
+ const match = regex.exec(code);
2126
+ if (match && match[0].length > 0) {
2127
+ if (plain) {
2128
+ tokens.push({ type: null, text: plain });
2129
+ plain = "";
2130
+ }
2131
+ tokens.push({ type, text: match[0] });
2132
+ index += match[0].length;
2133
+ continue outer;
2134
+ }
2135
+ }
2136
+ const word = /[\w$]+|[^\w$]/y;
2137
+ word.lastIndex = index;
2138
+ const chunk = word.exec(code)[0];
2139
+ plain += chunk;
2140
+ index += chunk.length;
2141
+ }
2142
+ if (plain) tokens.push({ type: null, text: plain });
2143
+ return tokens;
2144
+ }
2145
+
2146
+ // src/security.ts
2147
+ function securityRequirements(operation) {
2148
+ return (operation.security ?? []).map((requirement) => ({
2149
+ schemes: Object.keys(requirement),
2150
+ scopes: requirement
2151
+ }));
2152
+ }
2153
+ function base64(text) {
2154
+ let binary = "";
2155
+ for (const byte of new TextEncoder().encode(text)) binary += String.fromCharCode(byte);
2156
+ return btoa(binary);
2157
+ }
2158
+ function hasCredential(scheme, credential) {
2159
+ if (!scheme || !credential) return false;
2160
+ if (scheme.type === "http" && String(scheme.scheme).toLowerCase() === "basic") return Boolean(credential.username || credential.password);
2161
+ return Boolean(credential.token);
2162
+ }
2163
+ function applyScheme(parts, scheme, credential) {
2164
+ if (scheme.type === "http") {
2165
+ const kind = String(scheme.scheme ?? "").toLowerCase();
2166
+ if (kind === "basic") parts.headers.Authorization = `Basic ${base64(`${credential.username ?? ""}:${credential.password ?? ""}`)}`;
2167
+ else if (kind === "bearer") parts.headers.Authorization = `Bearer ${credential.token}`;
2168
+ else parts.headers.Authorization = `${scheme.scheme} ${credential.token}`;
2169
+ } else if (scheme.type === "apiKey") {
2170
+ const target = scheme.in === "query" ? parts.query : scheme.in === "cookie" ? parts.cookies : parts.headers;
2171
+ target[scheme.name] = credential.token ?? "";
2172
+ } else if (scheme.type === "oauth2" || scheme.type === "openIdConnect") {
2173
+ parts.headers.Authorization = `Bearer ${credential.token}`;
2174
+ }
2175
+ }
2176
+ function applySecurity(schemes, requirements, credentials) {
2177
+ const parts = { headers: {}, query: {}, cookies: {} };
2178
+ const usable = requirements.find(
2179
+ (requirement) => requirement.schemes.length > 0 && requirement.schemes.every((name) => hasCredential(schemes[name], credentials[name]))
2180
+ );
2181
+ for (const name of usable?.schemes ?? []) applyScheme(parts, schemes[name], credentials[name]);
2182
+ return parts;
2183
+ }
2184
+ function describeScheme(scheme) {
2185
+ if (scheme.type === "http") {
2186
+ const kind = String(scheme.scheme ?? "");
2187
+ return kind.toLowerCase() === "bearer" ? `Bearer${scheme.bearerFormat ? ` (${scheme.bearerFormat})` : ""}` : `HTTP ${kind}`;
2188
+ }
2189
+ if (scheme.type === "apiKey") return `API key (${scheme.in}: ${scheme.name})`;
2190
+ if (scheme.type === "oauth2") return `OAuth 2.0 (${Object.keys(scheme.flows ?? {}).join(", ")})`;
2191
+ if (scheme.type === "openIdConnect") return "OpenID Connect";
2192
+ if (scheme.type === "mutualTLS") return "Mutual TLS";
2193
+ return String(scheme.type ?? "");
2194
+ }
2195
+ var TOKEN_FLOWS = ["clientCredentials", "password"];
2196
+ function buildTokenRequest(flowName, flow, credential) {
2197
+ const params = new URLSearchParams({ grant_type: flowName === "password" ? "password" : "client_credentials" });
2198
+ if (flowName === "password") {
2199
+ params.set("username", credential.username ?? "");
2200
+ params.set("password", credential.password ?? "");
2201
+ }
2202
+ if (credential.scopes?.trim()) params.set("scope", credential.scopes.trim());
2203
+ const headers = { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" };
2204
+ if (credential.clientId) headers.Authorization = `Basic ${base64(`${credential.clientId}:${credential.clientSecret ?? ""}`)}`;
2205
+ return { method: "POST", url: String(flow.tokenUrl ?? ""), headers, body: params.toString() };
2206
+ }
2207
+
2208
+ // src/convert.ts
2209
+ var REF_PREFIXES = [
2210
+ ["#/definitions/", "#/components/schemas/"],
2211
+ ["#/responses/", "#/components/responses/"]
2212
+ ];
2213
+ var SCHEMA_KEYS = [
2214
+ "format",
2215
+ "items",
2216
+ "enum",
2217
+ "default",
2218
+ "minimum",
2219
+ "maximum",
2220
+ "exclusiveMinimum",
2221
+ "exclusiveMaximum",
2222
+ "minLength",
2223
+ "maxLength",
2224
+ "pattern",
2225
+ "minItems",
2226
+ "maxItems",
2227
+ "uniqueItems",
2228
+ "multipleOf"
2229
+ ];
2230
+ var FORM_TYPES = ["application/x-www-form-urlencoded", "multipart/form-data"];
2231
+ function convertRef(ref, bodyParameters) {
2232
+ if (ref.startsWith("#/parameters/")) {
2233
+ const name = ref.slice("#/parameters/".length);
2234
+ return bodyParameters.has(name) ? `#/components/requestBodies/${name}` : `#/components/parameters/${name}`;
2235
+ }
2236
+ for (const [from, to] of REF_PREFIXES) if (ref.startsWith(from)) return to + ref.slice(from.length);
2237
+ return ref;
2238
+ }
2239
+ function convertSchema(schema) {
2240
+ if (!schema || typeof schema !== "object") return schema;
2241
+ if (Array.isArray(schema)) return schema.map(convertSchema);
2242
+ const result = {};
2243
+ for (const [key, value] of Object.entries(schema)) {
2244
+ switch (key) {
2245
+ case "$ref":
2246
+ result.$ref = convertRef(String(value), /* @__PURE__ */ new Set());
2247
+ break;
2248
+ case "x-nullable":
2249
+ if (value) result.nullable = true;
2250
+ break;
2251
+ case "discriminator":
2252
+ result.discriminator = typeof value === "string" ? { propertyName: value } : value;
2253
+ break;
2254
+ case "properties":
2255
+ case "patternProperties":
2256
+ result[key] = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, convertSchema(child)]));
2257
+ break;
2258
+ case "items":
2259
+ case "additionalProperties":
2260
+ case "not":
2261
+ result[key] = typeof value === "object" ? convertSchema(value) : value;
2262
+ break;
2263
+ case "allOf":
2264
+ case "anyOf":
2265
+ case "oneOf":
2266
+ result[key] = value.map(convertSchema);
2267
+ break;
2268
+ default:
2269
+ result[key] = value;
2270
+ }
2271
+ }
2272
+ if (result.type === "file") {
2273
+ result.type = "string";
2274
+ result.format = "binary";
2275
+ }
2276
+ return result;
2277
+ }
2278
+ function convertParameter(parameter) {
2279
+ const { type, collectionFormat, "x-example": example, allowEmptyValue, ...rest } = parameter;
2280
+ const schema = type === "file" ? { type: "string", format: "binary" } : { type };
2281
+ const result = {};
2282
+ for (const [key, value] of Object.entries(rest)) {
2283
+ if (SCHEMA_KEYS.includes(key)) schema[key] = key === "items" ? convertSchema(value) : value;
2284
+ else result[key] = value;
2285
+ }
2286
+ result.schema = convertSchema(schema);
2287
+ if (example !== void 0) result.example = example;
2288
+ if (allowEmptyValue) result.allowEmptyValue = true;
2289
+ if (type === "array") {
2290
+ const format = collectionFormat ?? "csv";
2291
+ if (format === "multi") Object.assign(result, { style: "form", explode: true });
2292
+ else if (format === "ssv") Object.assign(result, { style: "spaceDelimited", explode: false });
2293
+ else if (format === "pipes") Object.assign(result, { style: "pipeDelimited", explode: false });
2294
+ else Object.assign(result, { style: parameter.in === "query" || parameter.in === "cookie" ? "form" : "simple", explode: false });
2295
+ }
2296
+ return result;
2297
+ }
2298
+ function bodyContent(schema, types, description, required) {
2299
+ const body = { content: Object.fromEntries(types.map((type) => [type, { schema: convertSchema(schema) }])) };
2300
+ if (description) body.description = description;
2301
+ if (required) body.required = true;
2302
+ return body;
2303
+ }
2304
+ function formBody(parameters, consumes) {
2305
+ const types = consumes.filter((type) => FORM_TYPES.includes(type));
2306
+ const hasFile = parameters.some((parameter) => parameter.type === "file");
2307
+ const contentTypes = types.length ? types : [hasFile ? "multipart/form-data" : "application/x-www-form-urlencoded"];
2308
+ const schema = { type: "object", properties: {} };
2309
+ const required = [];
2310
+ for (const parameter of parameters) {
2311
+ const { schema: propertySchema } = convertParameter({ ...parameter, in: "query" });
2312
+ if (parameter.description) propertySchema.description = parameter.description;
2313
+ schema.properties[parameter.name] = propertySchema;
2314
+ if (parameter.required) required.push(parameter.name);
2315
+ }
2316
+ if (required.length) schema.required = required;
2317
+ return { content: Object.fromEntries(contentTypes.map((type) => [type, { schema }])) };
2318
+ }
2319
+ function convertResponse(response, produces) {
2320
+ if (response.$ref) return { $ref: convertRef(response.$ref, /* @__PURE__ */ new Set()) };
2321
+ const { schema, examples, headers, ...rest } = response;
2322
+ const result = { ...rest, description: rest.description ?? "" };
2323
+ if (headers) {
2324
+ result.headers = Object.fromEntries(
2325
+ Object.entries(headers).map(([name, header]) => {
2326
+ const { schema: headerSchema, description } = convertParameter({ ...header, in: "header" });
2327
+ return [name, { ...description ? { description } : {}, schema: headerSchema }];
2328
+ })
2329
+ );
2330
+ }
2331
+ if (schema) {
2332
+ const types = produces.length ? produces : ["application/json"];
2333
+ result.content = Object.fromEntries(
2334
+ types.map((type) => [type, { schema: convertSchema(schema), ...examples?.[type] !== void 0 ? { example: examples[type] } : {} }])
2335
+ );
2336
+ }
2337
+ return result;
2338
+ }
2339
+ function convertSecurityScheme(scheme) {
2340
+ const description = scheme.description ? { description: scheme.description } : {};
2341
+ if (scheme.type === "basic") return { type: "http", scheme: "basic", ...description };
2342
+ if (scheme.type === "apiKey") return { type: "apiKey", name: scheme.name, in: scheme.in, ...description };
2343
+ if (scheme.type === "oauth2") {
2344
+ const scopes = scheme.scopes ?? {};
2345
+ const flow = {
2346
+ implicit: { implicit: { authorizationUrl: scheme.authorizationUrl, scopes } },
2347
+ password: { password: { tokenUrl: scheme.tokenUrl, scopes } },
2348
+ application: { clientCredentials: { tokenUrl: scheme.tokenUrl, scopes } },
2349
+ accessCode: { authorizationCode: { authorizationUrl: scheme.authorizationUrl, tokenUrl: scheme.tokenUrl, scopes } }
2350
+ }[scheme.flow] ?? {};
2351
+ return { type: "oauth2", flows: flow, ...description };
2352
+ }
2353
+ return { ...scheme };
2354
+ }
2355
+ var resolveParameter = (doc, parameter) => parameter.$ref?.startsWith("#/parameters/") ? doc.parameters?.[parameter.$ref.slice("#/parameters/".length)] ?? parameter : parameter;
2356
+ function convertSwagger2(doc) {
2357
+ const bodyParameters = new Set(
2358
+ Object.entries(doc.parameters ?? {}).filter(([, parameter]) => parameter.in === "body").map(([name]) => name)
2359
+ );
2360
+ const globalConsumes = doc.consumes ?? ["application/json"];
2361
+ const globalProduces = doc.produces ?? ["application/json"];
2362
+ const schemes = doc.schemes?.length ? doc.schemes : ["https"];
2363
+ const servers = doc.host ? schemes.map((scheme) => ({ url: `${scheme}://${doc.host}${doc.basePath ?? ""}` })) : [{ url: doc.basePath ?? "/" }];
2364
+ const components = {};
2365
+ if (doc.definitions) {
2366
+ components.schemas = Object.fromEntries(Object.entries(doc.definitions).map(([name, schema]) => [name, convertSchema(schema)]));
2367
+ }
2368
+ if (doc.parameters) {
2369
+ for (const [name, parameter] of Object.entries(doc.parameters)) {
2370
+ if (parameter.in === "body") {
2371
+ (components.requestBodies ??= {})[name] = bodyContent(parameter.schema, globalConsumes, parameter.description, parameter.required);
2372
+ } else if (parameter.in !== "formData") {
2373
+ (components.parameters ??= {})[name] = convertParameter(parameter);
2374
+ }
2375
+ }
2376
+ }
2377
+ if (doc.responses) {
2378
+ components.responses = Object.fromEntries(
2379
+ Object.entries(doc.responses).map(([name, response]) => [name, convertResponse(response, globalProduces)])
2380
+ );
2381
+ }
2382
+ if (doc.securityDefinitions) {
2383
+ components.securitySchemes = Object.fromEntries(
2384
+ Object.entries(doc.securityDefinitions).map(([name, scheme]) => [name, convertSecurityScheme(scheme)])
2385
+ );
2386
+ }
2387
+ const paths = {};
2388
+ for (const [path2, item] of Object.entries(doc.paths ?? {})) {
2389
+ const pathParameters = item.parameters ?? [];
2390
+ const pathItem = {};
2391
+ for (const [key, value] of Object.entries(item)) {
2392
+ if (key === "parameters" || typeof value !== "object" || !["get", "put", "post", "delete", "options", "head", "patch"].includes(key)) {
2393
+ if (key !== "parameters") pathItem[key] = value;
2394
+ continue;
2395
+ }
2396
+ const operation = value;
2397
+ const { parameters = [], consumes, produces, responses = {}, ...rest } = operation;
2398
+ const opConsumes = consumes ?? globalConsumes;
2399
+ const opProduces = produces ?? globalProduces;
2400
+ const converted = { ...rest };
2401
+ const merged = /* @__PURE__ */ new Map();
2402
+ for (const raw of [...pathParameters, ...parameters]) {
2403
+ const resolved = resolveParameter(doc, raw);
2404
+ merged.set(`${resolved.in}:${resolved.name}`, raw);
2405
+ }
2406
+ const formData2 = [];
2407
+ const outParameters = [];
2408
+ for (const raw of merged.values()) {
2409
+ const resolved = resolveParameter(doc, raw);
2410
+ if (resolved.in === "body") {
2411
+ converted.requestBody = raw.$ref ? { $ref: convertRef(raw.$ref, bodyParameters) } : bodyContent(resolved.schema, opConsumes.filter((type) => !FORM_TYPES.includes(type)).length ? opConsumes.filter((type) => !FORM_TYPES.includes(type)) : ["application/json"], resolved.description, resolved.required);
2412
+ } else if (resolved.in === "formData") {
2413
+ formData2.push(resolved);
2414
+ } else {
2415
+ outParameters.push(raw.$ref ? { $ref: convertRef(raw.$ref, bodyParameters) } : convertParameter(raw));
2416
+ }
2417
+ }
2418
+ if (formData2.length) converted.requestBody = formBody(formData2, opConsumes);
2419
+ if (outParameters.length) converted.parameters = outParameters;
2420
+ converted.responses = Object.fromEntries(
2421
+ Object.entries(responses).map(([status, response]) => [status, convertResponse(response, opProduces)])
2422
+ );
2423
+ pathItem[key] = converted;
2424
+ }
2425
+ paths[path2] = pathItem;
2426
+ }
2427
+ const result = { openapi: "3.0.3", info: doc.info ?? { title: "API", version: "" }, servers, paths };
2428
+ for (const key of ["tags", "security", "externalDocs"]) if (doc[key] !== void 0) result[key] = doc[key];
2429
+ for (const [key, value] of Object.entries(doc)) if (key.startsWith("x-")) result[key] = value;
2430
+ if (Object.keys(components).length) result.components = components;
2431
+ return result;
2432
+ }
2433
+
2434
+ // src/parse.ts
2435
+ import { parse as parseYaml } from "yaml";
2436
+
2437
+ // src/external.ts
2438
+ var EXTERNAL_KEY = "x-oaspect-external";
2439
+ var isExternal = (ref) => !ref.startsWith("#");
2440
+ function hasExternalRefs(node) {
2441
+ if (!node || typeof node !== "object") return false;
2442
+ if (Array.isArray(node)) return node.some(hasExternalRefs);
2443
+ const ref = node.$ref;
2444
+ if (typeof ref === "string" && isExternal(ref)) return true;
2445
+ return Object.values(node).some(hasExternalRefs);
2446
+ }
2447
+ async function resolveExternalRefs(doc, { baseUrl, read, maxDocuments = 100 }) {
2448
+ if (!hasExternalRefs(doc)) return doc;
2449
+ const documents = /* @__PURE__ */ new Map();
2450
+ const hoisted = /* @__PURE__ */ new Map();
2451
+ const store = {};
2452
+ const usedKeys = /* @__PURE__ */ new Set();
2453
+ function load(url) {
2454
+ if (!documents.has(url)) {
2455
+ if (documents.size >= maxDocuments) throw new Error(`More than ${maxDocuments} external documents referenced`);
2456
+ documents.set(url, read(url).then((text) => parseSpec(text)));
2457
+ }
2458
+ return documents.get(url);
2459
+ }
2460
+ function keyFor(url, pointer) {
2461
+ const segment = pointer.split("/").filter(Boolean).pop() ?? url.split("/").pop().replace(/\.(ya?ml|json)$/i, "");
2462
+ const base = decodeURIComponent(segment.replace(/~1/g, "/").replace(/~0/g, "~")).replace(/[^\w.-]/g, "_") || "external";
2463
+ let key = base;
2464
+ for (let index = 2; usedKeys.has(key); index += 1) key = `${base}_${index}`;
2465
+ usedKeys.add(key);
2466
+ return key;
2467
+ }
2468
+ async function hoist(url, pointer) {
2469
+ const id = `${url}#${pointer}`;
2470
+ const existing = hoisted.get(id);
2471
+ if (existing) return existing;
2472
+ const key = keyFor(url, pointer);
2473
+ hoisted.set(id, key);
2474
+ const target = pointer ? resolvePointer(await load(url), `#${pointer}`) : await load(url);
2475
+ if (target === void 0) throw new Error(`${id} not found`);
2476
+ store[key] = await walk(target, url, false);
2477
+ return key;
2478
+ }
2479
+ async function walk(node, base, isRoot) {
2480
+ if (!node || typeof node !== "object") return node;
2481
+ if (Array.isArray(node)) return Promise.all(node.map((item) => walk(item, base, isRoot)));
2482
+ const object = node;
2483
+ if (typeof object.$ref === "string" && (isExternal(object.$ref) || !isRoot)) {
2484
+ const [file, pointer = ""] = object.$ref.split("#");
2485
+ const url = file ? new URL(file, base).href : base;
2486
+ const key = await hoist(url, pointer.startsWith("/") ? pointer : pointer ? `/${pointer}` : "");
2487
+ const { $ref: _ref, ...siblings } = object;
2488
+ return { ...await walk(siblings, base, isRoot), $ref: `#/components/${EXTERNAL_KEY}/${key}` };
2489
+ }
2490
+ const result = {};
2491
+ for (const [key, value] of Object.entries(object)) result[key] = await walk(value, base, isRoot);
2492
+ return result;
2493
+ }
2494
+ const resolved = await walk(doc, baseUrl, true);
2495
+ resolved.components = { ...resolved.components, [EXTERNAL_KEY]: store };
2496
+ return resolved;
2497
+ }
2498
+
2499
+ // src/parse.ts
2500
+ function parseSpec(text) {
2501
+ const trimmed = text.trimStart();
2502
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
2503
+ try {
2504
+ return JSON.parse(text);
2505
+ } catch (error) {
2506
+ throw new Error(`Invalid JSON: ${error.message}`);
2507
+ }
2508
+ }
2509
+ try {
2510
+ return parseYaml(text, { maxAliasCount: 1e3 });
2511
+ } catch (error) {
2512
+ throw new Error(`Invalid YAML: ${error.message}`);
2513
+ }
2514
+ }
2515
+ function isOpenApiDocument(value) {
2516
+ const doc = value;
2517
+ return Boolean(doc && typeof doc === "object" && (doc.openapi || doc.swagger) && doc.paths);
2518
+ }
2519
+ function normalizeSpec(doc) {
2520
+ return String(doc.swagger ?? "").startsWith("2") ? convertSwagger2(doc) : doc;
2521
+ }
2522
+ function loadSpecText(text) {
2523
+ const doc = parseSpec(text);
2524
+ if (!isOpenApiDocument(doc)) throw new Error('Not an OpenAPI document (missing "openapi"/"swagger" or "paths").');
2525
+ return normalizeSpec(doc);
2526
+ }
2527
+ async function loadSpec(text, options) {
2528
+ const doc = loadSpecText(text);
2529
+ if (!options?.read || !options.baseUrl) return doc;
2530
+ return resolveExternalRefs(doc, options);
2531
+ }
2532
+ export {
2533
+ EXTERNAL_KEY,
2534
+ HTTP_METHODS,
2535
+ SNIPPET_LANGUAGES,
2536
+ TOKEN_FLOWS,
2537
+ applySecurity,
2538
+ buildModel,
2539
+ buildRequest,
2540
+ buildTokenRequest,
2541
+ childrenOf,
2542
+ constraintsOf,
2543
+ convertSchema,
2544
+ convertSwagger2,
2545
+ defaultBody,
2546
+ defaultForm,
2547
+ defaultValues,
2548
+ deref,
2549
+ describeScheme,
2550
+ exampleFromSchema,
2551
+ formEncode,
2552
+ hasCredential,
2553
+ hasExternalRefs,
2554
+ inferType,
2555
+ isMultipart,
2556
+ isOpenApiDocument,
2557
+ jsonMediaType,
2558
+ linkTarget,
2559
+ loadSpec,
2560
+ loadSpecText,
2561
+ localize,
2562
+ mediaExample,
2563
+ mediaExamples,
2564
+ modelAnchor,
2565
+ normalizeSpec,
2566
+ parameterExample,
2567
+ parseBlocks,
2568
+ parseInline,
2569
+ parseMarkdown,
2570
+ parseSpec,
2571
+ refName,
2572
+ resolveExternalRefs,
2573
+ resolvePointer,
2574
+ resolveSchema,
2575
+ resolveSnippet,
2576
+ safeUrl,
2577
+ securityRequirements,
2578
+ selectLocale,
2579
+ serverUrl,
2580
+ slugify,
2581
+ tagAnchor,
2582
+ tokenize,
2583
+ typeLabel
2584
+ };
2585
+ //# sourceMappingURL=index.js.map