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

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 (92) hide show
  1. package/dist/{defineMacro-CNkUpxia.js → defineMacro-B76LsJwO.js} +4 -4
  2. package/dist/defineMacro-B76LsJwO.js.map +1 -0
  3. package/dist/{defineMacro-Vw-xQvq7.d.ts → defineMacro-B7qm3zTd.d.ts} +5 -6
  4. package/dist/{defineMacro-BryDiuQl.cjs → defineMacro-CEZHaCXE.cjs} +5 -5
  5. package/dist/defineMacro-CEZHaCXE.cjs.map +1 -0
  6. package/dist/factory-wJLzHeXT.d.ts +27 -0
  7. package/dist/factory.cjs +56 -56
  8. package/dist/factory.cjs.map +1 -1
  9. package/dist/factory.d.ts +3 -27
  10. package/dist/factory.js +6 -6
  11. package/dist/factory.js.map +1 -1
  12. package/dist/{index-CTaN_ee_.d.ts → index-BKD4drsX.d.ts} +47 -114
  13. package/dist/index.cjs +193 -270
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.ts +31 -21
  16. package/dist/index.js +154 -236
  17. package/dist/index.js.map +1 -1
  18. package/dist/macros.cjs +12 -12
  19. package/dist/macros.cjs.map +1 -1
  20. package/dist/macros.d.ts +3 -3
  21. package/dist/macros.js +5 -5
  22. package/dist/macros.js.map +1 -1
  23. package/dist/{operationParams-B44p6EQy.d.ts → operationParams-ByVfpYr7.d.ts} +10 -3
  24. package/dist/{visitor-DepQEKyp.js → refs-Dx6U5LoE.js} +116 -121
  25. package/dist/refs-Dx6U5LoE.js.map +1 -0
  26. package/dist/{visitor-B7Zlnp4c.cjs → refs-u5SDdyV7.cjs} +139 -144
  27. package/dist/refs-u5SDdyV7.cjs.map +1 -0
  28. package/dist/{response-BeG6hq2D.cjs → schema-BkvrrOAr.cjs} +171 -153
  29. package/dist/schema-BkvrrOAr.cjs.map +1 -0
  30. package/dist/{response-Rd1uisM1.js → schema-YNbOtTCM.js} +167 -155
  31. package/dist/schema-YNbOtTCM.js.map +1 -0
  32. package/dist/{types-DQTgVSwE.d.ts → types-BP9BZoq-.d.ts} +56 -80
  33. package/dist/types.d.ts +5 -5
  34. package/dist/{utils-DW9rnfsD.js → utils-BJi0y-xg.js} +57 -50
  35. package/dist/utils-BJi0y-xg.js.map +1 -0
  36. package/dist/{utils-BDI3kXlb.cjs → utils-CEepwqmb.cjs} +74 -67
  37. package/dist/utils-CEepwqmb.cjs.map +1 -0
  38. package/dist/utils.cjs +11 -11
  39. package/dist/utils.d.ts +45 -30
  40. package/dist/utils.js +3 -3
  41. package/package.json +1 -2
  42. package/dist/defineMacro-BryDiuQl.cjs.map +0 -1
  43. package/dist/defineMacro-CNkUpxia.js.map +0 -1
  44. package/dist/response-BeG6hq2D.cjs.map +0 -1
  45. package/dist/response-Rd1uisM1.js.map +0 -1
  46. package/dist/utils-BDI3kXlb.cjs.map +0 -1
  47. package/dist/utils-DW9rnfsD.js.map +0 -1
  48. package/dist/visitor-B7Zlnp4c.cjs.map +0 -1
  49. package/dist/visitor-DepQEKyp.js.map +0 -1
  50. package/src/constants.ts +0 -153
  51. package/src/dedupe.ts +0 -231
  52. package/src/defineMacro.ts +0 -139
  53. package/src/defineNode.ts +0 -105
  54. package/src/definePrinter.ts +0 -256
  55. package/src/dialect.ts +0 -76
  56. package/src/factory.ts +0 -44
  57. package/src/guards.ts +0 -28
  58. package/src/index.ts +0 -13
  59. package/src/infer.ts +0 -132
  60. package/src/macros/index.ts +0 -3
  61. package/src/macros/macroDiscriminatorEnum.ts +0 -50
  62. package/src/macros/macroEnumName.ts +0 -33
  63. package/src/macros/macroSimplifyUnion.ts +0 -60
  64. package/src/nodes/base.ts +0 -49
  65. package/src/nodes/code.ts +0 -352
  66. package/src/nodes/content.ts +0 -51
  67. package/src/nodes/file.ts +0 -379
  68. package/src/nodes/function.ts +0 -283
  69. package/src/nodes/index.ts +0 -93
  70. package/src/nodes/input.ts +0 -144
  71. package/src/nodes/operation.ts +0 -165
  72. package/src/nodes/output.ts +0 -49
  73. package/src/nodes/parameter.ts +0 -71
  74. package/src/nodes/property.ts +0 -67
  75. package/src/nodes/requestBody.ts +0 -54
  76. package/src/nodes/response.ts +0 -173
  77. package/src/nodes/schema.ts +0 -732
  78. package/src/registry.ts +0 -75
  79. package/src/signature.ts +0 -207
  80. package/src/types.ts +0 -9
  81. package/src/utils/codegen.ts +0 -104
  82. package/src/utils/extractStringsFromNodes.ts +0 -35
  83. package/src/utils/fileMerge.ts +0 -184
  84. package/src/utils/index.ts +0 -11
  85. package/src/utils/operationParams.ts +0 -353
  86. package/src/utils/refs.ts +0 -138
  87. package/src/utils/schemaGraph.ts +0 -169
  88. package/src/utils/schemaMerge.ts +0 -34
  89. package/src/utils/schemaTraversal.ts +0 -86
  90. package/src/utils/strings.ts +0 -139
  91. package/src/visitor.ts +0 -519
  92. /package/dist/{chunk-CNktS9qV.js → rolldown-runtime-CNktS9qV.js} +0 -0
