@kubb/ast 4.34.0 → 4.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -169,6 +169,63 @@ const isParameterNode = isKind("Parameter");
169
169
  */
170
170
  const isResponseNode = isKind("Response");
171
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
+ function print(node) {
211
+ const handler = nodes[node.type];
212
+ if (handler) {
213
+ const context = {
214
+ print,
215
+ options: resolvedOptions
216
+ };
217
+ return handler.call(context, node);
218
+ }
219
+ }
220
+ return {
221
+ name,
222
+ options: resolvedOptions,
223
+ print,
224
+ for: (nodes) => nodes.map(print)
225
+ };
226
+ };
227
+ }
228
+ //#endregion
172
229
  //#region src/refs.ts
173
230
  /**
174
231
  * Indexes named schemas from `root.schemas` by name. Unnamed schemas are skipped.
@@ -192,6 +249,27 @@ function refMapToObject(refMap) {
192
249
  }
193
250
  //#endregion
194
251
  //#region src/visitor.ts
252
+ function createLimit(concurrency) {
253
+ let active = 0;
254
+ const queue = [];
255
+ function next() {
256
+ if (active < concurrency && queue.length > 0) {
257
+ active++;
258
+ queue.shift()();
259
+ }
260
+ }
261
+ return function limit(fn) {
262
+ return new Promise((resolve, reject) => {
263
+ queue.push(() => {
264
+ Promise.resolve(fn()).then(resolve, reject).finally(() => {
265
+ active--;
266
+ next();
267
+ });
268
+ });
269
+ next();
270
+ });
271
+ };
272
+ }
195
273
  /**
196
274
  * Traversable children of `node`, respecting `recurse` for schema nodes.
197
275
  */
@@ -218,30 +296,34 @@ function getChildren(node, recurse) {
218
296
  }
219
297
  /**
220
298
  * Depth-first traversal for side effects. Visitor return values are ignored.
299
+ * Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
221
300
  */
222
301
  async function walk(node, visitor, options = {}) {
223
- const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep;
302
+ return _walk(node, visitor, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30));
303
+ }
304
+ async function _walk(node, visitor, recurse, limit) {
224
305
  switch (node.kind) {
225
306
  case "Root":
226
- await visitor.root?.(node);
307
+ await limit(() => visitor.root?.(node));
227
308
  break;
228
309
  case "Operation":
229
- await visitor.operation?.(node);
310
+ await limit(() => visitor.operation?.(node));
230
311
  break;
231
312
  case "Schema":
232
- await visitor.schema?.(node);
313
+ await limit(() => visitor.schema?.(node));
233
314
  break;
234
315
  case "Property":
235
- await visitor.property?.(node);
316
+ await limit(() => visitor.property?.(node));
236
317
  break;
237
318
  case "Parameter":
238
- await visitor.parameter?.(node);
319
+ await limit(() => visitor.parameter?.(node));
239
320
  break;
240
321
  case "Response":
241
- await visitor.response?.(node);
322
+ await limit(() => visitor.response?.(node));
242
323
  break;
243
324
  }
244
- for (const child of getChildren(node, recurse)) await walk(child, visitor, options);
325
+ const children = getChildren(node, recurse);
326
+ await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)));
245
327
  }
