🚀. Socket Launch Week Day 2:Introducing Manifest Alerts.Learn more
Sign In

@kubb/ast

Package Overview
Dependencies
Maintainers
1
Versions
167
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kubb/ast - npm Package Compare versions

Comparing version
5.0.0-beta.56
to
5.0.0-beta.57
dist/types-C5aVnRE1.d.ts

Sorry, the diff of this file is too big to display

+128
import type { BaseNode, NodeKind } from './nodes/base.ts'
import type { SchemaNode } from './nodes/index.ts'
/**
* Visitor callback names, one per traversable node kind. Kept in sync with the
* keys of `Visitor` in `visitor.ts`.
*/
type VisitorKey = 'input' | 'output' | 'operation' | 'schema' | 'property' | 'parameter' | 'response'
/**
* Distributive `Omit` that preserves each member of a union.
*
* @example
* ```ts
* type A = { kind: 'a'; keep: string; drop: number }
* type B = { kind: 'b'; keep: boolean; drop: number }
* type Result = DistributiveOmit<A | B, 'drop'>
* // -> { kind: 'a'; keep: string } | { kind: 'b'; keep: boolean }
* ```
*/
export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never
/**
* Builds a type guard that matches nodes of the given `kind`.
*/
export function isKind<T extends BaseNode>(kind: NodeKind) {
return (node: unknown): node is T => (node as BaseNode).kind === kind
}
/**
* Updates a schema's `optional` and `nullish` flags from a parent's `required`
* value and the schema's own `nullable`. Mirrors how OpenAPI parameters and
* object properties combine "required" and "nullable" into a single AST.
*
* - Non-required + non-nullable → `optional: true`.
* - Non-required + nullable → `nullish: true`.
* - Required → both flags cleared.
*/
export function syncOptionality(schema: SchemaNode, required: boolean): SchemaNode {
const nullable = schema.nullable ?? false
return {
...schema,
optional: !required && !nullable ? true : undefined,
nullish: !required && nullable ? true : undefined,
}
}
/**
* The single definition derived from one {@link defineNode} call: the node's
* `create` builder, its `is` guard, and the traversal metadata the registry
* collects into the visitor tables.
*/
export type NodeDef<TNode extends BaseNode = BaseNode, TInput = never> = {
/**
* Node discriminator this definition owns.
*/
kind: NodeKind
/**
* Builds a node from its input, applying `defaults` and the optional `build` hook.
*/
create: (input: TInput) => TNode
/**
* Type guard matching this node kind.
*/
is: (node: unknown) => node is TNode
/**
* Child node fields in traversal order. Feeds `VISITOR_KEYS`.
*/
children?: ReadonlyArray<string>
/**
* Visitor callback name. Feeds `VISITOR_KEY_BY_KIND`.
*/
visitorKey?: VisitorKey
/**
* When `true`, `create` is rerun after children are rebuilt so computed fields
* stay in sync. Feeds `nodeRebuilders`.
*/
rebuild?: boolean
}
type DefineNodeConfig<TNode extends BaseNode, TInput, TBuilt extends object> = {
kind: TNode['kind']
defaults?: Partial<TNode>
build?: (input: TInput) => TBuilt
children?: ReadonlyArray<string>
visitorKey?: VisitorKey
rebuild?: boolean
}
/**
* Defines a node once and derives its `create` builder, `is` guard, and traversal
* metadata. `create` merges `defaults`, the `build` hook (or the raw input), and the
* `kind`, so node construction lives in one place without scattered `as` casts.
*
* Set `rebuild: true` when the `build` hook derives fields from children. After a
* transform rewrites those children, the registry reruns `create` so the derived
* fields stay correct.
*
* @example Simple node
* ```ts
* const importDef = defineNode<ImportNode>({ kind: 'Import' })
* const createImport = importDef.create
* ```
*
* @example Node with a build hook that is rerun on transform
* ```ts
* const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
* kind: 'Property',
* build: (props) => ({ ...props, required: props.required ?? false }),
* children: ['schema'],
* visitorKey: 'property',
* rebuild: true,
* })
* ```
*/
export function defineNode<TNode extends BaseNode, TInput = Omit<TNode, 'kind'>, TBuilt extends object = Omit<TNode, 'kind'>>(
config: DefineNodeConfig<TNode, TInput, TBuilt>,
): NodeDef<TNode, TInput> {
const { kind, defaults, build, children, visitorKey, rebuild } = config
function create(input: TInput): TNode {
const base = build ? build(input) : input
return { ...defaults, ...(base as object), kind } as TNode
}
return { kind, create, is: isKind<TNode>(kind), children, visitorKey, rebuild }
}
import type { NodeDef } from './node.ts'
import { arrowFunctionDef, breakDef, constDef, functionDef, jsxDef, textDef, typeDef } from './nodes/code.ts'
import { contentDef } from './nodes/content.ts'
import { exportDef, fileDef, importDef, sourceDef } from './nodes/file.ts'
import { functionParameterDef, functionParametersDef, indexedAccessTypeDef, objectBindingPatternDef, typeLiteralDef } from './nodes/function.ts'
import type { Node, NodeKind } from './nodes/index.ts'
import { inputDef } from './nodes/input.ts'
import { operationDef } from './nodes/operation.ts'
import { outputDef } from './nodes/output.ts'
import { parameterDef } from './nodes/parameter.ts'
import { propertyDef } from './nodes/property.ts'
import { requestBodyDef } from './nodes/requestBody.ts'
import { responseDef } from './nodes/response.ts'
import { schemaDef } from './nodes/schema.ts'
/**
* Every node definition. Adding a node means adding its `defineNode` to one
* `nodes/*.ts` file and listing it here. The visitor tables below derive from it.
*/
export const nodeDefs = [
inputDef,
outputDef,
operationDef,
requestBodyDef,
contentDef,
responseDef,
schemaDef,
propertyDef,
parameterDef,
functionParameterDef,
functionParametersDef,
typeLiteralDef,
indexedAccessTypeDef,
objectBindingPatternDef,
constDef,
typeDef,
functionDef,
arrowFunctionDef,
textDef,
breakDef,
jsxDef,
importDef,
exportDef,
sourceDef,
fileDef,
] satisfies ReadonlyArray<NodeDef>
/**
* Child node fields per node kind, in traversal order (Babel's `VISITOR_KEYS`).
* Derived from each definition's `children`.
*/
export const VISITOR_KEYS = Object.fromEntries(nodeDefs.flatMap((def) => (def.children ? [[def.kind, def.children] as const] : []))) as Partial<
Record<NodeKind, ReadonlyArray<string>>
>
/**
* Maps a node kind to the matching visitor callback name. Derived from each
* definition's `visitorKey`.
*/
export const VISITOR_KEY_BY_KIND = Object.fromEntries(nodeDefs.flatMap((def) => (def.visitorKey ? [[def.kind, def.visitorKey] as const] : []))) as Partial<
Record<NodeKind, NonNullable<NodeDef['visitorKey']>>
>
/**
* Per-kind builders rerun after children are rebuilt. Derived from each
* definition's `rebuild` flag.
*/
export const nodeRebuilders = Object.fromEntries(
nodeDefs.flatMap((def) => (def.rebuild ? [[def.kind, def.create as unknown as (node: Node) => Node] as const] : [])),
) as Partial<Record<NodeKind, (node: Node) => Node>>
+2
-46
import { t as __name } from "./chunk-C0LytTxp.js";
import { $ as DedupeCanonical, $t as schemaTypes, A as createFunctionParameter, At as NumberSchemaNode, B as createProperty, Bt as UnionSchemaNode, C as UserFileNode, Ct as ImportNode, D as createExport, Dt as DatetimeSchemaNode, E as createConst, Et as DateSchemaNode, F as createOperation, Ft as SchemaNode, G as createText, Gt as ConstNode, H as createSchema, Ht as PropertyNode, I as createOutput, It as SchemaNodeByType, J as update, Jt as JsxNode, K as createType, Kt as FunctionNode, L as createParameter, Lt as SchemaType, M as createImport, Mt as PrimitiveSchemaType, N as createInput, Nt as RefSchemaNode, O as createFile, Ot as EnumSchemaNode, P as createJsx, Pt as ScalarSchemaType, Q as defineSchemaDialect, Qt as httpMethods, R as createParameterGroup, Rt as StringSchemaNode, S as DistributiveOmit, St as FileNode, T as createBreak, Tt as ArraySchemaNode, U as createSource, Ut as ArrowFunctionNode, V as createResponse, Vt as UrlSchemaNode, W as createStreamInput, Wt as CodeNode, X as ParserOptions, Xt as TypeNode, Y as InferSchemaNode, Yt as TextNode, Z as SchemaDialect, Zt as NodeKind, _ as Printer, _t as FunctionParameterNode, a as createDiscriminantNode, at as OutputNode, b as createPrinterFactory, bt as ParamsTypeNode, c as findCircularSchemas, ct as HttpMethod, d as ParentOf, dt as ResponseNode, et as DedupeLookups, f as Visitor, ft as StatusCode, g as walk, gt as FunctionParamNode, h as transform, ht as FunctionNodeType, i as containsCircularRef, it as Node, j as createFunctionParameters, jt as ObjectSchemaNode, k as createFunction, kt as IntersectionSchemaNode, l as isStringType, lt as HttpOperationNode, m as collect, mt as ParameterNode, n as caseParams, nt as applyDedupe, o as createOperationParams, ot as InputMeta, p as VisitorContext, pt as ParameterLocation, q as syncOptionality, qt as JSDocNode, r as collectUsedSchemaNames, rt as buildDedupePlan, s as extractStringsFromNodes, st as InputNode, t as OperationParamsResolver, tt as DedupePlan, u as syncSchemaRef, ut as OperationNode, v as PrinterFactoryOptions, vt as FunctionParametersNode, w as createArrowFunction, wt as SourceNode, x as definePrinter, xt as ExportNode, y as PrinterPartial, yt as ParameterGroupNode, z as createParamsType, zt as TimeSchemaNode } from "./types-BL7RpQAE.js";
import { $ as createParameter, $t as InferSchemaNode, A as applyDedupe, At as contentDef, B as inputDef, Bt as ScalarSchemaType, C as createFile, Cn as DistributiveOmit, Ct as createExport, D as DedupeCanonical, Dn as NodeKind, Dt as fileDef, E as defineSchemaDialect, En as syncOptionality, Et as exportDef, F as outputDef, Ft as IntersectionSchemaNode, G as operationDef, Gt as TimeSchemaNode, H as HttpOperationNode, Ht as SchemaNodeByType, I as InputMeta, It as NumberSchemaNode, J as responseDef, Jt as createSchema, K as ResponseNode, Kt as UnionSchemaNode, L as InputNode, Lt as ObjectSchemaNode, M as Node, Mt as DateSchemaNode, N as OutputNode, Nt as DatetimeSchemaNode, O as DedupeLookups, On as httpMethods, Ot as importDef, P as createOutput, Pt as EnumSchemaNode, Q as ParameterNode, Qt as propertyDef, R as createInput, Rt as PrimitiveSchemaType, S as UserFileNode, Sn as typeDef, St as SourceNode, T as SchemaDialect, Tn as defineNode, Tt as createSource, U as OperationNode, Ut as SchemaType, V as HttpMethod, Vt as SchemaNode, W as createOperation, Wt as StringSchemaNode, X as requestBodyDef, Xt as PropertyNode, Y as StatusCode, Yt as schemaDef, Z as ParameterLocation, Zt as createProperty, _ as Printer, _n as createText, _t as objectBindingPatternDef, a as createDiscriminantNode, an as JSDocNode, at as IndexedAccessTypeNode, b as createPrinterFactory, bn as jsxDef, bt as FileNode, c as findCircularSchemas, cn as TypeNode, ct as TypeLiteralNode, d as ParentOf, dn as constDef, dt as createIndexedAccessType, en as ParserOptions, et as parameterDef, f as Visitor, fn as createArrowFunction, ft as createObjectBindingPattern, g as walk, gn as createJsx, gt as indexedAccessTypeDef, h as transform, hn as createFunction, ht as functionParametersDef, i as containsCircularRef, in as FunctionNode, it as FunctionParametersNode, j as buildDedupePlan, jt as ArraySchemaNode, k as DedupePlan, kn as schemaTypes, kt as sourceDef, l as isStringType, ln as arrowFunctionDef, lt as createFunctionParameter, m as collect, mn as createConst, mt as functionParameterDef, n as caseParams, nn as CodeNode, nt as FunctionParamNode, o as createOperationParams, on as JsxNode, ot as ObjectBindingPatternNode, p as VisitorContext, pn as createBreak, pt as createTypeLiteral, q as createResponse, qt as UrlSchemaNode, r as collectUsedSchemaNames, rn as ConstNode, rt as FunctionParameterNode, s as extractStringsFromNodes, sn as TextNode, st as TypeExpression, t as OperationParamsResolver, tn as ArrowFunctionNode, tt as FunctionNodeType, u as syncSchemaRef, un as breakDef, ut as createFunctionParameters, v as PrinterFactoryOptions, vn as createType, vt as typeLiteralDef, w as update, wn as NodeDef, wt as createImport, x as definePrinter, xn as textDef, xt as ImportNode, y as PrinterPartial, yn as functionDef, yt as ExportNode, z as createStreamInput, zt as RefSchemaNode } from "./types-C5aVnRE1.js";

