@kubb/ast 5.0.0-alpha.48 → 5.0.0-alpha.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,23 +1,33 @@
1
1
  {
2
2
  "name": "@kubb/ast",
3
- "version": "5.0.0-alpha.48",
3
+ "version": "5.0.0-alpha.49",
4
4
  "description": "Spec-agnostic AST layer for Kubb. Defines nodes, visitor pattern, and factory functions used across codegen plugins.",
5
5
  "keywords": [
6
- "kubb",
7
6
  "ast",
8
- "typescript",
9
7
  "codegen",
10
- "openapi"
8
+ "kubb",
9
+ "openapi",
10
+ "typescript"
11
11
  ],
12
+ "license": "MIT",
13
+ "author": "stijnvanhulle",
12
14
  "repository": {
13
15
  "type": "git",
14
16
  "url": "git+https://github.com/kubb-labs/kubb.git",
15
17
  "directory": "packages/ast"
16
18
  },
17
- "license": "MIT",
18
- "author": "stijnvanhulle",
19
- "sideEffects": false,
19
+ "files": [
20
+ "src",
21
+ "dist",
22
+ "!/**/**.test.**",
23
+ "!/**/__tests__/**",
24
+ "!/**/__snapshots__/**"
25
+ ],
20
26
  "type": "module",
27
+ "sideEffects": false,
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
21
31
  "exports": {
22
32
  ".": {
23
33
  "import": "./dist/index.js",
@@ -25,32 +35,22 @@
25
35
  },
26
36
  "./package.json": "./package.json"
27
37
  },
28
- "types": "./dist/index.d.ts",
29
- "files": [
30
- "src",
31
- "dist",
32
- "!/**/**.test.**",
33
- "!/**/__tests__/**",
34
- "!/**/__snapshots__/**"
35
- ],
38
+ "publishConfig": {
39
+ "access": "public",
40
+ "registry": "https://registry.npmjs.org/"
41
+ },
36
42
  "devDependencies": {
37
43
  "@types/node": "^25.6.0",
38
44
  "@internals/utils": "0.0.0"
39
45
  },
40
- "main": "./dist/index.cjs",
41
- "module": "./dist/index.js",
42
46
  "engines": {
43
47
  "node": ">=22"
44
48
  },
45
- "publishConfig": {
46
- "access": "public",
47
- "registry": "https://registry.npmjs.org/"
48
- },
49
49
  "scripts": {
50
50
  "build": "tsdown",
51
51
  "clean": "npx rimraf ./dist",
52
- "lint": "bun biome lint .",
53
- "lint:fix": "bun biome lint --fix --unsafe .",
52
+ "lint": "oxlint .",
53
+ "lint:fix": "oxlint --fix .",
54
54
  "release": "pnpm publish --no-git-check",
55
55
  "release:canary": "bash ../../.github/canary.sh && node ../../scripts/build.js canary && pnpm publish --no-git-check",
56
56
  "start": "tsdown --watch",
package/src/factory.ts CHANGED
@@ -61,7 +61,9 @@ export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omi
61
61
 
62
62
  type CreateSchemaObjectInput = Omit<ObjectSchemaNode, 'kind' | 'properties' | 'primitive'> & { properties?: Array<PropertyNode>; primitive?: 'object' }
63
63
  type CreateSchemaInput = CreateSchemaObjectInput | DistributiveOmit<Exclude<SchemaNode, ObjectSchemaNode>, 'kind'>
64
- type CreateSchemaOutput<T extends CreateSchemaInput> = InferSchemaNode<T> & { kind: 'Schema' }
64
+ type CreateSchemaOutput<T extends CreateSchemaInput> = InferSchemaNode<T> & {
65
+ kind: 'Schema'
66
+ }
65
67
 
66
68
  /**
67
69
  * Creates an `InputNode` with stable defaults for `schemas` and `operations`.
@@ -208,10 +210,19 @@ export function createSchema(props: CreateSchemaInput): SchemaNode {
208
210
  const inferredPrimitive = TYPE_TO_PRIMITIVE[props.type as keyof typeof TYPE_TO_PRIMITIVE]
209
211
 
210
212
  if (props['type'] === 'object') {
211
- return { properties: [], primitive: 'object', ...props, kind: 'Schema' } as CreateSchemaOutput<typeof props>
213
+ return {
214
+ properties: [],
215
+ primitive: 'object',
216
+ ...props,
217
+ kind: 'Schema',
218
+ } as CreateSchemaOutput<typeof props>
212
219
  }
213
220
 
214
- return { primitive: inferredPrimitive, ...props, kind: 'Schema' } as CreateSchemaOutput<typeof props>
221
+ return {
222
+ primitive: inferredPrimitive,
223
+ ...props,
224
+ kind: 'Schema',
225
+ } as CreateSchemaOutput<typeof props>
215
226
  }
216
227
 
217
228
  type UserPropertyNode = Pick<PropertyNode, 'name' | 'schema'> & Partial<Omit<PropertyNode, 'kind' | 'name' | 'schema'>>
@@ -369,7 +380,14 @@ export function createFunctionParameter(
369
380
  export function createParamsType(
370
381
  props:
371
382
  | { variant: 'reference'; name: string }
372
- | { variant: 'struct'; properties: Array<{ name: string; optional: boolean; type: ParamsTypeNode }> }
383
+ | {
384
+ variant: 'struct'
385
+ properties: Array<{
386
+ name: string
387
+ optional: boolean
388
+ type: ParamsTypeNode
389
+ }>
390
+ }
373
391
  | { variant: 'member'; base: string; key: string },
374
392
  ): ParamsTypeNode {
375
393
  return { ...props, kind: 'ParamsType' } as ParamsTypeNode
package/src/index.ts CHANGED
@@ -34,12 +34,5 @@ export { childName, collectImports, enumPropName, findDiscriminator } from './re
34
34
  export { mergeAdjacentObjects, setDiscriminatorEnum, setEnumName, simplifyUnion } from './transformers.ts'
35
35
  export type * from './types.ts'
36
36
  export type { OperationParamsResolver } from './utils.ts'
37
- export {
38
- caseParams,
39
- createDiscriminantNode,
40
- createOperationParams,
41
- extractStringsFromNodes,
42
- isStringType,
43
- syncSchemaRef,
44
- } from './utils.ts'
37
+ export { caseParams, createDiscriminantNode, createOperationParams, extractStringsFromNodes, isStringType, syncSchemaRef } from './utils.ts'
45
38
  export { collect, transform, walk } from './visitor.ts'
package/src/mocks.ts CHANGED
@@ -9,8 +9,16 @@ export function buildSampleTree(): InputNode {
9
9
  type: 'object',
10
10
  name: 'Pet',
11
11
  properties: [
12
- createProperty({ name: 'id', schema: createSchema({ type: 'integer' }), required: true }),
13
- createProperty({ name: 'name', schema: createSchema({ type: 'string' }), required: true }),
12
+ createProperty({
13
+ name: 'id',
14
+ schema: createSchema({ type: 'integer' }),
15
+ required: true,
16
+ }),
17
+ createProperty({
18
+ name: 'name',
19
+ schema: createSchema({ type: 'string' }),
20
+ required: true,
21
+ }),
14
22
  ],
15
23
  })
16
24
 
@@ -19,9 +27,19 @@ export function buildSampleTree(): InputNode {
19
27
  method: 'GET',
20
28
  path: '/pets/{petId}',
21
29
  tags: ['pets'],
22
- parameters: [createParameter({ name: 'petId', in: 'path', schema: createSchema({ type: 'integer' }), required: true })],
30
+ parameters: [
31
+ createParameter({
32
+ name: 'petId',
33
+ in: 'path',
34
+ schema: createSchema({ type: 'integer' }),
35
+ required: true,
36
+ }),
37
+ ],
23
38
  responses: [
24
- createResponse({ statusCode: '200', schema: createSchema({ type: 'ref', name: 'Pet' }) }),
39
+ createResponse({
40
+ statusCode: '200',
41
+ schema: createSchema({ type: 'ref', name: 'Pet' }),
42
+ }),
25
43
  createResponse({
26
44
  statusCode: '404',
27
45
  schema: createSchema({ type: 'ref', name: 'Error' }),
@@ -47,14 +65,28 @@ export function buildFixture(): InputNode {
47
65
  name: 'Pet',
48
66
  type: 'object',
49
67
  properties: [
50
- createProperty({ name: 'id', schema: createSchema({ type: 'integer' }), required: true }),
51
- createProperty({ name: 'name', schema: createSchema({ type: 'string' }), required: true }),
68
+ createProperty({
69
+ name: 'id',
70
+ schema: createSchema({ type: 'integer' }),
71
+ required: true,
72
+ }),
73
+ createProperty({
74
+ name: 'name',
75
+ schema: createSchema({ type: 'string' }),
76
+ required: true,
77
+ }),
52
78
  ],
53
79
  }),
54
80
  createSchema({
55
81
  name: 'NewPet',
56
82
  type: 'object',
57
- properties: [createProperty({ name: 'name', schema: createSchema({ type: 'string' }), required: true })],
83
+ properties: [
84
+ createProperty({
85
+ name: 'name',
86
+ schema: createSchema({ type: 'string' }),
87
+ required: true,
88
+ }),
89
+ ],
58
90
  }),
59
91
  createSchema({
60
92
  name: 'PetList',
@@ -65,11 +97,23 @@ export function buildFixture(): InputNode {
65
97
  name: 'Error',
66
98
  type: 'object',
67
99
  properties: [
68
- createProperty({ name: 'code', schema: createSchema({ type: 'integer' }), required: true }),
69
- createProperty({ name: 'message', schema: createSchema({ type: 'string' }), required: true }),
100
+ createProperty({
101
+ name: 'code',
102
+ schema: createSchema({ type: 'integer' }),
103
+ required: true,
104
+ }),
105
+ createProperty({
106
+ name: 'message',
107
+ schema: createSchema({ type: 'string' }),
108
+ required: true,
109
+ }),
70
110
  ],
71
111
  }),
72
- createSchema({ name: 'PetOrError', type: 'union', members: [refPet, refError] }),
112
+ createSchema({
113
+ name: 'PetOrError',
114
+ type: 'union',
115
+ members: [refPet, refError],
116
+ }),
73
117
  createSchema({
74
118
  name: 'FullPet',
75
119
  type: 'intersection',
@@ -77,7 +121,12 @@ export function buildFixture(): InputNode {
77
121
  refPet,
78
122
  createSchema({
79
123
  type: 'object',
80
- properties: [createProperty({ name: 'createdAt', schema: createSchema({ type: 'datetime' }) })],
124
+ properties: [
125
+ createProperty({
126
+ name: 'createdAt',
127
+ schema: createSchema({ type: 'datetime' }),
128
+ }),
129
+ ],
81
130
  }),
82
131
  ],
83
132
  }),
@@ -88,10 +137,24 @@ export function buildFixture(): InputNode {
88
137
  method: 'GET',
89
138
  path: '/pets',
90
139
  tags: ['pets'],
91
- parameters: [createParameter({ name: 'limit', in: 'query', schema: createSchema({ type: 'integer' }) })],
140
+ parameters: [
141
+ createParameter({
142
+ name: 'limit',
143
+ in: 'query',
144
+ schema: createSchema({ type: 'integer' }),
145
+ }),
146
+ ],
92
147
  responses: [
93
- createResponse({ statusCode: '200', schema: createSchema({ type: 'ref', ref: 'PetList' }), mediaType: 'application/json' }),
94
- createResponse({ statusCode: '400', schema: refError, mediaType: 'application/json' }),
148
+ createResponse({
149
+ statusCode: '200',
150
+ schema: createSchema({ type: 'ref', ref: 'PetList' }),
151
+ mediaType: 'application/json',
152
+ }),
153
+ createResponse({
154
+ statusCode: '400',
155
+ schema: refError,
156
+ mediaType: 'application/json',
157
+ }),
95
158
  ],
96
159
  }),
97
160
  createOperation({
@@ -100,7 +163,13 @@ export function buildFixture(): InputNode {
100
163
  path: '/pets',
101
164
  tags: ['pets'],
102
165
  requestBody: { schema: createSchema({ type: 'ref', ref: 'NewPet' }) },
103
- responses: [createResponse({ statusCode: '201', schema: refPet, mediaType: 'application/json' })],
166
+ responses: [
167
+ createResponse({
168
+ statusCode: '201',
169
+ schema: refPet,
170
+ mediaType: 'application/json',
171
+ }),
172
+ ],
104
173
  }),
105
174
  ],
106
175
  })
@@ -53,7 +53,11 @@ export type ParamsTypeNode = BaseNode & {
53
53
  /**
54
54
  * Properties of the struct type.
55
55
  */
56
- properties: Array<{ name: string; optional: boolean; type: ParamsTypeNode }>
56
+ properties: Array<{
57
+ name: string
58
+ optional: boolean
59
+ type: ParamsTypeNode
60
+ }>
57
61
  }
58
62
  | {
59
63
  /**
package/src/printer.ts CHANGED
@@ -201,11 +201,20 @@ export function createPrinterFactory<TNode, TKey extends string, TNodeByKey exte
201
201
  options: T['options']
202
202
  nodes: Partial<{
203
203
  [K in TKey]: (
204
- this: { transform: (node: TNode) => T['output'] | null | undefined; options: T['options'] },
204
+ this: {
205
+ transform: (node: TNode) => T['output'] | null | undefined
206
+ options: T['options']
207
+ },
205
208
  node: TNodeByKey[K],
206
209
  ) => T['output'] | null | undefined
207
210
  }>
208
- print?: (this: { transform: (node: TNode) => T['output'] | null | undefined; options: T['options'] }, node: TNode) => T['printOutput'] | null | undefined
211
+ print?: (
212
+ this: {
213
+ transform: (node: TNode) => T['output'] | null | undefined
214
+ options: T['options']
215
+ },
216
+ node: TNode,
217
+ ) => T['printOutput'] | null | undefined
209
218
  },
210
219
  ): (options?: T['options']) => {
211
220
  name: T['name']
@@ -149,7 +149,10 @@ export function setEnumName(propNode: SchemaNode, parentName: string | null | un
149
149
  }
150
150
 
151
151
  if (enumNode) {
152
- return { ...propNode, name: enumPropName(parentName, propName, enumSuffix) }
152
+ return {
153
+ ...propNode,
154
+ name: enumPropName(parentName, propName, enumSuffix),
155
+ }
153
156
  }
154
157
 
155
158
  return propNode
package/src/utils.ts CHANGED
@@ -273,7 +273,10 @@ function resolveParamsType({
273
273
  resolver: OperationParamsResolver | undefined
274
274
  }): ParamsTypeNode {
275
275
  if (!resolver) {
276
- return createParamsType({ variant: 'reference', name: param.schema.primitive ?? 'unknown' })
276
+ return createParamsType({
277
+ variant: 'reference',
278
+ name: param.schema.primitive ?? 'unknown',
279
+ })
277
280
  }
278
281
 
279
282
  const individualName = resolver.resolveParamName(node, param)
@@ -289,7 +292,11 @@ function resolveParamsType({
289
292
  const groupName = groupLocation ? groupResolvers[groupLocation].call(resolver, node, param) : undefined
290
293
 
291
294
  if (groupName && groupName !== individualName) {
292
- return createParamsType({ variant: 'member', base: groupName, key: param.name })
295
+ return createParamsType({
296
+ variant: 'member',
297
+ base: groupName,
298
+ key: param.name,
299
+ })
293
300
  }
294
301
 
295
302
  return createParamsType({ variant: 'reference', name: individualName })
@@ -319,7 +326,11 @@ export function createOperationParams(node: OperationNode, options: CreateOperat
319
326
  const headersName = paramNames?.headers ?? 'headers'
320
327
  const pathName = paramNames?.path ?? 'pathParams'
321
328
 
322
- const wrapType = (type: string): ParamsTypeNode => createParamsType({ variant: 'reference', name: typeWrapper ? typeWrapper(type) : type })
329
+ const wrapType = (type: string): ParamsTypeNode =>
330
+ createParamsType({
331
+ variant: 'reference',
332
+ name: typeWrapper ? typeWrapper(type) : type,
333
+ })
323
334
  // Only reference-variant TypeNodes are wrapped — they hold a plain type name string that needs casing applied.
324
335
  // Member and struct TypeNodes are pre-resolved structured expressions and are passed through unchanged.
325
336
  const wrapTypeNode = (type: ParamsTypeNode): ParamsTypeNode => (type.kind === 'ParamsType' && type.variant === 'reference' ? wrapType(type.name) : type)
@@ -332,8 +343,22 @@ export function createOperationParams(node: OperationNode, options: CreateOperat
332
343
  const bodyType = node.requestBody?.schema ? wrapType(resolver?.resolveDataName(node) ?? 'unknown') : undefined
333
344
  const bodyRequired = node.requestBody?.required ?? false
334
345
 
335
- const queryGroupType = resolver ? resolveGroupType({ node, params: queryParams, groupMethod: resolver.resolveQueryParamsName, resolver }) : undefined
336
- const headerGroupType = resolver ? resolveGroupType({ node, params: headerParams, groupMethod: resolver.resolveHeaderParamsName, resolver }) : undefined
346
+ const queryGroupType = resolver
347
+ ? resolveGroupType({
348
+ node,
349
+ params: queryParams,
350
+ groupMethod: resolver.resolveQueryParamsName,
351
+ resolver,
352
+ })
353
+ : undefined
354
+ const headerGroupType = resolver
355
+ ? resolveGroupType({
356
+ node,
357
+ params: headerParams,
358
+ groupMethod: resolver.resolveHeaderParamsName,
359
+ resolver,
360
+ })
361
+ : undefined
337
362
 
338
363
  const params: Array<FunctionParameterNode | ParameterGroupNode> = []
339
364
 
@@ -341,25 +366,66 @@ export function createOperationParams(node: OperationNode, options: CreateOperat
341
366
  const children: Array<FunctionParameterNode> = [
342
367
  ...pathParams.map((p) => {
343
368
  const type = resolveParamsType({ node, param: p, resolver })
344
- return createFunctionParameter({ name: p.name, type: wrapTypeNode(type), optional: !p.required })
369
+ return createFunctionParameter({
370
+ name: p.name,
371
+ type: wrapTypeNode(type),
372
+ optional: !p.required,
373
+ })
374
+ }),
375
+ ...(bodyType
376
+ ? [
377
+ createFunctionParameter({
378
+ name: dataName,
379
+ type: bodyType,
380
+ optional: !bodyRequired,
381
+ }),
382
+ ]
383
+ : []),
384
+ ...buildGroupParam({
385
+ name: paramsName,
386
+ node,
387
+ params: queryParams,
388
+ groupType: queryGroupType,
389
+ resolver,
390
+ wrapType,
391
+ }),
392
+ ...buildGroupParam({
393
+ name: headersName,
394
+ node,
395
+ params: headerParams,
396
+ groupType: headerGroupType,
397
+ resolver,
398
+ wrapType,
345
399
  }),
346
- ...(bodyType ? [createFunctionParameter({ name: dataName, type: bodyType, optional: !bodyRequired })] : []),
347
- ...buildGroupParam({ name: paramsName, node, params: queryParams, groupType: queryGroupType, resolver, wrapType }),
348
- ...buildGroupParam({ name: headersName, node, params: headerParams, groupType: headerGroupType, resolver, wrapType }),
349
400
  ]
350
401
 
351
402
  if (children.length) {
352
- params.push(createParameterGroup({ properties: children, default: children.every((c) => c.optional) ? '{}' : undefined }))
403
+ params.push(
404
+ createParameterGroup({
405
+ properties: children,
406
+ default: children.every((c) => c.optional) ? '{}' : undefined,
407
+ }),
408
+ )
353
409
  }
354
410
  } else {
355
411
  if (pathParams.length) {
356
412
  if (pathParamsType === 'inlineSpread') {
357
413
  const spreadType = resolver?.resolvePathParamsName(node, pathParams[0]!) ?? undefined
358
- params.push(createFunctionParameter({ name: pathName, type: spreadType ? wrapType(spreadType) : undefined, rest: true }))
414
+ params.push(
415
+ createFunctionParameter({
416
+ name: pathName,
417
+ type: spreadType ? wrapType(spreadType) : undefined,
418
+ rest: true,
419
+ }),
420
+ )
359
421
  } else {
360
422
  const pathChildren = pathParams.map((p) => {
361
423
  const type = resolveParamsType({ node, param: p, resolver })
362
- return createFunctionParameter({ name: p.name, type: wrapTypeNode(type), optional: !p.required })
424
+ return createFunctionParameter({
425
+ name: p.name,
426
+ type: wrapTypeNode(type),
427
+ optional: !p.required,
428
+ })
363
429
  })
364
430
  params.push(
365
431
  createParameterGroup({
@@ -372,11 +438,35 @@ export function createOperationParams(node: OperationNode, options: CreateOperat
372
438
  }
373
439
 
374
440
  if (bodyType) {
375
- params.push(createFunctionParameter({ name: dataName, type: bodyType, optional: !bodyRequired }))
441
+ params.push(
442
+ createFunctionParameter({
443
+ name: dataName,
444
+ type: bodyType,
445
+ optional: !bodyRequired,
446
+ }),
447
+ )
376
448
  }
377
449
 
378
- params.push(...buildGroupParam({ name: paramsName, node, params: queryParams, groupType: queryGroupType, resolver, wrapType }))
379
- params.push(...buildGroupParam({ name: headersName, node, params: headerParams, groupType: headerGroupType, resolver, wrapType }))
450
+ params.push(
451
+ ...buildGroupParam({
452
+ name: paramsName,
453
+ node,
454
+ params: queryParams,
455
+ groupType: queryGroupType,
456
+ resolver,
457
+ wrapType,
458
+ }),
459
+ )
460
+ params.push(
461
+ ...buildGroupParam({
462
+ name: headersName,
463
+ node,
464
+ params: headerParams,
465
+ groupType: headerGroupType,
466
+ resolver,
467
+ wrapType,
468
+ }),
469
+ )
380
470
  }
381
471
 
382
472
  params.push(...extraParams)
@@ -446,7 +536,10 @@ function resolveGroupType({
446
536
  return undefined
447
537
  }
448
538
  const allOptional = params.every((p) => !p.required)
449
- return { type: createParamsType({ variant: 'reference', name: groupName }), optional: allOptional }
539
+ return {
540
+ type: createParamsType({ variant: 'reference', name: groupName }),
541
+ optional: allOptional,
542
+ }
450
543
  }
451
544
 
452
545
  /**
@@ -466,7 +559,11 @@ function toStructType({
466
559
  }): ParamsTypeNode {
467
560
  return createParamsType({
468
561
  variant: 'struct',
469
- properties: params.map((p) => ({ name: p.name, optional: !p.required, type: resolveParamsType({ node, param: p, resolver }) })),
562
+ properties: params.map((p) => ({
563
+ name: p.name,
564
+ optional: !p.required,
565
+ type: resolveParamsType({ node, param: p, resolver }),
566
+ })),
470
567
  })
471
568
  }
472
569