@kubb/ast 5.0.0-alpha.22 → 5.0.0-alpha.24

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/src/utils.ts CHANGED
@@ -1,21 +1,22 @@
1
1
  import { camelCase, isValidVarName } from '@internals/utils'
2
2
 
3
+ import { createFunctionParameter, createFunctionParameters, createParameterGroup, createProperty, createSchema, createTypeNode } from './factory.ts'
3
4
  import { narrowSchema } from './guards.ts'
4
- import type { ParameterNode, SchemaNode } from './nodes/index.ts'
5
+ import type { FunctionParameterNode, FunctionParametersNode, OperationNode, ParameterGroupNode, ParameterNode, SchemaNode, TypeNode } from './nodes/index.ts'
5
6
  import type { SchemaType } from './nodes/schema.ts'
6
7
 
7
8
  const plainStringTypes = new Set<SchemaType>(['string', 'uuid', 'email', 'url', 'datetime'] as const)
8
9
 
9
10
  /**
10
- * Returns `true` when a schema is emitted as a plain TypeScript `string`.
11
+ * Returns `true` when a schema is emitted as a plain `string` type.
11
12
  *
12
13
  * - `string`, `uuid`, `email`, `url`, `datetime` are always plain strings.
13
14
  * - `date` and `time` are plain strings when their `representation` is `'string'` rather than `'date'`.
14
15
  *
15
16
  * @example
16
17
  * ```ts
17
- * isStringType(createSchema({ type: 'uuid' })) // true
18
- * isStringType(createSchema({ type: 'date', representation: 'date' })) // false
18
+ * isStringType(createSchema({ type: 'uuid' })) // true
19
+ * isStringType(createSchema({ type: 'date', representation: 'date' })) // false
19
20
  * ```
20
21
  */
