@kubb/ast 5.0.0-beta.62 → 5.0.0-beta.63

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.
Files changed (73) hide show
  1. package/dist/{defineMacro-Vw-xQvq7.d.ts → defineMacro-BATi7xoC.d.ts} +4 -5
  2. package/dist/{defineMacro-BryDiuQl.cjs → defineMacro-CEZHaCXE.cjs} +5 -5
  3. package/dist/defineMacro-CEZHaCXE.cjs.map +1 -0
  4. package/dist/{defineMacro-CNkUpxia.js → defineMacro-Shz8f6SG.js} +3 -3
  5. package/dist/defineMacro-Shz8f6SG.js.map +1 -0
  6. package/dist/factory.cjs +56 -56
  7. package/dist/factory.cjs.map +1 -1
  8. package/dist/factory.d.ts +5 -5
  9. package/dist/factory.js +5 -5
  10. package/dist/factory.js.map +1 -1
  11. package/dist/{index-CTaN_ee_.d.ts → index-B9cc8MBS.d.ts} +46 -113
  12. package/dist/index.cjs +142 -271
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +12 -5
  15. package/dist/index.js +108 -236
  16. package/dist/index.js.map +1 -1
  17. package/dist/macros.cjs +12 -12
  18. package/dist/macros.cjs.map +1 -1
  19. package/dist/macros.d.ts +2 -2
  20. package/dist/macros.js +4 -4
  21. package/dist/macros.js.map +1 -1
  22. package/dist/{operationParams-B44p6EQy.d.ts → operationParams-k5CKwSWZ.d.ts} +9 -2
  23. package/dist/{visitor-DepQEKyp.js → refs-BjNDuCBD.js} +115 -120
  24. package/dist/refs-BjNDuCBD.js.map +1 -0
  25. package/dist/{visitor-B7Zlnp4c.cjs → refs-u5SDdyV7.cjs} +139 -144
  26. package/dist/refs-u5SDdyV7.cjs.map +1 -0
  27. package/dist/{response-BeG6hq2D.cjs → schema-BkvrrOAr.cjs} +171 -153
  28. package/dist/schema-BkvrrOAr.cjs.map +1 -0
  29. package/dist/{response-Rd1uisM1.js → schema-Cbnxmz4b.js} +166 -154
  30. package/dist/schema-Cbnxmz4b.js.map +1 -0
  31. package/dist/{types-DQTgVSwE.d.ts → types-BB_xgRJ3.d.ts} +55 -79
  32. package/dist/types.d.ts +5 -5
  33. package/dist/{utils-BDI3kXlb.cjs → utils-CEepwqmb.cjs} +74 -67
  34. package/dist/utils-CEepwqmb.cjs.map +1 -0
  35. package/dist/{utils-DW9rnfsD.js → utils-DaXkewb1.js} +56 -49
  36. package/dist/utils-DaXkewb1.js.map +1 -0
  37. package/dist/utils.cjs +11 -11
  38. package/dist/utils.d.ts +44 -29
  39. package/dist/utils.js +3 -3
  40. package/package.json +1 -1
  41. package/src/constants.ts +3 -6
  42. package/src/defineMacro.ts +1 -1
  43. package/src/defineNode.ts +6 -9
  44. package/src/definePrinter.ts +5 -3
  45. package/src/dialect.ts +23 -13
  46. package/src/factory.ts +4 -4
  47. package/src/index.ts +1 -1
  48. package/src/infer.ts +1 -1
  49. package/src/macros/macroEnumName.ts +1 -1
  50. package/src/nodes/code.ts +8 -5
  51. package/src/nodes/file.ts +5 -4
  52. package/src/nodes/operation.ts +3 -0
  53. package/src/nodes/parameter.ts +5 -5
  54. package/src/nodes/property.ts +5 -5
  55. package/src/nodes/schema.ts +4 -4
  56. package/src/optionality.ts +15 -0
  57. package/src/types.ts +1 -2
  58. package/src/utils/codegen.ts +6 -7
  59. package/src/utils/fileMerge.ts +7 -8
  60. package/src/utils/operationParams.ts +8 -8
  61. package/src/utils/refs.ts +14 -18
  62. package/src/utils/schemaGraph.ts +41 -33
  63. package/src/utils/schemaMerge.ts +2 -2
  64. package/src/visitor.ts +1 -1
  65. package/dist/defineMacro-BryDiuQl.cjs.map +0 -1
  66. package/dist/defineMacro-CNkUpxia.js.map +0 -1
  67. package/dist/response-BeG6hq2D.cjs.map +0 -1
  68. package/dist/response-Rd1uisM1.js.map +0 -1
  69. package/dist/utils-BDI3kXlb.cjs.map +0 -1
  70. package/dist/utils-DW9rnfsD.js.map +0 -1
  71. package/dist/visitor-B7Zlnp4c.cjs.map +0 -1
  72. package/dist/visitor-DepQEKyp.js.map +0 -1
  73. package/src/dedupe.ts +0 -231
