ajsc 5.2.4 → 7.1.0

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 (142) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +303 -144
  3. package/dist/converter/BaseConverter.d.ts +315 -0
  4. package/dist/converter/BaseConverter.js +131 -0
  5. package/dist/converter/BaseConverter.js.map +1 -0
  6. package/dist/converter/Emitter.d.ts +35 -0
  7. package/dist/converter/Emitter.js +50 -0
  8. package/dist/converter/Emitter.js.map +1 -0
  9. package/dist/converter/discriminatedUnions.d.ts +47 -0
  10. package/dist/converter/discriminatedUnions.js +168 -0
  11. package/dist/converter/discriminatedUnions.js.map +1 -0
  12. package/dist/converter/formatDefault.d.ts +20 -0
  13. package/dist/converter/formatDefault.js +31 -0
  14. package/dist/converter/formatDefault.js.map +1 -0
  15. package/dist/converter/index.d.ts +24 -0
  16. package/dist/converter/index.js +24 -0
  17. package/dist/converter/index.js.map +1 -0
  18. package/dist/converter/mergeUnions.d.ts +36 -0
  19. package/dist/converter/mergeUnions.js +189 -0
  20. package/dist/converter/mergeUnions.js.map +1 -0
  21. package/dist/converter/naming.d.ts +29 -0
  22. package/dist/converter/naming.js +137 -0
  23. package/dist/converter/naming.js.map +1 -0
  24. package/dist/converter/registry.d.ts +18 -0
  25. package/dist/converter/registry.js +50 -0
  26. package/dist/converter/registry.js.map +1 -0
  27. package/dist/converter/walk.d.ts +9 -0
  28. package/dist/converter/walk.js +40 -0
  29. package/dist/converter/walk.js.map +1 -0
  30. package/dist/index.d.ts +71 -3
  31. package/dist/index.js +63 -3
  32. package/dist/index.js.map +1 -1
  33. package/dist/{JSONSchemaConverter.d.ts → ir/JSONSchemaConverter.d.ts} +1 -1
  34. package/dist/{JSONSchemaConverter.js → ir/JSONSchemaConverter.js} +9 -3
  35. package/dist/ir/JSONSchemaConverter.js.map +1 -0
  36. package/dist/ir/index.d.ts +1 -0
  37. package/dist/ir/index.js +2 -0
  38. package/dist/ir/index.js.map +1 -0
  39. package/dist/kotlin/KotlinBaseConverter.d.ts +18 -0
  40. package/dist/kotlin/KotlinBaseConverter.js +36 -0
  41. package/dist/kotlin/KotlinBaseConverter.js.map +1 -0
  42. package/dist/kotlin/KotlinConverter.d.ts +67 -0
  43. package/dist/kotlin/KotlinConverter.js +142 -0
  44. package/dist/kotlin/KotlinConverter.js.map +1 -0
  45. package/dist/kotlin/annotations.d.ts +26 -0
  46. package/dist/kotlin/annotations.js +35 -0
  47. package/dist/kotlin/annotations.js.map +1 -0
  48. package/dist/kotlin/enums.d.ts +15 -0
  49. package/dist/kotlin/enums.js +58 -0
  50. package/dist/kotlin/enums.js.map +1 -0
  51. package/dist/kotlin/index.d.ts +13 -0
  52. package/dist/kotlin/index.js +14 -0
  53. package/dist/kotlin/index.js.map +1 -0
  54. package/dist/kotlin/objectEmitter.d.ts +12 -0
  55. package/dist/kotlin/objectEmitter.js +74 -0
  56. package/dist/kotlin/objectEmitter.js.map +1 -0
  57. package/dist/kotlin/sealedUnion.d.ts +17 -0
  58. package/dist/kotlin/sealedUnion.js +74 -0
  59. package/dist/kotlin/sealedUnion.js.map +1 -0
  60. package/dist/kotlin/typeMapper.d.ts +17 -0
  61. package/dist/kotlin/typeMapper.js +107 -0
  62. package/dist/kotlin/typeMapper.js.map +1 -0
  63. package/dist/kotlin/unsupported.d.ts +13 -0
  64. package/dist/kotlin/unsupported.js +53 -0
  65. package/dist/kotlin/unsupported.js.map +1 -0
  66. package/dist/swift/SwiftBaseConverter.d.ts +18 -0
  67. package/dist/swift/SwiftBaseConverter.js +38 -0
  68. package/dist/swift/SwiftBaseConverter.js.map +1 -0
  69. package/dist/swift/SwiftConverter.d.ts +60 -0
  70. package/dist/swift/SwiftConverter.js +113 -0
  71. package/dist/swift/SwiftConverter.js.map +1 -0
  72. package/dist/swift/discriminatedEnum.d.ts +18 -0
  73. package/dist/swift/discriminatedEnum.js +99 -0
  74. package/dist/swift/discriminatedEnum.js.map +1 -0
  75. package/dist/swift/enums.d.ts +15 -0
  76. package/dist/swift/enums.js +62 -0
  77. package/dist/swift/enums.js.map +1 -0
  78. package/dist/swift/index.d.ts +13 -0
  79. package/dist/swift/index.js +14 -0
  80. package/dist/swift/index.js.map +1 -0
  81. package/dist/swift/structEmitter.d.ts +12 -0
  82. package/dist/swift/structEmitter.js +70 -0
  83. package/dist/swift/structEmitter.js.map +1 -0
  84. package/dist/swift/typeMapper.d.ts +18 -0
  85. package/dist/swift/typeMapper.js +106 -0
  86. package/dist/swift/typeMapper.js.map +1 -0
  87. package/dist/swift/unsupported.d.ts +19 -0
  88. package/dist/swift/unsupported.js +88 -0
  89. package/dist/swift/unsupported.js.map +1 -0
  90. package/dist/typescript/TypescriptBaseConverter.d.ts +25 -0
  91. package/dist/typescript/TypescriptBaseConverter.js +178 -0
  92. package/dist/typescript/TypescriptBaseConverter.js.map +1 -0
  93. package/dist/typescript/TypescriptConverter.d.ts +74 -0
  94. package/dist/typescript/TypescriptConverter.js +254 -0
  95. package/dist/typescript/TypescriptConverter.js.map +1 -0
  96. package/dist/typescript/index.d.ts +12 -0
  97. package/dist/typescript/index.js +13 -0
  98. package/dist/typescript/index.js.map +1 -0
  99. package/dist/utils/index.d.ts +2 -0
  100. package/dist/utils/index.js +3 -0
  101. package/dist/utils/index.js.map +1 -0
  102. package/package.json +39 -6
  103. package/dist/JSONSchemaConverter.js.map +0 -1
  104. package/dist/JSONSchemaConverter.test.d.ts +0 -1
  105. package/dist/JSONSchemaConverter.test.js +0 -585
  106. package/dist/JSONSchemaConverter.test.js.map +0 -1
  107. package/dist/Typebox.test.d.ts +0 -1
  108. package/dist/Typebox.test.js +0 -88
  109. package/dist/Typebox.test.js.map +0 -1
  110. package/dist/TypescriptBaseConverter.d.ts +0 -75
  111. package/dist/TypescriptBaseConverter.js +0 -321
  112. package/dist/TypescriptBaseConverter.js.map +0 -1
  113. package/dist/TypescriptConverter.additionalProperties.test.d.ts +0 -1
  114. package/dist/TypescriptConverter.additionalProperties.test.js +0 -110
  115. package/dist/TypescriptConverter.additionalProperties.test.js.map +0 -1
  116. package/dist/TypescriptConverter.arrays.test.d.ts +0 -1
  117. package/dist/TypescriptConverter.arrays.test.js +0 -130
  118. package/dist/TypescriptConverter.arrays.test.js.map +0 -1
  119. package/dist/TypescriptConverter.composites.advanced.test.d.ts +0 -1
  120. package/dist/TypescriptConverter.composites.advanced.test.js +0 -1070
  121. package/dist/TypescriptConverter.composites.advanced.test.js.map +0 -1
  122. package/dist/TypescriptConverter.composites.test.d.ts +0 -1
  123. package/dist/TypescriptConverter.composites.test.js +0 -335
  124. package/dist/TypescriptConverter.composites.test.js.map +0 -1
  125. package/dist/TypescriptConverter.d.ts +0 -163
  126. package/dist/TypescriptConverter.js +0 -606
  127. package/dist/TypescriptConverter.js.map +0 -1
  128. package/dist/TypescriptConverter.jsdoc.test.d.ts +0 -1
  129. package/dist/TypescriptConverter.jsdoc.test.js +0 -194
  130. package/dist/TypescriptConverter.jsdoc.test.js.map +0 -1
  131. package/dist/TypescriptConverter.objects.test.d.ts +0 -1
  132. package/dist/TypescriptConverter.objects.test.js +0 -258
  133. package/dist/TypescriptConverter.objects.test.js.map +0 -1
  134. package/dist/TypescriptConverter.options.test.d.ts +0 -1
  135. package/dist/TypescriptConverter.options.test.js +0 -501
  136. package/dist/TypescriptConverter.options.test.js.map +0 -1
  137. package/dist/TypescriptConverter.primitives.test.d.ts +0 -1
  138. package/dist/TypescriptConverter.primitives.test.js +0 -26
  139. package/dist/TypescriptConverter.primitives.test.js.map +0 -1
  140. package/dist/utils/path-utils.test.d.ts +0 -1
  141. package/dist/utils/path-utils.test.js +0 -92
  142. package/dist/utils/path-utils.test.js.map +0 -1