package/src/registry.ts DELETED
@@ -1,75 +0,0 @@
1
- import type { NodeDef } from './defineNode.ts'
2
- import { arrowFunctionDef, breakDef, constDef, functionDef, jsxDef, textDef, typeDef } from './nodes/code.ts'
3
- import { contentDef } from './nodes/content.ts'
4
- import { exportDef, fileDef, importDef, sourceDef } from './nodes/file.ts'
5
- import { functionParameterDef, functionParametersDef, indexedAccessTypeDef, objectBindingPatternDef, typeLiteralDef } from './nodes/function.ts'
6
- import { inputDef } from './nodes/input.ts'
7
- import { operationDef } from './nodes/operation.ts'
8
- import { outputDef } from './nodes/output.ts'
9
- import { parameterDef } from './nodes/parameter.ts'
10
- import { propertyDef } from './nodes/property.ts'
11
- import { requestBodyDef } from './nodes/requestBody.ts'
12
- import { responseDef } from './nodes/response.ts'
13
- import { schemaDef } from './nodes/schema.ts'
14
-
15
- // Surface every def from one place so the package barrel re-exports them with `export * from './registry.ts'`.
16
- // Adding a node means adding its `defineNode` to a `nodes/*.ts` file and listing it in `nodeDefs` below, nothing else.
17
- export {
18
- arrowFunctionDef,
19
- breakDef,
20
- constDef,
21
- contentDef,
22
- exportDef,
23
- fileDef,
24
- functionDef,
25
- functionParameterDef,
26
- functionParametersDef,
27
- importDef,
28
- indexedAccessTypeDef,
29
- inputDef,
30
- jsxDef,
31
- objectBindingPatternDef,
32
- operationDef,
33
- outputDef,
34
- parameterDef,
35
- propertyDef,
36
- requestBodyDef,
37
- responseDef,
38
- schemaDef,
39
- sourceDef,
40
- textDef,
41
- typeDef,
42
- typeLiteralDef,
43
- }
44
-
45
- /**
46
- * Every node definition. Adding a node means adding its `defineNode` to one
47
- * `nodes/*.ts` file and listing it here. The visitor tables in `visitor.ts` derive from it.
48
- */
49
- export const nodeDefs = [
50
- inputDef,
51
- outputDef,
52
- operationDef,
53
- requestBodyDef,
54
- contentDef,
55
- responseDef,
56
- schemaDef,
57
- propertyDef,
58
- parameterDef,
59
- functionParameterDef,
60
- functionParametersDef,
61
- typeLiteralDef,
62
- indexedAccessTypeDef,
63
- objectBindingPatternDef,
64
- constDef,
65
- typeDef,
66
- functionDef,
67
- arrowFunctionDef,
68
- textDef,
69
- breakDef,
70
- jsxDef,
71
- importDef,
72
- exportDef,
73
- sourceDef,
74
- fileDef,
75
- ] satisfies ReadonlyArray<NodeDef>
package/src/signature.ts DELETED
@@ -1,207 +0,0 @@
1
- import { hash } from 'node:crypto'
2
- import type { SchemaNode } from './nodes/index.ts'
3
- import { extractRefName } from './utils/index.ts'
4
-
5
- /**
6
- * The flags shared by every node kind that affect its type: `primitive`, `format`, `nullable`.
7
- */
8
- function flagsDescriptor(node: SchemaNode): string {
9
- return `${node.primitive ?? ''};${node.format ?? ''};${node.nullable ? 1 : 0}`
10
- }
11
-
12
- function refTargetName(node: Extract<SchemaNode, { type: 'ref' }>): string {
13
- if (node.ref) return extractRefName(node.ref)
14
- return node.name ?? ''
15
- }
16
-
17
- type ScalarField = { kind: 'scalar'; key: string; prefix: string }
18
- type BoolField = { kind: 'bool'; key: string; prefix: string }
19
- type ChildField = { kind: 'child'; key: string; prefix: string }
20
- type ChildrenField = { kind: 'children'; key: string; prefix: string }
21
- type ObjectPropsField = { kind: 'objectProps' }
22
- type AdditionalPropsField = { kind: 'additionalProps' }
23
- type PatternPropsField = { kind: 'patternProps' }
24
- type EnumValuesField = { kind: 'enumValues' }
25
- type RefTargetField = { kind: 'refTarget' }
26
-
27
- type ShapeField =
28
- | ScalarField
29
- | BoolField
30
- | ChildField
31
- | ChildrenField
32
- | ObjectPropsField
33
- | AdditionalPropsField
34
- | PatternPropsField
35
- | EnumValuesField
36
- | RefTargetField
37
-
38
- const arrayTupleFields: ReadonlyArray<ShapeField> = [
39
- { kind: 'children', key: 'items', prefix: 'i' },
40
- { kind: 'child', key: 'rest', prefix: 'r' },
41
- { kind: 'scalar', key: 'min', prefix: 'mn' },
42
- { kind: 'scalar', key: 'max', prefix: 'mx' },
43
- { kind: 'bool', key: 'unique', prefix: 'u' },
44
- ]
45
-
46
- const numericFields: ReadonlyArray<ShapeField> = [
47
- { kind: 'scalar', key: 'min', prefix: 'mn' },
48
- { kind: 'scalar', key: 'max', prefix: 'mx' },
49
- { kind: 'scalar', key: 'exclusiveMinimum', prefix: 'emn' },
50
- { kind: 'scalar', key: 'exclusiveMaximum', prefix: 'emx' },
51
- { kind: 'scalar', key: 'multipleOf', prefix: 'mo' },
52
- ]
53
-
54
- const rangeFields: ReadonlyArray<ShapeField> = [
55
- { kind: 'scalar', key: 'min', prefix: 'mn' },
56
- { kind: 'scalar', key: 'max', prefix: 'mx' },
57
- ]
58
-
59
- /**
60
- * Maps each node `type` to its ordered shape-contributing fields. Types absent from the map
61
- * (boolean, null, any, and other scalars) fall back to `${type}|${flags}`.
62
- */
63
- const SHAPE_KEYS: Partial<Record<SchemaNode['type'], ReadonlyArray<ShapeField>>> = {
64
- object: [
65
- { kind: 'objectProps' },
66
- { kind: 'additionalProps' },
67
- { kind: 'patternProps' },
68
- { kind: 'scalar', key: 'minProperties', prefix: 'mn' },
69
- { kind: 'scalar', key: 'maxProperties', prefix: 'mx' },
70
- ],
71
- array: arrayTupleFields,
72
- tuple: arrayTupleFields,
73
- union: [
74
- { kind: 'scalar', key: 'strategy', prefix: 's' },
75
- { kind: 'scalar', key: 'discriminatorPropertyName', prefix: 'd' },
76
- { kind: 'children', key: 'members', prefix: 'm' },
77
- ],
78
- intersection: [{ kind: 'children', key: 'members', prefix: 'm' }],
79
- enum: [{ kind: 'enumValues' }],
80
- ref: [{ kind: 'refTarget' }],
81
- string: [
82
- { kind: 'scalar', key: 'min', prefix: 'mn' },
83
- { kind: 'scalar', key: 'max', prefix: 'mx' },
84
- { kind: 'scalar', key: 'pattern', prefix: 'pt' },
85
- ],
86
- number: numericFields,
87
- integer: numericFields,
88
- bigint: numericFields,
89
- url: [
90
- { kind: 'scalar', key: 'path', prefix: 'path' },
91
- { kind: 'scalar', key: 'min', prefix: 'mn' },
92
- { kind: 'scalar', key: 'max', prefix: 'mx' },
93
- ],
94
- uuid: rangeFields,
95
- email: rangeFields,
96
- datetime: [
97
- { kind: 'bool', key: 'offset', prefix: 'o' },
98
- { kind: 'bool', key: 'local', prefix: 'l' },
99
- ],
100
- date: [{ kind: 'scalar', key: 'representation', prefix: 'rep' }],
101
- time: [{ kind: 'scalar', key: 'representation', prefix: 'rep' }],
102
- }
103
-
104
- function serializeShapeField(field: ShapeField, node: SchemaNode, record: Record<string, unknown>): string {
105
- switch (field.kind) {
106
- case 'scalar':
107
- return `${field.prefix}:${record[field.key] ?? ''}`
108
- case 'bool':
109
- return `${field.prefix}:${record[field.key] ? 1 : 0}`
110
- case 'child': {
111
- const child = record[field.key] as SchemaNode | undefined
112
- return `${field.prefix}:${child ? signatureOf(child) : ''}`
113
- }
114
- case 'children': {
115
- const children = (record[field.key] as Array<SchemaNode> | undefined) ?? []
116
- return `${field.prefix}[${children.map((c) => signatureOf(c)).join(',')}]`
117
- }
118
- case 'objectProps': {
119
- const obj = node as Extract<SchemaNode, { type: 'object' }>
120
- const props = (obj.properties ?? []).map((prop) => `${prop.name}${prop.required ? '!' : '?'}${signatureOf(prop.schema)}`).join(',')
121
- return `p[${props}]`
122
- }
123
- case 'additionalProps': {
124
- const obj = node as Extract<SchemaNode, { type: 'object' }>
125
- if (typeof obj.additionalProperties === 'boolean') return `ab:${obj.additionalProperties}`
126
- if (obj.additionalProperties) return `as:${signatureOf(obj.additionalProperties)}`
127
- return ''
128
- }
129
- case 'patternProps': {
130
- const obj = node as Extract<SchemaNode, { type: 'object' }>
131
- const pattern = obj.patternProperties
132
- ? Object.keys(obj.patternProperties)
133
- .sort()
134
- .map((key) => `${key}=${signatureOf(obj.patternProperties![key]!)}`)
135
- .join(',')
136
- : ''
137
- return `pp[${pattern}]`
138
- }
139
- case 'enumValues': {
140
- const en = node as Extract<SchemaNode, { type: 'enum' }>
141
- let values = ''
142
- if (en.namedEnumValues?.length) {
143
- values = en.namedEnumValues.map((entry) => `${entry.name}=${entry.primitive}:${String(entry.value)}`).join(',')
144
- } else if (en.enumValues?.length) {
145
- values = en.enumValues.map((value) => `${value === null ? 'null' : typeof value}:${String(value)}`).join(',')
146
- }
147
- return `v[${values}]`
148
- }
149
- case 'refTarget': {
150
- return `->${refTargetName(node as Extract<SchemaNode, { type: 'ref' }>)}`
151
- }
152
- }
153
- }
154
-
155
- /**
156
- * Builds the local shape descriptor that {@link signatureOf} hashes: the node's kind, flags,
157
- * constraints, and its children's signatures.
158
- */
159
- function describeShape(node: SchemaNode): string {
160
- const flags = flagsDescriptor(node)
161
- const fields = SHAPE_KEYS[node.type]
162
- if (!fields) return `${node.type}|${flags}`
163
-
164
- const record = node as unknown as Record<string, unknown>
165
- const parts: Array<string> = [`${node.type}|${flags}`]
166
- for (const field of fields) {
167
- parts.push(serializeShapeField(field, node, record))
168
- }
169
- return parts.join('|')
170
- }
171
-
172
- /**
173
- * Caches the digest per node, keyed by identity. A `WeakMap` so entries die with the node, and so
174
- * a tree hashed during dedupe planning is not walked again when it is rewritten during streaming.
175
- * Reuse is safe because a signature depends only on content, and nodes are immutable once created.
176
- */
177
- const signatureCache = new WeakMap<SchemaNode, string>()
178
-
179
- /**
180
- * Computes a deterministic, shape-only signature (a content hash) for a schema node. Two schemas
181
- * share a signature when they are structurally identical, ignoring documentation (`name`, `title`,
182
- * `description`, `example`, `default`, `deprecated`) and usage-slot flags (`optional`, `nullish`,
183
- * `readOnly`, `writeOnly`). `nullable` is kept because it changes the produced type, and `ref`
184
- * nodes compare by target name, which also terminates on circular shapes.
185
- *
186
- * @example Two enums with different descriptions share a signature
187
- * ```ts
188
- * signatureOf(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'], description: 'x' })) ===
189
- * signatureOf(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'] }))
190
- * ```
191
- */
192
- export function signatureOf(node: SchemaNode): string {
193
- const cached = signatureCache.get(node)
194
- if (cached !== undefined) return cached
195
- const signature = hash('sha256', describeShape(node), 'hex')
196
- signatureCache.set(node, signature)
197
-
198
- return signature
199
- }
200
-
201
- /**
202
- * Returns `true` when two schema nodes are structurally identical under shape-only equality,
203
- * meaning they produce the same TypeScript type.
204
- */
205
- export function isSchemaEqual(a: SchemaNode, b: SchemaNode): boolean {
206
- return signatureOf(a) === signatureOf(b)
207
- }
package/src/types.ts DELETED
@@ -1,9 +0,0 @@
1
- export type { DedupeCanonical, DedupeLookups, DedupePlan } from './dedupe.ts'
2
- export type { Dialect, SchemaDialect } from './dialect.ts'
3
- export type { DistributiveOmit, NodeDef } from './defineNode.ts'
4
- export type { InferSchemaNode, ParserOptions } from './infer.ts'
5
- export type * from './nodes/index.ts'
6
- export type { ParentOf, Visitor, VisitorContext } from './visitor.ts'
7
- export type { Printer, PrinterFactoryOptions, PrinterPartial } from './definePrinter.ts'
8
- export type { OperationParamsResolver } from './utils/operationParams.ts'
9
- export type { Enforce, Macro } from './defineMacro.ts'
@@ -1,104 +0,0 @@
1
- import { isIdentifier, singleQuote } from '@internals/utils'
2
- import { INDENT } from '../constants.ts'
3
-
4
- /**
5
- * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no
6
- * comments so callers always get a usable string.
7
- *
8
- * @example
9
- * ```ts
10
- * buildJSDoc(['@type string', '@example hello'])
11
- * // '/**\n * @type string\n * @example hello\n *\/\n '
12
- * ```
13
- */
14
- export function buildJSDoc(
15
- comments: Array<string>,
16
- options: {
17
- /**
18
- * String used to indent each comment line.
19
- * @default ' * '
20
- */
21
- indent?: string
22
- /**
23
- * String appended after the closing tag.
24
- * @default '\n '
25
- */
26
- suffix?: string
27
- /**
28
- * Returned as-is when `comments` is empty.
29
- * @default ' '
30
- */
31
- fallback?: string
32
- } = {},
33
- ): string {
34
- const { indent = ' * ', suffix = '\n ', fallback = ' ' } = options
35
-
36
- if (comments.length === 0) return fallback
37
-
38
- return `/**\n${comments.map((c) => `${indent}${c}`).join('\n')}\n */${suffix}`
39
- }
40
-
41
- /**
42
- * Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
43
- */
44
- function indentLines(text: string): string {
45
- if (!text) return ''
46
- return text
47
- .split('\n')
48
- .map((line) => (line.trim() ? `${INDENT}${line}` : ''))
49
- .join('\n')
50
- }
51
-
52
- /**
53
- * Renders an object key, quoting it with single quotes only when it is not a valid identifier.
54
- * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.
55
- *
56
- * @example
57
- * ```ts
58
- * objectKey('name') // 'name'
59
- * objectKey('x-total') // "'x-total'"
60
- * ```
61
- */
62
- export function objectKey(name: string): string {
63
- return isIdentifier(name) ? name : singleQuote(name)
64
- }
65
-
66
- /**
67
- * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
68
- * level and closing the brace at column zero. Nested objects built the same way indent cumulatively,
69
- * so callers never re-parse the generated code. A trailing comma is added per entry to match the
70
- * formatter's multi-line style.
71
- *
72
- * @example
73
- * ```ts
74
- * buildObject(['id: z.number()', 'name: z.string()'])
75
- * // '{\n id: z.number(),\n name: z.string(),\n}'
76
- * ```
77
- */
78
- export function buildObject(entries: Array<string>): string {
79
- if (entries.length === 0) return '{}'
80
- const body = entries.map((entry) => `${indentLines(entry)},`).join('\n')
81
-
82
- return `{\n${body}\n}`
83
- }
84
-
85
- /**
86
- * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on
87
- * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented
88
- * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`,
89
- * `z.array([…])`, and similar member lists so objects inside them nest correctly.
90
- *
91
- * @example
92
- * ```ts
93
- * buildList(['z.string()', 'z.number()'])
94
- * // '[z.string(), z.number()]'
95
- * ```
96
- */
97
- export function buildList(items: Array<string>, brackets: [open: string, close: string] = ['[', ']']): string {
98
- const [open, close] = brackets
99
- if (items.length === 0) return `${open}${close}`
100
- if (!items.some((item) => item.includes('\n'))) return `${open}${items.join(', ')}${close}`
101
- const body = items.map((item) => `${indentLines(item)},`).join('\n')
102
-
103
- return `${open}\n${body}\n${close}`
104
- }
@@ -1,35 +0,0 @@
1
- import type { CodeNode } from '../nodes/code.ts'
2
-
3
- /**
4
- * Extracts all string content from a `CodeNode` tree recursively.
5
- *
6
- * Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
7
- * and nested node content. Used to build the full source string for import filtering.
8
- */
9
- export function extractStringsFromNodes(nodes: Array<CodeNode> | undefined): string {
10
- if (!nodes?.length) return ''
11
-
12
- return nodes
13
- .map((node) => {
14
- // Backward-compat: compiled plugins may still pass bare strings at runtime
15
- if (typeof node === 'string') return node as string
16
- if (node.kind === 'Text') return node.value
17
- if (node.kind === 'Break') return ''
18
- if (node.kind === 'Jsx') return node.value
19
-
20
- const parts: Array<string> = []
21
-
22
- if ('params' in node && node.params) parts.push(node.params)
23
- if ('generics' in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(', ') : node.generics)
24
- if ('returnType' in node && node.returnType) parts.push(node.returnType)
25
- if ('type' in node && typeof node.type === 'string') parts.push(node.type)
26
-
27
- const nested = extractStringsFromNodes(node.nodes)
28
-
29
- if (nested) parts.push(nested)
30
-
31
- return parts.join('\n')
32
- })
33
- .filter(Boolean)
34
- .join('\n')
35
- }
@@ -1,184 +0,0 @@
1
- /**
2
- * File-member merging. `combineImports`, `combineExports`, and `combineSources` deduplicate and sort
3
- * the import, export, and source entries of one file, and drop imports nothing references. This works
4
- * on a file's members, not on schema content.
5
- *
6
- * For collapsing duplicate schema shapes by structural signature, see `dedupe.ts`.
7
- */
8
- import type { ExportNode, ImportNode, SourceNode } from '../nodes/index.ts'
9
- import { extractStringsFromNodes } from './extractStringsFromNodes.ts'
10
-
11
- function sourceKey(source: SourceNode): string {
12
- const nameKey = source.name ?? extractStringsFromNodes(source.nodes)
13
- return `${nameKey}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`
14
- }
15
-
16
- function pathTypeKey(path: string, isTypeOnly: boolean | null | undefined): string {
17
- return `${path}:${isTypeOnly ?? false}`
18
- }
19
-
20
- function exportKey(path: string, name: string | null | undefined, isTypeOnly: boolean | null | undefined, asAlias: boolean | null | undefined): string {
21
- return `${path}:${name ?? ''}:${isTypeOnly ?? false}:${asAlias ?? ''}`
22
- }
23
-
24
- function importKey(path: string, name: string | null | undefined, isTypeOnly: boolean | null | undefined): string {
25
- return `${path}:${name ?? ''}:${isTypeOnly ?? false}`
26
- }
27
-
28
- /**
29
- * Computes a multi-level sort key for exports and imports:
30
- * non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
31
- */
32
- function sortKey(node: { name?: string | Array<unknown> | null; isTypeOnly?: boolean | null; path: string }): string {
33
- const isArray = Array.isArray(node.name) ? '1' : '0'
34
- const typeOnly = node.isTypeOnly ? '0' : '1'
35
- const hasName = node.name != null ? '1' : '0'
36
- const name = Array.isArray(node.name) ? node.name.toSorted().join('\0') : (node.name ?? '')
37
- return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`
38
- }
39
-
40
- /**
41
- * Deduplicates and merges `SourceNode` objects by `name + isExportable + isTypeOnly`.
42
- *
43
- * Unnamed sources are deduplicated by object reference. Returns a deduplicated array in original order.
44
- */
45
- export function combineSources(sources: Array<SourceNode>): Array<SourceNode> {
46
- const seen = new Map<string, SourceNode>()
47
- for (const source of sources) {
48
- const key = sourceKey(source)
49
- if (!seen.has(key)) seen.set(key, source)
50
- }
51
- return [...seen.values()]
52
- }
53
-
54
- /**
55
- * Merges `incoming` names into `existing`, preserving order and dropping duplicates.
56
- *
57
- * Shared by `combineExports` and `combineImports` for the same-path name-merge case.
58
- */
59
- function mergeNameArrays<TName>(existing: Array<TName>, incoming: Array<TName>): Array<TName> {
60
- const merged = new Set(existing)
61
- for (const name of incoming) merged.add(name)
62
- return [...merged]
63
- }
64
-
65
- /**
66
- * Deduplicates and merges `ExportNode` objects by path and type.
67
- *
68
- * Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
69
- * Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
70
- */
71
- export function combineExports(exports: Array<ExportNode>): Array<ExportNode> {
72
- const result: Array<ExportNode> = []
73
- // Accumulates array-named exports keyed by `path:isTypeOnly` for name-merging
74
- const namedByPath = new Map<string, ExportNode>()
75
- // Deduplicates non-array exports by their exact identity
76
- const seen = new Set<string>()
77
-
78
- // Precompute sort keys once, avoids recomputing per comparison.
79
- const keyed = exports.map((node) => ({ node, key: sortKey(node) }))
80
- keyed.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))
81
-
82
- for (const { node: curr } of keyed) {
83
- const { name, path, isTypeOnly, asAlias } = curr
84
-
85
- if (Array.isArray(name)) {
86
- if (!name.length) continue
87
-
88
- const key = pathTypeKey(path, isTypeOnly)
89
- const existing = namedByPath.get(key)
90
-
91
- if (existing && Array.isArray(existing.name)) {
92
- existing.name = mergeNameArrays(existing.name, name)
93
- } else {
94
- const newItem: ExportNode = { ...curr, name: [...new Set(name)] }
95
- result.push(newItem)
96
- namedByPath.set(key, newItem)
97
- }
98
- } else {
99
- const key = exportKey(path, name, isTypeOnly, asAlias)
100
- if (!seen.has(key)) {
101
- result.push(curr)
102
- seen.add(key)
103
- }
104
- }
105
- }
106
-
107
- return result
108
- }
109
-
110
- /**
111
- * Deduplicates and merges `ImportNode` objects, filtering out unused imports.
112
- *
113
- * Retains imports that are referenced in `source` or re-exported. Imports with the same path and
114
- * `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
115
- */
116
- export function combineImports(imports: Array<ImportNode>, exports: Array<ExportNode>, source?: string): Array<ImportNode> {
117
- // Build a lookup of all exported names to retain imports that are re-exported
118
- const exportedNames = new Set(exports.flatMap((e) => (Array.isArray(e.name) ? e.name : e.name ? [e.name] : [])))
119
- const isUsed = (importName: string): boolean => !source || source.includes(importName) || exportedNames.has(importName)
120
-
121
- // Memoize object import names so the same logical (propertyName, name) pair always
122
- // reuses the same object reference. Set-based deduplication then works correctly.
123
- const importNameMemo = new Map<string, { propertyName: string; name?: string }>()
124
- const canonicalizeName = (n: string | { propertyName: string; name?: string }): string | { propertyName: string; name?: string } => {
125
- if (typeof n === 'string') return n
126
- const key = `${n.propertyName}:${n.name ?? ''}`
127
- if (!importNameMemo.has(key)) importNameMemo.set(key, n)
128
- return importNameMemo.get(key)!
129
- }
130
-
131
- // Paths that keep at least one used named import. A default import from such a path is retained
132
- // even when its binding can't be found in `source` e.g. a generated `client` default import
133
- // alongside `import type { Client } from <same path>`, where merged grouped output omits the body.
134
- const pathsWithUsedNamedImport = new Set<string>()
135
- for (const node of imports) {
136
- if (!Array.isArray(node.name)) continue
137
- if (node.name.some((item) => (typeof item === 'string' ? isUsed(item) : isUsed(item.name ?? item.propertyName)))) {
138
- pathsWithUsedNamedImport.add(node.path)
139
- }
140
- }
141
-
142
- const result: Array<ImportNode> = []
143
- // Accumulates array-named imports keyed by `path:isTypeOnly` for name-merging
144
- const namedByPath = new Map<string, ImportNode>()
145
- // Deduplicates non-array imports by their exact identity
146
- const seen = new Set<string>()
147
-
148
- // Precompute sort keys once, avoids recomputing per comparison.
149
- const keyed = imports.map((node) => ({ node, key: sortKey(node) }))
150
- keyed.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))
151
-
152
- for (const { node: curr } of keyed) {
153
- if (curr.path === curr.root) continue
154
-
155
- const { path, isTypeOnly } = curr
156
- let { name } = curr
157
-
158
- if (Array.isArray(name)) {
159
- name = [...new Set(name.map(canonicalizeName))].filter((item) => (typeof item === 'string' ? isUsed(item) : isUsed(item.name ?? item.propertyName)))
160
- if (!name.length) continue
161
-
162
- const key = pathTypeKey(path, isTypeOnly)
163
- const existing = namedByPath.get(key)
164
-
165
- if (existing && Array.isArray(existing.name)) {
166
- existing.name = mergeNameArrays(existing.name, name)
167
- } else {
168
- const newItem: ImportNode = { ...curr, name }
169
- result.push(newItem)
170
- namedByPath.set(key, newItem)
171
- }
172
- } else {
173
- if (name && !isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue
174
-
175
- const key = importKey(path, name, isTypeOnly)
176
- if (!seen.has(key)) {
177
- result.push(curr)
178
- seen.add(key)
179
- }
180
- }
181
- }
182
-
183
- return result
184
- }
@@ -1,11 +0,0 @@
1
- export { isValidVarName } from '@internals/utils'
2
- export { buildJSDoc, buildList, buildObject, objectKey } from './codegen.ts'
3
- export { extractStringsFromNodes } from './extractStringsFromNodes.ts'
4
- export { childName, enumPropName, extractRefName, isStringType, resolveGroupType, resolveRefName, syncSchemaRef } from './refs.ts'
5
- export { mergeAdjacentObjectsLazy } from './schemaMerge.ts'
6
- export { getNestedAccessor, jsStringEscape, stringify, stringifyObject, toRegExpString, trimQuotes } from './strings.ts'
7
- export { collectUsedSchemaNames, containsCircularRef, findCircularSchemas } from './schemaGraph.ts'
8
- export { lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties } from './schemaTraversal.ts'
9
- export type { MappedProperty, MappedSchema, SchemaTransform } from './schemaTraversal.ts'
10
- export { buildGroupParam, buildTypeLiteral, caseParams, createOperationParams, resolveParamType } from './operationParams.ts'
11
- export type { BuildGroupArgs, ParamGroupType } from './operationParams.ts'