21
22
  export function isStringType(node: SchemaNode): boolean {
@@ -61,17 +62,367 @@ export function caseParams(params: Array<ParameterNode>, casing: 'camelcase' | u
61
62
  }
62
63
 
63
64
  /**
64
- * Syncs property/parameter schema optionality flags from `required` and `schema.nullable`.
65
+ * Creates a single-property object schema used as a discriminator literal.
65
66
  *
66
- * - `optional` is set for non-required, non-nullable schemas.
67
- * - `nullish` is set for non-required, nullable schemas.
67
+ * @example
68
+ * ```ts
69
+ * createDiscriminantNode({ propertyName: 'type', value: 'dog' })
70
+ * // -> { type: 'object', properties: [{ name: 'type', required: true, schema: enum('dog') }] }
71
+ * ```
72
+ */
73
+ export function createDiscriminantNode({ propertyName, value }: { propertyName: string; value: string }): SchemaNode {
74
+ return createSchema({
75
+ type: 'object',
76
+ primitive: 'object',
77
+ properties: [
78
+ createProperty({
79
+ name: propertyName,
80
+ schema: createSchema({
81
+ type: 'enum',
82
+ primitive: 'string',
83
+ enumValues: [value],
84
+ }),
85
+ required: true,
86
+ }),
87
+ ],
88
+ })
89
+ }
90
+
91
+ /**
92
+ * Named type for a group of parameters (query or header) emitted as a single typed parameter.
93
+ */
94
+ export type ParamGroupType = {
95
+ /**
96
+ * TypeNode for the group type.
97
+ */
98
+ type: TypeNode
99
+ /**
100
+ * Whether the parameter group is optional.
101
+ */
102
+ optional: boolean
103
+ }
104
+
105
+ /**
106
+ * Resolver interface for {@link createOperationParams}.
107
+ *
108
+ * `ResolverTs` from `@kubb/plugin-ts` satisfies this interface and can be passed directly.
109
+ */
110
+ export type OperationParamsResolver = {
111
+ /**
112
+ * Resolves the type name for an individual parameter.
113
+ *
114
+ * @example Individual path parameter name
115
+ * `resolver.resolveParamName(node, param) // → 'DeletePetPathPetId'`
116
+ */
117
+ resolveParamName(node: OperationNode, param: ParameterNode): string
118
+ /**
119
+ * Resolves the request body type name.
120
+ *
121
+ * @example Request body type name
122
+ * `resolver.resolveDataName(node) // → 'CreatePetData'`
123
+ */
124
+ resolveDataName(node: OperationNode): string
125
+ /**
126
+ * Resolves the grouped path parameters type name.
127
+ * When the return value equals `resolveParamName`, no indexed access is emitted.
128
+ *
129
+ * @example Grouped path params type name
130
+ * `resolver.resolvePathParamsName(node, param) // → 'DeletePetPathParams'`
131
+ */
132
+ resolvePathParamsName(node: OperationNode, param: ParameterNode): string
133
+ /**
134
+ * Resolves the grouped query parameters type name.
135
+ * When the return value equals `resolveParamName`, an inline struct type is emitted instead.
136
+ *
137
+ * @example Grouped query params type name
138
+ * `resolver.resolveQueryParamsName(node, param) // → 'FindPetsByStatusQueryParams'`
139
+ */
140
+ resolveQueryParamsName(node: OperationNode, param: ParameterNode): string
141
+ /**
142
+ * Resolves the grouped header parameters type name.
143
+ * When the return value equals `resolveParamName`, an inline struct type is emitted instead.
144
+ *
145
+ * @example Grouped header params type name
146
+ * `resolver.resolveHeaderParamsName(node, param) // → 'DeletePetHeaderParams'`
147
+ */
148
+ resolveHeaderParamsName(node: OperationNode, param: ParameterNode): string
149
+ }
150
+
151
+ /**
152
+ * Options for {@link createOperationParams}.
68
153
  */
69
- export function syncOptionality(required: boolean, schema: SchemaNode): SchemaNode {
70
- const nullable = schema.nullable ?? false
154
+ export type CreateOperationParamsOptions = {
155
+ /**
156
+ * How all operation parameters are grouped in the function signature.
157
+ * - `'object'` wraps all params into a single destructured object `{ petId, data, params }`
158
+ * - `'inline'` emits each param category as a separate top-level parameter
159
+ */
160
+ paramsType: 'object' | 'inline'
161
+ /**
162
+ * How path parameters are emitted when `paramsType` is `'inline'`.
163
+ * - `'object'` groups them as `{ petId, storeId }: PathParams`
164
+ * - `'inline'` spreads them as individual parameters `petId: string, storeId: string`
165
+ * - `'inlineSpread'` emits a single rest parameter `...pathParams: PathParams`
166
+ */
167
+ pathParamsType: 'object' | 'inline' | 'inlineSpread'
168
+ /**
169
+ * Converts parameter names to camelCase before output.
170
+ */
171
+ paramsCasing?: 'camelcase'
172
+ /**
173
+ * Resolver for parameter and request body type names.
174
+ * Pass `ResolverTs` from `@kubb/plugin-ts` directly.
175
+ * When omitted, falls back to the schema primitive or `'unknown'`.
176
+ */
177
+ resolver?: OperationParamsResolver
178
+ /**
179
+ * Default value for the path parameters binding when `pathParamsType` is `'object'`.
180
+ * Falls back to `'{}'` when all path params are optional.
181
+ */
182
+ pathParamsDefault?: string
183
+ /**
184
+ * Extra parameters appended after the standard operation parameters.
185
+ *
186
+ * @example Plugin-specific trailing parameter
187
+ * ```ts
188
+ * extraParams: [createFunctionParameter({ name: 'options', type: 'Partial<RequestOptions>', default: '{}' })]
189
+ * ```
190
+ */
191
+ extraParams?: Array<FunctionParameterNode | ParameterGroupNode>
192
+ /**
193
+ * Override the default parameter names used for body, query, header, and rest-path groups.
194
+ *
195
+ * Useful when targeting languages or frameworks with different naming conventions.
196
+ *
197
+ * @default { data: 'data', params: 'params', headers: 'headers', path: 'pathParams' }
198
+ */
199
+ paramNames?: {
200
+ /**
201
+ * Name for the request body parameter.
202
+ * @default 'data'
203
+ */
204
+ data?: string
205
+ /**
206
+ * Name for the query parameters group parameter.
207
+ * @default 'params'
208
+ */
209
+ params?: string
210
+ /**
211
+ * Name for the header parameters group parameter.
212
+ * @default 'headers'
213
+ */
214
+ headers?: string
215
+ /**
216
+ * Name for the rest path-parameters parameter when `pathParamsType` is `'inlineSpread'`.
217
+ * @default 'pathParams'
218
+ */
219
+ path?: string
220
+ }
221
+ /**
222
+ * Applies a uniform transformation to every resolved type name before it is used
223
+ * in a parameter node. Use this for framework-level type wrappers.
224
+ *
225
+ * @example Vue Query — wrap every parameter type with `MaybeRefOrGetter`
226
+ * `typeWrapper: (t) => \`MaybeRefOrGetter<${t}>\``
227
+ */
228
+ typeWrapper?: (type: string) => string
229
+ }
71
230
 
72
- return {
73
- ...schema,
74
- optional: !required && !nullable ? true : undefined,
75
- nullish: !required && nullable ? true : undefined,
231
+ function resolveType({ node, param, resolver }: { node: OperationNode; param: ParameterNode; resolver: OperationParamsResolver | undefined }): TypeNode {
232
+ if (!resolver) {
233
+ return createTypeNode({ variant: 'reference', name: param.schema.primitive ?? 'unknown' })
76
234
  }
235
+
236
+ const individualName = resolver.resolveParamName(node, param)
237
+
238
+ const groupLocation = param.in === 'path' || param.in === 'query' || param.in === 'header' ? param.in : undefined
239
+
240
+ const groupResolvers = {
241
+ path: resolver.resolvePathParamsName,
242
+ query: resolver.resolveQueryParamsName,
243
+ header: resolver.resolveHeaderParamsName,
244
+ } as const
245
+
246
+ const groupName = groupLocation ? groupResolvers[groupLocation].call(resolver, node, param) : undefined
247
+
248
+ if (groupName && groupName !== individualName) {
249
+ return createTypeNode({ variant: 'member', base: groupName, key: param.name })
250
+ }
251
+
252
+ return createTypeNode({ variant: 'reference', name: individualName })
253
+ }
254
+
255
+ /**
256
+ * Converts an {@link OperationNode} into a {@link FunctionParametersNode}.
257
+ *
258
+ * Centralizes the per-plugin `getParams()` pattern. Provide a `resolver` for
259
+ * type resolution and `extraParams` for plugin-specific trailing parameters.
260
+ *
261
+ * @example
262
+ * ```ts
263
+ * const params = createOperationParams(node, {
264
+ * paramsType: 'inline',
265
+ * pathParamsType: 'inline',
266
+ * resolver: tsResolver,
267
+ * extraParams: [createFunctionParameter({ name: 'options', type: createTypeNode({ variant: 'reference', name: 'Partial<RequestOptions>' }), default: '{}' })],
268
+ * })
269
+ * ```
270
+ */
271
+ export function createOperationParams(node: OperationNode, options: CreateOperationParamsOptions): FunctionParametersNode {
272
+ const { paramsType, pathParamsType, paramsCasing, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options
273
+
274
+ const dataName = paramNames?.data ?? 'data'
275
+ const paramsName = paramNames?.params ?? 'params'
276
+ const headersName = paramNames?.headers ?? 'headers'
277
+ const pathName = paramNames?.path ?? 'pathParams'
278
+
279
+ const wrapType = (type: string): TypeNode => createTypeNode({ variant: 'reference', name: typeWrapper ? typeWrapper(type) : type })
280
+ // Only reference TypeNodes are wrapped (they hold a plain type name string).
281
+ // Member and struct TypeNodes are pre-resolved structured expressions and are passed through unchanged.
282
+ const wrapTypeNode = (type: TypeNode): TypeNode => (type.variant === 'reference' ? wrapType(type.name) : type)
283
+
284
+ const casedParams = caseParams(node.parameters, paramsCasing)
285
+ const pathParams = casedParams.filter((p) => p.in === 'path')
286
+ const queryParams = casedParams.filter((p) => p.in === 'query')
287
+ const headerParams = casedParams.filter((p) => p.in === 'header')
288
+
289
+ const bodyType = node.requestBody?.schema ? wrapType(resolver?.resolveDataName(node) ?? 'unknown') : undefined
290
+ const bodyRequired = node.requestBody?.required ?? false
291
+
292
+ const queryGroupType = resolver ? resolveGroupType({ node, params: queryParams, groupMethod: resolver.resolveQueryParamsName, resolver }) : undefined
293
+ const headerGroupType = resolver ? resolveGroupType({ node, params: headerParams, groupMethod: resolver.resolveHeaderParamsName, resolver }) : undefined
294
+
295
+ const params: Array<FunctionParameterNode | ParameterGroupNode> = []
296
+
297
+ if (paramsType === 'object') {
298
+ const children: Array<FunctionParameterNode> = [
299
+ ...pathParams.map((p) => {
300
+ const type = resolveType({ node, param: p, resolver })
301
+ return createFunctionParameter({ name: p.name, type: wrapTypeNode(type), optional: !p.required })
302
+ }),
303
+ ...(bodyType ? [createFunctionParameter({ name: dataName, type: bodyType, optional: !bodyRequired })] : []),
304
+ ...buildGroupParam({ name: paramsName, node, params: queryParams, groupType: queryGroupType, resolver, wrapType }),
305
+ ...buildGroupParam({ name: headersName, node, params: headerParams, groupType: headerGroupType, resolver, wrapType }),
306
+ ]
307
+
308
+ if (children.length) {
309
+ params.push(createParameterGroup({ properties: children, default: children.every((c) => c.optional) ? '{}' : undefined }))
310
+ }
311
+ } else {
312
+ if (pathParams.length) {
313
+ if (pathParamsType === 'inlineSpread') {
314
+ const spreadType = resolver?.resolvePathParamsName(node, pathParams[0]!) ?? undefined
315
+ params.push(createFunctionParameter({ name: pathName, type: spreadType ? wrapType(spreadType) : undefined, rest: true }))
316
+ } else {
317
+ const pathChildren = pathParams.map((p) => {
318
+ const type = resolveType({ node, param: p, resolver })
319
+ return createFunctionParameter({ name: p.name, type: wrapTypeNode(type), optional: !p.required })
320
+ })
321
+ params.push(
322
+ createParameterGroup({
323
+ properties: pathChildren,
324
+ inline: pathParamsType === 'inline',
325
+ default: pathParamsDefault ?? (pathChildren.every((c) => c.optional) ? '{}' : undefined),
326
+ }),
327
+ )
328
+ }
329
+ }
330
+
331
+ if (bodyType) {
332
+ params.push(createFunctionParameter({ name: dataName, type: bodyType, optional: !bodyRequired }))
333
+ }
334
+
335
+ params.push(...buildGroupParam({ name: paramsName, node, params: queryParams, groupType: queryGroupType, resolver, wrapType }))
336
+ params.push(...buildGroupParam({ name: headersName, node, params: headerParams, groupType: headerGroupType, resolver, wrapType }))
337
+ }
338
+
339
+ params.push(...extraParams)
340
+
341
+ return createFunctionParameters({ params })
342
+ }
343
+
344
+ /**
345
+ * Builds a single {@link FunctionParameterNode} for a query or header group.
346
+ * Returns an empty array when there are no params to emit.
347
+ *
348
+ * If a pre-resolved `groupType` is provided it emits `name: GroupType`.
349
+ * Otherwise, it builds an inline struct from the individual params.
350
+ */
351
+ function buildGroupParam({
352
+ name,
353
+ node,
354
+ params,
355
+ groupType,
356
+ resolver,
357
+ wrapType,
358
+ }: {
359
+ name: string
360
+ node: OperationNode
361
+ params: Array<ParameterNode>
362
+ groupType: ParamGroupType | undefined
363
+ resolver: OperationParamsResolver | undefined
364
+ wrapType: (type: string) => TypeNode
365
+ }): Array<FunctionParameterNode> {
366
+ if (groupType) {
367
+ const type = groupType.type.variant === 'reference' ? wrapType(groupType.type.name) : groupType.type
368
+ return [createFunctionParameter({ name, type, optional: groupType.optional })]
369
+ }
370
+ if (params.length) {
371
+ return [
372
+ createFunctionParameter({
373
+ name,
374
+ type: toStructType({ node, params, resolver }),
375
+ optional: params.every((p) => !p.required),
376
+ }),
377
+ ]
378
+ }
379
+ return []
380
+ }
381
+
382
+ /**
383
+ * Derives a {@link ParamGroupType} from the resolver's group method.
384
+ * Returns `undefined` when the group name equals the individual param name (no real group).
385
+ */
386
+ function resolveGroupType({
387
+ node,
388
+ params,
389
+ groupMethod,
390
+ resolver,
391
+ }: {
392
+ node: OperationNode
393
+ params: Array<ParameterNode>
394
+ groupMethod: (_node: OperationNode, _param: ParameterNode) => string
395
+ resolver: OperationParamsResolver
396
+ }): ParamGroupType | undefined {
397
+ if (!params.length) {
398
+ return undefined
399
+ }
400
+ const firstParam = params[0]!
401
+ const groupName = groupMethod.call(resolver, node, firstParam)
402
+ if (groupName === resolver.resolveParamName(node, firstParam)) {
403
+ return undefined
404
+ }
405
+ const allOptional = params.every((p) => !p.required)
406
+ return { type: createTypeNode({ variant: 'reference', name: groupName }), optional: allOptional }
407
+ }
408
+
409
+ /**
410
+ * Builds a {@link TypeNode} with `variant: 'struct'` for an inline anonymous type grouping named fields.
411
+ *
412
+ * Used when query or header parameters have no dedicated group type name.
413
+ * Each language printer renders this appropriately (TypeScript: `{ petId: string; name?: string }`).
414
+ */
415
+ function toStructType({
416
+ node,
417
+ params,
418
+ resolver,
419
+ }: {
420
+ node: OperationNode
421
+ params: Array<ParameterNode>
422
+ resolver: OperationParamsResolver | undefined
423
+ }): TypeNode {
424
+ return createTypeNode({
425
+ variant: 'struct',
426
+ properties: params.map((p) => ({ name: p.name, optional: !p.required, type: resolveType({ node, param: p, resolver }) })),
427
+ })
77
428
  }
package/src/visitor.ts CHANGED
@@ -288,8 +288,9 @@ function getChildren(node: Node, recurse: boolean): Array<Node> {
288
288
  case 'Response':
289
289
  return node.schema ? [node.schema] : []
290
290
  case 'FunctionParameter':
291
- case 'ObjectBindingParameter':
291
+ case 'ParameterGroup':
292
292
  case 'FunctionParameters':
293
+ case 'Type':
293
294
  return []
294
295
  }
295
296
  }
@@ -342,7 +343,7 @@ async function _walk(node: Node, visitor: AsyncVisitor, recurse: boolean, limit:
342
343
  await limit(() => visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> }))
343
344
  break
344
345
  case 'FunctionParameter':
345
- case 'ObjectBindingParameter':
346
+ case 'ParameterGroup':
346
347
  case 'FunctionParameters':
347
348
  break
348
349
  }
@@ -457,8 +458,9 @@ export function transform(node: Node, options: TransformOptions): Node {
457
458
  }
458
459
  }