@@ -16,35 +16,2 @@ //#region src/guards.d.ts

/**
* Returns `true` when the input is an `InputNode`.
*
* @example
* ```ts
* if (isInputNode(node)) {
* console.log(node.schemas.length)
* }
* ```
*/
declare const isInputNode: (node: unknown) => node is InputNode;
/**
* Returns `true` when the input is an `OutputNode`.
*
* @example
* ```ts
* if (isOutputNode(node)) {
* console.log(node.files.length)
* }
* ```
*/
declare const isOutputNode: (node: unknown) => node is OutputNode;
/**
* Returns `true` when the input is an `OperationNode`.
*
* @example
* ```ts
* if (isOperationNode(node)) {
* console.log(node.operationId)
* }
* ```
*/
declare const isOperationNode: (node: unknown) => node is OperationNode;
/**
* Narrows an `OperationNode` to an `HttpOperationNode`, guaranteeing `method` and `path`.

@@ -60,13 +27,2 @@ *

declare function isHttpOperationNode(node: OperationNode): node is HttpOperationNode;
/**
* Returns `true` when the input is a `SchemaNode`.
*
* @example
* ```ts
* if (isSchemaNode(node)) {
* console.log(node.type)
* }
* ```
*/
declare const isSchemaNode: (node: unknown) => node is SchemaNode;
//#endregion

@@ -143,3 +99,3 @@ //#region src/signature.d.ts

//#endregion
export { type ArraySchemaNode, type ArrowFunctionNode, type CodeNode, type ConstNode, type DateSchemaNode, type DatetimeSchemaNode, type DedupeCanonical, type DedupeLookups, type DedupePlan, type DistributiveOmit, type EnumSchemaNode, type ExportNode, type FileNode, type FunctionNode, type FunctionNodeType, type FunctionParamNode, type FunctionParameterNode, type FunctionParametersNode, type HttpMethod, type HttpOperationNode, type ImportNode, type InferSchemaNode, type InputMeta, type InputNode, type IntersectionSchemaNode, type JSDocNode, type JsxNode, type Node, type NodeKind, type NumberSchemaNode, type ObjectSchemaNode, type OperationNode, type OperationParamsResolver, type OutputNode, type ParameterGroupNode, type ParameterLocation, type ParameterNode, type ParamsTypeNode, type ParentOf, type ParserOptions, type PrimitiveSchemaType, type Printer, type PrinterFactoryOptions, type PrinterPartial, type PropertyNode, type RefSchemaNode, type ResponseNode, type ScalarSchemaType, type SchemaDialect, type SchemaNode, type SchemaNodeByType, type SchemaType, type SourceNode, type StatusCode, type StringSchemaNode, type TextNode, type TimeSchemaNode, type TypeNode, type UnionSchemaNode, type UrlSchemaNode, type UserFileNode, type Visitor, type VisitorContext, applyDedupe, buildDedupePlan, caseParams, collect, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createResponse, createSchema, createSource, createStreamInput, createText, createType, definePrinter, defineSchemaDialect, extractStringsFromNodes, findCircularSchemas, httpMethods, isHttpOperationNode, isInputNode, isOperationNode, isOutputNode, isSchemaNode, isStringType, mergeAdjacentObjectsLazy, narrowSchema, schemaTypes, setDiscriminatorEnum, setEnumName, signatureOf, simplifyUnion, syncOptionality, syncSchemaRef, transform, update, walk };
export { type ArraySchemaNode, type ArrowFunctionNode, type CodeNode, type ConstNode, type DateSchemaNode, type DatetimeSchemaNode, type DedupeCanonical, type DedupeLookups, type DedupePlan, type DistributiveOmit, type EnumSchemaNode, type ExportNode, type FileNode, type FunctionNode, type FunctionNodeType, type FunctionParamNode, type FunctionParameterNode, type FunctionParametersNode, type HttpMethod, type HttpOperationNode, type ImportNode, type IndexedAccessTypeNode, type InferSchemaNode, type InputMeta, type InputNode, type IntersectionSchemaNode, type JSDocNode, type JsxNode, type Node, type NodeDef, type NodeKind, type NumberSchemaNode, type ObjectBindingPatternNode, type ObjectSchemaNode, type OperationNode, type OperationParamsResolver, type OutputNode, type ParameterLocation, type ParameterNode, type ParentOf, type ParserOptions, type PrimitiveSchemaType, type Printer, type PrinterFactoryOptions, type PrinterPartial, type PropertyNode, type RefSchemaNode, type ResponseNode, type ScalarSchemaType, type SchemaDialect, type SchemaNode, type SchemaNodeByType, type SchemaType, type SourceNode, type StatusCode, type StringSchemaNode, type TextNode, type TimeSchemaNode, type TypeExpression, type TypeLiteralNode, type TypeNode, type UnionSchemaNode, type UrlSchemaNode, type UserFileNode, type Visitor, type VisitorContext, applyDedupe, arrowFunctionDef, breakDef, buildDedupePlan, caseParams, collect, collectUsedSchemaNames, constDef, containsCircularRef, contentDef, createArrowFunction, createBreak, createConst, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createIndexedAccessType, createInput, createJsx, createObjectBindingPattern, createOperation, createOperationParams, createOutput, createParameter, createPrinterFactory, createProperty, createResponse, createSchema, createSource, createStreamInput, createText, createType, createTypeLiteral, defineNode, definePrinter, defineSchemaDialect, exportDef, extractStringsFromNodes, fileDef, findCircularSchemas, functionDef, functionParameterDef, functionParametersDef, httpMethods, importDef, indexedAccessTypeDef, inputDef, isHttpOperationNode, isStringType, jsxDef, mergeAdjacentObjectsLazy, narrowSchema, objectBindingPatternDef, operationDef, outputDef, parameterDef, propertyDef, requestBodyDef, responseDef, schemaDef, schemaTypes, setDiscriminatorEnum, setEnumName, signatureOf, simplifyUnion, sourceDef, syncOptionality, syncSchemaRef, textDef, transform, typeDef, typeLiteralDef, update, walk };
//# sourceMappingURL=index.d.ts.map

@@ -1,2 +0,2 @@