@@ -0,0 +1,315 @@
1
+ import { ILanguageConverter, IRNode, SignatureOccurrenceValue } from "../types.js";
2
+ export { walkIR } from "./walk.js";
3
+ export type RefTypeName = string;
4
+ export interface RefTypeEntry {
5
+ signature: SignatureOccurrenceValue["signature"];
6
+ name: RefTypeName;
7
+ code: string;
8
+ title?: string;
9
+ description?: string;
10
+ doc?: string;
11
+ }
12
+ export type RefTypes = RefTypeEntry[];
13
+ /**
14
+ * Per-language configuration bundle. Each language subclass declares one
15
+ * `languageProfile` field; the base class reads from it instead of calling
16
+ * a method-per-knob. Optional fields fall through to the base default.
17
+ */
18
+ export interface LanguageProfile {
19
+ /** Language identifier emitted as `language` on the converter. */
20
+ language: string;
21
+ /**
22
+ * When true, `getReferencedType` short-circuits IR nodes whose `name` matches
23
+ * the root name back to a direct self-reference (so e.g. a `Tree` schema with
24
+ * `children: Array<{$ref: "#"}>` emits as `children: Array<Tree>` rather than
25
+ * extracting a duplicate `Child` type). Default: true. All current languages
26
+ * use the default; this hook exists for hypothetical future targets that want
27
+ * a different recursion shape.
28
+ */
29
+ detectSelfReferenceToRoot?: boolean;
30
+ /**
31
+ * When true, `enhanceDiscriminatedUnions` ALSO walks `oneOf` unions (in addition
32
+ * to `anyOf`). Default: false. Languages that emit a tagged-union form for `oneOf`
33
+ * (Kotlin sealed interface, Swift enum w/ associated values) override to true.
34
+ */
35
+ processOneOfAsDiscriminatedUnion?: boolean;
36
+ /**
37
+ * When true, `applyDiscriminatedUnionEnhancements` populates `discriminatorInfo`
38
+ * for downstream consolidated enum emission. Default: false. TS overrides based
39
+ * on `enumStyle === "enum" && !inlineTypes`.
40
+ */
41
+ shouldPopulateDiscriminatorInfo?: boolean;
42
+ /**
43
+ * When true, `stripDiscriminatorField` removes the discriminator key from variant
44
+ * payload bodies (because the language hoists it into a tag annotation or codable
45
+ * plumbing). Default: false. Kotlin = `isKotlinx`. Swift = `isCodable`.
46
+ */
47
+ shouldEraseDiscriminator?: boolean;
48
+ /**
49
+ * Custom ref-type naming configuration. Merged shallow over the BaseConverter default
50
+ * (postfix list, depluralize, etc.). Useful for adding language-specific postfixes
51
+ * (e.g. "Enum" in TS).
52
+ */
53
+ refTypeNamingConfig?: Partial<RefTypeNamingConfig>;
54
+ /**
55
+ * Parent-name component used by `applyDiscriminatedUnionEnhancements` when deriving
56
+ * variant names. Default: last non-numeric segment of `ir.path`. Kotlin extends this
57
+ * with a fallback to `ir.name || ir.title`; Swift always returns "" (variants are
58
+ * nested in the enum, no parent suffix needed).
59
+ */
60
+ getDiscriminatedVariantParentName?: (ir: IRNode) => string;
61
+ /**
62
+ * Override ref-type name resolution. `defaultResolver()` invokes the path-based
63
+ * default. TS uses this to apply enum-style overrides.
64
+ */
65
+ resolveRefTypeName?: (ir: IRNode, signature: string, defaultResolver: () => string) => string;
66
+ /**
67
+ * Language-specific signature dedup decision. Default: false. TS = `dedupSignatures.has(sig)`.
68
+ */
69
+ shouldReuseExistingSignature?: (signature: string) => boolean;
70
+ }
71
+ export interface RefTypeNamingConfig {
72
+ /** Base postfixes to try for name collision resolution */
73
+ postfixes: string[];
74
+ /** If true, singularize array item path segments (e.g. "entries" → "entry", "people" → "person") */
75
+ depluralize?: boolean;
76
+ /** If true, handle "*" path endings with AnyKey/AnyProperty postfixes */
77
+ handleAnySymbol?: boolean;
78
+ /** If true, strip leading "*" from proposed names */
79
+ stripLeadingAnySymbol?: boolean;
80
+ /**
81
+ * Controls the postfix added to array item type names.
82
+ * - `false` (default) → no postfix, uses property name directly
83
+ * - `string` → custom postfix (e.g. "Item" → ContactsItem, "Element" → ContactsElement)
84
+ */
85
+ arrayItemNaming?: string | false;
86
+ /**
87
+ * Additional words that should not be singularized when `depluralize` is true.
88
+ * Built-in uncountables: "data", "metadata".
89
+ * @example ["criteria", "alumni", "corpus"]
90
+ */
91
+ uncountableWords?: string[];
92
+ }
93
+ export type GenerateTypeUtils = {
94
+ getReferencedType(ir: IRNode): string | undefined;
95
+ };
96
+ /**
97
+ * The state-and-method surface that helper modules in `src/converter/`
98
+ * need to operate on a BaseConverter instance. BaseConverter implements
99
+ * this; helpers take it as their first argument.
100
+ *
101
+ * Using this interface (rather than the BaseConverter class itself) keeps
102
+ * helper modules from depending on the abstract class shape — they only
103
+ * see the concrete contract they need.
104
+ *
105
+ * @internal
106
+ */
107
+ export interface BaseConverterContext {
108
+ readonly refTypes: RefTypeEntry[];
109
+ readonly usedDeclarationNames: Set<string>;
110
+ rootName?: string;
111
+ rootDoc?: string;
112
+ baseOpts?: BaseConverterOpts;
113
+ readonly variantNames: Map<IRNode, string>;
114
+ readonly discriminatorInfo: Map<IRNode, {
115
+ allValues: string[];
116
+ thisValue: string;
117
+ }>;
118
+ readonly dedupSignatures: Set<string>;
119
+ mergeCounter: number;
120
+ /** Used internally by `getUniqueRefTypeName`; exposed for the helper to mutate. */
121
+ fallbackCounter: number;
122
+ readonly languageProfile: LanguageProfile;
123
+ /** Subclass-implemented; called by `getReferencedType` after registering an entry. */
124
+ generateObjectType(ir: IRNode, utils: GenerateTypeUtils): string;
125
+ /** Returns a name not already in `usedDeclarationNames`, suffixing as needed. */
126
+ findAvailableName(base: string): string;
127
+ /** Locates a const-string discriminator property across union options. */
128
+ findDiscriminatorProperty(options: IRNode[], sharedPropNames: string[]): string | null;
129
+ /** Computes shared and combined property names across union options. */
130
+ collectUnionPropertyNames(options: IRNode[]): {
131
+ allPropNames: string[];
132
+ sharedPropNames: string[];
133
+ };
134
+ /** Returns a clone of `opt` with the discriminator property removed. */
135
+ stripDiscriminatorField(opt: IRNode, discriminator: string): IRNode;
136
+ /** Returns the const string value of an enum/literal IR, if any. */
137
+ getConstStringValue(ir: IRNode | undefined): string | undefined;
138
+ }
139
+ export interface BaseConverterOpts {
140
+ /** Overrides the IR root name (which defaults to schema.title or "Root"). */
141
+ rootTypeName?: string;
142
+ /**
143
+ * Controls the postfix added to array item type names.
144
+ * - `false` (default) → no postfix, uses property name directly
145
+ * - `string` → custom postfix (e.g. "Item" → ContactsItem, "Element" → ContactsElement)
146
+ */
147
+ arrayItemNaming?: string | false;
148
+ /**
149
+ * If true (default), singularize array item path segments when generating type names.
150
+ */
151
+ depluralize?: boolean;
152
+ /**
153
+ * Additional words that should not be singularized when `depluralize` is true.
154
+ */
155
+ uncountableWords?: string[];
156
+ /**
157
+ * How to handle unions that survive merging with no discriminator.
158
+ * - `"throw"` (default) — throw with a path-bearing message
159
+ * - `"fallback"` — emit a language-specific fallback type (added in later tasks)
160
+ */
161
+ unsupportedUnions?: "throw" | "fallback";
162
+ /**
163
+ * Shared registry of declaration names already emitted. When provided,
164
+ * the converter uses this Set as its `usedDeclarationNames` and mutates
165
+ * it as new types are emitted. Pass the same Set across multiple emit
166
+ * calls to avoid duplicate-name compile errors when the resulting code
167
+ * blocks are concatenated into one Kotlin/Swift namespace.
168
+ *
169
+ * Names that collide across calls fall through the standard collision-
170
+ * resolution path (parent path escalation, postfix list, then a numeric
171
+ * suffix). Pair with {@link namePrefix} for cleaner per-slot names.
172
+ *
173
+ * Most useful for Kotlin and Swift, which require named declarations for
174
+ * all non-primitive types. Harmless for TypeScript, which can use
175
+ * `inlineTypes: true` to flatten nested types instead.
176
+ */
177
+ nameRegistry?: Set<string>;
178
+ /**
179
+ * Optional synthetic component prepended to every extracted (nested)
180
+ * type name during ref-type naming. With `namePrefix: "Body"`, a nested
181
+ * `address` field extracts as `BodyAddress` instead of `Address`.
182
+ *
183
+ * Useful when emitting multiple sibling schemas that share an output
184
+ * namespace — pair with {@link nameRegistry} and a per-slot
185
+ * {@link rootTypeName} to avoid all cross-call collisions.
186
+ *
187
+ * Does not affect the root type name (use `rootTypeName` for that).
188
+ * The prefix is sanitized via PascalCase, so non-identifier characters
189
+ * are stripped.
190
+ */
191
+ namePrefix?: string;
192
+ }
193
+ export declare abstract class BaseConverter implements Partial<ILanguageConverter>, BaseConverterContext {
194
+ abstract readonly code: string;
195
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
196
+ abstract readonly languageProfile: LanguageProfile;
197
+ abstract readonly rootTypeName: string;
198
+ abstract readonly extractedTypeNames: string[];
199
+ abstract readonly imports: string[];
200
+ get language(): string;
201
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
202
+ refTypes: RefTypes;
203
+ /**
204
+ * Shared registry of all top-level declaration names (types + enums) for cross-namespace collision detection.
205
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
206
+ */
207
+ usedDeclarationNames: Set<string>;
208
+ /**
209
+ * Root schema name, used as fallback context for root-level array item naming.
210
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
211
+ */
212
+ rootName?: string;
213
+ /**
214
+ * Optional doc note attached to the root type declaration. Populated by
215
+ * subclasses (e.g. for additionalProperties annotations) since the root
216
+ * type is not held in the refTypes registry.
217
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
218
+ */
219
+ rootDoc?: string;
220
+ /**
221
+ * Shared options available to all language converters.
222
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
223
+ */
224
+ baseOpts?: BaseConverterOpts;
225
+ /** @internal Public for `BaseConverterContext`; treat as private. */
226
+ fallbackCounter: number;
227
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
228
+ mergeCounter: number;
229
+ /**
230
+ * Maps discriminator literal IR nodes to their consolidated enum info.
231
+ * Used by generateLiteralType and preRegisterEnumNames to emit a single
232
+ * consolidated enum and member references instead of single-value enums.
233
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
234
+ */
235
+ discriminatorInfo: Map<IRNode, {
236
+ allValues: string[];
237
+ thisValue: string;
238
+ }>;
239
+ /**
240
+ * Maps variant IR nodes to their enhancement-assigned names.
241
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
242
+ */
243
+ variantNames: Map<IRNode, string>;
244
+ /**
245
+ * Signatures eligible for cross-variant deduplication.
246
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
247
+ */
248
+ dedupSignatures: Set<string>;
249
+ /**
250
+ * Returns names of all extracted ref types in declaration order.
251
+ * Subclasses may filter further (e.g. to exclude the root type).
252
+ */
253
+ protected computeExtractedTypeNames(): string[];
254
+ /** Path-derived, collision-free ref type name. Delegates to `naming.ts`. */
255
+ protected getUniqueRefTypeName(signature: string, nodePath: string): RefTypeName;
256
+ /**
257
+ * Each language subclass must implement object-literal emission.
258
+ * `getReferencedType` calls this when registering a new ref type.
259
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
260
+ */
261
+ abstract generateObjectType(ir: IRNode, utils: GenerateTypeUtils): string;
262
+ /** Resolves an IR node to its registered ref-type name. Delegates to `registry.ts`. */
263
+ protected getReferencedType(ir: IRNode): string | undefined;
264
+ /**
265
+ * Recursively walks the IR tree (bottom-up) and merges anyOf unions
266
+ * whose options are all objects with compatible property types.
267
+ * Delegates to `mergeUnions.ts`.
268
+ */
269
+ protected mergeCompatibleUnions(ir: IRNode): IRNode;
270
+ /** Delegates to `mergeUnions.ts`. */
271
+ protected tryMergeObjectUnion(ir: IRNode): IRNode | null;
272
+ /** Delegates to `mergeUnions.ts`. */
273
+ protected tryMergeProperty(instances: IRNode[]): IRNode | null;
274
+ /** Delegates to `mergeUnions.ts`. */
275
+ protected isDiscriminatedUnion(options: IRNode[], sharedPropNames: string[], allPropNames: string[]): boolean;
276
+ /**
277
+ * Walks the IR tree and applies discriminated union enhancements
278
+ * to anyOf unions that survived merging. Delegates to `discriminatedUnions.ts`.
279
+ */
280
+ protected enhanceDiscriminatedUnions(ir: IRNode): void;
281
+ /**
282
+ * Delegates to `discriminatedUnions.ts`.
283
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
284
+ */
285
+ stripDiscriminatorField(opt: IRNode, discriminator: string): IRNode;
286
+ /**
287
+ * Returns `base` if it is not already taken in `usedDeclarationNames`,
288
+ * otherwise appends an incrementing suffix (`base2`, `base3`, …) until a
289
+ * free name is found. Subclasses use this for collision-free declaration
290
+ * names where path-derived disambiguation is not appropriate (e.g. enum
291
+ * names derived from a property name).
292
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
293
+ */
294
+ findAvailableName(base: string): string;
295
+ /** Delegates to `discriminatedUnions.ts`. */
296
+ protected applyDiscriminatedUnionEnhancements(ir: IRNode): void;
297
+ /**
298
+ * Delegates to `discriminatedUnions.ts`.
299
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
300
+ */
301
+ collectUnionPropertyNames(options: IRNode[]): {
302
+ allPropNames: string[];
303
+ sharedPropNames: string[];
304
+ };
305
+ /**
306
+ * Delegates to `discriminatedUnions.ts`.
307
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
308
+ */
309
+ findDiscriminatorProperty(options: IRNode[], sharedPropNames: string[]): string | null;
310
+ /**
311
+ * Delegates to `discriminatedUnions.ts`.
312
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
313
+ */
314
+ getConstStringValue(ir: IRNode | undefined): string | undefined;
315
+ }
@@ -0,0 +1,131 @@
1
+ import { computeExtractedTypeNames, getUniqueRefTypeName, } from "./naming.js";
2
+ import { getReferencedType } from "./registry.js";
3
+ import { isDiscriminatedUnion, mergeCompatibleUnions, tryMergeObjectUnion, tryMergeProperty, } from "./mergeUnions.js";
4
+ import { applyDiscriminatedUnionEnhancements, collectUnionPropertyNames, enhanceDiscriminatedUnions, findDiscriminatorProperty, getConstStringValue, stripDiscriminatorField, } from "./discriminatedUnions.js";
5
+ export { walkIR } from "./walk.js";
6
+ export class BaseConverter {
7
+ constructor() {
8
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
9
+ this.refTypes = [];
10
+ /**
11
+ * Shared registry of all top-level declaration names (types + enums) for cross-namespace collision detection.
12
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
13
+ */
14
+ this.usedDeclarationNames = new Set();
15
+ /** @internal Public for `BaseConverterContext`; treat as private. */
16
+ this.fallbackCounter = 0;
17
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
18
+ this.mergeCounter = 0;
19
+ /**
20
+ * Maps discriminator literal IR nodes to their consolidated enum info.
21
+ * Used by generateLiteralType and preRegisterEnumNames to emit a single
22
+ * consolidated enum and member references instead of single-value enums.
23
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
24
+ */
25
+ this.discriminatorInfo = new Map();
26
+ /**
27
+ * Maps variant IR nodes to their enhancement-assigned names.
28
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
29
+ */
30
+ this.variantNames = new Map();
31
+ /**
32
+ * Signatures eligible for cross-variant deduplication.
33
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
34
+ */
35
+ this.dedupSignatures = new Set();
36
+ }
37
+ get language() {
38
+ return this.languageProfile.language;
39
+ }
40
+ /**
41
+ * Returns names of all extracted ref types in declaration order.
42
+ * Subclasses may filter further (e.g. to exclude the root type).
43
+ */
44
+ computeExtractedTypeNames() {
45
+ return computeExtractedTypeNames(this);
46
+ }
47
+ /** Path-derived, collision-free ref type name. Delegates to `naming.ts`. */
48
+ getUniqueRefTypeName(signature, nodePath) {
49
+ return getUniqueRefTypeName(this, signature, nodePath);
50
+ }
51
+ /** Resolves an IR node to its registered ref-type name. Delegates to `registry.ts`. */
52
+ getReferencedType(ir) {
53
+ return getReferencedType(this, ir);
54
+ }
55
+ /**
56
+ * Recursively walks the IR tree (bottom-up) and merges anyOf unions
57
+ * whose options are all objects with compatible property types.
58
+ * Delegates to `mergeUnions.ts`.
59
+ */
60
+ mergeCompatibleUnions(ir) {
61
+ return mergeCompatibleUnions(this, ir);
62
+ }
63
+ /** Delegates to `mergeUnions.ts`. */
64
+ tryMergeObjectUnion(ir) {
65
+ return tryMergeObjectUnion(this, ir);
66
+ }
67
+ /** Delegates to `mergeUnions.ts`. */
68
+ tryMergeProperty(instances) {
69
+ return tryMergeProperty(instances);
70
+ }
71
+ /** Delegates to `mergeUnions.ts`. */
72
+ isDiscriminatedUnion(options, sharedPropNames, allPropNames) {
73
+ return isDiscriminatedUnion(options, sharedPropNames, allPropNames);
74
+ }
75
+ /**
76
+ * Walks the IR tree and applies discriminated union enhancements
77
+ * to anyOf unions that survived merging. Delegates to `discriminatedUnions.ts`.
78
+ */
79
+ enhanceDiscriminatedUnions(ir) {
80
+ enhanceDiscriminatedUnions(this, ir);
81
+ }
82
+ /**
83
+ * Delegates to `discriminatedUnions.ts`.
84
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
85
+ */
86
+ stripDiscriminatorField(opt, discriminator) {
87
+ return stripDiscriminatorField(this, opt, discriminator);
88
+ }
89
+ /**
90
+ * Returns `base` if it is not already taken in `usedDeclarationNames`,
91
+ * otherwise appends an incrementing suffix (`base2`, `base3`, …) until a
92
+ * free name is found. Subclasses use this for collision-free declaration
93
+ * names where path-derived disambiguation is not appropriate (e.g. enum
94
+ * names derived from a property name).
95
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
96
+ */
97
+ findAvailableName(base) {
98
+ if (!this.usedDeclarationNames.has(base))
99
+ return base;
100
+ let i = 2;
101
+ while (this.usedDeclarationNames.has(base + i))
102
+ i++;
103
+ return base + i;
104
+ }
105
+ /** Delegates to `discriminatedUnions.ts`. */
106
+ applyDiscriminatedUnionEnhancements(ir) {
107
+ applyDiscriminatedUnionEnhancements(this, ir);
108
+ }
109
+ /**
110
+ * Delegates to `discriminatedUnions.ts`.
111
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
112
+ */
113
+ collectUnionPropertyNames(options) {
114
+ return collectUnionPropertyNames(options);
115
+ }
116
+ /**
117
+ * Delegates to `discriminatedUnions.ts`.
118
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
119
+ */
120
+ findDiscriminatorProperty(options, sharedPropNames) {
121
+ return findDiscriminatorProperty(options, sharedPropNames);
122
+ }
123
+ /**
124
+ * Delegates to `discriminatedUnions.ts`.
125
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
126
+ */
127
+ getConstStringValue(ir) {
128
+ return getConstStringValue(ir);
129
+ }
130
+ }
131
+ //# sourceMappingURL=BaseConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseConverter.js","sourceRoot":"","sources":["../../src/converter/BaseConverter.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mCAAmC,EACnC,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AA4NnC,MAAM,OAAgB,aAAa;IAAnC;QAYE,sFAAsF;QAC/E,aAAQ,GAAa,EAAE,CAAC;QAC/B;;;WAGG;QACI,yBAAoB,GAAG,IAAI,GAAG,EAAU,CAAC;QAkBhD,qEAAqE;QAC9D,oBAAe,GAAG,CAAC,CAAC;QAE3B,sFAAsF;QAC/E,iBAAY,GAAG,CAAC,CAAC;QAExB;;;;;WAKG;QACI,sBAAiB,GAAG,IAAI,GAAG,EAG/B,CAAC;QACJ;;;WAGG;QACI,iBAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;QAChD;;;WAGG;QACI,oBAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAwH7C,CAAC;IA7KC,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC;IACvC,CAAC;IAqDD;;;OAGG;IACO,yBAAyB;QACjC,OAAO,yBAAyB,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,4EAA4E;IAClE,oBAAoB,CAAC,SAAiB,EAAE,QAAgB;QAChE,OAAO,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IASD,uFAAuF;IAC7E,iBAAiB,CAAC,EAAU;QACpC,OAAO,iBAAiB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrC,CAAC;IAED;;;;OAIG;IACO,qBAAqB,CAAC,EAAU;QACxC,OAAO,qBAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,qCAAqC;IAC3B,mBAAmB,CAAC,EAAU;QACtC,OAAO,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,qCAAqC;IAC3B,gBAAgB,CAAC,SAAmB;QAC5C,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED,qCAAqC;IAC3B,oBAAoB,CAC5B,OAAiB,EACjB,eAAyB,EACzB,YAAsB;QAEtB,OAAO,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC;IACtE,CAAC;IAED;;;OAGG;IACO,0BAA0B,CAAC,EAAU;QAC7C,0BAA0B,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvC,CAAC;IAED;;;OAGG;IACI,uBAAuB,CAAC,GAAW,EAAE,aAAqB;QAC/D,OAAO,uBAAuB,CAAC,IAAI,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;IAC3D,CAAC;IAED;;;;;;;OAOG;IACI,iBAAiB,CAAC,IAAY;QACnC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;YAAE,CAAC,EAAE,CAAC;QACpD,OAAO,IAAI,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,6CAA6C;IACnC,mCAAmC,CAAC,EAAU;QACtD,mCAAmC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAChD,CAAC;IAED;;;OAGG;IACI,yBAAyB,CAAC,OAAiB;QAIhD,OAAO,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACI,yBAAyB,CAC9B,OAAiB,EACjB,eAAyB;QAEzB,OAAO,yBAAyB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAC7D,CAAC;IAED;;;OAGG;IACI,mBAAmB,CAAC,EAAsB;QAC/C,OAAO,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,35 @@
1
+ export interface EmitterOptions {
2
+ /**
3
+ * Indentation unit (string repeated per nesting level). Defaults to two spaces.
4
+ * Common values: `" "` (2 spaces, Kotlin convention), `" "` (4 spaces, Swift).
5
+ */
6
+ indentUnit?: string;
7
+ }
8
+ /**
9
+ * Indent-aware string builder for code emission. Tracks nesting depth via
10
+ * `block()` and emits a single line at the current depth via `line()`.
11
+ *
12
+ * Designed so that all current Kotlin/Swift output can be reproduced without
13
+ * any hardcoded pad strings inside the emit logic.
14
+ */
15
+ export declare class Emitter {
16
+ private readonly indentUnit;
17
+ private currentIndent;
18
+ private readonly lines;
19
+ constructor(opts?: EmitterOptions);
20
+ /** Emit a line at the current indent. Empty string emits a blank line with no indent. */
21
+ line(s?: string): this;
22
+ /** Emit a blank line (no indent). */
23
+ blank(): this;
24
+ /**
25
+ * Emit `header + " {"`, then run `body` at one deeper indent, then emit `footer`.
26
+ * Footer defaults to `"}"`.
27
+ */
28
+ block(header: string, body: () => void, footer?: string): this;
29
+ /**
30
+ * Emit pre-formatted multi-line content at current indent. Each non-empty
31
+ * source line is prefixed with the current indent; empty source lines stay empty.
32
+ */
33
+ raw(s: string): this;
34
+ toString(): string;
35
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Indent-aware string builder for code emission. Tracks nesting depth via
3
+ * `block()` and emits a single line at the current depth via `line()`.
4
+ *
5
+ * Designed so that all current Kotlin/Swift output can be reproduced without
6
+ * any hardcoded pad strings inside the emit logic.
7
+ */
8
+ export class Emitter {
9
+ constructor(opts = {}) {
10
+ this.currentIndent = "";
11
+ this.lines = [];
12
+ this.indentUnit = opts.indentUnit ?? " ";
13
+ }
14
+ /** Emit a line at the current indent. Empty string emits a blank line with no indent. */
15
+ line(s = "") {
16
+ this.lines.push(s.length ? this.currentIndent + s : "");
17
+ return this;
18
+ }
19
+ /** Emit a blank line (no indent). */
20
+ blank() {
21
+ this.lines.push("");
22
+ return this;
23
+ }
24
+ /**
25
+ * Emit `header + " {"`, then run `body` at one deeper indent, then emit `footer`.
26
+ * Footer defaults to `"}"`.
27
+ */
28
+ block(header, body, footer = "}") {
29
+ this.line(header + " {");
30
+ this.currentIndent += this.indentUnit;
31
+ body();
32
+ this.currentIndent = this.currentIndent.slice(0, -this.indentUnit.length);
33
+ this.line(footer);
34
+ return this;
35
+ }
36
+ /**
37
+ * Emit pre-formatted multi-line content at current indent. Each non-empty
38
+ * source line is prefixed with the current indent; empty source lines stay empty.
39
+ */
40
+ raw(s) {
41
+ for (const ln of s.split("\n")) {
42
+ this.lines.push(ln.length ? this.currentIndent + ln : "");
43
+ }
44
+ return this;
45
+ }
46
+ toString() {
47
+ return this.lines.join("\n");
48
+ }
49
+ }
50
+ //# sourceMappingURL=Emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Emitter.js","sourceRoot":"","sources":["../../src/converter/Emitter.ts"],"names":[],"mappings":"AAQA;;;;;;GAMG;AACH,MAAM,OAAO,OAAO;IAKlB,YAAY,OAAuB,EAAE;QAH7B,kBAAa,GAAG,EAAE,CAAC;QACV,UAAK,GAAa,EAAE,CAAC;QAGpC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC;IAC5C,CAAC;IAED,yFAAyF;IACzF,IAAI,CAAC,CAAC,GAAG,EAAE;QACT,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qCAAqC;IACrC,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAc,EAAE,IAAgB,EAAE,MAAM,GAAG,GAAG;QAClD,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,CAAC;QACtC,IAAI,EAAE,CAAC;QACP,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,CAAS;QACX,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,47 @@
1
+ import { IRNode } from "../types.js";
2
+ import type { BaseConverterContext } from "./BaseConverter.js";
3
+ /**
4
+ * Collects all property names (in first-seen order) and shared property names
5
+ * across union options.
6
+ *
7
+ * Pure helper — does not depend on any converter context.
8
+ */
9
+ export declare function collectUnionPropertyNames(options: IRNode[]): {
10
+ allPropNames: string[];
11
+ sharedPropNames: string[];
12
+ };
13
+ /**
14
+ * Extracts a single const string value from an IR node (literal with string
15
+ * value or single-value string enum).
16
+ *
17
+ * Pure helper — does not depend on any converter context.
18
+ */
19
+ export declare function getConstStringValue(ir: IRNode | undefined): string | undefined;
20
+ /**
21
+ * Finds the discriminator property among shared properties: a property where
22
+ * each option has a distinct const or single-value-enum string value.
23
+ */
24
+ export declare function findDiscriminatorProperty(options: IRNode[], sharedPropNames: string[]): string | null;
25
+ /**
26
+ * Walks the IR tree and applies discriminated union enhancements
27
+ * to anyOf unions that survived merging. Subclasses may opt in to also
28
+ * process `oneOf` unions via the `processOneOfAsDiscriminatedUnion`
29
+ * field on `languageProfile`.
30
+ */
31
+ export declare function enhanceDiscriminatedUnions(c: BaseConverterContext, ir: IRNode): void;
32
+ /**
33
+ * Enhances an unmerged anyOf union that has a discriminator property.
34
+ * Sets `ir.name` on each variant to a discriminator-derived name and
35
+ * populates `discriminatorInfo` for consolidated enum emission.
36
+ */
37
+ export declare function applyDiscriminatedUnionEnhancements(c: BaseConverterContext, ir: IRNode): void;
38
+ /**
39
+ * Returns a copy of the variant IR node with the discriminator property removed
40
+ * when `languageProfile.shouldEraseDiscriminator` is true. Otherwise returns the original.
41
+ *
42
+ * Used by language emitters that hoist the discriminator into a sealed-interface
43
+ * annotation (Kotlin `@JsonClassDiscriminator`) or a Codable plumbing block (Swift
44
+ * generated `init(from:)`/`encode(to:)`), where carrying the field on the variant
45
+ * struct would cause a duplicate-key error during decode.
46
+ */
47
+ export declare function stripDiscriminatorField(c: BaseConverterContext, opt: IRNode, discriminator: string): IRNode;