459
460
  case 'FunctionParameter':
460
- case 'ObjectBindingParameter':
461
+ case 'ParameterGroup':
461
462
  case 'FunctionParameters':
463
+ case 'Type':
462
464
  return node
463
465
  }
464
466
  }
@@ -546,7 +548,7 @@ export function collect<T>(node: Node, options: CollectOptions<T>): Array<T> {
546
548
  v = visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> })
547
549
  break
548
550
  case 'FunctionParameter':
549
- case 'ObjectBindingParameter':
551
+ case 'ParameterGroup':
550
552
  case 'FunctionParameters':
551
553
  break
552
554
  }
@@ -1,196 +0,0 @@
1
- import type { FunctionNode, FunctionNodeType } from '../nodes/function.ts'
2
- import type { FunctionParameterNode, FunctionParametersNode, ObjectBindingParameterNode } from '../nodes/index.ts'
3
- import type { PrinterFactoryOptions } from './printer.ts'
4
- import { createPrinterFactory } from './printer.ts'
5
-
6
- /**
7
- * Maps each function-printer handler key to its concrete node type.
8
- */
9
- export type FunctionNodeByType = {
10
- functionParameter: FunctionParameterNode
11
- objectBindingParameter: ObjectBindingParameterNode
12
- functionParameters: FunctionParametersNode
13
- }
14
-
15
- const kindToHandlerKey = {
16
- FunctionParameter: 'functionParameter',
17
- ObjectBindingParameter: 'objectBindingParameter',
18
- FunctionParameters: 'functionParameters',
19
- } satisfies Record<string, FunctionNodeType>
20
-
21
- /**
22
- * Creates a function-parameter printer factory.
23
- *
24
- * This wrapper uses `createPrinterFactory` and dispatches handlers by `node.kind`
25
- * (for function nodes) rather than by `node.type` (for schema nodes).
26
- *
27
- * @example
28
- * ```ts
29
- * type MyPrinter = PrinterFactoryOptions<'my', { mode: 'declaration' | 'call' }, string>
30
- *
31
- * export const myPrinter = defineFunctionPrinter<MyPrinter>((options) => ({
32
- * name: 'my',
33
- * options,
34
- * nodes: {
35
- * functionParameter(node) {
36
- * return options.mode === 'declaration' && node.type ? `${node.name}: ${node.type}` : node.name
37
- * },
38
- * objectBindingParameter(node) {
39
- * const inner = node.properties.map(p => this.transform(p)).filter(Boolean).join(', ')
40
- * return `{ ${inner} }`
41
- * },
42
- * functionParameters(node) {
43
- * return node.params.map(p => this.transform(p)).filter(Boolean).join(', ')
44
- * },
45
- * },
46
- * }))
47
- * ```
48
- */
49
- export const defineFunctionPrinter = createPrinterFactory<FunctionNode, FunctionNodeType, FunctionNodeByType>((node) => kindToHandlerKey[node.kind])
50
-
51
- export type FunctionPrinterOptions = {
52
- /**
53
- * Rendering modes supported by `functionPrinter`.
54
- *
55
- * | Mode | Output example | Use case |
56
- * |---------------|---------------------------------------------|---------------------------------|
57
- * | `declaration` | `id: string, config: Config = {}` | Function parameter declaration |
58
- * | `call` | `id, { method, url }` | Function call arguments |
59
- * | `keys` | `{ id, config }` | Key names only (destructuring) |
60
- * | `values` | `{ id: id, config: config }` | Key/value object entries |
61
- */
62
- mode: 'declaration' | 'call' | 'keys' | 'values'
63
- /**
64
- * Optional transformation applied to every parameter name before printing.
65
- */
66
- transformName?: (name: string) => string
67
- /**
68
- * Optional transformation applied to every type string before printing.
69
- */
70
- transformType?: (type: string) => string
71
- }
72
-
73
- type DefaultPrinter = PrinterFactoryOptions<'functionParameters', FunctionPrinterOptions, string>
74
-
75
- function rank(param: FunctionParameterNode | ObjectBindingParameterNode): number {
76
- if (param.kind === 'ObjectBindingParameter') {
77
- if (param.default) return 2
78
- const isOptional = param.optional ?? param.properties.every((p) => p.optional || p.default !== undefined)
79
- return isOptional ? 1 : 0
80
- }
81
- if (param.rest) return 3
82
- if (param.default) return 2
83
- return param.optional ? 1 : 0
84
- }
85
-
86
- function sortParams(params: Array<FunctionParameterNode | ObjectBindingParameterNode>): Array<FunctionParameterNode | ObjectBindingParameterNode> {
87
- return [...params].sort((a, b) => rank(a) - rank(b))
88
- }
89
-
90
- function sortChildParams(params: Array<FunctionParameterNode>): Array<FunctionParameterNode> {
91
- return [...params].sort((a, b) => rank(a) - rank(b))
92
- }
93
-
94
- /**
95
- * Default function-signature printer.
96
- * Covers the four standard output modes used across Kubb plugins.
97
- *
98
- * @example
99
- * ```ts
100
- * const printer = functionPrinter({ mode: 'declaration' })
101
- *
102
- * const sig = createFunctionParameters({
103
- * params: [
104
- * createFunctionParameter({ name: 'petId', type: 'string', optional: false }),
105
- * createFunctionParameter({ name: 'config', type: 'Config', optional: false, default: '{}' }),
106
- * ],
107
- * })
108
- *
109
- * printer.print(sig) // → "petId: string, config: Config = {}"
110
- * ```
111
- */
112
- export const functionPrinter = defineFunctionPrinter<DefaultPrinter>((options) => ({
113
- name: 'functionParameters',
114
- options,
115
- nodes: {
116
- functionParameter(node) {
117
- const { mode, transformName, transformType } = this.options
118
- const name = transformName ? transformName(node.name) : node.name
119
- const type = node.type && transformType ? transformType(node.type) : node.type
120
-
121
- if (mode === 'keys' || mode === 'values') {
122
- return node.rest ? `...${name}` : name
123
- }
124
-
125
- if (mode === 'call') {
126
- return node.rest ? `...${name}` : name
127
- }
128
-
129
- if (node.rest) {
130
- return type ? `...${name}: ${type}` : `...${name}`
131
- }
132
- if (type) {
133
- if (node.optional) return `${name}?: ${type}`
134
- return node.default ? `${name}: ${type} = ${node.default}` : `${name}: ${type}`
135
- }
136
- return node.default ? `${name} = ${node.default}` : name
137
- },
138
- objectBindingParameter(node) {
139
- const { mode, transformName, transformType } = this.options
140
- const sorted = sortChildParams(node.properties)
141
- const isOptional = node.optional ?? sorted.every((p) => p.optional || p.default !== undefined)
142
-
143
- if (node.inline) {
144
- return sorted
145
- .map((p) => this.transform(p))
146
- .filter(Boolean)
147
- .join(', ')
148
- }
149
-
150
- if (mode === 'keys' || mode === 'values') {
151
- const keys = sorted.map((p) => p.name).join(', ')
152
- return `{ ${keys} }`
153
- }
154
-
155
- if (mode === 'call') {
156
- const keys = sorted.map((p) => p.name).join(', ')
157
- return `{ ${keys} }`
158
- }
159
-
160
- const names = sorted.map((p) => {
161
- const n = transformName ? transformName(p.name) : p.name
162
-
163
- return n
164
- })
165
-
166
- const nameStr = names.length ? `{ ${names.join(', ')} }` : undefined
167
- if (!nameStr) return null
168
-
169
- let typeAnnotation = node.type
170
- if (!typeAnnotation) {
171
- const typeParts = sorted
172
- .filter((p) => p.type)
173
- .map((p) => {
174
- const t = transformType && p.type ? transformType(p.type) : p.type!
175
- return p.optional || p.default !== undefined ? `${p.name}?: ${t}` : `${p.name}: ${t}`
176
- })
177
- typeAnnotation = typeParts.length ? `{ ${typeParts.join('; ')} }` : undefined
178
- }
179
-
180
- if (typeAnnotation) {
181
- if (isOptional) return `${nameStr}: ${typeAnnotation} = ${node.default ?? '{}'}`
182
- return node.default ? `${nameStr}: ${typeAnnotation} = ${node.default}` : `${nameStr}: ${typeAnnotation}`
183
- }
184
-
185
- return node.default ? `${nameStr} = ${node.default}` : nameStr
186
- },
187
- functionParameters(node) {
188
- const sorted = sortParams(node.params)
189
-
190
- return sorted
191
- .map((p) => this.transform(p))
192
- .filter(Boolean)
193
- .join(', ')
194
- },
195
- },
196
- }))
@@ -1,3 +0,0 @@
1
- export { defineFunctionPrinter, functionPrinter } from './functionPrinter.ts'
2
- export type { Printer, PrinterFactoryOptions } from './printer.ts'
3
- export { createPrinterFactory, definePrinter } from './printer.ts'