package/src/dedupe.ts DELETED
@@ -1,231 +0,0 @@
1
- import type { Node, OperationNode, SchemaNode } from './nodes/index.ts'
2
- import { createSchema } from './nodes/schema.ts'
3
- import { signatureOf } from './signature.ts'
4
- import { extractRefName } from './utils/index.ts'
5
- import { collectLazy, transform } from './visitor.ts'
6
-
7
- /**
8
- * A canonical destination for a deduplicated shape: the shared schema name and
9
- * the synthetic `$ref` path that points at it.
10
- */
11
- export type DedupeCanonical = {
12
- /**
13
- * Canonical schema name every duplicate occurrence refers to.
14
- */
15
- name: string
16
- /**
17
- * `$ref` path stored on the generated `ref` nodes (for example `#/components/schemas/Status`).
18
- */
19
- ref: string
20
- }
21
-
22
- /**
23
- * The result of {@link buildDedupePlan}: a lookup from structural signature to its
24
- * canonical target, plus the freshly hoisted definitions that must be added to
25
- * the schema list.
26
- */
27
- export type DedupePlan = {
28
- /**
29
- * Maps a structural signature to the canonical schema that represents it.
30
- */
31
- canonicalBySignature: Map<string, DedupeCanonical>
32
- /**
33
- * Maps the name of a top-level schema that duplicates a canonical one to that canonical, so
34
- * references to the duplicate can be repointed at the first schema with the same content.
35
- */
36
- aliasNames: Map<string, DedupeCanonical>
37
- /**
38
- * New top-level schema definitions created for inline shapes that had no existing
39
- * named component. Nested duplicates inside each definition are already collapsed.
40
- */
41
- hoisted: Array<SchemaNode>
42
- }
43
-
44
- /**
45
- * The lookups {@link applyDedupe} needs from a {@link DedupePlan}.
46
- */
47
- export type DedupeLookups = Pick<DedupePlan, 'canonicalBySignature' | 'aliasNames'>
48
-
49
- /**
50
- * Options that inject the naming and candidate policy into {@link buildDedupePlan}.
51
- * The mechanics (grouping, counting, rewriting) live here. The policy lives in the caller.
52
- */
53
- export type BuildDedupePlanOptions = {
54
- /**
55
- * Returns `true` when a node should be deduplicated. This is the only gate, so it must
56
- * reject both ineligible kinds (return `false` for anything other than, say, enums and
57
- * objects) and unsafe shapes (e.g. nodes that reference a circular schema).
58
- */
59
- isCandidate: (node: SchemaNode) => boolean
60
- /**
61
- * Produces the canonical name for an inline shape with no existing named component.
62
- * Return `null` to leave the shape inline (for example when no contextual name exists).
63
- */
64
- nameFor: (node: SchemaNode, signature: string) => string | null
65
- /**
66
- * Builds the `$ref` path for a canonical name.
67
- */
68
- refFor: (name: string) => string
69
- /**
70
- * Minimum number of occurrences before a shape is deduplicated.
71
- *
72
- * @default 2
73
- */
74
- minOccurrences?: number
75
- }
76
-
77
- /**
78
- * Builds the shared `ref` replacement for a duplicate occurrence, carrying the
79
- * usage-slot and documentation fields that are not part of the canonical type.
80
- */
81
- function createRefNode(node: SchemaNode, canonical: DedupeCanonical): SchemaNode {
82
- return createSchema({
83
- type: 'ref',
84
- name: canonical.name,
85
- ref: canonical.ref,
86
- optional: node.optional,
87
- nullish: node.nullish,
88
- readOnly: node.readOnly,
89
- writeOnly: node.writeOnly,
90
- deprecated: node.deprecated,
91
- description: node.description,
92
- default: node.default,
93
- example: node.example,
94
- })
95
- }
96
-
97
- /**
98
- * Rewrites a node, replacing every candidate sub-schema whose signature has a canonical
99
- * target with a `ref` to that target. Replacing a node with a `ref` prunes its subtree,
100
- * so nested duplicates inside a replaced shape are not visited again. A `ref` that points
101
- * at a duplicate top-level schema (see `aliasNames`) is repointed at the first schema with
102
- * the same content.
103
- *
104
- * Pass `skipRootMatch` when rewriting a canonical definition so its own root is not
105
- * turned into a reference to itself. Nested duplicates are still collapsed.
106
- *
107
- * @example
108
- * ```ts
109
- * const next = applyDedupe(operationNode, plan)
110
- * ```
111
- */
112
- export function applyDedupe(node: SchemaNode, plan: DedupeLookups, skipRootMatch?: boolean): SchemaNode
113
- export function applyDedupe(node: OperationNode, plan: DedupeLookups, skipRootMatch?: boolean): OperationNode
114
- export function applyDedupe(node: Node, plan: DedupeLookups, skipRootMatch = false): Node {
115
- const { canonicalBySignature, aliasNames } = plan
116
- if (canonicalBySignature.size === 0 && aliasNames.size === 0) return node
117
-
118
- const root = node
119
-
120
- return transform(node, {
121
- schema(schemaNode) {
122
- if (schemaNode.type === 'ref') {
123
- const target = schemaNode.ref ? extractRefName(schemaNode.ref) : schemaNode.name
124
- const canonical = target ? aliasNames.get(target) : undefined
125
-
126
- return canonical ? { ...schemaNode, name: canonical.name, ref: canonical.ref } : undefined
127
- }
128
-
129
- const signature = signatureOf(schemaNode)
130
- if (skipRootMatch && schemaNode === root) return undefined
131
-
132
- const canonical = canonicalBySignature.get(signature)
133
- if (!canonical) return undefined
134
-
135
- return createRefNode(schemaNode, canonical)
136
- },
137
- })
138
- }
139
-
140
- /**
141
- * Strips usage-slot flags from a hoisted definition and applies its canonical name.
142
- * A standalone definition is never optional, so `optional`/`nullish` are cleared.
143
- */
144
- function cleanDefinition(node: SchemaNode, name: string): SchemaNode {
145
- return { ...node, name, optional: undefined, nullish: undefined }
146
- }
147
-
148
- /**
149
- * Scans a forest of schema and operation nodes and produces a {@link DedupePlan}.
150
- *
151
- * A shape that occurs at least `minOccurrences` times is deduplicated: if any occurrence
152
- * is a named top-level schema, the first one becomes the canonical (so other top-level
153
- * duplicates and inline copies turn into references to it). Every other top-level name with
154
- * the same content is recorded in `aliasNames`, so refs to it can be repointed at the
155
- * canonical. Otherwise a new definition is hoisted using `nameFor`. The plan is then applied
156
- * per node with {@link applyDedupe}.
157
- *
158
- * @example
159
- * ```ts
160
- * const plan = buildDedupePlan([...schemaNodes, ...operationNodes], {
161
- * isCandidate: (node) => node.type === 'enum' || node.type === 'object',
162
- * nameFor: (node) => node.name ?? null,
163
- * refFor: (name) => `#/components/schemas/${name}`,
164
- * })
165
- * ```
166
- */
167
- export function buildDedupePlan(roots: ReadonlyArray<Node>, options: BuildDedupePlanOptions): DedupePlan {
168
- const { isCandidate, nameFor, refFor, minOccurrences = 2 } = options
169
-
170
- const topLevelNodes = new Set<SchemaNode>()
171
-
172
- type Group = {
173
- count: number
174
- representative: SchemaNode
175
- topLevelNames: Array<string>
176
- }
177
- const groups = new Map<string, Group>()
178
-
179
- function record(schemaNode: SchemaNode): void {
180
- if (!isCandidate(schemaNode)) return
181
- const signature = signatureOf(schemaNode)
182
-
183
- const isTopLevel = topLevelNodes.has(schemaNode) && !!schemaNode.name
184
- const group = groups.get(signature)
185
- if (group) {
186
- group.count++
187
- if (isTopLevel) group.topLevelNames.push(schemaNode.name!)
188
- } else {
189
- groups.set(signature, { count: 1, representative: schemaNode, topLevelNames: isTopLevel ? [schemaNode.name!] : [] })
190
- }
191
- }
192
-
193
- for (const root of roots) {
194
- if (root.kind === 'Schema') topLevelNodes.add(root)
195
- for (const schemaNode of collectLazy<SchemaNode>(root, { schema: (node) => node })) {
196
- record(schemaNode)
197
- }
198
- }
199
-
200
- const canonicalBySignature = new Map<string, DedupeCanonical>()
201
- const aliasNames = new Map<string, DedupeCanonical>()
202
- const pendingHoists: Array<{ name: string; representative: SchemaNode }> = []
203
-
204
- for (const [signature, group] of groups) {
205
- if (group.count < minOccurrences) continue
206
-
207
- const [firstName, ...duplicateNames] = group.topLevelNames
208
- if (firstName) {
209
- const canonical: DedupeCanonical = { name: firstName, ref: refFor(firstName) }
210
- canonicalBySignature.set(signature, canonical)
211
- for (const duplicate of duplicateNames) {
212
- aliasNames.set(duplicate, canonical)
213
- }
214
- continue
215
- }
216
-
217
- const name = nameFor(group.representative, signature)
218
- if (!name) continue
219
-
220
- canonicalBySignature.set(signature, { name, ref: refFor(name) })
221
- pendingHoists.push({ name, representative: group.representative })
222
- }
223
-
224
- // Build hoisted definitions only after every canonical name is known, so nested
225
- // duplicates inside a definition also resolve to refs.
226
- const hoisted = pendingHoists.map(({ name, representative }) =>
227
- cleanDefinition(applyDedupe(representative, { canonicalBySignature, aliasNames }, true), name),
228
- )
229
-
230
- return { canonicalBySignature, aliasNames, hoisted }
231
- }