@contractkit/openapi-to-ck 0.7.1 → 0.7.2
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/.turbo/turbo-build$colon$ci.log +24 -40
- package/.turbo/turbo-test$colon$ci.log +37 -77
- package/CHANGELOG.md +7 -0
- package/README.md +78 -0
- package/coverage/clover.xml +11 -11
- package/coverage/coverage-final.json +9 -9
- package/coverage/index.html +1 -1
- package/coverage/src/ast-to-ck.ts.html +1 -1
- package/coverage/src/circular-refs.ts.html +1 -1
- package/coverage/src/convert.ts.html +1 -1
- package/coverage/src/index.html +1 -1
- package/coverage/src/normalize.ts.html +1 -1
- package/coverage/src/paths-to-ast.ts.html +1 -1
- package/coverage/src/schema-to-ast.ts.html +1 -1
- package/coverage/src/tag-splitter.ts.html +1 -1
- package/coverage/src/warnings.ts.html +1 -1
- package/coverage/tests/helpers.ts.html +1 -1
- package/coverage/tests/index.html +1 -1
- package/package.json +4 -4
- package/.turbo/turbo-build.log +0 -20
- package/.turbo/turbo-format.log +0 -36
- package/.turbo/turbo-test.log +0 -19
- package/dist/chunk-CQGFQKBJ.js +0 -1681
- package/dist/chunk-CQGFQKBJ.js.map +0 -1
- package/dist/chunk-FNUU2DWY.js +0 -1779
- package/dist/chunk-FNUU2DWY.js.map +0 -1
- package/dist/chunk-LD2HAFZG.js +0 -1681
- package/dist/chunk-LD2HAFZG.js.map +0 -1
- package/dist/chunk-LQ2B3EJG.js +0 -1777
- package/dist/chunk-LQ2B3EJG.js.map +0 -1
- package/dist/chunk-M6JA6WY2.js +0 -1714
- package/dist/chunk-M6JA6WY2.js.map +0 -1
- package/dist/chunk-MQTKLXTN.js +0 -1681
- package/dist/chunk-MQTKLXTN.js.map +0 -1
- package/dist/chunk-NV7RGUUS.js +0 -1699
- package/dist/chunk-NV7RGUUS.js.map +0 -1
- package/dist/chunk-REM25FDE.js +0 -1779
- package/dist/chunk-REM25FDE.js.map +0 -1
- package/dist/chunk-SNW7GJOM.js +0 -1681
- package/dist/chunk-SNW7GJOM.js.map +0 -1
- package/dist/chunk-UWOSCBRG.js +0 -1681
- package/dist/chunk-UWOSCBRG.js.map +0 -1
package/dist/chunk-MQTKLXTN.js
DELETED
|
@@ -1,1681 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
-
|
|
4
|
-
// src/normalize.ts
|
|
5
|
-
function normalize(doc, warnings) {
|
|
6
|
-
const version = detectVersion(doc);
|
|
7
|
-
if (version === "2.0") {
|
|
8
|
-
return normalizeSwagger2(doc, warnings);
|
|
9
|
-
}
|
|
10
|
-
if (version === "3.0") {
|
|
11
|
-
return normalizeOas30(doc, warnings);
|
|
12
|
-
}
|
|
13
|
-
return doc;
|
|
14
|
-
}
|
|
15
|
-
__name(normalize, "normalize");
|
|
16
|
-
function detectVersion(doc) {
|
|
17
|
-
if (typeof doc.swagger === "string" && doc.swagger.startsWith("2")) return "2.0";
|
|
18
|
-
if (typeof doc.openapi === "string") {
|
|
19
|
-
if (doc.openapi.startsWith("3.0")) return "3.0";
|
|
20
|
-
}
|
|
21
|
-
return "3.1";
|
|
22
|
-
}
|
|
23
|
-
__name(detectVersion, "detectVersion");
|
|
24
|
-
function normalizeSwagger2(doc, warnings) {
|
|
25
|
-
const info = doc.info ?? {
|
|
26
|
-
title: "Untitled",
|
|
27
|
-
version: "0.0.0"
|
|
28
|
-
};
|
|
29
|
-
const basePath = doc.basePath ?? "";
|
|
30
|
-
const schemes = doc.schemes ?? [
|
|
31
|
-
"https"
|
|
32
|
-
];
|
|
33
|
-
const host = doc.host ?? "localhost";
|
|
34
|
-
const globalConsumes = doc.consumes ?? [
|
|
35
|
-
"application/json"
|
|
36
|
-
];
|
|
37
|
-
const globalProduces = doc.produces ?? [
|
|
38
|
-
"application/json"
|
|
39
|
-
];
|
|
40
|
-
const result = {
|
|
41
|
-
openapi: "3.1.0",
|
|
42
|
-
info: {
|
|
43
|
-
title: info.title ?? "Untitled",
|
|
44
|
-
version: info.version ?? "0.0.0",
|
|
45
|
-
description: info.description
|
|
46
|
-
},
|
|
47
|
-
servers: [
|
|
48
|
-
{
|
|
49
|
-
url: `${schemes[0]}://${host}${basePath}`
|
|
50
|
-
}
|
|
51
|
-
],
|
|
52
|
-
paths: {},
|
|
53
|
-
components: {
|
|
54
|
-
schemas: {},
|
|
55
|
-
securitySchemes: {}
|
|
56
|
-
},
|
|
57
|
-
tags: doc.tags ?? []
|
|
58
|
-
};
|
|
59
|
-
const definitions = doc.definitions ?? {};
|
|
60
|
-
for (const [name, schema] of Object.entries(definitions)) {
|
|
61
|
-
result.components.schemas[name] = normalizeNullable30(schema);
|
|
62
|
-
}
|
|
63
|
-
const secDefs = doc.securityDefinitions ?? {};
|
|
64
|
-
for (const [name, scheme] of Object.entries(secDefs)) {
|
|
65
|
-
result.components.securitySchemes[name] = convertSecurityScheme2(scheme);
|
|
66
|
-
}
|
|
67
|
-
const paths = doc.paths ?? {};
|
|
68
|
-
for (const [path, pathItem] of Object.entries(paths)) {
|
|
69
|
-
result.paths[path] = normalizePathItem2(pathItem, globalConsumes, globalProduces, warnings);
|
|
70
|
-
}
|
|
71
|
-
if (doc.security) {
|
|
72
|
-
result.security = doc.security;
|
|
73
|
-
}
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
__name(normalizeSwagger2, "normalizeSwagger2");
|
|
77
|
-
function normalizePathItem2(pathItem, globalConsumes, globalProduces, warnings) {
|
|
78
|
-
const methods = [
|
|
79
|
-
"get",
|
|
80
|
-
"post",
|
|
81
|
-
"put",
|
|
82
|
-
"patch",
|
|
83
|
-
"delete",
|
|
84
|
-
"head",
|
|
85
|
-
"options"
|
|
86
|
-
];
|
|
87
|
-
const normalized = {};
|
|
88
|
-
const pathParams = pathItem.parameters ?? [];
|
|
89
|
-
for (const method of methods) {
|
|
90
|
-
const op = pathItem[method];
|
|
91
|
-
if (!op) continue;
|
|
92
|
-
const opConsumes = op.consumes ?? globalConsumes;
|
|
93
|
-
const opProduces = op.produces ?? globalProduces;
|
|
94
|
-
const params = [
|
|
95
|
-
...pathParams,
|
|
96
|
-
...op.parameters ?? []
|
|
97
|
-
];
|
|
98
|
-
const nonBodyParams = [];
|
|
99
|
-
let requestBody;
|
|
100
|
-
for (const param of params) {
|
|
101
|
-
if (param.in === "body") {
|
|
102
|
-
const contentType = opConsumes[0] ?? "application/json";
|
|
103
|
-
requestBody = {
|
|
104
|
-
description: param.description,
|
|
105
|
-
required: param.required ?? true,
|
|
106
|
-
content: {
|
|
107
|
-
[contentType]: {
|
|
108
|
-
schema: normalizeNullable30(param.schema ?? {})
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
} else if (param.in === "formData") {
|
|
113
|
-
warnings.info(`#/paths/${encodePathSegment(method)}`, "formData parameters converted to multipart/form-data requestBody");
|
|
114
|
-
if (!requestBody) {
|
|
115
|
-
requestBody = {
|
|
116
|
-
content: {
|
|
117
|
-
"multipart/form-data": {
|
|
118
|
-
schema: {
|
|
119
|
-
type: "object",
|
|
120
|
-
properties: {},
|
|
121
|
-
required: []
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
const formSchema = requestBody.content["multipart/form-data"].schema;
|
|
128
|
-
const props = formSchema.properties;
|
|
129
|
-
props[param.name] = normalizeNullable30(param);
|
|
130
|
-
if (param.required) {
|
|
131
|
-
formSchema.required.push(param.name);
|
|
132
|
-
}
|
|
133
|
-
} else {
|
|
134
|
-
const normalizedParam = {
|
|
135
|
-
...param
|
|
136
|
-
};
|
|
137
|
-
if (param.type) {
|
|
138
|
-
normalizedParam.schema = normalizeNullable30({
|
|
139
|
-
type: param.type,
|
|
140
|
-
format: param.format,
|
|
141
|
-
enum: param.enum,
|
|
142
|
-
items: param.items,
|
|
143
|
-
default: param.default,
|
|
144
|
-
minimum: param.minimum,
|
|
145
|
-
maximum: param.maximum,
|
|
146
|
-
minLength: param.minLength,
|
|
147
|
-
maxLength: param.maxLength,
|
|
148
|
-
pattern: param.pattern
|
|
149
|
-
});
|
|
150
|
-
delete normalizedParam.type;
|
|
151
|
-
delete normalizedParam.format;
|
|
152
|
-
delete normalizedParam.enum;
|
|
153
|
-
delete normalizedParam.items;
|
|
154
|
-
}
|
|
155
|
-
nonBodyParams.push(normalizedParam);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const responses = {};
|
|
159
|
-
const opResponses = op.responses ?? {};
|
|
160
|
-
for (const [code, resp] of Object.entries(opResponses)) {
|
|
161
|
-
const contentType = opProduces[0] ?? "application/json";
|
|
162
|
-
if (resp.schema) {
|
|
163
|
-
responses[code] = {
|
|
164
|
-
description: resp.description ?? "",
|
|
165
|
-
content: {
|
|
166
|
-
[contentType]: {
|
|
167
|
-
schema: normalizeNullable30(resp.schema)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
} else {
|
|
172
|
-
responses[code] = {
|
|
173
|
-
description: resp.description ?? ""
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
normalized[method] = {
|
|
178
|
-
operationId: op.operationId,
|
|
179
|
-
summary: op.summary,
|
|
180
|
-
description: op.description,
|
|
181
|
-
tags: op.tags,
|
|
182
|
-
parameters: nonBodyParams.length > 0 ? nonBodyParams : void 0,
|
|
183
|
-
requestBody,
|
|
184
|
-
responses,
|
|
185
|
-
security: op.security,
|
|
186
|
-
deprecated: op.deprecated
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
return normalized;
|
|
190
|
-
}
|
|
191
|
-
__name(normalizePathItem2, "normalizePathItem2");
|
|
192
|
-
function convertSecurityScheme2(scheme) {
|
|
193
|
-
const type = scheme.type;
|
|
194
|
-
if (type === "basic") {
|
|
195
|
-
return {
|
|
196
|
-
type: "http",
|
|
197
|
-
scheme: "basic"
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
if (type === "apiKey") {
|
|
201
|
-
return {
|
|
202
|
-
type: "apiKey",
|
|
203
|
-
name: scheme.name,
|
|
204
|
-
in: scheme.in
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
if (type === "oauth2") {
|
|
208
|
-
const flow = scheme.flow;
|
|
209
|
-
const flows = {};
|
|
210
|
-
if (flow === "implicit") {
|
|
211
|
-
flows.implicit = {
|
|
212
|
-
authorizationUrl: scheme.authorizationUrl,
|
|
213
|
-
scopes: scheme.scopes ?? {}
|
|
214
|
-
};
|
|
215
|
-
} else if (flow === "password") {
|
|
216
|
-
flows.password = {
|
|
217
|
-
tokenUrl: scheme.tokenUrl,
|
|
218
|
-
scopes: scheme.scopes ?? {}
|
|
219
|
-
};
|
|
220
|
-
} else if (flow === "application") {
|
|
221
|
-
flows.clientCredentials = {
|
|
222
|
-
tokenUrl: scheme.tokenUrl,
|
|
223
|
-
scopes: scheme.scopes ?? {}
|
|
224
|
-
};
|
|
225
|
-
} else if (flow === "accessCode") {
|
|
226
|
-
flows.authorizationCode = {
|
|
227
|
-
authorizationUrl: scheme.authorizationUrl,
|
|
228
|
-
tokenUrl: scheme.tokenUrl,
|
|
229
|
-
scopes: scheme.scopes ?? {}
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
return {
|
|
233
|
-
type: "oauth2",
|
|
234
|
-
flows
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
return scheme;
|
|
238
|
-
}
|
|
239
|
-
__name(convertSecurityScheme2, "convertSecurityScheme2");
|
|
240
|
-
function normalizeOas30(doc, _warnings) {
|
|
241
|
-
if (doc.components?.schemas) {
|
|
242
|
-
for (const [name, schema] of Object.entries(doc.components.schemas)) {
|
|
243
|
-
doc.components.schemas[name] = normalizeNullable30(schema);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
if (doc.paths) {
|
|
247
|
-
for (const pathItem of Object.values(doc.paths)) {
|
|
248
|
-
normalizePathItemSchemas(pathItem);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
doc.openapi = "3.1.0";
|
|
252
|
-
return doc;
|
|
253
|
-
}
|
|
254
|
-
__name(normalizeOas30, "normalizeOas30");
|
|
255
|
-
function normalizePathItemSchemas(pathItem) {
|
|
256
|
-
const methods = [
|
|
257
|
-
"get",
|
|
258
|
-
"post",
|
|
259
|
-
"put",
|
|
260
|
-
"patch",
|
|
261
|
-
"delete",
|
|
262
|
-
"head",
|
|
263
|
-
"options"
|
|
264
|
-
];
|
|
265
|
-
for (const method of methods) {
|
|
266
|
-
const op = pathItem[method];
|
|
267
|
-
if (!op) continue;
|
|
268
|
-
const params = op.parameters ?? [];
|
|
269
|
-
for (const param of params) {
|
|
270
|
-
if (param.schema) {
|
|
271
|
-
param.schema = normalizeNullable30(param.schema);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
const reqBody = op.requestBody;
|
|
275
|
-
if (reqBody?.content) {
|
|
276
|
-
for (const mediaType of Object.values(reqBody.content)) {
|
|
277
|
-
if (mediaType.schema) {
|
|
278
|
-
mediaType.schema = normalizeNullable30(mediaType.schema);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
const responses = op.responses ?? {};
|
|
283
|
-
for (const resp of Object.values(responses)) {
|
|
284
|
-
if (resp.content) {
|
|
285
|
-
for (const mediaType of Object.values(resp.content)) {
|
|
286
|
-
if (mediaType.schema) {
|
|
287
|
-
mediaType.schema = normalizeNullable30(mediaType.schema);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
__name(normalizePathItemSchemas, "normalizePathItemSchemas");
|
|
295
|
-
function normalizeNullable30(schema) {
|
|
296
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
297
|
-
const result = {
|
|
298
|
-
...schema
|
|
299
|
-
};
|
|
300
|
-
if (result.nullable === true && typeof result.type === "string") {
|
|
301
|
-
result.type = [
|
|
302
|
-
result.type,
|
|
303
|
-
"null"
|
|
304
|
-
];
|
|
305
|
-
delete result.nullable;
|
|
306
|
-
}
|
|
307
|
-
if (result.properties && typeof result.properties === "object") {
|
|
308
|
-
const props = result.properties;
|
|
309
|
-
for (const [key, val] of Object.entries(props)) {
|
|
310
|
-
props[key] = normalizeNullable30(val);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
if (result.items && typeof result.items === "object" && !Array.isArray(result.items)) {
|
|
314
|
-
result.items = normalizeNullable30(result.items);
|
|
315
|
-
}
|
|
316
|
-
if (result.additionalProperties && typeof result.additionalProperties === "object") {
|
|
317
|
-
result.additionalProperties = normalizeNullable30(result.additionalProperties);
|
|
318
|
-
}
|
|
319
|
-
for (const combiner of [
|
|
320
|
-
"allOf",
|
|
321
|
-
"oneOf",
|
|
322
|
-
"anyOf"
|
|
323
|
-
]) {
|
|
324
|
-
if (Array.isArray(result[combiner])) {
|
|
325
|
-
result[combiner] = result[combiner].map(normalizeNullable30);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return result;
|
|
329
|
-
}
|
|
330
|
-
__name(normalizeNullable30, "normalizeNullable30");
|
|
331
|
-
function encodePathSegment(s) {
|
|
332
|
-
return s.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
333
|
-
}
|
|
334
|
-
__name(encodePathSegment, "encodePathSegment");
|
|
335
|
-
|
|
336
|
-
// src/circular-refs.ts
|
|
337
|
-
function detectCircularRefs(schemas) {
|
|
338
|
-
const circular = /* @__PURE__ */ new Set();
|
|
339
|
-
const visiting = /* @__PURE__ */ new Set();
|
|
340
|
-
const visited = /* @__PURE__ */ new Set();
|
|
341
|
-
function visit(name) {
|
|
342
|
-
if (visited.has(name)) return;
|
|
343
|
-
if (visiting.has(name)) {
|
|
344
|
-
circular.add(name);
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
visiting.add(name);
|
|
348
|
-
const schema = schemas[name];
|
|
349
|
-
if (schema && typeof schema === "object") {
|
|
350
|
-
for (const ref of collectRefs(schema)) {
|
|
351
|
-
const refName = extractRefName(ref);
|
|
352
|
-
if (refName && schemas[refName]) {
|
|
353
|
-
visit(refName);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
visiting.delete(name);
|
|
358
|
-
visited.add(name);
|
|
359
|
-
}
|
|
360
|
-
__name(visit, "visit");
|
|
361
|
-
for (const name of Object.keys(schemas)) {
|
|
362
|
-
visit(name);
|
|
363
|
-
}
|
|
364
|
-
return circular;
|
|
365
|
-
}
|
|
366
|
-
__name(detectCircularRefs, "detectCircularRefs");
|
|
367
|
-
function collectRefs(obj) {
|
|
368
|
-
const refs = [];
|
|
369
|
-
function walk(val) {
|
|
370
|
-
if (!val || typeof val !== "object") return;
|
|
371
|
-
if (Array.isArray(val)) {
|
|
372
|
-
for (const item of val) walk(item);
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
const record = val;
|
|
376
|
-
if (typeof record.$ref === "string") {
|
|
377
|
-
refs.push(record.$ref);
|
|
378
|
-
}
|
|
379
|
-
for (const v of Object.values(record)) {
|
|
380
|
-
walk(v);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
__name(walk, "walk");
|
|
384
|
-
walk(obj);
|
|
385
|
-
return refs;
|
|
386
|
-
}
|
|
387
|
-
__name(collectRefs, "collectRefs");
|
|
388
|
-
function extractRefName(ref) {
|
|
389
|
-
const match = ref.match(/^#\/(?:components\/schemas|definitions)\/(.+)$/);
|
|
390
|
-
return match?.[1];
|
|
391
|
-
}
|
|
392
|
-
__name(extractRefName, "extractRefName");
|
|
393
|
-
|
|
394
|
-
// src/schema-to-ast.ts
|
|
395
|
-
var LOC = {
|
|
396
|
-
file: "",
|
|
397
|
-
line: 0
|
|
398
|
-
};
|
|
399
|
-
var FORMAT_TO_SCALAR = {
|
|
400
|
-
email: "email",
|
|
401
|
-
uri: "url",
|
|
402
|
-
url: "url",
|
|
403
|
-
uuid: "uuid",
|
|
404
|
-
date: "date",
|
|
405
|
-
"date-time": "datetime",
|
|
406
|
-
time: "time",
|
|
407
|
-
binary: "binary",
|
|
408
|
-
int64: "bigint"
|
|
409
|
-
};
|
|
410
|
-
function schemasToModels(schemas, ctx) {
|
|
411
|
-
const models = [];
|
|
412
|
-
for (const [name, schema] of Object.entries(schemas)) {
|
|
413
|
-
const modelCtx = {
|
|
414
|
-
...ctx,
|
|
415
|
-
path: `#/components/schemas/${name}`
|
|
416
|
-
};
|
|
417
|
-
const model = schemaToModel(name, schema, modelCtx);
|
|
418
|
-
if (model) models.push(model);
|
|
419
|
-
}
|
|
420
|
-
models.push(...ctx.extractedModels);
|
|
421
|
-
return models;
|
|
422
|
-
}
|
|
423
|
-
__name(schemasToModels, "schemasToModels");
|
|
424
|
-
function schemaToModel(name, schema, ctx) {
|
|
425
|
-
warnUnsupported(schema, ctx);
|
|
426
|
-
const description = ctx.includeComments ? schema.description : void 0;
|
|
427
|
-
if (schema.allOf && schema.allOf.length === 2) {
|
|
428
|
-
const [first, second] = schema.allOf;
|
|
429
|
-
const refMember = first?.$ref ? first : second?.$ref ? second : null;
|
|
430
|
-
const objectMember = first?.$ref ? second : first;
|
|
431
|
-
if (refMember?.$ref && objectMember?.properties) {
|
|
432
|
-
const baseName = extractRefName(refMember.$ref);
|
|
433
|
-
if (baseName) {
|
|
434
|
-
const fields = schemaPropertiesToFields(objectMember, ctx);
|
|
435
|
-
return {
|
|
436
|
-
kind: "model",
|
|
437
|
-
name,
|
|
438
|
-
base: baseName,
|
|
439
|
-
fields,
|
|
440
|
-
description,
|
|
441
|
-
loc: LOC
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
if (schema.properties || schema.type === "object" && !schema.additionalProperties) {
|
|
447
|
-
const fields = schemaPropertiesToFields(schema, ctx);
|
|
448
|
-
return {
|
|
449
|
-
kind: "model",
|
|
450
|
-
name,
|
|
451
|
-
fields,
|
|
452
|
-
description,
|
|
453
|
-
loc: LOC
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
const typeNode = schemaToTypeNode(schema, ctx);
|
|
457
|
-
return {
|
|
458
|
-
kind: "model",
|
|
459
|
-
name,
|
|
460
|
-
fields: [],
|
|
461
|
-
type: typeNode,
|
|
462
|
-
description,
|
|
463
|
-
loc: LOC
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
__name(schemaToModel, "schemaToModel");
|
|
467
|
-
function schemaToTypeNode(schema, ctx) {
|
|
468
|
-
if (schema.$ref) {
|
|
469
|
-
const refName = extractRefName(schema.$ref);
|
|
470
|
-
if (refName) {
|
|
471
|
-
if (ctx.circularRefs.has(refName)) {
|
|
472
|
-
return {
|
|
473
|
-
kind: "lazy",
|
|
474
|
-
inner: {
|
|
475
|
-
kind: "ref",
|
|
476
|
-
name: refName
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
return {
|
|
481
|
-
kind: "ref",
|
|
482
|
-
name: refName
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
ctx.warnings.warn(ctx.path, `Unresolvable $ref: ${schema.$ref}`);
|
|
486
|
-
return {
|
|
487
|
-
kind: "scalar",
|
|
488
|
-
name: "unknown"
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
if (schema.const !== void 0) {
|
|
492
|
-
return {
|
|
493
|
-
kind: "literal",
|
|
494
|
-
value: schema.const
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
if (schema.enum) {
|
|
498
|
-
return {
|
|
499
|
-
kind: "enum",
|
|
500
|
-
values: schema.enum.map(String)
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
if (schema.oneOf && schema.oneOf.length > 0) {
|
|
504
|
-
return toUnion(schema.oneOf, ctx);
|
|
505
|
-
}
|
|
506
|
-
if (schema.anyOf && schema.anyOf.length > 0) {
|
|
507
|
-
return toUnion(schema.anyOf, ctx);
|
|
508
|
-
}
|
|
509
|
-
if (schema.allOf && schema.allOf.length > 0) {
|
|
510
|
-
if (schema.allOf.length === 1) {
|
|
511
|
-
return schemaToTypeNode(schema.allOf[0], ctx);
|
|
512
|
-
}
|
|
513
|
-
return {
|
|
514
|
-
kind: "intersection",
|
|
515
|
-
members: schema.allOf.map((s) => schemaToTypeNode(s, ctx))
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
const types = normalizeTypeField(schema);
|
|
519
|
-
if (types === null) {
|
|
520
|
-
if (schema.properties) {
|
|
521
|
-
return schemaToInlineObject(schema, ctx);
|
|
522
|
-
}
|
|
523
|
-
return {
|
|
524
|
-
kind: "scalar",
|
|
525
|
-
name: "unknown"
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
const { baseType, nullable } = types;
|
|
529
|
-
let typeNode;
|
|
530
|
-
switch (baseType) {
|
|
531
|
-
case "string":
|
|
532
|
-
typeNode = stringSchemaToType(schema);
|
|
533
|
-
break;
|
|
534
|
-
case "integer":
|
|
535
|
-
typeNode = integerSchemaToType(schema);
|
|
536
|
-
break;
|
|
537
|
-
case "number":
|
|
538
|
-
typeNode = numberSchemaToType(schema);
|
|
539
|
-
break;
|
|
540
|
-
case "boolean":
|
|
541
|
-
typeNode = {
|
|
542
|
-
kind: "scalar",
|
|
543
|
-
name: "boolean"
|
|
544
|
-
};
|
|
545
|
-
break;
|
|
546
|
-
case "null":
|
|
547
|
-
typeNode = {
|
|
548
|
-
kind: "scalar",
|
|
549
|
-
name: "null"
|
|
550
|
-
};
|
|
551
|
-
break;
|
|
552
|
-
case "array":
|
|
553
|
-
typeNode = arraySchemaToType(schema, ctx);
|
|
554
|
-
break;
|
|
555
|
-
case "object":
|
|
556
|
-
typeNode = objectSchemaToType(schema, ctx);
|
|
557
|
-
break;
|
|
558
|
-
default:
|
|
559
|
-
ctx.warnings.warn(ctx.path, `Unknown type: ${baseType}`);
|
|
560
|
-
typeNode = {
|
|
561
|
-
kind: "scalar",
|
|
562
|
-
name: "unknown"
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
if (nullable) {
|
|
566
|
-
return {
|
|
567
|
-
kind: "union",
|
|
568
|
-
members: [
|
|
569
|
-
typeNode,
|
|
570
|
-
{
|
|
571
|
-
kind: "scalar",
|
|
572
|
-
name: "null"
|
|
573
|
-
}
|
|
574
|
-
]
|
|
575
|
-
};
|
|
576
|
-
}
|
|
577
|
-
return typeNode;
|
|
578
|
-
}
|
|
579
|
-
__name(schemaToTypeNode, "schemaToTypeNode");
|
|
580
|
-
function stringSchemaToType(schema) {
|
|
581
|
-
if (schema.format) {
|
|
582
|
-
const scalarName = FORMAT_TO_SCALAR[schema.format];
|
|
583
|
-
if (scalarName) {
|
|
584
|
-
return {
|
|
585
|
-
kind: "scalar",
|
|
586
|
-
name: scalarName
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
const mods = {};
|
|
591
|
-
if (schema.minLength !== void 0 && schema.maxLength !== void 0 && schema.minLength === schema.maxLength) {
|
|
592
|
-
mods.len = schema.minLength;
|
|
593
|
-
} else {
|
|
594
|
-
if (schema.minLength !== void 0) mods.min = schema.minLength;
|
|
595
|
-
if (schema.maxLength !== void 0) mods.max = schema.maxLength;
|
|
596
|
-
}
|
|
597
|
-
if (schema.pattern) mods.regex = `/${schema.pattern}/`;
|
|
598
|
-
if (schema.format && !FORMAT_TO_SCALAR[schema.format]) mods.format = schema.format;
|
|
599
|
-
return {
|
|
600
|
-
kind: "scalar",
|
|
601
|
-
name: "string",
|
|
602
|
-
...mods
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
__name(stringSchemaToType, "stringSchemaToType");
|
|
606
|
-
function integerSchemaToType(schema) {
|
|
607
|
-
const name = schema.format === "int64" ? "bigint" : "int";
|
|
608
|
-
const mods = {};
|
|
609
|
-
if (schema.minimum !== void 0) mods.min = schema.minimum;
|
|
610
|
-
if (schema.maximum !== void 0) mods.max = schema.maximum;
|
|
611
|
-
return {
|
|
612
|
-
kind: "scalar",
|
|
613
|
-
name,
|
|
614
|
-
...mods
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
__name(integerSchemaToType, "integerSchemaToType");
|
|
618
|
-
function numberSchemaToType(schema) {
|
|
619
|
-
const mods = {};
|
|
620
|
-
if (schema.minimum !== void 0) mods.min = schema.minimum;
|
|
621
|
-
if (schema.maximum !== void 0) mods.max = schema.maximum;
|
|
622
|
-
return {
|
|
623
|
-
kind: "scalar",
|
|
624
|
-
name: "number",
|
|
625
|
-
...mods
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
__name(numberSchemaToType, "numberSchemaToType");
|
|
629
|
-
function arraySchemaToType(schema, ctx) {
|
|
630
|
-
if (schema.prefixItems && schema.prefixItems.length > 0) {
|
|
631
|
-
return {
|
|
632
|
-
kind: "tuple",
|
|
633
|
-
items: schema.prefixItems.map((s) => schemaToTypeNode(s, ctx))
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
const item = schema.items ? schemaToTypeNode(schema.items, ctx) : {
|
|
637
|
-
kind: "scalar",
|
|
638
|
-
name: "unknown"
|
|
639
|
-
};
|
|
640
|
-
const mods = {};
|
|
641
|
-
if (schema.minItems !== void 0) mods.min = schema.minItems;
|
|
642
|
-
if (schema.maxItems !== void 0) mods.max = schema.maxItems;
|
|
643
|
-
return {
|
|
644
|
-
kind: "array",
|
|
645
|
-
item,
|
|
646
|
-
...mods
|
|
647
|
-
};
|
|
648
|
-
}
|
|
649
|
-
__name(arraySchemaToType, "arraySchemaToType");
|
|
650
|
-
function objectSchemaToType(schema, ctx) {
|
|
651
|
-
if (schema.additionalProperties && typeof schema.additionalProperties === "object" && !schema.properties) {
|
|
652
|
-
return {
|
|
653
|
-
kind: "record",
|
|
654
|
-
key: {
|
|
655
|
-
kind: "scalar",
|
|
656
|
-
name: "string"
|
|
657
|
-
},
|
|
658
|
-
value: schemaToTypeNode(schema.additionalProperties, ctx)
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
if (schema.properties) {
|
|
662
|
-
return schemaToInlineObject(schema, ctx);
|
|
663
|
-
}
|
|
664
|
-
return {
|
|
665
|
-
kind: "scalar",
|
|
666
|
-
name: "object"
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
__name(objectSchemaToType, "objectSchemaToType");
|
|
670
|
-
function schemaToInlineObject(schema, ctx) {
|
|
671
|
-
const fields = schemaPropertiesToFields(schema, ctx);
|
|
672
|
-
return {
|
|
673
|
-
kind: "inlineObject",
|
|
674
|
-
fields
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
__name(schemaToInlineObject, "schemaToInlineObject");
|
|
678
|
-
function schemaPropertiesToFields(schema, ctx) {
|
|
679
|
-
const properties = schema.properties ?? {};
|
|
680
|
-
const required = new Set(schema.required ?? []);
|
|
681
|
-
const fields = [];
|
|
682
|
-
for (const [name, propSchema] of Object.entries(properties)) {
|
|
683
|
-
const propCtx = {
|
|
684
|
-
...ctx,
|
|
685
|
-
path: `${ctx.path}/properties/${name}`
|
|
686
|
-
};
|
|
687
|
-
const fieldType = schemaToTypeNode(propSchema, propCtx);
|
|
688
|
-
let nullable = false;
|
|
689
|
-
let effectiveType = fieldType;
|
|
690
|
-
if (fieldType.kind === "union") {
|
|
691
|
-
const nonNull = fieldType.members.filter((m) => !(m.kind === "scalar" && m.name === "null"));
|
|
692
|
-
if (nonNull.length < fieldType.members.length) {
|
|
693
|
-
nullable = true;
|
|
694
|
-
effectiveType = nonNull.length === 1 ? nonNull[0] : {
|
|
695
|
-
kind: "union",
|
|
696
|
-
members: nonNull
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
const visibility = propSchema.readOnly ? "readonly" : propSchema.writeOnly ? "writeonly" : "normal";
|
|
701
|
-
fields.push({
|
|
702
|
-
name,
|
|
703
|
-
optional: !required.has(name),
|
|
704
|
-
nullable,
|
|
705
|
-
visibility,
|
|
706
|
-
type: effectiveType,
|
|
707
|
-
default: propSchema.default,
|
|
708
|
-
deprecated: propSchema.deprecated,
|
|
709
|
-
description: ctx.includeComments ? propSchema.description : void 0,
|
|
710
|
-
loc: LOC
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
return fields;
|
|
714
|
-
}
|
|
715
|
-
__name(schemaPropertiesToFields, "schemaPropertiesToFields");
|
|
716
|
-
function normalizeTypeField(schema) {
|
|
717
|
-
if (!schema.type) return null;
|
|
718
|
-
if (typeof schema.type === "string") {
|
|
719
|
-
return {
|
|
720
|
-
baseType: schema.type,
|
|
721
|
-
nullable: false
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
if (Array.isArray(schema.type)) {
|
|
725
|
-
const types = schema.type;
|
|
726
|
-
const nonNull = types.filter((t) => t !== "null");
|
|
727
|
-
const nullable = types.includes("null");
|
|
728
|
-
if (nonNull.length === 1) {
|
|
729
|
-
return {
|
|
730
|
-
baseType: nonNull[0],
|
|
731
|
-
nullable
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
if (nonNull.length === 0) {
|
|
735
|
-
return {
|
|
736
|
-
baseType: "null",
|
|
737
|
-
nullable: false
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
return {
|
|
741
|
-
baseType: nonNull[0],
|
|
742
|
-
nullable
|
|
743
|
-
};
|
|
744
|
-
}
|
|
745
|
-
return null;
|
|
746
|
-
}
|
|
747
|
-
__name(normalizeTypeField, "normalizeTypeField");
|
|
748
|
-
function toUnion(schemas, ctx) {
|
|
749
|
-
const members = schemas.map((s) => schemaToTypeNode(s, ctx));
|
|
750
|
-
if (members.length === 1) return members[0];
|
|
751
|
-
return {
|
|
752
|
-
kind: "union",
|
|
753
|
-
members
|
|
754
|
-
};
|
|
755
|
-
}
|
|
756
|
-
__name(toUnion, "toUnion");
|
|
757
|
-
function warnUnsupported(schema, ctx) {
|
|
758
|
-
if (schema.discriminator) ctx.warnings.warn(ctx.path, "discriminator is not supported, skipping");
|
|
759
|
-
if (schema.xml) ctx.warnings.warn(ctx.path, "xml metadata is not supported, skipping");
|
|
760
|
-
if (schema.externalDocs) ctx.warnings.info(ctx.path, "externalDocs is not supported, skipping");
|
|
761
|
-
if (schema.not) ctx.warnings.warn(ctx.path, "not keyword is not supported, skipping");
|
|
762
|
-
}
|
|
763
|
-
__name(warnUnsupported, "warnUnsupported");
|
|
764
|
-
function extractInlineModel(schema, suggestedName, ctx) {
|
|
765
|
-
if (schema.$ref) {
|
|
766
|
-
return {
|
|
767
|
-
typeNode: schemaToTypeNode(schema, ctx)
|
|
768
|
-
};
|
|
769
|
-
}
|
|
770
|
-
if (schema.properties || schema.type === "object" && schema.additionalProperties === void 0) {
|
|
771
|
-
const fields = schemaPropertiesToFields(schema, ctx);
|
|
772
|
-
const model = {
|
|
773
|
-
kind: "model",
|
|
774
|
-
name: suggestedName,
|
|
775
|
-
fields,
|
|
776
|
-
description: ctx.includeComments ? schema.description : void 0,
|
|
777
|
-
loc: LOC
|
|
778
|
-
};
|
|
779
|
-
return {
|
|
780
|
-
typeNode: {
|
|
781
|
-
kind: "ref",
|
|
782
|
-
name: suggestedName
|
|
783
|
-
},
|
|
784
|
-
model
|
|
785
|
-
};
|
|
786
|
-
}
|
|
787
|
-
return {
|
|
788
|
-
typeNode: schemaToTypeNode(schema, ctx)
|
|
789
|
-
};
|
|
790
|
-
}
|
|
791
|
-
__name(extractInlineModel, "extractInlineModel");
|
|
792
|
-
function sanitizeName(name, warnings) {
|
|
793
|
-
const cleaned = name.replace(/[^a-zA-Z0-9_$]/g, " ").split(/\s+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
794
|
-
if (cleaned !== name) {
|
|
795
|
-
warnings.info(`#/components/schemas/${name}`, `Schema name sanitized: "${name}" \u2192 "${cleaned}"`);
|
|
796
|
-
}
|
|
797
|
-
return cleaned || "UnnamedSchema";
|
|
798
|
-
}
|
|
799
|
-
__name(sanitizeName, "sanitizeName");
|
|
800
|
-
|
|
801
|
-
// src/paths-to-ast.ts
|
|
802
|
-
var LOC2 = {
|
|
803
|
-
file: "",
|
|
804
|
-
line: 0
|
|
805
|
-
};
|
|
806
|
-
var HTTP_METHODS = [
|
|
807
|
-
"get",
|
|
808
|
-
"post",
|
|
809
|
-
"put",
|
|
810
|
-
"patch",
|
|
811
|
-
"delete"
|
|
812
|
-
];
|
|
813
|
-
function pathsToRoutes(doc, ctx) {
|
|
814
|
-
const routes = [];
|
|
815
|
-
const routeTags = /* @__PURE__ */ new Map();
|
|
816
|
-
const paths = doc.paths ?? {};
|
|
817
|
-
for (const [path, pathItem] of Object.entries(paths)) {
|
|
818
|
-
if (!pathItem) continue;
|
|
819
|
-
const result = pathItemToRoute(path, pathItem, ctx);
|
|
820
|
-
if (result) {
|
|
821
|
-
routes.push(result.route);
|
|
822
|
-
routeTags.set(result.route, result.tag);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
return {
|
|
826
|
-
routes,
|
|
827
|
-
routeTags
|
|
828
|
-
};
|
|
829
|
-
}
|
|
830
|
-
__name(pathsToRoutes, "pathsToRoutes");
|
|
831
|
-
function pathItemToRoute(path, pathItem, ctx) {
|
|
832
|
-
const operations = [];
|
|
833
|
-
let primaryTag = "default";
|
|
834
|
-
const pathParams = (pathItem.parameters ?? []).filter((p) => p.in === "path");
|
|
835
|
-
for (const method of HTTP_METHODS) {
|
|
836
|
-
const op = pathItem[method];
|
|
837
|
-
if (!op) continue;
|
|
838
|
-
const opNode = operationToNode(method, op, path, ctx);
|
|
839
|
-
operations.push(opNode);
|
|
840
|
-
if (op.tags && op.tags.length > 0 && primaryTag === "default") {
|
|
841
|
-
primaryTag = op.tags[0];
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
if (operations.length === 0) return null;
|
|
845
|
-
const params = buildPathParams(path, pathParams, pathItem, ctx);
|
|
846
|
-
const route = {
|
|
847
|
-
path,
|
|
848
|
-
operations,
|
|
849
|
-
loc: LOC2
|
|
850
|
-
};
|
|
851
|
-
if (params.length > 0) {
|
|
852
|
-
route.params = {
|
|
853
|
-
kind: "params",
|
|
854
|
-
nodes: params
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
|
-
if (pathItem.description && ctx.includeComments) {
|
|
858
|
-
route.description = pathItem.description;
|
|
859
|
-
}
|
|
860
|
-
return {
|
|
861
|
-
route,
|
|
862
|
-
tag: primaryTag
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
__name(pathItemToRoute, "pathItemToRoute");
|
|
866
|
-
function operationToNode(method, op, path, ctx) {
|
|
867
|
-
const pathPrefix = `#/paths/${encodePathSegment2(path)}/${method}`;
|
|
868
|
-
const schemaCtx = makeSchemaCtx(ctx, pathPrefix);
|
|
869
|
-
const node = {
|
|
870
|
-
method,
|
|
871
|
-
responses: [],
|
|
872
|
-
loc: LOC2
|
|
873
|
-
};
|
|
874
|
-
if (op.operationId) {
|
|
875
|
-
node.sdk = op.operationId;
|
|
876
|
-
}
|
|
877
|
-
if (op.description && ctx.includeComments) {
|
|
878
|
-
node.description = op.description;
|
|
879
|
-
}
|
|
880
|
-
if (op.deprecated) {
|
|
881
|
-
node.modifiers = [
|
|
882
|
-
"deprecated"
|
|
883
|
-
];
|
|
884
|
-
}
|
|
885
|
-
const queryParams = [];
|
|
886
|
-
const headerParams = [];
|
|
887
|
-
for (const param of op.parameters ?? []) {
|
|
888
|
-
if (param.in === "query") {
|
|
889
|
-
queryParams.push(parameterToNode(param, schemaCtx));
|
|
890
|
-
} else if (param.in === "header") {
|
|
891
|
-
headerParams.push(parameterToNode(param, schemaCtx));
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
if (queryParams.length > 0) {
|
|
895
|
-
node.query = {
|
|
896
|
-
kind: "params",
|
|
897
|
-
nodes: queryParams
|
|
898
|
-
};
|
|
899
|
-
}
|
|
900
|
-
if (headerParams.length > 0) {
|
|
901
|
-
node.headers = {
|
|
902
|
-
kind: "params",
|
|
903
|
-
nodes: headerParams
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
if (op.requestBody) {
|
|
907
|
-
node.request = requestBodyToNode(op.requestBody, op.operationId ?? `${method}${toPascalCase(path)}`, schemaCtx, ctx);
|
|
908
|
-
}
|
|
909
|
-
const responses = op.responses ?? {};
|
|
910
|
-
for (const [code, resp] of Object.entries(responses)) {
|
|
911
|
-
const statusCode = parseInt(code, 10);
|
|
912
|
-
if (isNaN(statusCode)) continue;
|
|
913
|
-
const respNode = responseToNode(statusCode, resp, op.operationId ?? `${method}${toPascalCase(path)}`, schemaCtx, ctx);
|
|
914
|
-
node.responses.push(respNode);
|
|
915
|
-
}
|
|
916
|
-
if (op.security !== void 0) {
|
|
917
|
-
node.security = convertSecurity(op.security);
|
|
918
|
-
}
|
|
919
|
-
return node;
|
|
920
|
-
}
|
|
921
|
-
__name(operationToNode, "operationToNode");
|
|
922
|
-
function buildPathParams(path, pathLevelParams, pathItem, ctx) {
|
|
923
|
-
const schemaCtx = makeSchemaCtx(ctx, `#/paths/${encodePathSegment2(path)}`);
|
|
924
|
-
const paramMap = /* @__PURE__ */ new Map();
|
|
925
|
-
for (const p of pathLevelParams) {
|
|
926
|
-
paramMap.set(p.name, p);
|
|
927
|
-
}
|
|
928
|
-
for (const method of HTTP_METHODS) {
|
|
929
|
-
const op = pathItem[method];
|
|
930
|
-
if (!op?.parameters) continue;
|
|
931
|
-
for (const p of op.parameters) {
|
|
932
|
-
if (p.in === "path" && !paramMap.has(p.name)) {
|
|
933
|
-
paramMap.set(p.name, p);
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
const templateNames = [
|
|
938
|
-
...path.matchAll(/\{([^}]+)\}/g)
|
|
939
|
-
].map((m) => m[1]);
|
|
940
|
-
return templateNames.map((name) => {
|
|
941
|
-
const param = paramMap.get(name);
|
|
942
|
-
if (param) {
|
|
943
|
-
return parameterToNode(param, schemaCtx);
|
|
944
|
-
}
|
|
945
|
-
return {
|
|
946
|
-
name,
|
|
947
|
-
optional: false,
|
|
948
|
-
nullable: false,
|
|
949
|
-
type: {
|
|
950
|
-
kind: "scalar",
|
|
951
|
-
name: "string"
|
|
952
|
-
},
|
|
953
|
-
loc: LOC2
|
|
954
|
-
};
|
|
955
|
-
});
|
|
956
|
-
}
|
|
957
|
-
__name(buildPathParams, "buildPathParams");
|
|
958
|
-
function parameterToNode(param, ctx) {
|
|
959
|
-
const type = param.schema ? schemaToTypeNode(param.schema, ctx) : {
|
|
960
|
-
kind: "scalar",
|
|
961
|
-
name: "string"
|
|
962
|
-
};
|
|
963
|
-
return {
|
|
964
|
-
name: param.name,
|
|
965
|
-
optional: param.in !== "path" && !param.required,
|
|
966
|
-
nullable: false,
|
|
967
|
-
type,
|
|
968
|
-
description: ctx.includeComments ? param.description : void 0,
|
|
969
|
-
loc: LOC2
|
|
970
|
-
};
|
|
971
|
-
}
|
|
972
|
-
__name(parameterToNode, "parameterToNode");
|
|
973
|
-
function requestBodyToNode(reqBody, operationName, schemaCtx, ctx) {
|
|
974
|
-
const content = reqBody.content;
|
|
975
|
-
if (!content) return void 0;
|
|
976
|
-
const [contentType, mediaType] = Object.entries(content)[0] ?? [];
|
|
977
|
-
if (!contentType || !mediaType?.schema) return void 0;
|
|
978
|
-
const { typeNode, model } = extractInlineModel(mediaType.schema, `${toPascalCase(operationName)}Request`, schemaCtx);
|
|
979
|
-
if (model) {
|
|
980
|
-
ctx.extractedModels.push(model);
|
|
981
|
-
}
|
|
982
|
-
return {
|
|
983
|
-
contentType,
|
|
984
|
-
bodyType: typeNode
|
|
985
|
-
};
|
|
986
|
-
}
|
|
987
|
-
__name(requestBodyToNode, "requestBodyToNode");
|
|
988
|
-
function responseToNode(statusCode, resp, operationName, schemaCtx, ctx) {
|
|
989
|
-
if (!resp.content) {
|
|
990
|
-
return {
|
|
991
|
-
statusCode
|
|
992
|
-
};
|
|
993
|
-
}
|
|
994
|
-
const [contentType, mediaType] = Object.entries(resp.content)[0] ?? [];
|
|
995
|
-
if (!contentType || !mediaType?.schema) {
|
|
996
|
-
return {
|
|
997
|
-
statusCode
|
|
998
|
-
};
|
|
999
|
-
}
|
|
1000
|
-
const { typeNode, model } = extractInlineModel(mediaType.schema, `${toPascalCase(operationName)}Response${statusCode}`, schemaCtx);
|
|
1001
|
-
if (model) {
|
|
1002
|
-
ctx.extractedModels.push(model);
|
|
1003
|
-
}
|
|
1004
|
-
return {
|
|
1005
|
-
statusCode,
|
|
1006
|
-
contentType,
|
|
1007
|
-
bodyType: typeNode
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
__name(responseToNode, "responseToNode");
|
|
1011
|
-
function convertSecurity(security) {
|
|
1012
|
-
if (security.length === 0) {
|
|
1013
|
-
return "none";
|
|
1014
|
-
}
|
|
1015
|
-
const allScopes = [];
|
|
1016
|
-
for (const requirement of security) {
|
|
1017
|
-
for (const scopes of Object.values(requirement)) {
|
|
1018
|
-
allScopes.push(...scopes);
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
if (allScopes.length > 0) {
|
|
1022
|
-
return {
|
|
1023
|
-
roles: allScopes,
|
|
1024
|
-
loc: LOC2
|
|
1025
|
-
};
|
|
1026
|
-
}
|
|
1027
|
-
return {
|
|
1028
|
-
roles: [],
|
|
1029
|
-
loc: LOC2
|
|
1030
|
-
};
|
|
1031
|
-
}
|
|
1032
|
-
__name(convertSecurity, "convertSecurity");
|
|
1033
|
-
function makeSchemaCtx(ctx, path) {
|
|
1034
|
-
return {
|
|
1035
|
-
circularRefs: ctx.circularRefs,
|
|
1036
|
-
warnings: ctx.warnings,
|
|
1037
|
-
path,
|
|
1038
|
-
includeComments: ctx.includeComments,
|
|
1039
|
-
namedSchemas: ctx.namedSchemas,
|
|
1040
|
-
extractedModels: ctx.extractedModels,
|
|
1041
|
-
inlineCounter: 0
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
__name(makeSchemaCtx, "makeSchemaCtx");
|
|
1045
|
-
function toPascalCase(input) {
|
|
1046
|
-
return input.replace(/[^a-zA-Z0-9]/g, " ").split(/\s+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
1047
|
-
}
|
|
1048
|
-
__name(toPascalCase, "toPascalCase");
|
|
1049
|
-
function encodePathSegment2(s) {
|
|
1050
|
-
return s.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
1051
|
-
}
|
|
1052
|
-
__name(encodePathSegment2, "encodePathSegment");
|
|
1053
|
-
|
|
1054
|
-
// src/tag-splitter.ts
|
|
1055
|
-
function splitByTag(models, routes, routeTags) {
|
|
1056
|
-
const routesByTag = /* @__PURE__ */ new Map();
|
|
1057
|
-
for (const route of routes) {
|
|
1058
|
-
const tag = routeTags.get(route) ?? "default";
|
|
1059
|
-
const group = routesByTag.get(tag) ?? [];
|
|
1060
|
-
group.push(route);
|
|
1061
|
-
routesByTag.set(tag, group);
|
|
1062
|
-
}
|
|
1063
|
-
const modelsByTag = /* @__PURE__ */ new Map();
|
|
1064
|
-
for (const [tag, tagRoutes] of routesByTag) {
|
|
1065
|
-
const refs = /* @__PURE__ */ new Set();
|
|
1066
|
-
for (const route of tagRoutes) {
|
|
1067
|
-
collectRouteRefs(route, refs);
|
|
1068
|
-
}
|
|
1069
|
-
modelsByTag.set(tag, refs);
|
|
1070
|
-
}
|
|
1071
|
-
const modelNameToModel = new Map(models.map((m) => [
|
|
1072
|
-
m.name,
|
|
1073
|
-
m
|
|
1074
|
-
]));
|
|
1075
|
-
const modelAssignment = /* @__PURE__ */ new Map();
|
|
1076
|
-
for (const model of models) {
|
|
1077
|
-
const tags = [];
|
|
1078
|
-
for (const [tag, refs] of modelsByTag) {
|
|
1079
|
-
if (refs.has(model.name)) {
|
|
1080
|
-
tags.push(tag);
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
if (tags.length === 0) {
|
|
1084
|
-
modelAssignment.set(model.name, "shared");
|
|
1085
|
-
} else if (tags.length === 1) {
|
|
1086
|
-
modelAssignment.set(model.name, tags[0]);
|
|
1087
|
-
} else {
|
|
1088
|
-
modelAssignment.set(model.name, "shared");
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
for (const model of models) {
|
|
1092
|
-
if (modelAssignment.get(model.name) === "shared") {
|
|
1093
|
-
const refs = /* @__PURE__ */ new Set();
|
|
1094
|
-
collectModelRefs(model, refs);
|
|
1095
|
-
for (const ref of refs) {
|
|
1096
|
-
if (modelNameToModel.has(ref)) {
|
|
1097
|
-
const currentTag = modelAssignment.get(ref);
|
|
1098
|
-
if (currentTag && currentTag !== "shared") {
|
|
1099
|
-
const otherTags = [
|
|
1100
|
-
...modelsByTag.entries()
|
|
1101
|
-
].filter(([t, r]) => t !== currentTag && r.has(ref)).map(([t]) => t);
|
|
1102
|
-
if (otherTags.length > 0) {
|
|
1103
|
-
modelAssignment.set(ref, "shared");
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
const result = /* @__PURE__ */ new Map();
|
|
1111
|
-
const allTags = /* @__PURE__ */ new Set([
|
|
1112
|
-
...routesByTag.keys(),
|
|
1113
|
-
...new Set(modelAssignment.values())
|
|
1114
|
-
]);
|
|
1115
|
-
for (const tag of allTags) {
|
|
1116
|
-
const tagModels = models.filter((m) => modelAssignment.get(m.name) === tag);
|
|
1117
|
-
const tagRoutes = routesByTag.get(tag) ?? [];
|
|
1118
|
-
if (tagModels.length === 0 && tagRoutes.length === 0) continue;
|
|
1119
|
-
const filename = sanitizeFilename(tag);
|
|
1120
|
-
result.set(`${filename}.ck`, {
|
|
1121
|
-
kind: "ckRoot",
|
|
1122
|
-
meta: tag !== "shared" ? {
|
|
1123
|
-
area: tag
|
|
1124
|
-
} : {},
|
|
1125
|
-
services: {},
|
|
1126
|
-
models: tagModels,
|
|
1127
|
-
routes: tagRoutes,
|
|
1128
|
-
file: `${filename}.ck`
|
|
1129
|
-
});
|
|
1130
|
-
}
|
|
1131
|
-
return result;
|
|
1132
|
-
}
|
|
1133
|
-
__name(splitByTag, "splitByTag");
|
|
1134
|
-
function mergeIntoSingle(models, routes, filename = "api") {
|
|
1135
|
-
return {
|
|
1136
|
-
kind: "ckRoot",
|
|
1137
|
-
meta: {},
|
|
1138
|
-
services: {},
|
|
1139
|
-
models,
|
|
1140
|
-
routes,
|
|
1141
|
-
file: `${filename}.ck`
|
|
1142
|
-
};
|
|
1143
|
-
}
|
|
1144
|
-
__name(mergeIntoSingle, "mergeIntoSingle");
|
|
1145
|
-
function collectRouteRefs(route, refs) {
|
|
1146
|
-
if (route.params) {
|
|
1147
|
-
collectParamSourceRefs(route.params, refs);
|
|
1148
|
-
}
|
|
1149
|
-
for (const op of route.operations) {
|
|
1150
|
-
if (op.query) collectParamSourceRefs(op.query, refs);
|
|
1151
|
-
if (op.headers) collectParamSourceRefs(op.headers, refs);
|
|
1152
|
-
if (op.request) collectTypeRefs(op.request.bodyType, refs);
|
|
1153
|
-
for (const resp of op.responses) {
|
|
1154
|
-
if (resp.bodyType) collectTypeRefs(resp.bodyType, refs);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
__name(collectRouteRefs, "collectRouteRefs");
|
|
1159
|
-
function collectParamSourceRefs(source, refs) {
|
|
1160
|
-
if (typeof source === "string") {
|
|
1161
|
-
refs.add(source);
|
|
1162
|
-
return;
|
|
1163
|
-
}
|
|
1164
|
-
if (Array.isArray(source)) {
|
|
1165
|
-
for (const param of source) {
|
|
1166
|
-
if (param && typeof param === "object" && "type" in param) {
|
|
1167
|
-
collectTypeRefs(param.type, refs);
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
return;
|
|
1171
|
-
}
|
|
1172
|
-
if (source && typeof source === "object" && "kind" in source) {
|
|
1173
|
-
collectTypeRefs(source, refs);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
__name(collectParamSourceRefs, "collectParamSourceRefs");
|
|
1177
|
-
function collectTypeRefs(type, refs) {
|
|
1178
|
-
switch (type.kind) {
|
|
1179
|
-
case "ref":
|
|
1180
|
-
refs.add(type.name);
|
|
1181
|
-
break;
|
|
1182
|
-
case "array":
|
|
1183
|
-
collectTypeRefs(type.item, refs);
|
|
1184
|
-
break;
|
|
1185
|
-
case "tuple":
|
|
1186
|
-
for (const item of type.items) collectTypeRefs(item, refs);
|
|
1187
|
-
break;
|
|
1188
|
-
case "record":
|
|
1189
|
-
collectTypeRefs(type.key, refs);
|
|
1190
|
-
collectTypeRefs(type.value, refs);
|
|
1191
|
-
break;
|
|
1192
|
-
case "union":
|
|
1193
|
-
case "intersection":
|
|
1194
|
-
for (const member of type.members) collectTypeRefs(member, refs);
|
|
1195
|
-
break;
|
|
1196
|
-
case "inlineObject":
|
|
1197
|
-
for (const field of type.fields) collectTypeRefs(field.type, refs);
|
|
1198
|
-
break;
|
|
1199
|
-
case "lazy":
|
|
1200
|
-
collectTypeRefs(type.inner, refs);
|
|
1201
|
-
break;
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
__name(collectTypeRefs, "collectTypeRefs");
|
|
1205
|
-
function collectModelRefs(model, refs) {
|
|
1206
|
-
if (model.base) refs.add(model.base);
|
|
1207
|
-
if (model.type) collectTypeRefs(model.type, refs);
|
|
1208
|
-
for (const field of model.fields) {
|
|
1209
|
-
collectTypeRefs(field.type, refs);
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
__name(collectModelRefs, "collectModelRefs");
|
|
1213
|
-
function sanitizeFilename(tag) {
|
|
1214
|
-
return tag.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "default";
|
|
1215
|
-
}
|
|
1216
|
-
__name(sanitizeFilename, "sanitizeFilename");
|
|
1217
|
-
|
|
1218
|
-
// src/ast-to-ck.ts
|
|
1219
|
-
var INDENT = " ";
|
|
1220
|
-
function astToCk(root, options = {}) {
|
|
1221
|
-
const { includeComments = true } = options;
|
|
1222
|
-
const ctx = {
|
|
1223
|
-
includeComments
|
|
1224
|
-
};
|
|
1225
|
-
const parts = [];
|
|
1226
|
-
const optionsBlock = serializeOptions(root);
|
|
1227
|
-
if (optionsBlock) parts.push(optionsBlock);
|
|
1228
|
-
for (const model of root.models) {
|
|
1229
|
-
parts.push(serializeModel(model, ctx));
|
|
1230
|
-
}
|
|
1231
|
-
for (const route of root.routes) {
|
|
1232
|
-
parts.push(serializeRoute(route, ctx));
|
|
1233
|
-
}
|
|
1234
|
-
return parts.join("\n\n") + "\n";
|
|
1235
|
-
}
|
|
1236
|
-
__name(astToCk, "astToCk");
|
|
1237
|
-
function serializeOptions(root) {
|
|
1238
|
-
const hasKeys = Object.keys(root.meta).length > 0;
|
|
1239
|
-
const hasServices = root.services && Object.keys(root.services).length > 0;
|
|
1240
|
-
const hasSecurity = root.security !== void 0;
|
|
1241
|
-
if (!hasKeys && !hasServices && !hasSecurity) return null;
|
|
1242
|
-
const lines = [
|
|
1243
|
-
"options {"
|
|
1244
|
-
];
|
|
1245
|
-
if (hasKeys) {
|
|
1246
|
-
lines.push(`${INDENT}keys: {`);
|
|
1247
|
-
for (const [key, value] of Object.entries(root.meta)) {
|
|
1248
|
-
lines.push(`${INDENT}${INDENT}${key}: ${value}`);
|
|
1249
|
-
}
|
|
1250
|
-
lines.push(`${INDENT}}`);
|
|
1251
|
-
}
|
|
1252
|
-
if (hasServices) {
|
|
1253
|
-
lines.push(`${INDENT}services: {`);
|
|
1254
|
-
for (const [name, path] of Object.entries(root.services)) {
|
|
1255
|
-
lines.push(`${INDENT}${INDENT}${name}: "${path}"`);
|
|
1256
|
-
}
|
|
1257
|
-
lines.push(`${INDENT}}`);
|
|
1258
|
-
}
|
|
1259
|
-
if (hasSecurity) {
|
|
1260
|
-
lines.push(`${INDENT}security: {`);
|
|
1261
|
-
if (root.security === "none") {
|
|
1262
|
-
lines.push(`${INDENT}${INDENT}none`);
|
|
1263
|
-
} else {
|
|
1264
|
-
const sec = root.security;
|
|
1265
|
-
if (sec.roles && sec.roles.length > 0) {
|
|
1266
|
-
lines.push(`${INDENT}${INDENT}roles: [${sec.roles.join(", ")}]`);
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
lines.push(`${INDENT}}`);
|
|
1270
|
-
}
|
|
1271
|
-
lines.push("}");
|
|
1272
|
-
return lines.join("\n");
|
|
1273
|
-
}
|
|
1274
|
-
__name(serializeOptions, "serializeOptions");
|
|
1275
|
-
function serializeModel(model, ctx) {
|
|
1276
|
-
const parts = [];
|
|
1277
|
-
const prefixes = [];
|
|
1278
|
-
if (model.inputCase && model.inputCase !== "camel") {
|
|
1279
|
-
prefixes.push(`format(input=${model.inputCase})`);
|
|
1280
|
-
}
|
|
1281
|
-
if (model.mode && model.mode !== "strict") {
|
|
1282
|
-
prefixes.push(`mode(${model.mode})`);
|
|
1283
|
-
}
|
|
1284
|
-
if (model.deprecated) {
|
|
1285
|
-
prefixes.push("deprecated");
|
|
1286
|
-
}
|
|
1287
|
-
const prefix = prefixes.length > 0 ? prefixes.join(" ") + " " : "";
|
|
1288
|
-
const comment = ctx.includeComments && model.description ? ` # ${model.description}` : "";
|
|
1289
|
-
if (model.type) {
|
|
1290
|
-
parts.push(`contract ${prefix}${model.name}: ${serializeType(model.type)}${comment}`);
|
|
1291
|
-
return parts.join("");
|
|
1292
|
-
}
|
|
1293
|
-
if (model.base) {
|
|
1294
|
-
parts.push(`contract ${prefix}${model.name}: ${model.base} & {${comment}`);
|
|
1295
|
-
} else {
|
|
1296
|
-
parts.push(`contract ${prefix}${model.name}: {${comment}`);
|
|
1297
|
-
}
|
|
1298
|
-
for (const field of model.fields) {
|
|
1299
|
-
parts.push(serializeField(field, 1, ctx));
|
|
1300
|
-
}
|
|
1301
|
-
parts.push("}");
|
|
1302
|
-
return parts.join("\n");
|
|
1303
|
-
}
|
|
1304
|
-
__name(serializeModel, "serializeModel");
|
|
1305
|
-
function serializeField(field, depth, ctx) {
|
|
1306
|
-
const indent = INDENT.repeat(depth);
|
|
1307
|
-
const optional = field.optional ? "?" : "";
|
|
1308
|
-
const visibility = field.visibility !== "normal" ? `${field.visibility} ` : "";
|
|
1309
|
-
const deprecated = field.deprecated ? "deprecated " : "";
|
|
1310
|
-
let typeStr = serializeType(field.type);
|
|
1311
|
-
if (field.nullable && !typeContainsNull(field.type)) {
|
|
1312
|
-
typeStr = `${typeStr} | null`;
|
|
1313
|
-
}
|
|
1314
|
-
const defaultVal = field.default !== void 0 ? ` = ${serializeDefault(field.default)}` : "";
|
|
1315
|
-
const comment = ctx.includeComments && field.description ? ` # ${field.description}` : "";
|
|
1316
|
-
return `${indent}${field.name}${optional}: ${deprecated}${visibility}${typeStr}${defaultVal}${comment}`;
|
|
1317
|
-
}
|
|
1318
|
-
__name(serializeField, "serializeField");
|
|
1319
|
-
function typeContainsNull(type) {
|
|
1320
|
-
if (type.kind === "scalar" && type.name === "null") return true;
|
|
1321
|
-
if (type.kind === "union") return type.members.some(typeContainsNull);
|
|
1322
|
-
return false;
|
|
1323
|
-
}
|
|
1324
|
-
__name(typeContainsNull, "typeContainsNull");
|
|
1325
|
-
function serializeDefault(value) {
|
|
1326
|
-
if (typeof value === "string") {
|
|
1327
|
-
if (/^[a-zA-Z_$][a-zA-Z0-9_$\-.]*$/.test(value)) return value;
|
|
1328
|
-
return `"${value}"`;
|
|
1329
|
-
}
|
|
1330
|
-
return String(value);
|
|
1331
|
-
}
|
|
1332
|
-
__name(serializeDefault, "serializeDefault");
|
|
1333
|
-
function serializeType(type) {
|
|
1334
|
-
switch (type.kind) {
|
|
1335
|
-
case "scalar":
|
|
1336
|
-
return serializeScalar(type);
|
|
1337
|
-
case "array":
|
|
1338
|
-
return serializeArray(type);
|
|
1339
|
-
case "tuple":
|
|
1340
|
-
return `tuple(${type.items.map(serializeType).join(", ")})`;
|
|
1341
|
-
case "record":
|
|
1342
|
-
return `record(${serializeType(type.key)}, ${serializeType(type.value)})`;
|
|
1343
|
-
case "enum":
|
|
1344
|
-
return `enum(${type.values.join(", ")})`;
|
|
1345
|
-
case "literal":
|
|
1346
|
-
return serializeLiteral(type);
|
|
1347
|
-
case "union":
|
|
1348
|
-
return type.members.map(serializeType).join(" | ");
|
|
1349
|
-
case "intersection":
|
|
1350
|
-
return type.members.map(serializeType).join(" & ");
|
|
1351
|
-
case "ref":
|
|
1352
|
-
return type.name;
|
|
1353
|
-
case "inlineObject":
|
|
1354
|
-
return serializeInlineObject(type);
|
|
1355
|
-
case "lazy":
|
|
1356
|
-
return `lazy(${serializeType(type.inner)})`;
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
__name(serializeType, "serializeType");
|
|
1360
|
-
function serializeScalar(type) {
|
|
1361
|
-
const args = [];
|
|
1362
|
-
if (type.len !== void 0) args.push(`length=${type.len}`);
|
|
1363
|
-
if (type.min !== void 0) args.push(typeof type.min === "string" ? `min="${type.min}"` : `min=${type.min}`);
|
|
1364
|
-
if (type.max !== void 0) args.push(typeof type.max === "string" ? `max="${type.max}"` : `max=${type.max}`);
|
|
1365
|
-
if (type.regex !== void 0) args.push(`regex=${type.regex}`);
|
|
1366
|
-
if (type.format !== void 0) args.push(`format=${type.format}`);
|
|
1367
|
-
if (args.length === 0) return type.name;
|
|
1368
|
-
return `${type.name}(${args.join(", ")})`;
|
|
1369
|
-
}
|
|
1370
|
-
__name(serializeScalar, "serializeScalar");
|
|
1371
|
-
function serializeArray(type) {
|
|
1372
|
-
const args = [
|
|
1373
|
-
serializeType(type.item)
|
|
1374
|
-
];
|
|
1375
|
-
if (type.min !== void 0) args.push(`min=${type.min}`);
|
|
1376
|
-
if (type.max !== void 0) args.push(`max=${type.max}`);
|
|
1377
|
-
return `array(${args.join(", ")})`;
|
|
1378
|
-
}
|
|
1379
|
-
__name(serializeArray, "serializeArray");
|
|
1380
|
-
function serializeLiteral(type) {
|
|
1381
|
-
if (typeof type.value === "string") return `literal("${type.value}")`;
|
|
1382
|
-
return `literal(${type.value})`;
|
|
1383
|
-
}
|
|
1384
|
-
__name(serializeLiteral, "serializeLiteral");
|
|
1385
|
-
function serializeInlineObject(type) {
|
|
1386
|
-
const modePrefix = type.mode ? `mode(${type.mode}) ` : "";
|
|
1387
|
-
if (type.fields.length === 0) return `${modePrefix}{}`;
|
|
1388
|
-
const lines = [
|
|
1389
|
-
`${modePrefix}{`
|
|
1390
|
-
];
|
|
1391
|
-
for (const field of type.fields) {
|
|
1392
|
-
lines.push(serializeField(field, 2, {
|
|
1393
|
-
includeComments: true
|
|
1394
|
-
}));
|
|
1395
|
-
}
|
|
1396
|
-
lines.push(`${INDENT}}`);
|
|
1397
|
-
return lines.join("\n");
|
|
1398
|
-
}
|
|
1399
|
-
__name(serializeInlineObject, "serializeInlineObject");
|
|
1400
|
-
function serializeRoute(route, ctx) {
|
|
1401
|
-
const lines = [];
|
|
1402
|
-
const modStr = serializeModifiers(route.modifiers);
|
|
1403
|
-
const comment = ctx.includeComments && route.description ? ` # ${route.description}` : "";
|
|
1404
|
-
lines.push(`operation${modStr} ${route.path}: {${comment}`);
|
|
1405
|
-
if (route.params) {
|
|
1406
|
-
serializeParamSource(lines, "params", route.params, route.paramsMode, 1, ctx);
|
|
1407
|
-
}
|
|
1408
|
-
if (route.security !== void 0) {
|
|
1409
|
-
serializeSecurityBlock(lines, route.security, 1, ctx);
|
|
1410
|
-
}
|
|
1411
|
-
for (const op of route.operations) {
|
|
1412
|
-
serializeOperation(lines, op, 1, ctx);
|
|
1413
|
-
}
|
|
1414
|
-
lines.push("}");
|
|
1415
|
-
return lines.join("\n");
|
|
1416
|
-
}
|
|
1417
|
-
__name(serializeRoute, "serializeRoute");
|
|
1418
|
-
function serializeOperation(lines, op, depth, ctx) {
|
|
1419
|
-
const indent = INDENT.repeat(depth);
|
|
1420
|
-
const modStr = serializeModifiers(op.modifiers);
|
|
1421
|
-
const comment = ctx.includeComments && op.description ? ` # ${op.description}` : "";
|
|
1422
|
-
lines.push(`${indent}${op.method}${modStr}: {${comment}`);
|
|
1423
|
-
const inner = INDENT.repeat(depth + 1);
|
|
1424
|
-
if (op.service) {
|
|
1425
|
-
lines.push(`${inner}service: ${op.service}`);
|
|
1426
|
-
}
|
|
1427
|
-
if (op.sdk) {
|
|
1428
|
-
lines.push(`${inner}sdk: ${op.sdk}`);
|
|
1429
|
-
}
|
|
1430
|
-
if (op.signature) {
|
|
1431
|
-
const sigComment = ctx.includeComments && op.signatureDescription ? ` # ${op.signatureDescription}` : "";
|
|
1432
|
-
lines.push(`${inner}signature: ${op.signature}${sigComment}`);
|
|
1433
|
-
}
|
|
1434
|
-
if (op.security !== void 0) {
|
|
1435
|
-
serializeSecurityBlock(lines, op.security, depth + 1, ctx);
|
|
1436
|
-
}
|
|
1437
|
-
if (op.query) {
|
|
1438
|
-
serializeParamSource(lines, "query", op.query, op.queryMode, depth + 1, ctx);
|
|
1439
|
-
}
|
|
1440
|
-
if (op.headers) {
|
|
1441
|
-
serializeParamSource(lines, "headers", op.headers, op.headersMode, depth + 1, ctx);
|
|
1442
|
-
}
|
|
1443
|
-
if (op.request) {
|
|
1444
|
-
serializeRequest(lines, op.request, depth + 1);
|
|
1445
|
-
}
|
|
1446
|
-
if (op.responses.length > 0) {
|
|
1447
|
-
serializeResponses(lines, op.responses, depth + 1);
|
|
1448
|
-
}
|
|
1449
|
-
lines.push(`${indent}}`);
|
|
1450
|
-
return lines;
|
|
1451
|
-
}
|
|
1452
|
-
__name(serializeOperation, "serializeOperation");
|
|
1453
|
-
function serializeModifiers(modifiers) {
|
|
1454
|
-
if (!modifiers || modifiers.length === 0) return "";
|
|
1455
|
-
return `(${modifiers.join(", ")})`;
|
|
1456
|
-
}
|
|
1457
|
-
__name(serializeModifiers, "serializeModifiers");
|
|
1458
|
-
function serializeParamSource(lines, keyword, source, mode, depth, ctx) {
|
|
1459
|
-
const indent = INDENT.repeat(depth);
|
|
1460
|
-
if (source.kind === "ref") {
|
|
1461
|
-
lines.push(`${indent}${keyword}: ${source.name}`);
|
|
1462
|
-
return;
|
|
1463
|
-
}
|
|
1464
|
-
if (source.kind === "type") {
|
|
1465
|
-
lines.push(`${indent}${keyword}: ${serializeType(source.node)}`);
|
|
1466
|
-
return;
|
|
1467
|
-
}
|
|
1468
|
-
const modeStr = mode ? `mode(${mode}) ` : "";
|
|
1469
|
-
lines.push(`${indent}${keyword}: ${modeStr}{`);
|
|
1470
|
-
for (const param of source.nodes) {
|
|
1471
|
-
const optional = param.optional ? "?" : "";
|
|
1472
|
-
let typeStr = serializeType(param.type);
|
|
1473
|
-
if (param.nullable && !typeContainsNull(param.type)) {
|
|
1474
|
-
typeStr = `${typeStr} | null`;
|
|
1475
|
-
}
|
|
1476
|
-
const defaultVal = param.default !== void 0 ? ` = ${serializeDefault(param.default)}` : "";
|
|
1477
|
-
const comment = ctx.includeComments && param.description ? ` # ${param.description}` : "";
|
|
1478
|
-
lines.push(`${INDENT.repeat(depth + 1)}${param.name}${optional}: ${typeStr}${defaultVal}${comment}`);
|
|
1479
|
-
}
|
|
1480
|
-
lines.push(`${indent}}`);
|
|
1481
|
-
}
|
|
1482
|
-
__name(serializeParamSource, "serializeParamSource");
|
|
1483
|
-
function serializeRequest(lines, request, depth) {
|
|
1484
|
-
const indent = INDENT.repeat(depth);
|
|
1485
|
-
lines.push(`${indent}request: {`);
|
|
1486
|
-
lines.push(`${INDENT.repeat(depth + 1)}${request.contentType}: ${serializeType(request.bodyType)}`);
|
|
1487
|
-
lines.push(`${indent}}`);
|
|
1488
|
-
}
|
|
1489
|
-
__name(serializeRequest, "serializeRequest");
|
|
1490
|
-
function serializeResponses(lines, responses, depth) {
|
|
1491
|
-
const indent = INDENT.repeat(depth);
|
|
1492
|
-
lines.push(`${indent}response: {`);
|
|
1493
|
-
for (const resp of responses) {
|
|
1494
|
-
if (resp.bodyType && resp.contentType) {
|
|
1495
|
-
lines.push(`${INDENT.repeat(depth + 1)}${resp.statusCode}: {`);
|
|
1496
|
-
lines.push(`${INDENT.repeat(depth + 2)}${resp.contentType}: ${serializeType(resp.bodyType)}`);
|
|
1497
|
-
lines.push(`${INDENT.repeat(depth + 1)}}`);
|
|
1498
|
-
} else {
|
|
1499
|
-
lines.push(`${INDENT.repeat(depth + 1)}${resp.statusCode}:`);
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
lines.push(`${indent}}`);
|
|
1503
|
-
}
|
|
1504
|
-
__name(serializeResponses, "serializeResponses");
|
|
1505
|
-
function serializeSecurityBlock(lines, security, depth, ctx) {
|
|
1506
|
-
const indent = INDENT.repeat(depth);
|
|
1507
|
-
if (security === "none") {
|
|
1508
|
-
lines.push(`${indent}security: none`);
|
|
1509
|
-
return;
|
|
1510
|
-
}
|
|
1511
|
-
const sec = security;
|
|
1512
|
-
if (sec.roles && sec.roles.length > 0) {
|
|
1513
|
-
const rolesComment = ctx.includeComments && sec.rolesDescription ? ` # ${sec.rolesDescription}` : "";
|
|
1514
|
-
lines.push(`${indent}security: {`);
|
|
1515
|
-
lines.push(`${INDENT.repeat(depth + 1)}roles: [${sec.roles.join(", ")}]${rolesComment}`);
|
|
1516
|
-
lines.push(`${indent}}`);
|
|
1517
|
-
} else {
|
|
1518
|
-
lines.push(`${indent}security: {}`);
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
__name(serializeSecurityBlock, "serializeSecurityBlock");
|
|
1522
|
-
|
|
1523
|
-
// src/convert.ts
|
|
1524
|
-
import { readFileSync } from "fs";
|
|
1525
|
-
import { parse as parseYaml } from "yaml";
|
|
1526
|
-
|
|
1527
|
-
// src/warnings.ts
|
|
1528
|
-
var WarningCollector = class {
|
|
1529
|
-
static {
|
|
1530
|
-
__name(this, "WarningCollector");
|
|
1531
|
-
}
|
|
1532
|
-
warnings = [];
|
|
1533
|
-
onWarning;
|
|
1534
|
-
constructor(onWarning) {
|
|
1535
|
-
this.onWarning = onWarning;
|
|
1536
|
-
}
|
|
1537
|
-
warn(path, message) {
|
|
1538
|
-
this.add({
|
|
1539
|
-
path,
|
|
1540
|
-
message,
|
|
1541
|
-
severity: "warn"
|
|
1542
|
-
});
|
|
1543
|
-
}
|
|
1544
|
-
info(path, message) {
|
|
1545
|
-
this.add({
|
|
1546
|
-
path,
|
|
1547
|
-
message,
|
|
1548
|
-
severity: "info"
|
|
1549
|
-
});
|
|
1550
|
-
}
|
|
1551
|
-
add(warning) {
|
|
1552
|
-
this.warnings.push(warning);
|
|
1553
|
-
this.onWarning?.(warning);
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1556
|
-
|
|
1557
|
-
// src/convert.ts
|
|
1558
|
-
async function convertOpenApiToCk(options) {
|
|
1559
|
-
const { split = "by-tag", includeComments = true } = options;
|
|
1560
|
-
const warnings = new WarningCollector(options.onWarning);
|
|
1561
|
-
const rawDoc = await parseInput(options.input);
|
|
1562
|
-
const doc = normalize(rawDoc, warnings);
|
|
1563
|
-
const schemas = sanitizeSchemaNames(doc, warnings);
|
|
1564
|
-
const circularRefs = detectCircularRefs(schemas);
|
|
1565
|
-
const extractedModels = [];
|
|
1566
|
-
const schemaCtx = {
|
|
1567
|
-
circularRefs,
|
|
1568
|
-
warnings,
|
|
1569
|
-
path: "#/components/schemas",
|
|
1570
|
-
includeComments,
|
|
1571
|
-
namedSchemas: schemas,
|
|
1572
|
-
extractedModels,
|
|
1573
|
-
inlineCounter: 0
|
|
1574
|
-
};
|
|
1575
|
-
const models = schemasToModels(schemas, schemaCtx);
|
|
1576
|
-
const { routes, routeTags } = pathsToRoutes(doc, {
|
|
1577
|
-
circularRefs,
|
|
1578
|
-
warnings,
|
|
1579
|
-
includeComments,
|
|
1580
|
-
namedSchemas: schemas,
|
|
1581
|
-
extractedModels,
|
|
1582
|
-
globalSecurity: doc.security
|
|
1583
|
-
});
|
|
1584
|
-
const files = /* @__PURE__ */ new Map();
|
|
1585
|
-
if (split === "by-tag") {
|
|
1586
|
-
const ckRoots = splitByTag(models, routes, routeTags);
|
|
1587
|
-
for (const [filename, root] of ckRoots) {
|
|
1588
|
-
files.set(filename, astToCk(root, {
|
|
1589
|
-
includeComments
|
|
1590
|
-
}));
|
|
1591
|
-
}
|
|
1592
|
-
} else {
|
|
1593
|
-
const root = mergeIntoSingle(models, routes);
|
|
1594
|
-
files.set("api.ck", astToCk(root, {
|
|
1595
|
-
includeComments
|
|
1596
|
-
}));
|
|
1597
|
-
}
|
|
1598
|
-
return {
|
|
1599
|
-
files,
|
|
1600
|
-
warnings: warnings.warnings
|
|
1601
|
-
};
|
|
1602
|
-
}
|
|
1603
|
-
__name(convertOpenApiToCk, "convertOpenApiToCk");
|
|
1604
|
-
async function parseInput(input) {
|
|
1605
|
-
if (typeof input === "object") {
|
|
1606
|
-
return input;
|
|
1607
|
-
}
|
|
1608
|
-
try {
|
|
1609
|
-
const content = readFileSync(input, "utf-8");
|
|
1610
|
-
return parseJsonOrYaml(content);
|
|
1611
|
-
} catch {
|
|
1612
|
-
return parseJsonOrYaml(input);
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
__name(parseInput, "parseInput");
|
|
1616
|
-
function parseJsonOrYaml(content) {
|
|
1617
|
-
try {
|
|
1618
|
-
return JSON.parse(content);
|
|
1619
|
-
} catch {
|
|
1620
|
-
return parseYaml(content);
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
__name(parseJsonOrYaml, "parseJsonOrYaml");
|
|
1624
|
-
function sanitizeSchemaNames(doc, warnings) {
|
|
1625
|
-
const original = doc.components?.schemas ?? {};
|
|
1626
|
-
const sanitized = {};
|
|
1627
|
-
const nameMap = /* @__PURE__ */ new Map();
|
|
1628
|
-
for (const name of Object.keys(original)) {
|
|
1629
|
-
const clean = sanitizeName(name, warnings);
|
|
1630
|
-
if (sanitized[clean]) {
|
|
1631
|
-
warnings.warn(`#/components/schemas/${name}`, `Name collision after sanitization: "${name}" and another schema both map to "${clean}"`);
|
|
1632
|
-
let i = 2;
|
|
1633
|
-
while (sanitized[`${clean}${i}`]) i++;
|
|
1634
|
-
nameMap.set(name, `${clean}${i}`);
|
|
1635
|
-
sanitized[`${clean}${i}`] = original[name];
|
|
1636
|
-
} else {
|
|
1637
|
-
nameMap.set(name, clean);
|
|
1638
|
-
sanitized[clean] = original[name];
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
if (nameMap.size > 0) {
|
|
1642
|
-
updateRefs(doc, nameMap);
|
|
1643
|
-
}
|
|
1644
|
-
return sanitized;
|
|
1645
|
-
}
|
|
1646
|
-
__name(sanitizeSchemaNames, "sanitizeSchemaNames");
|
|
1647
|
-
function updateRefs(obj, nameMap) {
|
|
1648
|
-
if (!obj || typeof obj !== "object") return;
|
|
1649
|
-
if (Array.isArray(obj)) {
|
|
1650
|
-
for (const item of obj) updateRefs(item, nameMap);
|
|
1651
|
-
return;
|
|
1652
|
-
}
|
|
1653
|
-
const record = obj;
|
|
1654
|
-
if (typeof record.$ref === "string") {
|
|
1655
|
-
const match = record.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
1656
|
-
if (match?.[1] && nameMap.has(match[1])) {
|
|
1657
|
-
record.$ref = `#/components/schemas/${nameMap.get(match[1])}`;
|
|
1658
|
-
}
|
|
1659
|
-
}
|
|
1660
|
-
for (const value of Object.values(record)) {
|
|
1661
|
-
updateRefs(value, nameMap);
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
__name(updateRefs, "updateRefs");
|
|
1665
|
-
|
|
1666
|
-
export {
|
|
1667
|
-
__name,
|
|
1668
|
-
normalize,
|
|
1669
|
-
detectCircularRefs,
|
|
1670
|
-
extractRefName,
|
|
1671
|
-
schemasToModels,
|
|
1672
|
-
schemaToTypeNode,
|
|
1673
|
-
sanitizeName,
|
|
1674
|
-
pathsToRoutes,
|
|
1675
|
-
splitByTag,
|
|
1676
|
-
mergeIntoSingle,
|
|
1677
|
-
astToCk,
|
|
1678
|
-
serializeType,
|
|
1679
|
-
convertOpenApiToCk
|
|
1680
|
-
};
|
|
1681
|
-
//# sourceMappingURL=chunk-MQTKLXTN.js.map
|