246
328
  function transform(node, visitor, options = {}) {
247
329
  const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep;
@@ -347,6 +429,7 @@ exports.createProperty = createProperty;
347
429
  exports.createResponse = createResponse;
348
430
  exports.createRoot = createRoot;
349
431
  exports.createSchema = createSchema;
432
+ exports.definePrinter = definePrinter;
350
433
  exports.httpMethods = httpMethods;
351
434
  exports.isOperationNode = isOperationNode;
352
435
  exports.isParameterNode = isParameterNode;
@@ -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":";;;;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.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 { 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: 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 function print(node: SchemaNode): T['output'] | null | undefined {\n const type = node.type as SchemaType\n\n const handler = nodes[type]\n if (handler) {\n const context: PrinterHandlerContext<T['output'], T['options']> = { print, options: resolvedOptions }\n return (handler as PrinterHandler<T['output'], T['options']>).call(context, node as SchemaNodeByType[SchemaType])\n }\n\n return undefined\n }\n\n return { name, options: resolvedOptions, print, for: (nodes) => nodes.map(print) }\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) 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 { C as OperationNode, U as SchemaNode, W as SchemaNodeByType, X as PropertyNode, _ as createRoot, a as collect, d as resolveRef, et as httpMethods, g as createResponse, h as createProperty, k as ParameterNode, l as buildRefMap, m as createParameter, nt as nodeKinds, o as transform, p as createOperation, rt as schemaTypes, s as walk, tt as mediaTypes, u as refMapToObject, v as createSchema, w as ResponseNode, x as RootNode, y as Node } from "./visitor-DRohZSfu.js";
2
+ import { A as ParameterNode, G as SchemaNodeByType, S as RootNode, T as ResponseNode, W as SchemaNode, Z as PropertyNode, _ as createResponse, a as transform, c as buildRefMap, f as definePrinter, g as createProperty, h as createParameter, i as collect, it as schemaTypes, l as refMapToObject, m as createOperation, nt as mediaTypes, o as walk, rt as nodeKinds, tt as httpMethods, u as resolveRef, v as createRoot, w as OperationNode, y as createSchema } from "./visitor-8N3AiSUr.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: Node) => node is RootNode;
12
+ declare const isRootNode: (node: unknown) => node is RootNode;
13
13
  /**
14
14
  * Type guard for `OperationNode`.
15
15
  */
16
- declare const isOperationNode: (node: Node) => node is OperationNode;
16
+ declare const isOperationNode: (node: unknown) => node is OperationNode;
17
17
  /**
18
18
  * Type guard for `SchemaNode`.
19
19
  */
20
- declare const isSchemaNode: (node: Node) => node is SchemaNode;
20
+ declare const isSchemaNode: (node: unknown) => node is SchemaNode;
21
21
  /**
22
22
  * Type guard for `PropertyNode`.
23
23
  */
24
- declare const isPropertyNode: (node: Node) => node is PropertyNode;
24
+ declare const isPropertyNode: (node: unknown) => node is PropertyNode;
25
25
  /**
26
26
  * Type guard for `ParameterNode`.
27
27
  */
28
- declare const isParameterNode: (node: Node) => node is ParameterNode;
28
+ declare const isParameterNode: (node: unknown) => node is ParameterNode;
29
29
  /**
30
30
  * Type guard for `ResponseNode`.
31
31
  */
32
- declare const isResponseNode: (node: Node) => node is ResponseNode;
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
@@ -167,6 +167,63 @@ const isParameterNode = isKind("Parameter");
167
167
  */
168
168
  const isResponseNode = isKind("Response");
169
169
  //#endregion
170
+ //#region src/printer.ts
171
+ /**
172
+ * Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern
173
+ * from `@kubb/core` — wraps a builder to make options optional and separates raw options
174
+ * from resolved options.
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>
179
+ *
180
+ * export const zodPrinter = definePrinter<ZodPrinter>((options) => {
181
+ * const { strict = true } = options
182
+ * return {
183
+ * name: 'zod',
184
+ * options: { strict },
185
+ * nodes: {
186
+ * string(node) {
187
+ * return `z.string()`
188
+ * },
189
+ * object(node) {
190
+ * const props = node.properties
191
+ * ?.map(p => `${p.name}: ${this.print(p)}`)
192
+ * .join(', ') ?? ''
193
+ * return `z.object({ ${props} })`
194
+ * },
195
+ * },
196
+ * }
197
+ * })
198
+ *
199
+ * const printer = zodPrinter({ strict: false })
200
+ * printer.name // 'zod'
201
+ * printer.options // { strict: false }
202
+ * printer.print(node) // 'z.string()'
203
+ * ```
204
+ */
205
+ function definePrinter(build) {
206
+ return (options) => {
207
+ const { name, options: resolvedOptions, nodes } = build(options ?? {});
208
+ function print(node) {
209
+ const handler = nodes[node.type];
210
+ if (handler) {
211
+ const context = {
212
+ print,
213
+ options: resolvedOptions
214
+ };
215
+ return handler.call(context, node);
216
+ }
217
+ }
218
+ return {
219
+ name,
220
+ options: resolvedOptions,
221
+ print,
222
+ for: (nodes) => nodes.map(print)
223
+ };
224
+ };
225
+ }
226
+ //#endregion
170
227
  //#region src/refs.ts
171
228
  /**
172
229
  * Indexes named schemas from `root.schemas` by name. Unnamed schemas are skipped.
@@ -190,6 +247,27 @@ function refMapToObject(refMap) {
190
247
  }
191
248
  //#endregion
192
249
  //#region src/visitor.ts
250
+ function createLimit(concurrency) {
251
+ let active = 0;
252
+ const queue = [];
253
+ function next() {
254
+ if (active < concurrency && queue.length > 0) {
255
+ active++;
256
+ queue.shift()();
257
+ }
258
+ }
259
+ return function limit(fn) {
260
+ return new Promise((resolve, reject) => {
261
+ queue.push(() => {
262
+ Promise.resolve(fn()).then(resolve, reject).finally(() => {
263
+ active--;
264
+ next();
265
+ });
266
+ });
267
+ next();
268
+ });
269
+ };
270
+ }
193
271
  /**
194
272
  * Traversable children of `node`, respecting `recurse` for schema nodes.
195
273
  */
@@ -216,30 +294,34 @@ function getChildren(node, recurse) {
216
294
  }
217
295
  /**
218
296
  * Depth-first traversal for side effects. Visitor return values are ignored.
297
+ * Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
219
298
  */
220
299
  async function walk(node, visitor, options = {}) {
221
- const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep;
300
+ return _walk(node, visitor, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30));
301
+ }
302
+ async function _walk(node, visitor, recurse, limit) {
222
303
  switch (node.kind) {
223
304
  case "Root":
224
- await visitor.root?.(node);
305
+ await limit(() => visitor.root?.(node));
225
306
  break;
226
307
  case "Operation":
227
- await visitor.operation?.(node);
308
+ await limit(() => visitor.operation?.(node));
228
309
  break;
229
310
  case "Schema":
230
- await visitor.schema?.(node);
311
+ await limit(() => visitor.schema?.(node));
231
312
  break;
232
313
  case "Property":
233
- await visitor.property?.(node);
314
+ await limit(() => visitor.property?.(node));
234
315
  break;
235
316
  case "Parameter":
236
- await visitor.parameter?.(node);
317
+ await limit(() => visitor.parameter?.(node));
237
318
  break;
238
319
  case "Response":
239
- await visitor.response?.(node);
320
+ await limit(() => visitor.response?.(node));
240
321
  break;
241
322
  }
242
- for (const child of getChildren(node, recurse)) await walk(child, visitor, options);
323
+ const children = getChildren(node, recurse);
324
+ await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit)));
243
325
  }
