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,107 @@
1
+ import { getOrCreateEnumDecl } from "./enums.js";
2
+ import { handleUnsupportedUnion } from "./unsupported.js";
3
+ export const PRIMITIVES = {
4
+ string: "String",
5
+ integer: "Long",
6
+ number: "Double",
7
+ boolean: "Boolean",
8
+ null: "Unit",
9
+ };
10
+ export const FORMAT_MAP = {
11
+ "date-time": { type: "Instant", import: "java.time.Instant", needsContextual: true },
12
+ "date": { type: "LocalDate", import: "java.time.LocalDate", needsContextual: true },
13
+ "time": { type: "LocalTime", import: "java.time.LocalTime", needsContextual: true },
14
+ "uuid": { type: "UUID", import: "java.util.UUID", needsContextual: true },
15
+ "uri": { type: "URI", import: "java.net.URI", needsContextual: true },
16
+ };
17
+ export const STRING_DOC_FORMATS = new Set(["email", "hostname", "ipv4", "ipv6"]);
18
+ /**
19
+ * Maps an IRNode to its Kotlin type expression. Handles primitives, formatted
20
+ * strings (with `@Contextual` and KDoc tracking), arrays, tuples (Pair/Triple),
21
+ * referenced object types, string enums, literals, and unions (T | null
22
+ * unwrapping, sealed-interface dispatch, unsupported-union policy).
23
+ */
24
+ export function generateKotlinType(c, ir, utils) {
25
+ switch (ir.type) {
26
+ case "string": {
27
+ const fmt = ir.constraints?.format;
28
+ if (fmt && FORMAT_MAP[fmt]) {
29
+ const m = FORMAT_MAP[fmt];
30
+ c.importsSet.add(m.import);
31
+ if (c.isKotlinx && m.needsContextual) {
32
+ c.importsSet.add("kotlinx.serialization.Contextual");
33
+ c.contextualNodes.add(ir);
34
+ }
35
+ return m.type;
36
+ }
37
+ if (fmt && STRING_DOC_FORMATS.has(fmt)) {
38
+ c.docFormatNodes.set(ir, fmt);
39
+ }
40
+ return "String";
41
+ }
42
+ case "integer": {
43
+ const fmt = ir.constraints?.format;
44
+ if (fmt === "int32")
45
+ return "Int";
46
+ return PRIMITIVES.integer;
47
+ }
48
+ case "number":
49
+ case "boolean":
50
+ case "null":
51
+ return PRIMITIVES[ir.type];
52
+ case "array":
53
+ return `List<${ir.items ? generateKotlinType(c, ir.items, utils) : "Any"}>`;
54
+ case "tuple": {
55
+ const items = ir.tupleItems ?? [];
56
+ if (items.length === 2) {
57
+ return `Pair<${generateKotlinType(c, items[0], utils)}, ${generateKotlinType(c, items[1], utils)}>`;
58
+ }
59
+ if (items.length === 3) {
60
+ return `Triple<${items.map((i) => generateKotlinType(c, i, utils)).join(", ")}>`;
61
+ }
62
+ throw new Error(`Unsupported: Kotlin tuple of length ${items.length} at "${ir.path}"; only Pair (2) and Triple (3) are supported.`);
63
+ }
64
+ case "object": {
65
+ const ref = utils.getReferencedType(ir);
66
+ if (ref)
67
+ return ref;
68
+ return "Any";
69
+ }
70
+ case "enum": {
71
+ if (ir.values?.every((v) => typeof v === "string")) {
72
+ return getOrCreateEnumDecl(c, ir.values, ir.path);
73
+ }
74
+ // fall through to Any for non-string enums (rare)
75
+ return "Any";
76
+ }
77
+ case "literal": {
78
+ const v = ir.constraints?.value;
79
+ if (typeof v === "string")
80
+ return "String";
81
+ if (typeof v === "boolean")
82
+ return "Boolean";
83
+ if (typeof v === "number") {
84
+ return Number.isInteger(v) ? "Long" : "Double";
85
+ }
86
+ if (v === null)
87
+ return "Unit";
88
+ return "Any";
89
+ }
90
+ case "union": {
91
+ // T | null → unwrap, mark nullable at the property level
92
+ const non = ir.options?.filter((o) => o.type !== "null") ?? [];
93
+ if (non.length === 1)
94
+ return generateKotlinType(c, non[0], utils);
95
+ // Discriminated union: enhanceDiscriminatedUnions populated variantNames
96
+ if (ir.options?.length &&
97
+ ir.options.every((o) => c.variantNames.has(o))) {
98
+ return c.emitSealedInterface(ir, utils);
99
+ }
100
+ // Untagged union — apply unsupportedUnions policy
101
+ return handleUnsupportedUnion(c, ir);
102
+ }
103
+ default:
104
+ return "Any";
105
+ }
106
+ }
107
+ //# sourceMappingURL=typeMapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeMapper.js","sourceRoot":"","sources":["../../src/kotlin/typeMapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { IRNode } from "../types.js";
2
+ import type { KotlinConverterContext } from "./KotlinConverter.js";
3
+ /**
4
+ * Applies the `unsupportedUnions` policy for an untagged union that survived
5
+ * merging and has no usable discriminator.
6
+ */
7
+ export declare function handleUnsupportedUnion(c: KotlinConverterContext, ir: IRNode): string;
8
+ /**
9
+ * Pre-emission guard pass that throws on JSON Schema features Kotlin codegen
10
+ * does not support: `not` and `patternProperties`. These are NOT silenced by
11
+ * `unsupportedUnions: 'fallback'`.
12
+ */
13
+ export declare function guardUnsupportedKeywords(_c: KotlinConverterContext, root: IRNode): void;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Applies the `unsupportedUnions` policy for an untagged union that survived
3
+ * merging and has no usable discriminator.
4
+ */
5
+ export function handleUnsupportedUnion(c, ir) {
6
+ const policy = c.baseOpts?.unsupportedUnions ?? "throw";
7
+ if (policy === "throw") {
8
+ const opts = ir.options?.map((o) => o.type).join(", ") ?? "?";
9
+ throw new Error(`Unsupported: untagged union at "${ir.path}"\n` +
10
+ ` options: [${opts}]\n` +
11
+ ` Add a discriminator property with a const per variant, or set unsupportedUnions:'fallback' to emit JsonElement.`);
12
+ }
13
+ // fallback
14
+ if (c.isKotlinx) {
15
+ c.importsSet.add("kotlinx.serialization.json.JsonElement");
16
+ return "JsonElement";
17
+ }
18
+ return "Any";
19
+ }
20
+ /**
21
+ * Pre-emission guard pass that throws on JSON Schema features Kotlin codegen
22
+ * does not support: `not` and `patternProperties`. These are NOT silenced by
23
+ * `unsupportedUnions: 'fallback'`.
24
+ */
25
+ export function guardUnsupportedKeywords(_c, root) {
26
+ const walk = (n) => {
27
+ if (n.not) {
28
+ throw new Error(`Unsupported: \`not\` keyword at "${n.path}".`);
29
+ }
30
+ if (n.patternProperties &&
31
+ Object.keys(n.patternProperties).length > 0) {
32
+ throw new Error(`Unsupported: patternProperties at "${n.path}".`);
33
+ }
34
+ if (n.properties) {
35
+ for (const k of Object.keys(n.properties))
36
+ walk(n.properties[k]);
37
+ }
38
+ if (n.items)
39
+ walk(n.items);
40
+ if (n.tupleItems)
41
+ for (const t of n.tupleItems)
42
+ walk(t);
43
+ if (n.options)
44
+ for (const o of n.options)
45
+ walk(o);
46
+ if (n.additionalProperties &&
47
+ typeof n.additionalProperties !== "boolean") {
48
+ walk(n.additionalProperties);
49
+ }
50
+ };
51
+ walk(root);
52
+ }
53
+ //# sourceMappingURL=unsupported.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unsupported.js","sourceRoot":"","sources":["../../src/kotlin/unsupported.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,CAAyB,EAAE,EAAU;IAC1E,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,iBAAiB,IAAI,OAAO,CAAC;IACxD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;QAC9D,MAAM,IAAI,KAAK,CACb,mCAAmC,EAAE,CAAC,IAAI,KAAK;YAC7C,eAAe,IAAI,KAAK;YACxB,mHAAmH,CACtH,CAAC;IACJ,CAAC;IACD,WAAW;IACX,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;QAChB,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QAC3D,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,EAA0B,EAAE,IAAY;IAC/E,MAAM,IAAI,GAAG,CAAC,CAAS,EAAQ,EAAE;QAC/B,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;QAClE,CAAC;QACD,IACE,CAAC,CAAC,iBAAiB;YACnB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,MAAM,GAAG,CAAC,EAC3C,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;YACjB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;gBAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,CAAC,KAAK;YAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,CAAC,CAAC,UAAU;YAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU;gBAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,CAAC,OAAO;YAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO;gBAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAClD,IACE,CAAC,CAAC,oBAAoB;YACtB,OAAO,CAAC,CAAC,oBAAoB,KAAK,SAAS,EAC3C,CAAC;YACD,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,CAAC;AACb,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { BaseConverter, GenerateTypeUtils } from "../converter/BaseConverter.js";
2
+ import { IRNode } from "../types.js";
3
+ export declare const SWIFT_RESERVED: Set<string>;
4
+ /**
5
+ * Converts a JSON property key to a valid Swift identifier:
6
+ * - kebab/snake → camelCase
7
+ * - non-identifier chars stripped
8
+ * - leading digit gets `_` prefix
9
+ * - reserved words wrapped in backticks
10
+ * - empty result becomes "value"
11
+ */
12
+ export declare function sanitizeSwiftIdentifier(raw: string): string;
13
+ export declare abstract class SwiftBaseConverter extends BaseConverter {
14
+ /** @internal Mutated by SwiftConverter helper modules; not part of the public API. */
15
+ importsSet: Set<string>;
16
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
17
+ abstract generateObjectType(ir: IRNode, utils: GenerateTypeUtils): string;
18
+ }
@@ -0,0 +1,38 @@
1
+ import { BaseConverter } from "../converter/BaseConverter.js";
2
+ export const SWIFT_RESERVED = new Set([
3
+ "associatedtype", "class", "deinit", "enum", "extension", "fileprivate",
4
+ "func", "import", "init", "inout", "internal", "let", "open", "operator",
5
+ "private", "protocol", "public", "static", "struct", "subscript",
6
+ "typealias", "var", "break", "case", "continue", "default", "defer",
7
+ "do", "else", "fallthrough", "for", "guard", "if", "in", "repeat",
8
+ "return", "switch", "where", "while", "as", "Any", "catch", "false",
9
+ "is", "nil", "rethrows", "super", "self", "Self", "throw", "throws",
10
+ "true", "try",
11
+ ]);
12
+ /**
13
+ * Converts a JSON property key to a valid Swift identifier:
14
+ * - kebab/snake → camelCase
15
+ * - non-identifier chars stripped
16
+ * - leading digit gets `_` prefix
17
+ * - reserved words wrapped in backticks
18
+ * - empty result becomes "value"
19
+ */
20
+ export function sanitizeSwiftIdentifier(raw) {
21
+ let name = raw.replace(/[-_](.)/g, (_, c) => c.toUpperCase());
22
+ name = name.replace(/[^a-zA-Z0-9_]/g, "");
23
+ if (!name)
24
+ name = "value";
25
+ if (/^\d/.test(name))
26
+ name = "_" + name;
27
+ if (SWIFT_RESERVED.has(name))
28
+ name = "`" + name + "`";
29
+ return name;
30
+ }
31
+ export class SwiftBaseConverter extends BaseConverter {
32
+ constructor() {
33
+ super(...arguments);
34
+ /** @internal Mutated by SwiftConverter helper modules; not part of the public API. */
35
+ this.importsSet = new Set();
36
+ }
37
+ }
38
+ //# sourceMappingURL=SwiftBaseConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwiftBaseConverter.js","sourceRoot":"","sources":["../../src/swift/SwiftBaseConverter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAqB,MAAM,+BAA+B,CAAC;AAGjF,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IACpC,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa;IACvE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU;IACxE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW;IAChE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO;IACnE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ;IACjE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO;IACnE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ;IACnE,MAAM,EAAE,KAAK;CACd,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,IAAI,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAE,CAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1E,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI;QAAE,IAAI,GAAG,OAAO,CAAC;IAC1B,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC;IACxC,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;IACtD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,OAAgB,kBAAmB,SAAQ,aAAa;IAA9D;;QACE,sFAAsF;QAC/E,eAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAIxC,CAAC;CAAA"}
@@ -0,0 +1,60 @@
1
+ import { JSONSchema7Definition } from "json-schema";
2
+ import { ILanguageConverter, IRNode } from "../types.js";
3
+ import { BaseConverterContext, BaseConverterOpts, GenerateTypeUtils, LanguageProfile } from "../converter/BaseConverter.js";
4
+ import { SwiftBaseConverter } from "./SwiftBaseConverter.js";
5
+ export interface SwiftConverterOpts extends BaseConverterOpts {
6
+ serializer?: "codable" | "none";
7
+ accessLevel?: "public" | "internal";
8
+ }
9
+ /**
10
+ * The state-and-method surface that helper modules in `src/swift/` need to
11
+ * operate on a SwiftConverter instance. SwiftConverter implements this;
12
+ * helpers take it as their first argument.
13
+ *
14
+ * @internal
15
+ */
16
+ export interface SwiftConverterContext extends BaseConverterContext {
17
+ readonly isCodable: boolean;
18
+ readonly accessLevel: "public" | "internal";
19
+ needsAnyCodable: boolean;
20
+ readonly importsSet: Set<string>;
21
+ readonly docFormatNodes: WeakMap<IRNode, string>;
22
+ readonly enumDecls: Map<string, {
23
+ name: string;
24
+ values: string[];
25
+ }>;
26
+ readonly sealedEnumDecls: string[];
27
+ generateType(ir: IRNode, utils: GenerateTypeUtils): string;
28
+ emitSwiftDiscriminatedEnum(ir: IRNode, utils: GenerateTypeUtils): string;
29
+ }
30
+ export declare class SwiftConverter extends SwiftBaseConverter implements ILanguageConverter, SwiftConverterContext {
31
+ readonly code: string;
32
+ readonly rootTypeName: string;
33
+ readonly extractedTypeNames: string[];
34
+ readonly imports: string[];
35
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
36
+ readonly languageProfile: LanguageProfile;
37
+ /** @internal Mutated by SwiftConverter helper modules; not part of the public API. */
38
+ isCodable: boolean;
39
+ /** @internal */
40
+ accessLevel: "public" | "internal";
41
+ /** @internal */
42
+ enumDecls: Map<string, {
43
+ name: string;
44
+ values: string[];
45
+ }>;
46
+ /** @internal */
47
+ docFormatNodes: WeakMap<IRNode, string>;
48
+ /** @internal */
49
+ sealedEnumDecls: string[];
50
+ /** @internal */
51
+ needsAnyCodable: boolean;
52
+ constructor(schema: JSONSchema7Definition, opts?: SwiftConverterOpts);
53
+ protected codableConformance(): string;
54
+ /** @internal Public for `SwiftConverterContext`; treat as protected for subclasses. */
55
+ generateType(ir: IRNode, utils: GenerateTypeUtils): string;
56
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
57
+ generateObjectType(ir: IRNode, utils: GenerateTypeUtils): string;
58
+ /** @internal Public for `SwiftConverterContext`; treat as protected for subclasses. */
59
+ emitSwiftDiscriminatedEnum(ir: IRNode, utils: GenerateTypeUtils): string;
60
+ }
@@ -0,0 +1,113 @@
1
+ import { JSONSchemaConverter } from "../ir/JSONSchemaConverter.js";
2
+ import { SwiftBaseConverter } from "./SwiftBaseConverter.js";
3
+ import { guardUnsupportedKeywords, anyCodableHelper } from "./unsupported.js";
4
+ import { buildEnumDeclarations } from "./enums.js";
5
+ import { generateSwiftType } from "./typeMapper.js";
6
+ import { generateSwiftObjectType } from "./structEmitter.js";
7
+ import { emitSwiftDiscriminatedEnum } from "./discriminatedEnum.js";
8
+ export class SwiftConverter extends SwiftBaseConverter {
9
+ constructor(schema, opts) {
10
+ super();
11
+ /** @internal */
12
+ this.enumDecls = new Map();
13
+ /** @internal */
14
+ this.docFormatNodes = new WeakMap();
15
+ /** @internal */
16
+ this.sealedEnumDecls = [];
17
+ /** @internal */
18
+ this.needsAnyCodable = false;
19
+ this.baseOpts = opts;
20
+ if (opts?.nameRegistry)
21
+ this.usedDeclarationNames = opts.nameRegistry;
22
+ this.isCodable = (opts?.serializer ?? "codable") === "codable";
23
+ this.accessLevel = opts?.accessLevel ?? "public";
24
+ this.languageProfile = {
25
+ language: "swift",
26
+ processOneOfAsDiscriminatedUnion: true,
27
+ shouldEraseDiscriminator: this.isCodable,
28
+ getDiscriminatedVariantParentName: () => "",
29
+ };
30
+ const ir = this.mergeCompatibleUnions(new JSONSchemaConverter(schema).irNode);
31
+ this.enhanceDiscriminatedUnions(ir);
32
+ guardUnsupportedKeywords(this, ir);
33
+ if (opts?.rootTypeName)
34
+ ir.name = opts.rootTypeName;
35
+ if (!ir.name)
36
+ ir.name = ir.title || "Root";
37
+ this.rootName = ir.name;
38
+ this.usedDeclarationNames.add(ir.name);
39
+ const utils = {
40
+ getReferencedType: this.getReferencedType.bind(this),
41
+ };
42
+ // Root-level string enum: emit a single Swift `enum` and skip the struct path.
43
+ if (ir.type === "enum" && ir.values?.every((v) => typeof v === "string")) {
44
+ const key = JSON.stringify([...ir.values].sort());
45
+ this.enumDecls.set(key, { name: ir.name, values: ir.values });
46
+ const enumCode = buildEnumDeclarations(this);
47
+ this.code = enumCode.join("\n\n") + "\n";
48
+ this.rootTypeName = ir.name;
49
+ this.extractedTypeNames = [];
50
+ this.imports = [...this.importsSet].sort();
51
+ return;
52
+ }
53
+ let rootDecl;
54
+ let needsRootStruct = true;
55
+ if (ir.type === "union" &&
56
+ ir.options?.length &&
57
+ ir.options.every((o) => this.variantNames.has(o))) {
58
+ // Root IS the discriminated union — emit it as a Swift enum directly.
59
+ this.emitSwiftDiscriminatedEnum(ir, utils);
60
+ needsRootStruct = false;
61
+ rootDecl = "";
62
+ }
63
+ else {
64
+ const rootBody = this.generateObjectType(ir, utils);
65
+ const rootDoc = this.rootDoc;
66
+ const rootDocPrefix = rootDoc ? `/// ${rootDoc}\n` : "";
67
+ rootDecl = `${rootDocPrefix}${this.accessLevel} struct ${ir.name}${this.codableConformance()} ${rootBody}`;
68
+ }
69
+ const childDecls = this.refTypes
70
+ .filter(({ name }) => name !== this.rootName)
71
+ .map(({ name, code, doc }) => {
72
+ const docPrefix = doc ? `/// ${doc}\n` : "";
73
+ return `${docPrefix}${this.accessLevel} struct ${name}${this.codableConformance()} ${code}`;
74
+ });
75
+ const enumCode = buildEnumDeclarations(this);
76
+ const allDecls = [...enumCode, ...this.sealedEnumDecls, ...childDecls];
77
+ if (needsRootStruct)
78
+ allDecls.push(rootDecl);
79
+ this.code = allDecls.filter(Boolean).join("\n\n") + "\n";
80
+ if (this.needsAnyCodable) {
81
+ this.code += "\n" + anyCodableHelper(this) + "\n";
82
+ }
83
+ this.rootTypeName = ir.name;
84
+ const refTypeNames = this.computeExtractedTypeNames().filter((n) => n !== this.rootTypeName);
85
+ const enumNames = [...this.enumDecls.values()].map(({ name }) => name).filter((n) => n !== this.rootTypeName);
86
+ const variantStructNames = [];
87
+ for (const decl of this.sealedEnumDecls) {
88
+ const matches = decl.matchAll(/struct (\w+)/g);
89
+ for (const m of matches) {
90
+ if (m[1] !== this.rootTypeName)
91
+ variantStructNames.push(m[1]);
92
+ }
93
+ }
94
+ this.extractedTypeNames = [...new Set([...variantStructNames, ...enumNames, ...refTypeNames])];
95
+ this.imports = [...this.importsSet].sort();
96
+ }
97
+ codableConformance() {
98
+ return this.isCodable ? ": Codable" : "";
99
+ }
100
+ /** @internal Public for `SwiftConverterContext`; treat as protected for subclasses. */
101
+ generateType(ir, utils) {
102
+ return generateSwiftType(this, ir, utils);
103
+ }
104
+ /** @internal Public for `BaseConverterContext`; treat as protected for subclasses. */
105
+ generateObjectType(ir, utils) {
106
+ return generateSwiftObjectType(this, ir, utils);
107
+ }
108
+ /** @internal Public for `SwiftConverterContext`; treat as protected for subclasses. */
109
+ emitSwiftDiscriminatedEnum(ir, utils) {
110
+ return emitSwiftDiscriminatedEnum(this, ir, utils);
111
+ }
112
+ }
113
+ //# sourceMappingURL=SwiftConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwiftConverter.js","sourceRoot":"","sources":["../../src/swift/SwiftConverter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAQnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AA2BpE,MAAM,OAAO,cACX,SAAQ,kBAAkB;IAwB1B,YAAY,MAA6B,EAAE,IAAyB;QAClE,KAAK,EAAE,CAAC;QAVV,gBAAgB;QACT,cAAS,GAAG,IAAI,GAAG,EAA8C,CAAC;QACzE,gBAAgB;QACT,mBAAc,GAAG,IAAI,OAAO,EAAkB,CAAC;QACtD,gBAAgB;QACT,oBAAe,GAAa,EAAE,CAAC;QACtC,gBAAgB;QACT,oBAAe,GAAG,KAAK,CAAC;QAI7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,IAAI,EAAE,YAAY;YAAE,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,YAAY,CAAC;QACtE,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,EAAE,UAAU,IAAI,SAAS,CAAC,KAAK,SAAS,CAAC;QAC/D,IAAI,CAAC,WAAW,GAAG,IAAI,EAAE,WAAW,IAAI,QAAQ,CAAC;QAEjD,IAAI,CAAC,eAAe,GAAG;YACrB,QAAQ,EAAE,OAAO;YACjB,gCAAgC,EAAE,IAAI;YACtC,wBAAwB,EAAE,IAAI,CAAC,SAAS;YACxC,iCAAiC,EAAE,GAAG,EAAE,CAAC,EAAE;SAC5C,CAAC;QAEF,MAAM,EAAE,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;QAC9E,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAC;QACpC,wBAAwB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnC,IAAI,IAAI,EAAE,YAAY;YAAE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC;QACpD,IAAI,CAAC,EAAE,CAAC,IAAI;YAAE,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,KAAK,IAAI,MAAM,CAAC;QAC3C,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAEvC,MAAM,KAAK,GAAsB;YAC/B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;SACrD,CAAC;QAEF,+EAA+E;QAC/E,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;YACzE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAI,EAAE,CAAC,MAAmB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAChE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,MAAkB,EAAE,CAAC,CAAC;YAC1E,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;YACzC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,IAAI,CAAC;YAC5B,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;YAC3C,OAAO;QACT,CAAC;QAED,IAAI,QAAgB,CAAC;QACrB,IAAI,eAAe,GAAG,IAAI,CAAC;QAE3B,IACE,EAAE,CAAC,IAAI,KAAK,OAAO;YACnB,EAAE,CAAC,OAAO,EAAE,MAAM;YAClB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EACjD,CAAC;YACD,sEAAsE;YACtE,IAAI,CAAC,0BAA0B,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC3C,eAAe,GAAG,KAAK,CAAC;YACxB,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC7B,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,QAAQ,GAAG,GAAG,aAAa,GAAG,IAAI,CAAC,WAAW,WAAW,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,kBAAkB,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC7G,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ;aAC7B,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC;aAC5C,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;YAC3B,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC,WAAW,WAAW,IAAI,GAAG,IAAI,CAAC,kBAAkB,EAAE,IAAI,IAAI,EAAE,CAAC;QAC9F,CAAC,CAAC,CAAC;QAEL,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE7C,MAAM,QAAQ,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC,eAAe,EAAE,GAAG,UAAU,CAAC,CAAC;QACvE,IAAI,eAAe;YAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;QACzD,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,IAAI,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,IAAI,CAAC;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,yBAAyB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7F,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9G,MAAM,kBAAkB,GAAa,EAAE,CAAC;QACxC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;YAC/C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,YAAY;oBAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;QACD,IAAI,CAAC,kBAAkB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,kBAAkB,EAAE,GAAG,SAAS,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/F,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,CAAC;IAES,kBAAkB;QAC1B,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,CAAC;IAED,uFAAuF;IAChF,YAAY,CAAC,EAAU,EAAE,KAAwB;QACtD,OAAO,iBAAiB,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED,sFAAsF;IAC/E,kBAAkB,CAAC,EAAU,EAAE,KAAwB;QAC5D,OAAO,uBAAuB,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IAED,uFAAuF;IAChF,0BAA0B,CAAC,EAAU,EAAE,KAAwB;QACpE,OAAO,0BAA0B,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import { GenerateTypeUtils } from "../converter/BaseConverter.js";
2
+ import { IRNode } from "../types.js";
3
+ import type { SwiftConverterContext } from "./SwiftConverter.js";
4
+ /**
5
+ * Emits a Swift `enum` with associated-value cases plus per-variant nested
6
+ * `struct` declarations for a discriminated union, registering them in
7
+ * `c.sealedEnumDecls`. Idempotent for nested visits: re-emitting the same
8
+ * enum short-circuits via `sealedEnumDeclsContainsName`.
9
+ */
10
+ export declare function emitSwiftDiscriminatedEnum(c: SwiftConverterContext, ir: IRNode, utils: GenerateTypeUtils): string;
11
+ /** Derives the Swift discriminated-enum name for a union IR node. */
12
+ export declare function deriveSwiftSealedName(c: SwiftConverterContext, ir: IRNode): string;
13
+ /**
14
+ * Substring-scans `c.sealedEnumDecls` for an existing declaration matching the
15
+ * given name. Used to detect prior emission so the orchestrator can skip the
16
+ * regular ref-types path for sealed variants.
17
+ */
18
+ export declare function sealedEnumDeclsContainsName(c: SwiftConverterContext, name: string): boolean;
@@ -0,0 +1,99 @@
1
+ import { Emitter } from "../converter/Emitter.js";
2
+ import { toSwiftCaseName } from "./enums.js";
3
+ import { generateSwiftObjectType } from "./structEmitter.js";
4
+ /**
5
+ * Emits a Swift `enum` with associated-value cases plus per-variant nested
6
+ * `struct` declarations for a discriminated union, registering them in
7
+ * `c.sealedEnumDecls`. Idempotent for nested visits: re-emitting the same
8
+ * enum short-circuits via `sealedEnumDeclsContainsName`.
9
+ */
10
+ export function emitSwiftDiscriminatedEnum(c, ir, utils) {
11
+ const enumName = deriveSwiftSealedName(c, ir);
12
+ if (c.usedDeclarationNames.has(enumName) && sealedEnumDeclsContainsName(c, enumName)) {
13
+ return enumName;
14
+ }
15
+ c.usedDeclarationNames.add(enumName);
16
+ const options = ir.options;
17
+ const discriminator = c.findDiscriminatorProperty(options, c.collectUnionPropertyNames(options).sharedPropNames);
18
+ if (!discriminator)
19
+ return "Any";
20
+ const variants = [];
21
+ for (const opt of options) {
22
+ const variantName = c.variantNames.get(opt);
23
+ const discValue = c.getConstStringValue(opt.properties[discriminator]);
24
+ const caseName = toSwiftCaseName(discValue);
25
+ // Build nested struct body, optionally erasing discriminator under codable
26
+ const tempIR = c.stripDiscriminatorField(opt, discriminator);
27
+ const body = generateSwiftObjectType(c, tempIR, utils);
28
+ variants.push({ caseName, structName: variantName, discValue, body });
29
+ }
30
+ const accessLevel = c.accessLevel;
31
+ const conformance = c.isCodable ? ": Codable" : "";
32
+ const e = new Emitter({ indentUnit: " " });
33
+ e.block(`${accessLevel} enum ${enumName}${conformance}`, () => {
34
+ for (const v of variants) {
35
+ e.line(`case ${v.caseName}(${v.structName})`);
36
+ }
37
+ e.blank();
38
+ // Nested variant structs. `v.body` is a `{\n ... \n}` block with its own
39
+ // 2-space inner indentation; `raw()` prefixes each non-empty line with the
40
+ // current Emitter indent (4 spaces here), preserving the existing inner
41
+ // 2-space indent for struct fields.
42
+ for (const v of variants) {
43
+ e.raw(`${accessLevel} struct ${v.structName}${conformance} ${v.body}`);
44
+ e.blank();
45
+ }
46
+ if (c.isCodable) {
47
+ e.line(`private enum CodingKeys: String, CodingKey { case ${discriminator} }`);
48
+ const kindCases = variants
49
+ .map((v) => v.caseName === v.discValue
50
+ ? `case ${v.caseName}`
51
+ : `case ${v.caseName} = "${v.discValue}"`)
52
+ .join("; ");
53
+ e.line(`private enum Kind: String, Codable { ${kindCases} }`);
54
+ e.blank();
55
+ e.block(`${accessLevel} init(from decoder: Decoder) throws`, () => {
56
+ e.line("let container = try decoder.container(keyedBy: CodingKeys.self)");
57
+ e.line(`let kind = try container.decode(Kind.self, forKey: .${discriminator})`);
58
+ e.line("let single = try decoder.singleValueContainer()");
59
+ e.block("switch kind", () => {
60
+ for (const v of variants) {
61
+ e.line(`case .${v.caseName}: self = .${v.caseName}(try single.decode(${v.structName}.self))`);
62
+ }
63
+ });
64
+ });
65
+ e.blank();
66
+ e.block(`${accessLevel} func encode(to encoder: Encoder) throws`, () => {
67
+ e.line("var container = encoder.singleValueContainer()");
68
+ e.block("switch self", () => {
69
+ for (const v of variants) {
70
+ e.line(`case .${v.caseName}(let v): try container.encode(v)`);
71
+ }
72
+ });
73
+ });
74
+ }
75
+ });
76
+ c.sealedEnumDecls.push(e.toString());
77
+ for (const v of variants)
78
+ c.usedDeclarationNames.add(v.structName);
79
+ return enumName;
80
+ }
81
+ /** Derives the Swift discriminated-enum name for a union IR node. */
82
+ export function deriveSwiftSealedName(c, ir) {
83
+ if (ir.name)
84
+ return ir.name;
85
+ if (ir.title)
86
+ return ir.title;
87
+ const segments = ir.path.split(".").filter((x) => !/^\d+$/.test(x));
88
+ const baseName = segments.map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("") || "Union";
89
+ return c.findAvailableName(baseName);
90
+ }
91
+ /**
92
+ * Substring-scans `c.sealedEnumDecls` for an existing declaration matching the
93
+ * given name. Used to detect prior emission so the orchestrator can skip the
94
+ * regular ref-types path for sealed variants.
95
+ */
96
+ export function sealedEnumDeclsContainsName(c, name) {
97
+ return c.sealedEnumDecls.some((d) => d.includes(`enum ${name}`));
98
+ }
99
+ //# sourceMappingURL=discriminatedEnum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discriminatedEnum.js","sourceRoot":"","sources":["../../src/swift/discriminatedEnum.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { SwiftConverterContext } from "./SwiftConverter.js";
2
+ /**
3
+ * Returns or creates a Swift `enum` declaration name for a given set of
4
+ * string values, deduplicating by sorted-values key. Tracks the declaration
5
+ * for later emission via {@link buildEnumDeclarations}.
6
+ */
7
+ export declare function getOrCreateEnumDecl(c: SwiftConverterContext, values: string[], path: string): string;
8
+ /** Sanitizes a JSON enum value into a Swift enum case name (lowerCamelCase). */
9
+ export declare function toSwiftCaseName(value: string): string;
10
+ /**
11
+ * Builds Swift raw-value `enum` declarations from the converter's accumulated
12
+ * `enumDecls` map. Used for both nested enums (rendered alongside structs) and
13
+ * root-level enum schemas (where the root IS the enum).
14
+ */
15
+ export declare function buildEnumDeclarations(c: SwiftConverterContext): string[];
@@ -0,0 +1,62 @@
1
+ import { toPascalCase } from "../utils/to-pascal-case.js";
2
+ /**
3
+ * Returns or creates a Swift `enum` declaration name for a given set of
4
+ * string values, deduplicating by sorted-values key. Tracks the declaration
5
+ * for later emission via {@link buildEnumDeclarations}.
6
+ */
7
+ export function getOrCreateEnumDecl(c, values, path) {
8
+ const key = JSON.stringify([...values].sort());
9
+ const existing = c.enumDecls.get(key);
10
+ if (existing)
11
+ return existing.name;
12
+ const segments = path.split(".").filter((x) => !/^\d+$/.test(x));
13
+ const baseName = segments.map((s) => toPascalCase(s)).join("") || "Value";
14
+ const name = c.findAvailableName(baseName);
15
+ c.usedDeclarationNames.add(name);
16
+ c.enumDecls.set(key, { name, values });
17
+ return name;
18
+ }
19
+ /** Sanitizes a JSON enum value into a Swift enum case name (lowerCamelCase). */
20
+ export function toSwiftCaseName(value) {
21
+ // Step 1: kebab/snake → camelCase, then strip invalid chars.
22
+ let n = value.replace(/[-_](.)/g, (_, c) => c.toUpperCase());
23
+ n = n.replace(/[^a-zA-Z0-9_]/g, "");
24
+ if (!n)
25
+ n = "value";
26
+ if (/^\d/.test(n))
27
+ n = "_" + n;
28
+ // Preserve all-uppercase identifiers (e.g. "US", "URL", "ID") to match Swift convention
29
+ // for acronyms — otherwise they'd render awkwardly as `uS`, `uRL`, etc.
30
+ if (n.length >= 2 && /^[A-Z][A-Z0-9_]*$/.test(n))
31
+ return n;
32
+ // Otherwise lowerCamelCase per Swift convention.
33
+ return n.charAt(0).toLowerCase() + n.slice(1);
34
+ }
35
+ /**
36
+ * Builds Swift raw-value `enum` declarations from the converter's accumulated
37
+ * `enumDecls` map. Used for both nested enums (rendered alongside structs) and
38
+ * root-level enum schemas (where the root IS the enum).
39
+ */
40
+ export function buildEnumDeclarations(c) {
41
+ return [...c.enumDecls.values()].map(({ name, values }) => {
42
+ const usedCases = new Set();
43
+ const cases = values.map((v) => {
44
+ let caseName = toSwiftCaseName(v);
45
+ const baseC = caseName;
46
+ let i = 2;
47
+ while (usedCases.has(caseName)) {
48
+ caseName = baseC + i;
49
+ i++;
50
+ }
51
+ usedCases.add(caseName);
52
+ // emit `case foo` if caseName matches v exactly, else `case foo = "raw"`
53
+ if (caseName === v) {
54
+ return ` case ${caseName}`;
55
+ }
56
+ return ` case ${caseName} = "${v}"`;
57
+ });
58
+ const conformance = c.isCodable ? ", Codable" : "";
59
+ return `${c.accessLevel} enum ${name}: String${conformance} {\n${cases.join("\n")}\n}`;
60
+ });
61
+ }
62
+ //# sourceMappingURL=enums.js.map