import { $ as DedupeCanonical, At as NumberSchemaNode, Bt as UnionSchemaNode, C as UserFileNode, Ct as ImportNode, Dt as DatetimeSchemaNode, Et as DateSchemaNode, Ft as SchemaNode, Gt as ConstNode, Ht as PropertyNode, It as SchemaNodeByType, Jt as JsxNode, Kt as FunctionNode, Lt as SchemaType, Mt as PrimitiveSchemaType, Nt as RefSchemaNode, Ot as EnumSchemaNode, Pt as ScalarSchemaType, Rt as StringSchemaNode, S as DistributiveOmit, St as FileNode, Tt as ArraySchemaNode, Ut as ArrowFunctionNode, Vt as UrlSchemaNode, Wt as CodeNode, X as ParserOptions, Xt as TypeNode, Y as InferSchemaNode, Yt as TextNode, Z as SchemaDialect, Zt as NodeKind, _ as Printer, _t as FunctionParameterNode, at as OutputNode, bt as ParamsTypeNode, ct as HttpMethod, d as ParentOf, dt as ResponseNode, et as DedupeLookups, f as Visitor, ft as StatusCode, gt as FunctionParamNode, ht as FunctionNodeType, it as Node, jt as ObjectSchemaNode, kt as IntersectionSchemaNode, lt as HttpOperationNode, mt as ParameterNode, ot as InputMeta, p as VisitorContext, pt as ParameterLocation, qt as JSDocNode, st as InputNode, t as OperationParamsResolver, tt as DedupePlan, ut as OperationNode, v as PrinterFactoryOptions, vt as FunctionParametersNode, wt as SourceNode, xt as ExportNode, y as PrinterPartial, yt as ParameterGroupNode, zt as TimeSchemaNode } from "./types-BL7RpQAE.js";
export type { ArraySchemaNode, ArrowFunctionNode, CodeNode, ConstNode, DateSchemaNode, DatetimeSchemaNode, DedupeCanonical, DedupeLookups, DedupePlan, DistributiveOmit, EnumSchemaNode, ExportNode, FileNode, FunctionNode, FunctionNodeType, FunctionParamNode, FunctionParameterNode, FunctionParametersNode, HttpMethod, HttpOperationNode, ImportNode, InferSchemaNode, InputMeta, InputNode, IntersectionSchemaNode, JSDocNode, JsxNode, Node, NodeKind, NumberSchemaNode, ObjectSchemaNode, OperationNode, OperationParamsResolver, OutputNode, ParameterGroupNode, ParameterLocation, ParameterNode, ParamsTypeNode, ParentOf, ParserOptions, PrimitiveSchemaType, Printer, PrinterFactoryOptions, PrinterPartial, PropertyNode, RefSchemaNode, ResponseNode, ScalarSchemaType, SchemaDialect, SchemaNode, SchemaNodeByType, SchemaType, SourceNode, StatusCode, StringSchemaNode, TextNode, TimeSchemaNode, TypeNode, UnionSchemaNode, UrlSchemaNode, UserFileNode, Visitor, VisitorContext };
import { $t as InferSchemaNode, Bt as ScalarSchemaType, Cn as DistributiveOmit, D as DedupeCanonical, Dn as NodeKind, Ft as IntersectionSchemaNode, Gt as TimeSchemaNode, H as HttpOperationNode, Ht as SchemaNodeByType, I as InputMeta, It as NumberSchemaNode, K as ResponseNode, Kt as UnionSchemaNode, L as InputNode, Lt as ObjectSchemaNode, M as Node, Mt as DateSchemaNode, N as OutputNode, Nt as DatetimeSchemaNode, O as DedupeLookups, Pt as EnumSchemaNode, Q as ParameterNode, Rt as PrimitiveSchemaType, S as UserFileNode, St as SourceNode, T as SchemaDialect, U as OperationNode, Ut as SchemaType, V as HttpMethod, Vt as SchemaNode, Wt as StringSchemaNode, Xt as PropertyNode, Y as StatusCode, Z as ParameterLocation, _ as Printer, an as JSDocNode, at as IndexedAccessTypeNode, bt as FileNode, cn as TypeNode, ct as TypeLiteralNode, d as ParentOf, en as ParserOptions, f as Visitor, in as FunctionNode, it as FunctionParametersNode, jt as ArraySchemaNode, k as DedupePlan, nn as CodeNode, nt as FunctionParamNode, on as JsxNode, ot as ObjectBindingPatternNode, p as VisitorContext, qt as UrlSchemaNode, rn as ConstNode, rt as FunctionParameterNode, sn as TextNode, st as TypeExpression, t as OperationParamsResolver, tn as ArrowFunctionNode, tt as FunctionNodeType, v as PrinterFactoryOptions, xt as ImportNode, y as PrinterPartial, yt as ExportNode, zt as RefSchemaNode } from "./types-C5aVnRE1.js";
export type { ArraySchemaNode, ArrowFunctionNode, CodeNode, ConstNode, DateSchemaNode, DatetimeSchemaNode, DedupeCanonical, DedupeLookups, DedupePlan, DistributiveOmit, EnumSchemaNode, ExportNode, FileNode, FunctionNode, FunctionNodeType, FunctionParamNode, FunctionParameterNode, FunctionParametersNode, HttpMethod, HttpOperationNode, ImportNode, IndexedAccessTypeNode, InferSchemaNode, InputMeta, InputNode, IntersectionSchemaNode, JSDocNode, JsxNode, Node, NodeKind, NumberSchemaNode, ObjectBindingPatternNode, ObjectSchemaNode, OperationNode, OperationParamsResolver, OutputNode, ParameterLocation, ParameterNode, ParentOf, ParserOptions, PrimitiveSchemaType, Printer, PrinterFactoryOptions, PrinterPartial, PropertyNode, RefSchemaNode, ResponseNode, ScalarSchemaType, SchemaDialect, SchemaNode, SchemaNodeByType, SchemaType, SourceNode, StatusCode, StringSchemaNode, TextNode, TimeSchemaNode, TypeExpression, TypeLiteralNode, TypeNode, UnionSchemaNode, UrlSchemaNode, UserFileNode, Visitor, VisitorContext };
{
"name": "@kubb/ast",
"version": "5.0.0-beta.56",
"version": "5.0.0-beta.57",
"description": "Spec-agnostic AST layer for Kubb. Defines the node tree, visitor pattern, factory functions, and type guards used across all code generation plugins.",

@@ -5,0 +5,0 @@ "keywords": [

@@ -114,7 +114,7 @@ <div align="center">

```ts
import { isSchemaNode, narrowSchema } from '@kubb/ast'
import { narrowSchema, schemaDef } from '@kubb/ast'
import type { Node } from '@kubb/ast/types'
function process(node: Node) {
if (isSchemaNode(node)) {
if (schemaDef.is(node)) {
const obj = narrowSchema(node, 'object')

@@ -121,0 +121,0 @@ obj?.properties?.forEach((p) => console.log(p.name))

@@ -1,3 +0,3 @@

import { createSchema } from './factory.ts'
import type { Node, OperationNode, SchemaNode } from './nodes/index.ts'
import { createSchema } from './nodes/schema.ts'
import { signatureOf } from './signature.ts'

@@ -4,0 +4,0 @@ import { extractRefName } from './utils/index.ts'

import { hash } from 'node:crypto'
import path from 'node:path'
import { trimExtName } from '@internals/utils'
import type { InferSchemaNode } from './infer.ts'
import type {
ArrowFunctionNode,
BreakNode,
ConstNode,
ContentNode,
ExportNode,
FileNode,
FunctionNode,
FunctionParameterNode,
FunctionParametersNode,
GenericOperationNode,
HttpOperationNode,
ImportNode,
InputMeta,
InputNode,
JsxNode,
Node,
ObjectSchemaNode,
OperationNode,
OutputNode,
ParameterGroupNode,
ParameterNode,
ParamsTypeNode,
PrimitiveSchemaType,
PropertyNode,
RequestBodyNode,
ResponseNode,
SchemaNode,
SourceNode,
TextNode,
TypeNode,
} from './nodes/index.ts'
import type { FileNode, Node } from './nodes/index.ts'
import { combineExports, combineImports, combineSources, extractStringsFromNodes } from './utils/ast.ts'
/**
* Updates a schema's `optional` and `nullish` flags from a parent's `required`
* value and the schema's own `nullable`. Mirrors how OpenAPI parameters and
* object properties combine "required" and "nullable" into a single AST.
*
* - Non-required + non-nullable → `optional: true`.
* - Non-required + nullable → `nullish: true`.
* - Required → both flags cleared.
*/
export function syncOptionality(schema: SchemaNode, required: boolean): SchemaNode {
const nullable = schema.nullable ?? false
return {
...schema,
optional: !required && !nullable ? true : undefined,
nullish: !required && nullable ? true : undefined,
}
}
/**
* Distributive `Omit` that preserves each member of a union.
*
* @example
* ```ts
* type A = { kind: 'a'; keep: string; drop: number }
* type B = { kind: 'b'; keep: boolean; drop: number }
* type Result = DistributiveOmit<A | B, 'drop'>
* // -> { kind: 'a'; keep: string } | { kind: 'b'; keep: boolean }
* ```
*/
export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never
/**
* Identity-preserving node update: returns `node` unchanged when every field in

@@ -97,528 +33,6 @@ * `changes` already equals (by reference) the current value, otherwise a new node

type CreateSchemaObjectInput = Omit<ObjectSchemaNode, 'kind' | 'properties' | 'primitive'> & { properties?: Array<PropertyNode>; primitive?: 'object' }
type CreateSchemaInput = CreateSchemaObjectInput | DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>
type CreateSchemaOutput<T extends CreateSchemaInput> = InferSchemaNode<T> & {
kind: 'Schema'
}
/**
* Creates an `InputNode` with stable defaults for `schemas` and `operations`.
*
* @example
* ```ts
* const input = createInput()
* // { kind: 'Input', schemas: [], operations: [] }
* ```
*
* @example
* ```ts
* const input = createInput({ schemas: [petSchema] })
* // keeps default operations: []
* ```
* Input descriptor for {@link createFile}, before `id`, `name`, and `extname` are computed
* and `imports`/`exports`/`sources` are deduplicated.
*/
export function createInput(overrides: Partial<Omit<InputNode, 'kind'>> = {}): InputNode {
return {
schemas: [],
operations: [],
meta: { circularNames: [], enumNames: [] },
...overrides,
kind: 'Input',
}
}
/**
* Creates a streaming `InputNode<true>` from pre-built `AsyncIterable` sources.
*
* @example
* ```ts
* const node = createStreamInput(schemasIterable, operationsIterable, { title: 'My API' })
* ```
*/
export function createStreamInput(schemas: AsyncIterable<SchemaNode>, operations: AsyncIterable<OperationNode>, meta?: InputMeta): InputNode<true> {
return { kind: 'Input', schemas, operations, meta }
}
/**
* Creates an `OutputNode` with a stable default for `files`.
*
* @example
* ```ts
* const output = createOutput()
* // { kind: 'Output', files: [] }
* ```
*
* @example
* ```ts
* const output = createOutput({ files: [petFile] })
* ```
*/
export function createOutput(overrides: Partial<Omit<OutputNode, 'kind'>> = {}): OutputNode {
return {
files: [],
...overrides,
kind: 'Output',
}
}
/**
* Creates an `OperationNode` with default empty arrays for `tags`, `parameters`, and `responses`.
*
* @example
* ```ts
* const operation = createOperation({
* operationId: 'getPetById',
* method: 'GET',
* path: '/pet/{petId}',
* })
* // tags, parameters, and responses are []
* ```
*
* @example
* ```ts
* const operation = createOperation({
* operationId: 'findPets',
* method: 'GET',
* path: '/pet/findByStatus',
* tags: ['pet'],
* })
* ```
*/
/**
* Loosely-typed content entry accepted by the builders, normalized into a {@link ContentNode}.
*/
type UserContent = Omit<ContentNode, 'kind'>
/**
* Creates a `ContentNode` for a single request-body or response content type.
*/
function createContent(props: UserContent): ContentNode {
return {
...props,
kind: 'Content',
}
}
/**
* Loosely-typed request body accepted by `createOperation`, normalized into a {@link RequestBodyNode}.
*/
type UserRequestBody = Omit<RequestBodyNode, 'kind' | 'content'> & {
content?: Array<UserContent>
}
/**
* Creates a `RequestBodyNode`, normalizing each content entry into a `ContentNode`.
*/
function createRequestBody(props: UserRequestBody): RequestBodyNode {
return {
...props,
kind: 'RequestBody',
content: props.content?.map(createContent),
}
}
export function createOperation(
props: Pick<HttpOperationNode, 'operationId' | 'method' | 'path'> &
Partial<Omit<HttpOperationNode, 'kind' | 'operationId' | 'method' | 'path' | 'requestBody'>> & {
requestBody?: UserRequestBody
},
): HttpOperationNode
export function createOperation(
props: Pick<GenericOperationNode, 'operationId'> &
Partial<Omit<GenericOperationNode, 'kind' | 'operationId' | 'requestBody'>> & {
requestBody?: UserRequestBody
},
): GenericOperationNode
export function createOperation(props: {
operationId: string
method?: HttpOperationNode['method']
path?: HttpOperationNode['path']
requestBody?: UserRequestBody
[key: string]: unknown
}): OperationNode {
const { requestBody, ...rest } = props
const isHttp = rest.method !== undefined && rest.path !== undefined
return {
tags: [],
parameters: [],
responses: [],
...rest,
...(isHttp ? { protocol: 'http' } : {}),
kind: 'Operation',
requestBody: requestBody ? createRequestBody(requestBody) : undefined,
} as OperationNode
}
/**
* Maps schema `type` to its underlying `primitive`.
* Primitive types map to themselves. Special string formats map to `'string'`.
* Complex types (`ref`, `enum`, `union`, `intersection`, `tuple`, `blob`) are left unset.
*/
const TYPE_TO_PRIMITIVE: Partial<Record<SchemaNode['type'], PrimitiveSchemaType>> = {
string: 'string',
number: 'number',
integer: 'integer',
bigint: 'bigint',
boolean: 'boolean',
null: 'null',
any: 'any',
unknown: 'unknown',
void: 'void',
never: 'never',
object: 'object',
array: 'array',
date: 'date',
uuid: 'string',
email: 'string',
url: 'string',
datetime: 'string',
time: 'string',
}
/**
* Creates a `SchemaNode`, narrowed to the variant of `props.type`.
* For object schemas, `properties` defaults to an empty array.
* `primitive` is automatically inferred from `type` when not explicitly provided.
*
* @example
* ```ts
* const scalar = createSchema({ type: 'string' })
* // { kind: 'Schema', type: 'string', primitive: 'string' }
* ```
*
* @example
* ```ts
* const uuid = createSchema({ type: 'uuid' })
* // { kind: 'Schema', type: 'uuid', primitive: 'string' }
* ```
*
* @example
* ```ts
* const object = createSchema({ type: 'object' })
* // { kind: 'Schema', type: 'object', primitive: 'object', properties: [] }
* ```
*
* @example
* ```ts
* const enumSchema = createSchema({
* type: 'enum',
* primitive: 'string',
* enumValues: ['available', 'pending'],
* })
* ```
*/
export function createSchema<T extends CreateSchemaInput>(props: T): CreateSchemaOutput<T>
export function createSchema(props: CreateSchemaInput): SchemaNode
export function createSchema(props: CreateSchemaInput): SchemaNode {
const inferredPrimitive = TYPE_TO_PRIMITIVE[props.type as keyof typeof TYPE_TO_PRIMITIVE]
if (props['type'] === 'object') {
return {
properties: [],
primitive: 'object',
...props,
kind: 'Schema',
} as CreateSchemaOutput<typeof props>
}
return {
primitive: inferredPrimitive,
...props,
kind: 'Schema',
} as CreateSchemaOutput<typeof props>
}
type UserPropertyNode = Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>
/**
* Creates a `PropertyNode`.
*
* `required` defaults to `false`.
* `schema.optional` and `schema.nullish` are derived from `required` and `schema.nullable`.
*
* @example
* ```ts
* const property = createProperty({
* name: 'status',
* schema: createSchema({ type: 'string' }),
* })
* // required=false, schema.optional=true
* ```
*
* @example
* ```ts
* const property = createProperty({
* name: 'status',
* required: true,
* schema: createSchema({ type: 'string', nullable: true }),
* })
* // required=true, no optional/nullish
* ```
*/
export function createProperty(props: UserPropertyNode): PropertyNode {
const required = props.required ?? false
return {
...props,
kind: 'Property',
required,
schema: syncOptionality(props.schema, required),
}
}
/**
* Creates a `ParameterNode`.
*
* `required` defaults to `false`.
* Nested schema flags are set from `required` and `schema.nullable`.
*
* @example
* ```ts
* const param = createParameter({
* name: 'petId',
* in: 'path',
* required: true,
* schema: createSchema({ type: 'string' }),
* })
* ```
*
* @example
* ```ts
* const param = createParameter({
* name: 'status',
* in: 'query',
* schema: createSchema({ type: 'string', nullable: true }),
* })
* // required=false, schema.nullish=true
* ```
*/
export function createParameter(
props: Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>,
): ParameterNode {
const required = props.required ?? false
return {
...props,
kind: 'Parameter',
required,
schema: syncOptionality(props.schema, required),
}
}
/**
* Creates a `ResponseNode`.
*
* Response body schemas live inside `content`. For convenience a single legacy `schema`
* (with optional `mediaType`/`keysToOmit`) is normalized into one `content` entry, so the same
* schema is never stored both at the node root and inside `content`.
*
* @example
* ```ts
* const response = createResponse({
* statusCode: '200',
* content: [{ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) }],
* })
* ```
*/
export function createResponse(
props: Pick<ResponseNode, 'statusCode'> &
Partial<Omit<ResponseNode, 'kind' | 'statusCode' | 'content'>> & {
content?: Array<UserContent>
schema?: SchemaNode
mediaType?: string | null
keysToOmit?: Array<string> | null
},
): ResponseNode {
const { schema, mediaType, keysToOmit, content, ...rest } = props
const entries = content ?? (schema ? [{ contentType: mediaType ?? 'application/json', schema, keysToOmit: keysToOmit ?? null }] : undefined)
return {
...rest,
kind: 'Response',
content: entries?.map(createContent),
}
}
/**
* Creates a `FunctionParameterNode`.
*
* `optional` defaults to `false`.
*
* @example Required typed param
* ```ts
* createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }) })
* // → petId: string
* ```
*
* @example Optional param
* ```ts
* createFunctionParameter({ name: 'params', type: createParamsType({ variant: 'reference', name: 'QueryParams' }), optional: true })
* // → params?: QueryParams
* ```
*
* @example Param with default (implicitly optional. Cannot combine with `optional: true`)
* ```ts
* createFunctionParameter({ name: 'config', type: createParamsType({ variant: 'reference', name: 'RequestConfig' }), default: '{}' })
* // → config: RequestConfig = {}
* ```
*/
export function createFunctionParameter(
props: { name: string; type?: ParamsTypeNode; rest?: boolean } & ({ optional: true; default?: never } | { optional?: false; default?: string }),
): FunctionParameterNode {
return {
optional: false,
...props,
kind: 'FunctionParameter',
} as FunctionParameterNode
}
/**
* Creates a {@link TypeNode} representing a language-agnostic structured type expression.
*
* Use `variant: 'struct'` for inline anonymous types and `variant: 'member'` for a single
* named field accessed from a group type. Each language's printer renders the variant
* into its own syntax (TypeScript, Python, C#, Kotlin, …).
*
* @example Reference type (TypeScript: `QueryParams`)
* ```ts
* createParamsType({ variant: 'reference', name: 'QueryParams' })
* ```
*
* @example Struct type (TypeScript: `{ petId: string }`)
* ```ts
* createParamsType({ variant: 'struct', properties: [{ name: 'petId', optional: false, type: createParamsType({ variant: 'reference', name: 'string' }) }] })
* ```
*
* @example Member type (TypeScript: `DeletePetPathParams['petId']`)
* ```ts
* createParamsType({ variant: 'member', base: 'DeletePetPathParams', key: 'petId' })
* ```
*/
export function createParamsType(
props:
| { variant: 'reference'; name: string }
| {
variant: 'struct'
properties: Array<{
name: string
optional: boolean
type: ParamsTypeNode
}>
}
| { variant: 'member'; base: string; key: string },
): ParamsTypeNode {
return { ...props, kind: 'ParamsType' } as ParamsTypeNode
}
/**
* Creates a `ParameterGroupNode` representing a group of related parameters treated as a unit.
*
* @example Grouped param (TypeScript declaration)
* ```ts
* createParameterGroup({
* properties: [
* createFunctionParameter({ name: 'id', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false }),
* createFunctionParameter({ name: 'name', type: createParamsType({ variant: 'reference', name: 'string' }), optional: true }),
* ],
* default: '{}',
* })
* // declaration → { id, name? }: { id: string; name?: string } = {}
* // call → { id, name }
* ```
*
* @example Inline (spread), children emitted as individual top-level parameters
* ```ts
* createParameterGroup({
* properties: [createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false })],
* inline: true,
* })
* // declaration → petId: string
* // call → petId
* ```
*/
export function createParameterGroup(
props: Pick<ParameterGroupNode, 'properties'> & Partial<Omit<ParameterGroupNode, 'kind' | 'properties'>>,
): ParameterGroupNode {
return {
...props,
kind: 'ParameterGroup',
}
}
/**
* Creates a `FunctionParametersNode` from an ordered list of parameters.
*
* @example
* ```ts
* createFunctionParameters({
* params: [
* createFunctionParameter({ name: 'petId', type: createParamsType({ variant: 'reference', name: 'string' }), optional: false }),
* createFunctionParameter({ name: 'config', type: createParamsType({ variant: 'reference', name: 'RequestConfig' }), optional: false, default: '{}' }),
* ],
* })
* ```
*
* @example
* ```ts
* const empty = createFunctionParameters()
* // { kind: 'FunctionParameters', params: [] }
* ```
*/
export function createFunctionParameters(props: Partial<Omit<FunctionParametersNode, 'kind'>> = {}): FunctionParametersNode {
return {
params: [],
...props,
kind: 'FunctionParameters',
}
}
/**
* Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
*
* @example Named import
* ```ts
* createImport({ name: ['useState'], path: 'react' })
* // import { useState } from 'react'
* ```
*
* @example Type-only import
* ```ts
* createImport({ name: ['FC'], path: 'react', isTypeOnly: true })
* // import type { FC } from 'react'
* ```
*/
export function createImport(props: Omit<ImportNode, 'kind'>): ImportNode {
return { ...props, kind: 'Import' }
}
/**
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
*
* @example Named export
* ```ts
* createExport({ name: ['Pet'], path: './Pet' })
* // export { Pet } from './Pet'
* ```
*
* @example Wildcard export
* ```ts
* createExport({ path: './utils' })
* // export * from './utils'
* ```
*/
export function createExport(props: Omit<ExportNode, 'kind'>): ExportNode {
return { ...props, kind: 'Export' }
}
/**
* Creates a `SourceNode` representing a fragment of source code within a file.
*
* @example
* ```ts
* createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
* ```
*/
export function createSource(props: Omit<SourceNode, 'kind'>): SourceNode {
return { ...props, kind: 'Source' }
}
export type UserFileNode<TMeta extends object = object> = Omit<FileNode<TMeta>, 'kind' | 'id' | 'name' | 'extname' | 'imports' | 'exports' | 'sources'> &

@@ -702,175 +116,1 @@ Pick<Partial<FileNode<TMeta>>, 'imports' | 'exports' | 'sources'>

}
/**
* Creates a `ConstNode` representing a TypeScript `const` declaration.
*
* Mirrors the `Const` component from `@kubb/renderer-jsx`.
* The component's `children` are represented as `nodes`.
*
* @example Simple constant
* ```ts
* createConst({ name: 'pet' })
* // const pet = ...
* ```
*
* @example Exported constant with type and `as const`
* ```ts
* createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true })
* // export const pets: Pet[] = ... as const
* ```
*
* @example With JSDoc and child nodes
* ```ts
* createConst({
* name: 'config',
* export: true,
* JSDoc: { comments: ['@description App configuration'] },
* nodes: [],
* })
* ```
*/
export function createConst(props: Omit<ConstNode, 'kind'>): ConstNode {
return { ...props, kind: 'Const' }
}
/**
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
*
* Mirrors the `Type` component from `@kubb/renderer-jsx`.
* The component's `children` are represented as `nodes`.
*
* @example Simple type alias
* ```ts
* createType({ name: 'Pet' })
* // type Pet = ...
* ```
*
* @example Exported type with JSDoc
* ```ts
* createType({
* name: 'PetStatus',
* export: true,
* JSDoc: { comments: ['@description Status of a pet'] },
* })
* // export type PetStatus = ...
* ```
*/
export function createType(props: Omit<TypeNode, 'kind'>): TypeNode {
return { ...props, kind: 'Type' }
}
/**
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
*
* Mirrors the `Function` component from `@kubb/renderer-jsx`.
* The component's `children` are represented as `nodes`.
*
* @example Simple function
* ```ts
* createFunction({ name: 'getPet' })
* // function getPet() { ... }
* ```
*
* @example Exported async function with return type
* ```ts
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
* // export async function fetchPet(): Promise<Pet> { ... }
* ```
*
* @example Function with generics and params
* ```ts
* createFunction({
* name: 'identity',
* export: true,
* generics: ['T'],
* params: 'value: T',
* returnType: 'T',
* })
* // export function identity<T>(value: T): T { ... }
* ```
*/
export function createFunction(props: Omit<FunctionNode, 'kind'>): FunctionNode {
return { ...props, kind: 'Function' }
}
/**
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
*
* Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.
* The component's `children` are represented as `nodes`.
*
* @example Simple arrow function
* ```ts
* createArrowFunction({ name: 'getPet' })
* // const getPet = () => { ... }
* ```
*
* @example Single-line exported arrow function
* ```ts
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
* // export const double = (n: number) => ...
* ```
*
* @example Async arrow function with generics
* ```ts
* createArrowFunction({
* name: 'fetchPet',
* export: true,
* async: true,
* generics: ['T'],
* params: 'id: string',
* returnType: 'T',
* })
* // export const fetchPet = async <T>(id: string): Promise<T> => { ... }
* ```
*/
export function createArrowFunction(props: Omit<ArrowFunctionNode, 'kind'>): ArrowFunctionNode {
return { ...props, kind: 'ArrowFunction' }
}
/**
* Creates a {@link TextNode} representing a raw string fragment in the source output.
*
* Use this instead of bare strings when building `nodes` arrays so that every
* entry in the array is a typed {@link CodeNode}.
*
* @example
* ```ts
* createText('return fetch(id)')
* // { kind: 'Text', value: 'return fetch(id)' }
* ```
*/
export function createText(value: string): TextNode {
return { value, kind: 'Text' }
}
/**
* Creates a {@link BreakNode} representing a line break in the source output.
*
* Corresponds to `<br/>` in JSX components. Prints as an empty string which,
* when joined with `\n` by `printNodes`, produces a blank line.
*
* @example
* ```ts
* createBreak()
* // { kind: 'Break' }
* ```
*/
export function createBreak(): BreakNode {
return { kind: 'Break' }
}
/**
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
*
* Use this to embed JSX markup (including fragments `<>…</>`) directly in generated code.
*
* @example
* ```ts
* createJsx('<>\n <a href={href}>Open</a>\n</>')
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
* ```
*/
export function createJsx(value: string): JsxNode {
return { value, kind: 'Jsx' }
}

@@ -1,2 +0,2 @@

import type { HttpOperationNode, InputNode, Node, NodeKind, OperationNode, OutputNode, SchemaNode, SchemaNodeByType } from './nodes/index.ts'
import type { HttpOperationNode, OperationNode, SchemaNode, SchemaNodeByType } from './nodes/index.ts'

@@ -16,43 +16,3 @@ /**

function isKind<T extends Node>(kind: NodeKind) {
return (node: unknown): node is T => (node as Node).kind === kind
}
/**
* Returns `true` when the input is an `InputNode`.
*
* @example
* ```ts
* if (isInputNode(node)) {
* console.log(node.schemas.length)
* }
* ```
*/
export const isInputNode = isKind<InputNode>('Input')
/**
* Returns `true` when the input is an `OutputNode`.
*
* @example
* ```ts
* if (isOutputNode(node)) {
* console.log(node.files.length)
* }
* ```
*/
export const isOutputNode = isKind<OutputNode>('Output')
/**
* Returns `true` when the input is an `OperationNode`.
*
* @example
* ```ts
* if (isOperationNode(node)) {
* console.log(node.operationId)
* }
* ```
*/
export const isOperationNode = isKind<OperationNode>('Operation')
/**
* Narrows an `OperationNode` to an `HttpOperationNode`, guaranteeing `method` and `path`.

@@ -70,13 +30,1 @@ *

}
/**
* Returns `true` when the input is a `SchemaNode`.
*
* @example
* ```ts
* if (isSchemaNode(node)) {
* console.log(node.type)
* }
* ```
*/
export const isSchemaNode = isKind<SchemaNode>('Schema')
export { httpMethods, schemaTypes } from './constants.ts'
export { applyDedupe, buildDedupePlan } from './dedupe.ts'
export { defineSchemaDialect } from './dialect.ts'
export { createFile, update } from './factory.ts'
export { isHttpOperationNode, narrowSchema } from './guards.ts'
export { defineNode } from './node.ts'
export type { NodeDef } from './node.ts'
export { syncOptionality } from './node.ts'
export {
arrowFunctionDef,
breakDef,
constDef,
createArrowFunction,
createBreak,
createConst,
createExport,
createFile,
createFunction,
createFunctionParameter,
createFunctionParameters,
createImport,
createInput,
createStreamInput,
createJsx,
createOperation,
createOutput,
createParameter,
createParameterGroup,
createParamsType,
createProperty,
createResponse,
createSchema,
createSource,
createText,
createType,
syncOptionality,
update,
} from './factory.ts'
export { isHttpOperationNode, isInputNode, isOperationNode, isOutputNode, isSchemaNode, narrowSchema } from './guards.ts'
functionDef,
jsxDef,
textDef,
typeDef,
} from './nodes/code.ts'
export { contentDef } from './nodes/content.ts'
export { createExport, createImport, createSource, exportDef, fileDef, importDef, sourceDef } from './nodes/file.ts'
export {
createFunctionParameter,
createFunctionParameters,
createIndexedAccessType,
createObjectBindingPattern,
createTypeLiteral,
functionParameterDef,
functionParametersDef,
indexedAccessTypeDef,
objectBindingPatternDef,
typeLiteralDef,
} from './nodes/function.ts'
export { createInput, createStreamInput, inputDef } from './nodes/input.ts'
export { createOperation, operationDef } from './nodes/operation.ts'
export { createOutput, outputDef } from './nodes/output.ts'
export { createParameter, parameterDef } from './nodes/parameter.ts'
export { createProperty, propertyDef } from './nodes/property.ts'
export { requestBodyDef } from './nodes/requestBody.ts'
export { createResponse, responseDef } from './nodes/response.ts'
export { createSchema, schemaDef } from './nodes/schema.ts'
export { createPrinterFactory, definePrinter } from './printer.ts'

@@ -33,0 +48,0 @@ export { signatureOf } from './signature.ts'

@@ -1,3 +0,8 @@

import { createInput, createOperation, createParameter, createProperty, createResponse, createSchema } from './factory.ts'
import { createInput } from './nodes/input.ts'
import type { InputNode } from './nodes/input.ts'
import { createOperation } from './nodes/operation.ts'
import { createParameter } from './nodes/parameter.ts'
import { createProperty } from './nodes/property.ts'
import { createResponse } from './nodes/response.ts'
import { createSchema } from './nodes/schema.ts'

@@ -4,0 +9,0 @@ /**

@@ -20,6 +20,7 @@ /**

| 'FunctionParameter'
| 'ParameterGroup'
| 'FunctionParameters'
| 'TypeLiteral'
| 'IndexedAccessType'
| 'ObjectBindingPattern'
| 'Type'
| 'ParamsType'
| 'File'

@@ -26,0 +27,0 @@ | 'Import'

@@ -0,1 +1,2 @@

import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'

@@ -299,1 +300,115 @@

export type CodeNode = ConstNode | TypeNode | FunctionNode | ArrowFunctionNode | TextNode | BreakNode | JsxNode
/**
* Definition for the {@link ConstNode}.
*/
export const constDef = defineNode<ConstNode>({ kind: 'Const' })
/**
* Creates a `ConstNode` representing a TypeScript `const` declaration.
*
* @example Exported constant with type and `as const`
* ```ts
* createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true })
* // export const pets: Pet[] = ... as const
* ```
*/
export const createConst = constDef.create
/**
* Definition for the {@link TypeNode}.
*/
export const typeDef = defineNode<TypeNode>({ kind: 'Type' })
/**
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
*
* @example
* ```ts
* createType({ name: 'Pet', export: true })
* // export type Pet = ...
* ```
*/
export const createType = typeDef.create
/**
* Definition for the {@link FunctionNode}.
*/
export const functionDef = defineNode<FunctionNode>({ kind: 'Function' })
/**
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
*
* @example
* ```ts
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
* // export async function fetchPet(): Promise<Pet> { ... }
* ```
*/
export const createFunction = functionDef.create
/**
* Definition for the {@link ArrowFunctionNode}.
*/
export const arrowFunctionDef = defineNode<ArrowFunctionNode>({ kind: 'ArrowFunction' })
/**
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
*
* @example
* ```ts
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
* // export const double = (n: number) => ...
* ```
*/
export const createArrowFunction = arrowFunctionDef.create
/**
* Definition for the {@link TextNode}.
*/
export const textDef = defineNode<TextNode, string>({ kind: 'Text', build: (value) => ({ value }) })
/**
* Creates a {@link TextNode} representing a raw string fragment in the source output.
*
* @example
* ```ts
* createText('return fetch(id)')
* // { kind: 'Text', value: 'return fetch(id)' }
* ```
*/
export const createText = textDef.create
/**
* Definition for the {@link BreakNode}.
*/
export const breakDef = defineNode<BreakNode, void>({ kind: 'Break', build: () => ({}) })
/**
* Creates a {@link BreakNode} representing a line break in the source output.
*
* @example
* ```ts
* createBreak()
* // { kind: 'Break' }
* ```
*/
export function createBreak(): BreakNode {
return breakDef.create()
}
/**
* Definition for the {@link JsxNode}.
*/
export const jsxDef = defineNode<JsxNode, string>({ kind: 'Jsx', build: (value) => ({ value }) })
/**
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
*
* @example
* ```ts
* createJsx('<>\n <a href={href}>Open</a>\n</>')
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
* ```
*/
export const createJsx = jsxDef.create

@@ -0,1 +1,2 @@

import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'

@@ -38,1 +39,19 @@ import type { SchemaNode } from './schema.ts'

}
/**
* Loosely-typed content entry accepted by the builders, normalized into a {@link ContentNode}.
*/
export type UserContent = Omit<ContentNode, 'kind'>
/**
* Definition for the {@link ContentNode}.
*/
export const contentDef = defineNode<ContentNode, UserContent>({
kind: 'Content',
children: ['schema'],
})
/**
* Creates a `ContentNode` for a single request-body or response content type.
*/
export const createContent = contentDef.create

@@ -0,1 +1,2 @@

import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'

@@ -233,1 +234,54 @@ import type { CodeNode } from './code.ts'

}
/**
* Definition for the {@link ImportNode}.
*/
export const importDef = defineNode<ImportNode>({ kind: 'Import' })
/**
* Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
*
* @example Named import
* ```ts
* createImport({ name: ['useState'], path: 'react' })
* // import { useState } from 'react'
* ```
*/
export const createImport = importDef.create
/**
* Definition for the {@link ExportNode}.
*/
export const exportDef = defineNode<ExportNode>({ kind: 'Export' })
/**
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
*
* @example Named export
* ```ts
* createExport({ name: ['Pet'], path: './Pet' })
* // export { Pet } from './Pet'
* ```
*/
export const createExport = exportDef.create
/**
* Definition for the {@link SourceNode}.
*/
export const sourceDef = defineNode<SourceNode>({ kind: 'Source' })
/**
* Creates a `SourceNode` representing a fragment of source code within a file.
*
* @example
* ```ts
* createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
* ```
*/
export const createSource = sourceDef.create
/**
* Definition for the {@link FileNode}. The fully resolved builder lives in
* `createFile`, so this definition only supplies the guard.
*/
export const fileDef = defineNode<FileNode>({ kind: 'File' })

@@ -0,78 +1,101 @@

import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'
/**
* AST node representing a language-agnostic type expression used as a function parameter
* type annotation. Each language printer renders the variant into its own syntax.
* A language-agnostic type expression used as a function parameter type annotation.
*
* - `struct` an inline anonymous type grouping named fields.
* TypeScript renders as `{ petId: string; name?: string }`.
* - `member` a single named field accessed from a named group type.
* TypeScript renders as `PathParams['petId']`.
* - a plain `string` is a type reference rendered as-is, e.g. `'string'`, `'QueryParams'`, `'Partial<Config>'`
* - a {@link TypeLiteralNode} is an inline anonymous type, e.g. `{ petId: string; name?: string }`
* - an {@link IndexedAccessTypeNode} is a single field accessed from a named type, e.g. `PathParams['petId']`
*/
export type TypeExpression = string | TypeLiteralNode | IndexedAccessTypeNode
/**
* AST node for an inline anonymous object type grouping named fields.
* TypeScript renders as `{ key: Type; other?: OtherType }`.
*
* @example Reference variant
* @example
* ```ts
* createParamsType({ variant: 'reference', name: 'QueryParams' })
* // QueryParams
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
* // { petId: string }
* ```
*/
export type TypeLiteralNode = BaseNode & {
/**
* Node kind.
*/
kind: 'TypeLiteral'
/**
* Members of the object type, rendered in order.
*/
members: Array<{
/**
* Member key.
*/
name: string
/**
* Member type expression.
*/
type: TypeExpression
/**
* Whether the member is optional, rendered with `?`.
*/
optional?: boolean
}>
}
/**
* AST node for a single field accessed from a named group type.
* TypeScript renders as `objectType['indexType']`.
*
* @example Struct variant
* @example
* ```ts
* createParamsType({ variant: 'struct', properties: [{ name: 'petId', optional: false, type: createParamsType({ variant: 'reference', name: 'string' }) }] })
* // { petId: string }
* createIndexedAccessType({ objectType: 'GetPetPathParams', indexType: 'petId' })
* // GetPetPathParams['petId']
* ```
*/
export type IndexedAccessTypeNode = BaseNode & {
/**
* Node kind.
*/
kind: 'IndexedAccessType'
/**
* Name of the type being indexed, e.g. `'GetPetPathParams'`.
*/
objectType: string
/**
* Field key to access, e.g. `'petId'`.
*/
indexType: string
}
/**
* AST node for an object destructuring binding, used as the name of a grouped function parameter.
* TypeScript renders as `{ id, name }` or `{ id: renamed }` when `propertyName` differs.
*
* @example Member variant
* @example
* ```ts
* createParamsType({ variant: 'member', base: 'PathParams', key: 'petId' })
* // PathParams['petId']
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
* // { id, name }
* ```
*/
export type ParamsTypeNode = BaseNode & {
export type ObjectBindingPatternNode = BaseNode & {
/**
* Node kind.
*/
kind: 'ParamsType'
} & (
| {
/**
* Reference variant, a plain type name or identifier.
* TypeScript renders as-is, e.g. `string`, `QueryParams`, `Partial<Config>`.
*/
variant: 'reference'
/**
* The full type name string, e.g. `'string'`, `'QueryParams'`, `'Partial<Config>'`.
*/
name: string
}
| {
/**
* Struct variant, an inline anonymous type grouping named fields.
* TypeScript renders as `{ key: Type; other?: OtherType }`.
*/
variant: 'struct'
/**
* Properties of the struct type.
*/
properties: Array<{
name: string
optional: boolean
type: ParamsTypeNode
}>
}
| {
/**
* Member variant, a single named field accessed from a group type.
* TypeScript renders as `Base['key']`.
*/
variant: 'member'
/**
* Base type name, e.g. `'DeletePetPathParams'`.
*/
base: string
/**
* The field name to access, e.g. `'petId'`.
*/
key: string
}
)
kind: 'ObjectBindingPattern'
/**
* Bound elements, rendered in order.
*/
elements: Array<{
/**
* Local binding name.
*/
name: string
/**
* Source key when it differs from the binding name, rendered as `propertyName: name`.
*/
propertyName?: string
}>
}

@@ -82,2 +105,5 @@ /**

*
* A simple parameter has a `string` name. A destructured group has an
* {@link ObjectBindingPatternNode} name paired with a {@link TypeLiteralNode} type.
*
* @example Required parameter

@@ -94,2 +120,5 @@ * `name: Type`

* `...name: Type[]`
*
* @example Destructured group
* `{ id, name? }: { id: string; name?: string } = {}`
*/

@@ -102,92 +131,21 @@ export type FunctionParameterNode = BaseNode & {

/**
* Parameter name in the generated signature.
* Parameter name, or an {@link ObjectBindingPatternNode} for a destructured group.
*/
name: string
name: string | ObjectBindingPatternNode
/**
* Type annotation as a structured {@link ParamsTypeNode}.
* Omit for untyped output.
*
* @example Reference type node
* `{ kind: 'ParamsType', variant: 'reference', name: 'string' }` → `petId: string`
*
* @example Struct type node
* `{ kind: 'ParamsType', variant: 'struct', properties: [...] }` → `{ key: Type; other?: OtherType }`
*
* @example Member type node
* `{ kind: 'ParamsType', variant: 'member', base: 'PathParams', key: 'petId' }` → `PathParams['petId']`
* Type annotation as a {@link TypeExpression}. Omit for untyped output.
*/
type?: ParamsTypeNode
type?: TypeExpression
/**
* When `true` the parameter is emitted as a rest parameter.
*
* @example Rest parameter
* `...name: Type[]`
* Whether the parameter is optional, rendered with `?`.
*/
rest?: boolean
} /**
* Optional parameter, rendered with `?` and may be omitted by the caller.
* Cannot be combined with `default` because a defaulted parameter is already optional.
*/ & (
| { optional: true; default?: never }
/**
* Required parameter, or a parameter with a default value.
*
* @example Required
* `name: Type`
*
* @example With default
* `name: Type = default`
*/
| { optional?: false; default?: string }
)
/**
* AST node for a group of related function parameters treated as a single unit.
*
* Each language printer decides how to render this group:
* - TypeScript/JS: destructured object `{ key1, key2 }: { key1: Type1; key2: Type2 } = {}`
* - Python: keyword-only args or a typed dict parameter
* - C# / Kotlin: named record / data-class parameter
*
* When `inline` is `true`, the group is spread as individual top-level parameters
* rather than wrapped in a single grouped construct.
*
* @example Grouped destructuring
* `{ id, name }: { id: string; name: string } = {}`
*
* @example Inline (spread as individual parameters)
* `id: string, name: string`
*/
export type ParameterGroupNode = BaseNode & {
optional?: boolean
/**
* Node kind.
* Default value, written verbatim after `=`. Commonly `'{}'` for a destructured group.
*/
kind: 'ParameterGroup'
default?: string
/**
* The individual parameters that form the group.
* Rendered as a destructured object or spread inline when `inline` is `true`.
* When `true` the parameter is emitted as a rest parameter, e.g. `...name: Type[]`.
*/
properties: Array<FunctionParameterNode>
/**
* Optional explicit type annotation for the whole group.
* When absent, printers auto-compute it from `properties`.
*/
type?: ParamsTypeNode
/**
* When `true`, `properties` are emitted as individual top-level parameters instead of
* being wrapped in a single grouped construct.
*
* @default false
*/
inline?: boolean
/**
* Whether the group as a whole is optional.
* If omitted, printers infer this from child properties.
*/
optional?: boolean
/**
* Default value for the group, written verbatim after `=`.
* Commonly `'{}'` to allow omitting the argument entirely.
*/
default?: string
rest?: boolean
}

@@ -204,4 +162,2 @@

* - `call` → `(id, { method, url })` function call arguments
* - `keys` → `{ id, config }` key names only (for destructuring)
* - `values` → `{ id: id, config: config }` key → value pairs
*/

@@ -216,3 +172,3 @@ export type FunctionParametersNode = BaseNode & {

*/
params: ReadonlyArray<FunctionParameterNode | ParameterGroupNode>
params: ReadonlyArray<FunctionParameterNode>
}

@@ -223,3 +179,3 @@

*/
export type FunctionParamNode = FunctionParameterNode | ParameterGroupNode | FunctionParametersNode | ParamsTypeNode
export type FunctionParamNode = FunctionParameterNode | FunctionParametersNode | TypeLiteralNode | IndexedAccessTypeNode | ObjectBindingPatternNode

@@ -229,2 +185,121 @@ /**

*/
export type FunctionNodeType = 'functionParameter' | 'parameterGroup' | 'functionParameters' | 'paramsType'
export type FunctionNodeType = 'functionParameter' | 'functionParameters' | 'typeLiteral' | 'indexedAccessType' | 'objectBindingPattern'
/**
* Definition for the {@link TypeLiteralNode}.
*/
export const typeLiteralDef = defineNode<TypeLiteralNode, Pick<TypeLiteralNode, 'members'>>({ kind: 'TypeLiteral' })
/**
* Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
*
* @example
* ```ts
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
* // { petId: string }
* ```
*/
export const createTypeLiteral = typeLiteralDef.create
/**
* Definition for the {@link IndexedAccessTypeNode}.
*/
export const indexedAccessTypeDef = defineNode<IndexedAccessTypeNode, Omit<IndexedAccessTypeNode, 'kind'>>({ kind: 'IndexedAccessType' })
/**
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
*
* @example
* ```ts
* createIndexedAccessType({ objectType: 'DeletePetPathParams', indexType: 'petId' })
* // DeletePetPathParams['petId']
* ```
*/
export const createIndexedAccessType = indexedAccessTypeDef.create
/**
* Definition for the {@link ObjectBindingPatternNode}.
*/
export const objectBindingPatternDef = defineNode<ObjectBindingPatternNode, Pick<ObjectBindingPatternNode, 'elements'>>({ kind: 'ObjectBindingPattern' })
/**
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
*
* @example
* ```ts
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
* // { id, name }
* ```
*/
export const createObjectBindingPattern = objectBindingPatternDef.create
/**
* Plain property descriptor for a destructured group built by {@link createFunctionParameter}.
*/
type FunctionParameterProperty = {
name: string
type: TypeExpression
optional?: boolean
}
type FunctionParameterInput =
| { name: string; type?: TypeExpression; optional?: boolean; default?: string; rest?: boolean }
| { properties: Array<FunctionParameterProperty>; optional?: boolean; default?: string }
/**
* Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
* Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
* paired with a {@link TypeLiteralNode} type.
*/
export const functionParameterDef = defineNode<FunctionParameterNode, FunctionParameterInput>({
kind: 'FunctionParameter',
build: (input) => {
if ('properties' in input) {
return {
name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
type: createTypeLiteral({ members: input.properties.map((p) => ({ name: p.name, type: p.type, optional: p.optional ?? false })) }),
optional: input.optional ?? false,
...(input.default !== undefined ? { default: input.default } : {}),
}
}
return { optional: false, ...input }
},
})
/**
* Creates a `FunctionParameterNode`. `optional` defaults to `false`.
*
* @example Optional param
* ```ts
* createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
* // → params?: QueryParams
* ```
*
* @example Destructured group
* ```ts
* createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
* // → { id, name }: { id: string; name?: string } = {}
* ```
*/
export const createFunctionParameter = functionParameterDef.create
/**
* Definition for the {@link FunctionParametersNode}.
*/
export const functionParametersDef = defineNode<FunctionParametersNode, Partial<Omit<FunctionParametersNode, 'kind'>>>({
kind: 'FunctionParameters',
defaults: { params: [] },
})
/**
* Creates a `FunctionParametersNode` from an ordered list of parameters.
*
* @example
* ```ts
* const empty = createFunctionParameters()
* // { kind: 'FunctionParameters', params: [] }
* ```
*/
export function createFunctionParameters(props: Partial<Omit<FunctionParametersNode, 'kind'>> = {}): FunctionParametersNode {
return functionParametersDef.create(props)
}
import type { ArrowFunctionNode, ConstNode, FunctionNode, TypeNode } from './code.ts'
import type { ContentNode } from './content.ts'
import type { ExportNode, FileNode, ImportNode, SourceNode } from './file.ts'
import type { FunctionParamNode, ParamsTypeNode } from './function.ts'
import type { FunctionParamNode } from './function.ts'
import type { InputNode } from './input.ts'

@@ -18,3 +18,12 @@ import type { OperationNode } from './operation.ts'

export type { ExportNode, FileNode, ImportNode, SourceNode } from './file.ts'
export type { FunctionNodeType, FunctionParameterNode, FunctionParametersNode, FunctionParamNode, ParameterGroupNode, ParamsTypeNode } from './function.ts'
export type {
FunctionNodeType,
FunctionParameterNode,
FunctionParametersNode,
FunctionParamNode,
IndexedAccessTypeNode,
ObjectBindingPatternNode,
TypeExpression,
TypeLiteralNode,
} from './function.ts'
export type { StatusCode } from './http.ts'

@@ -85,4 +94,3 @@ export type { InputMeta, InputNode } from './input.ts'

| TypeNode
| ParamsTypeNode
| FunctionNode
| ArrowFunctionNode
import type { Streamable } from '@internals/utils'
import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'

@@ -104,1 +105,36 @@ import type { OperationNode } from './operation.ts'

} & (Stream extends true ? { meta?: InputMeta } : { meta: InputMeta })
/**
* Definition for the {@link InputNode}.
*/
export const inputDef = defineNode<InputNode, Partial<Omit<InputNode, 'kind'>>>({
kind: 'Input',
defaults: { schemas: [], operations: [], meta: { circularNames: [], enumNames: [] } },
children: ['schemas', 'operations'],
visitorKey: 'input',
})
/**
* Creates an `InputNode` with stable defaults for `schemas` and `operations`.
*
* @example
* ```ts
* const input = createInput()
* // { kind: 'Input', schemas: [], operations: [] }
* ```
*/
export function createInput(overrides: Partial<Omit<InputNode, 'kind'>> = {}): InputNode {
return inputDef.create(overrides)
}
/**
* Creates a streaming `InputNode<true>` from pre-built `AsyncIterable` sources.
*
* @example
* ```ts
* const node = createStreamInput(schemasIterable, operationsIterable, { title: 'My API' })
* ```
*/
export function createStreamInput(schemas: AsyncIterable<SchemaNode>, operations: AsyncIterable<OperationNode>, meta?: InputMeta): InputNode<true> {
return { kind: 'Input', schemas, operations, meta }
}

@@ -0,4 +1,5 @@

import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'
import type { ParameterNode } from './parameter.ts'
import type { RequestBodyNode } from './requestBody.ts'
import { createRequestBody, type RequestBodyNode, type UserRequestBody } from './requestBody.ts'
import type { ResponseNode } from './response.ts'

@@ -108,1 +109,58 @@

export type OperationNode = HttpOperationNode | GenericOperationNode
type OperationInput = {
operationId: string
method?: HttpOperationNode['method']
path?: HttpOperationNode['path']
requestBody?: UserRequestBody
[key: string]: unknown
}
/**
* Definition for the {@link OperationNode}. HTTP operations (those carrying both
* `method` and `path`) are tagged with `protocol: 'http'`, and the request body is
* normalized into a `RequestBodyNode`.
*/
export const operationDef = defineNode<OperationNode, OperationInput>({
kind: 'Operation',
build: (props) => {
const { requestBody, ...rest } = props
const isHttp = rest.method !== undefined && rest.path !== undefined
return {
tags: [],
parameters: [],
responses: [],
...rest,
...(isHttp ? { protocol: 'http' as const } : {}),
requestBody: requestBody ? createRequestBody(requestBody) : undefined,
}
},
children: ['parameters', 'requestBody', 'responses'],
visitorKey: 'operation',
})
/**
* Creates an `OperationNode` with default empty arrays for `tags`, `parameters`, and `responses`.
*
* @example
* ```ts
* const operation = createOperation({ operationId: 'getPetById', method: 'GET', path: '/pet/{petId}' })
* // tags, parameters, and responses are []
* ```
*/
export function createOperation(
props: Pick<HttpOperationNode, 'operationId' | 'method' | 'path'> &
Partial<Omit<HttpOperationNode, 'kind' | 'operationId' | 'method' | 'path' | 'requestBody'>> & {
requestBody?: UserRequestBody
},
): HttpOperationNode
export function createOperation(
props: Pick<GenericOperationNode, 'operationId'> &
Partial<Omit<GenericOperationNode, 'kind' | 'operationId' | 'requestBody'>> & {
requestBody?: UserRequestBody
},
): GenericOperationNode
export function createOperation(props: OperationInput): OperationNode {
return operationDef.create(props)
}

@@ -0,1 +1,2 @@

import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'

@@ -27,1 +28,23 @@ import type { FileNode } from './file.ts'

}
/**
* Definition for the {@link OutputNode}.
*/
export const outputDef = defineNode<OutputNode, Partial<Omit<OutputNode, 'kind'>>>({
kind: 'Output',
defaults: { files: [] },
visitorKey: 'output',
})
/**
* Creates an `OutputNode` with a stable default for `files`.
*
* @example
* ```ts
* const output = createOutput()
* // { kind: 'Output', files: [] }
* ```
*/
export function createOutput(overrides: Partial<Omit<OutputNode, 'kind'>> = {}): OutputNode {
return outputDef.create(overrides)
}

@@ -0,1 +1,2 @@

import { defineNode, syncOptionality } from '../node.ts'
import type { BaseNode } from './base.ts'

@@ -42,1 +43,33 @@ import type { SchemaNode } from './schema.ts'

}
type UserParameterNode = Pick<ParameterNode, 'name' | 'in' | 'schema'> & Partial<Omit<ParameterNode, 'kind' | 'name' | 'in' | 'schema'>>
/**
* Definition for the {@link ParameterNode}. `required` defaults to `false` and the
* schema's `optional`/`nullish` flags are kept in sync with it.
*/
export const parameterDef = defineNode<ParameterNode, UserParameterNode>({
kind: 'Parameter',
build: (props) => {
const required = props.required ?? false
return { ...props, required, schema: syncOptionality(props.schema, required) }
},
children: ['schema'],
visitorKey: 'parameter',
rebuild: true,
})
/**
* Creates a `ParameterNode`.
*
* @example
* ```ts
* const param = createParameter({
* name: 'petId',
* in: 'path',
* required: true,
* schema: createSchema({ type: 'string' }),
* })
* ```
*/
export const createParameter = parameterDef.create

@@ -0,1 +1,2 @@

import { defineNode, syncOptionality } from '../node.ts'
import type { BaseNode } from './base.ts'

@@ -35,1 +36,36 @@ import type { SchemaNode } from './schema.ts'

}
/**
* Loosely-typed property accepted by `createProperty`, with `required` optional.
*/
export type UserPropertyNode = Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>
/**
* Definition for the {@link PropertyNode}. `required` defaults to `false` and the
* schema's `optional`/`nullish` flags are kept in sync with it.
*/
export const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
kind: 'Property',
build: (props) => {
const required = props.required ?? false
return { ...props, required, schema: syncOptionality(props.schema, required) }
},
children: ['schema'],
visitorKey: 'property',
rebuild: true,
})
/**
* Creates a `PropertyNode`.
*
* @example
* ```ts
* const property = createProperty({
* name: 'status',
* required: true,
* schema: createSchema({ type: 'string', nullable: true }),
* })
* // required=true, no optional/nullish
* ```
*/
export const createProperty = propertyDef.create

@@ -0,3 +1,4 @@

import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'
import type { ContentNode } from './content.ts'
import { type ContentNode, createContent, type UserContent } from './content.ts'

@@ -43,1 +44,22 @@ /**

}
/**
* Loosely-typed request body accepted by `createOperation`, normalized into a {@link RequestBodyNode}.
*/
export type UserRequestBody = Omit<RequestBodyNode, 'kind' | 'content'> & {
content?: Array<UserContent>
}
/**
* Definition for the {@link RequestBodyNode}, normalizing each content entry into a `ContentNode`.
*/
export const requestBodyDef = defineNode<RequestBodyNode, UserRequestBody>({
kind: 'RequestBody',
build: (props) => ({ ...props, content: props.content?.map(createContent) }),
children: ['content'],
})
/**
* Creates a `RequestBodyNode`, normalizing each content entry into a `ContentNode`.
*/
export const createRequestBody = requestBodyDef.create

@@ -0,4 +1,6 @@

import { defineNode } from '../node.ts'
import type { BaseNode } from './base.ts'
import type { ContentNode } from './content.ts'
import { type ContentNode, createContent, type UserContent } from './content.ts'
import type { StatusCode } from './http.ts'
import type { SchemaNode } from './schema.ts'

@@ -51,1 +53,37 @@ /**

}
type ResponseInput = Pick<ResponseNode, 'statusCode'> &
Partial<Omit<ResponseNode, 'kind' | 'statusCode' | 'content'>> & {
content?: Array<UserContent>
schema?: SchemaNode
mediaType?: string | null
keysToOmit?: Array<string> | null
}
/**
* Definition for the {@link ResponseNode}. A single legacy `schema` (with optional
* `mediaType`/`keysToOmit`) is normalized into one `content` entry.
*/
export const responseDef = defineNode<ResponseNode, ResponseInput>({
kind: 'Response',
build: (props) => {
const { schema, mediaType, keysToOmit, content, ...rest } = props
const entries = content ?? (schema ? [{ contentType: mediaType ?? 'application/json', schema, keysToOmit: keysToOmit ?? null }] : undefined)
return { ...rest, content: entries?.map(createContent) }
},
children: ['content'],
visitorKey: 'response',
})
/**
* Creates a `ResponseNode`.
*
* @example
* ```ts
* const response = createResponse({
* statusCode: '200',
* content: [{ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) }],
* })
* ```
*/
export const createResponse = responseDef.create

@@ -0,1 +1,3 @@

import type { InferSchemaNode } from '../infer.ts'
import { defineNode, type DistributiveOmit } from '../node.ts'
import type { BaseNode } from './base.ts'

@@ -660,1 +662,71 @@ import type { PropertyNode } from './property.ts'

| ScalarSchemaNode
type CreateSchemaObjectInput = Omit<ObjectSchemaNode, 'kind' | 'properties' | 'primitive'> & { properties?: Array<PropertyNode>; primitive?: 'object' }
type CreateSchemaInput = CreateSchemaObjectInput | DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>
type CreateSchemaOutput<T extends CreateSchemaInput> = InferSchemaNode<T> & {
kind: 'Schema'
}
/**
* Maps schema `type` to its underlying `primitive`.
* Primitive types map to themselves. Special string formats map to `'string'`.
* Complex types (`ref`, `enum`, `union`, `intersection`, `tuple`, `blob`) are left unset.
*/
const TYPE_TO_PRIMITIVE: Partial<Record<SchemaNode['type'], PrimitiveSchemaType>> = {
string: 'string',
number: 'number',
integer: 'integer',
bigint: 'bigint',
boolean: 'boolean',
null: 'null',
any: 'any',
unknown: 'unknown',
void: 'void',
never: 'never',
object: 'object',
array: 'array',
date: 'date',
uuid: 'string',
email: 'string',
url: 'string',
datetime: 'string',
time: 'string',
}
/**
* Definition for the {@link SchemaNode}. Object schemas default `properties` to an
* empty array, and `primitive` is inferred from `type` when not explicitly provided.
*/
export const schemaDef = defineNode<SchemaNode, CreateSchemaInput>({
kind: 'Schema',
build: (props) => {
if (props.type === 'object') {
return { properties: [], primitive: 'object' as const, ...props }
}
return { primitive: TYPE_TO_PRIMITIVE[props.type as keyof typeof TYPE_TO_PRIMITIVE], ...props }
},
children: ['properties', 'items', 'members', 'additionalProperties'],
visitorKey: 'schema',
})
/**
* Creates a `SchemaNode`, narrowed to the variant of `props.type`.
*
* @example
* ```ts
* const scalar = createSchema({ type: 'string' })
* // { kind: 'Schema', type: 'string', primitive: 'string' }
* ```
*
* @example
* ```ts
* const object = createSchema({ type: 'object' })
* // { kind: 'Schema', type: 'object', primitive: 'object', properties: [] }
* ```
*/
export function createSchema<T extends CreateSchemaInput>(props: T): CreateSchemaOutput<T>
export function createSchema(props: CreateSchemaInput): SchemaNode
export function createSchema(props: CreateSchemaInput): SchemaNode {
return schemaDef.create(props)
}
import { isScalarPrimitive } from './constants.ts'
import { createProperty, createSchema } from './factory.ts'
import { narrowSchema } from './guards.ts'
import type { SchemaNode } from './nodes/schema.ts'
import { createProperty } from './nodes/property.ts'
import { createSchema, type SchemaNode } from './nodes/schema.ts'
import { enumPropName } from './utils/index.ts'

@@ -6,0 +6,0 @@

export type { DedupeCanonical, DedupeLookups, DedupePlan } from './dedupe.ts'
export type { SchemaDialect } from './dialect.ts'
export type { DistributiveOmit } from './factory.ts'
export type { DistributiveOmit } from './node.ts'
export type { InferSchemaNode, ParserOptions } from './infer.ts'

@@ -23,2 +23,3 @@ export type {

ImportNode,
IndexedAccessTypeNode,
InputMeta,

@@ -32,9 +33,8 @@ InputNode,

NumberSchemaNode,
ObjectBindingPatternNode,
ObjectSchemaNode,
OperationNode,
OutputNode,
ParameterGroupNode,
ParameterLocation,
ParameterNode,
ParamsTypeNode,
PrimitiveSchemaType,

@@ -53,2 +53,4 @@ PropertyNode,

TimeSchemaNode,
TypeExpression,
TypeLiteralNode,
TypeNode,

@@ -55,0 +57,0 @@ UnionSchemaNode,

import { camelCase, isValidVarName, memoize } from '@internals/utils'
import { createFunctionParameter, createFunctionParameters, createParameterGroup, createParamsType, createProperty, createSchema } from '../factory.ts'
import { narrowSchema } from '../guards.ts'
import { createFunctionParameter, createFunctionParameters, createIndexedAccessType, createTypeLiteral } from '../nodes/function.ts'
import { createProperty } from '../nodes/property.ts'
import { createSchema } from '../nodes/schema.ts'
import type {

@@ -12,7 +14,7 @@ CodeNode,

OperationNode,
ParameterGroupNode,
ParameterNode,
ParamsTypeNode,
SchemaNode,
SourceNode,
TypeExpression,
TypeLiteralNode,
} from '../nodes/index.ts'

@@ -124,5 +126,5 @@ import type { SchemaType } from '../nodes/schema.ts'

/**
* TypeNode for the group type.
* Type expression for the group, a plain group-name reference.
*/
type: ParamsTypeNode
type: TypeExpression
/**

@@ -135,2 +137,11 @@ * Whether the parameter group is optional.

/**
* A single member of a destructured parameter group, fed to `createFunctionParameter({ properties })`.
*/
type GroupProperty = {
name: string
type: TypeExpression
optional?: boolean
}
/**
* Resolver interface for {@link createOperationParams}.

@@ -221,3 +232,3 @@ *

*/
extraParams?: Array<FunctionParameterNode | ParameterGroupNode>
extraParams?: Array<FunctionParameterNode>
/**

@@ -262,3 +273,10 @@ * Override the default parameter names used for body, query, header, and rest-path groups.

function resolveParamsType({
/**
* Resolves the {@link TypeExpression} for an individual parameter.
*
* Without a resolver, falls back to the schema primitive (a plain type-name string).
* When the parameter belongs to a named group, emits an {@link IndexedAccessTypeNode}
* (`GroupParams['petId']`); otherwise the resolved individual name as a plain string.
*/
export function resolveParamType({
node,

@@ -271,8 +289,5 @@ param,

resolver: OperationParamsResolver | undefined
}): ParamsTypeNode {
}): TypeExpression {
if (!resolver) {
return createParamsType({
variant: 'reference',
name: param.schema.primitive ?? 'unknown',
})
return param.schema.primitive ?? 'unknown'
}

@@ -293,10 +308,6 @@

if (groupName && groupName !== individualName) {
return createParamsType({
variant: 'member',
base: groupName,
key: param.name,
})
return createIndexedAccessType({ objectType: groupName, indexType: param.name })
}
return createParamsType({ variant: 'reference', name: individualName })
return individualName
}

@@ -307,6 +318,6 @@

*
* Centralizes parameter grouping logic for all plugins. Provide a `resolver` for type name resolution
* and `extraParams` for plugin-specific trailing parameters (e.g., `options` objects).
* Supports three grouping modes: `object` (single destructured param), `inline` (separate params),
* and `inlineSpread` (rest parameter). Use `CreateOperationParamsOptions` to fine-tune output.
* Centralizes parameter grouping logic for all plugins. `paramsType` chooses between one
* destructured object parameter (`object`) and separate top-level parameters (`inline`), while
* `pathParamsType` controls how path params render in inline mode. Provide a `resolver` for type
* name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
*/

@@ -321,10 +332,6 @@ export function createOperationParams(node: OperationNode, options: CreateOperationParamsOptions): FunctionParametersNode {

const wrapType = (type: string): ParamsTypeNode =>
createParamsType({
variant: 'reference',
name: typeWrapper ? typeWrapper(type) : type,
})
// Only reference-variant TypeNodes are wrapped, they hold a plain type name string that needs casing applied.
// Member and struct TypeNodes are pre-resolved structured expressions and are passed through unchanged.
const wrapTypeNode = (type: ParamsTypeNode): ParamsTypeNode => (type.kind === 'ParamsType' && type.variant === 'reference' ? wrapType(type.name) : type)
const wrapType = (type: string): string => (typeWrapper ? typeWrapper(type) : type)
// Only plain type-name references are wrapped, they need casing applied.
// TypeLiteral and IndexedAccessType expressions are pre-resolved and pass through unchanged.
const wrapTypeExpression = (type: TypeExpression): TypeExpression => (typeof type === 'string' ? wrapType(type) : type)

@@ -336,129 +343,44 @@ const casedParams = caseParams(node.parameters, paramsCasing)

const toProperty = (param: ParameterNode): GroupProperty => ({
name: param.name,
type: wrapTypeExpression(resolveParamType({ node, param, resolver })),
optional: !param.required,
})
const emptyObjectDefault = (props: Array<GroupProperty>): string | undefined => (props.every((p) => p.optional) ? '{}' : undefined)
const bodyType = node.requestBody?.content?.[0]?.schema ? wrapType(resolver?.resolveDataName(node) ?? 'unknown') : undefined
const bodyRequired = node.requestBody?.required ?? false
const bodyProperty: Array<GroupProperty> = bodyType ? [{ name: dataName, type: bodyType, optional: !(node.requestBody?.required ?? false) }] : []
const queryGroupType = resolver
? resolveGroupType({
node,
params: queryParams,
groupMethod: resolver.resolveQueryParamsName,
resolver,
})
: undefined
const headerGroupType = resolver
? resolveGroupType({
node,
params: headerParams,
groupMethod: resolver.resolveHeaderParamsName,
resolver,
})
: undefined
const trailingGroups: Array<BuildGroupArgs> = [
{ name: paramsName, node, params: queryParams, groupType: resolveGroupType({ node, params: queryParams, group: 'query', resolver }), resolver, wrapType },
{
name: headersName,
node,
params: headerParams,
groupType: resolveGroupType({ node, params: headerParams, group: 'header', resolver }),
resolver,
wrapType,
},
]
const params: Array<FunctionParameterNode | ParameterGroupNode> = []
const params: Array<FunctionParameterNode> = []
if (paramsType === 'object') {
const children: Array<FunctionParameterNode> = [
...pathParams.map((p) => {
const type = resolveParamsType({ node, param: p, resolver })
return createFunctionParameter({
name: p.name,
type: wrapTypeNode(type),
optional: !p.required,
})
}),
...(bodyType
? [
createFunctionParameter({
name: dataName,
type: bodyType,
optional: !bodyRequired,
}),
]
: []),
...buildGroupParam({
name: paramsName,
node,
params: queryParams,
groupType: queryGroupType,
resolver,
wrapType,
}),
...buildGroupParam({
name: headersName,
node,
params: headerParams,
groupType: headerGroupType,
resolver,
wrapType,
}),
]
const children = [...pathParams.map(toProperty), ...bodyProperty, ...trailingGroups.flatMap(buildGroupProperty)]
if (children.length) {
params.push(
createParameterGroup({
properties: children,
default: children.every((c) => c.optional) ? '{}' : undefined,
}),
)
params.push(createFunctionParameter({ properties: children, default: emptyObjectDefault(children) }))
}
} else {
if (pathParams.length) {
if (pathParamsType === 'inlineSpread') {
const spreadType = resolver?.resolvePathParamsName(node, pathParams[0]!)
params.push(
createFunctionParameter({
name: pathName,
type: spreadType ? wrapType(spreadType) : undefined,
rest: true,
}),
)
} else {
const pathChildren = pathParams.map((p) => {
const type = resolveParamsType({ node, param: p, resolver })
return createFunctionParameter({
name: p.name,
type: wrapTypeNode(type),
optional: !p.required,
})
})
params.push(
createParameterGroup({
properties: pathChildren,
inline: pathParamsType === 'inline',
default: pathParamsDefault ?? (pathChildren.every((c) => c.optional) ? '{}' : undefined),
}),
)
}
if (pathParamsType === 'inlineSpread' && pathParams.length) {
const spreadType = resolver?.resolvePathParamsName(node, pathParams[0]!)
params.push(createFunctionParameter({ name: pathName, type: spreadType ? wrapType(spreadType) : undefined, rest: true }))
} else if (pathParamsType === 'inline') {
params.push(...pathParams.map((p) => createFunctionParameter(toProperty(p))))
} else if (pathParams.length) {
const pathChildren = pathParams.map(toProperty)
params.push(createFunctionParameter({ properties: pathChildren, default: pathParamsDefault ?? emptyObjectDefault(pathChildren) }))
}
if (bodyType) {
params.push(
createFunctionParameter({
name: dataName,
type: bodyType,
optional: !bodyRequired,
}),
)
}
params.push(
...buildGroupParam({
name: paramsName,
node,
params: queryParams,
groupType: queryGroupType,
resolver,
wrapType,
}),
)
params.push(
...buildGroupParam({
name: headersName,
node,
params: headerParams,
groupType: headerGroupType,
resolver,
wrapType,
}),
)
params.push(...bodyProperty.map((p) => createFunctionParameter(p)))
params.push(...trailingGroups.flatMap(buildGroupParam))
}

@@ -472,35 +394,27 @@

/**
* Builds a single {@link FunctionParameterNode} for a query or header group.
* Returns an empty array when there are no params to emit.
*
* If a pre-resolved `groupType` is provided it emits `name: GroupType`.
* Otherwise, it builds an inline struct from the individual params.
* Shared arguments for building a query or header parameter group.
*/
function buildGroupParam({
name,
node,
params,
groupType,
resolver,
wrapType,
}: {
type BuildGroupArgs = {
name: string
node: OperationNode
params: Array<ParameterNode>
groupType: ParamGroupType | null | undefined
groupType: ParamGroupType | null
resolver: OperationParamsResolver | undefined
wrapType: (type: string) => ParamsTypeNode
}): Array<FunctionParameterNode> {
wrapType: (type: string) => string
}
/**
* Builds the property descriptor for a query or header group.
* Returns an empty array when there are no params to emit.
*
* A pre-resolved `groupType` emits `name: GroupType`. Otherwise it builds an inline
* {@link TypeLiteralNode} from the individual params.
*/
function buildGroupProperty({ name, node, params, groupType, resolver, wrapType }: BuildGroupArgs): Array<GroupProperty> {
if (groupType) {
const type = groupType.type.kind === 'ParamsType' && groupType.type.variant === 'reference' ? wrapType(groupType.type.name) : groupType.type
return [createFunctionParameter({ name, type, optional: groupType.optional })]
const type = typeof groupType.type === 'string' ? wrapType(groupType.type) : groupType.type
return [{ name, type, optional: groupType.optional }]
}
if (params.length) {
return [
createFunctionParameter({
name,
type: toStructType({ node, params, resolver }),
optional: params.every((p) => !p.required),
}),
]
return [{ name, type: buildTypeLiteral({ node, params, resolver }), optional: params.every((p) => !p.required) }]
}

@@ -511,9 +425,22 @@ return []

/**
* Derives a {@link ParamGroupType} from the resolver's group method.
* Returns `null` when the group name equals the individual param name (no real group).
* Builds a single {@link FunctionParameterNode} for a query or header group.
* Returns an empty array when there are no params to emit.
*
* A pre-resolved `groupType` emits `name: GroupType`. Otherwise it builds an inline
* {@link TypeLiteralNode} from the individual params.
*/
function resolveGroupType({
export function buildGroupParam(args: BuildGroupArgs): Array<FunctionParameterNode> {
return buildGroupProperty(args).map((p) => createFunctionParameter(p))
}
/**
* Derives a {@link ParamGroupType} for a query or header group from the resolver.
*
* Returns `null` when there is no resolver, no params, or the group name equals the
* individual param name (so there is no real group to emit).
*/
export function resolveGroupType({
node,
params,
groupMethod,
group,
resolver,

@@ -523,9 +450,10 @@ }: {

params: Array<ParameterNode>
groupMethod: (_node: OperationNode, _param: ParameterNode) => string
resolver: OperationParamsResolver
group: 'query' | 'header'
resolver: OperationParamsResolver | undefined
}): ParamGroupType | null {
if (!params.length) {
if (!resolver || !params.length) {
return null
}
const firstParam = params[0]!
const groupMethod = group === 'query' ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName
const groupName = groupMethod.call(resolver, node, firstParam)

@@ -535,11 +463,7 @@ if (groupName === resolver.resolveParamName(node, firstParam)) {

}
const allOptional = params.every((p) => !p.required)
return {
type: createParamsType({ variant: 'reference', name: groupName }),
optional: allOptional,
}
return { type: groupName, optional: params.every((p) => !p.required) }
}
/**
* Builds a {@link TypeNode} with `variant: 'struct'` for an inline anonymous type grouping named fields.
* Builds a {@link TypeLiteralNode} for an inline anonymous type grouping named fields.
*

@@ -549,3 +473,3 @@ * Used when query or header parameters have no dedicated group type name.

*/
function toStructType({
export function buildTypeLiteral({
node,

@@ -558,9 +482,8 @@ params,

resolver: OperationParamsResolver | undefined
}): ParamsTypeNode {
return createParamsType({
variant: 'struct',
properties: params.map((p) => ({
}): TypeLiteralNode {
return createTypeLiteral({
members: params.map((p) => ({
name: p.name,
type: resolveParamType({ node, param: p, resolver }),
optional: !p.required,
type: resolveParamsType({ node, param: p, resolver }),
})),

@@ -567,0 +490,0 @@ })

import type { VisitorDepth } from './constants.ts'
import { visitorDepths, WALK_CONCURRENCY } from './constants.ts'
import { createParameter, createProperty } from './factory.ts'
import { nodeRebuilders, VISITOR_KEY_BY_KIND, VISITOR_KEYS } from './registry.ts'
import type {

@@ -8,3 +8,2 @@ ContentNode,

Node,
NodeKind,
OperationNode,

@@ -285,20 +284,2 @@ OutputNode,

/**
* Child node fields per node kind, in traversal order (Babel's `VISITOR_KEYS`).
*
* Each listed property holds a child node, an array of child nodes, or, for
* `additionalProperties` a node or the literal `true` (skipped). Every value
* in a child slot is a node, so one table drives both `getChildren` and `transform`.
*/
const VISITOR_KEYS = {
Input: ['schemas', 'operations'],
Operation: ['parameters', 'requestBody', 'responses'],
RequestBody: ['content'],
Content: ['schema'],
Response: ['content'],
Schema: ['properties', 'items', 'members', 'additionalProperties'],
Property: ['schema'],
Parameter: ['schema'],
} as const satisfies Partial<Record<NodeKind, ReadonlyArray<string>>>
const visitorKeysByKind = VISITOR_KEYS as Record<string, ReadonlyArray<string> | undefined>

@@ -342,17 +323,2 @@

/**
* Maps a node `kind` to the matching visitor callback name. Only the seven
* traversable node kinds have an entry. Every other kind resolves to
* `undefined` and is skipped.
*/
const VISITOR_KEY_BY_KIND: Partial<Record<NodeKind, keyof Visitor>> = {
Input: 'input',
Output: 'output',
Operation: 'operation',
Schema: 'schema',
Property: 'property',
Parameter: 'parameter',
Response: 'response',
}
/**
* Invokes the visitor callback that matches `node.kind`, passing the traversal

@@ -461,17 +427,7 @@ * context. Returns the callback's result (a replacement node, a collected

const finalize = nodeFinalizers[rebuilt.kind]
return finalize ? finalize(rebuilt) : rebuilt
const rebuild = nodeRebuilders[rebuilt.kind]
return rebuild ? rebuild(rebuilt) : rebuilt
}
/**
* Per-kind builders rerun after children are rebuilt. `Property`/`Parameter`
* resync schema optionality against their `required` flag once the schema may
* have changed.
*/
const nodeFinalizers: Partial<Record<NodeKind, (node: Node) => Node>> = {
Property: (node) => createProperty(node as PropertyNode),
Parameter: (node) => createParameter(node as ParameterNode),
}
/**
* Immutably rebuilds a node's children using {@link VISITOR_KEYS}, transforming

@@ -478,0 +434,0 @@ * each child node and leaving non-node values (e.g. `additionalProperties: true`) intact.

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display