244
326
  function transform(node, visitor, options = {}) {
245
327
  const recurse = (options.depth ?? visitorDepths.deep) === visitorDepths.deep;
@@ -337,6 +419,6 @@ function collect(node, visitor, options = {}) {
337
419
  return results;
338
420
  }
339
421
  //#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 };
422
+ 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
423
 
342
424
  //# 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":"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"}
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 { 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: 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 function print(node: SchemaNode): T['output'] | null | undefined {\n const type = node.type as SchemaType\n\n const handler = nodes[type]\n if (handler) {\n const context: PrinterHandlerContext<T['output'], T['options']> = { print, options: resolvedOptions }\n return (handler as PrinterHandler<T['output'], T['options']>).call(context, node as SchemaNodeByType[SchemaType])\n }\n\n return undefined\n }\n\n return { name, options: resolvedOptions, print, for: (nodes) => nodes.map(print) }\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) 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 VisitorDepth, A as ArraySchemaNode, B as RefSchemaNode, C as OperationNode, D as StatusCode, E as MediaType, F as EnumValueNode, G as SchemaType, H as ScalarSchemaType, I as IntersectionSchemaNode, J as TimeSchemaNode, K as SpecialSchemaType, L as NumberSchemaNode, M as DateSchemaNode, N as DatetimeSchemaNode, O as ParameterLocation, P as EnumSchemaNode, Q as NodeKind, R as ObjectSchemaNode, S as HttpMethod, T as HttpStatusCode, U as SchemaNode, V as ScalarSchemaNode, W as SchemaNodeByType, X as PropertyNode, Y as UnionSchemaNode, Z as BaseNode, b as RootMeta, c as RefMap, f as DistributiveOmit, i as VisitorOptions, j as ComplexSchemaType, k as ParameterNode, n as CollectVisitor, q as StringSchemaNode, r as Visitor, t as AsyncVisitor, w as ResponseNode, x as RootNode, y as Node, z as PrimitiveSchemaType } from "./visitor-DRohZSfu.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 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, type VisitorOptions };
1
+ import { $ as NodeKind, A as ParameterNode, B as PrimitiveSchemaType, C as HttpMethod, D as MediaType, E as HttpStatusCode, F as EnumSchemaNode, G as SchemaNodeByType, H as ScalarSchemaNode, I as EnumValueNode, J as StringSchemaNode, K as SchemaType, L as IntersectionSchemaNode, M as ComplexSchemaType, N as DateSchemaNode, O as StatusCode, P as DatetimeSchemaNode, Q as BaseNode, R as NumberSchemaNode, S as RootNode, T as ResponseNode, U as ScalarSchemaType, V as RefSchemaNode, W as SchemaNode, X as UnionSchemaNode, Y as TimeSchemaNode, Z as PropertyNode, b as Node, d as Printer, et as VisitorDepth, j as ArraySchemaNode, k as ParameterLocation, n as CollectVisitor, p as DistributiveOmit, q as SpecialSchemaType, r as Visitor, s as RefMap, t as AsyncVisitor, w as OperationNode, x as RootMeta, z as ObjectSchemaNode } from "./visitor-8N3AiSUr.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 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 };
@@ -454,6 +454,105 @@ declare function createParameter(props: Pick<ParameterNode, 'name' | 'in' | 'sch
454
454
  */
455
455
  declare function createResponse(props: Pick<ResponseNode, 'statusCode'> & Partial<Omit<ResponseNode, 'kind' | 'statusCode'>>): ResponseNode;
456
456
  //#endregion
457
+ //#region src/printer.d.ts
458
+ /**
459
+ * Handler context for `definePrinter` — mirrors `PluginContext` from `@kubb/core`.
460
+ * Available as `this` inside each node handler.
461
+ */
462
+ type PrinterHandlerContext<TOutput, TOptions extends object> = {
463
+ /**
464
+ * Recursively print a nested `SchemaNode`.
465
+ */
466
+ print: (node: SchemaNode) => TOutput | null | undefined;
467
+ /**
468
+ * Options for this printer instance.
469
+ */
470
+ options: TOptions;
471
+ };
472
+ /**
473
+ * Handler for a specific `SchemaNode` variant identified by `SchemaType` key `T`.
474
+ * Use a regular function (not an arrow function) so that `this` is available.
475
+ */
476
+ type PrinterHandler<TOutput, TOptions extends object, T extends SchemaType = SchemaType> = (this: PrinterHandlerContext<TOutput, TOptions>, node: SchemaNodeByType[T]) => TOutput | null | undefined;
477
+ /**
478
+ * Shape of the type parameter passed to `definePrinter`.
479
+ * Mirrors `AdapterFactoryOptions` / `PluginFactoryOptions` from `@kubb/core`.
480
+ *
481
+ * - `TName` — unique string identifier (e.g. `'zod'`, `'ts'`)
482
+ * - `TOptions` — options passed to and stored on the printer
483
+ * - `TOutput` — the type emitted by `print` (typically `string`)
484
+ */
485
+ type PrinterFactoryOptions<TName extends string = string, TOptions extends object = object, TOutput = unknown> = {
486
+ name: TName;
487
+ options: TOptions;
488
+ output: TOutput;
489
+ };
490
+ /**
491
+ * The object returned by calling a `definePrinter` instance.
492
+ * Mirrors the shape of `Adapter` from `@kubb/core`.
493
+ */
494
+ type Printer<T extends PrinterFactoryOptions = PrinterFactoryOptions> = {
495
+ /**
496
+ * Unique identifier supplied at creation time.
497
+ */
498
+ name: T['name'];
499
+ /**
500
+ * Options for this printer instance.
501
+ */
502
+ options: T['options'];
503
+ /**
504
+ * Emits `TOutput` from a `SchemaNode`. Returns `null | undefined` when no handler matches.
505
+ */
506
+ print: (node: SchemaNode) => T['output'] | null | undefined;
507
+ /**
508
+ * Maps `print` over an array of `SchemaNode`s.
509
+ */
510
+ for: (nodes: Array<SchemaNode>) => Array<T['output'] | null | undefined>;
511
+ };
512
+ type PrinterBuilder<T extends PrinterFactoryOptions> = (options: T['options']) => {
513
+ name: T['name'];
514
+ /**
515
+ * Options to store on the printer.
516
+ */
517
+ options: T['options'];
518
+ nodes: Partial<{ [K in SchemaType]: PrinterHandler<T['output'], T['options'], K> }>;
519
+ };
520
+ /**
521
+ * Creates a named printer factory. Mirrors the `definePlugin` / `defineAdapter` pattern
522
+ * from `@kubb/core` — wraps a builder to make options optional and separates raw options
523
+ * from resolved options.
524
+ *
525
+ * @example
526
+ * ```ts
527
+ * type ZodPrinter = PrinterFactoryOptions<'zod', { strict?: boolean }, { strict: boolean }, string>
528
+ *
529
+ * export const zodPrinter = definePrinter<ZodPrinter>((options) => {
530
+ * const { strict = true } = options
531
+ * return {
532
+ * name: 'zod',
533
+ * options: { strict },
534
+ * nodes: {
535
+ * string(node) {
536
+ * return `z.string()`
537
+ * },
538
+ * object(node) {
539
+ * const props = node.properties
540
+ * ?.map(p => `${p.name}: ${this.print(p)}`)
541
+ * .join(', ') ?? ''
542
+ * return `z.object({ ${props} })`
543
+ * },
544
+ * },
545
+ * }
546
+ * })
547
+ *
548
+ * const printer = zodPrinter({ strict: false })
549
+ * printer.name // 'zod'
550
+ * printer.options // { strict: false }
551
+ * printer.print(node) // 'z.string()'
552
+ * ```
553
+ */
554
+ declare function definePrinter<T extends PrinterFactoryOptions = PrinterFactoryOptions>(build: PrinterBuilder<T>): (options?: T['options']) => Printer<T>;
555
+ //#endregion
457
556
  //#region src/refs.d.ts
458
557
  /**
459
558
  * Schema name to `SchemaNode` mapping.
@@ -478,6 +577,11 @@ declare function refMapToObject(refMap: RefMap): Record<string, SchemaNode>;
478
577
  */
479
578
  type VisitorOptions = {
480
579
  depth?: VisitorDepth;
580
+ /**
581
+ * Maximum number of sibling nodes visited concurrently inside `walk`.
582
+ * @default 30
583
+ */
584
+ concurrency?: number;
481
585
  };
482
586
  /**
483
587
  * Synchronous visitor for `transform` and `walk`.
@@ -515,6 +619,7 @@ type CollectVisitor<T> = {
515
619
  };
516
620
  /**
517
621
  * Depth-first traversal for side effects. Visitor return values are ignored.
622
+ * Sibling nodes at each level are visited concurrently up to `options.concurrency` (default: 30).
518
623
  */
519
624
  declare function walk(node: Node, visitor: AsyncVisitor, options?: VisitorOptions): Promise<void>;
520
625
  /**
@@ -532,5 +637,5 @@ declare function transform(node: Node, visitor: Visitor, options?: VisitorOption
532
637
  */
533
638
  declare function collect<T>(node: Node, visitor: CollectVisitor<T>, options?: VisitorOptions): Array<T>;
534
639
  //#endregion
535
- export { VisitorDepth as $, ArraySchemaNode as A, RefSchemaNode as B, OperationNode as C, StatusCode as D, MediaType as E, EnumValueNode as F, SchemaType as G, ScalarSchemaType as H, IntersectionSchemaNode as I, TimeSchemaNode as J, SpecialSchemaType as K, NumberSchemaNode as L, DateSchemaNode as M, DatetimeSchemaNode as N, ParameterLocation as O, EnumSchemaNode as P, NodeKind as Q, ObjectSchemaNode as R, HttpMethod as S, HttpStatusCode as T, SchemaNode as U, ScalarSchemaNode as V, SchemaNodeByType as W, PropertyNode as X, UnionSchemaNode as Y, BaseNode as Z, createRoot as _, collect as a, RootMeta as b, RefMap as c, resolveRef as d, httpMethods as et, DistributiveOmit as f, createResponse as g, createProperty as h, VisitorOptions as i, ComplexSchemaType as j, ParameterNode as k, buildRefMap as l, createParameter as m, CollectVisitor as n, nodeKinds as nt, transform as o, createOperation as p, StringSchemaNode as q, Visitor as r, schemaTypes as rt, walk as s, AsyncVisitor as t, mediaTypes as tt, refMapToObject as u, createSchema as v, ResponseNode as w, RootNode as x, Node as y, PrimitiveSchemaType as z };
536
- //# sourceMappingURL=visitor-DRohZSfu.d.ts.map
640
+ export { NodeKind as $, ParameterNode as A, PrimitiveSchemaType as B, HttpMethod as C, MediaType as D, HttpStatusCode as E, EnumSchemaNode as F, SchemaNodeByType as G, ScalarSchemaNode as H, EnumValueNode as I, StringSchemaNode as J, SchemaType as K, IntersectionSchemaNode as L, ComplexSchemaType as M, DateSchemaNode as N, StatusCode as O, DatetimeSchemaNode as P, BaseNode as Q, NumberSchemaNode as R, RootNode as S, ResponseNode as T, ScalarSchemaType as U, RefSchemaNode as V, SchemaNode as W, UnionSchemaNode as X, TimeSchemaNode as Y, PropertyNode as Z, createResponse as _, transform as a, Node as b, buildRefMap as c, Printer as d, VisitorDepth as et, definePrinter as f, createProperty as g, createParameter as h, collect as i, schemaTypes as it, ArraySchemaNode as j, ParameterLocation as k, refMapToObject as l, createOperation as m, CollectVisitor as n, mediaTypes as nt, walk as o, DistributiveOmit as p, SpecialSchemaType as q, Visitor as r, nodeKinds as rt, RefMap as s, AsyncVisitor as t, httpMethods as tt, resolveRef as u, createRoot as v, OperationNode as w, RootMeta as x, createSchema as y, ObjectSchemaNode as z };
641
+ //# sourceMappingURL=visitor-8N3AiSUr.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/ast",
3
- "version": "4.34.0",
3
+ "version": "4.35.0",
4
4
  "description": "Spec-agnostic AST layer for Kubb. Defines nodes, visitor pattern, and factory functions used across codegen plugins.",
5
5
  "keywords": [
6
6
  "kubb",
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/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: Node): node is T => node.kind === kind
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/printer.ts ADDED
@@ -0,0 +1,127 @@
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
+ function print(node: SchemaNode): T['output'] | null | undefined {
114
+ const type = node.type as SchemaType
115
+
116
+ const handler = nodes[type]
117
+ if (handler) {
118
+ const context: PrinterHandlerContext<T['output'], T['options']> = { print, options: resolvedOptions }
119
+ return (handler as PrinterHandler<T['output'], T['options']>).call(context, node as SchemaNodeByType[SchemaType])
120
+ }
121
+
122
+ return undefined
123
+ }
124
+
125
+ return { name, options: resolvedOptions, print, for: (nodes) => nodes.map(print) }
126
+ }
127
+ }
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 } from './printer.ts'
39
40
  export type { RefMap } from './refs.ts'
40
- export type { AsyncVisitor, CollectVisitor, Visitor, VisitorOptions } from './visitor.ts'
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
  /**
@@ -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
- for (const child of getChildren(node, recurse)) {
107
- await walk(child, visitor, options)
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
  /**