@kubb/ast 5.18.5 → 5.18.6
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/README.md +8 -8
- package/dist/index.cjs +1015 -624
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1495 -1315
- package/dist/index.d.ts +1495 -1315
- package/dist/index.js +1082 -751
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
// \0rolldown/runtime.js
|
|
3
3
|
var __create = Object.create;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", {
|
|
6
|
+
value,
|
|
7
|
+
configurable: true
|
|
8
|
+
});
|
|
5
9
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
10
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
11
|
var __getProtoOf = Object.getPrototypeOf;
|
|
@@ -29,14 +33,29 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
33
|
value: mod,
|
|
30
34
|
enumerable: true
|
|
31
35
|
}) : target, mod));
|
|
32
|
-
let node_crypto = require("node:crypto");
|
|
33
36
|
let node_path = require("node:path");
|
|
34
37
|
node_path = __toESM(node_path, 1);
|
|
38
|
+
let node_crypto = require("node:crypto");
|
|
39
|
+
// ../../internals/utils/src/promise.ts
|
|
40
|
+
/**
|
|
41
|
+
* Returns the value cached under `key` in `store`, computing and storing it on the first call.
|
|
42
|
+
* Pass a `WeakMap` for object keys, so an entry goes away with its key, or a `Map` for primitive
|
|
43
|
+
* keys. A cached `null` or `undefined` counts as a hit, so `compute` runs once per key.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* `const refs = memo(refCache, node, () => collectRefs(node))`
|
|
47
|
+
*/
|
|
48
|
+
function memo(store, key, compute) {
|
|
49
|
+
if (store.has(key)) return store.get(key);
|
|
50
|
+
const value = compute();
|
|
51
|
+
store.set(key, value);
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
35
54
|
// src/constants.ts
|
|
36
55
|
/**
|
|
37
56
|
* Node kind discriminators used by every AST node (for example `node.kind === nodeKinds.text`).
|
|
38
57
|
*/
|
|
39
|
-
const nodeKinds = {
|
|
58
|
+
const nodeKinds$1 = {
|
|
40
59
|
input: "Input",
|
|
41
60
|
operation: "Operation",
|
|
42
61
|
schema: "Schema",
|
|
@@ -62,7 +81,7 @@ const nodeKinds = {
|
|
|
62
81
|
*
|
|
63
82
|
* Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
|
|
64
83
|
*/
|
|
65
|
-
const schemaTypes = {
|
|
84
|
+
const schemaTypes$1 = {
|
|
66
85
|
/**
|
|
67
86
|
* Text value.
|
|
68
87
|
*/
|
|
@@ -170,6 +189,19 @@ const schemaTypes = {
|
|
|
170
189
|
*/
|
|
171
190
|
never: "never"
|
|
172
191
|
};
|
|
192
|
+
// src/optionality.ts
|
|
193
|
+
/**
|
|
194
|
+
* Generic JSON Schema optionality: a non-required field is optional, and a
|
|
195
|
+
* non-required nullable field is nullish.
|
|
196
|
+
*/
|
|
197
|
+
function applyOptionality(schema, required) {
|
|
198
|
+
const nullable = schema.nullable ?? false;
|
|
199
|
+
return {
|
|
200
|
+
...schema,
|
|
201
|
+
optional: !required && !nullable ? true : void 0,
|
|
202
|
+
nullish: !required && nullable ? true : void 0
|
|
203
|
+
};
|
|
204
|
+
}
|
|
173
205
|
// src/guards.ts
|
|
174
206
|
/**
|
|
175
207
|
* Narrows a `SchemaNode` to the variant that matches `type`.
|
|
@@ -180,22 +212,204 @@ const schemaTypes = {
|
|
|
180
212
|
* const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | null
|
|
181
213
|
* ```
|
|
182
214
|
*/
|
|
183
|
-
function narrowSchema(node, type) {
|
|
215
|
+
function narrowSchema$1(node, type) {
|
|
184
216
|
return node?.type === type ? node : null;
|
|
185
217
|
}
|
|
218
|
+
__name(narrowSchema$1, "narrowSchema");
|
|
186
219
|
/**
|
|
187
220
|
* Narrows an `OperationNode` to an `HttpOperationNode` so `method` and `path` are present.
|
|
188
221
|
*
|
|
189
222
|
* @example
|
|
190
223
|
* ```ts
|
|
191
|
-
* if (
|
|
224
|
+
* if (ast.http.isOperation(node)) {
|
|
192
225
|
* console.log(node.method, node.path)
|
|
193
226
|
* }
|
|
194
227
|
* ```
|
|
195
228
|
*/
|
|
196
|
-
function isHttpOperationNode(node) {
|
|
229
|
+
function isHttpOperationNode$1(node) {
|
|
197
230
|
return node.protocol === "http" || node.method !== void 0 && node.path !== void 0;
|
|
198
231
|
}
|
|
232
|
+
__name(isHttpOperationNode$1, "isHttpOperationNode");
|
|
233
|
+
// src/mediaType/index.ts
|
|
234
|
+
var mediaType_exports = /* @__PURE__ */ __exportAll({
|
|
235
|
+
getBase: () => getBase,
|
|
236
|
+
isJson: () => isJson,
|
|
237
|
+
isStream: () => isStream
|
|
238
|
+
});
|
|
239
|
+
const jsonMediaTypes = /* @__PURE__ */ new Set(["application/json", "text/json"]);
|
|
240
|
+
const streamMediaTypes = /* @__PURE__ */ new Set([
|
|
241
|
+
"application/jsonl",
|
|
242
|
+
"application/x-ndjson",
|
|
243
|
+
"application/json-seq",
|
|
244
|
+
"text/event-stream"
|
|
245
|
+
]);
|
|
246
|
+
/** The media type without its parameters, in lower case: `Text/Plain; charset=utf-8` gives `text/plain`. */
|
|
247
|
+
function getBase(mediaType) {
|
|
248
|
+
return (typeof mediaType === "string" ? mediaType : mediaType.contentType).split(";")[0].trim().toLowerCase();
|
|
249
|
+
}
|
|
250
|
+
/** Whether the media type is `application/json`, `text/json`, or has a `+json` suffix. */
|
|
251
|
+
function isJson(mediaType) {
|
|
252
|
+
const baseType = getBase(mediaType);
|
|
253
|
+
return jsonMediaTypes.has(baseType) || baseType.endsWith("+json");
|
|
254
|
+
}
|
|
255
|
+
/** Whether the media type is a stream of items: SSE, JSON Lines, or a `+json-seq` sequence. */
|
|
256
|
+
function isStream(mediaType) {
|
|
257
|
+
const baseType = getBase(mediaType);
|
|
258
|
+
return streamMediaTypes.has(baseType) || baseType.startsWith("application/") && baseType.endsWith("+json-seq");
|
|
259
|
+
}
|
|
260
|
+
// src/utils/schemaProperties.ts
|
|
261
|
+
/**
|
|
262
|
+
* Finds every matching property exposed by an object, resolved reference, or intersection.
|
|
263
|
+
*
|
|
264
|
+
* References are followed through their parsed `schema`. Circular references terminate without
|
|
265
|
+
* revisiting a node. Unions are not traversed because a property on one branch does not describe
|
|
266
|
+
* every branch.
|
|
267
|
+
*
|
|
268
|
+
* @example Faker discriminator narrowing
|
|
269
|
+
* ```ts
|
|
270
|
+
* const values = resolveSchemaProperties({ node: member, propertyName: union.discriminatorPropertyName }).flatMap(({ schema }) =>
|
|
271
|
+
* getSchemaLiteralValues(schema),
|
|
272
|
+
* )
|
|
273
|
+
* const typeName = `Extract<Pet, { type: ${values.map(JSON.stringify).join(' | ')} }>`
|
|
274
|
+
* ```
|
|
275
|
+
*
|
|
276
|
+
* @example Zod discriminated unions
|
|
277
|
+
* ```ts
|
|
278
|
+
* const canDiscriminate = union.members?.every(
|
|
279
|
+
* (member) => resolveSchemaProperties({ node: member, propertyName: 'type' }).length > 0,
|
|
280
|
+
* )
|
|
281
|
+
* const expression = canDiscriminate ? `z.discriminatedUnion('type', members)` : `z.union(members)`
|
|
282
|
+
* ```
|
|
283
|
+
*
|
|
284
|
+
* @example TypeScript property lookup
|
|
285
|
+
* ```ts
|
|
286
|
+
* const properties = resolveSchemaProperties({ node: schema, propertyName: 'status' })
|
|
287
|
+
* const statusSchemas = properties.map((property) => print(property.schema))
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
function resolveSchemaProperties$1({ node, propertyName }) {
|
|
291
|
+
const properties = [];
|
|
292
|
+
walkSchema(node, "intersection", (current) => {
|
|
293
|
+
if (current.type !== "object") return;
|
|
294
|
+
const property = current.properties.find((candidate) => candidate.name === propertyName);
|
|
295
|
+
if (property) properties.push(property);
|
|
296
|
+
});
|
|
297
|
+
return properties;
|
|
298
|
+
}
|
|
299
|
+
__name(resolveSchemaProperties$1, "resolveSchemaProperties");
|
|
300
|
+
function walkSchema(node, through, visit) {
|
|
301
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
302
|
+
function walk(current) {
|
|
303
|
+
if (!current || visited.has(current)) return;
|
|
304
|
+
visited.add(current);
|
|
305
|
+
visit(current);
|
|
306
|
+
if (current.type === "ref") return walk(current.schema);
|
|
307
|
+
if (current.type === through) for (const member of current.members ?? []) walk(member);
|
|
308
|
+
}
|
|
309
|
+
walk(node);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Reads the unique literal values represented by an enum, resolved reference, or union.
|
|
313
|
+
*
|
|
314
|
+
* Named enum values take precedence over simple enum values, matching how renderers consume
|
|
315
|
+
* `EnumSchemaNode`.
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```ts
|
|
319
|
+
* const values = getSchemaLiteralValues(enumNode)
|
|
320
|
+
* // ['cat', 'dog']
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
function getSchemaLiteralValues$1(node) {
|
|
324
|
+
const values = /* @__PURE__ */ new Set();
|
|
325
|
+
walkSchema(node, "union", (current) => {
|
|
326
|
+
if (current.type !== "enum") return;
|
|
327
|
+
for (const { value } of current.namedEnumValues ?? current.enumValues?.map((value) => ({ value })) ?? []) values.add(value);
|
|
328
|
+
});
|
|
329
|
+
return [...values];
|
|
330
|
+
}
|
|
331
|
+
__name(getSchemaLiteralValues$1, "getSchemaLiteralValues");
|
|
332
|
+
function collectPropertyNames(node) {
|
|
333
|
+
const names = /* @__PURE__ */ new Set();
|
|
334
|
+
walkSchema(node, "intersection", (current) => {
|
|
335
|
+
if (current.type === "object") for (const property of current.properties) names.add(property.name);
|
|
336
|
+
});
|
|
337
|
+
return names;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Infers an implicit discriminator: a property every member exposes with a distinct single
|
|
341
|
+
* literal value, the same shape a declared OpenAPI `discriminator` already narrows on.
|
|
342
|
+
*/
|
|
343
|
+
function inferDiscriminatorPropertyName$1(members) {
|
|
344
|
+
if (members.length < 2) return void 0;
|
|
345
|
+
let candidates;
|
|
346
|
+
for (const member of members) {
|
|
347
|
+
const names = collectPropertyNames(member);
|
|
348
|
+
candidates = candidates ? new Set([...candidates].filter((name) => names.has(name))) : names;
|
|
349
|
+
}
|
|
350
|
+
for (const name of candidates ?? []) {
|
|
351
|
+
const values = members.map((member) => {
|
|
352
|
+
const literals = new Set(resolveSchemaProperties$1({
|
|
353
|
+
node: member,
|
|
354
|
+
propertyName: name
|
|
355
|
+
}).flatMap((property) => getSchemaLiteralValues$1(property.schema)));
|
|
356
|
+
return literals.size === 1 ? [...literals][0] : void 0;
|
|
357
|
+
});
|
|
358
|
+
if (values.every((value) => value !== void 0) && new Set(values).size === members.length) return name;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
__name(inferDiscriminatorPropertyName$1, "inferDiscriminatorPropertyName");
|
|
362
|
+
// src/schema/index.ts
|
|
363
|
+
var schema_exports = /* @__PURE__ */ __exportAll({
|
|
364
|
+
applyOptionality: () => applyOptionality,
|
|
365
|
+
find: () => findSchema$1,
|
|
366
|
+
findProperties: () => resolveSchemaProperties$1,
|
|
367
|
+
getEmbeddedJson: () => getEmbeddedJson,
|
|
368
|
+
getLiterals: () => getSchemaLiteralValues$1,
|
|
369
|
+
getNumberBounds: () => getNumberBounds,
|
|
370
|
+
inferDiscriminator: () => inferDiscriminatorPropertyName$1,
|
|
371
|
+
isString: () => isString,
|
|
372
|
+
narrow: () => narrowSchema$1,
|
|
373
|
+
types: () => schemaTypes$1
|
|
374
|
+
});
|
|
375
|
+
const plainStringTypes = /* @__PURE__ */ new Set([
|
|
376
|
+
"string",
|
|
377
|
+
"uuid",
|
|
378
|
+
"email",
|
|
379
|
+
"url",
|
|
380
|
+
"datetime"
|
|
381
|
+
]);
|
|
382
|
+
/** The schema of the JSON document a string holds (`contentMediaType` with `contentSchema`), else `undefined`. */
|
|
383
|
+
function getEmbeddedJson({ content }) {
|
|
384
|
+
if (!content?.schema || content.encoding || !content.mediaType) return void 0;
|
|
385
|
+
return isJson(content.mediaType) ? content.schema : void 0;
|
|
386
|
+
}
|
|
387
|
+
/** Whether a schema prints as a plain `string`: string-like types, and `date` or `time` with a `'string'` representation. */
|
|
388
|
+
function isString(node) {
|
|
389
|
+
if (plainStringTypes.has(node.type)) return true;
|
|
390
|
+
const temporal = narrowSchema$1(node, "date") ?? narrowSchema$1(node, "time");
|
|
391
|
+
return temporal ? temporal.representation !== "date" : false;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* The tightest inclusive bounds of a number schema. An exclusive bound moves to the next point of `step` (`1` for an
|
|
395
|
+
* integer), an integer bound rounds inward, and an integer bound past `Number.MAX_SAFE_INTEGER` is left out, since it
|
|
396
|
+
* prints as a rounded or invalid literal.
|
|
397
|
+
*/
|
|
398
|
+
function getNumberBounds({ min, max, exclusive, integer = false, step }) {
|
|
399
|
+
const grid = step ?? (integer ? 1 : void 0);
|
|
400
|
+
const above = (bound) => grid ? (Math.floor(bound / grid) + 1) * grid : bound;
|
|
401
|
+
const below = (bound) => grid ? (Math.ceil(bound / grid) - 1) * grid : bound;
|
|
402
|
+
const tightest = (pick, bounds) => {
|
|
403
|
+
const usable = bounds.filter((bound) => bound !== void 0 && (!integer || Number.isSafeInteger(bound)));
|
|
404
|
+
return usable.length ? pick(...usable) : void 0;
|
|
405
|
+
};
|
|
406
|
+
const lower = tightest(Math.max, [min !== void 0 && integer ? Math.ceil(min) : min, exclusive?.min === void 0 ? void 0 : above(exclusive.min)]);
|
|
407
|
+
const upper = tightest(Math.min, [max !== void 0 && integer ? Math.floor(max) : max, exclusive?.max === void 0 ? void 0 : below(exclusive.max)]);
|
|
408
|
+
return {
|
|
409
|
+
...lower !== void 0 ? { min: lower } : {},
|
|
410
|
+
...upper !== void 0 ? { max: upper } : {}
|
|
411
|
+
};
|
|
412
|
+
}
|
|
199
413
|
// src/visitor.ts
|
|
200
414
|
/**
|
|
201
415
|
* Child node fields per node kind, in traversal order (Babel's `VISITOR_KEYS`).
|
|
@@ -273,7 +487,7 @@ function isNodeRecord(value) {
|
|
|
273
487
|
* ```
|
|
274
488
|
*/
|
|
275
489
|
function getChildren(node, recurse) {
|
|
276
|
-
if (node.kind === nodeKinds.schema && !recurse) return [];
|
|
490
|
+
if (node.kind === nodeKinds$1.schema && !recurse) return [];
|
|
277
491
|
const children = [];
|
|
278
492
|
visitChildNodes(node, (child) => {
|
|
279
493
|
children.push(child);
|
|
@@ -281,12 +495,18 @@ function getChildren(node, recurse) {
|
|
|
281
495
|
});
|
|
282
496
|
return children;
|
|
283
497
|
}
|
|
498
|
+
function isNeverPrinted({ node, key }) {
|
|
499
|
+
if (node.kind !== nodeKinds$1.schema) return false;
|
|
500
|
+
if (key === "contains" && (node.type === "array" || node.type === "tuple")) return node.contains?.min === 0 && node.contains.max === void 0;
|
|
501
|
+
if (key === "content" && node.type === "string") return !getEmbeddedJson(node);
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
284
504
|
/**
|
|
285
505
|
* Calls `visit` for each direct child node and stops at the first call that returns `true`.
|
|
286
|
-
* With `checks: true`, a schema's {@link schemaCheckKeys} fields are walked too.
|
|
506
|
+
* With `checks: true`, a schema's {@link schemaCheckKeys} fields are walked too, except checks that cannot fail.
|
|
287
507
|
*/
|
|
288
508
|
function visitChildNodes(node, visit, { checks = false } = {}) {
|
|
289
|
-
const keys = checks && node.kind === nodeKinds.schema ? [...VISITOR_KEYS[node.kind] ?? [], ...schemaCheckKeys] : VISITOR_KEYS[node.kind];
|
|
509
|
+
const keys = checks && node.kind === nodeKinds$1.schema ? [...VISITOR_KEYS[node.kind] ?? [], ...schemaCheckKeys] : VISITOR_KEYS[node.kind];
|
|
290
510
|
if (!keys) return false;
|
|
291
511
|
const record = node;
|
|
292
512
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -300,6 +520,10 @@ function visitChildNodes(node, visit, { checks = false } = {}) {
|
|
|
300
520
|
return false;
|
|
301
521
|
};
|
|
302
522
|
for (const key of keys) {
|
|
523
|
+
if (checks && isNeverPrinted({
|
|
524
|
+
node,
|
|
525
|
+
key
|
|
526
|
+
})) continue;
|
|
303
527
|
const value = record[key];
|
|
304
528
|
if (Array.isArray(value)) {
|
|
305
529
|
for (const item of value) if (isNode(item) ? visitOnce(item) : isNodeRecord(item) && visitRecord(item)) return true;
|
|
@@ -323,10 +547,10 @@ function visitChildNodes(node, visit, { checks = false } = {}) {
|
|
|
323
547
|
* })
|
|
324
548
|
* ```
|
|
325
549
|
*/
|
|
326
|
-
function findSchema(node, { predicate, followRefs = false }) {
|
|
550
|
+
function findSchema$1(node, { predicate, followRefs = false }) {
|
|
327
551
|
const seen = followRefs ? /* @__PURE__ */ new WeakSet() : void 0;
|
|
328
552
|
const walk = (current) => {
|
|
329
|
-
if (current.kind === nodeKinds.schema) {
|
|
553
|
+
if (current.kind === nodeKinds$1.schema) {
|
|
330
554
|
if (predicate(current)) return current;
|
|
331
555
|
if (seen) {
|
|
332
556
|
if (seen.has(current)) return void 0;
|
|
@@ -346,6 +570,7 @@ function findSchema(node, { predicate, followRefs = false }) {
|
|
|
346
570
|
};
|
|
347
571
|
return walk(node);
|
|
348
572
|
}
|
|
573
|
+
__name(findSchema$1, "findSchema");
|
|
349
574
|
/**
|
|
350
575
|
* Runs the visitor callback that matches `node.kind` with the traversal
|
|
351
576
|
* context. The result is a replacement node, a collected value, or `undefined`
|
|
@@ -385,10 +610,11 @@ function applyVisitor(node, visitor, parent) {
|
|
|
385
610
|
* })
|
|
386
611
|
* ```
|
|
387
612
|
*/
|
|
388
|
-
function transform(node, options) {
|
|
613
|
+
function transform$1(node, options) {
|
|
389
614
|
const { depth, parent, ...visitor } = options;
|
|
390
615
|
return transformNode(node, visitor, (depth ?? "deep") === "deep", parent);
|
|
391
616
|
}
|
|
617
|
+
__name(transform$1, "transform");
|
|
392
618
|
/**
|
|
393
619
|
* Visits a single node, then immutably rebuilds its children. Returns the original
|
|
394
620
|
* reference when neither the visitor nor the child rebuild changed anything, so callers
|
|
@@ -402,7 +628,7 @@ function transformNode(node, visitor, recurse, parent) {
|
|
|
402
628
|
* (e.g. `additionalProperties: true`) intact.
|
|
403
629
|
*/
|
|
404
630
|
function transformChildren(node, visitor, recurse) {
|
|
405
|
-
const keys = node.kind === nodeKinds.schema && !recurse ? void 0 : VISITOR_KEYS[node.kind];
|
|
631
|
+
const keys = node.kind === nodeKinds$1.schema && !recurse ? void 0 : VISITOR_KEYS[node.kind];
|
|
406
632
|
if (!keys) return node;
|
|
407
633
|
const record = node;
|
|
408
634
|
let updates;
|
|
@@ -449,161 +675,439 @@ function transformChildren(node, visitor, recurse) {
|
|
|
449
675
|
};
|
|
450
676
|
}
|
|
451
677
|
/**
|
|
452
|
-
*
|
|
453
|
-
* the visitor callbacks. Use `collectSync` for the eager array form.
|
|
454
|
-
*
|
|
455
|
-
* @example Collect every operationId
|
|
456
|
-
* ```ts
|
|
457
|
-
* const ids: string[] = []
|
|
458
|
-
* for (const id of collect<string>(root, {
|
|
459
|
-
* operation(node) {
|
|
460
|
-
* return node.operationId
|
|
461
|
-
* },
|
|
462
|
-
* })) {
|
|
463
|
-
* ids.push(id)
|
|
464
|
-
* }
|
|
465
|
-
* ```
|
|
466
|
-
*/
|
|
467
|
-
function* collect(node, options) {
|
|
468
|
-
const { depth, parent, ...visitor } = options;
|
|
469
|
-
yield* collectNode(node, visitor, (depth ?? "deep") === "deep", parent);
|
|
470
|
-
}
|
|
471
|
-
function* collectNode(node, visitor, recurse, parent) {
|
|
472
|
-
const v = applyVisitor(node, visitor, parent);
|
|
473
|
-
if (v != null) yield v;
|
|
474
|
-
for (const child of getChildren(node, recurse)) yield* collectNode(child, visitor, recurse, node);
|
|
475
|
-
}
|
|
476
|
-
/**
|
|
477
|
-
* Eager depth-first collection pass. Gathers every non-null value the visitor
|
|
678
|
+
* Depth-first collection pass. Gathers every non-null value the visitor
|
|
478
679
|
* callbacks return into an array.
|
|
479
680
|
*
|
|
480
681
|
* @example Collect every operationId
|
|
481
682
|
* ```ts
|
|
482
|
-
* const ids =
|
|
683
|
+
* const ids = collect<string>(root, {
|
|
483
684
|
* operation(node) {
|
|
484
685
|
* return node.operationId
|
|
485
686
|
* },
|
|
486
687
|
* })
|
|
487
688
|
* ```
|
|
488
689
|
*/
|
|
489
|
-
function
|
|
690
|
+
function collect$1(node, options) {
|
|
490
691
|
const { depth, parent, ...visitor } = options;
|
|
491
692
|
const result = [];
|
|
492
693
|
collectInto(node, visitor, (depth ?? "deep") === "deep", parent, result);
|
|
493
694
|
return result;
|
|
494
695
|
}
|
|
696
|
+
__name(collect$1, "collect");
|
|
495
697
|
function collectInto(node, visitor, recurse, parent, result) {
|
|
496
698
|
const v = applyVisitor(node, visitor, parent);
|
|
497
699
|
if (v != null) result.push(v);
|
|
498
700
|
for (const child of getChildren(node, recurse)) collectInto(child, visitor, recurse, node, result);
|
|
499
701
|
}
|
|
500
|
-
// src/
|
|
702
|
+
// src/utils/refs.ts
|
|
501
703
|
/**
|
|
502
|
-
*
|
|
503
|
-
*
|
|
704
|
+
* Returns the last segment of a `$ref` pointer, for example `'Pet'` for `#/components/schemas/Pet`.
|
|
705
|
+
* The segment is decoded like the pointer resolver does: percent-escapes first, then `~1` and `~0`
|
|
706
|
+
* (RFC 6901), so `a~1b~0c` names the component `a/b~c`.
|
|
504
707
|
*/
|
|
505
|
-
function
|
|
506
|
-
|
|
507
|
-
if (
|
|
508
|
-
|
|
708
|
+
function refName$1(ref) {
|
|
709
|
+
const cached = refNames.get(ref);
|
|
710
|
+
if (cached !== void 0) return cached;
|
|
711
|
+
const segment = ref.split("/").at(-1) ?? ref;
|
|
712
|
+
let decoded = segment;
|
|
713
|
+
try {
|
|
714
|
+
decoded = decodeURIComponent(segment);
|
|
715
|
+
} catch {}
|
|
716
|
+
const name = decoded.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
717
|
+
if (refNames.size >= memoLimit) refNames.clear();
|
|
718
|
+
refNames.set(ref, name);
|
|
719
|
+
return name;
|
|
509
720
|
}
|
|
721
|
+
__name(refName$1, "refName");
|
|
722
|
+
const refNames = /* @__PURE__ */ new Map();
|
|
723
|
+
const memoLimit = 1e5;
|
|
510
724
|
/**
|
|
511
|
-
*
|
|
512
|
-
*
|
|
725
|
+
* Resolves the emitted name of the schema a ref node points at. Prefers `targetName` (set when
|
|
726
|
+
* the referenced schema was renamed, e.g. to break a collision), then the last segment of `ref`,
|
|
727
|
+
* then `name`, then the nested `schema.name`.
|
|
728
|
+
*
|
|
729
|
+
* Returns `null` for non-ref nodes or when no name resolves.
|
|
513
730
|
*
|
|
514
731
|
* @example
|
|
515
|
-
* `
|
|
732
|
+
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
|
|
733
|
+
*
|
|
734
|
+
* @example Collision-renamed target
|
|
735
|
+
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Order', targetName: 'OrderSchema' }) // 'OrderSchema'`
|
|
516
736
|
*/
|
|
517
|
-
function
|
|
518
|
-
|
|
737
|
+
function resolveRefName$1(node) {
|
|
738
|
+
if (!node || node.type !== "ref") return null;
|
|
739
|
+
if (node.targetName) return node.targetName;
|
|
740
|
+
if (node.ref) return refName$1(node.ref);
|
|
741
|
+
return node.name ?? node.schema?.name ?? null;
|
|
519
742
|
}
|
|
743
|
+
__name(resolveRefName$1, "resolveRefName");
|
|
520
744
|
/**
|
|
521
|
-
*
|
|
522
|
-
* Adds no runtime behavior.
|
|
745
|
+
* Follows a resolved ref chain to its target schema. Returns an unresolved or cyclic ref as is.
|
|
523
746
|
*
|
|
524
747
|
* @example
|
|
525
748
|
* ```ts
|
|
526
|
-
* const
|
|
527
|
-
* name: 'untagged',
|
|
528
|
-
* operation(node) {
|
|
529
|
-
* return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
|
|
530
|
-
* },
|
|
531
|
-
* })
|
|
749
|
+
* const target = resolveRef(refSchema)
|
|
532
750
|
* ```
|
|
533
751
|
*/
|
|
534
|
-
function
|
|
535
|
-
return
|
|
752
|
+
function resolveRef$1(node) {
|
|
753
|
+
if (node.type !== "ref" || !node.schema) return node;
|
|
754
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
755
|
+
let current = node;
|
|
756
|
+
while (current.type === "ref" && current.schema) {
|
|
757
|
+
if (seen.has(current)) return current;
|
|
758
|
+
seen.add(current);
|
|
759
|
+
current = current.schema;
|
|
760
|
+
}
|
|
761
|
+
return current;
|
|
536
762
|
}
|
|
763
|
+
__name(resolveRef$1, "resolveRef");
|
|
764
|
+
/** Fields of a ref node that describe the ref itself, so they never override the resolved schema. */
|
|
765
|
+
const REF_OWN_KEYS = /* @__PURE__ */ new Set([
|
|
766
|
+
"kind",
|
|
767
|
+
"type",
|
|
768
|
+
"name",
|
|
769
|
+
"ref",
|
|
770
|
+
"schema"
|
|
771
|
+
]);
|
|
537
772
|
/**
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
773
|
+
* Merges a ref node with its resolved schema, giving the fields set at the usage site precedence.
|
|
774
|
+
*
|
|
775
|
+
* Every field on the ref except `kind`, `type`, `name`, `ref`, and `schema` overrides the same field
|
|
776
|
+
* of the resolved `schema` (for example `description`, `nullable`, `readOnly`, `deprecated`). Fields
|
|
777
|
+
* left `undefined` on the ref do not shadow the resolved schema. A ref without a resolved `schema`
|
|
778
|
+
* is returned as is.
|
|
779
|
+
*
|
|
780
|
+
* @example
|
|
781
|
+
* ```ts
|
|
782
|
+
* const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A pet', schema: petSchema })
|
|
783
|
+
* mergeRefWithSchema(ref) // petSchema's fields with description 'A pet'
|
|
784
|
+
* ```
|
|
541
785
|
*/
|
|
542
|
-
function
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
if (
|
|
548
|
-
const next = callback(current, context);
|
|
549
|
-
if (next != null) current = next;
|
|
786
|
+
function mergeRefWithSchema$1(node) {
|
|
787
|
+
if (!node.schema) return node;
|
|
788
|
+
const merged = { ...node.schema };
|
|
789
|
+
for (const key of Object.keys(node)) {
|
|
790
|
+
const value = node[key];
|
|
791
|
+
if (value !== void 0 && !REF_OWN_KEYS.has(key)) merged[key] = value;
|
|
550
792
|
}
|
|
551
|
-
return
|
|
793
|
+
return merged;
|
|
552
794
|
}
|
|
795
|
+
__name(mergeRefWithSchema$1, "mergeRefWithSchema");
|
|
553
796
|
/**
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
macros: ordered,
|
|
564
|
-
key,
|
|
565
|
-
node,
|
|
566
|
-
context
|
|
567
|
-
});
|
|
568
|
-
visitor[key] = callback;
|
|
569
|
-
}
|
|
570
|
-
return visitor;
|
|
797
|
+
* Returns `true` when a schema is a bare ref without modifiers, metadata, or omit keys.
|
|
798
|
+
*
|
|
799
|
+
* Modifiers inherited from the resolved schema are included in the check because a ref emits the
|
|
800
|
+
* referenced schema variable with those modifiers already applied.
|
|
801
|
+
*/
|
|
802
|
+
function isBareRef$1(node, keysToOmit) {
|
|
803
|
+
if (!node || node.type !== "ref") return false;
|
|
804
|
+
const meta = mergeRefWithSchema$1(node);
|
|
805
|
+
return !meta.nullable && !meta.optional && !meta.nullish && meta.default === void 0 && !meta.description && !meta.examples?.length && !keysToOmit?.length;
|
|
571
806
|
}
|
|
807
|
+
__name(isBareRef$1, "isBareRef");
|
|
808
|
+
// src/utils/schemaGraph.ts
|
|
809
|
+
const refEntries = /* @__PURE__ */ new WeakMap();
|
|
810
|
+
const checkRefEntries = /* @__PURE__ */ new WeakMap();
|
|
811
|
+
const schemaRefs = /* @__PURE__ */ new WeakMap();
|
|
812
|
+
const importedRefNames = /* @__PURE__ */ new WeakMap();
|
|
813
|
+
const importedCheckRefNames = /* @__PURE__ */ new WeakMap();
|
|
572
814
|
/**
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
815
|
+
* Walks a node's subtree once and lists every ref it holds, in traversal order, as the resolved
|
|
816
|
+
* name plus whether the ref carries a `$ref` pointer. Memoized per node and per `checks` mode, so
|
|
817
|
+
* each helper below scans a schema once.
|
|
818
|
+
*/
|
|
819
|
+
function collectRefEntries(node, { checks }) {
|
|
820
|
+
return memo(checks ? checkRefEntries : refEntries, node, () => {
|
|
821
|
+
const entries = [];
|
|
822
|
+
const walk = (current) => {
|
|
823
|
+
if (current.kind === nodeKinds$1.schema && current.type === "ref") {
|
|
824
|
+
const name = resolveRefName$1(current);
|
|
825
|
+
if (name) entries.push({
|
|
826
|
+
name,
|
|
827
|
+
hasPointer: Boolean(current.ref)
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
visitChildNodes(current, walk, { checks });
|
|
831
|
+
return false;
|
|
832
|
+
};
|
|
833
|
+
walk(node);
|
|
834
|
+
return entries;
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Collects the names of every schema a node's subtree references, resolved with `ast.ref.getName`.
|
|
839
|
+
* Each ref contributes its name only, so the schema it points to is never traversed. Memoized by
|
|
840
|
+
* node identity, which lets `findCircularSchemas` and `ast.graph.containsCircular` share one scan per schema.
|
|
576
841
|
*
|
|
577
842
|
* @example
|
|
578
843
|
* ```ts
|
|
579
|
-
*
|
|
844
|
+
* collectSchemaRefs(petSchema)
|
|
845
|
+
* // Set { 'Category', 'Tag' }
|
|
580
846
|
* ```
|
|
847
|
+
*/
|
|
848
|
+
function collectSchemaRefs$1(node) {
|
|
849
|
+
return memo(schemaRefs, node, () => new Set(collectRefEntries(node, { checks: true }).map((entry) => entry.name)));
|
|
850
|
+
}
|
|
851
|
+
__name(collectSchemaRefs$1, "collectSchemaRefs");
|
|
852
|
+
/**
|
|
853
|
+
* Collects the de-duplicated target names of every pointer-carrying ref in a node's subtree, in
|
|
854
|
+
* first-occurrence order. Memoized by node identity, so `resolver.imports` reads the same result
|
|
855
|
+
* across the ts, zod, and faker plugins instead of re-scanning the same schema per plugin.
|
|
581
856
|
*
|
|
582
|
-
*
|
|
857
|
+
* Only refs that carry a `$ref` pointer count, so a synthesized ref pointing at a sibling in the
|
|
858
|
+
* same file (a union member created by name) is left out. That leaves exactly the set
|
|
859
|
+
* `resolver.imports` emits. Refs inside `conditionals`, `contains` and `content` count only with
|
|
860
|
+
* `checks: true`, for a plugin that prints those checks.
|
|
861
|
+
*
|
|
862
|
+
* @example
|
|
583
863
|
* ```ts
|
|
584
|
-
*
|
|
864
|
+
* collectImportedRefNames(petSchema)
|
|
865
|
+
* // ['Category', 'Tag']
|
|
585
866
|
* ```
|
|
586
867
|
*/
|
|
587
|
-
function
|
|
588
|
-
|
|
589
|
-
return transform(root, {
|
|
590
|
-
...composeMacros(macros),
|
|
591
|
-
...options
|
|
592
|
-
});
|
|
868
|
+
function collectImportedRefNames$1(node, { checks = false } = {}) {
|
|
869
|
+
return memo(checks ? importedCheckRefNames : importedRefNames, node, () => [...new Set(collectRefEntries(node, { checks }).flatMap((entry) => entry.hasPointer ? [entry.name] : []))]);
|
|
593
870
|
}
|
|
594
|
-
|
|
871
|
+
__name(collectImportedRefNames$1, "collectImportedRefNames");
|
|
595
872
|
/**
|
|
596
|
-
*
|
|
597
|
-
*
|
|
873
|
+
* Collects the names of all top-level schemas transitively used by a set of operations.
|
|
874
|
+
*
|
|
875
|
+
* An operation uses a schema when its parameters, request body, or responses reference it, directly
|
|
876
|
+
* or through other named schemas. Once a name is added to the result it is not revisited, so
|
|
877
|
+
* reference cycles terminate.
|
|
878
|
+
*
|
|
879
|
+
* Pair it with `include` filters so schemas reachable only from excluded operations stay ungenerated.
|
|
880
|
+
*
|
|
881
|
+
* @example Only generate schemas referenced by included operations
|
|
882
|
+
* ```ts
|
|
883
|
+
* const includedOps = operations.filter((op) => resolver.default.options(op, { options, include }) !== null)
|
|
884
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
885
|
+
*
|
|
886
|
+
* for (const schema of schemas) {
|
|
887
|
+
* if (schema.name && !allowed.has(schema.name)) continue
|
|
888
|
+
* // generate schema
|
|
889
|
+
* }
|
|
890
|
+
* ```
|
|
598
891
|
*/
|
|
599
|
-
function
|
|
600
|
-
const
|
|
892
|
+
function collectUsedSchemaNames$1(operations, schemas) {
|
|
893
|
+
const schemaMap = /* @__PURE__ */ new Map();
|
|
894
|
+
for (const schema of schemas) if (schema.name) schemaMap.set(schema.name, schema);
|
|
895
|
+
const result = /* @__PURE__ */ new Set();
|
|
896
|
+
function visitSchema(schema) {
|
|
897
|
+
for (const name of collectSchemaRefs$1(schema)) if (!result.has(name)) {
|
|
898
|
+
result.add(name);
|
|
899
|
+
const namedSchema = schemaMap.get(name);
|
|
900
|
+
if (namedSchema) visitSchema(namedSchema);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
for (const op of operations) for (const schema of collect$1(op, {
|
|
904
|
+
depth: "shallow",
|
|
905
|
+
schema: (node) => node
|
|
906
|
+
})) visitSchema(schema);
|
|
907
|
+
return result;
|
|
908
|
+
}
|
|
909
|
+
__name(collectUsedSchemaNames$1, "collectUsedSchemaNames");
|
|
910
|
+
/**
|
|
911
|
+
* Finds every schema that takes part in a circular dependency chain, including direct self-loops.
|
|
912
|
+
*
|
|
913
|
+
* Wrap the returned schema positions in a deferred construct (a lazy getter or `z.lazy(() => …)`) so
|
|
914
|
+
* the generated code does not recurse forever. Refs are followed by name only, so the walk stays
|
|
915
|
+
* linear in the size of the schema graph.
|
|
916
|
+
*
|
|
917
|
+
* @note Call this once on the full graph, then check individual schemas with `ast.graph.containsCircular()`.
|
|
918
|
+
*/
|
|
919
|
+
function findCircularSchemas$1(schemas) {
|
|
920
|
+
const graph = /* @__PURE__ */ new Map();
|
|
921
|
+
for (const schema of schemas) if (schema.name) graph.set(schema.name, collectSchemaRefs$1(schema));
|
|
922
|
+
const circular = /* @__PURE__ */ new Set();
|
|
923
|
+
for (const start of graph.keys()) {
|
|
924
|
+
const visited = /* @__PURE__ */ new Set();
|
|
925
|
+
const stack = [...graph.get(start) ?? []];
|
|
926
|
+
while (stack.length > 0) {
|
|
927
|
+
const node = stack.pop();
|
|
928
|
+
if (node === start) {
|
|
929
|
+
circular.add(start);
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
if (visited.has(node)) continue;
|
|
933
|
+
visited.add(node);
|
|
934
|
+
const next = graph.get(node);
|
|
935
|
+
if (next) for (const r of next) stack.push(r);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
return circular;
|
|
939
|
+
}
|
|
940
|
+
__name(findCircularSchemas$1, "findCircularSchemas");
|
|
941
|
+
// src/graph/index.ts
|
|
942
|
+
var graph_exports = /* @__PURE__ */ __exportAll({
|
|
943
|
+
containsCircular: () => containsCircular,
|
|
944
|
+
getCircularNames: () => findCircularSchemas$1,
|
|
945
|
+
getImportedNames: () => collectImportedRefNames$1,
|
|
946
|
+
getRefNames: () => collectSchemaRefs$1,
|
|
947
|
+
getUsedNames: () => collectUsedSchemaNames$1
|
|
948
|
+
});
|
|
949
|
+
/** Whether a schema, or anything inside it, refers to one of `circularSchemas`, other than `excludeName`. */
|
|
950
|
+
function containsCircular(node, { circularSchemas, excludeName }) {
|
|
951
|
+
if (!node || circularSchemas.size === 0) return false;
|
|
952
|
+
for (const name of collectSchemaRefs$1(node)) if (name !== excludeName && circularSchemas.has(name)) return true;
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
// src/http/requestBody.ts
|
|
956
|
+
var requestBody_exports = /* @__PURE__ */ __exportAll({ getSchema: () => getSchema });
|
|
957
|
+
/** The schema of the first request body entry, else `undefined` when the operation takes no body. */
|
|
958
|
+
function getSchema(node) {
|
|
959
|
+
return node.requestBody?.content?.[0]?.schema;
|
|
960
|
+
}
|
|
961
|
+
// src/http/status.ts
|
|
962
|
+
var status_exports = /* @__PURE__ */ __exportAll({
|
|
963
|
+
getClass: () => statusClass,
|
|
964
|
+
isError: () => isError,
|
|
965
|
+
isSuccess: () => isSuccess,
|
|
966
|
+
toCode: () => toCode
|
|
967
|
+
});
|
|
968
|
+
const classByRange = /* @__PURE__ */ new Map([
|
|
969
|
+
["1xx", 1],
|
|
970
|
+
["2xx", 2],
|
|
971
|
+
["3xx", 3],
|
|
972
|
+
["4xx", 4],
|
|
973
|
+
["5xx", 5]
|
|
974
|
+
]);
|
|
975
|
+
/** The class digit of a status code or range: `2` for `201` and `2xx`, `null` for `default`. */
|
|
976
|
+
function statusClass(input) {
|
|
977
|
+
const statusCode = typeof input === "object" ? input.statusCode : input;
|
|
978
|
+
const rangeClass = classByRange.get(String(statusCode));
|
|
979
|
+
if (rangeClass) return rangeClass;
|
|
980
|
+
const code = Number(statusCode);
|
|
981
|
+
return Number.isNaN(code) ? null : Math.floor(code / 100);
|
|
982
|
+
}
|
|
983
|
+
function isSuccess(statusCode) {
|
|
984
|
+
return statusClass(statusCode) === 2;
|
|
985
|
+
}
|
|
986
|
+
function isError(statusCode) {
|
|
987
|
+
const code = statusClass(statusCode);
|
|
988
|
+
return code !== null && code >= 4;
|
|
989
|
+
}
|
|
990
|
+
/** One concrete code for a status or range: `200` for `2xx` and `default`, the code itself otherwise. */
|
|
991
|
+
function toCode(input) {
|
|
992
|
+
const statusCode = typeof input === "object" ? input.statusCode : input;
|
|
993
|
+
const code = Number(statusCode);
|
|
994
|
+
return Number.isNaN(code) ? (statusClass(statusCode) ?? 2) * 100 : code;
|
|
995
|
+
}
|
|
996
|
+
// src/http/responses.ts
|
|
997
|
+
var responses_exports = /* @__PURE__ */ __exportAll({
|
|
998
|
+
filterError: () => filterError,
|
|
999
|
+
filterSuccess: () => filterSuccess,
|
|
1000
|
+
findPrimary: () => findPrimary,
|
|
1001
|
+
getImportedNames: () => getImportedNames
|
|
1002
|
+
});
|
|
1003
|
+
/** The `4xx` and `5xx` responses, ranges included. */
|
|
1004
|
+
function filterError(node) {
|
|
1005
|
+
return node.responses.filter((response) => isError(response.statusCode));
|
|
1006
|
+
}
|
|
1007
|
+
/** The ref names the response bodies import, in order, with repeats. */
|
|
1008
|
+
function getImportedNames(responses) {
|
|
1009
|
+
return responses.flatMap((response) => (response.content ?? []).flatMap((entry) => entry.schema ? collectImportedRefNames$1(entry.schema) : []));
|
|
1010
|
+
}
|
|
1011
|
+
function filterSuccess(node) {
|
|
1012
|
+
return node.responses.filter((response) => isSuccess(response.statusCode));
|
|
1013
|
+
}
|
|
1014
|
+
/** The success response a client returns: one with a body first, then an exact code over a `2xx` range. */
|
|
1015
|
+
function findPrimary(node) {
|
|
1016
|
+
const responses = filterSuccess(node);
|
|
1017
|
+
const withBody = responses.filter((response) => response.content?.some((entry) => entry.contentType));
|
|
1018
|
+
const candidates = withBody.length ? withBody : responses;
|
|
1019
|
+
return candidates.find((response) => !Number.isNaN(Number(response.statusCode))) ?? candidates[0] ?? null;
|
|
1020
|
+
}
|
|
1021
|
+
// src/http/index.ts
|
|
1022
|
+
var http_exports = /* @__PURE__ */ __exportAll({
|
|
1023
|
+
getBaseURL: () => getBaseURL,
|
|
1024
|
+
groupParameters: () => groupParameters,
|
|
1025
|
+
isOperation: () => isHttpOperationNode$1,
|
|
1026
|
+
requestBody: () => requestBody_exports,
|
|
1027
|
+
responses: () => responses_exports,
|
|
1028
|
+
status: () => status_exports
|
|
1029
|
+
});
|
|
1030
|
+
/** The server's URL when it is absolute and has no template variables, else `undefined`. */
|
|
1031
|
+
function getBaseURL(server) {
|
|
1032
|
+
if (!server || server.variables || server.url.includes("{") || !server.url.includes("://")) return void 0;
|
|
1033
|
+
return URL.canParse(server.url) ? server.url : void 0;
|
|
1034
|
+
}
|
|
1035
|
+
const parametersByNode = /* @__PURE__ */ new WeakMap();
|
|
1036
|
+
/** The operation's parameters by location, with a `querystring` parameter in `query`. A repeated name keeps its first parameter. */
|
|
1037
|
+
function groupParameters(node) {
|
|
1038
|
+
const cached = parametersByNode.get(node);
|
|
1039
|
+
if (cached) return cached;
|
|
1040
|
+
const group = (...locations) => {
|
|
1041
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1042
|
+
return locations.flatMap((location) => node.parameters.filter((param) => {
|
|
1043
|
+
if (param.in !== location || seen.has(param.name)) return false;
|
|
1044
|
+
seen.add(param.name);
|
|
1045
|
+
return true;
|
|
1046
|
+
}));
|
|
1047
|
+
};
|
|
1048
|
+
const groups = {
|
|
1049
|
+
path: group("path"),
|
|
1050
|
+
query: group("query", "querystring"),
|
|
1051
|
+
header: group("header"),
|
|
1052
|
+
cookie: group("cookie")
|
|
1053
|
+
};
|
|
1054
|
+
parametersByNode.set(node, groups);
|
|
1055
|
+
return groups;
|
|
1056
|
+
}
|
|
1057
|
+
// src/nodes/schema.ts
|
|
1058
|
+
/**
|
|
1059
|
+
* Maps schema `type` to its underlying `primitive`.
|
|
1060
|
+
* Primitive types map to themselves and special string formats map to `'string'`.
|
|
1061
|
+
* Any type not listed here (such as `ref`, `enum`, `union`, `intersection`, `not`, `tuple`, `ipv4`, `ipv6`, `blob`) has no `primitive`.
|
|
1062
|
+
*/
|
|
1063
|
+
const TYPE_TO_PRIMITIVE = {
|
|
1064
|
+
string: "string",
|
|
1065
|
+
number: "number",
|
|
1066
|
+
integer: "integer",
|
|
1067
|
+
bigint: "bigint",
|
|
1068
|
+
boolean: "boolean",
|
|
1069
|
+
null: "null",
|
|
1070
|
+
any: "any",
|
|
1071
|
+
unknown: "unknown",
|
|
1072
|
+
void: "void",
|
|
1073
|
+
never: "never",
|
|
1074
|
+
object: "object",
|
|
1075
|
+
array: "array",
|
|
1076
|
+
date: "date",
|
|
1077
|
+
uuid: "string",
|
|
1078
|
+
email: "string",
|
|
1079
|
+
url: "string",
|
|
1080
|
+
datetime: "string",
|
|
1081
|
+
time: "string"
|
|
1082
|
+
};
|
|
1083
|
+
function createSchema(props) {
|
|
1084
|
+
if (props.type === "object") return {
|
|
1085
|
+
properties: [],
|
|
1086
|
+
primitive: "object",
|
|
1087
|
+
...props,
|
|
1088
|
+
kind: nodeKinds$1.schema
|
|
1089
|
+
};
|
|
601
1090
|
return {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
1091
|
+
primitive: TYPE_TO_PRIMITIVE[props.type],
|
|
1092
|
+
...props,
|
|
1093
|
+
kind: nodeKinds$1.schema
|
|
605
1094
|
};
|
|
606
1095
|
}
|
|
1096
|
+
// src/ref/index.ts
|
|
1097
|
+
var ref_exports = /* @__PURE__ */ __exportAll({
|
|
1098
|
+
getName: () => getName,
|
|
1099
|
+
getSchema: () => resolveRef$1,
|
|
1100
|
+
isAlias: () => isBareRef$1,
|
|
1101
|
+
mergeSchema: () => mergeSchema
|
|
1102
|
+
});
|
|
1103
|
+
/** A resolved ref merged with its target schema, so usage-site fields such as `description` win. Other nodes come back unchanged. */
|
|
1104
|
+
function mergeSchema(node) {
|
|
1105
|
+
const ref = narrowSchema$1(node, "ref");
|
|
1106
|
+
return ref?.schema ? createSchema(mergeRefWithSchema$1(ref)) : node;
|
|
1107
|
+
}
|
|
1108
|
+
function getName(input) {
|
|
1109
|
+
return typeof input === "string" ? refName$1(input) : resolveRefName$1(input);
|
|
1110
|
+
}
|
|
607
1111
|
// src/createPrinter.ts
|
|
608
1112
|
/**
|
|
609
1113
|
* Creates a schema printer: a function that takes a `SchemaNode` and emits
|
|
@@ -627,9 +1131,9 @@ function optionality(schema, required) {
|
|
|
627
1131
|
*
|
|
628
1132
|
* @example Tiny Zod printer
|
|
629
1133
|
* ```ts
|
|
630
|
-
* import {
|
|
1134
|
+
* import { ast, createPrinter } from '@kubb/kit'
|
|
631
1135
|
*
|
|
632
|
-
* type PrinterZod = PrinterFactoryOptions<'zod', { strict?: boolean }, string>
|
|
1136
|
+
* type PrinterZod = ast.PrinterFactoryOptions<'zod', { strict?: boolean }, string>
|
|
633
1137
|
*
|
|
634
1138
|
* export const zodPrinter = createPrinter<PrinterZod>((options) => ({
|
|
635
1139
|
* name: 'zod',
|
|
@@ -646,7 +1150,7 @@ function optionality(schema, required) {
|
|
|
646
1150
|
* }))
|
|
647
1151
|
* ```
|
|
648
1152
|
*/
|
|
649
|
-
function createPrinter(build) {
|
|
1153
|
+
function createPrinter$1(build) {
|
|
650
1154
|
return (options) => {
|
|
651
1155
|
const { name, options: resolvedOptions, nodes, overrides, print: printOverride } = build(options ?? {});
|
|
652
1156
|
const merged = overrides ? {
|
|
@@ -676,60 +1180,168 @@ function createPrinter(build) {
|
|
|
676
1180
|
};
|
|
677
1181
|
};
|
|
678
1182
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
Text: ["value"],
|
|
682
|
-
Jsx: ["value"],
|
|
683
|
-
Function: [
|
|
684
|
-
"params",
|
|
685
|
-
"generics",
|
|
686
|
-
"returnType"
|
|
687
|
-
],
|
|
688
|
-
ArrowFunction: [
|
|
689
|
-
"params",
|
|
690
|
-
"generics",
|
|
691
|
-
"returnType"
|
|
692
|
-
],
|
|
693
|
-
Const: ["type"]
|
|
694
|
-
};
|
|
1183
|
+
__name(createPrinter$1, "createPrinter");
|
|
1184
|
+
// src/defineMacro.ts
|
|
695
1185
|
/**
|
|
696
|
-
*
|
|
697
|
-
*
|
|
698
|
-
* Collects the text fields and nested node content, to build the source string for import filtering.
|
|
1186
|
+
* Sort weight for an `enforce` hint. `pre` sorts before unmarked items and `post` after, so a plain
|
|
1187
|
+
* list keeps its authored order.
|
|
699
1188
|
*/
|
|
700
|
-
function
|
|
701
|
-
if (
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
if (typeof node === "string") {
|
|
705
|
-
if (node) collected.push(node);
|
|
706
|
-
continue;
|
|
707
|
-
}
|
|
708
|
-
if (node.kind === nodeKinds.break) continue;
|
|
709
|
-
const parts = [];
|
|
710
|
-
const record = node;
|
|
711
|
-
for (const field of CODE_NODE_TEXT_FIELDS[node.kind] ?? []) {
|
|
712
|
-
const value = record[field];
|
|
713
|
-
if (Array.isArray(value)) parts.push(value.join(", "));
|
|
714
|
-
if (typeof value === "string" && value) parts.push(value);
|
|
715
|
-
}
|
|
716
|
-
const nested = "nodes" in node ? extractStringsFromNodes(node.nodes) : "";
|
|
717
|
-
if (nested) parts.push(nested);
|
|
718
|
-
if (parts.length) collected.push(parts.join("\n"));
|
|
719
|
-
}
|
|
720
|
-
return collected.join("\n");
|
|
1189
|
+
function enforceWeight(enforce) {
|
|
1190
|
+
if (enforce === "pre") return 0;
|
|
1191
|
+
if (enforce === "post") return 2;
|
|
1192
|
+
return 1;
|
|
721
1193
|
}
|
|
722
|
-
// src/utils/combineFileMembers.ts
|
|
723
1194
|
/**
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
*
|
|
1195
|
+
* Compares two `enforce` hints for `Array.prototype.sort`: `pre` first, unmarked next, `post`
|
|
1196
|
+
* last. Equal hints compare as `0`, so a stable sort keeps authored order within a bucket.
|
|
1197
|
+
*
|
|
1198
|
+
* @example
|
|
1199
|
+
* `plugins.sort((a, b) => compareMacroOrder(a.enforce, b.enforce))`
|
|
728
1200
|
*/
|
|
729
|
-
|
|
1201
|
+
function compareMacroOrder(a, b) {
|
|
1202
|
+
return enforceWeight(a) - enforceWeight(b);
|
|
1203
|
+
}
|
|
730
1204
|
/**
|
|
731
|
-
*
|
|
732
|
-
|
|
1205
|
+
* Types a macro for inference and a single construction site, mirroring `defineExtension`.
|
|
1206
|
+
* Adds no runtime behavior.
|
|
1207
|
+
*
|
|
1208
|
+
* @example
|
|
1209
|
+
* ```ts
|
|
1210
|
+
* const macroUntagged = defineMacro({
|
|
1211
|
+
* name: 'untagged',
|
|
1212
|
+
* operation(node) {
|
|
1213
|
+
* return node.tags?.length ? undefined : { ...node, tags: ['untagged'] }
|
|
1214
|
+
* },
|
|
1215
|
+
* })
|
|
1216
|
+
* ```
|
|
1217
|
+
*/
|
|
1218
|
+
function defineMacro$1(macro) {
|
|
1219
|
+
return macro;
|
|
1220
|
+
}
|
|
1221
|
+
__name(defineMacro$1, "defineMacro");
|
|
1222
|
+
/**
|
|
1223
|
+
* Runs every macro's callback for one node kind in order, chaining the result so each macro sees
|
|
1224
|
+
* the previous macro's output. Returns `undefined` when nothing changed, so `transform` keeps the
|
|
1225
|
+
* original reference (structural sharing).
|
|
1226
|
+
*/
|
|
1227
|
+
function chain({ macros, key, node, context }) {
|
|
1228
|
+
let current = node;
|
|
1229
|
+
for (const macro of macros) {
|
|
1230
|
+
const callback = macro[key];
|
|
1231
|
+
if (!callback) continue;
|
|
1232
|
+
if (macro.match && !macro.match(current)) continue;
|
|
1233
|
+
const next = callback(current, context);
|
|
1234
|
+
if (next != null) current = next;
|
|
1235
|
+
}
|
|
1236
|
+
return current === node ? void 0 : current;
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Folds an ordered list of macros into a single {@link Visitor} for `transform`. Macros are
|
|
1240
|
+
* stable-sorted by `enforce`, then applied sequentially per node so later macros see earlier output.
|
|
1241
|
+
*/
|
|
1242
|
+
function composeMacros(macros) {
|
|
1243
|
+
const ordered = [...macros].sort((a, b) => compareMacroOrder(a.enforce, b.enforce));
|
|
1244
|
+
const visitor = {};
|
|
1245
|
+
for (const key of visitorKeys) {
|
|
1246
|
+
if (!ordered.some((macro) => typeof macro[key] === "function")) continue;
|
|
1247
|
+
const callback = (node, context) => chain({
|
|
1248
|
+
macros: ordered,
|
|
1249
|
+
key,
|
|
1250
|
+
node,
|
|
1251
|
+
context
|
|
1252
|
+
});
|
|
1253
|
+
visitor[key] = callback;
|
|
1254
|
+
}
|
|
1255
|
+
return visitor;
|
|
1256
|
+
}
|
|
1257
|
+
/**
|
|
1258
|
+
* Runs a list of macros over a node tree and returns the rewritten tree. Keeps `transform`'s
|
|
1259
|
+
* structural sharing, so an empty or no-op macro list returns the same reference. Pass
|
|
1260
|
+
* `depth: 'shallow'` to rewrite the root node only.
|
|
1261
|
+
*
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```ts
|
|
1264
|
+
* const next = applyMacros(root, [macroIntegerToString])
|
|
1265
|
+
* ```
|
|
1266
|
+
*
|
|
1267
|
+
* @example Apply to the root node only
|
|
1268
|
+
* ```ts
|
|
1269
|
+
* const named = applyMacros(node, [macroEnumName({ parentName, propName, enumSuffix })], { depth: 'shallow' })
|
|
1270
|
+
* ```
|
|
1271
|
+
*/
|
|
1272
|
+
function applyMacros$1(root, macros, options) {
|
|
1273
|
+
if (macros.length === 0) return root;
|
|
1274
|
+
return transform$1(root, {
|
|
1275
|
+
...composeMacros(macros),
|
|
1276
|
+
...options
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
__name(applyMacros$1, "applyMacros");
|
|
1280
|
+
// src/macro/index.ts
|
|
1281
|
+
var macro_exports = /* @__PURE__ */ __exportAll({
|
|
1282
|
+
apply: () => applyMacros$1,
|
|
1283
|
+
compareOrder: () => compareMacroOrder
|
|
1284
|
+
});
|
|
1285
|
+
// src/utils/nodeText.ts
|
|
1286
|
+
const CODE_NODE_TEXT_FIELDS = {
|
|
1287
|
+
Text: ["value"],
|
|
1288
|
+
Jsx: ["value"],
|
|
1289
|
+
Function: [
|
|
1290
|
+
"params",
|
|
1291
|
+
"generics",
|
|
1292
|
+
"returnType"
|
|
1293
|
+
],
|
|
1294
|
+
ArrowFunction: [
|
|
1295
|
+
"params",
|
|
1296
|
+
"generics",
|
|
1297
|
+
"returnType"
|
|
1298
|
+
],
|
|
1299
|
+
Const: ["type"]
|
|
1300
|
+
};
|
|
1301
|
+
/**
|
|
1302
|
+
* Extracts all string content from a `CodeNode` tree recursively.
|
|
1303
|
+
* Collects the text fields and nested node content, to build the source string for import filtering.
|
|
1304
|
+
*/
|
|
1305
|
+
function getNodeText(nodes) {
|
|
1306
|
+
if (!nodes?.length) return "";
|
|
1307
|
+
const collected = [];
|
|
1308
|
+
for (const node of nodes) {
|
|
1309
|
+
if (typeof node === "string") {
|
|
1310
|
+
if (node) collected.push(node);
|
|
1311
|
+
continue;
|
|
1312
|
+
}
|
|
1313
|
+
if (node.kind === nodeKinds$1.break) continue;
|
|
1314
|
+
const parts = [];
|
|
1315
|
+
const record = node;
|
|
1316
|
+
for (const field of CODE_NODE_TEXT_FIELDS[node.kind] ?? []) {
|
|
1317
|
+
const value = record[field];
|
|
1318
|
+
if (Array.isArray(value)) parts.push(value.join(", "));
|
|
1319
|
+
if (typeof value === "string" && value) parts.push(value);
|
|
1320
|
+
}
|
|
1321
|
+
const nested = "nodes" in node ? getNodeText(node.nodes) : "";
|
|
1322
|
+
if (nested) parts.push(nested);
|
|
1323
|
+
if (parts.length) collected.push(parts.join("\n"));
|
|
1324
|
+
}
|
|
1325
|
+
return collected.join("\n");
|
|
1326
|
+
}
|
|
1327
|
+
// src/node/index.ts
|
|
1328
|
+
var node_exports = /* @__PURE__ */ __exportAll({
|
|
1329
|
+
collect: () => collect$1,
|
|
1330
|
+
getText: () => getNodeText,
|
|
1331
|
+
kinds: () => nodeKinds$1,
|
|
1332
|
+
transform: () => transform$1
|
|
1333
|
+
});
|
|
1334
|
+
// src/utils/combineFileMembers.ts
|
|
1335
|
+
/**
|
|
1336
|
+
* File-member merging. `combineImports` and `combineExports` deduplicate and sort the import and
|
|
1337
|
+
* export entries of one file, while `combineSources` deduplicates source entries in original order.
|
|
1338
|
+
* `combineImports` also drops imports nothing references. This works on a file's members, not on
|
|
1339
|
+
* schema content.
|
|
1340
|
+
*/
|
|
1341
|
+
const IDENTIFIER_RUN = /[\w$]+/g;
|
|
1342
|
+
/**
|
|
1343
|
+
* How many imports a file needs before indexing the source beats scanning it once per name.
|
|
1344
|
+
*/
|
|
733
1345
|
const INDEX_ABOVE_IMPORTS = 128;
|
|
734
1346
|
/**
|
|
735
1347
|
* Returns the local binding an import name item introduces: the alias when there is one, else the
|
|
@@ -898,7 +1510,7 @@ function nodeFactory(kind) {
|
|
|
898
1510
|
* // import { useState } from 'react'
|
|
899
1511
|
* ```
|
|
900
1512
|
*/
|
|
901
|
-
const createImport = nodeFactory(nodeKinds.import);
|
|
1513
|
+
const createImport = nodeFactory(nodeKinds$1.import);
|
|
902
1514
|
/**
|
|
903
1515
|
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
|
|
904
1516
|
*
|
|
@@ -908,7 +1520,7 @@ const createImport = nodeFactory(nodeKinds.import);
|
|
|
908
1520
|
* // export { Pet } from './Pet'
|
|
909
1521
|
* ```
|
|
910
1522
|
*/
|
|
911
|
-
const createExport = nodeFactory(nodeKinds.export);
|
|
1523
|
+
const createExport = nodeFactory(nodeKinds$1.export);
|
|
912
1524
|
/**
|
|
913
1525
|
* Creates a `SourceNode` representing a fragment of source code within a file.
|
|
914
1526
|
*
|
|
@@ -917,7 +1529,7 @@ const createExport = nodeFactory(nodeKinds.export);
|
|
|
917
1529
|
* createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
|
|
918
1530
|
* ```
|
|
919
1531
|
*/
|
|
920
|
-
const createSource = nodeFactory(nodeKinds.source);
|
|
1532
|
+
const createSource = nodeFactory(nodeKinds$1.source);
|
|
921
1533
|
/**
|
|
922
1534
|
* Creates a fully resolved `FileNode` from a file input descriptor.
|
|
923
1535
|
*
|
|
@@ -966,7 +1578,7 @@ function createFile(input) {
|
|
|
966
1578
|
const sourceParts = [];
|
|
967
1579
|
const localNames = /* @__PURE__ */ new Set();
|
|
968
1580
|
for (const item of resolvedSources) {
|
|
969
|
-
const extracted = item.nodes &&
|
|
1581
|
+
const extracted = item.nodes && getNodeText(item.nodes);
|
|
970
1582
|
if (extracted) sourceParts.push(extracted);
|
|
971
1583
|
if (item.name) localNames.add(item.name);
|
|
972
1584
|
}
|
|
@@ -984,7 +1596,7 @@ function createFile(input) {
|
|
|
984
1596
|
})();
|
|
985
1597
|
return {
|
|
986
1598
|
...input,
|
|
987
|
-
kind: nodeKinds.file,
|
|
1599
|
+
kind: nodeKinds$1.file,
|
|
988
1600
|
id: (0, node_crypto.hash)("sha256", input.path, "hex"),
|
|
989
1601
|
name: node_path.default.basename(input.baseName, extname),
|
|
990
1602
|
extname,
|
|
@@ -999,7 +1611,7 @@ function createFile(input) {
|
|
|
999
1611
|
* Replaces every name a file imports from a virtual file (one whose sources are all inline, so it is never written) with that name's
|
|
1000
1612
|
* `inline.expression`, until no inline names are left. The definitions' own imports move to the importing file.
|
|
1001
1613
|
*/
|
|
1002
|
-
function inlineFiles(files, { language }) {
|
|
1614
|
+
function inlineFiles$1(files, { language }) {
|
|
1003
1615
|
const virtualFiles = new Map(files.filter((file) => file.sources.length > 0 && file.sources.every((source) => source.inline)).map((file) => [file.path, file]));
|
|
1004
1616
|
const result = {
|
|
1005
1617
|
files: [],
|
|
@@ -1050,415 +1662,148 @@ function inlineFiles(files, { language }) {
|
|
|
1050
1662
|
}
|
|
1051
1663
|
imports.push(...definition.imports);
|
|
1052
1664
|
return lang.wrap(definition.expression);
|
|
1053
|
-
}),
|
|
1054
|
-
used
|
|
1055
|
-
};
|
|
1056
|
-
}
|
|
1057
|
-
function findTarget(file, local) {
|
|
1058
|
-
if (virtualFiles.has(file.path) && file.sources.some((source) => source.name === local)) return {
|
|
1059
|
-
path: file.path,
|
|
1060
|
-
name: local
|
|
1061
|
-
};
|
|
1062
|
-
for (const imp of file.imports) {
|
|
1063
|
-
const item = virtualFiles.has(imp.path) && [imp.name].flat().find((item) => importLocalName(item) === local);
|
|
1064
|
-
if (item) return {
|
|
1065
|
-
path: imp.path,
|
|
1066
|
-
name: typeof item === "string" ? item : item.propertyName
|
|
1067
|
-
};
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
for (const file of files) {
|
|
1071
|
-
if (virtualFiles.has(file.path) || !file.imports.some((imp) => virtualFiles.has(imp.path))) continue;
|
|
1072
|
-
const lang = language(file);
|
|
1073
|
-
if (!lang) {
|
|
1074
|
-
result.problems.push({
|
|
1075
|
-
path: file.path,
|
|
1076
|
-
message: `No parser for "${file.extname}" files supports inline sources.`
|
|
1077
|
-
});
|
|
1078
|
-
continue;
|
|
1079
|
-
}
|
|
1080
|
-
const carried = [];
|
|
1081
|
-
const sources = file.sources.map((source) => ({
|
|
1082
|
-
...source,
|
|
1083
|
-
nodes: rewriteNodes(source.nodes, (text) => replaceNames(text, file, lang, carried).text)
|
|
1084
|
-
}));
|
|
1085
|
-
const imports = [...file.imports.filter((imp) => !virtualFiles.has(imp.path)), ...carried.map((imp) => imp.root ? {
|
|
1086
|
-
...imp,
|
|
1087
|
-
root: file.path
|
|
1088
|
-
} : imp)];
|
|
1089
|
-
result.files.push(createFile({
|
|
1090
|
-
...file,
|
|
1091
|
-
sources,
|
|
1092
|
-
imports
|
|
1093
|
-
}));
|
|
1094
|
-
}
|
|
1095
|
-
return result;
|
|
1096
|
-
}
|
|
1097
|
-
function pickNames(imp, used) {
|
|
1098
|
-
if (!Array.isArray(imp.name)) return used.has(imp.name) ? [imp] : [];
|
|
1099
|
-
const name = imp.name.filter((item) => used.has(importLocalName(item)));
|
|
1100
|
-
return name.length > 0 ? [{
|
|
1101
|
-
...imp,
|
|
1102
|
-
name
|
|
1103
|
-
}] : [];
|
|
1104
|
-
}
|
|
1105
|
-
function rewriteNodes(nodes, rewrite) {
|
|
1106
|
-
return nodes?.map((node) => {
|
|
1107
|
-
if (typeof node === "string") return rewrite(node);
|
|
1108
|
-
if (node.kind === nodeKinds.break) return node;
|
|
1109
|
-
const next = { ...node };
|
|
1110
|
-
for (const field of CODE_NODE_TEXT_FIELDS[node.kind] ?? []) {
|
|
1111
|
-
const value = next[field];
|
|
1112
|
-
if (Array.isArray(value)) next[field] = value.map(rewrite);
|
|
1113
|
-
if (typeof value === "string" && value) next[field] = rewrite(value);
|
|
1114
|
-
}
|
|
1115
|
-
if ("nodes" in node && node.nodes) next.nodes = rewriteNodes(node.nodes, rewrite);
|
|
1116
|
-
return next;
|
|
1117
|
-
});
|
|
1118
|
-
}
|
|
1119
|
-
// src/utils/refs.ts
|
|
1120
|
-
/**
|
|
1121
|
-
* Returns the last segment of a `$ref` pointer, for example `'Pet'` for `#/components/schemas/Pet`.
|
|
1122
|
-
* The segment is decoded like the pointer resolver does: percent-escapes first, then `~1` and `~0`
|
|
1123
|
-
* (RFC 6901), so `a~1b~0c` names the component `a/b~c`.
|
|
1124
|
-
*/
|
|
1125
|
-
function refName(ref) {
|
|
1126
|
-
const cached = refNames.get(ref);
|
|
1127
|
-
if (cached !== void 0) return cached;
|
|
1128
|
-
const segment = ref.split("/").at(-1) ?? ref;
|
|
1129
|
-
let decoded = segment;
|
|
1130
|
-
try {
|
|
1131
|
-
decoded = decodeURIComponent(segment);
|
|
1132
|
-
} catch {}
|
|
1133
|
-
const name = decoded.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
1134
|
-
if (refNames.size >= memoLimit) refNames.clear();
|
|
1135
|
-
refNames.set(ref, name);
|
|
1136
|
-
return name;
|
|
1137
|
-
}
|
|
1138
|
-
const refNames = /* @__PURE__ */ new Map();
|
|
1139
|
-
const memoLimit = 1e5;
|
|
1140
|
-
/**
|
|
1141
|
-
* Resolves the emitted name of the schema a ref node points at. Prefers `targetName` (set when
|
|
1142
|
-
* the referenced schema was renamed, e.g. to break a collision), then the last segment of `ref`,
|
|
1143
|
-
* then `name`, then the nested `schema.name`.
|
|
1144
|
-
*
|
|
1145
|
-
* Returns `null` for non-ref nodes or when no name resolves.
|
|
1146
|
-
*
|
|
1147
|
-
* @example
|
|
1148
|
-
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
|
|
1149
|
-
*
|
|
1150
|
-
* @example Collision-renamed target
|
|
1151
|
-
* `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Order', targetName: 'OrderSchema' }) // 'OrderSchema'`
|
|
1152
|
-
*/
|
|
1153
|
-
function resolveRefName(node) {
|
|
1154
|
-
if (!node || node.type !== "ref") return null;
|
|
1155
|
-
if (node.targetName) return node.targetName;
|
|
1156
|
-
if (node.ref) return refName(node.ref);
|
|
1157
|
-
return node.name ?? node.schema?.name ?? null;
|
|
1158
|
-
}
|
|
1159
|
-
/**
|
|
1160
|
-
* Follows a resolved ref chain to its target schema. Returns an unresolved or cyclic ref as is.
|
|
1161
|
-
*
|
|
1162
|
-
* @example
|
|
1163
|
-
* ```ts
|
|
1164
|
-
* const target = resolveRef(refSchema)
|
|
1165
|
-
* ```
|
|
1166
|
-
*/
|
|
1167
|
-
function resolveRef(node) {
|
|
1168
|
-
if (node.type !== "ref" || !node.schema) return node;
|
|
1169
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
1170
|
-
let current = node;
|
|
1171
|
-
while (current.type === "ref" && current.schema) {
|
|
1172
|
-
if (seen.has(current)) return current;
|
|
1173
|
-
seen.add(current);
|
|
1174
|
-
current = current.schema;
|
|
1175
|
-
}
|
|
1176
|
-
return current;
|
|
1177
|
-
}
|
|
1178
|
-
/** Fields of a ref node that describe the ref itself, so they never override the resolved schema. */
|
|
1179
|
-
const REF_OWN_KEYS = /* @__PURE__ */ new Set([
|
|
1180
|
-
"kind",
|
|
1181
|
-
"type",
|
|
1182
|
-
"name",
|
|
1183
|
-
"ref",
|
|
1184
|
-
"schema"
|
|
1185
|
-
]);
|
|
1186
|
-
/**
|
|
1187
|
-
* Merges a ref node with its resolved schema, giving the fields set at the usage site precedence.
|
|
1188
|
-
*
|
|
1189
|
-
* Every field on the ref except `kind`, `type`, `name`, `ref`, and `schema` overrides the same field
|
|
1190
|
-
* of the resolved `schema` (for example `description`, `nullable`, `readOnly`, `deprecated`). Fields
|
|
1191
|
-
* left `undefined` on the ref do not shadow the resolved schema. A ref without a resolved `schema`
|
|
1192
|
-
* is returned as is.
|
|
1193
|
-
*
|
|
1194
|
-
* @example
|
|
1195
|
-
* ```ts
|
|
1196
|
-
* const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A pet', schema: petSchema })
|
|
1197
|
-
* mergeRefWithSchema(ref) // petSchema's fields with description 'A pet'
|
|
1198
|
-
* ```
|
|
1199
|
-
*/
|
|
1200
|
-
function mergeRefWithSchema(node) {
|
|
1201
|
-
if (!node.schema) return node;
|
|
1202
|
-
const merged = { ...node.schema };
|
|
1203
|
-
for (const key of Object.keys(node)) {
|
|
1204
|
-
const value = node[key];
|
|
1205
|
-
if (value !== void 0 && !REF_OWN_KEYS.has(key)) merged[key] = value;
|
|
1206
|
-
}
|
|
1207
|
-
return merged;
|
|
1208
|
-
}
|
|
1209
|
-
/**
|
|
1210
|
-
* Returns `true` when a schema is a bare ref without modifiers, metadata, or omit keys.
|
|
1211
|
-
*
|
|
1212
|
-
* Modifiers inherited from the resolved schema are included in the check because a ref emits the
|
|
1213
|
-
* referenced schema variable with those modifiers already applied.
|
|
1214
|
-
*/
|
|
1215
|
-
function isBareRef(node, keysToOmit) {
|
|
1216
|
-
if (!node || node.type !== "ref") return false;
|
|
1217
|
-
const meta = mergeRefWithSchema(node);
|
|
1218
|
-
return !meta.nullable && !meta.optional && !meta.nullish && meta.default === void 0 && !meta.description && !meta.examples?.length && !keysToOmit?.length;
|
|
1219
|
-
}
|
|
1220
|
-
// ../../internals/utils/src/promise.ts
|
|
1221
|
-
/**
|
|
1222
|
-
* Returns the value cached under `key` in `store`, computing and storing it on the first call.
|
|
1223
|
-
* Pass a `WeakMap` for object keys, so an entry goes away with its key, or a `Map` for primitive
|
|
1224
|
-
* keys. A cached `null` or `undefined` counts as a hit, so `compute` runs once per key.
|
|
1225
|
-
*
|
|
1226
|
-
* @example
|
|
1227
|
-
* `const refs = memo(refCache, node, () => collectRefs(node))`
|
|
1228
|
-
*/
|
|
1229
|
-
function memo(store, key, compute) {
|
|
1230
|
-
if (store.has(key)) return store.get(key);
|
|
1231
|
-
const value = compute();
|
|
1232
|
-
store.set(key, value);
|
|
1233
|
-
return value;
|
|
1234
|
-
}
|
|
1235
|
-
// src/utils/schemaGraph.ts
|
|
1236
|
-
const refEntries = /* @__PURE__ */ new WeakMap();
|
|
1237
|
-
const checkRefEntries = /* @__PURE__ */ new WeakMap();
|
|
1238
|
-
const schemaRefs = /* @__PURE__ */ new WeakMap();
|
|
1239
|
-
const importedRefNames = /* @__PURE__ */ new WeakMap();
|
|
1240
|
-
const importedCheckRefNames = /* @__PURE__ */ new WeakMap();
|
|
1241
|
-
/**
|
|
1242
|
-
* Walks a node's subtree once and lists every ref it holds, in traversal order, as the resolved
|
|
1243
|
-
* name plus whether the ref carries a `$ref` pointer. Memoized per node and per `checks` mode, so
|
|
1244
|
-
* each helper below scans a schema once.
|
|
1245
|
-
*/
|
|
1246
|
-
function collectRefEntries(node, { checks }) {
|
|
1247
|
-
return memo(checks ? checkRefEntries : refEntries, node, () => {
|
|
1248
|
-
const entries = [];
|
|
1249
|
-
const walk = (current) => {
|
|
1250
|
-
if (current.kind === nodeKinds.schema && current.type === "ref") {
|
|
1251
|
-
const name = resolveRefName(current);
|
|
1252
|
-
if (name) entries.push({
|
|
1253
|
-
name,
|
|
1254
|
-
hasPointer: Boolean(current.ref)
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1257
|
-
visitChildNodes(current, walk, { checks });
|
|
1258
|
-
return false;
|
|
1259
|
-
};
|
|
1260
|
-
walk(node);
|
|
1261
|
-
return entries;
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
/**
|
|
1265
|
-
* Collects the names of every schema a node's subtree references, resolved with `resolveRefName`.
|
|
1266
|
-
* Each ref contributes its name only, so the schema it points to is never traversed. Memoized by
|
|
1267
|
-
* node identity, which lets `findCircularSchemas` and `containsCircularRef` share one scan per schema.
|
|
1268
|
-
*
|
|
1269
|
-
* @example
|
|
1270
|
-
* ```ts
|
|
1271
|
-
* collectSchemaRefs(petSchema)
|
|
1272
|
-
* // Set { 'Category', 'Tag' }
|
|
1273
|
-
* ```
|
|
1274
|
-
*/
|
|
1275
|
-
function collectSchemaRefs(node) {
|
|
1276
|
-
return memo(schemaRefs, node, () => new Set(collectRefEntries(node, { checks: true }).map((entry) => entry.name)));
|
|
1277
|
-
}
|
|
1278
|
-
/**
|
|
1279
|
-
* Collects the de-duplicated target names of every pointer-carrying ref in a node's subtree, in
|
|
1280
|
-
* first-occurrence order. Memoized by node identity, so `resolver.imports` reads the same result
|
|
1281
|
-
* across the ts, zod, and faker plugins instead of re-scanning the same schema per plugin.
|
|
1282
|
-
*
|
|
1283
|
-
* Only refs that carry a `$ref` pointer count, so a synthesized ref pointing at a sibling in the
|
|
1284
|
-
* same file (a union member created by name) is left out. That leaves exactly the set
|
|
1285
|
-
* `resolver.imports` emits. Refs inside `conditionals`, `contains` and `content` count only with
|
|
1286
|
-
* `checks: true`, for a plugin that prints those checks.
|
|
1287
|
-
*
|
|
1288
|
-
* @example
|
|
1289
|
-
* ```ts
|
|
1290
|
-
* collectImportedRefNames(petSchema)
|
|
1291
|
-
* // ['Category', 'Tag']
|
|
1292
|
-
* ```
|
|
1293
|
-
*/
|
|
1294
|
-
function collectImportedRefNames(node, { checks = false } = {}) {
|
|
1295
|
-
return memo(checks ? importedCheckRefNames : importedRefNames, node, () => [...new Set(collectRefEntries(node, { checks }).flatMap((entry) => entry.hasPointer ? [entry.name] : []))]);
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
|
-
* Collects the names of all top-level schemas transitively used by a set of operations.
|
|
1299
|
-
*
|
|
1300
|
-
* An operation uses a schema when its parameters, request body, or responses reference it, directly
|
|
1301
|
-
* or through other named schemas. Once a name is added to the result it is not revisited, so
|
|
1302
|
-
* reference cycles terminate.
|
|
1303
|
-
*
|
|
1304
|
-
* Pair it with `include` filters so schemas reachable only from excluded operations stay ungenerated.
|
|
1305
|
-
*
|
|
1306
|
-
* @example Only generate schemas referenced by included operations
|
|
1307
|
-
* ```ts
|
|
1308
|
-
* const includedOps = operations.filter((op) => resolver.default.options(op, { options, include }) !== null)
|
|
1309
|
-
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
1310
|
-
*
|
|
1311
|
-
* for (const schema of schemas) {
|
|
1312
|
-
* if (schema.name && !allowed.has(schema.name)) continue
|
|
1313
|
-
* // generate schema
|
|
1314
|
-
* }
|
|
1315
|
-
* ```
|
|
1316
|
-
*/
|
|
1317
|
-
function collectUsedSchemaNames(operations, schemas) {
|
|
1318
|
-
const schemaMap = /* @__PURE__ */ new Map();
|
|
1319
|
-
for (const schema of schemas) if (schema.name) schemaMap.set(schema.name, schema);
|
|
1320
|
-
const result = /* @__PURE__ */ new Set();
|
|
1321
|
-
function visitSchema(schema) {
|
|
1322
|
-
for (const name of collectSchemaRefs(schema)) if (!result.has(name)) {
|
|
1323
|
-
result.add(name);
|
|
1324
|
-
const namedSchema = schemaMap.get(name);
|
|
1325
|
-
if (namedSchema) visitSchema(namedSchema);
|
|
1326
|
-
}
|
|
1665
|
+
}),
|
|
1666
|
+
used
|
|
1667
|
+
};
|
|
1327
1668
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
* linear in the size of the schema graph.
|
|
1340
|
-
*
|
|
1341
|
-
* @note Call this once on the full graph, then check individual schemas with `containsCircularRef()`.
|
|
1342
|
-
*/
|
|
1343
|
-
function findCircularSchemas(schemas) {
|
|
1344
|
-
const graph = /* @__PURE__ */ new Map();
|
|
1345
|
-
for (const schema of schemas) if (schema.name) graph.set(schema.name, collectSchemaRefs(schema));
|
|
1346
|
-
const circular = /* @__PURE__ */ new Set();
|
|
1347
|
-
for (const start of graph.keys()) {
|
|
1348
|
-
const visited = /* @__PURE__ */ new Set();
|
|
1349
|
-
const stack = [...graph.get(start) ?? []];
|
|
1350
|
-
while (stack.length > 0) {
|
|
1351
|
-
const node = stack.pop();
|
|
1352
|
-
if (node === start) {
|
|
1353
|
-
circular.add(start);
|
|
1354
|
-
break;
|
|
1355
|
-
}
|
|
1356
|
-
if (visited.has(node)) continue;
|
|
1357
|
-
visited.add(node);
|
|
1358
|
-
const next = graph.get(node);
|
|
1359
|
-
if (next) for (const r of next) stack.push(r);
|
|
1669
|
+
function findTarget(file, local) {
|
|
1670
|
+
if (virtualFiles.has(file.path) && file.sources.some((source) => source.name === local)) return {
|
|
1671
|
+
path: file.path,
|
|
1672
|
+
name: local
|
|
1673
|
+
};
|
|
1674
|
+
for (const imp of file.imports) {
|
|
1675
|
+
const item = virtualFiles.has(imp.path) && [imp.name].flat().find((item) => importLocalName(item) === local);
|
|
1676
|
+
if (item) return {
|
|
1677
|
+
path: imp.path,
|
|
1678
|
+
name: typeof item === "string" ? item : item.propertyName
|
|
1679
|
+
};
|
|
1360
1680
|
}
|
|
1361
1681
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
* ```
|
|
1387
|
-
*
|
|
1388
|
-
* @example TypeScript property lookup
|
|
1389
|
-
* ```ts
|
|
1390
|
-
* const properties = resolveSchemaProperties({ node: schema, propertyName: 'status' })
|
|
1391
|
-
* const statusSchemas = properties.map((property) => print(property.schema))
|
|
1392
|
-
* ```
|
|
1393
|
-
*/
|
|
1394
|
-
function resolveSchemaProperties({ node, propertyName }) {
|
|
1395
|
-
const properties = [];
|
|
1396
|
-
walkSchema(node, "intersection", (current) => {
|
|
1397
|
-
if (current.type !== "object") return;
|
|
1398
|
-
const property = current.properties.find((candidate) => candidate.name === propertyName);
|
|
1399
|
-
if (property) properties.push(property);
|
|
1400
|
-
});
|
|
1401
|
-
return properties;
|
|
1402
|
-
}
|
|
1403
|
-
function walkSchema(node, through, visit) {
|
|
1404
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
1405
|
-
function walk(current) {
|
|
1406
|
-
if (!current || visited.has(current)) return;
|
|
1407
|
-
visited.add(current);
|
|
1408
|
-
visit(current);
|
|
1409
|
-
if (current.type === "ref") return walk(current.schema);
|
|
1410
|
-
if (current.type === through) for (const member of current.members ?? []) walk(member);
|
|
1682
|
+
for (const file of files) {
|
|
1683
|
+
if (virtualFiles.has(file.path) || !file.imports.some((imp) => virtualFiles.has(imp.path))) continue;
|
|
1684
|
+
const lang = language(file);
|
|
1685
|
+
if (!lang) {
|
|
1686
|
+
result.problems.push({
|
|
1687
|
+
path: file.path,
|
|
1688
|
+
message: `No parser for "${file.extname}" files supports inline sources.`
|
|
1689
|
+
});
|
|
1690
|
+
continue;
|
|
1691
|
+
}
|
|
1692
|
+
const carried = [];
|
|
1693
|
+
const sources = file.sources.map((source) => ({
|
|
1694
|
+
...source,
|
|
1695
|
+
nodes: rewriteNodes(source.nodes, (text) => replaceNames(text, file, lang, carried).text)
|
|
1696
|
+
}));
|
|
1697
|
+
const imports = [...file.imports.filter((imp) => !virtualFiles.has(imp.path)), ...carried.map((imp) => imp.root ? {
|
|
1698
|
+
...imp,
|
|
1699
|
+
root: file.path
|
|
1700
|
+
} : imp)];
|
|
1701
|
+
result.files.push(createFile({
|
|
1702
|
+
...file,
|
|
1703
|
+
sources,
|
|
1704
|
+
imports
|
|
1705
|
+
}));
|
|
1411
1706
|
}
|
|
1412
|
-
|
|
1707
|
+
return result;
|
|
1413
1708
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
* const values = getSchemaLiteralValues(enumNode)
|
|
1423
|
-
* // ['cat', 'dog']
|
|
1424
|
-
* ```
|
|
1425
|
-
*/
|
|
1426
|
-
function getSchemaLiteralValues(node) {
|
|
1427
|
-
const values = /* @__PURE__ */ new Set();
|
|
1428
|
-
walkSchema(node, "union", (current) => {
|
|
1429
|
-
if (current.type !== "enum") return;
|
|
1430
|
-
for (const { value } of current.namedEnumValues ?? current.enumValues?.map((value) => ({ value })) ?? []) values.add(value);
|
|
1431
|
-
});
|
|
1432
|
-
return [...values];
|
|
1709
|
+
__name(inlineFiles$1, "inlineFiles");
|
|
1710
|
+
function pickNames(imp, used) {
|
|
1711
|
+
if (!Array.isArray(imp.name)) return used.has(imp.name) ? [imp] : [];
|
|
1712
|
+
const name = imp.name.filter((item) => used.has(importLocalName(item)));
|
|
1713
|
+
return name.length > 0 ? [{
|
|
1714
|
+
...imp,
|
|
1715
|
+
name
|
|
1716
|
+
}] : [];
|
|
1433
1717
|
}
|
|
1434
|
-
function
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
if (
|
|
1718
|
+
function rewriteNodes(nodes, rewrite) {
|
|
1719
|
+
return nodes?.map((node) => {
|
|
1720
|
+
if (typeof node === "string") return rewrite(node);
|
|
1721
|
+
if (node.kind === nodeKinds$1.break) return node;
|
|
1722
|
+
const next = { ...node };
|
|
1723
|
+
for (const field of CODE_NODE_TEXT_FIELDS[node.kind] ?? []) {
|
|
1724
|
+
const value = next[field];
|
|
1725
|
+
if (Array.isArray(value)) next[field] = value.map(rewrite);
|
|
1726
|
+
if (typeof value === "string" && value) next[field] = rewrite(value);
|
|
1727
|
+
}
|
|
1728
|
+
if ("nodes" in node && node.nodes) next.nodes = rewriteNodes(node.nodes, rewrite);
|
|
1729
|
+
return next;
|
|
1438
1730
|
});
|
|
1439
|
-
return names;
|
|
1440
1731
|
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
*/
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1732
|
+
// src/file/index.ts
|
|
1733
|
+
var file_exports = /* @__PURE__ */ __exportAll({ inline: () => inlineFiles$1 });
|
|
1734
|
+
// src/deprecated.ts
|
|
1735
|
+
/** @deprecated Use `ast.ref.isAlias`. Removed in Kubb v6. */
|
|
1736
|
+
const isBareRef = isBareRef$1;
|
|
1737
|
+
/** @deprecated Use `ast.ref.mergeSchema`. Removed in Kubb v6. */
|
|
1738
|
+
const mergeRefWithSchema = mergeRefWithSchema$1;
|
|
1739
|
+
/** @deprecated Use `ast.ref.getName`. Removed in Kubb v6. */
|
|
1740
|
+
const refName = getName;
|
|
1741
|
+
/** @deprecated Use `ast.ref.getSchema`. Removed in Kubb v6. */
|
|
1742
|
+
const resolveRef = resolveRef$1;
|
|
1743
|
+
/** @deprecated Use `ast.ref.getName`. Removed in Kubb v6. */
|
|
1744
|
+
const resolveRefName = getName;
|
|
1745
|
+
/** @deprecated Use `ast.graph.getImportedNames`. Removed in Kubb v6. */
|
|
1746
|
+
const collectImportedRefNames = collectImportedRefNames$1;
|
|
1747
|
+
/** @deprecated Use `ast.graph.getRefNames`. Removed in Kubb v6. */
|
|
1748
|
+
const collectSchemaRefs = collectSchemaRefs$1;
|
|
1749
|
+
/** @deprecated Use `ast.graph.getUsedNames`. Removed in Kubb v6. */
|
|
1750
|
+
const collectUsedSchemaNames = collectUsedSchemaNames$1;
|
|
1751
|
+
/** @deprecated Use `ast.graph.getCircularNames`. Removed in Kubb v6. */
|
|
1752
|
+
const findCircularSchemas = findCircularSchemas$1;
|
|
1753
|
+
/** @deprecated Use `ast.schema.getLiterals`. Removed in Kubb v6. */
|
|
1754
|
+
const getSchemaLiteralValues = getSchemaLiteralValues$1;
|
|
1755
|
+
/** @deprecated Use `ast.schema.inferDiscriminator`. Removed in Kubb v6. */
|
|
1756
|
+
const inferDiscriminatorPropertyName = inferDiscriminatorPropertyName$1;
|
|
1757
|
+
/** @deprecated Use `ast.schema.findProperties`. Removed in Kubb v6. */
|
|
1758
|
+
const resolveSchemaProperties = resolveSchemaProperties$1;
|
|
1759
|
+
/** @deprecated Use `ast.http.isOperation`. Removed in Kubb v6. */
|
|
1760
|
+
const isHttpOperationNode = isHttpOperationNode$1;
|
|
1761
|
+
/** @deprecated Use `ast.node.collect`, which returns the same array. Removed in Kubb v6. */
|
|
1762
|
+
const collectSync = collect$1;
|
|
1763
|
+
/** @deprecated Use `ast.schema.applyOptionality`. Removed in Kubb v6. */
|
|
1764
|
+
const optionality = applyOptionality;
|
|
1765
|
+
/** @deprecated Use `ast.node.getText`. Removed in Kubb v6. */
|
|
1766
|
+
const extractStringsFromNodes = getNodeText;
|
|
1767
|
+
/** @deprecated Use `ast.macro.compareOrder`. Removed in Kubb v6. */
|
|
1768
|
+
const compareEnforce = compareMacroOrder;
|
|
1769
|
+
/** @deprecated Use `createPrinter` from `@kubb/kit`. Removed in Kubb v6. */
|
|
1770
|
+
const createPrinter = createPrinter$1;
|
|
1771
|
+
/** @deprecated Use `defineMacro` from `@kubb/kit`. Removed in Kubb v6. */
|
|
1772
|
+
const defineMacro = defineMacro$1;
|
|
1773
|
+
/** @deprecated Use `ast.macro.apply`. Removed in Kubb v6. */
|
|
1774
|
+
const applyMacros = applyMacros$1;
|
|
1775
|
+
/** @deprecated Use `ast.node.kinds`. Removed in Kubb v6. */
|
|
1776
|
+
const nodeKinds = nodeKinds$1;
|
|
1777
|
+
/** @deprecated Use `ast.schema.types`. Removed in Kubb v6. */
|
|
1778
|
+
const schemaTypes = schemaTypes$1;
|
|
1779
|
+
/** @deprecated Use `ast.schema.find`. Removed in Kubb v6. */
|
|
1780
|
+
const findSchema = findSchema$1;
|
|
1781
|
+
/** @deprecated Use `ast.schema.narrow`. Removed in Kubb v6. */
|
|
1782
|
+
const narrowSchema = narrowSchema$1;
|
|
1783
|
+
/** @deprecated Use `ast.node.transform`. Removed in Kubb v6. */
|
|
1784
|
+
const transform = transform$1;
|
|
1785
|
+
/** @deprecated Use `ast.node.collect`. Removed in Kubb v6. */
|
|
1786
|
+
const collect = collect$1;
|
|
1787
|
+
/** @deprecated Use `ast.file.inline`. Removed in Kubb v6. */
|
|
1788
|
+
const inlineFiles = inlineFiles$1;
|
|
1789
|
+
// src/auth/index.ts
|
|
1790
|
+
var auth_exports = /* @__PURE__ */ __exportAll({ getRequirements: () => getRequirements });
|
|
1791
|
+
/** Joins each requirement with its schemes. Drops undeclared and repeated requirements, and keeps an empty one (no auth needed). */
|
|
1792
|
+
function getRequirements({ auth, schemes }) {
|
|
1793
|
+
const credentials = new Map(schemes?.map((scheme) => [scheme.name, scheme.credential]));
|
|
1794
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1795
|
+
const resolved = [];
|
|
1796
|
+
for (const requirement of auth ?? []) {
|
|
1797
|
+
const key = requirement.map(({ scheme, scopes }) => [scheme, ...scopes ?? []].join(" ")).join("\0");
|
|
1798
|
+
if (seen.has(key) || !requirement.every(({ scheme }) => credentials.has(scheme))) continue;
|
|
1799
|
+
seen.add(key);
|
|
1800
|
+
resolved.push(requirement.map(({ scheme, scopes }) => ({
|
|
1801
|
+
name: scheme,
|
|
1802
|
+
credential: credentials.get(scheme),
|
|
1803
|
+
scopes: scopes ?? []
|
|
1804
|
+
})));
|
|
1461
1805
|
}
|
|
1806
|
+
return resolved;
|
|
1462
1807
|
}
|
|
1463
1808
|
// src/nodes/code.ts
|
|
1464
1809
|
/**
|
|
@@ -1470,7 +1815,7 @@ function inferDiscriminatorPropertyName(members) {
|
|
|
1470
1815
|
* // export const pets: Pet[] = ... as const
|
|
1471
1816
|
* ```
|
|
1472
1817
|
*/
|
|
1473
|
-
const createConst = nodeFactory(nodeKinds.const);
|
|
1818
|
+
const createConst = nodeFactory(nodeKinds$1.const);
|
|
1474
1819
|
/**
|
|
1475
1820
|
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
|
|
1476
1821
|
*
|
|
@@ -1480,7 +1825,7 @@ const createConst = nodeFactory(nodeKinds.const);
|
|
|
1480
1825
|
* // export type Pet = ...
|
|
1481
1826
|
* ```
|
|
1482
1827
|
*/
|
|
1483
|
-
const createType = nodeFactory(nodeKinds.type);
|
|
1828
|
+
const createType = nodeFactory(nodeKinds$1.type);
|
|
1484
1829
|
/**
|
|
1485
1830
|
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
|
|
1486
1831
|
*
|
|
@@ -1490,7 +1835,7 @@ const createType = nodeFactory(nodeKinds.type);
|
|
|
1490
1835
|
* // export async function fetchPet(): Promise<Pet> { ... }
|
|
1491
1836
|
* ```
|
|
1492
1837
|
*/
|
|
1493
|
-
const createFunction = nodeFactory(nodeKinds.function);
|
|
1838
|
+
const createFunction = nodeFactory(nodeKinds$1.function);
|
|
1494
1839
|
/**
|
|
1495
1840
|
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
|
|
1496
1841
|
*
|
|
@@ -1500,7 +1845,7 @@ const createFunction = nodeFactory(nodeKinds.function);
|
|
|
1500
1845
|
* // export const double = (n: number) => ...
|
|
1501
1846
|
* ```
|
|
1502
1847
|
*/
|
|
1503
|
-
const createArrowFunction = nodeFactory(nodeKinds.arrowFunction);
|
|
1848
|
+
const createArrowFunction = nodeFactory(nodeKinds$1.arrowFunction);
|
|
1504
1849
|
/**
|
|
1505
1850
|
* Creates a {@link TextNode} representing a raw string fragment in the source output.
|
|
1506
1851
|
*
|
|
@@ -1512,7 +1857,7 @@ const createArrowFunction = nodeFactory(nodeKinds.arrowFunction);
|
|
|
1512
1857
|
*/
|
|
1513
1858
|
function createText(value) {
|
|
1514
1859
|
return {
|
|
1515
|
-
kind: nodeKinds.text,
|
|
1860
|
+
kind: nodeKinds$1.text,
|
|
1516
1861
|
value
|
|
1517
1862
|
};
|
|
1518
1863
|
}
|
|
@@ -1526,7 +1871,7 @@ function createText(value) {
|
|
|
1526
1871
|
* ```
|
|
1527
1872
|
*/
|
|
1528
1873
|
function createBreak() {
|
|
1529
|
-
return { kind: nodeKinds.break };
|
|
1874
|
+
return { kind: nodeKinds$1.break };
|
|
1530
1875
|
}
|
|
1531
1876
|
/**
|
|
1532
1877
|
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
|
|
@@ -1539,7 +1884,7 @@ function createBreak() {
|
|
|
1539
1884
|
*/
|
|
1540
1885
|
function createJsx(value) {
|
|
1541
1886
|
return {
|
|
1542
|
-
kind: nodeKinds.jsx,
|
|
1887
|
+
kind: nodeKinds$1.jsx,
|
|
1543
1888
|
value
|
|
1544
1889
|
};
|
|
1545
1890
|
}
|
|
@@ -1547,7 +1892,7 @@ function createJsx(value) {
|
|
|
1547
1892
|
/**
|
|
1548
1893
|
* Creates a `ContentNode` for a single request-body or response content type.
|
|
1549
1894
|
*/
|
|
1550
|
-
const createContent = nodeFactory(nodeKinds.content);
|
|
1895
|
+
const createContent = nodeFactory(nodeKinds$1.content);
|
|
1551
1896
|
// src/nodes/input.ts
|
|
1552
1897
|
/**
|
|
1553
1898
|
* Creates an `InputNode`, defaulting `schemas`/`operations` to empty arrays and `meta` to an empty
|
|
@@ -1565,14 +1910,14 @@ function createInput(overrides = {}) {
|
|
|
1565
1910
|
operations: [],
|
|
1566
1911
|
meta: {},
|
|
1567
1912
|
...overrides,
|
|
1568
|
-
kind: nodeKinds.input
|
|
1913
|
+
kind: nodeKinds$1.input
|
|
1569
1914
|
};
|
|
1570
1915
|
}
|
|
1571
1916
|
// src/nodes/requestBody.ts
|
|
1572
1917
|
/**
|
|
1573
1918
|
* Creates a `RequestBodyNode`.
|
|
1574
1919
|
*/
|
|
1575
|
-
const createRequestBody = nodeFactory(nodeKinds.requestBody);
|
|
1920
|
+
const createRequestBody = nodeFactory(nodeKinds$1.requestBody);
|
|
1576
1921
|
// src/nodes/operation.ts
|
|
1577
1922
|
function createOperation(props) {
|
|
1578
1923
|
const { requestBody, ...rest } = props;
|
|
@@ -1582,7 +1927,7 @@ function createOperation(props) {
|
|
|
1582
1927
|
parameters: [],
|
|
1583
1928
|
responses: [],
|
|
1584
1929
|
...rest,
|
|
1585
|
-
kind: nodeKinds.operation,
|
|
1930
|
+
kind: nodeKinds$1.operation,
|
|
1586
1931
|
...isHttp ? { protocol: "http" } : {},
|
|
1587
1932
|
requestBody: requestBody ? createRequestBody(requestBody) : void 0
|
|
1588
1933
|
};
|
|
@@ -1607,8 +1952,8 @@ function createParameter(input) {
|
|
|
1607
1952
|
return {
|
|
1608
1953
|
...input,
|
|
1609
1954
|
required,
|
|
1610
|
-
schema:
|
|
1611
|
-
kind: nodeKinds.parameter
|
|
1955
|
+
schema: applyOptionality(input.schema, required),
|
|
1956
|
+
kind: nodeKinds$1.parameter
|
|
1612
1957
|
};
|
|
1613
1958
|
}
|
|
1614
1959
|
// src/nodes/property.ts
|
|
@@ -1631,8 +1976,8 @@ function createProperty(input) {
|
|
|
1631
1976
|
return {
|
|
1632
1977
|
...input,
|
|
1633
1978
|
required,
|
|
1634
|
-
schema:
|
|
1635
|
-
kind: nodeKinds.property
|
|
1979
|
+
schema: applyOptionality(input.schema, required),
|
|
1980
|
+
kind: nodeKinds$1.property
|
|
1636
1981
|
};
|
|
1637
1982
|
}
|
|
1638
1983
|
// src/nodes/response.ts
|
|
@@ -1658,46 +2003,7 @@ function createResponse(props) {
|
|
|
1658
2003
|
return {
|
|
1659
2004
|
...rest,
|
|
1660
2005
|
content: entries,
|
|
1661
|
-
kind: nodeKinds.response
|
|
1662
|
-
};
|
|
1663
|
-
}
|
|
1664
|
-
// src/nodes/schema.ts
|
|
1665
|
-
/**
|
|
1666
|
-
* Maps schema `type` to its underlying `primitive`.
|
|
1667
|
-
* Primitive types map to themselves and special string formats map to `'string'`.
|
|
1668
|
-
* Any type not listed here (such as `ref`, `enum`, `union`, `intersection`, `not`, `tuple`, `ipv4`, `ipv6`, `blob`) has no `primitive`.
|
|
1669
|
-
*/
|
|
1670
|
-
const TYPE_TO_PRIMITIVE = {
|
|
1671
|
-
string: "string",
|
|
1672
|
-
number: "number",
|
|
1673
|
-
integer: "integer",
|
|
1674
|
-
bigint: "bigint",
|
|
1675
|
-
boolean: "boolean",
|
|
1676
|
-
null: "null",
|
|
1677
|
-
any: "any",
|
|
1678
|
-
unknown: "unknown",
|
|
1679
|
-
void: "void",
|
|
1680
|
-
never: "never",
|
|
1681
|
-
object: "object",
|
|
1682
|
-
array: "array",
|
|
1683
|
-
date: "date",
|
|
1684
|
-
uuid: "string",
|
|
1685
|
-
email: "string",
|
|
1686
|
-
url: "string",
|
|
1687
|
-
datetime: "string",
|
|
1688
|
-
time: "string"
|
|
1689
|
-
};
|
|
1690
|
-
function createSchema(props) {
|
|
1691
|
-
if (props.type === "object") return {
|
|
1692
|
-
properties: [],
|
|
1693
|
-
primitive: "object",
|
|
1694
|
-
...props,
|
|
1695
|
-
kind: nodeKinds.schema
|
|
1696
|
-
};
|
|
1697
|
-
return {
|
|
1698
|
-
primitive: TYPE_TO_PRIMITIVE[props.type],
|
|
1699
|
-
...props,
|
|
1700
|
-
kind: nodeKinds.schema
|
|
2006
|
+
kind: nodeKinds$1.response
|
|
1701
2007
|
};
|
|
1702
2008
|
}
|
|
1703
2009
|
// src/nodes/index.ts
|
|
@@ -1722,10 +2028,26 @@ var nodes_exports = /* @__PURE__ */ __exportAll({
|
|
|
1722
2028
|
createText: () => createText,
|
|
1723
2029
|
createType: () => createType
|
|
1724
2030
|
});
|
|
2031
|
+
// src/server/index.ts
|
|
2032
|
+
var server_exports = /* @__PURE__ */ __exportAll({
|
|
2033
|
+
get: () => get,
|
|
2034
|
+
groupByName: () => groupByName
|
|
2035
|
+
});
|
|
2036
|
+
/** The server at `index`, else the first one. */
|
|
2037
|
+
function get({ servers, index = 0 }) {
|
|
2038
|
+
return servers?.[index] ?? servers?.[0];
|
|
2039
|
+
}
|
|
2040
|
+
/** Named servers by name. The first server with a name wins. */
|
|
2041
|
+
function groupByName(servers) {
|
|
2042
|
+
const named = /* @__PURE__ */ new Map();
|
|
2043
|
+
for (const server of servers ?? []) if (server.name && !named.has(server.name)) named.set(server.name, server);
|
|
2044
|
+
return named;
|
|
2045
|
+
}
|
|
1725
2046
|
// src/index.ts
|
|
1726
2047
|
var src_exports = /* @__PURE__ */ __exportAll({
|
|
1727
2048
|
applyMacros: () => applyMacros,
|
|
1728
2049
|
ast: () => src_exports,
|
|
2050
|
+
auth: () => auth_exports,
|
|
1729
2051
|
collect: () => collect,
|
|
1730
2052
|
collectImportedRefNames: () => collectImportedRefNames,
|
|
1731
2053
|
collectSchemaRefs: () => collectSchemaRefs,
|
|
@@ -1736,22 +2058,31 @@ var src_exports = /* @__PURE__ */ __exportAll({
|
|
|
1736
2058
|
defineMacro: () => defineMacro,
|
|
1737
2059
|
extractStringsFromNodes: () => extractStringsFromNodes,
|
|
1738
2060
|
factory: () => nodes_exports,
|
|
2061
|
+
file: () => file_exports,
|
|
1739
2062
|
findCircularSchemas: () => findCircularSchemas,
|
|
1740
2063
|
findSchema: () => findSchema,
|
|
1741
2064
|
getSchemaLiteralValues: () => getSchemaLiteralValues,
|
|
2065
|
+
graph: () => graph_exports,
|
|
2066
|
+
http: () => http_exports,
|
|
1742
2067
|
inferDiscriminatorPropertyName: () => inferDiscriminatorPropertyName,
|
|
1743
2068
|
inlineFiles: () => inlineFiles,
|
|
1744
2069
|
isBareRef: () => isBareRef,
|
|
1745
2070
|
isHttpOperationNode: () => isHttpOperationNode,
|
|
2071
|
+
macro: () => macro_exports,
|
|
2072
|
+
mediaType: () => mediaType_exports,
|
|
1746
2073
|
mergeRefWithSchema: () => mergeRefWithSchema,
|
|
1747
2074
|
narrowSchema: () => narrowSchema,
|
|
2075
|
+
node: () => node_exports,
|
|
1748
2076
|
nodeKinds: () => nodeKinds,
|
|
1749
2077
|
optionality: () => optionality,
|
|
2078
|
+
ref: () => ref_exports,
|
|
1750
2079
|
refName: () => refName,
|
|
1751
2080
|
resolveRef: () => resolveRef,
|
|
1752
2081
|
resolveRefName: () => resolveRefName,
|
|
1753
2082
|
resolveSchemaProperties: () => resolveSchemaProperties,
|
|
2083
|
+
schema: () => schema_exports,
|
|
1754
2084
|
schemaTypes: () => schemaTypes,
|
|
2085
|
+
server: () => server_exports,
|
|
1755
2086
|
transform: () => transform
|
|
1756
2087
|
});
|
|
1757
2088
|
exports.applyMacros = applyMacros;
|
|
@@ -1761,6 +2092,12 @@ Object.defineProperty(exports, "ast", {
|
|
|
1761
2092
|
return src_exports;
|
|
1762
2093
|
}
|
|
1763
2094
|
});
|
|
2095
|
+
Object.defineProperty(exports, "auth", {
|
|
2096
|
+
enumerable: true,
|
|
2097
|
+
get: function() {
|
|
2098
|
+
return auth_exports;
|
|
2099
|
+
}
|
|
2100
|
+
});
|
|
1764
2101
|
exports.collect = collect;
|
|
1765
2102
|
exports.collectImportedRefNames = collectImportedRefNames;
|
|
1766
2103
|
exports.collectSchemaRefs = collectSchemaRefs;
|
|
@@ -1776,22 +2113,76 @@ Object.defineProperty(exports, "factory", {
|
|
|
1776
2113
|
return nodes_exports;
|
|
1777
2114
|
}
|
|
1778
2115
|
});
|
|
2116
|
+
Object.defineProperty(exports, "file", {
|
|
2117
|
+
enumerable: true,
|
|
2118
|
+
get: function() {
|
|
2119
|
+
return file_exports;
|
|
2120
|
+
}
|
|
2121
|
+
});
|
|
1779
2122
|
exports.findCircularSchemas = findCircularSchemas;
|
|
1780
2123
|
exports.findSchema = findSchema;
|
|
1781
2124
|
exports.getSchemaLiteralValues = getSchemaLiteralValues;
|
|
2125
|
+
Object.defineProperty(exports, "graph", {
|
|
2126
|
+
enumerable: true,
|
|
2127
|
+
get: function() {
|
|
2128
|
+
return graph_exports;
|
|
2129
|
+
}
|
|
2130
|
+
});
|
|
2131
|
+
Object.defineProperty(exports, "http", {
|
|
2132
|
+
enumerable: true,
|
|
2133
|
+
get: function() {
|
|
2134
|
+
return http_exports;
|
|
2135
|
+
}
|
|
2136
|
+
});
|
|
1782
2137
|
exports.inferDiscriminatorPropertyName = inferDiscriminatorPropertyName;
|
|
1783
2138
|
exports.inlineFiles = inlineFiles;
|
|
1784
2139
|
exports.isBareRef = isBareRef;
|
|
1785
2140
|
exports.isHttpOperationNode = isHttpOperationNode;
|
|
2141
|
+
Object.defineProperty(exports, "macro", {
|
|
2142
|
+
enumerable: true,
|
|
2143
|
+
get: function() {
|
|
2144
|
+
return macro_exports;
|
|
2145
|
+
}
|
|
2146
|
+
});
|
|
2147
|
+
Object.defineProperty(exports, "mediaType", {
|
|
2148
|
+
enumerable: true,
|
|
2149
|
+
get: function() {
|
|
2150
|
+
return mediaType_exports;
|
|
2151
|
+
}
|
|
2152
|
+
});
|
|
1786
2153
|
exports.mergeRefWithSchema = mergeRefWithSchema;
|
|
1787
2154
|
exports.narrowSchema = narrowSchema;
|
|
2155
|
+
Object.defineProperty(exports, "node", {
|
|
2156
|
+
enumerable: true,
|
|
2157
|
+
get: function() {
|
|
2158
|
+
return node_exports;
|
|
2159
|
+
}
|
|
2160
|
+
});
|
|
1788
2161
|
exports.nodeKinds = nodeKinds;
|
|
1789
2162
|
exports.optionality = optionality;
|
|
2163
|
+
Object.defineProperty(exports, "ref", {
|
|
2164
|
+
enumerable: true,
|
|
2165
|
+
get: function() {
|
|
2166
|
+
return ref_exports;
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
1790
2169
|
exports.refName = refName;
|
|
1791
2170
|
exports.resolveRef = resolveRef;
|
|
1792
2171
|
exports.resolveRefName = resolveRefName;
|
|
1793
2172
|
exports.resolveSchemaProperties = resolveSchemaProperties;
|
|
2173
|
+
Object.defineProperty(exports, "schema", {
|
|
2174
|
+
enumerable: true,
|
|
2175
|
+
get: function() {
|
|
2176
|
+
return schema_exports;
|
|
2177
|
+
}
|
|
2178
|
+
});
|
|
1794
2179
|
exports.schemaTypes = schemaTypes;
|
|
2180
|
+
Object.defineProperty(exports, "server", {
|
|
2181
|
+
enumerable: true,
|
|
2182
|
+
get: function() {
|
|
2183
|
+
return server_exports;
|
|
2184
|
+
}
|
|
2185
|
+
});
|
|
1795
2186
|
exports.transform = transform;
|
|
1796
2187
|
|
|
1797
2188
|
//# sourceMappingURL=index.cjs.map
|