ajsc 5.2.4 → 7.0.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 (141) hide show
  1. package/README.md +253 -145
  2. package/dist/converter/BaseConverter.d.ts +283 -0
  3. package/dist/converter/BaseConverter.js +131 -0
  4. package/dist/converter/BaseConverter.js.map +1 -0
  5. package/dist/converter/Emitter.d.ts +35 -0
  6. package/dist/converter/Emitter.js +50 -0
  7. package/dist/converter/Emitter.js.map +1 -0
  8. package/dist/converter/discriminatedUnions.d.ts +47 -0
  9. package/dist/converter/discriminatedUnions.js +168 -0
  10. package/dist/converter/discriminatedUnions.js.map +1 -0
  11. package/dist/converter/formatDefault.d.ts +20 -0
  12. package/dist/converter/formatDefault.js +31 -0
  13. package/dist/converter/formatDefault.js.map +1 -0
  14. package/dist/converter/index.d.ts +2 -0
  15. package/dist/converter/index.js +2 -0
  16. package/dist/converter/index.js.map +1 -0
  17. package/dist/converter/mergeUnions.d.ts +36 -0
  18. package/dist/converter/mergeUnions.js +189 -0
  19. package/dist/converter/mergeUnions.js.map +1 -0
  20. package/dist/converter/naming.d.ts +29 -0
  21. package/dist/converter/naming.js +130 -0
  22. package/dist/converter/naming.js.map +1 -0
  23. package/dist/converter/registry.d.ts +18 -0
  24. package/dist/converter/registry.js +50 -0
  25. package/dist/converter/registry.js.map +1 -0
  26. package/dist/converter/walk.d.ts +9 -0
  27. package/dist/converter/walk.js +40 -0
  28. package/dist/converter/walk.js.map +1 -0
  29. package/dist/index.d.ts +71 -3
  30. package/dist/index.js +63 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/{JSONSchemaConverter.d.ts → ir/JSONSchemaConverter.d.ts} +1 -1
  33. package/dist/{JSONSchemaConverter.js → ir/JSONSchemaConverter.js} +9 -3
  34. package/dist/ir/JSONSchemaConverter.js.map +1 -0
  35. package/dist/ir/index.d.ts +1 -0
  36. package/dist/ir/index.js +2 -0
  37. package/dist/ir/index.js.map +1 -0
  38. package/dist/kotlin/KotlinBaseConverter.d.ts +18 -0
  39. package/dist/kotlin/KotlinBaseConverter.js +36 -0
  40. package/dist/kotlin/KotlinBaseConverter.js.map +1 -0
  41. package/dist/kotlin/KotlinConverter.d.ts +67 -0
  42. package/dist/kotlin/KotlinConverter.js +140 -0
  43. package/dist/kotlin/KotlinConverter.js.map +1 -0
  44. package/dist/kotlin/annotations.d.ts +26 -0
  45. package/dist/kotlin/annotations.js +35 -0
  46. package/dist/kotlin/annotations.js.map +1 -0
  47. package/dist/kotlin/enums.d.ts +15 -0
  48. package/dist/kotlin/enums.js +58 -0
  49. package/dist/kotlin/enums.js.map +1 -0
  50. package/dist/kotlin/index.d.ts +2 -0
  51. package/dist/kotlin/index.js +3 -0
  52. package/dist/kotlin/index.js.map +1 -0
  53. package/dist/kotlin/objectEmitter.d.ts +12 -0
  54. package/dist/kotlin/objectEmitter.js +74 -0
  55. package/dist/kotlin/objectEmitter.js.map +1 -0
  56. package/dist/kotlin/sealedUnion.d.ts +17 -0
  57. package/dist/kotlin/sealedUnion.js +74 -0
  58. package/dist/kotlin/sealedUnion.js.map +1 -0
  59. package/dist/kotlin/typeMapper.d.ts +17 -0
  60. package/dist/kotlin/typeMapper.js +107 -0
  61. package/dist/kotlin/typeMapper.js.map +1 -0
  62. package/dist/kotlin/unsupported.d.ts +13 -0
  63. package/dist/kotlin/unsupported.js +53 -0
  64. package/dist/kotlin/unsupported.js.map +1 -0
  65. package/dist/swift/SwiftBaseConverter.d.ts +18 -0
  66. package/dist/swift/SwiftBaseConverter.js +38 -0
  67. package/dist/swift/SwiftBaseConverter.js.map +1 -0
  68. package/dist/swift/SwiftConverter.d.ts +60 -0
  69. package/dist/swift/SwiftConverter.js +111 -0
  70. package/dist/swift/SwiftConverter.js.map +1 -0
  71. package/dist/swift/discriminatedEnum.d.ts +18 -0
  72. package/dist/swift/discriminatedEnum.js +99 -0
  73. package/dist/swift/discriminatedEnum.js.map +1 -0
  74. package/dist/swift/enums.d.ts +15 -0
  75. package/dist/swift/enums.js +62 -0
  76. package/dist/swift/enums.js.map +1 -0
  77. package/dist/swift/index.d.ts +2 -0
  78. package/dist/swift/index.js +3 -0
  79. package/dist/swift/index.js.map +1 -0
  80. package/dist/swift/structEmitter.d.ts +12 -0
  81. package/dist/swift/structEmitter.js +70 -0
  82. package/dist/swift/structEmitter.js.map +1 -0
  83. package/dist/swift/typeMapper.d.ts +18 -0
  84. package/dist/swift/typeMapper.js +106 -0
  85. package/dist/swift/typeMapper.js.map +1 -0
  86. package/dist/swift/unsupported.d.ts +19 -0
  87. package/dist/swift/unsupported.js +88 -0
  88. package/dist/swift/unsupported.js.map +1 -0
  89. package/dist/typescript/TypescriptBaseConverter.d.ts +25 -0
  90. package/dist/typescript/TypescriptBaseConverter.js +178 -0
  91. package/dist/typescript/TypescriptBaseConverter.js.map +1 -0
  92. package/dist/typescript/TypescriptConverter.d.ts +74 -0
  93. package/dist/typescript/TypescriptConverter.js +252 -0
  94. package/dist/typescript/TypescriptConverter.js.map +1 -0
  95. package/dist/typescript/index.d.ts +2 -0
  96. package/dist/typescript/index.js +3 -0
  97. package/dist/typescript/index.js.map +1 -0
  98. package/dist/utils/index.d.ts +2 -0
  99. package/dist/utils/index.js +3 -0
  100. package/dist/utils/index.js.map +1 -0
  101. package/package.json +37 -5
  102. package/dist/JSONSchemaConverter.js.map +0 -1
  103. package/dist/JSONSchemaConverter.test.d.ts +0 -1
  104. package/dist/JSONSchemaConverter.test.js +0 -585
  105. package/dist/JSONSchemaConverter.test.js.map +0 -1
  106. package/dist/Typebox.test.d.ts +0 -1
  107. package/dist/Typebox.test.js +0 -88
  108. package/dist/Typebox.test.js.map +0 -1
  109. package/dist/TypescriptBaseConverter.d.ts +0 -75
  110. package/dist/TypescriptBaseConverter.js +0 -321
  111. package/dist/TypescriptBaseConverter.js.map +0 -1
  112. package/dist/TypescriptConverter.additionalProperties.test.d.ts +0 -1
  113. package/dist/TypescriptConverter.additionalProperties.test.js +0 -110
  114. package/dist/TypescriptConverter.additionalProperties.test.js.map +0 -1
  115. package/dist/TypescriptConverter.arrays.test.d.ts +0 -1
  116. package/dist/TypescriptConverter.arrays.test.js +0 -130
  117. package/dist/TypescriptConverter.arrays.test.js.map +0 -1
  118. package/dist/TypescriptConverter.composites.advanced.test.d.ts +0 -1
  119. package/dist/TypescriptConverter.composites.advanced.test.js +0 -1070
  120. package/dist/TypescriptConverter.composites.advanced.test.js.map +0 -1
  121. package/dist/TypescriptConverter.composites.test.d.ts +0 -1
  122. package/dist/TypescriptConverter.composites.test.js +0 -335
  123. package/dist/TypescriptConverter.composites.test.js.map +0 -1
  124. package/dist/TypescriptConverter.d.ts +0 -163
  125. package/dist/TypescriptConverter.js +0 -606
  126. package/dist/TypescriptConverter.js.map +0 -1
  127. package/dist/TypescriptConverter.jsdoc.test.d.ts +0 -1
  128. package/dist/TypescriptConverter.jsdoc.test.js +0 -194
  129. package/dist/TypescriptConverter.jsdoc.test.js.map +0 -1
  130. package/dist/TypescriptConverter.objects.test.d.ts +0 -1
  131. package/dist/TypescriptConverter.objects.test.js +0 -258
  132. package/dist/TypescriptConverter.objects.test.js.map +0 -1
  133. package/dist/TypescriptConverter.options.test.d.ts +0 -1
  134. package/dist/TypescriptConverter.options.test.js +0 -501
  135. package/dist/TypescriptConverter.options.test.js.map +0 -1
  136. package/dist/TypescriptConverter.primitives.test.d.ts +0 -1
  137. package/dist/TypescriptConverter.primitives.test.js +0 -26
  138. package/dist/TypescriptConverter.primitives.test.js.map +0 -1
  139. package/dist/utils/path-utils.test.d.ts +0 -1
  140. package/dist/utils/path-utils.test.js +0 -92
  141. package/dist/utils/path-utils.test.js.map +0 -1
