saturndocs 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/LICENSE +21 -0
- package/dist/auth-FRCFGNYT.js +14 -0
- package/dist/brokenLinks-TTOBP4P7.js +48 -0
- package/dist/build-F5PWGP57.js +39 -0
- package/dist/chunk-3P2OFTXR.js +71 -0
- package/dist/chunk-3V753MRI.js +100 -0
- package/dist/chunk-5KX4ZK5E.js +104 -0
- package/dist/chunk-CMNX5DLQ.js +119 -0
- package/dist/chunk-GYRVGWDM.js +3499 -0
- package/dist/chunk-I6U4V7B4.js +1552 -0
- package/dist/chunk-J6P3VGGE.js +21 -0
- package/dist/chunk-KGJESHJC.js +37 -0
- package/dist/chunk-M2BZEDAS.js +57 -0
- package/dist/chunk-N7QPZMLP.js +82 -0
- package/dist/chunk-OEAEX5YW.js +51 -0
- package/dist/chunk-OZWTXMO3.js +584 -0
- package/dist/chunk-QLFODLVN.js +46 -0
- package/dist/chunk-R3X2DPFF.js +568 -0
- package/dist/chunk-S45UWCML.js +588 -0
- package/dist/chunk-SABK3R2P.js +2452 -0
- package/dist/chunk-STCCGFKC.js +246 -0
- package/dist/chunk-TKISMN3P.js +39 -0
- package/dist/chunk-U7PKMSB3.js +465 -0
- package/dist/chunk-VNYDYHXM.js +22 -0
- package/dist/chunk-VXEUNRVA.js +26 -0
- package/dist/chunk-XO4CUC7V.js +99 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +95 -0
- package/dist/deploy-QU7DCKWU.js +11 -0
- package/dist/dev-VDSDCBO2.js +43 -0
- package/dist/index.d.ts +382 -0
- package/dist/index.js +191 -0
- package/dist/init-7T5TEPBH.js +14 -0
- package/dist/manage-MKH27U3B.js +12 -0
- package/dist/openapiCheck-KGBQJTIQ.js +66 -0
- package/dist/pages-HIPXRLSY.js +15 -0
- package/dist/read-DMSJUEDA.js +160 -0
- package/dist/read-ZEVUZNNB.js +146 -0
- package/dist/requests-H5MIGBIS.js +13 -0
- package/dist/schema-XJUEZSIW.js +13 -0
- package/dist/sites-I4WI2MPG.js +14 -0
- package/dist/status-7R3NOI5H.js +14 -0
- package/dist/suggestions-4WFQ3APX.js +739 -0
- package/dist/validate-VXL4PL42.js +30 -0
- package/package.json +68 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
// ../openapi/dist/index.js
|
|
2
|
+
import { parse as parseYaml } from "yaml";
|
|
3
|
+
var nodeImport = async (specifier) => await import(specifier);
|
|
4
|
+
var HTTP_METHODS = [
|
|
5
|
+
"get",
|
|
6
|
+
"post",
|
|
7
|
+
"put",
|
|
8
|
+
"patch",
|
|
9
|
+
"delete",
|
|
10
|
+
"head",
|
|
11
|
+
"options",
|
|
12
|
+
"trace"
|
|
13
|
+
];
|
|
14
|
+
var MAX_REF_DEPTH = 40;
|
|
15
|
+
var SCHEMA_REF = /* @__PURE__ */ Symbol("schemaRef");
|
|
16
|
+
function isRecord(value) {
|
|
17
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18
|
+
}
|
|
19
|
+
function withSchemaRef(value, ref) {
|
|
20
|
+
if (!isRecord(value)) return value;
|
|
21
|
+
Object.defineProperty(value, SCHEMA_REF, { value: ref, enumerable: false, configurable: true });
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
function decodePointerToken(token) {
|
|
25
|
+
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
26
|
+
}
|
|
27
|
+
function lookupPointer(root, ref) {
|
|
28
|
+
const pointer = ref.slice(1);
|
|
29
|
+
const tokens = pointer.split("/").filter((segment) => segment.length > 0);
|
|
30
|
+
let current = root;
|
|
31
|
+
for (const rawToken of tokens) {
|
|
32
|
+
const token = decodePointerToken(rawToken);
|
|
33
|
+
if (isRecord(current)) {
|
|
34
|
+
current = current[token];
|
|
35
|
+
} else if (Array.isArray(current)) {
|
|
36
|
+
current = current[Number(token)];
|
|
37
|
+
} else {
|
|
38
|
+
current = void 0;
|
|
39
|
+
}
|
|
40
|
+
if (current === void 0) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`OpenAPI specification contains an unresolvable reference: "${ref}"`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return current;
|
|
47
|
+
}
|
|
48
|
+
function parseDocument(source, filePath) {
|
|
49
|
+
let root;
|
|
50
|
+
try {
|
|
51
|
+
root = parseYaml(source);
|
|
52
|
+
} catch (cause) {
|
|
53
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
54
|
+
const suffix = filePath ? ` in ${filePath}` : "";
|
|
55
|
+
throw new Error(`Failed to parse OpenAPI specification${suffix}: ${message}`);
|
|
56
|
+
}
|
|
57
|
+
if (!isRecord(root)) {
|
|
58
|
+
const suffix = filePath ? ` in ${filePath}` : "";
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Failed to parse OpenAPI specification${suffix}: the document is empty or not an object.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return root;
|
|
64
|
+
}
|
|
65
|
+
function splitRef(ref) {
|
|
66
|
+
const hashIndex = ref.indexOf("#");
|
|
67
|
+
if (hashIndex === -1) return { filePart: ref, pointer: "" };
|
|
68
|
+
return {
|
|
69
|
+
filePart: ref.slice(0, hashIndex),
|
|
70
|
+
pointer: ref.slice(hashIndex)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function isHttpRef(ref) {
|
|
74
|
+
return /^https?:\/\//i.test(ref);
|
|
75
|
+
}
|
|
76
|
+
function isAbsolutePath(path) {
|
|
77
|
+
return path.startsWith("/");
|
|
78
|
+
}
|
|
79
|
+
function normalizePath(path) {
|
|
80
|
+
const absolute = isAbsolutePath(path);
|
|
81
|
+
const parts = [];
|
|
82
|
+
for (const part of path.split("/")) {
|
|
83
|
+
if (part === "" || part === ".") continue;
|
|
84
|
+
if (part === "..") {
|
|
85
|
+
if (parts.length > 0 && parts[parts.length - 1] !== "..") {
|
|
86
|
+
parts.pop();
|
|
87
|
+
} else if (!absolute) {
|
|
88
|
+
parts.push("..");
|
|
89
|
+
}
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
parts.push(part);
|
|
93
|
+
}
|
|
94
|
+
const normalized = parts.join("/");
|
|
95
|
+
if (absolute) return `/${normalized}`;
|
|
96
|
+
return normalized || ".";
|
|
97
|
+
}
|
|
98
|
+
function resolvePath(...paths) {
|
|
99
|
+
let out = "";
|
|
100
|
+
for (const path of paths) {
|
|
101
|
+
if (!path) continue;
|
|
102
|
+
if (isAbsolutePath(path)) {
|
|
103
|
+
out = path;
|
|
104
|
+
} else {
|
|
105
|
+
out = out ? `${out}/${path}` : path;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!isAbsolutePath(out)) out = `${process.cwd()}/${out}`;
|
|
109
|
+
return normalizePath(out);
|
|
110
|
+
}
|
|
111
|
+
function dirnamePath(path) {
|
|
112
|
+
const normalized = normalizePath(path);
|
|
113
|
+
const index = normalized.lastIndexOf("/");
|
|
114
|
+
if (index <= 0) return isAbsolutePath(normalized) ? "/" : ".";
|
|
115
|
+
return normalized.slice(0, index);
|
|
116
|
+
}
|
|
117
|
+
function relativePath(from, to) {
|
|
118
|
+
const fromParts = normalizePath(from).split("/").filter(Boolean);
|
|
119
|
+
const toParts = normalizePath(to).split("/").filter(Boolean);
|
|
120
|
+
let common = 0;
|
|
121
|
+
while (common < fromParts.length && common < toParts.length && fromParts[common] === toParts[common]) {
|
|
122
|
+
common += 1;
|
|
123
|
+
}
|
|
124
|
+
return [
|
|
125
|
+
...Array.from({ length: fromParts.length - common }, () => ".."),
|
|
126
|
+
...toParts.slice(common)
|
|
127
|
+
].join("/") || "";
|
|
128
|
+
}
|
|
129
|
+
function isInsideRoot(rootDir, filePath) {
|
|
130
|
+
const rel = relativePath(rootDir, filePath);
|
|
131
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolutePath(rel);
|
|
132
|
+
}
|
|
133
|
+
function withSiblings(resolvedTarget, siblings, ref) {
|
|
134
|
+
if (Object.keys(siblings).length > 0 && isRecord(resolvedTarget)) {
|
|
135
|
+
return withSchemaRef({ ...resolvedTarget, ...siblings }, ref);
|
|
136
|
+
}
|
|
137
|
+
return withSchemaRef(resolvedTarget, ref);
|
|
138
|
+
}
|
|
139
|
+
function withSourceRef(out, node) {
|
|
140
|
+
const sourceRef = node[SCHEMA_REF];
|
|
141
|
+
return typeof sourceRef === "string" ? withSchemaRef(out, sourceRef) : out;
|
|
142
|
+
}
|
|
143
|
+
function resolveRefs(node, root, seen, depth) {
|
|
144
|
+
if (depth > MAX_REF_DEPTH) {
|
|
145
|
+
return node;
|
|
146
|
+
}
|
|
147
|
+
if (Array.isArray(node)) {
|
|
148
|
+
return node.map((item) => resolveRefs(item, root, seen, depth + 1));
|
|
149
|
+
}
|
|
150
|
+
if (!isRecord(node)) {
|
|
151
|
+
return node;
|
|
152
|
+
}
|
|
153
|
+
const ref = node["$ref"];
|
|
154
|
+
if (typeof ref === "string" && ref.startsWith("#/")) {
|
|
155
|
+
if (seen.has(ref)) {
|
|
156
|
+
return { $ref: ref };
|
|
157
|
+
}
|
|
158
|
+
const target = lookupPointer(root, ref);
|
|
159
|
+
const nextSeen = new Set(seen);
|
|
160
|
+
nextSeen.add(ref);
|
|
161
|
+
const resolvedTarget = resolveRefs(target, root, nextSeen, depth + 1);
|
|
162
|
+
const siblings = {};
|
|
163
|
+
for (const [key, value] of Object.entries(node)) {
|
|
164
|
+
if (key !== "$ref") siblings[key] = resolveRefs(value, root, seen, depth + 1);
|
|
165
|
+
}
|
|
166
|
+
return withSiblings(resolvedTarget, siblings, ref);
|
|
167
|
+
}
|
|
168
|
+
const out = {};
|
|
169
|
+
for (const [key, value] of Object.entries(node)) {
|
|
170
|
+
out[key] = resolveRefs(value, root, seen, depth + 1);
|
|
171
|
+
}
|
|
172
|
+
return withSourceRef(out, node);
|
|
173
|
+
}
|
|
174
|
+
async function resolveRefsAsync(node, root, seen, depth, context) {
|
|
175
|
+
if (depth > MAX_REF_DEPTH) {
|
|
176
|
+
return node;
|
|
177
|
+
}
|
|
178
|
+
if (Array.isArray(node)) {
|
|
179
|
+
return Promise.all(
|
|
180
|
+
node.map((item) => resolveRefsAsync(item, root, seen, depth + 1, context))
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
if (!isRecord(node)) {
|
|
184
|
+
return node;
|
|
185
|
+
}
|
|
186
|
+
const ref = node["$ref"];
|
|
187
|
+
const local = typeof ref === "string" && ref.startsWith("#/");
|
|
188
|
+
const external = typeof ref === "string" && !local && context.currentFile !== "" && !isHttpRef(ref);
|
|
189
|
+
if (typeof ref === "string" && (local || external)) {
|
|
190
|
+
const marker = `${context.currentFile}:${ref}`;
|
|
191
|
+
if (seen.has(marker)) {
|
|
192
|
+
return { $ref: ref };
|
|
193
|
+
}
|
|
194
|
+
const nextSeen = new Set(seen);
|
|
195
|
+
nextSeen.add(marker);
|
|
196
|
+
const resolvedTarget = local ? await resolveRefsAsync(lookupPointer(root, ref), root, nextSeen, depth + 1, context) : await context.resolver.resolveExternal(ref, context.currentFile, nextSeen, depth + 1);
|
|
197
|
+
const siblings = {};
|
|
198
|
+
for (const [key, value] of Object.entries(node)) {
|
|
199
|
+
if (key !== "$ref") siblings[key] = await resolveRefsAsync(value, root, seen, depth + 1, context);
|
|
200
|
+
}
|
|
201
|
+
return withSiblings(resolvedTarget, siblings, ref);
|
|
202
|
+
}
|
|
203
|
+
const out = {};
|
|
204
|
+
for (const [key, value] of Object.entries(node)) {
|
|
205
|
+
out[key] = await resolveRefsAsync(value, root, seen, depth + 1, context);
|
|
206
|
+
}
|
|
207
|
+
return withSourceRef(out, node);
|
|
208
|
+
}
|
|
209
|
+
function* resolve(node) {
|
|
210
|
+
return yield node;
|
|
211
|
+
}
|
|
212
|
+
function runResolving(steps, resolveNode) {
|
|
213
|
+
let step = steps.next();
|
|
214
|
+
while (!step.done) step = steps.next(resolveNode(step.value));
|
|
215
|
+
return step.value;
|
|
216
|
+
}
|
|
217
|
+
async function runResolvingAsync(steps, resolveNode) {
|
|
218
|
+
let step = steps.next();
|
|
219
|
+
while (!step.done) step = steps.next(await resolveNode(step.value));
|
|
220
|
+
return step.value;
|
|
221
|
+
}
|
|
222
|
+
function operationSlug(method, path) {
|
|
223
|
+
return `${method} ${path}`.toLowerCase().replace(/[{}]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
224
|
+
}
|
|
225
|
+
function* pickContent(content) {
|
|
226
|
+
if (!isRecord(content)) return void 0;
|
|
227
|
+
const keys = Object.keys(content);
|
|
228
|
+
if (keys.length === 0) return void 0;
|
|
229
|
+
const contentType = keys.includes("application/json") ? "application/json" : keys[0];
|
|
230
|
+
const contentTypes = [
|
|
231
|
+
contentType,
|
|
232
|
+
...keys.filter((key) => key !== contentType)
|
|
233
|
+
];
|
|
234
|
+
const resolved = yield* resolve(content[contentType]);
|
|
235
|
+
const media = isRecord(resolved) ? resolved : {};
|
|
236
|
+
return {
|
|
237
|
+
contentType,
|
|
238
|
+
contentTypes,
|
|
239
|
+
schema: media["schema"],
|
|
240
|
+
example: extractExample(media),
|
|
241
|
+
examples: extractExamples(media)
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function extractExample(media) {
|
|
245
|
+
if (media["example"] !== void 0) {
|
|
246
|
+
return media["example"];
|
|
247
|
+
}
|
|
248
|
+
const examples = media["examples"];
|
|
249
|
+
if (isRecord(examples)) {
|
|
250
|
+
const first = Object.values(examples)[0];
|
|
251
|
+
if (isRecord(first) && "value" in first) {
|
|
252
|
+
return first["value"];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return void 0;
|
|
256
|
+
}
|
|
257
|
+
function extractExamples(media) {
|
|
258
|
+
const examples = [];
|
|
259
|
+
if (media["example"] !== void 0) {
|
|
260
|
+
examples.push({ name: "Example", value: media["example"] });
|
|
261
|
+
}
|
|
262
|
+
const rawExamples = media["examples"];
|
|
263
|
+
if (!isRecord(rawExamples)) return examples;
|
|
264
|
+
for (const [name, raw] of Object.entries(rawExamples)) {
|
|
265
|
+
if (!isRecord(raw) || !("value" in raw)) continue;
|
|
266
|
+
const example = { name, value: raw["value"] };
|
|
267
|
+
const summary = asStringOrUndefined(raw["summary"]);
|
|
268
|
+
if (summary !== void 0) example.summary = summary;
|
|
269
|
+
examples.push(example);
|
|
270
|
+
}
|
|
271
|
+
return examples;
|
|
272
|
+
}
|
|
273
|
+
function codeSamples(raw) {
|
|
274
|
+
const value = raw["x-codeSamples"] ?? raw["x-code-samples"];
|
|
275
|
+
if (!Array.isArray(value)) return [];
|
|
276
|
+
const samples = [];
|
|
277
|
+
for (const entry of value) {
|
|
278
|
+
if (!isRecord(entry)) continue;
|
|
279
|
+
const lang = asStringOrUndefined(entry["lang"]);
|
|
280
|
+
const source = asStringOrUndefined(entry["source"]);
|
|
281
|
+
if (!lang || source === void 0) continue;
|
|
282
|
+
const sample = { lang, source };
|
|
283
|
+
const label = asStringOrUndefined(entry["label"]);
|
|
284
|
+
if (label !== void 0) sample.label = label;
|
|
285
|
+
samples.push(sample);
|
|
286
|
+
}
|
|
287
|
+
return samples;
|
|
288
|
+
}
|
|
289
|
+
function securityNames(requirement) {
|
|
290
|
+
if (!Array.isArray(requirement)) return [];
|
|
291
|
+
const names = [];
|
|
292
|
+
for (const entry of requirement) {
|
|
293
|
+
if (isRecord(entry)) {
|
|
294
|
+
for (const name of Object.keys(entry)) {
|
|
295
|
+
if (!names.includes(name)) names.push(name);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return names;
|
|
300
|
+
}
|
|
301
|
+
function securityRequirementGroups(requirement) {
|
|
302
|
+
if (!Array.isArray(requirement)) return { groups: [], optional: false };
|
|
303
|
+
const groups = [];
|
|
304
|
+
let optional = false;
|
|
305
|
+
for (const entry of requirement) {
|
|
306
|
+
if (!isRecord(entry)) continue;
|
|
307
|
+
const names = [];
|
|
308
|
+
for (const name of Object.keys(entry)) {
|
|
309
|
+
if (!names.includes(name)) names.push(name);
|
|
310
|
+
}
|
|
311
|
+
if (names.length === 0) optional = true;
|
|
312
|
+
else groups.push(names);
|
|
313
|
+
}
|
|
314
|
+
return { groups, optional };
|
|
315
|
+
}
|
|
316
|
+
var SECURITY_SCHEME_TYPES = [
|
|
317
|
+
"apiKey",
|
|
318
|
+
"http",
|
|
319
|
+
"oauth2",
|
|
320
|
+
"openIdConnect",
|
|
321
|
+
"mutualTLS"
|
|
322
|
+
];
|
|
323
|
+
var API_KEY_LOCATIONS = ["header", "query", "cookie"];
|
|
324
|
+
function normalizeSecurityScheme(name, raw) {
|
|
325
|
+
if (!isRecord(raw)) return void 0;
|
|
326
|
+
const type = raw["type"];
|
|
327
|
+
if (typeof type !== "string") return void 0;
|
|
328
|
+
if (!SECURITY_SCHEME_TYPES.includes(type)) return void 0;
|
|
329
|
+
const info = { name, type };
|
|
330
|
+
const description = asStringOrUndefined(raw["description"]);
|
|
331
|
+
if (description !== void 0) info.description = description;
|
|
332
|
+
if (type === "apiKey") {
|
|
333
|
+
const location = raw["in"];
|
|
334
|
+
const parameterName = asStringOrUndefined(raw["name"]);
|
|
335
|
+
if (typeof location !== "string") return void 0;
|
|
336
|
+
if (!API_KEY_LOCATIONS.includes(location)) {
|
|
337
|
+
return void 0;
|
|
338
|
+
}
|
|
339
|
+
if (parameterName === void 0 || parameterName.length === 0) return void 0;
|
|
340
|
+
info.in = location;
|
|
341
|
+
info.parameterName = parameterName;
|
|
342
|
+
return info;
|
|
343
|
+
}
|
|
344
|
+
if (type === "http") {
|
|
345
|
+
const scheme = asStringOrUndefined(raw["scheme"]);
|
|
346
|
+
if (scheme === void 0 || scheme.length === 0) return void 0;
|
|
347
|
+
info.scheme = scheme.toLowerCase();
|
|
348
|
+
const bearerFormat = asStringOrUndefined(raw["bearerFormat"]);
|
|
349
|
+
if (bearerFormat !== void 0) info.bearerFormat = bearerFormat;
|
|
350
|
+
return info;
|
|
351
|
+
}
|
|
352
|
+
return info;
|
|
353
|
+
}
|
|
354
|
+
function securitySchemeMap(resolved) {
|
|
355
|
+
if (!isRecord(resolved)) return {};
|
|
356
|
+
const map = {};
|
|
357
|
+
for (const [name, raw] of Object.entries(resolved)) {
|
|
358
|
+
const info = normalizeSecurityScheme(name, raw);
|
|
359
|
+
if (info) map[name] = info;
|
|
360
|
+
}
|
|
361
|
+
return map;
|
|
362
|
+
}
|
|
363
|
+
function securitySchemesNode(root) {
|
|
364
|
+
const components = root["components"];
|
|
365
|
+
return isRecord(components) ? components["securitySchemes"] : void 0;
|
|
366
|
+
}
|
|
367
|
+
function asStringOrUndefined(value) {
|
|
368
|
+
return typeof value === "string" ? value : void 0;
|
|
369
|
+
}
|
|
370
|
+
function* toParamInfo(raw) {
|
|
371
|
+
const resolved = yield* resolve(raw);
|
|
372
|
+
if (!isRecord(resolved)) return void 0;
|
|
373
|
+
const name = resolved["name"];
|
|
374
|
+
const location = resolved["in"];
|
|
375
|
+
if (typeof name !== "string" || typeof location !== "string") return void 0;
|
|
376
|
+
if (location !== "query" && location !== "path" && location !== "header" && location !== "cookie") {
|
|
377
|
+
return void 0;
|
|
378
|
+
}
|
|
379
|
+
const required = location === "path" ? true : resolved["required"] === true;
|
|
380
|
+
const info = { name, location, required };
|
|
381
|
+
const description = asStringOrUndefined(resolved["description"]);
|
|
382
|
+
if (description !== void 0) info.description = description;
|
|
383
|
+
if (resolved["schema"] !== void 0) info.schema = resolved["schema"];
|
|
384
|
+
return info;
|
|
385
|
+
}
|
|
386
|
+
function* collectParameters(pathParams, opParams) {
|
|
387
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
388
|
+
const order = [];
|
|
389
|
+
for (const list of [pathParams, opParams]) {
|
|
390
|
+
if (!Array.isArray(list)) continue;
|
|
391
|
+
for (const raw of list) {
|
|
392
|
+
const info = yield* toParamInfo(raw);
|
|
393
|
+
if (!info) continue;
|
|
394
|
+
const key = `${info.location}:${info.name}`;
|
|
395
|
+
if (!byKey.has(key)) order.push(key);
|
|
396
|
+
byKey.set(key, info);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return order.map((key) => byKey.get(key));
|
|
400
|
+
}
|
|
401
|
+
function* buildRequestBody(raw) {
|
|
402
|
+
const resolved = yield* resolve(raw);
|
|
403
|
+
if (!isRecord(resolved)) return void 0;
|
|
404
|
+
const picked = yield* pickContent(resolved["content"]);
|
|
405
|
+
if (!picked) return void 0;
|
|
406
|
+
const body = {
|
|
407
|
+
required: resolved["required"] === true,
|
|
408
|
+
contentType: picked.contentType,
|
|
409
|
+
contentTypes: picked.contentTypes,
|
|
410
|
+
examples: picked.examples
|
|
411
|
+
};
|
|
412
|
+
if (picked.schema !== void 0) body.schema = picked.schema;
|
|
413
|
+
if (picked.example !== void 0) body.example = picked.example;
|
|
414
|
+
return body;
|
|
415
|
+
}
|
|
416
|
+
function* buildResponses(raw) {
|
|
417
|
+
if (!isRecord(raw)) return [];
|
|
418
|
+
const responses = [];
|
|
419
|
+
for (const [status, value] of Object.entries(raw)) {
|
|
420
|
+
const resolved = yield* resolve(value);
|
|
421
|
+
const info = { status, examples: [] };
|
|
422
|
+
if (isRecord(resolved)) {
|
|
423
|
+
const description = asStringOrUndefined(resolved["description"]);
|
|
424
|
+
if (description !== void 0) info.description = description;
|
|
425
|
+
if (isRecord(resolved["headers"])) {
|
|
426
|
+
const headers = [];
|
|
427
|
+
for (const [name, rawHeader] of Object.entries(resolved["headers"])) {
|
|
428
|
+
const header = yield* resolve(rawHeader);
|
|
429
|
+
if (!isRecord(header)) continue;
|
|
430
|
+
const content = yield* pickContent(header["content"]);
|
|
431
|
+
headers.push({
|
|
432
|
+
name,
|
|
433
|
+
required: header["required"] === true,
|
|
434
|
+
description: asStringOrUndefined(header["description"]),
|
|
435
|
+
schema: header["schema"] ?? content?.schema
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
if (headers.length > 0) info.headers = headers;
|
|
439
|
+
}
|
|
440
|
+
const picked = yield* pickContent(resolved["content"]);
|
|
441
|
+
if (picked) {
|
|
442
|
+
info.contentType = picked.contentType;
|
|
443
|
+
info.contentTypes = picked.contentTypes;
|
|
444
|
+
if (picked.schema !== void 0) info.schema = picked.schema;
|
|
445
|
+
if (picked.example !== void 0) info.example = picked.example;
|
|
446
|
+
info.examples = picked.examples;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
responses.push(info);
|
|
450
|
+
}
|
|
451
|
+
return responses;
|
|
452
|
+
}
|
|
453
|
+
function parseOpenApi(source) {
|
|
454
|
+
const root = parseDocument(source);
|
|
455
|
+
return runResolving(buildParsedSpec(root), (node) => resolveRefs(node, root, /* @__PURE__ */ new Set(), 0));
|
|
456
|
+
}
|
|
457
|
+
function* buildParsedSpec(root) {
|
|
458
|
+
const info = isRecord(root["info"]) ? root["info"] : {};
|
|
459
|
+
const title = asStringOrUndefined(info["title"]) ?? "";
|
|
460
|
+
const version = asStringOrUndefined(info["version"]) ?? "";
|
|
461
|
+
const description = asStringOrUndefined(info["description"]);
|
|
462
|
+
const servers = [];
|
|
463
|
+
if (Array.isArray(root["servers"])) {
|
|
464
|
+
for (const server of root["servers"]) {
|
|
465
|
+
if (isRecord(server) && typeof server["url"] === "string") {
|
|
466
|
+
servers.push(server["url"]);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const rootSecurity = securityNames(root["security"]);
|
|
471
|
+
const rootRequirements = securityRequirementGroups(root["security"]);
|
|
472
|
+
const securitySchemes = securitySchemeMap(yield* resolve(securitySchemesNode(root)));
|
|
473
|
+
const paths = root["paths"];
|
|
474
|
+
if (!isRecord(paths)) {
|
|
475
|
+
throw new Error(
|
|
476
|
+
"Failed to parse OpenAPI specification: missing or invalid `paths` object."
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
const operations = [];
|
|
480
|
+
for (const [path, pathItemRaw] of Object.entries(paths)) {
|
|
481
|
+
if (!isRecord(pathItemRaw)) continue;
|
|
482
|
+
const pathParams = pathItemRaw["parameters"];
|
|
483
|
+
for (const method of HTTP_METHODS) {
|
|
484
|
+
const opRaw = pathItemRaw[method];
|
|
485
|
+
if (!isRecord(opRaw)) continue;
|
|
486
|
+
const tags = Array.isArray(opRaw["tags"]) ? opRaw["tags"].filter((tag) => typeof tag === "string") : [];
|
|
487
|
+
const requirements = opRaw["security"] !== void 0 ? securityRequirementGroups(opRaw["security"]) : rootRequirements;
|
|
488
|
+
const operation = {
|
|
489
|
+
slug: operationSlug(method, path),
|
|
490
|
+
method,
|
|
491
|
+
path,
|
|
492
|
+
deprecated: opRaw["deprecated"] === true,
|
|
493
|
+
codeSamples: codeSamples(opRaw),
|
|
494
|
+
tags,
|
|
495
|
+
parameters: yield* collectParameters(pathParams, opRaw["parameters"]),
|
|
496
|
+
responses: yield* buildResponses(opRaw["responses"]),
|
|
497
|
+
security: opRaw["security"] !== void 0 ? securityNames(opRaw["security"]) : rootSecurity,
|
|
498
|
+
securityRequirements: requirements.groups,
|
|
499
|
+
securityOptional: requirements.optional
|
|
500
|
+
};
|
|
501
|
+
const operationId = asStringOrUndefined(opRaw["operationId"]);
|
|
502
|
+
if (operationId !== void 0) operation.operationId = operationId;
|
|
503
|
+
const summary = asStringOrUndefined(opRaw["summary"]);
|
|
504
|
+
if (summary !== void 0) operation.summary = summary;
|
|
505
|
+
const opDescription = asStringOrUndefined(opRaw["description"]);
|
|
506
|
+
if (opDescription !== void 0) operation.description = opDescription;
|
|
507
|
+
if (operation.deprecated) {
|
|
508
|
+
const deprecationMessage = asStringOrUndefined(opRaw["x-deprecation-message"]);
|
|
509
|
+
if (deprecationMessage !== void 0) operation.deprecationMessage = deprecationMessage;
|
|
510
|
+
else if (opDescription !== void 0 && /deprecat/i.test(opDescription)) operation.deprecationMessage = opDescription;
|
|
511
|
+
}
|
|
512
|
+
const requestBody = yield* buildRequestBody(opRaw["requestBody"]);
|
|
513
|
+
if (requestBody !== void 0) operation.requestBody = requestBody;
|
|
514
|
+
operations.push(operation);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
const spec = { title, version, servers, operations, securitySchemes };
|
|
518
|
+
if (description !== void 0) spec.description = description;
|
|
519
|
+
return spec;
|
|
520
|
+
}
|
|
521
|
+
async function parseOpenApiFile(filePath, options = {}) {
|
|
522
|
+
const rootFile = resolvePath(filePath);
|
|
523
|
+
const rootDir = dirnamePath(rootFile);
|
|
524
|
+
const reader = options.readFile ?? (async (path) => {
|
|
525
|
+
const fs = await nodeImport("node:fs/promises");
|
|
526
|
+
return fs.readFile(path, "utf8");
|
|
527
|
+
});
|
|
528
|
+
const cache = /* @__PURE__ */ new Map();
|
|
529
|
+
const loadDocument = (targetPath) => {
|
|
530
|
+
const absolute = resolvePath(targetPath);
|
|
531
|
+
let promise = cache.get(absolute);
|
|
532
|
+
if (!promise) {
|
|
533
|
+
promise = reader(absolute).then(
|
|
534
|
+
(source) => parseDocument(source, absolute)
|
|
535
|
+
);
|
|
536
|
+
cache.set(absolute, promise);
|
|
537
|
+
return promise;
|
|
538
|
+
}
|
|
539
|
+
return promise;
|
|
540
|
+
};
|
|
541
|
+
const resolver = {
|
|
542
|
+
async resolveExternal(ref, referringFile, seen, depth) {
|
|
543
|
+
const { filePart, pointer } = splitRef(ref);
|
|
544
|
+
if (filePart.length === 0) {
|
|
545
|
+
const referringRoot = await loadDocument(referringFile);
|
|
546
|
+
const target2 = pointer ? lookupPointer(referringRoot, pointer) : referringRoot;
|
|
547
|
+
const targetMarker2 = `${referringFile}:${pointer}`;
|
|
548
|
+
if (seen.has(targetMarker2)) return { $ref: ref };
|
|
549
|
+
const nextSeen2 = new Set(seen);
|
|
550
|
+
nextSeen2.add(targetMarker2);
|
|
551
|
+
return resolveRefsAsync(
|
|
552
|
+
target2,
|
|
553
|
+
referringRoot,
|
|
554
|
+
nextSeen2,
|
|
555
|
+
depth + 1,
|
|
556
|
+
{ resolver, currentFile: referringFile }
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
const targetPath = resolvePath(dirnamePath(referringFile), filePart);
|
|
560
|
+
if (!isInsideRoot(rootDir, targetPath)) {
|
|
561
|
+
throw new Error(
|
|
562
|
+
`OpenAPI external reference "${ref}" from ${referringFile} resolves outside the spec root directory ${rootDir}.`
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
const targetRoot = await loadDocument(targetPath);
|
|
566
|
+
const target = pointer ? lookupPointer(targetRoot, pointer) : targetRoot;
|
|
567
|
+
const targetMarker = `${targetPath}:${pointer}`;
|
|
568
|
+
if (seen.has(targetMarker)) return { $ref: ref };
|
|
569
|
+
const nextSeen = new Set(seen);
|
|
570
|
+
nextSeen.add(targetMarker);
|
|
571
|
+
return resolveRefsAsync(
|
|
572
|
+
target,
|
|
573
|
+
targetRoot,
|
|
574
|
+
nextSeen,
|
|
575
|
+
depth + 1,
|
|
576
|
+
{ resolver, currentFile: targetPath }
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
const root = await loadDocument(rootFile);
|
|
581
|
+
const context = { resolver, currentFile: rootFile };
|
|
582
|
+
return runResolvingAsync(buildParsedSpec(root), (node) => resolveRefsAsync(node, root, /* @__PURE__ */ new Set(), 0, context));
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
export {
|
|
586
|
+
parseOpenApi,
|
|
587
|
+
parseOpenApiFile
|
|
588
|
+
};
|