@kubb/ast 4.34.0 → 4.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +95 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +95 -14
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/{visitor-DRohZSfu.d.ts → visitor-CmsfJzro.d.ts} +117 -4
- package/package.json +1 -1
- package/src/constants.ts +5 -0
- package/src/factory.ts +13 -3
- package/src/guards.ts +1 -1
- package/src/index.ts +1 -0
- package/src/nodes/schema.ts +1 -1
- package/src/printer.ts +129 -0
- package/src/types.ts +2 -1
- package/src/visitor.ts +49 -12
package/dist/index.cjs
CHANGED
|
@@ -95,10 +95,12 @@ function createOperation(props) {
|
|
|
95
95
|
kind: "Operation"
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Creates a `SchemaNode`, narrowed to the variant of `props.type`.
|
|
100
|
-
*/
|
|
101
98
|
function createSchema(props) {
|
|
99
|
+
if (props["type"] === "object") return {
|
|
100
|
+
properties: [],
|
|
101
|
+
...props,
|
|
102
|
+
kind: "Schema"
|
|
103
|
+
};
|
|
102
104
|
return {
|
|
103
105
|
...props,
|
|
104
106
|
kind: "Schema"
|
|
@@ -169,6 +171,60 @@ const isParameterNode = isKind("Parameter");
|
|
|
169
171
|
*/
|
|
170
172
|
const isResponseNode = isKind("Response");
|
|
171
173
|
//#endregion
|
|
174
|
+
//#region src/printer.ts
|
|
175
|
+
/**
|
|
176
|
+
* Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern
|
|
177
|
+
* from `@kubb/core` — wraps a builder to make options optional and separates raw options
|
|
178
|
+
* from resolved options.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>
|
|
183
|
+
*
|
|
184
|
+
* export const zodPrinter = definePrinter<ZodPrinter>((options) => {
|
|
185
|
+
* const { strict = true } = options
|
|
186
|
+
* return {
|
|
187
|
+
* name: 'zod',
|
|
188
|
+
* options: { strict },
|
|
189
|
+
* nodes: {
|
|
190
|
+
* string(node) {
|
|
191
|
+
* return `z.string()`
|
|
192
|
+
* },
|
|
193
|
+
* object(node) {
|
|
194
|
+
* const props = node.properties
|
|
195
|
+
* ?.map(p => `${p.name}: ${this.print(p)}`)
|
|
196
|
+
* .join(', ') ?? ''
|
|
197
|
+
* return `z.object({ ${props} })`
|
|
198
|
+
* },
|
|
199
|
+
* },
|
|
200
|
+
* }
|
|
201
|
+
* })
|
|
202
|
+
*
|
|
203
|
+
* const printer = zodPrinter({ strict: false })
|
|
204
|
+
* printer.name // 'zod'
|
|
205
|
+
* printer.options // { strict: false }
|
|
206
|
+
* printer.print(node) // 'z.string()'
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
function definePrinter(build) {
|
|
210
|
+
return (options) => {
|
|
211
|
+
const { name, options: resolvedOptions, nodes } = build(options ?? {});
|
|
212
|
+
const context = {
|
|
213
|
+
options: resolvedOptions,
|
|
214
|
+
print: (node) => {
|
|
215
|
+
const handler = nodes[node.type];
|
|
216
|
+
return handler ? handler.call(context, node) : void 0;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
return {
|
|
220
|
+
name,
|
|
221
|
+
options: resolvedOptions,
|
|
222
|
+
print: context.print,
|
|
223
|
+
for: (nodes) => nodes.map(context.print)
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
//#endregion
|
|
172
228
|
//#region src/refs.ts
|
|
173
229
|
/**
|
|
174
230
|
* Indexes named schemas from `root.schemas` by name. Unnamed schemas are skipped.
|
|
@@ -192,6 +248,27 @@ function refMapToObject(refMap) {
|
|
|
192
248
|
}
|
|
193
249
|
//#endregion
|
|
194
250
|
//#region src/visitor.ts
|
|
251
|
+
function createLimit(concurrency) {
|
|
252
|
+
let active = 0;
|
|
253
|
+
const queue = [];
|
|
254
|
+
function next() {
|
|
255
|
+
if (active < concurrency && queue.length > 0) {
|
|
256
|
+
active++;
|
|
257
|
+
queue.shift()();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return function limit(fn) {
|
|
261
|
+
return new Promise((resolve, reject) => {
|
|
262
|
+
queue.push(() => {
|
|
263
|
+
Promise.resolve(fn()).then(resolve, reject).finally(() => {
|
|
264
|
+
active--;
|
|
265
|
+
next();
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
next();
|
|
269
|
+
});
|
|
270
|
+
};
|
|
271
|
+
}
|
|
195
272
|
/**
|
|
196
273
|
* Traversable children of `node`, respecting `recurse` for schema nodes.
|
|
197
274
|
*/
|
|
@@ -206,7 +283,7 @@ function getChildren(node, recurse) {
|
|
|
206
283
|
case "Schema": {
|
|
207
284
|
const children = [];
|
|
208
285
|
if (!recurse) return [];
|
|
209
|
-
if ("properties" in node && node.properties) children.push(...node.properties);
|
|
286
|
+
if ("properties" in node && node.properties.length > 0) children.push(...node.properties);
|
|
210
287
|
if ("items" in node && node.items) children.push(...node.items);
|
|
211
288
|
if ("members" in node && node.members) children.push(...node.members);
|
|
212
289
|
return children;
|
|
@@ -218,30 +295,34 @@ function getChildren(node, recurse) {
|
|
|
218
295
|
}
|
|
219
296
|
/**
|
|
220
297
|
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
298
|
+
* Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
|
|
221
299
|
*/
|
|
222
300
|
async function walk(node, visitor, options = {}) {
|
|
223
|
-
|
|
301
|
+
return _walk(node, visitor, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30));
|
|
302
|
+
}
|
|
303
|
+
async function _walk(node, visitor, recurse, limit) {
|
|
224
304
|
switch (node.kind) {
|
|
225
305
|
case "Root":
|
|
226
|
-
await visitor.root?.(node);
|
|
306
|
+
await limit(() => visitor.root?.(node));
|
|
227
307
|
break;
|
|
228
308
|
case "Operation":
|
|
229
|
-
await visitor.operation?.(node);
|
|
309
|
+
await limit(() => visitor.operation?.(node));
|
|
230
310
|
break;
|
|
231
311
|
case "Schema":
|
|
232
|
-
await visitor.schema?.(node);
|
|
312
|
+
await limit(() => visitor.schema?.(node));
|
|
233
313
|
break;
|
|
234
314
|
case "Property":
|
|
235
|
-
await visitor.property?.(node);
|
|
315
|
+
await limit(() => visitor.property?.(node));
|
|
236
316
|
break;
|
|
237
317
|
case "Parameter":
|
|
238
|
-
await visitor.parameter?.(node);
|
|
318
|
+
await limit(() => visitor.parameter?.(node));
|
|
239
319
|
break;
|
|
240
320
|
case "Response":
|
|
241
|
-
await visitor.response?.(node);
|
|
321
|
+
await limit(() => visitor.response?.(node));
|
|
242
322
|
break;
|
|
243
323
|
}
|
|
244
|
-
|
|
324
|
+
const children = getChildren(node, recurse);
|
|
325
|
+
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)));
|
|
245
326
|
}
|
|
246
327
|
function transform(node, visitor, options = {}) {
|
|
247
328
|
const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep;
|
|
@@ -273,7 +354,7 @@ function transform(node, visitor, options = {}) {
|
|
|
273
354
|
if (replaced) schema = replaced;
|
|
274
355
|
return {
|
|
275
356
|
...schema,
|
|
276
|
-
..."properties" in schema && recurse ? { properties: schema.properties
|
|
357
|
+
..."properties" in schema && recurse ? { properties: schema.properties.map((p) => transform(p, visitor, options)) } : {},
|
|
277
358
|
..."items" in schema && recurse ? { items: schema.items?.map((i) => transform(i, visitor, options)) } : {},
|
|
278
359
|
..."members" in schema && recurse ? { members: schema.members?.map((m) => transform(m, visitor, options)) } : {}
|
|
279
360
|
};
|
|
@@ -347,6 +428,7 @@ exports.createProperty = createProperty;
|
|
|
347
428
|
exports.createResponse = createResponse;
|
|
348
429
|
exports.createRoot = createRoot;
|
|
349
430
|
exports.createSchema = createSchema;
|
|
431
|
+
exports.definePrinter = definePrinter;
|
|
350
432
|
exports.httpMethods = httpMethods;
|
|
351
433
|
exports.isOperationNode = isOperationNode;
|
|
352
434
|
exports.isParameterNode = isParameterNode;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/constants.ts","../src/factory.ts","../src/guards.ts","../src/refs.ts","../src/visitor.ts"],"sourcesContent":["import type { NodeKind } from './nodes/base.ts'\nimport type { MediaType } from './nodes/http.ts'\nimport type { HttpMethod } from './nodes/operation.ts'\nimport type { ParameterLocation } from './nodes/parameter.ts'\nimport type { SchemaType } from './nodes/schema.ts'\n\n/**\n * Depth for schema traversal in visitor functions.\n */\nexport type VisitorDepth = 'shallow' | 'deep'\n\nexport const visitorDepths = {\n shallow: 'shallow',\n deep: 'deep',\n} as const satisfies Record<VisitorDepth, VisitorDepth>\n\nexport const nodeKinds = {\n root: 'Root',\n operation: 'Operation',\n schema: 'Schema',\n property: 'Property',\n parameter: 'Parameter',\n response: 'Response',\n} as const satisfies Record<Lowercase<NodeKind>, NodeKind>\n\nexport const schemaTypes = {\n string: 'string',\n /**\n * Floating-point number (`float`, `double`).\n */\n number: 'number',\n /**\n * Whole number (`int32`). Use `bigint` for `int64`.\n */\n integer: 'integer',\n /**\n * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.\n */\n bigint: 'bigint',\n boolean: 'boolean',\n null: 'null',\n any: 'any',\n unknown: 'unknown',\n void: 'void',\n object: 'object',\n array: 'array',\n tuple: 'tuple',\n union: 'union',\n intersection: 'intersection',\n enum: 'enum',\n ref: 'ref',\n date: 'date',\n datetime: 'datetime',\n time: 'time',\n uuid: 'uuid',\n email: 'email',\n url: 'url',\n blob: 'blob',\n} as const satisfies Record<SchemaType, SchemaType>\n\nexport const httpMethods = {\n get: 'GET',\n post: 'POST',\n put: 'PUT',\n patch: 'PATCH',\n delete: 'DELETE',\n head: 'HEAD',\n options: 'OPTIONS',\n trace: 'TRACE',\n} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>\n\nexport const parameterLocations = {\n path: 'path',\n query: 'query',\n header: 'header',\n cookie: 'cookie',\n} as const satisfies Record<ParameterLocation, ParameterLocation>\n\n/**\n * Fallback status code string for API spec responses.\n */\nexport const DEFAULT_STATUS_CODE = 'default' as const\n\nexport const mediaTypes = {\n applicationJson: 'application/json',\n applicationXml: 'application/xml',\n applicationFormUrlEncoded: 'application/x-www-form-urlencoded',\n applicationOctetStream: 'application/octet-stream',\n applicationPdf: 'application/pdf',\n applicationZip: 'application/zip',\n applicationGraphql: 'application/graphql',\n multipartFormData: 'multipart/form-data',\n textPlain: 'text/plain',\n textHtml: 'text/html',\n textCsv: 'text/csv',\n textXml: 'text/xml',\n imagePng: 'image/png',\n imageJpeg: 'image/jpeg',\n imageGif: 'image/gif',\n imageWebp: 'image/webp',\n imageSvgXml: 'image/svg+xml',\n audioMpeg: 'audio/mpeg',\n videoMp4: 'video/mp4',\n} as const satisfies Record<string, MediaType>\n","import type { OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'\n\n/**\n * Distributive variant of `Omit` that preserves union members.\n */\nexport type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never\n\n/**\n * Creates a `RootNode`.\n */\nexport function createRoot(overrides: Partial<Omit<RootNode, 'kind'>> = {}): RootNode {\n return {\n schemas: [],\n operations: [],\n ...overrides,\n kind: 'Root',\n }\n}\n\n/**\n * Creates an `OperationNode`.\n */\nexport function createOperation(\n props: Pick<OperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<OperationNode, 'kind' | 'operationId' | 'method' | 'path'>>,\n): OperationNode {\n return {\n tags: [],\n parameters: [],\n responses: [],\n ...props,\n kind: 'Operation',\n }\n}\n\n/**\n * Creates a `SchemaNode`, narrowed to the variant of `props.type`.\n */\nexport function createSchema<T extends DistributiveOmit<SchemaNode, 'kind'>>(props: T): T & { kind: 'Schema' } {\n return { ...props, kind: 'Schema' } as T & { kind: 'Schema' }\n}\n\n/**\n * Creates a `PropertyNode`. `required` defaults to `false`.\n */\nexport function createProperty(props: Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>): PropertyNode {\n return {\n required: false,\n ...props,\n kind: 'Property',\n }\n}\n\n/**\n * Creates a `ParameterNode`. `required` defaults to `false`.\n */\nexport function createParameter(\n props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,\n): ParameterNode {\n return {\n required: false,\n ...props,\n kind: 'Parameter',\n }\n}\n\n/**\n * Creates a `ResponseNode`.\n */\nexport function createResponse(props: Pick<ResponseNode, 'statusCode'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode'>>): ResponseNode {\n return {\n ...props,\n kind: 'Response',\n }\n}\n","import type { Node, NodeKind, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode, SchemaNodeByType } from './nodes/index.ts'\n\n/**\n * Narrows a `SchemaNode` to the specific variant matching `type`.\n */\nexport function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | undefined, type: T): SchemaNodeByType[T] | undefined {\n return node?.type === type ? (node as SchemaNodeByType[T]) : undefined\n}\n\nfunction isKind<T extends Node>(kind: NodeKind) {\n return (node: Node): node is T => node.kind === kind\n}\n\n/**\n * Type guard for `RootNode`.\n */\nexport const isRootNode = isKind<RootNode>('Root')\n\n/**\n * Type guard for `OperationNode`.\n */\nexport const isOperationNode = isKind<OperationNode>('Operation')\n\n/**\n * Type guard for `SchemaNode`.\n */\nexport const isSchemaNode = isKind<SchemaNode>('Schema')\n\n/**\n * Type guard for `PropertyNode`.\n */\nexport const isPropertyNode = isKind<PropertyNode>('Property')\n\n/**\n * Type guard for `ParameterNode`.\n */\nexport const isParameterNode = isKind<ParameterNode>('Parameter')\n\n/**\n * Type guard for `ResponseNode`.\n */\nexport const isResponseNode = isKind<ResponseNode>('Response')\n","import type { RootNode } from './nodes/root.ts'\nimport type { SchemaNode } from './nodes/schema.ts'\n\n/**\n * Schema name to `SchemaNode` mapping.\n */\nexport type RefMap = Map<string, SchemaNode>\n\n/**\n * Indexes named schemas from `root.schemas` by name. Unnamed schemas are skipped.\n */\nexport function buildRefMap(root: RootNode): RefMap {\n const map: RefMap = new Map()\n\n for (const schema of root.schemas) {\n if (schema.name) {\n map.set(schema.name, schema)\n }\n }\n return map\n}\n\n/**\n * Looks up a schema by name. Prefer over `RefMap.get()` to keep the resolution strategy swappable.\n */\nexport function resolveRef(refMap: RefMap, ref: string): SchemaNode | undefined {\n return refMap.get(ref)\n}\n\n/**\n * Converts a `RefMap` to a plain object.\n */\nexport function refMapToObject(refMap: RefMap): Record<string, SchemaNode> {\n return Object.fromEntries(refMap)\n}\n","import type { VisitorDepth } from './constants.ts'\nimport { visitorDepths } from './constants.ts'\nimport type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'\n\n/**\n * Shared options for `walk`, `transform`, and `collect`.\n */\nexport type VisitorOptions = {\n depth?: VisitorDepth\n}\n\n/**\n * Synchronous visitor for `transform` and `walk`.\n */\nexport type Visitor = {\n root?(node: RootNode): void | RootNode\n operation?(node: OperationNode): void | OperationNode\n schema?(node: SchemaNode): void | SchemaNode\n property?(node: PropertyNode): void | PropertyNode\n parameter?(node: ParameterNode): void | ParameterNode\n response?(node: ResponseNode): void | ResponseNode\n}\n\ntype MaybePromise<T> = T | Promise<T>\n\n/**\n * Async visitor for `walk`. Synchronous `Visitor` objects are compatible.\n */\nexport type AsyncVisitor = {\n root?(node: RootNode): MaybePromise<void | RootNode>\n operation?(node: OperationNode): MaybePromise<void | OperationNode>\n schema?(node: SchemaNode): MaybePromise<void | SchemaNode>\n property?(node: PropertyNode): MaybePromise<void | PropertyNode>\n parameter?(node: ParameterNode): MaybePromise<void | ParameterNode>\n response?(node: ResponseNode): MaybePromise<void | ResponseNode>\n}\n\n/**\n * Visitor for `collect`.\n */\nexport type CollectVisitor<T> = {\n root?(node: RootNode): T | undefined\n operation?(node: OperationNode): T | undefined\n schema?(node: SchemaNode): T | undefined\n property?(node: PropertyNode): T | undefined\n parameter?(node: ParameterNode): T | undefined\n response?(node: ResponseNode): T | undefined\n}\n\n/**\n * Traversable children of `node`, respecting `recurse` for schema nodes.\n */\nfunction getChildren(node: Node, recurse: boolean): Array<Node> {\n switch (node.kind) {\n case 'Root':\n return [...node.schemas, ...node.operations]\n case 'Operation':\n return [...node.parameters, ...(node.requestBody ? [node.requestBody] : []), ...node.responses]\n case 'Schema': {\n const children: Array<Node> = []\n\n if (!recurse) return []\n\n if ('properties' in node && node.properties) children.push(...node.properties)\n if ('items' in node && node.items) children.push(...node.items)\n if ('members' in node && node.members) children.push(...node.members)\n\n return children\n }\n case 'Property':\n return [node.schema]\n case 'Parameter':\n return [node.schema]\n case 'Response':\n return node.schema ? [node.schema] : []\n }\n}\n\n/**\n * Depth-first traversal for side effects. Visitor return values are ignored.\n */\nexport async function walk(node: Node, visitor: AsyncVisitor, options: VisitorOptions = {}): Promise<void> {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n\n switch (node.kind) {\n case 'Root':\n await visitor.root?.(node)\n break\n case 'Operation':\n await visitor.operation?.(node)\n break\n case 'Schema':\n await visitor.schema?.(node)\n break\n case 'Property':\n await visitor.property?.(node)\n break\n case 'Parameter':\n await visitor.parameter?.(node)\n break\n case 'Response':\n await visitor.response?.(node)\n break\n }\n\n for (const child of getChildren(node, recurse)) {\n await walk(child, visitor, options)\n }\n}\n\n/**\n * Depth-first immutable transformation. Visitor return values replace nodes; `undefined` keeps the original.\n */\nexport function transform(node: RootNode, visitor: Visitor, options?: VisitorOptions): RootNode\nexport function transform(node: OperationNode, visitor: Visitor, options?: VisitorOptions): OperationNode\nexport function transform(node: SchemaNode, visitor: Visitor, options?: VisitorOptions): SchemaNode\nexport function transform(node: PropertyNode, visitor: Visitor, options?: VisitorOptions): PropertyNode\nexport function transform(node: ParameterNode, visitor: Visitor, options?: VisitorOptions): ParameterNode\nexport function transform(node: ResponseNode, visitor: Visitor, options?: VisitorOptions): ResponseNode\nexport function transform(node: Node, visitor: Visitor, options?: VisitorOptions): Node\nexport function transform(node: Node, visitor: Visitor, options: VisitorOptions = {}): Node {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n\n switch (node.kind) {\n case 'Root': {\n let root = node\n const replaced = visitor.root?.(root)\n if (replaced) root = replaced\n\n return {\n ...root,\n schemas: root.schemas.map((s) => transform(s, visitor, options)),\n operations: root.operations.map((op) => transform(op, visitor, options)),\n }\n }\n case 'Operation': {\n let op = node\n const replaced = visitor.operation?.(op)\n if (replaced) op = replaced\n\n return {\n ...op,\n parameters: op.parameters.map((p) => transform(p, visitor, options)),\n requestBody: op.requestBody ? transform(op.requestBody, visitor, options) : undefined,\n responses: op.responses.map((r) => transform(r, visitor, options)),\n }\n }\n case 'Schema': {\n let schema = node\n const replaced = visitor.schema?.(schema)\n if (replaced) schema = replaced\n\n return {\n ...schema,\n ...('properties' in schema && recurse ? { properties: schema.properties?.map((p) => transform(p, visitor, options)) } : {}),\n ...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, visitor, options)) } : {}),\n ...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, visitor, options)) } : {}),\n }\n }\n case 'Property': {\n let prop = node\n const replaced = visitor.property?.(prop)\n if (replaced) prop = replaced\n\n return {\n ...prop,\n schema: transform(prop.schema, visitor, options),\n }\n }\n case 'Parameter': {\n let param = node\n const replaced = visitor.parameter?.(param)\n if (replaced) param = replaced\n\n return {\n ...param,\n schema: transform(param.schema, visitor, options),\n }\n }\n case 'Response': {\n let response = node\n const replaced = visitor.response?.(response)\n if (replaced) response = replaced\n\n return {\n ...response,\n schema: response.schema ? transform(response.schema, visitor, options) : undefined,\n }\n }\n }\n}\n\n/**\n * Depth-first synchronous reduction. Collects non-`undefined` visitor return values into an array.\n */\nexport function collect<T>(node: Node, visitor: CollectVisitor<T>, options: VisitorOptions = {}): Array<T> {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n const results: Array<T> = []\n\n let v: T | undefined\n switch (node.kind) {\n case 'Root':\n v = visitor.root?.(node)\n break\n case 'Operation':\n v = visitor.operation?.(node)\n break\n case 'Schema':\n v = visitor.schema?.(node)\n break\n case 'Property':\n v = visitor.property?.(node)\n break\n case 'Parameter':\n v = visitor.parameter?.(node)\n break\n case 'Response':\n v = visitor.response?.(node)\n break\n }\n if (v !== undefined) results.push(v)\n\n for (const child of getChildren(node, recurse)) {\n for (const item of collect(child, visitor, options)) {\n results.push(item)\n }\n }\n\n return results\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/constants.ts","../src/factory.ts","../src/guards.ts","../src/printer.ts","../src/refs.ts","../src/visitor.ts"],"sourcesContent":["import type { NodeKind } from './nodes/base.ts'\nimport type { MediaType } from './nodes/http.ts'\nimport type { HttpMethod } from './nodes/operation.ts'\nimport type { ParameterLocation } from './nodes/parameter.ts'\nimport type { SchemaType } from './nodes/schema.ts'\n\n/**\n * Depth for schema traversal in visitor functions.\n */\nexport type VisitorDepth = 'shallow' | 'deep'\n\nexport const visitorDepths = {\n shallow: 'shallow',\n deep: 'deep',\n} as const satisfies Record<VisitorDepth, VisitorDepth>\n\nexport const nodeKinds = {\n root: 'Root',\n operation: 'Operation',\n schema: 'Schema',\n property: 'Property',\n parameter: 'Parameter',\n response: 'Response',\n} as const satisfies Record<Lowercase<NodeKind>, NodeKind>\n\nexport const schemaTypes = {\n string: 'string',\n /**\n * Floating-point number (`float`, `double`).\n */\n number: 'number',\n /**\n * Whole number (`int32`). Use `bigint` for `int64`.\n */\n integer: 'integer',\n /**\n * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.\n */\n bigint: 'bigint',\n boolean: 'boolean',\n null: 'null',\n any: 'any',\n unknown: 'unknown',\n void: 'void',\n object: 'object',\n array: 'array',\n tuple: 'tuple',\n union: 'union',\n intersection: 'intersection',\n enum: 'enum',\n ref: 'ref',\n date: 'date',\n datetime: 'datetime',\n time: 'time',\n uuid: 'uuid',\n email: 'email',\n url: 'url',\n blob: 'blob',\n} as const satisfies Record<SchemaType, SchemaType>\n\nexport const httpMethods = {\n get: 'GET',\n post: 'POST',\n put: 'PUT',\n patch: 'PATCH',\n delete: 'DELETE',\n head: 'HEAD',\n options: 'OPTIONS',\n trace: 'TRACE',\n} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>\n\nexport const parameterLocations = {\n path: 'path',\n query: 'query',\n header: 'header',\n cookie: 'cookie',\n} as const satisfies Record<ParameterLocation, ParameterLocation>\n\n/**\n * Default max concurrent visitor calls in `walk`.\n */\nexport const WALK_CONCURRENCY = 30\n\n/**\n * Fallback status code string for API spec responses.\n */\nexport const DEFAULT_STATUS_CODE = 'default' as const\n\nexport const mediaTypes = {\n applicationJson: 'application/json',\n applicationXml: 'application/xml',\n applicationFormUrlEncoded: 'application/x-www-form-urlencoded',\n applicationOctetStream: 'application/octet-stream',\n applicationPdf: 'application/pdf',\n applicationZip: 'application/zip',\n applicationGraphql: 'application/graphql',\n multipartFormData: 'multipart/form-data',\n textPlain: 'text/plain',\n textHtml: 'text/html',\n textCsv: 'text/csv',\n textXml: 'text/xml',\n imagePng: 'image/png',\n imageJpeg: 'image/jpeg',\n imageGif: 'image/gif',\n imageWebp: 'image/webp',\n imageSvgXml: 'image/svg+xml',\n audioMpeg: 'audio/mpeg',\n videoMp4: 'video/mp4',\n} as const satisfies Record<string, MediaType>\n","import type { ObjectSchemaNode, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'\n\n/**\n * Distributive variant of `Omit` that preserves union members.\n */\nexport type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never\n\n/**\n * Creates a `RootNode`.\n */\nexport function createRoot(overrides: Partial<Omit<RootNode, 'kind'>> = {}): RootNode {\n return {\n schemas: [],\n operations: [],\n ...overrides,\n kind: 'Root',\n }\n}\n\n/**\n * Creates an `OperationNode`.\n */\nexport function createOperation(\n props: Pick<OperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<OperationNode, 'kind' | 'operationId' | 'method' | 'path'>>,\n): OperationNode {\n return {\n tags: [],\n parameters: [],\n responses: [],\n ...props,\n kind: 'Operation',\n }\n}\n\n/**\n * Creates a `SchemaNode`, narrowed to the variant of `props.type`.\n * For object schemas, `properties` defaults to `[]` when not provided.\n */\nexport function createSchema<T extends Omit<ObjectSchemaNode, 'kind' | 'properties'> & { properties?: Array<PropertyNode> }>(\n props: T,\n): Omit<T, 'properties'> & { properties: Array<PropertyNode>; kind: 'Schema' }\nexport function createSchema<T extends DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>>(props: T): T & { kind: 'Schema' }\nexport function createSchema(props: DistributiveOmit<SchemaNode, 'kind'>): SchemaNode\nexport function createSchema(props: Record<string, unknown>): Record<string, unknown> {\n if (props['type'] === 'object') {\n return { properties: [], ...props, kind: 'Schema' }\n }\n\n return { ...props, kind: 'Schema' }\n}\n\n/**\n * Creates a `PropertyNode`. `required` defaults to `false`.\n */\nexport function createProperty(props: Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>): PropertyNode {\n return {\n required: false,\n ...props,\n kind: 'Property',\n }\n}\n\n/**\n * Creates a `ParameterNode`. `required` defaults to `false`.\n */\nexport function createParameter(\n props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,\n): ParameterNode {\n return {\n required: false,\n ...props,\n kind: 'Parameter',\n }\n}\n\n/**\n * Creates a `ResponseNode`.\n */\nexport function createResponse(props: Pick<ResponseNode, 'statusCode'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode'>>): ResponseNode {\n return {\n ...props,\n kind: 'Response',\n }\n}\n","import type { Node, NodeKind, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode, SchemaNodeByType } from './nodes/index.ts'\n\n/**\n * Narrows a `SchemaNode` to the specific variant matching `type`.\n */\nexport function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | undefined, type: T): SchemaNodeByType[T] | undefined {\n return node?.type === type ? (node as SchemaNodeByType[T]) : undefined\n}\n\nfunction isKind<T extends Node>(kind: NodeKind) {\n return (node: unknown): node is T => (node as Node).kind === kind\n}\n\n/**\n * Type guard for `RootNode`.\n */\nexport const isRootNode = isKind<RootNode>('Root')\n\n/**\n * Type guard for `OperationNode`.\n */\nexport const isOperationNode = isKind<OperationNode>('Operation')\n\n/**\n * Type guard for `SchemaNode`.\n */\nexport const isSchemaNode = isKind<SchemaNode>('Schema')\n\n/**\n * Type guard for `PropertyNode`.\n */\nexport const isPropertyNode = isKind<PropertyNode>('Property')\n\n/**\n * Type guard for `ParameterNode`.\n */\nexport const isParameterNode = isKind<ParameterNode>('Parameter')\n\n/**\n * Type guard for `ResponseNode`.\n */\nexport const isResponseNode = isKind<ResponseNode>('Response')\n","import type { SchemaNode, SchemaNodeByType, SchemaType } from './nodes/index.ts'\n\n/**\n * Handler context for `definePrinter` — mirrors `PluginContext` from `@kubb/core`.\n * Available as `this` inside each node handler.\n */\nexport type PrinterHandlerContext<TOutput, TOptions extends object> = {\n /**\n * Recursively print a nested `SchemaNode`.\n */\n print: (node: SchemaNode) => TOutput | null | undefined\n /**\n * Options for this printer instance.\n */\n options: TOptions\n}\n\n/**\n * Handler for a specific `SchemaNode` variant identified by `SchemaType` key `T`.\n * Use a regular function (not an arrow function) so that `this` is available.\n */\nexport type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (\n this: PrinterHandlerContext<TOutput, TOptions>,\n node: SchemaNodeByType[T],\n) => TOutput | null | undefined\n\n/**\n * Shape of the type parameter passed to `definePrinter`.\n * Mirrors `AdapterFactoryOptions` / `PluginFactoryOptions` from `@kubb/core`.\n *\n * - `TName` — unique string identifier (e.g. `'zod'`, `'ts'`)\n * - `TOptions` — options passed to and stored on the printer\n * - `TOutput` — the type emitted by `print` (typically `string`)\n */\nexport type PrinterFactoryOptions<TName extends string = string, TOptions extends object = object, TOutput = unknown> = {\n name: TName\n options: TOptions\n output: TOutput\n}\n\n/**\n * The object returned by calling a `definePrinter` instance.\n * Mirrors the shape of `Adapter` from `@kubb/core`.\n */\nexport type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {\n /**\n * Unique identifier supplied at creation time.\n */\n name: T['name']\n /**\n * Options for this printer instance.\n */\n options: T['options']\n /**\n * Emits `TOutput` from a `SchemaNode`. Returns `null | undefined` when no handler matches.\n */\n print: (node: SchemaNode) => T['output'] | null | undefined\n /**\n * Maps `print` over an array of `SchemaNode`s.\n */\n for: (nodes: Array<SchemaNode>) => Array<T['output'] | null | undefined>\n}\n\ntype PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) => {\n name: T['name']\n /**\n * Options to store on the printer.\n */\n options: T['options']\n nodes: Partial<{\n [K in SchemaType]: PrinterHandler<T['output'], T['options'], K>\n }>\n}\n\n/**\n * Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern\n * from `@kubb/core` — wraps a builder to make options optional and separates raw options\n * from resolved options.\n *\n * @example\n * ```ts\n * type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>\n *\n * export const zodPrinter = definePrinter<ZodPrinter>((options) => {\n * const { strict = true } = options\n * return {\n * name: 'zod',\n * options: { strict },\n * nodes: {\n * string(node) {\n * return `z.string()`\n * },\n * object(node) {\n * const props = node.properties\n * ?.map(p => `${p.name}: ${this.print(p)}`)\n * .join(', ') ?? ''\n * return `z.object({ ${props} })`\n * },\n * },\n * }\n * })\n *\n * const printer = zodPrinter({ strict: false })\n * printer.name // 'zod'\n * printer.options // { strict: false }\n * printer.print(node) // 'z.string()'\n * ```\n */\nexport function definePrinter<T extends PrinterFactoryOptions = PrinterFactoryOptions>(build: PrinterBuilder<T>): (options?: T['options']) => Printer<T> {\n return (options) => {\n const { name, options: resolvedOptions, nodes } = build(options ?? ({} as T['options']))\n\n const context: PrinterHandlerContext<T['output'], T['options']> = {\n options: resolvedOptions,\n print: (node: SchemaNode) => {\n const type = node.type as SchemaType\n const handler = nodes[type]\n return handler ? (handler as PrinterHandler<T['output'], T['options']>).call(context, node as SchemaNodeByType[SchemaType]) : undefined\n },\n }\n\n return {\n name,\n options: resolvedOptions,\n print: context.print,\n for: (nodes) => nodes.map(context.print),\n }\n }\n}\n","import type { RootNode } from './nodes/root.ts'\nimport type { SchemaNode } from './nodes/schema.ts'\n\n/**\n * Schema name to `SchemaNode` mapping.\n */\nexport type RefMap = Map<string, SchemaNode>\n\n/**\n * Indexes named schemas from `root.schemas` by name. Unnamed schemas are skipped.\n */\nexport function buildRefMap(root: RootNode): RefMap {\n const map: RefMap = new Map()\n\n for (const schema of root.schemas) {\n if (schema.name) {\n map.set(schema.name, schema)\n }\n }\n return map\n}\n\n/**\n * Looks up a schema by name. Prefer over `RefMap.get()` to keep the resolution strategy swappable.\n */\nexport function resolveRef(refMap: RefMap, ref: string): SchemaNode | undefined {\n return refMap.get(ref)\n}\n\n/**\n * Converts a `RefMap` to a plain object.\n */\nexport function refMapToObject(refMap: RefMap): Record<string, SchemaNode> {\n return Object.fromEntries(refMap)\n}\n","import type { VisitorDepth } from './constants.ts'\nimport { visitorDepths, WALK_CONCURRENCY } from './constants.ts'\nimport type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'\n\nfunction createLimit(concurrency: number) {\n let active = 0\n const queue: Array<() => void> = []\n\n function next() {\n if (active < concurrency && queue.length > 0) {\n active++\n queue.shift()!()\n }\n }\n\n return function limit<T>(fn: () => Promise<T> | T): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n queue.push(() => {\n Promise.resolve(fn())\n .then(resolve, reject)\n .finally(() => {\n active--\n next()\n })\n })\n next()\n })\n }\n}\n\ntype LimitFn = ReturnType<typeof createLimit>\n\n/**\n * Shared options for `walk`, `transform`, and `collect`.\n */\nexport type VisitorOptions = {\n depth?: VisitorDepth\n /**\n * Maximum number of sibling nodes visited concurrently inside `walk`.\n * @default 30\n */\n concurrency?: number\n}\n\n/**\n * Synchronous visitor for `transform` and `walk`.\n */\nexport type Visitor = {\n root?(node: RootNode): void | RootNode\n operation?(node: OperationNode): void | OperationNode\n schema?(node: SchemaNode): void | SchemaNode\n property?(node: PropertyNode): void | PropertyNode\n parameter?(node: ParameterNode): void | ParameterNode\n response?(node: ResponseNode): void | ResponseNode\n}\n\ntype MaybePromise<T> = T | Promise<T>\n\n/**\n * Async visitor for `walk`. Synchronous `Visitor` objects are compatible.\n */\nexport type AsyncVisitor = {\n root?(node: RootNode): MaybePromise<void | RootNode>\n operation?(node: OperationNode): MaybePromise<void | OperationNode>\n schema?(node: SchemaNode): MaybePromise<void | SchemaNode>\n property?(node: PropertyNode): MaybePromise<void | PropertyNode>\n parameter?(node: ParameterNode): MaybePromise<void | ParameterNode>\n response?(node: ResponseNode): MaybePromise<void | ResponseNode>\n}\n\n/**\n * Visitor for `collect`.\n */\nexport type CollectVisitor<T> = {\n root?(node: RootNode): T | undefined\n operation?(node: OperationNode): T | undefined\n schema?(node: SchemaNode): T | undefined\n property?(node: PropertyNode): T | undefined\n parameter?(node: ParameterNode): T | undefined\n response?(node: ResponseNode): T | undefined\n}\n\n/**\n * Traversable children of `node`, respecting `recurse` for schema nodes.\n */\nfunction getChildren(node: Node, recurse: boolean): Array<Node> {\n switch (node.kind) {\n case 'Root':\n return [...node.schemas, ...node.operations]\n case 'Operation':\n return [...node.parameters, ...(node.requestBody ? [node.requestBody] : []), ...node.responses]\n case 'Schema': {\n const children: Array<Node> = []\n\n if (!recurse) return []\n\n if ('properties' in node && node.properties.length > 0) children.push(...node.properties)\n if ('items' in node && node.items) children.push(...node.items)\n if ('members' in node && node.members) children.push(...node.members)\n\n return children\n }\n case 'Property':\n return [node.schema]\n case 'Parameter':\n return [node.schema]\n case 'Response':\n return node.schema ? [node.schema] : []\n }\n}\n\n/**\n * Depth-first traversal for side effects. Visitor return values are ignored.\n * Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).\n */\nexport async function walk(node: Node, visitor: AsyncVisitor, options: VisitorOptions = {}): Promise<void> {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n const limit = createLimit(options.concurrency ?? WALK_CONCURRENCY)\n return _walk(node, visitor, recurse, limit)\n}\n\nasync function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit: LimitFn): Promise<void> {\n switch (node.kind) {\n case 'Root':\n await limit(() => visitor.root?.(node))\n break\n case 'Operation':\n await limit(() => visitor.operation?.(node))\n break\n case 'Schema':\n await limit(() => visitor.schema?.(node))\n break\n case 'Property':\n await limit(() => visitor.property?.(node))\n break\n case 'Parameter':\n await limit(() => visitor.parameter?.(node))\n break\n case 'Response':\n await limit(() => visitor.response?.(node))\n break\n }\n\n const children = getChildren(node, recurse)\n await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)))\n}\n\n/**\n * Depth-first immutable transformation. Visitor return values replace nodes; `undefined` keeps the original.\n */\nexport function transform(node: RootNode, visitor: Visitor, options?: VisitorOptions): RootNode\nexport function transform(node: OperationNode, visitor: Visitor, options?: VisitorOptions): OperationNode\nexport function transform(node: SchemaNode, visitor: Visitor, options?: VisitorOptions): SchemaNode\nexport function transform(node: PropertyNode, visitor: Visitor, options?: VisitorOptions): PropertyNode\nexport function transform(node: ParameterNode, visitor: Visitor, options?: VisitorOptions): ParameterNode\nexport function transform(node: ResponseNode, visitor: Visitor, options?: VisitorOptions): ResponseNode\nexport function transform(node: Node, visitor: Visitor, options?: VisitorOptions): Node\nexport function transform(node: Node, visitor: Visitor, options: VisitorOptions = {}): Node {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n\n switch (node.kind) {\n case 'Root': {\n let root = node\n const replaced = visitor.root?.(root)\n if (replaced) root = replaced\n\n return {\n ...root,\n schemas: root.schemas.map((s) => transform(s, visitor, options)),\n operations: root.operations.map((op) => transform(op, visitor, options)),\n }\n }\n case 'Operation': {\n let op = node\n const replaced = visitor.operation?.(op)\n if (replaced) op = replaced\n\n return {\n ...op,\n parameters: op.parameters.map((p) => transform(p, visitor, options)),\n requestBody: op.requestBody ? transform(op.requestBody, visitor, options) : undefined,\n responses: op.responses.map((r) => transform(r, visitor, options)),\n }\n }\n case 'Schema': {\n let schema = node\n const replaced = visitor.schema?.(schema)\n if (replaced) schema = replaced\n\n return {\n ...schema,\n ...('properties' in schema && recurse ? { properties: schema.properties.map((p) => transform(p, visitor, options)) } : {}),\n ...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, visitor, options)) } : {}),\n ...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, visitor, options)) } : {}),\n }\n }\n case 'Property': {\n let prop = node\n const replaced = visitor.property?.(prop)\n if (replaced) prop = replaced\n\n return {\n ...prop,\n schema: transform(prop.schema, visitor, options),\n }\n }\n case 'Parameter': {\n let param = node\n const replaced = visitor.parameter?.(param)\n if (replaced) param = replaced\n\n return {\n ...param,\n schema: transform(param.schema, visitor, options),\n }\n }\n case 'Response': {\n let response = node\n const replaced = visitor.response?.(response)\n if (replaced) response = replaced\n\n return {\n ...response,\n schema: response.schema ? transform(response.schema, visitor, options) : undefined,\n }\n }\n }\n}\n\n/**\n * Depth-first synchronous reduction. Collects non-`undefined` visitor return values into an array.\n */\nexport function collect<T>(node: Node, visitor: CollectVisitor<T>, options: VisitorOptions = {}): Array<T> {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n const results: Array<T> = []\n\n let v: T | undefined\n switch (node.kind) {\n case 'Root':\n v = visitor.root?.(node)\n break\n case 'Operation':\n v = visitor.operation?.(node)\n break\n case 'Schema':\n v = visitor.schema?.(node)\n break\n case 'Property':\n v = visitor.property?.(node)\n break\n case 'Parameter':\n v = visitor.parameter?.(node)\n break\n case 'Response':\n v = visitor.response?.(node)\n break\n }\n if (v !== undefined) results.push(v)\n\n for (const child of getChildren(node, recurse)) {\n for (const item of collect(child, visitor, options)) {\n results.push(item)\n }\n }\n\n return results\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __name } from "./chunk--u3MIqq1.js";
|
|
2
|
-
import {
|
|
2
|
+
import { D as OperationNode, J as SchemaNodeByType, N as ParameterNode, O as ResponseNode, S as createSchema, T as RootNode, _ as createOperation, a as transform, at as mediaTypes, b as createResponse, c as buildRefMap, et as PropertyNode, h as definePrinter, i as collect, it as httpMethods, l as refMapToObject, o as walk, ot as nodeKinds, q as SchemaNode, st as schemaTypes, u as resolveRef, v as createParameter, x as createRoot, y as createProperty } from "./visitor-CmsfJzro.js";
|
|
3
3
|
|
|
4
4
|
//#region src/guards.d.ts
|
|
5
5
|
/**
|
|
@@ -9,27 +9,27 @@ declare function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | u
|
|
|
9
9
|
/**
|
|
10
10
|
* Type guard for `RootNode`.
|
|
11
11
|
*/
|
|
12
|
-
declare const isRootNode: (node:
|
|
12
|
+
declare const isRootNode: (node: unknown) => node is RootNode;
|
|
13
13
|
/**
|
|
14
14
|
* Type guard for `OperationNode`.
|
|
15
15
|
*/
|
|
16
|
-
declare const isOperationNode: (node:
|
|
16
|
+
declare const isOperationNode: (node: unknown) => node is OperationNode;
|
|
17
17
|
/**
|
|
18
18
|
* Type guard for `SchemaNode`.
|
|
19
19
|
*/
|
|
20
|
-
declare const isSchemaNode: (node:
|
|
20
|
+
declare const isSchemaNode: (node: unknown) => node is SchemaNode;
|
|
21
21
|
/**
|
|
22
22
|
* Type guard for `PropertyNode`.
|
|
23
23
|
*/
|
|
24
|
-
declare const isPropertyNode: (node:
|
|
24
|
+
declare const isPropertyNode: (node: unknown) => node is PropertyNode;
|
|
25
25
|
/**
|
|
26
26
|
* Type guard for `ParameterNode`.
|
|
27
27
|
*/
|
|
28
|
-
declare const isParameterNode: (node:
|
|
28
|
+
declare const isParameterNode: (node: unknown) => node is ParameterNode;
|
|
29
29
|
/**
|
|
30
30
|
* Type guard for `ResponseNode`.
|
|
31
31
|
*/
|
|
32
|
-
declare const isResponseNode: (node:
|
|
32
|
+
declare const isResponseNode: (node: unknown) => node is ResponseNode;
|
|
33
33
|
//#endregion
|
|
34
|
-
export { buildRefMap, collect, createOperation, createParameter, createProperty, createResponse, createRoot, createSchema, httpMethods, isOperationNode, isParameterNode, isPropertyNode, isResponseNode, isRootNode, isSchemaNode, mediaTypes, narrowSchema, nodeKinds, refMapToObject, resolveRef, schemaTypes, transform, walk };
|
|
34
|
+
export { buildRefMap, collect, createOperation, createParameter, createProperty, createResponse, createRoot, createSchema, definePrinter, httpMethods, isOperationNode, isParameterNode, isPropertyNode, isResponseNode, isRootNode, isSchemaNode, mediaTypes, narrowSchema, nodeKinds, refMapToObject, resolveRef, schemaTypes, transform, walk };
|
|
35
35
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -93,10 +93,12 @@ function createOperation(props) {
|
|
|
93
93
|
kind: "Operation"
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Creates a `SchemaNode`, narrowed to the variant of `props.type`.
|
|
98
|
-
*/
|
|
99
96
|
function createSchema(props) {
|
|
97
|
+
if (props["type"] === "object") return {
|
|
98
|
+
properties: [],
|
|
99
|
+
...props,
|
|
100
|
+
kind: "Schema"
|
|
101
|
+
};
|
|
100
102
|
return {
|
|
101
103
|
...props,
|
|
102
104
|
kind: "Schema"
|
|
@@ -167,6 +169,60 @@ const isParameterNode = isKind("Parameter");
|
|
|
167
169
|
*/
|
|
168
170
|
const isResponseNode = isKind("Response");
|
|
169
171
|
//#endregion
|
|
172
|
+
//#region src/printer.ts
|
|
173
|
+
/**
|
|
174
|
+
* Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern
|
|
175
|
+
* from `@kubb/core` — wraps a builder to make options optional and separates raw options
|
|
176
|
+
* from resolved options.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>
|
|
181
|
+
*
|
|
182
|
+
* export const zodPrinter = definePrinter<ZodPrinter>((options) => {
|
|
183
|
+
* const { strict = true } = options
|
|
184
|
+
* return {
|
|
185
|
+
* name: 'zod',
|
|
186
|
+
* options: { strict },
|
|
187
|
+
* nodes: {
|
|
188
|
+
* string(node) {
|
|
189
|
+
* return `z.string()`
|
|
190
|
+
* },
|
|
191
|
+
* object(node) {
|
|
192
|
+
* const props = node.properties
|
|
193
|
+
* ?.map(p => `${p.name}: ${this.print(p)}`)
|
|
194
|
+
* .join(', ') ?? ''
|
|
195
|
+
* return `z.object({ ${props} })`
|
|
196
|
+
* },
|
|
197
|
+
* },
|
|
198
|
+
* }
|
|
199
|
+
* })
|
|
200
|
+
*
|
|
201
|
+
* const printer = zodPrinter({ strict: false })
|
|
202
|
+
* printer.name // 'zod'
|
|
203
|
+
* printer.options // { strict: false }
|
|
204
|
+
* printer.print(node) // 'z.string()'
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
function definePrinter(build) {
|
|
208
|
+
return (options) => {
|
|
209
|
+
const { name, options: resolvedOptions, nodes } = build(options ?? {});
|
|
210
|
+
const context = {
|
|
211
|
+
options: resolvedOptions,
|
|
212
|
+
print: (node) => {
|
|
213
|
+
const handler = nodes[node.type];
|
|
214
|
+
return handler ? handler.call(context, node) : void 0;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
return {
|
|
218
|
+
name,
|
|
219
|
+
options: resolvedOptions,
|
|
220
|
+
print: context.print,
|
|
221
|
+
for: (nodes) => nodes.map(context.print)
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//#endregion
|
|
170
226
|
//#region src/refs.ts
|
|
171
227
|
/**
|
|
172
228
|
* Indexes named schemas from `root.schemas` by name. Unnamed schemas are skipped.
|
|
@@ -190,6 +246,27 @@ function refMapToObject(refMap) {
|
|
|
190
246
|
}
|
|
191
247
|
//#endregion
|
|
192
248
|
//#region src/visitor.ts
|
|
249
|
+
function createLimit(concurrency) {
|
|
250
|
+
let active = 0;
|
|
251
|
+
const queue = [];
|
|
252
|
+
function next() {
|
|
253
|
+
if (active < concurrency && queue.length > 0) {
|
|
254
|
+
active++;
|
|
255
|
+
queue.shift()();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return function limit(fn) {
|
|
259
|
+
return new Promise((resolve, reject) => {
|
|
260
|
+
queue.push(() => {
|
|
261
|
+
Promise.resolve(fn()).then(resolve, reject).finally(() => {
|
|
262
|
+
active--;
|
|
263
|
+
next();
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
next();
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
}
|
|
193
270
|
/**
|
|
194
271
|
* Traversable children of `node`, respecting `recurse` for schema nodes.
|
|
195
272
|
*/
|
|
@@ -204,7 +281,7 @@ function getChildren(node, recurse) {
|
|
|
204
281
|
case "Schema": {
|
|
205
282
|
const children = [];
|
|
206
283
|
if (!recurse) return [];
|
|
207
|
-
if ("properties" in node && node.properties) children.push(...node.properties);
|
|
284
|
+
if ("properties" in node && node.properties.length > 0) children.push(...node.properties);
|
|
208
285
|
if ("items" in node && node.items) children.push(...node.items);
|
|
209
286
|
if ("members" in node && node.members) children.push(...node.members);
|
|
210
287
|
return children;
|
|
@@ -216,30 +293,34 @@ function getChildren(node, recurse) {
|
|
|
216
293
|
}
|
|
217
294
|
/**
|
|
218
295
|
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
296
|
+
* Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
|
|
219
297
|
*/
|
|
220
298
|
async function walk(node, visitor, options = {}) {
|
|
221
|
-
|
|
299
|
+
return _walk(node, visitor, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30));
|
|
300
|
+
}
|
|
301
|
+
async function _walk(node, visitor, recurse, limit) {
|
|
222
302
|
switch (node.kind) {
|
|
223
303
|
case "Root":
|
|
224
|
-
await visitor.root?.(node);
|
|
304
|
+
await limit(() => visitor.root?.(node));
|
|
225
305
|
break;
|
|
226
306
|
case "Operation":
|
|
227
|
-
await visitor.operation?.(node);
|
|
307
|
+
await limit(() => visitor.operation?.(node));
|
|
228
308
|
break;
|
|
229
309
|
case "Schema":
|
|
230
|
-
await visitor.schema?.(node);
|
|
310
|
+
await limit(() => visitor.schema?.(node));
|
|
231
311
|
break;
|
|
232
312
|
case "Property":
|
|
233
|
-
await visitor.property?.(node);
|
|
313
|
+
await limit(() => visitor.property?.(node));
|
|
234
314
|
break;
|
|
235
315
|
case "Parameter":
|
|
236
|
-
await visitor.parameter?.(node);
|
|
316
|
+
await limit(() => visitor.parameter?.(node));
|
|
237
317
|
break;
|
|
238
318
|
case "Response":
|
|
239
|
-
await visitor.response?.(node);
|
|
319
|
+
await limit(() => visitor.response?.(node));
|
|
240
320
|
break;
|
|
241
321
|
}
|
|
242
|
-
|
|
322
|
+
const children = getChildren(node, recurse);
|
|
323
|
+
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)));
|
|
243
324
|
}
|
|
244
325
|
function transform(node, visitor, options = {}) {
|
|
245
326
|
const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep;
|
|
@@ -271,7 +352,7 @@ function transform(node, visitor, options = {}) {
|
|
|
271
352
|
if (replaced) schema = replaced;
|
|
272
353
|
return {
|
|
273
354
|
...schema,
|
|
274
|
-
..."properties" in schema && recurse ? { properties: schema.properties
|
|
355
|
+
..."properties" in schema && recurse ? { properties: schema.properties.map((p) => transform(p, visitor, options)) } : {},
|
|
275
356
|
..."items" in schema && recurse ? { items: schema.items?.map((i) => transform(i, visitor, options)) } : {},
|
|
276
357
|
..."members" in schema && recurse ? { members: schema.members?.map((m) => transform(m, visitor, options)) } : {}
|
|
277
358
|
};
|
|
@@ -337,6 +418,6 @@ function collect(node, visitor, options = {}) {
|
|
|
337
418
|
return results;
|
|
338
419
|
}
|
|
339
420
|
//#endregion
|
|
340
|
-
export { buildRefMap, collect, createOperation, createParameter, createProperty, createResponse, createRoot, createSchema, httpMethods, isOperationNode, isParameterNode, isPropertyNode, isResponseNode, isRootNode, isSchemaNode, mediaTypes, narrowSchema, nodeKinds, refMapToObject, resolveRef, schemaTypes, transform, walk };
|
|
421
|
+
export { buildRefMap, collect, createOperation, createParameter, createProperty, createResponse, createRoot, createSchema, definePrinter, httpMethods, isOperationNode, isParameterNode, isPropertyNode, isResponseNode, isRootNode, isSchemaNode, mediaTypes, narrowSchema, nodeKinds, refMapToObject, resolveRef, schemaTypes, transform, walk };
|
|
341
422
|
|
|
342
423
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/constants.ts","../src/factory.ts","../src/guards.ts","../src/refs.ts","../src/visitor.ts"],"sourcesContent":["import type { NodeKind } from './nodes/base.ts'\nimport type { MediaType } from './nodes/http.ts'\nimport type { HttpMethod } from './nodes/operation.ts'\nimport type { ParameterLocation } from './nodes/parameter.ts'\nimport type { SchemaType } from './nodes/schema.ts'\n\n/**\n * Depth for schema traversal in visitor functions.\n */\nexport type VisitorDepth = 'shallow' | 'deep'\n\nexport const visitorDepths = {\n shallow: 'shallow',\n deep: 'deep',\n} as const satisfies Record<VisitorDepth, VisitorDepth>\n\nexport const nodeKinds = {\n root: 'Root',\n operation: 'Operation',\n schema: 'Schema',\n property: 'Property',\n parameter: 'Parameter',\n response: 'Response',\n} as const satisfies Record<Lowercase<NodeKind>, NodeKind>\n\nexport const schemaTypes = {\n string: 'string',\n /**\n * Floating-point number (`float`, `double`).\n */\n number: 'number',\n /**\n * Whole number (`int32`). Use `bigint` for `int64`.\n */\n integer: 'integer',\n /**\n * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.\n */\n bigint: 'bigint',\n boolean: 'boolean',\n null: 'null',\n any: 'any',\n unknown: 'unknown',\n void: 'void',\n object: 'object',\n array: 'array',\n tuple: 'tuple',\n union: 'union',\n intersection: 'intersection',\n enum: 'enum',\n ref: 'ref',\n date: 'date',\n datetime: 'datetime',\n time: 'time',\n uuid: 'uuid',\n email: 'email',\n url: 'url',\n blob: 'blob',\n} as const satisfies Record<SchemaType, SchemaType>\n\nexport const httpMethods = {\n get: 'GET',\n post: 'POST',\n put: 'PUT',\n patch: 'PATCH',\n delete: 'DELETE',\n head: 'HEAD',\n options: 'OPTIONS',\n trace: 'TRACE',\n} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>\n\nexport const parameterLocations = {\n path: 'path',\n query: 'query',\n header: 'header',\n cookie: 'cookie',\n} as const satisfies Record<ParameterLocation, ParameterLocation>\n\n/**\n * Fallback status code string for API spec responses.\n */\nexport const DEFAULT_STATUS_CODE = 'default' as const\n\nexport const mediaTypes = {\n applicationJson: 'application/json',\n applicationXml: 'application/xml',\n applicationFormUrlEncoded: 'application/x-www-form-urlencoded',\n applicationOctetStream: 'application/octet-stream',\n applicationPdf: 'application/pdf',\n applicationZip: 'application/zip',\n applicationGraphql: 'application/graphql',\n multipartFormData: 'multipart/form-data',\n textPlain: 'text/plain',\n textHtml: 'text/html',\n textCsv: 'text/csv',\n textXml: 'text/xml',\n imagePng: 'image/png',\n imageJpeg: 'image/jpeg',\n imageGif: 'image/gif',\n imageWebp: 'image/webp',\n imageSvgXml: 'image/svg+xml',\n audioMpeg: 'audio/mpeg',\n videoMp4: 'video/mp4',\n} as const satisfies Record<string, MediaType>\n","import type { OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'\n\n/**\n * Distributive variant of `Omit` that preserves union members.\n */\nexport type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never\n\n/**\n * Creates a `RootNode`.\n */\nexport function createRoot(overrides: Partial<Omit<RootNode, 'kind'>> = {}): RootNode {\n return {\n schemas: [],\n operations: [],\n ...overrides,\n kind: 'Root',\n }\n}\n\n/**\n * Creates an `OperationNode`.\n */\nexport function createOperation(\n props: Pick<OperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<OperationNode, 'kind' | 'operationId' | 'method' | 'path'>>,\n): OperationNode {\n return {\n tags: [],\n parameters: [],\n responses: [],\n ...props,\n kind: 'Operation',\n }\n}\n\n/**\n * Creates a `SchemaNode`, narrowed to the variant of `props.type`.\n */\nexport function createSchema<T extends DistributiveOmit<SchemaNode, 'kind'>>(props: T): T & { kind: 'Schema' } {\n return { ...props, kind: 'Schema' } as T & { kind: 'Schema' }\n}\n\n/**\n * Creates a `PropertyNode`. `required` defaults to `false`.\n */\nexport function createProperty(props: Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>): PropertyNode {\n return {\n required: false,\n ...props,\n kind: 'Property',\n }\n}\n\n/**\n * Creates a `ParameterNode`. `required` defaults to `false`.\n */\nexport function createParameter(\n props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,\n): ParameterNode {\n return {\n required: false,\n ...props,\n kind: 'Parameter',\n }\n}\n\n/**\n * Creates a `ResponseNode`.\n */\nexport function createResponse(props: Pick<ResponseNode, 'statusCode'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode'>>): ResponseNode {\n return {\n ...props,\n kind: 'Response',\n }\n}\n","import type { Node, NodeKind, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode, SchemaNodeByType } from './nodes/index.ts'\n\n/**\n * Narrows a `SchemaNode` to the specific variant matching `type`.\n */\nexport function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | undefined, type: T): SchemaNodeByType[T] | undefined {\n return node?.type === type ? (node as SchemaNodeByType[T]) : undefined\n}\n\nfunction isKind<T extends Node>(kind: NodeKind) {\n return (node: Node): node is T => node.kind === kind\n}\n\n/**\n * Type guard for `RootNode`.\n */\nexport const isRootNode = isKind<RootNode>('Root')\n\n/**\n * Type guard for `OperationNode`.\n */\nexport const isOperationNode = isKind<OperationNode>('Operation')\n\n/**\n * Type guard for `SchemaNode`.\n */\nexport const isSchemaNode = isKind<SchemaNode>('Schema')\n\n/**\n * Type guard for `PropertyNode`.\n */\nexport const isPropertyNode = isKind<PropertyNode>('Property')\n\n/**\n * Type guard for `ParameterNode`.\n */\nexport const isParameterNode = isKind<ParameterNode>('Parameter')\n\n/**\n * Type guard for `ResponseNode`.\n */\nexport const isResponseNode = isKind<ResponseNode>('Response')\n","import type { RootNode } from './nodes/root.ts'\nimport type { SchemaNode } from './nodes/schema.ts'\n\n/**\n * Schema name to `SchemaNode` mapping.\n */\nexport type RefMap = Map<string, SchemaNode>\n\n/**\n * Indexes named schemas from `root.schemas` by name. Unnamed schemas are skipped.\n */\nexport function buildRefMap(root: RootNode): RefMap {\n const map: RefMap = new Map()\n\n for (const schema of root.schemas) {\n if (schema.name) {\n map.set(schema.name, schema)\n }\n }\n return map\n}\n\n/**\n * Looks up a schema by name. Prefer over `RefMap.get()` to keep the resolution strategy swappable.\n */\nexport function resolveRef(refMap: RefMap, ref: string): SchemaNode | undefined {\n return refMap.get(ref)\n}\n\n/**\n * Converts a `RefMap` to a plain object.\n */\nexport function refMapToObject(refMap: RefMap): Record<string, SchemaNode> {\n return Object.fromEntries(refMap)\n}\n","import type { VisitorDepth } from './constants.ts'\nimport { visitorDepths } from './constants.ts'\nimport type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'\n\n/**\n * Shared options for `walk`, `transform`, and `collect`.\n */\nexport type VisitorOptions = {\n depth?: VisitorDepth\n}\n\n/**\n * Synchronous visitor for `transform` and `walk`.\n */\nexport type Visitor = {\n root?(node: RootNode): void | RootNode\n operation?(node: OperationNode): void | OperationNode\n schema?(node: SchemaNode): void | SchemaNode\n property?(node: PropertyNode): void | PropertyNode\n parameter?(node: ParameterNode): void | ParameterNode\n response?(node: ResponseNode): void | ResponseNode\n}\n\ntype MaybePromise<T> = T | Promise<T>\n\n/**\n * Async visitor for `walk`. Synchronous `Visitor` objects are compatible.\n */\nexport type AsyncVisitor = {\n root?(node: RootNode): MaybePromise<void | RootNode>\n operation?(node: OperationNode): MaybePromise<void | OperationNode>\n schema?(node: SchemaNode): MaybePromise<void | SchemaNode>\n property?(node: PropertyNode): MaybePromise<void | PropertyNode>\n parameter?(node: ParameterNode): MaybePromise<void | ParameterNode>\n response?(node: ResponseNode): MaybePromise<void | ResponseNode>\n}\n\n/**\n * Visitor for `collect`.\n */\nexport type CollectVisitor<T> = {\n root?(node: RootNode): T | undefined\n operation?(node: OperationNode): T | undefined\n schema?(node: SchemaNode): T | undefined\n property?(node: PropertyNode): T | undefined\n parameter?(node: ParameterNode): T | undefined\n response?(node: ResponseNode): T | undefined\n}\n\n/**\n * Traversable children of `node`, respecting `recurse` for schema nodes.\n */\nfunction getChildren(node: Node, recurse: boolean): Array<Node> {\n switch (node.kind) {\n case 'Root':\n return [...node.schemas, ...node.operations]\n case 'Operation':\n return [...node.parameters, ...(node.requestBody ? [node.requestBody] : []), ...node.responses]\n case 'Schema': {\n const children: Array<Node> = []\n\n if (!recurse) return []\n\n if ('properties' in node && node.properties) children.push(...node.properties)\n if ('items' in node && node.items) children.push(...node.items)\n if ('members' in node && node.members) children.push(...node.members)\n\n return children\n }\n case 'Property':\n return [node.schema]\n case 'Parameter':\n return [node.schema]\n case 'Response':\n return node.schema ? [node.schema] : []\n }\n}\n\n/**\n * Depth-first traversal for side effects. Visitor return values are ignored.\n */\nexport async function walk(node: Node, visitor: AsyncVisitor, options: VisitorOptions = {}): Promise<void> {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n\n switch (node.kind) {\n case 'Root':\n await visitor.root?.(node)\n break\n case 'Operation':\n await visitor.operation?.(node)\n break\n case 'Schema':\n await visitor.schema?.(node)\n break\n case 'Property':\n await visitor.property?.(node)\n break\n case 'Parameter':\n await visitor.parameter?.(node)\n break\n case 'Response':\n await visitor.response?.(node)\n break\n }\n\n for (const child of getChildren(node, recurse)) {\n await walk(child, visitor, options)\n }\n}\n\n/**\n * Depth-first immutable transformation. Visitor return values replace nodes; `undefined` keeps the original.\n */\nexport function transform(node: RootNode, visitor: Visitor, options?: VisitorOptions): RootNode\nexport function transform(node: OperationNode, visitor: Visitor, options?: VisitorOptions): OperationNode\nexport function transform(node: SchemaNode, visitor: Visitor, options?: VisitorOptions): SchemaNode\nexport function transform(node: PropertyNode, visitor: Visitor, options?: VisitorOptions): PropertyNode\nexport function transform(node: ParameterNode, visitor: Visitor, options?: VisitorOptions): ParameterNode\nexport function transform(node: ResponseNode, visitor: Visitor, options?: VisitorOptions): ResponseNode\nexport function transform(node: Node, visitor: Visitor, options?: VisitorOptions): Node\nexport function transform(node: Node, visitor: Visitor, options: VisitorOptions = {}): Node {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n\n switch (node.kind) {\n case 'Root': {\n let root = node\n const replaced = visitor.root?.(root)\n if (replaced) root = replaced\n\n return {\n ...root,\n schemas: root.schemas.map((s) => transform(s, visitor, options)),\n operations: root.operations.map((op) => transform(op, visitor, options)),\n }\n }\n case 'Operation': {\n let op = node\n const replaced = visitor.operation?.(op)\n if (replaced) op = replaced\n\n return {\n ...op,\n parameters: op.parameters.map((p) => transform(p, visitor, options)),\n requestBody: op.requestBody ? transform(op.requestBody, visitor, options) : undefined,\n responses: op.responses.map((r) => transform(r, visitor, options)),\n }\n }\n case 'Schema': {\n let schema = node\n const replaced = visitor.schema?.(schema)\n if (replaced) schema = replaced\n\n return {\n ...schema,\n ...('properties' in schema && recurse ? { properties: schema.properties?.map((p) => transform(p, visitor, options)) } : {}),\n ...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, visitor, options)) } : {}),\n ...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, visitor, options)) } : {}),\n }\n }\n case 'Property': {\n let prop = node\n const replaced = visitor.property?.(prop)\n if (replaced) prop = replaced\n\n return {\n ...prop,\n schema: transform(prop.schema, visitor, options),\n }\n }\n case 'Parameter': {\n let param = node\n const replaced = visitor.parameter?.(param)\n if (replaced) param = replaced\n\n return {\n ...param,\n schema: transform(param.schema, visitor, options),\n }\n }\n case 'Response': {\n let response = node\n const replaced = visitor.response?.(response)\n if (replaced) response = replaced\n\n return {\n ...response,\n schema: response.schema ? transform(response.schema, visitor, options) : undefined,\n }\n }\n }\n}\n\n/**\n * Depth-first synchronous reduction. Collects non-`undefined` visitor return values into an array.\n */\nexport function collect<T>(node: Node, visitor: CollectVisitor<T>, options: VisitorOptions = {}): Array<T> {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n const results: Array<T> = []\n\n let v: T | undefined\n switch (node.kind) {\n case 'Root':\n v = visitor.root?.(node)\n break\n case 'Operation':\n v = visitor.operation?.(node)\n break\n case 'Schema':\n v = visitor.schema?.(node)\n break\n case 'Property':\n v = visitor.property?.(node)\n break\n case 'Parameter':\n v = visitor.parameter?.(node)\n break\n case 'Response':\n v = visitor.response?.(node)\n break\n }\n if (v !== undefined) results.push(v)\n\n for (const child of getChildren(node, recurse)) {\n for (const item of collect(child, visitor, options)) {\n results.push(item)\n }\n }\n\n return results\n}\n"],"mappings":";;AAWA,MAAa,gBAAgB;CAC3B,SAAS;CACT,MAAM;CACP;AAED,MAAa,YAAY;CACvB,MAAM;CACN,WAAW;CACX,QAAQ;CACR,UAAU;CACV,WAAW;CACX,UAAU;CACX;AAED,MAAa,cAAc;CACzB,QAAQ;CAIR,QAAQ;CAIR,SAAS;CAIT,QAAQ;CACR,SAAS;CACT,MAAM;CACN,KAAK;CACL,SAAS;CACT,MAAM;CACN,QAAQ;CACR,OAAO;CACP,OAAO;CACP,OAAO;CACP,cAAc;CACd,MAAM;CACN,KAAK;CACL,MAAM;CACN,UAAU;CACV,MAAM;CACN,MAAM;CACN,OAAO;CACP,KAAK;CACL,MAAM;CACP;AAED,MAAa,cAAc;CACzB,KAAK;CACL,MAAM;CACN,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;CACN,SAAS;CACT,OAAO;CACR;AAcD,MAAa,aAAa;CACxB,iBAAiB;CACjB,gBAAgB;CAChB,2BAA2B;CAC3B,wBAAwB;CACxB,gBAAgB;CAChB,gBAAgB;CAChB,oBAAoB;CACpB,mBAAmB;CACnB,WAAW;CACX,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,WAAW;CACX,UAAU;CACV,WAAW;CACX,aAAa;CACb,WAAW;CACX,UAAU;CACX;;;;;;AC7FD,SAAgB,WAAW,YAA6C,EAAE,EAAY;AACpF,QAAO;EACL,SAAS,EAAE;EACX,YAAY,EAAE;EACd,GAAG;EACH,MAAM;EACP;;;;;AAMH,SAAgB,gBACd,OACe;AACf,QAAO;EACL,MAAM,EAAE;EACR,YAAY,EAAE;EACd,WAAW,EAAE;EACb,GAAG;EACH,MAAM;EACP;;;;;AAMH,SAAgB,aAA6D,OAAkC;AAC7G,QAAO;EAAE,GAAG;EAAO,MAAM;EAAU;;;;;AAMrC,SAAgB,eAAe,OAAsH;AACnJ,QAAO;EACL,UAAU;EACV,GAAG;EACH,MAAM;EACP;;;;;AAMH,SAAgB,gBACd,OACe;AACf,QAAO;EACL,UAAU;EACV,GAAG;EACH,MAAM;EACP;;;;;AAMH,SAAgB,eAAe,OAA4G;AACzI,QAAO;EACL,GAAG;EACH,MAAM;EACP;;;;;;;ACnEH,SAAgB,aAA2C,MAA8B,MAA0C;AACjI,QAAO,MAAM,SAAS,OAAQ,OAA+B,KAAA;;AAG/D,SAAS,OAAuB,MAAgB;AAC9C,SAAQ,SAA0B,KAAK,SAAS;;;;;AAMlD,MAAa,aAAa,OAAiB,OAAO;;;;AAKlD,MAAa,kBAAkB,OAAsB,YAAY;;;;AAKjE,MAAa,eAAe,OAAmB,SAAS;;;;AAKxD,MAAa,iBAAiB,OAAqB,WAAW;;;;AAK9D,MAAa,kBAAkB,OAAsB,YAAY;;;;AAKjE,MAAa,iBAAiB,OAAqB,WAAW;;;;;;AC9B9D,SAAgB,YAAY,MAAwB;CAClD,MAAM,sBAAc,IAAI,KAAK;AAE7B,MAAK,MAAM,UAAU,KAAK,QACxB,KAAI,OAAO,KACT,KAAI,IAAI,OAAO,MAAM,OAAO;AAGhC,QAAO;;;;;AAMT,SAAgB,WAAW,QAAgB,KAAqC;AAC9E,QAAO,OAAO,IAAI,IAAI;;;;;AAMxB,SAAgB,eAAe,QAA4C;AACzE,QAAO,OAAO,YAAY,OAAO;;;;;;;ACmBnC,SAAS,YAAY,MAAY,SAA+B;AAC9D,SAAQ,KAAK,MAAb;EACE,KAAK,OACH,QAAO,CAAC,GAAG,KAAK,SAAS,GAAG,KAAK,WAAW;EAC9C,KAAK,YACH,QAAO;GAAC,GAAG,KAAK;GAAY,GAAI,KAAK,cAAc,CAAC,KAAK,YAAY,GAAG,EAAE;GAAG,GAAG,KAAK;GAAU;EACjG,KAAK,UAAU;GACb,MAAM,WAAwB,EAAE;AAEhC,OAAI,CAAC,QAAS,QAAO,EAAE;AAEvB,OAAI,gBAAgB,QAAQ,KAAK,WAAY,UAAS,KAAK,GAAG,KAAK,WAAW;AAC9E,OAAI,WAAW,QAAQ,KAAK,MAAO,UAAS,KAAK,GAAG,KAAK,MAAM;AAC/D,OAAI,aAAa,QAAQ,KAAK,QAAS,UAAS,KAAK,GAAG,KAAK,QAAQ;AAErE,UAAO;;EAET,KAAK,WACH,QAAO,CAAC,KAAK,OAAO;EACtB,KAAK,YACH,QAAO,CAAC,KAAK,OAAO;EACtB,KAAK,WACH,QAAO,KAAK,SAAS,CAAC,KAAK,OAAO,GAAG,EAAE;;;;;;AAO7C,eAAsB,KAAK,MAAY,SAAuB,UAA0B,EAAE,EAAiB;CACzG,MAAM,WAAW,QAAQ,SAAS,cAAc,UAAU,cAAc;AAExE,SAAQ,KAAK,MAAb;EACE,KAAK;AACH,SAAM,QAAQ,OAAO,KAAK;AAC1B;EACF,KAAK;AACH,SAAM,QAAQ,YAAY,KAAK;AAC/B;EACF,KAAK;AACH,SAAM,QAAQ,SAAS,KAAK;AAC5B;EACF,KAAK;AACH,SAAM,QAAQ,WAAW,KAAK;AAC9B;EACF,KAAK;AACH,SAAM,QAAQ,YAAY,KAAK;AAC/B;EACF,KAAK;AACH,SAAM,QAAQ,WAAW,KAAK;AAC9B;;AAGJ,MAAK,MAAM,SAAS,YAAY,MAAM,QAAQ,CAC5C,OAAM,KAAK,OAAO,SAAS,QAAQ;;AAcvC,SAAgB,UAAU,MAAY,SAAkB,UAA0B,EAAE,EAAQ;CAC1F,MAAM,WAAW,QAAQ,SAAS,cAAc,UAAU,cAAc;AAExE,SAAQ,KAAK,MAAb;EACE,KAAK,QAAQ;GACX,IAAI,OAAO;GACX,MAAM,WAAW,QAAQ,OAAO,KAAK;AACrC,OAAI,SAAU,QAAO;AAErB,UAAO;IACL,GAAG;IACH,SAAS,KAAK,QAAQ,KAAK,MAAM,UAAU,GAAG,SAAS,QAAQ,CAAC;IAChE,YAAY,KAAK,WAAW,KAAK,OAAO,UAAU,IAAI,SAAS,QAAQ,CAAC;IACzE;;EAEH,KAAK,aAAa;GAChB,IAAI,KAAK;GACT,MAAM,WAAW,QAAQ,YAAY,GAAG;AACxC,OAAI,SAAU,MAAK;AAEnB,UAAO;IACL,GAAG;IACH,YAAY,GAAG,WAAW,KAAK,MAAM,UAAU,GAAG,SAAS,QAAQ,CAAC;IACpE,aAAa,GAAG,cAAc,UAAU,GAAG,aAAa,SAAS,QAAQ,GAAG,KAAA;IAC5E,WAAW,GAAG,UAAU,KAAK,MAAM,UAAU,GAAG,SAAS,QAAQ,CAAC;IACnE;;EAEH,KAAK,UAAU;GACb,IAAI,SAAS;GACb,MAAM,WAAW,QAAQ,SAAS,OAAO;AACzC,OAAI,SAAU,UAAS;AAEvB,UAAO;IACL,GAAG;IACH,GAAI,gBAAgB,UAAU,UAAU,EAAE,YAAY,OAAO,YAAY,KAAK,MAAM,UAAU,GAAG,SAAS,QAAQ,CAAC,EAAE,GAAG,EAAE;IAC1H,GAAI,WAAW,UAAU,UAAU,EAAE,OAAO,OAAO,OAAO,KAAK,MAAM,UAAU,GAAG,SAAS,QAAQ,CAAC,EAAE,GAAG,EAAE;IAC3G,GAAI,aAAa,UAAU,UAAU,EAAE,SAAS,OAAO,SAAS,KAAK,MAAM,UAAU,GAAG,SAAS,QAAQ,CAAC,EAAE,GAAG,EAAE;IAClH;;EAEH,KAAK,YAAY;GACf,IAAI,OAAO;GACX,MAAM,WAAW,QAAQ,WAAW,KAAK;AACzC,OAAI,SAAU,QAAO;AAErB,UAAO;IACL,GAAG;IACH,QAAQ,UAAU,KAAK,QAAQ,SAAS,QAAQ;IACjD;;EAEH,KAAK,aAAa;GAChB,IAAI,QAAQ;GACZ,MAAM,WAAW,QAAQ,YAAY,MAAM;AAC3C,OAAI,SAAU,SAAQ;AAEtB,UAAO;IACL,GAAG;IACH,QAAQ,UAAU,MAAM,QAAQ,SAAS,QAAQ;IAClD;;EAEH,KAAK,YAAY;GACf,IAAI,WAAW;GACf,MAAM,WAAW,QAAQ,WAAW,SAAS;AAC7C,OAAI,SAAU,YAAW;AAEzB,UAAO;IACL,GAAG;IACH,QAAQ,SAAS,SAAS,UAAU,SAAS,QAAQ,SAAS,QAAQ,GAAG,KAAA;IAC1E;;;;;;;AAQP,SAAgB,QAAW,MAAY,SAA4B,UAA0B,EAAE,EAAY;CACzG,MAAM,WAAW,QAAQ,SAAS,cAAc,UAAU,cAAc;CACxE,MAAM,UAAoB,EAAE;CAE5B,IAAI;AACJ,SAAQ,KAAK,MAAb;EACE,KAAK;AACH,OAAI,QAAQ,OAAO,KAAK;AACxB;EACF,KAAK;AACH,OAAI,QAAQ,YAAY,KAAK;AAC7B;EACF,KAAK;AACH,OAAI,QAAQ,SAAS,KAAK;AAC1B;EACF,KAAK;AACH,OAAI,QAAQ,WAAW,KAAK;AAC5B;EACF,KAAK;AACH,OAAI,QAAQ,YAAY,KAAK;AAC7B;EACF,KAAK;AACH,OAAI,QAAQ,WAAW,KAAK;AAC5B;;AAEJ,KAAI,MAAM,KAAA,EAAW,SAAQ,KAAK,EAAE;AAEpC,MAAK,MAAM,SAAS,YAAY,MAAM,QAAQ,CAC5C,MAAK,MAAM,QAAQ,QAAQ,OAAO,SAAS,QAAQ,CACjD,SAAQ,KAAK,KAAK;AAItB,QAAO"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/constants.ts","../src/factory.ts","../src/guards.ts","../src/printer.ts","../src/refs.ts","../src/visitor.ts"],"sourcesContent":["import type { NodeKind } from './nodes/base.ts'\nimport type { MediaType } from './nodes/http.ts'\nimport type { HttpMethod } from './nodes/operation.ts'\nimport type { ParameterLocation } from './nodes/parameter.ts'\nimport type { SchemaType } from './nodes/schema.ts'\n\n/**\n * Depth for schema traversal in visitor functions.\n */\nexport type VisitorDepth = 'shallow' | 'deep'\n\nexport const visitorDepths = {\n shallow: 'shallow',\n deep: 'deep',\n} as const satisfies Record<VisitorDepth, VisitorDepth>\n\nexport const nodeKinds = {\n root: 'Root',\n operation: 'Operation',\n schema: 'Schema',\n property: 'Property',\n parameter: 'Parameter',\n response: 'Response',\n} as const satisfies Record<Lowercase<NodeKind>, NodeKind>\n\nexport const schemaTypes = {\n string: 'string',\n /**\n * Floating-point number (`float`, `double`).\n */\n number: 'number',\n /**\n * Whole number (`int32`). Use `bigint` for `int64`.\n */\n integer: 'integer',\n /**\n * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.\n */\n bigint: 'bigint',\n boolean: 'boolean',\n null: 'null',\n any: 'any',\n unknown: 'unknown',\n void: 'void',\n object: 'object',\n array: 'array',\n tuple: 'tuple',\n union: 'union',\n intersection: 'intersection',\n enum: 'enum',\n ref: 'ref',\n date: 'date',\n datetime: 'datetime',\n time: 'time',\n uuid: 'uuid',\n email: 'email',\n url: 'url',\n blob: 'blob',\n} as const satisfies Record<SchemaType, SchemaType>\n\nexport const httpMethods = {\n get: 'GET',\n post: 'POST',\n put: 'PUT',\n patch: 'PATCH',\n delete: 'DELETE',\n head: 'HEAD',\n options: 'OPTIONS',\n trace: 'TRACE',\n} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>\n\nexport const parameterLocations = {\n path: 'path',\n query: 'query',\n header: 'header',\n cookie: 'cookie',\n} as const satisfies Record<ParameterLocation, ParameterLocation>\n\n/**\n * Default max concurrent visitor calls in `walk`.\n */\nexport const WALK_CONCURRENCY = 30\n\n/**\n * Fallback status code string for API spec responses.\n */\nexport const DEFAULT_STATUS_CODE = 'default' as const\n\nexport const mediaTypes = {\n applicationJson: 'application/json',\n applicationXml: 'application/xml',\n applicationFormUrlEncoded: 'application/x-www-form-urlencoded',\n applicationOctetStream: 'application/octet-stream',\n applicationPdf: 'application/pdf',\n applicationZip: 'application/zip',\n applicationGraphql: 'application/graphql',\n multipartFormData: 'multipart/form-data',\n textPlain: 'text/plain',\n textHtml: 'text/html',\n textCsv: 'text/csv',\n textXml: 'text/xml',\n imagePng: 'image/png',\n imageJpeg: 'image/jpeg',\n imageGif: 'image/gif',\n imageWebp: 'image/webp',\n imageSvgXml: 'image/svg+xml',\n audioMpeg: 'audio/mpeg',\n videoMp4: 'video/mp4',\n} as const satisfies Record<string, MediaType>\n","import type { ObjectSchemaNode, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'\n\n/**\n * Distributive variant of `Omit` that preserves union members.\n */\nexport type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never\n\n/**\n * Creates a `RootNode`.\n */\nexport function createRoot(overrides: Partial<Omit<RootNode, 'kind'>> = {}): RootNode {\n return {\n schemas: [],\n operations: [],\n ...overrides,\n kind: 'Root',\n }\n}\n\n/**\n * Creates an `OperationNode`.\n */\nexport function createOperation(\n props: Pick<OperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<OperationNode, 'kind' | 'operationId' | 'method' | 'path'>>,\n): OperationNode {\n return {\n tags: [],\n parameters: [],\n responses: [],\n ...props,\n kind: 'Operation',\n }\n}\n\n/**\n * Creates a `SchemaNode`, narrowed to the variant of `props.type`.\n * For object schemas, `properties` defaults to `[]` when not provided.\n */\nexport function createSchema<T extends Omit<ObjectSchemaNode, 'kind' | 'properties'> & { properties?: Array<PropertyNode> }>(\n props: T,\n): Omit<T, 'properties'> & { properties: Array<PropertyNode>; kind: 'Schema' }\nexport function createSchema<T extends DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>>(props: T): T & { kind: 'Schema' }\nexport function createSchema(props: DistributiveOmit<SchemaNode, 'kind'>): SchemaNode\nexport function createSchema(props: Record<string, unknown>): Record<string, unknown> {\n if (props['type'] === 'object') {\n return { properties: [], ...props, kind: 'Schema' }\n }\n\n return { ...props, kind: 'Schema' }\n}\n\n/**\n * Creates a `PropertyNode`. `required` defaults to `false`.\n */\nexport function createProperty(props: Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>): PropertyNode {\n return {\n required: false,\n ...props,\n kind: 'Property',\n }\n}\n\n/**\n * Creates a `ParameterNode`. `required` defaults to `false`.\n */\nexport function createParameter(\n props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,\n): ParameterNode {\n return {\n required: false,\n ...props,\n kind: 'Parameter',\n }\n}\n\n/**\n * Creates a `ResponseNode`.\n */\nexport function createResponse(props: Pick<ResponseNode, 'statusCode'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode'>>): ResponseNode {\n return {\n ...props,\n kind: 'Response',\n }\n}\n","import type { Node, NodeKind, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode, SchemaNodeByType } from './nodes/index.ts'\n\n/**\n * Narrows a `SchemaNode` to the specific variant matching `type`.\n */\nexport function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | undefined, type: T): SchemaNodeByType[T] | undefined {\n return node?.type === type ? (node as SchemaNodeByType[T]) : undefined\n}\n\nfunction isKind<T extends Node>(kind: NodeKind) {\n return (node: unknown): node is T => (node as Node).kind === kind\n}\n\n/**\n * Type guard for `RootNode`.\n */\nexport const isRootNode = isKind<RootNode>('Root')\n\n/**\n * Type guard for `OperationNode`.\n */\nexport const isOperationNode = isKind<OperationNode>('Operation')\n\n/**\n * Type guard for `SchemaNode`.\n */\nexport const isSchemaNode = isKind<SchemaNode>('Schema')\n\n/**\n * Type guard for `PropertyNode`.\n */\nexport const isPropertyNode = isKind<PropertyNode>('Property')\n\n/**\n * Type guard for `ParameterNode`.\n */\nexport const isParameterNode = isKind<ParameterNode>('Parameter')\n\n/**\n * Type guard for `ResponseNode`.\n */\nexport const isResponseNode = isKind<ResponseNode>('Response')\n","import type { SchemaNode, SchemaNodeByType, SchemaType } from './nodes/index.ts'\n\n/**\n * Handler context for `definePrinter` — mirrors `PluginContext` from `@kubb/core`.\n * Available as `this` inside each node handler.\n */\nexport type PrinterHandlerContext<TOutput, TOptions extends object> = {\n /**\n * Recursively print a nested `SchemaNode`.\n */\n print: (node: SchemaNode) => TOutput | null | undefined\n /**\n * Options for this printer instance.\n */\n options: TOptions\n}\n\n/**\n * Handler for a specific `SchemaNode` variant identified by `SchemaType` key `T`.\n * Use a regular function (not an arrow function) so that `this` is available.\n */\nexport type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (\n this: PrinterHandlerContext<TOutput, TOptions>,\n node: SchemaNodeByType[T],\n) => TOutput | null | undefined\n\n/**\n * Shape of the type parameter passed to `definePrinter`.\n * Mirrors `AdapterFactoryOptions` / `PluginFactoryOptions` from `@kubb/core`.\n *\n * - `TName` — unique string identifier (e.g. `'zod'`, `'ts'`)\n * - `TOptions` — options passed to and stored on the printer\n * - `TOutput` — the type emitted by `print` (typically `string`)\n */\nexport type PrinterFactoryOptions<TName extends string = string, TOptions extends object = object, TOutput = unknown> = {\n name: TName\n options: TOptions\n output: TOutput\n}\n\n/**\n * The object returned by calling a `definePrinter` instance.\n * Mirrors the shape of `Adapter` from `@kubb/core`.\n */\nexport type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {\n /**\n * Unique identifier supplied at creation time.\n */\n name: T['name']\n /**\n * Options for this printer instance.\n */\n options: T['options']\n /**\n * Emits `TOutput` from a `SchemaNode`. Returns `null | undefined` when no handler matches.\n */\n print: (node: SchemaNode) => T['output'] | null | undefined\n /**\n * Maps `print` over an array of `SchemaNode`s.\n */\n for: (nodes: Array<SchemaNode>) => Array<T['output'] | null | undefined>\n}\n\ntype PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) => {\n name: T['name']\n /**\n * Options to store on the printer.\n */\n options: T['options']\n nodes: Partial<{\n [K in SchemaType]: PrinterHandler<T['output'], T['options'], K>\n }>\n}\n\n/**\n * Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern\n * from `@kubb/core` — wraps a builder to make options optional and separates raw options\n * from resolved options.\n *\n * @example\n * ```ts\n * type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>\n *\n * export const zodPrinter = definePrinter<ZodPrinter>((options) => {\n * const { strict = true } = options\n * return {\n * name: 'zod',\n * options: { strict },\n * nodes: {\n * string(node) {\n * return `z.string()`\n * },\n * object(node) {\n * const props = node.properties\n * ?.map(p => `${p.name}: ${this.print(p)}`)\n * .join(', ') ?? ''\n * return `z.object({ ${props} })`\n * },\n * },\n * }\n * })\n *\n * const printer = zodPrinter({ strict: false })\n * printer.name // 'zod'\n * printer.options // { strict: false }\n * printer.print(node) // 'z.string()'\n * ```\n */\nexport function definePrinter<T extends PrinterFactoryOptions = PrinterFactoryOptions>(build: PrinterBuilder<T>): (options?: T['options']) => Printer<T> {\n return (options) => {\n const { name, options: resolvedOptions, nodes } = build(options ?? ({} as T['options']))\n\n const context: PrinterHandlerContext<T['output'], T['options']> = {\n options: resolvedOptions,\n print: (node: SchemaNode) => {\n const type = node.type as SchemaType\n const handler = nodes[type]\n return handler ? (handler as PrinterHandler<T['output'], T['options']>).call(context, node as SchemaNodeByType[SchemaType]) : undefined\n },\n }\n\n return {\n name,\n options: resolvedOptions,\n print: context.print,\n for: (nodes) => nodes.map(context.print),\n }\n }\n}\n","import type { RootNode } from './nodes/root.ts'\nimport type { SchemaNode } from './nodes/schema.ts'\n\n/**\n * Schema name to `SchemaNode` mapping.\n */\nexport type RefMap = Map<string, SchemaNode>\n\n/**\n * Indexes named schemas from `root.schemas` by name. Unnamed schemas are skipped.\n */\nexport function buildRefMap(root: RootNode): RefMap {\n const map: RefMap = new Map()\n\n for (const schema of root.schemas) {\n if (schema.name) {\n map.set(schema.name, schema)\n }\n }\n return map\n}\n\n/**\n * Looks up a schema by name. Prefer over `RefMap.get()` to keep the resolution strategy swappable.\n */\nexport function resolveRef(refMap: RefMap, ref: string): SchemaNode | undefined {\n return refMap.get(ref)\n}\n\n/**\n * Converts a `RefMap` to a plain object.\n */\nexport function refMapToObject(refMap: RefMap): Record<string, SchemaNode> {\n return Object.fromEntries(refMap)\n}\n","import type { VisitorDepth } from './constants.ts'\nimport { visitorDepths, WALK_CONCURRENCY } from './constants.ts'\nimport type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'\n\nfunction createLimit(concurrency: number) {\n let active = 0\n const queue: Array<() => void> = []\n\n function next() {\n if (active < concurrency && queue.length > 0) {\n active++\n queue.shift()!()\n }\n }\n\n return function limit<T>(fn: () => Promise<T> | T): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n queue.push(() => {\n Promise.resolve(fn())\n .then(resolve, reject)\n .finally(() => {\n active--\n next()\n })\n })\n next()\n })\n }\n}\n\ntype LimitFn = ReturnType<typeof createLimit>\n\n/**\n * Shared options for `walk`, `transform`, and `collect`.\n */\nexport type VisitorOptions = {\n depth?: VisitorDepth\n /**\n * Maximum number of sibling nodes visited concurrently inside `walk`.\n * @default 30\n */\n concurrency?: number\n}\n\n/**\n * Synchronous visitor for `transform` and `walk`.\n */\nexport type Visitor = {\n root?(node: RootNode): void | RootNode\n operation?(node: OperationNode): void | OperationNode\n schema?(node: SchemaNode): void | SchemaNode\n property?(node: PropertyNode): void | PropertyNode\n parameter?(node: ParameterNode): void | ParameterNode\n response?(node: ResponseNode): void | ResponseNode\n}\n\ntype MaybePromise<T> = T | Promise<T>\n\n/**\n * Async visitor for `walk`. Synchronous `Visitor` objects are compatible.\n */\nexport type AsyncVisitor = {\n root?(node: RootNode): MaybePromise<void | RootNode>\n operation?(node: OperationNode): MaybePromise<void | OperationNode>\n schema?(node: SchemaNode): MaybePromise<void | SchemaNode>\n property?(node: PropertyNode): MaybePromise<void | PropertyNode>\n parameter?(node: ParameterNode): MaybePromise<void | ParameterNode>\n response?(node: ResponseNode): MaybePromise<void | ResponseNode>\n}\n\n/**\n * Visitor for `collect`.\n */\nexport type CollectVisitor<T> = {\n root?(node: RootNode): T | undefined\n operation?(node: OperationNode): T | undefined\n schema?(node: SchemaNode): T | undefined\n property?(node: PropertyNode): T | undefined\n parameter?(node: ParameterNode): T | undefined\n response?(node: ResponseNode): T | undefined\n}\n\n/**\n * Traversable children of `node`, respecting `recurse` for schema nodes.\n */\nfunction getChildren(node: Node, recurse: boolean): Array<Node> {\n switch (node.kind) {\n case 'Root':\n return [...node.schemas, ...node.operations]\n case 'Operation':\n return [...node.parameters, ...(node.requestBody ? [node.requestBody] : []), ...node.responses]\n case 'Schema': {\n const children: Array<Node> = []\n\n if (!recurse) return []\n\n if ('properties' in node && node.properties.length > 0) children.push(...node.properties)\n if ('items' in node && node.items) children.push(...node.items)\n if ('members' in node && node.members) children.push(...node.members)\n\n return children\n }\n case 'Property':\n return [node.schema]\n case 'Parameter':\n return [node.schema]\n case 'Response':\n return node.schema ? [node.schema] : []\n }\n}\n\n/**\n * Depth-first traversal for side effects. Visitor return values are ignored.\n * Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).\n */\nexport async function walk(node: Node, visitor: AsyncVisitor, options: VisitorOptions = {}): Promise<void> {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n const limit = createLimit(options.concurrency ?? WALK_CONCURRENCY)\n return _walk(node, visitor, recurse, limit)\n}\n\nasync function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit: LimitFn): Promise<void> {\n switch (node.kind) {\n case 'Root':\n await limit(() => visitor.root?.(node))\n break\n case 'Operation':\n await limit(() => visitor.operation?.(node))\n break\n case 'Schema':\n await limit(() => visitor.schema?.(node))\n break\n case 'Property':\n await limit(() => visitor.property?.(node))\n break\n case 'Parameter':\n await limit(() => visitor.parameter?.(node))\n break\n case 'Response':\n await limit(() => visitor.response?.(node))\n break\n }\n\n const children = getChildren(node, recurse)\n await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)))\n}\n\n/**\n * Depth-first immutable transformation. Visitor return values replace nodes; `undefined` keeps the original.\n */\nexport function transform(node: RootNode, visitor: Visitor, options?: VisitorOptions): RootNode\nexport function transform(node: OperationNode, visitor: Visitor, options?: VisitorOptions): OperationNode\nexport function transform(node: SchemaNode, visitor: Visitor, options?: VisitorOptions): SchemaNode\nexport function transform(node: PropertyNode, visitor: Visitor, options?: VisitorOptions): PropertyNode\nexport function transform(node: ParameterNode, visitor: Visitor, options?: VisitorOptions): ParameterNode\nexport function transform(node: ResponseNode, visitor: Visitor, options?: VisitorOptions): ResponseNode\nexport function transform(node: Node, visitor: Visitor, options?: VisitorOptions): Node\nexport function transform(node: Node, visitor: Visitor, options: VisitorOptions = {}): Node {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n\n switch (node.kind) {\n case 'Root': {\n let root = node\n const replaced = visitor.root?.(root)\n if (replaced) root = replaced\n\n return {\n ...root,\n schemas: root.schemas.map((s) => transform(s, visitor, options)),\n operations: root.operations.map((op) => transform(op, visitor, options)),\n }\n }\n case 'Operation': {\n let op = node\n const replaced = visitor.operation?.(op)\n if (replaced) op = replaced\n\n return {\n ...op,\n parameters: op.parameters.map((p) => transform(p, visitor, options)),\n requestBody: op.requestBody ? transform(op.requestBody, visitor, options) : undefined,\n responses: op.responses.map((r) => transform(r, visitor, options)),\n }\n }\n case 'Schema': {\n let schema = node\n const replaced = visitor.schema?.(schema)\n if (replaced) schema = replaced\n\n return {\n ...schema,\n ...('properties' in schema && recurse ? { properties: schema.properties.map((p) => transform(p, visitor, options)) } : {}),\n ...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, visitor, options)) } : {}),\n ...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, visitor, options)) } : {}),\n }\n }\n case 'Property': {\n let prop = node\n const replaced = visitor.property?.(prop)\n if (replaced) prop = replaced\n\n return {\n ...prop,\n schema: transform(prop.schema, visitor, options),\n }\n }\n case 'Parameter': {\n let param = node\n const replaced = visitor.parameter?.(param)\n if (replaced) param = replaced\n\n return {\n ...param,\n schema: transform(param.schema, visitor, options),\n }\n }\n case 'Response': {\n let response = node\n const replaced = visitor.response?.(response)\n if (replaced) response = replaced\n\n return {\n ...response,\n schema: response.schema ? transform(response.schema, visitor, options) : undefined,\n }\n }\n }\n}\n\n/**\n * Depth-first synchronous reduction. Collects non-`undefined` visitor return values into an array.\n */\nexport function collect<T>(node: Node, visitor: CollectVisitor<T>, options: VisitorOptions = {}): Array<T> {\n const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep\n const results: Array<T> = []\n\n let v: T | undefined\n switch (node.kind) {\n case 'Root':\n v = visitor.root?.(node)\n break\n case 'Operation':\n v = visitor.operation?.(node)\n break\n case 'Schema':\n v = visitor.schema?.(node)\n break\n case 'Property':\n v = visitor.property?.(node)\n break\n case 'Parameter':\n v = visitor.parameter?.(node)\n break\n case 'Response':\n v = visitor.response?.(node)\n break\n }\n if (v !== undefined) results.push(v)\n\n for (const child of getChildren(node, recurse)) {\n for (const item of collect(child, visitor, options)) {\n results.push(item)\n }\n }\n\n return results\n}\n"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
export { type ArraySchemaNode, type AsyncVisitor, type BaseNode, type CollectVisitor, type ComplexSchemaType, type DateSchemaNode, type DatetimeSchemaNode, type DistributiveOmit, type EnumSchemaNode, type EnumValueNode, type HttpMethod, type HttpStatusCode, type IntersectionSchemaNode, type MediaType, type Node, type NodeKind, type NumberSchemaNode, type ObjectSchemaNode, type OperationNode, type ParameterLocation, type ParameterNode, type PrimitiveSchemaType, type PropertyNode, type RefMap, type RefSchemaNode, type ResponseNode, type RootMeta, type RootNode, type ScalarSchemaNode, type ScalarSchemaType, type SchemaNode, type SchemaNodeByType, type SchemaType, type SpecialSchemaType, type StatusCode, type StringSchemaNode, type TimeSchemaNode, type UnionSchemaNode, type Visitor, type VisitorDepth
|
|
1
|
+
import { $ as UnionSchemaNode, A as MediaType, B as IntersectionSchemaNode, C as Node, D as OperationNode, E as HttpMethod, F as ComplexSchemaType, G as ScalarSchemaNode, H as ObjectSchemaNode, I as DateSchemaNode, J as SchemaNodeByType, K as ScalarSchemaType, L as DatetimeSchemaNode, M as ParameterLocation, N as ParameterNode, O as ResponseNode, P as ArraySchemaNode, Q as TimeSchemaNode, R as EnumSchemaNode, T as RootNode, U as PrimitiveSchemaType, V as NumberSchemaNode, W as RefSchemaNode, X as SpecialSchemaType, Y as SchemaType, Z as StringSchemaNode, d as Printer, et as PropertyNode, f as PrinterFactoryOptions, g as DistributiveOmit, j as StatusCode, k as HttpStatusCode, m as PrinterHandlerContext, n as CollectVisitor, nt as NodeKind, p as PrinterHandler, q as SchemaNode, r as Visitor, rt as VisitorDepth, s as RefMap, t as AsyncVisitor, tt as BaseNode, w as RootMeta, z as EnumValueNode } from "./visitor-CmsfJzro.js";
|
|
2
|
+
export { type ArraySchemaNode, type AsyncVisitor, type BaseNode, type CollectVisitor, type ComplexSchemaType, type DateSchemaNode, type DatetimeSchemaNode, type DistributiveOmit, type EnumSchemaNode, type EnumValueNode, type HttpMethod, type HttpStatusCode, type IntersectionSchemaNode, type MediaType, type Node, type NodeKind, type NumberSchemaNode, type ObjectSchemaNode, type OperationNode, type ParameterLocation, type ParameterNode, type PrimitiveSchemaType, type Printer, type PrinterFactoryOptions, type PrinterHandler, type PrinterHandlerContext, type PropertyNode, type RefMap, type RefSchemaNode, type ResponseNode, type RootMeta, type RootNode, type ScalarSchemaNode, type ScalarSchemaType, type SchemaNode, type SchemaNodeByType, type SchemaType, type SpecialSchemaType, type StatusCode, type StringSchemaNode, type TimeSchemaNode, type UnionSchemaNode, type Visitor, type VisitorDepth };
|
|
@@ -143,7 +143,7 @@ type SchemaNodeBase = BaseNode & {
|
|
|
143
143
|
*/
|
|
144
144
|
type ObjectSchemaNode = SchemaNodeBase & {
|
|
145
145
|
type: 'object';
|
|
146
|
-
properties
|
|
146
|
+
properties: Array<PropertyNode>;
|
|
147
147
|
/**
|
|
148
148
|
* `true` allows any value; a `SchemaNode` constrains it; absent means not permitted.
|
|
149
149
|
*/
|
|
@@ -437,10 +437,18 @@ declare function createRoot(overrides?: Partial<Omit<RootNode, 'kind'>>): RootNo
|
|
|
437
437
|
declare function createOperation(props: Pick<OperationNode, 'operationId' | 'method' | 'path'> & Partial<Omit<OperationNode, 'kind' | 'operationId' | 'method' | 'path'>>): OperationNode;
|
|
438
438
|
/**
|
|
439
439
|
* Creates a `SchemaNode`, narrowed to the variant of `props.type`.
|
|
440
|
+
* For object schemas, `properties` defaults to `[]` when not provided.
|
|
440
441
|
*/
|
|
441
|
-
declare function createSchema<T extends
|
|
442
|
+
declare function createSchema<T extends Omit<ObjectSchemaNode, 'kind' | 'properties'> & {
|
|
443
|
+
properties?: Array<PropertyNode>;
|
|
444
|
+
}>(props: T): Omit<T, 'properties'> & {
|
|
445
|
+
properties: Array<PropertyNode>;
|
|
442
446
|
kind: 'Schema';
|
|
443
447
|
};
|
|
448
|
+
declare function createSchema<T extends DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>>(props: T): T & {
|
|
449
|
+
kind: 'Schema';
|
|
450
|
+
};
|
|
451
|
+
declare function createSchema(props: DistributiveOmit<SchemaNode, 'kind'>): SchemaNode;
|
|
444
452
|
/**
|
|
445
453
|
* Creates a `PropertyNode`. `required` defaults to `false`.
|
|
446
454
|
*/
|
|
@@ -454,6 +462,105 @@ declare function createParameter(props: Pick<ParameterNode, 'name' | 'in' | 'sch
|
|
|
454
462
|
*/
|
|
455
463
|
declare function createResponse(props: Pick<ResponseNode, 'statusCode'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode'>>): ResponseNode;
|
|
456
464
|
//#endregion
|
|
465
|
+
//#region src/printer.d.ts
|
|
466
|
+
/**
|
|
467
|
+
* Handler context for `definePrinter` — mirrors `PluginContext` from `@kubb/core`.
|
|
468
|
+
* Available as `this` inside each node handler.
|
|
469
|
+
*/
|
|
470
|
+
type PrinterHandlerContext<TOutput, TOptions extends object> = {
|
|
471
|
+
/**
|
|
472
|
+
* Recursively print a nested `SchemaNode`.
|
|
473
|
+
*/
|
|
474
|
+
print: (node: SchemaNode) => TOutput | null | undefined;
|
|
475
|
+
/**
|
|
476
|
+
* Options for this printer instance.
|
|
477
|
+
*/
|
|
478
|
+
options: TOptions;
|
|
479
|
+
};
|
|
480
|
+
/**
|
|
481
|
+
* Handler for a specific `SchemaNode` variant identified by `SchemaType` key `T`.
|
|
482
|
+
* Use a regular function (not an arrow function) so that `this` is available.
|
|
483
|
+
*/
|
|
484
|
+
type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (this: PrinterHandlerContext<TOutput, TOptions>, node: SchemaNodeByType[T]) => TOutput | null | undefined;
|
|
485
|
+
/**
|
|
486
|
+
* Shape of the type parameter passed to `definePrinter`.
|
|
487
|
+
* Mirrors `AdapterFactoryOptions` / `PluginFactoryOptions` from `@kubb/core`.
|
|
488
|
+
*
|
|
489
|
+
* - `TName` — unique string identifier (e.g. `'zod'`, `'ts'`)
|
|
490
|
+
* - `TOptions` — options passed to and stored on the printer
|
|
491
|
+
* - `TOutput` — the type emitted by `print` (typically `string`)
|
|
492
|
+
*/
|
|
493
|
+
type PrinterFactoryOptions<TName extends string = string, TOptions extends object = object, TOutput = unknown> = {
|
|
494
|
+
name: TName;
|
|
495
|
+
options: TOptions;
|
|
496
|
+
output: TOutput;
|
|
497
|
+
};
|
|
498
|
+
/**
|
|
499
|
+
* The object returned by calling a `definePrinter` instance.
|
|
500
|
+
* Mirrors the shape of `Adapter` from `@kubb/core`.
|
|
501
|
+
*/
|
|
502
|
+
type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {
|
|
503
|
+
/**
|
|
504
|
+
* Unique identifier supplied at creation time.
|
|
505
|
+
*/
|
|
506
|
+
name: T['name'];
|
|
507
|
+
/**
|
|
508
|
+
* Options for this printer instance.
|
|
509
|
+
*/
|
|
510
|
+
options: T['options'];
|
|
511
|
+
/**
|
|
512
|
+
* Emits `TOutput` from a `SchemaNode`. Returns `null | undefined` when no handler matches.
|
|
513
|
+
*/
|
|
514
|
+
print: (node: SchemaNode) => T['output'] | null | undefined;
|
|
515
|
+
/**
|
|
516
|
+
* Maps `print` over an array of `SchemaNode`s.
|
|
517
|
+
*/
|
|
518
|
+
for: (nodes: Array<SchemaNode>) => Array<T['output'] | null | undefined>;
|
|
519
|
+
};
|
|
520
|
+
type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) => {
|
|
521
|
+
name: T['name'];
|
|
522
|
+
/**
|
|
523
|
+
* Options to store on the printer.
|
|
524
|
+
*/
|
|
525
|
+
options: T['options'];
|
|
526
|
+
nodes: Partial<{ [K in SchemaType]: PrinterHandler<T['output'], T['options'], K> }>;
|
|
527
|
+
};
|
|
528
|
+
/**
|
|
529
|
+
* Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern
|
|
530
|
+
* from `@kubb/core` — wraps a builder to make options optional and separates raw options
|
|
531
|
+
* from resolved options.
|
|
532
|
+
*
|
|
533
|
+
* @example
|
|
534
|
+
* ```ts
|
|
535
|
+
* type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>
|
|
536
|
+
*
|
|
537
|
+
* export const zodPrinter = definePrinter<ZodPrinter>((options) => {
|
|
538
|
+
* const { strict = true } = options
|
|
539
|
+
* return {
|
|
540
|
+
* name: 'zod',
|
|
541
|
+
* options: { strict },
|
|
542
|
+
* nodes: {
|
|
543
|
+
* string(node) {
|
|
544
|
+
* return `z.string()`
|
|
545
|
+
* },
|
|
546
|
+
* object(node) {
|
|
547
|
+
* const props = node.properties
|
|
548
|
+
* ?.map(p => `${p.name}: ${this.print(p)}`)
|
|
549
|
+
* .join(', ') ?? ''
|
|
550
|
+
* return `z.object({ ${props} })`
|
|
551
|
+
* },
|
|
552
|
+
* },
|
|
553
|
+
* }
|
|
554
|
+
* })
|
|
555
|
+
*
|
|
556
|
+
* const printer = zodPrinter({ strict: false })
|
|
557
|
+
* printer.name // 'zod'
|
|
558
|
+
* printer.options // { strict: false }
|
|
559
|
+
* printer.print(node) // 'z.string()'
|
|
560
|
+
* ```
|
|
561
|
+
*/
|
|
562
|
+
declare function definePrinter<T extends PrinterFactoryOptions = PrinterFactoryOptions>(build: PrinterBuilder<T>): (options?: T['options']) => Printer<T>;
|
|
563
|
+
//#endregion
|
|
457
564
|
//#region src/refs.d.ts
|
|
458
565
|
/**
|
|
459
566
|
* Schema name to `SchemaNode` mapping.
|
|
@@ -478,6 +585,11 @@ declare function refMapToObject(refMap: RefMap): Record<string, SchemaNode>;
|
|
|
478
585
|
*/
|
|
479
586
|
type VisitorOptions = {
|
|
480
587
|
depth?: VisitorDepth;
|
|
588
|
+
/**
|
|
589
|
+
* Maximum number of sibling nodes visited concurrently inside `walk`.
|
|
590
|
+
* @default 30
|
|
591
|
+
*/
|
|
592
|
+
concurrency?: number;
|
|
481
593
|
};
|
|
482
594
|
/**
|
|
483
595
|
* Synchronous visitor for `transform` and `walk`.
|
|
@@ -515,6 +627,7 @@ type CollectVisitor<T> = {
|
|
|
515
627
|
};
|
|
516
628
|
/**
|
|
517
629
|
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
630
|
+
* Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
|
|
518
631
|
*/
|
|
519
632
|
declare function walk(node: Node, visitor: AsyncVisitor, options?: VisitorOptions): Promise<void>;
|
|
520
633
|
/**
|
|
@@ -532,5 +645,5 @@ declare function transform(node: Node, visitor: Visitor, options?: VisitorOption
|
|
|
532
645
|
*/
|
|
533
646
|
declare function collect<T>(node: Node, visitor: CollectVisitor<T>, options?: VisitorOptions): Array<T>;
|
|
534
647
|
//#endregion
|
|
535
|
-
export {
|
|
536
|
-
//# sourceMappingURL=visitor-
|
|
648
|
+
export { UnionSchemaNode as $, MediaType as A, IntersectionSchemaNode as B, Node as C, OperationNode as D, HttpMethod as E, ComplexSchemaType as F, ScalarSchemaNode as G, ObjectSchemaNode as H, DateSchemaNode as I, SchemaNodeByType as J, ScalarSchemaType as K, DatetimeSchemaNode as L, ParameterLocation as M, ParameterNode as N, ResponseNode as O, ArraySchemaNode as P, TimeSchemaNode as Q, EnumSchemaNode as R, createSchema as S, RootNode as T, PrimitiveSchemaType as U, NumberSchemaNode as V, RefSchemaNode as W, SpecialSchemaType as X, SchemaType as Y, StringSchemaNode as Z, createOperation as _, transform as a, mediaTypes as at, createResponse as b, buildRefMap as c, Printer as d, PropertyNode as et, PrinterFactoryOptions as f, DistributiveOmit as g, definePrinter as h, collect as i, httpMethods as it, StatusCode as j, HttpStatusCode as k, refMapToObject as l, PrinterHandlerContext as m, CollectVisitor as n, NodeKind as nt, walk as o, nodeKinds as ot, PrinterHandler as p, SchemaNode as q, Visitor as r, VisitorDepth as rt, RefMap as s, schemaTypes as st, AsyncVisitor as t, BaseNode as tt, resolveRef as u, createParameter as v, RootMeta as w, createRoot as x, createProperty as y, EnumValueNode as z };
|
|
649
|
+
//# sourceMappingURL=visitor-CmsfJzro.d.ts.map
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -76,6 +76,11 @@ export const parameterLocations = {
|
|
|
76
76
|
cookie: 'cookie',
|
|
77
77
|
} as const satisfies Record<ParameterLocation, ParameterLocation>
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Default max concurrent visitor calls in `walk`.
|
|
81
|
+
*/
|
|
82
|
+
export const WALK_CONCURRENCY = 30
|
|
83
|
+
|
|
79
84
|
/**
|
|
80
85
|
* Fallback status code string for API spec responses.
|
|
81
86
|
*/
|
package/src/factory.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'
|
|
1
|
+
import type { ObjectSchemaNode, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Distributive variant of `Omit` that preserves union members.
|
|
@@ -34,9 +34,19 @@ export function createOperation(
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Creates a `SchemaNode`, narrowed to the variant of `props.type`.
|
|
37
|
+
* For object schemas, `properties` defaults to `[]` when not provided.
|
|
37
38
|
*/
|
|
38
|
-
export function createSchema<T extends
|
|
39
|
-
|
|
39
|
+
export function createSchema<T extends Omit<ObjectSchemaNode, 'kind' | 'properties'> & { properties?: Array<PropertyNode> }>(
|
|
40
|
+
props: T,
|
|
41
|
+
): Omit<T, 'properties'> & { properties: Array<PropertyNode>; kind: 'Schema' }
|
|
42
|
+
export function createSchema<T extends DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>>(props: T): T & { kind: 'Schema' }
|
|
43
|
+
export function createSchema(props: DistributiveOmit<SchemaNode, 'kind'>): SchemaNode
|
|
44
|
+
export function createSchema(props: Record<string, unknown>): Record<string, unknown> {
|
|
45
|
+
if (props['type'] === 'object') {
|
|
46
|
+
return { properties: [], ...props, kind: 'Schema' }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { ...props, kind: 'Schema' }
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
/**
|
package/src/guards.ts
CHANGED
|
@@ -8,7 +8,7 @@ export function narrowSchema<T extends SchemaNode['type']>(node: SchemaNode | un
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
function isKind<T extends Node>(kind: NodeKind) {
|
|
11
|
-
return (node:
|
|
11
|
+
return (node: unknown): node is T => (node as Node).kind === kind
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { httpMethods, mediaTypes, nodeKinds, schemaTypes } from './constants.ts'
|
|
2
2
|
export { createOperation, createParameter, createProperty, createResponse, createRoot, createSchema } from './factory.ts'
|
|
3
3
|
export { isOperationNode, isParameterNode, isPropertyNode, isResponseNode, isRootNode, isSchemaNode, narrowSchema } from './guards.ts'
|
|
4
|
+
export { definePrinter } from './printer.ts'
|
|
4
5
|
export { buildRefMap, refMapToObject, resolveRef } from './refs.ts'
|
|
5
6
|
export { collect, transform, walk } from './visitor.ts'
|
package/src/nodes/schema.ts
CHANGED
|
@@ -50,7 +50,7 @@ type SchemaNodeBase = BaseNode & {
|
|
|
50
50
|
*/
|
|
51
51
|
export type ObjectSchemaNode = SchemaNodeBase & {
|
|
52
52
|
type: 'object'
|
|
53
|
-
properties
|
|
53
|
+
properties: Array<PropertyNode>
|
|
54
54
|
/**
|
|
55
55
|
* `true` allows any value; a `SchemaNode` constrains it; absent means not permitted.
|
|
56
56
|
*/
|
package/src/printer.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { SchemaNode, SchemaNodeByType, SchemaType } from './nodes/index.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler context for `definePrinter` — mirrors `PluginContext` from `@kubb/core`.
|
|
5
|
+
* Available as `this` inside each node handler.
|
|
6
|
+
*/
|
|
7
|
+
export type PrinterHandlerContext<TOutput, TOptions extends object> = {
|
|
8
|
+
/**
|
|
9
|
+
* Recursively print a nested `SchemaNode`.
|
|
10
|
+
*/
|
|
11
|
+
print: (node: SchemaNode) => TOutput | null | undefined
|
|
12
|
+
/**
|
|
13
|
+
* Options for this printer instance.
|
|
14
|
+
*/
|
|
15
|
+
options: TOptions
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handler for a specific `SchemaNode` variant identified by `SchemaType` key `T`.
|
|
20
|
+
* Use a regular function (not an arrow function) so that `this` is available.
|
|
21
|
+
*/
|
|
22
|
+
export type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (
|
|
23
|
+
this: PrinterHandlerContext<TOutput, TOptions>,
|
|
24
|
+
node: SchemaNodeByType[T],
|
|
25
|
+
) => TOutput | null | undefined
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Shape of the type parameter passed to `definePrinter`.
|
|
29
|
+
* Mirrors `AdapterFactoryOptions` / `PluginFactoryOptions` from `@kubb/core`.
|
|
30
|
+
*
|
|
31
|
+
* - `TName` — unique string identifier (e.g. `'zod'`, `'ts'`)
|
|
32
|
+
* - `TOptions` — options passed to and stored on the printer
|
|
33
|
+
* - `TOutput` — the type emitted by `print` (typically `string`)
|
|
34
|
+
*/
|
|
35
|
+
export type PrinterFactoryOptions<TName extends string = string, TOptions extends object = object, TOutput = unknown> = {
|
|
36
|
+
name: TName
|
|
37
|
+
options: TOptions
|
|
38
|
+
output: TOutput
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The object returned by calling a `definePrinter` instance.
|
|
43
|
+
* Mirrors the shape of `Adapter` from `@kubb/core`.
|
|
44
|
+
*/
|
|
45
|
+
export type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {
|
|
46
|
+
/**
|
|
47
|
+
* Unique identifier supplied at creation time.
|
|
48
|
+
*/
|
|
49
|
+
name: T['name']
|
|
50
|
+
/**
|
|
51
|
+
* Options for this printer instance.
|
|
52
|
+
*/
|
|
53
|
+
options: T['options']
|
|
54
|
+
/**
|
|
55
|
+
* Emits `TOutput` from a `SchemaNode`. Returns `null | undefined` when no handler matches.
|
|
56
|
+
*/
|
|
57
|
+
print: (node: SchemaNode) => T['output'] | null | undefined
|
|
58
|
+
/**
|
|
59
|
+
* Maps `print` over an array of `SchemaNode`s.
|
|
60
|
+
*/
|
|
61
|
+
for: (nodes: Array<SchemaNode>) => Array<T['output'] | null | undefined>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) => {
|
|
65
|
+
name: T['name']
|
|
66
|
+
/**
|
|
67
|
+
* Options to store on the printer.
|
|
68
|
+
*/
|
|
69
|
+
options: T['options']
|
|
70
|
+
nodes: Partial<{
|
|
71
|
+
[K in SchemaType]: PrinterHandler<T['output'], T['options'], K>
|
|
72
|
+
}>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern
|
|
77
|
+
* from `@kubb/core` — wraps a builder to make options optional and separates raw options
|
|
78
|
+
* from resolved options.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>
|
|
83
|
+
*
|
|
84
|
+
* export const zodPrinter = definePrinter<ZodPrinter>((options) => {
|
|
85
|
+
* const { strict = true } = options
|
|
86
|
+
* return {
|
|
87
|
+
* name: 'zod',
|
|
88
|
+
* options: { strict },
|
|
89
|
+
* nodes: {
|
|
90
|
+
* string(node) {
|
|
91
|
+
* return `z.string()`
|
|
92
|
+
* },
|
|
93
|
+
* object(node) {
|
|
94
|
+
* const props = node.properties
|
|
95
|
+
* ?.map(p => `${p.name}: ${this.print(p)}`)
|
|
96
|
+
* .join(', ') ?? ''
|
|
97
|
+
* return `z.object({ ${props} })`
|
|
98
|
+
* },
|
|
99
|
+
* },
|
|
100
|
+
* }
|
|
101
|
+
* })
|
|
102
|
+
*
|
|
103
|
+
* const printer = zodPrinter({ strict: false })
|
|
104
|
+
* printer.name // 'zod'
|
|
105
|
+
* printer.options // { strict: false }
|
|
106
|
+
* printer.print(node) // 'z.string()'
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export function definePrinter<T extends PrinterFactoryOptions = PrinterFactoryOptions>(build: PrinterBuilder<T>): (options?: T['options']) => Printer<T> {
|
|
110
|
+
return (options) => {
|
|
111
|
+
const { name, options: resolvedOptions, nodes } = build(options ?? ({} as T['options']))
|
|
112
|
+
|
|
113
|
+
const context: PrinterHandlerContext<T['output'], T['options']> = {
|
|
114
|
+
options: resolvedOptions,
|
|
115
|
+
print: (node: SchemaNode) => {
|
|
116
|
+
const type = node.type as SchemaType
|
|
117
|
+
const handler = nodes[type]
|
|
118
|
+
return handler ? (handler as PrinterHandler<T['output'], T['options']>).call(context, node as SchemaNodeByType[SchemaType]) : undefined
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
name,
|
|
124
|
+
options: resolvedOptions,
|
|
125
|
+
print: context.print,
|
|
126
|
+
for: (nodes) => nodes.map(context.print),
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -36,5 +36,6 @@ export type {
|
|
|
36
36
|
TimeSchemaNode,
|
|
37
37
|
UnionSchemaNode,
|
|
38
38
|
} from './nodes/index.ts'
|
|
39
|
+
export type { Printer, PrinterFactoryOptions, PrinterHandler, PrinterHandlerContext } from './printer.ts'
|
|
39
40
|
export type { RefMap } from './refs.ts'
|
|
40
|
-
export type { AsyncVisitor, CollectVisitor, Visitor
|
|
41
|
+
export type { AsyncVisitor, CollectVisitor, Visitor } from './visitor.ts'
|
package/src/visitor.ts
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
1
|
import type { VisitorDepth } from './constants.ts'
|
|
2
|
-
import { visitorDepths } from './constants.ts'
|
|
2
|
+
import { visitorDepths, WALK_CONCURRENCY } from './constants.ts'
|
|
3
3
|
import type { Node, OperationNode, ParameterNode, PropertyNode, ResponseNode, RootNode, SchemaNode } from './nodes/index.ts'
|
|
4
4
|
|
|
5
|
+
function createLimit(concurrency: number) {
|
|
6
|
+
let active = 0
|
|
7
|
+
const queue: Array<() => void> = []
|
|
8
|
+
|
|
9
|
+
function next() {
|
|
10
|
+
if (active < concurrency && queue.length > 0) {
|
|
11
|
+
active++
|
|
12
|
+
queue.shift()!()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return function limit<T>(fn: () => Promise<T> | T): Promise<T> {
|
|
17
|
+
return new Promise<T>((resolve, reject) => {
|
|
18
|
+
queue.push(() => {
|
|
19
|
+
Promise.resolve(fn())
|
|
20
|
+
.then(resolve, reject)
|
|
21
|
+
.finally(() => {
|
|
22
|
+
active--
|
|
23
|
+
next()
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
next()
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type LimitFn = ReturnType<typeof createLimit>
|
|
32
|
+
|
|
5
33
|
/**
|
|
6
34
|
* Shared options for `walk`, `transform`, and `collect`.
|
|
7
35
|
*/
|
|
8
36
|
export type VisitorOptions = {
|
|
9
37
|
depth?: VisitorDepth
|
|
38
|
+
/**
|
|
39
|
+
* Maximum number of sibling nodes visited concurrently inside `walk`.
|
|
40
|
+
* @default 30
|
|
41
|
+
*/
|
|
42
|
+
concurrency?: number
|
|
10
43
|
}
|
|
11
44
|
|
|
12
45
|
/**
|
|
@@ -61,7 +94,7 @@ function getChildren(node: Node, recurse: boolean): Array<Node> {
|
|
|
61
94
|
|
|
62
95
|
if (!recurse) return []
|
|
63
96
|
|
|
64
|
-
if ('properties' in node && node.properties) children.push(...node.properties)
|
|
97
|
+
if ('properties' in node && node.properties.length > 0) children.push(...node.properties)
|
|
65
98
|
if ('items' in node && node.items) children.push(...node.items)
|
|
66
99
|
if ('members' in node && node.members) children.push(...node.members)
|
|
67
100
|
|
|
@@ -78,34 +111,38 @@ function getChildren(node: Node, recurse: boolean): Array<Node> {
|
|
|
78
111
|
|
|
79
112
|
/**
|
|
80
113
|
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
114
|
+
* Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
|
|
81
115
|
*/
|
|
82
116
|
export async function walk(node: Node, visitor: AsyncVisitor, options: VisitorOptions = {}): Promise<void> {
|
|
83
117
|
const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep
|
|
118
|
+
const limit = createLimit(options.concurrency ?? WALK_CONCURRENCY)
|
|
119
|
+
return _walk(node, visitor, recurse, limit)
|
|
120
|
+
}
|
|
84
121
|
|
|
122
|
+
async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit: LimitFn): Promise<void> {
|
|
85
123
|
switch (node.kind) {
|
|
86
124
|
case 'Root':
|
|
87
|
-
await visitor.root?.(node)
|
|
125
|
+
await limit(() => visitor.root?.(node))
|
|
88
126
|
break
|
|
89
127
|
case 'Operation':
|
|
90
|
-
await visitor.operation?.(node)
|
|
128
|
+
await limit(() => visitor.operation?.(node))
|
|
91
129
|
break
|
|
92
130
|
case 'Schema':
|
|
93
|
-
await visitor.schema?.(node)
|
|
131
|
+
await limit(() => visitor.schema?.(node))
|
|
94
132
|
break
|
|
95
133
|
case 'Property':
|
|
96
|
-
await visitor.property?.(node)
|
|
134
|
+
await limit(() => visitor.property?.(node))
|
|
97
135
|
break
|
|
98
136
|
case 'Parameter':
|
|
99
|
-
await visitor.parameter?.(node)
|
|
137
|
+
await limit(() => visitor.parameter?.(node))
|
|
100
138
|
break
|
|
101
139
|
case 'Response':
|
|
102
|
-
await visitor.response?.(node)
|
|
140
|
+
await limit(() => visitor.response?.(node))
|
|
103
141
|
break
|
|
104
142
|
}
|
|
105
143
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
144
|
+
const children = getChildren(node, recurse)
|
|
145
|
+
await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)))
|
|
109
146
|
}
|
|
110
147
|
|
|
111
148
|
/**
|
|
@@ -152,7 +189,7 @@ export function transform(node: Node, visitor: Visitor, options: VisitorOptions
|
|
|
152
189
|
|
|
153
190
|
return {
|
|
154
191
|
...schema,
|
|
155
|
-
...('properties' in schema && recurse ? { properties: schema.properties
|
|
192
|
+
...('properties' in schema && recurse ? { properties: schema.properties.map((p) => transform(p, visitor, options)) } : {}),
|
|
156
193
|
...('items' in schema && recurse ? { items: schema.items?.map((i) => transform(i, visitor, options)) } : {}),
|
|
157
194
|
...('members' in schema && recurse ? { members: schema.members?.map((m) => transform(m, visitor, options)) } : {}),
|
|
158
195
|
}
|