@@ -0,0 +1,283 @@
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 === rootName
23
+ * back to a self-reference. Default: true (correct for Kotlin/Swift; TS sets false
24
+ * to preserve a known recursion behavior — note: TS no longer sets this to false
25
+ * after the recursion bug fix, so default true is correct for all current languages).
26
+ */
27
+ detectSelfReferenceToRoot?: boolean;
28
+ /**
29
+ * When true, `enhanceDiscriminatedUnions` ALSO walks `oneOf` unions (in addition
30
+ * to `anyOf`). Default: false. Languages that emit a tagged-union form for `oneOf`
31
+ * (Kotlin sealed interface, Swift enum w/ associated values) override to true.
32
+ */
33
+ processOneOfAsDiscriminatedUnion?: boolean;
34
+ /**
35
+ * When true, `applyDiscriminatedUnionEnhancements` populates `discriminatorInfo`
36
+ * for downstream consolidated enum emission. Default: false. TS overrides based
37
+ * on `enumStyle === "enum" && !inlineTypes`.
38
+ */
39
+ shouldPopulateDiscriminatorInfo?: boolean;
40
+ /**
41
+ * When true, `stripDiscriminatorField` removes the discriminator key from variant
42
+ * payload bodies (because the language hoists it into a tag annotation or codable
43
+ * plumbing). Default: false. Kotlin = `isKotlinx`. Swift = `isCodable`.
44
+ */
45
+ shouldEraseDiscriminator?: boolean;
46
+ /**
47
+ * Custom ref-type naming configuration. Merged shallow over the BaseConverter default
48
+ * (postfix list, depluralize, etc.). Useful for adding language-specific postfixes
49
+ * (e.g. "Enum" in TS).
50
+ */
51
+ refTypeNamingConfig?: Partial<RefTypeNamingConfig>;
52
+ /**
53
+ * Parent-name component used by `applyDiscriminatedUnionEnhancements` when deriving
54
+ * variant names. Default: last non-numeric segment of `ir.path`. Kotlin extends this
55
+ * with a fallback to `ir.name || ir.title`; Swift always returns "" (variants are
56
+ * nested in the enum, no parent suffix needed).
57
+ */
58
+ getDiscriminatedVariantParentName?: (ir: IRNode) => string;
59
+ /**
60
+ * Override ref-type name resolution. `defaultResolver()` invokes the path-based
61
+ * default. TS uses this to apply enum-style overrides.
62
+ */
63
+ resolveRefTypeName?: (ir: IRNode, signature: string, defaultResolver: () => string) => string;
64
+ /**
65
+ * Language-specific signature dedup decision. Default: false. TS = `dedupSignatures.has(sig)`.
66
+ */
67
+ shouldReuseExistingSignature?: (signature: string) => boolean;
68
+ }
69
+ export interface RefTypeNamingConfig {
70
+ /** Base postfixes to try for name collision resolution */
71
+ postfixes: string[];
72
+ /** If true, singularize array item path segments (e.g. "entries" → "entry", "people" → "person") */
73
+ depluralize?: boolean;
74
+ /** If true, handle "*" path endings with AnyKey/AnyProperty postfixes */
75
+ handleAnySymbol?: boolean;
76
+ /** If true, strip leading "*" from proposed names */
77
+ stripLeadingAnySymbol?: boolean;
78
+ /**
79
+ * Controls the postfix added to array item type names.
80
+ * - `false` (default) → no postfix, uses property name directly
81
+ * - `string` → custom postfix (e.g. "Item" → ContactsItem, "Element" → ContactsElement)
82
+ */
83
+ arrayItemNaming?: string | false;
84
+ /**
85
+ * Additional words that should not be singularized when `depluralize` is true.
86
+ * Built-in uncountables: "data", "metadata".
87
+ * @example ["criteria", "alumni", "corpus"]
88
+ */
89
+ uncountableWords?: string[];
90
+ }
91
+ export type GenerateTypeUtils = {
92
+ getReferencedType(ir: IRNode): string | undefined;
93
+ };
94
+ /**
95
+ * The state-and-method surface that helper modules in `src/converter/`
96
+ * need to operate on a BaseConverter instance. BaseConverter implements
97
+ * this; helpers take it as their first argument.
98
+ *
99
+ * Using this interface (rather than the BaseConverter class itself) keeps
100
+ * helper modules from depending on the abstract class shape — they only
101
+ * see the concrete contract they need.
102
+ *
103
+ * @internal
104
+ */
105
+ export interface BaseConverterContext {
106
+ readonly refTypes: RefTypeEntry[];
107
+ readonly usedDeclarationNames: Set<string>;
108
+ rootName?: string;
109
+ rootDoc?: string;
110
+ baseOpts?: BaseConverterOpts;
111
+ readonly variantNames: Map<IRNode, string>;
112
+ readonly discriminatorInfo: Map<IRNode, {
113
+ allValues: string[];
114
+ thisValue: string;
115
+ }>;
116
+ readonly dedupSignatures: Set<string>;
117
+ mergeCounter: number;
118
+ /** Used internally by `getUniqueRefTypeName`; exposed for the helper to mutate. */
119
+ fallbackCounter: number;
120
+ readonly languageProfile: LanguageProfile;
121
+ /** Subclass-implemented; called by `getReferencedType` after registering an entry. */
122
+ generateObjectType(ir: IRNode, utils: GenerateTypeUtils): string;
123
+ /** Returns a name not already in `usedDeclarationNames`, suffixing as needed. */
124
+ findAvailableName(base: string): string;
125
+ /** Locates a const-string discriminator property across union options. */
126
+ findDiscriminatorProperty(options: IRNode[], sharedPropNames: string[]): string | null;
127
+ /** Computes shared and combined property names across union options. */
128
+ collectUnionPropertyNames(options: IRNode[]): {
129
+ allPropNames: string[];
130
+ sharedPropNames: string[];
131
+ };
132
+ /** Returns a clone of `opt` with the discriminator property removed. */
133
+ stripDiscriminatorField(opt: IRNode, discriminator: string): IRNode;
134
+ /** Returns the const string value of an enum/literal IR, if any. */
135
+ getConstStringValue(ir: IRNode | undefined): string | undefined;
136
+ }
137
+ export interface BaseConverterOpts {
138
+ /** Overrides the IR root name (which defaults to schema.title or "Root"). */
139
+ rootTypeName?: string;
140
+ /**
141
+ * Controls the postfix added to array item type names.
142
+ * - `false` (default) → no postfix, uses property name directly
143
+ * - `string` → custom postfix (e.g. "Item" → ContactsItem, "Element" → ContactsElement)
144
+ */
145
+ arrayItemNaming?: string | false;
146
+ /**
147
+ * If true (default), singularize array item path segments when generating type names.
148
+ */
149
+ depluralize?: boolean;
150
+ /**
151
+ * Additional words that should not be singularized when `depluralize` is true.
152
+ */
153
+ uncountableWords?: string[];
154
+ /**
155
+ * How to handle unions that survive merging with no discriminator.
156
+ * - `"throw"` (default) — throw with a path-bearing message
157
+ * - `"fallback"` — emit a language-specific fallback type (added in later tasks)
158
+ */
159
+ unsupportedUnions?: "throw" | "fallback";
160
+ }
161
+ export declare abstract class BaseConverter implements Partial<ILanguageConverter>, BaseConverterContext {
162
+ abstract readonly code: string;
163
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
164
+ abstract readonly languageProfile: LanguageProfile;
165
+ abstract readonly rootTypeName: string;
166
+ abstract readonly extractedTypeNames: string[];
167
+ abstract readonly imports: string[];
168
+ get language(): string;
169
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
170
+ refTypes: RefTypes;
171
+ /**
172
+ * Shared registry of all top-level declaration names (types + enums) for cross-namespace collision detection.
173
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
174
+ */
175
+ usedDeclarationNames: Set<string>;
176
+ /**
177
+ * Root schema name, used as fallback context for root-level array item naming.
178
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
179
+ */
180
+ rootName?: string;
181
+ /**
182
+ * Optional doc note attached to the root type declaration. Populated by
183
+ * subclasses (e.g. for additionalProperties annotations) since the root
184
+ * type is not held in the refTypes registry.
185
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
186
+ */
187
+ rootDoc?: string;
188
+ /**
189
+ * Shared options available to all language converters.
190
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
191
+ */
192
+ baseOpts?: BaseConverterOpts;
193
+ /** @internal Public for `BaseConverterContext`; treat as private. */
194
+ fallbackCounter: number;
195
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
196
+ mergeCounter: number;
197
+ /**
198
+ * Maps discriminator literal IR nodes to their consolidated enum info.
199
+ * Used by generateLiteralType and preRegisterEnumNames to emit a single
200
+ * consolidated enum and member references instead of single-value enums.
201
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
202
+ */
203
+ discriminatorInfo: Map<IRNode, {
204
+ allValues: string[];
205
+ thisValue: string;
206
+ }>;
207
+ /**
208
+ * Maps variant IR nodes to their enhancement-assigned names.
209
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
210
+ */
211
+ variantNames: Map<IRNode, string>;
212
+ /**
213
+ * Signatures eligible for cross-variant deduplication.
214
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
215
+ */
216
+ dedupSignatures: Set<string>;
217
+ /**
218
+ * Returns names of all extracted ref types in declaration order.
219
+ * Subclasses may filter further (e.g. to exclude the root type).
220
+ */
221
+ protected computeExtractedTypeNames(): string[];
222
+ /** Path-derived, collision-free ref type name. Delegates to `naming.ts`. */
223
+ protected getUniqueRefTypeName(signature: string, nodePath: string): RefTypeName;
224
+ /**
225
+ * Each language subclass must implement object-literal emission.
226
+ * `getReferencedType` calls this when registering a new ref type.
227
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
228
+ */
229
+ abstract generateObjectType(ir: IRNode, utils: GenerateTypeUtils): string;
230
+ /** Resolves an IR node to its registered ref-type name. Delegates to `registry.ts`. */
231
+ protected getReferencedType(ir: IRNode): string | undefined;
232
+ /**
233
+ * Recursively walks the IR tree (bottom-up) and merges anyOf unions
234
+ * whose options are all objects with compatible property types.
235
+ * Delegates to `mergeUnions.ts`.
236
+ */
237
+ protected mergeCompatibleUnions(ir: IRNode): IRNode;
238
+ /** Delegates to `mergeUnions.ts`. */
239
+ protected tryMergeObjectUnion(ir: IRNode): IRNode | null;
240
+ /** Delegates to `mergeUnions.ts`. */
241
+ protected tryMergeProperty(instances: IRNode[]): IRNode | null;
242
+ /** Delegates to `mergeUnions.ts`. */
243
+ protected isDiscriminatedUnion(options: IRNode[], sharedPropNames: string[], allPropNames: string[]): boolean;
244
+ /**
245
+ * Walks the IR tree and applies discriminated union enhancements
246
+ * to anyOf unions that survived merging. Delegates to `discriminatedUnions.ts`.
247
+ */
248
+ protected enhanceDiscriminatedUnions(ir: IRNode): void;
249
+ /**
250
+ * Delegates to `discriminatedUnions.ts`.
251
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
252
+ */
253
+ stripDiscriminatorField(opt: IRNode, discriminator: string): IRNode;
254
+ /**
255
+ * Returns `base` if it is not already taken in `usedDeclarationNames`,
256
+ * otherwise appends an incrementing suffix (`base2`, `base3`, …) until a
257
+ * free name is found. Subclasses use this for collision-free declaration
258
+ * names where path-derived disambiguation is not appropriate (e.g. enum
259
+ * names derived from a property name).
260
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
261
+ */
262
+ findAvailableName(base: string): string;
263
+ /** Delegates to `discriminatedUnions.ts`. */
264
+ protected applyDiscriminatedUnionEnhancements(ir: IRNode): void;
265
+ /**
266
+ * Delegates to `discriminatedUnions.ts`.
267
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
268
+ */
269
+ collectUnionPropertyNames(options: IRNode[]): {
270
+ allPropNames: string[];
271
+ sharedPropNames: string[];
272
+ };
273
+ /**
274
+ * Delegates to `discriminatedUnions.ts`.
275
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
276
+ */
277
+ findDiscriminatorProperty(options: IRNode[], sharedPropNames: string[]): string | null;
278
+ /**
279
+ * Delegates to `discriminatedUnions.ts`.
280
+ * @internal Public for `BaseConverterContext`; treat as protected for subclasses.
281
+ */
282
+ getConstStringValue(ir: IRNode | undefined): string | undefined;
283
+ }
@@ -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":"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"}
@@ -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;