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.
- package/CHANGELOG.md +103 -0
- package/README.md +303 -144
- package/dist/converter/BaseConverter.d.ts +315 -0
- package/dist/converter/BaseConverter.js +131 -0
- package/dist/converter/BaseConverter.js.map +1 -0
- package/dist/converter/Emitter.d.ts +35 -0
- package/dist/converter/Emitter.js +50 -0
- package/dist/converter/Emitter.js.map +1 -0
- package/dist/converter/discriminatedUnions.d.ts +47 -0
- package/dist/converter/discriminatedUnions.js +168 -0
- package/dist/converter/discriminatedUnions.js.map +1 -0
- package/dist/converter/formatDefault.d.ts +20 -0
- package/dist/converter/formatDefault.js +31 -0
- package/dist/converter/formatDefault.js.map +1 -0
- package/dist/converter/index.d.ts +24 -0
- package/dist/converter/index.js +24 -0
- package/dist/converter/index.js.map +1 -0
- package/dist/converter/mergeUnions.d.ts +36 -0
- package/dist/converter/mergeUnions.js +189 -0
- package/dist/converter/mergeUnions.js.map +1 -0
- package/dist/converter/naming.d.ts +29 -0
- package/dist/converter/naming.js +137 -0
- package/dist/converter/naming.js.map +1 -0
- package/dist/converter/registry.d.ts +18 -0
- package/dist/converter/registry.js +50 -0
- package/dist/converter/registry.js.map +1 -0
- package/dist/converter/walk.d.ts +9 -0
- package/dist/converter/walk.js +40 -0
- package/dist/converter/walk.js.map +1 -0
- package/dist/index.d.ts +71 -3
- package/dist/index.js +63 -3
- package/dist/index.js.map +1 -1
- package/dist/{JSONSchemaConverter.d.ts → ir/JSONSchemaConverter.d.ts} +1 -1
- package/dist/{JSONSchemaConverter.js → ir/JSONSchemaConverter.js} +9 -3
- package/dist/ir/JSONSchemaConverter.js.map +1 -0
- package/dist/ir/index.d.ts +1 -0
- package/dist/ir/index.js +2 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/kotlin/KotlinBaseConverter.d.ts +18 -0
- package/dist/kotlin/KotlinBaseConverter.js +36 -0
- package/dist/kotlin/KotlinBaseConverter.js.map +1 -0
- package/dist/kotlin/KotlinConverter.d.ts +67 -0
- package/dist/kotlin/KotlinConverter.js +142 -0
- package/dist/kotlin/KotlinConverter.js.map +1 -0
- package/dist/kotlin/annotations.d.ts +26 -0
- package/dist/kotlin/annotations.js +35 -0
- package/dist/kotlin/annotations.js.map +1 -0
- package/dist/kotlin/enums.d.ts +15 -0
- package/dist/kotlin/enums.js +58 -0
- package/dist/kotlin/enums.js.map +1 -0
- package/dist/kotlin/index.d.ts +13 -0
- package/dist/kotlin/index.js +14 -0
- package/dist/kotlin/index.js.map +1 -0
- package/dist/kotlin/objectEmitter.d.ts +12 -0
- package/dist/kotlin/objectEmitter.js +74 -0
- package/dist/kotlin/objectEmitter.js.map +1 -0
- package/dist/kotlin/sealedUnion.d.ts +17 -0
- package/dist/kotlin/sealedUnion.js +74 -0
- package/dist/kotlin/sealedUnion.js.map +1 -0
- package/dist/kotlin/typeMapper.d.ts +17 -0
- package/dist/kotlin/typeMapper.js +107 -0
- package/dist/kotlin/typeMapper.js.map +1 -0
- package/dist/kotlin/unsupported.d.ts +13 -0
- package/dist/kotlin/unsupported.js +53 -0
- package/dist/kotlin/unsupported.js.map +1 -0
- package/dist/swift/SwiftBaseConverter.d.ts +18 -0
- package/dist/swift/SwiftBaseConverter.js +38 -0
- package/dist/swift/SwiftBaseConverter.js.map +1 -0
- package/dist/swift/SwiftConverter.d.ts +60 -0
- package/dist/swift/SwiftConverter.js +113 -0
- package/dist/swift/SwiftConverter.js.map +1 -0
- package/dist/swift/discriminatedEnum.d.ts +18 -0
- package/dist/swift/discriminatedEnum.js +99 -0
- package/dist/swift/discriminatedEnum.js.map +1 -0
- package/dist/swift/enums.d.ts +15 -0
- package/dist/swift/enums.js +62 -0
- package/dist/swift/enums.js.map +1 -0
- package/dist/swift/index.d.ts +13 -0
- package/dist/swift/index.js +14 -0
- package/dist/swift/index.js.map +1 -0
- package/dist/swift/structEmitter.d.ts +12 -0
- package/dist/swift/structEmitter.js +70 -0
- package/dist/swift/structEmitter.js.map +1 -0
- package/dist/swift/typeMapper.d.ts +18 -0
- package/dist/swift/typeMapper.js +106 -0
- package/dist/swift/typeMapper.js.map +1 -0
- package/dist/swift/unsupported.d.ts +19 -0
- package/dist/swift/unsupported.js +88 -0
- package/dist/swift/unsupported.js.map +1 -0
- package/dist/typescript/TypescriptBaseConverter.d.ts +25 -0
- package/dist/typescript/TypescriptBaseConverter.js +178 -0
- package/dist/typescript/TypescriptBaseConverter.js.map +1 -0
- package/dist/typescript/TypescriptConverter.d.ts +74 -0
- package/dist/typescript/TypescriptConverter.js +254 -0
- package/dist/typescript/TypescriptConverter.js.map +1 -0
- package/dist/typescript/index.d.ts +12 -0
- package/dist/typescript/index.js +13 -0
- package/dist/typescript/index.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +39 -6
- package/dist/JSONSchemaConverter.js.map +0 -1
- package/dist/JSONSchemaConverter.test.d.ts +0 -1
- package/dist/JSONSchemaConverter.test.js +0 -585
- package/dist/JSONSchemaConverter.test.js.map +0 -1
- package/dist/Typebox.test.d.ts +0 -1
- package/dist/Typebox.test.js +0 -88
- package/dist/Typebox.test.js.map +0 -1
- package/dist/TypescriptBaseConverter.d.ts +0 -75
- package/dist/TypescriptBaseConverter.js +0 -321
- package/dist/TypescriptBaseConverter.js.map +0 -1
- package/dist/TypescriptConverter.additionalProperties.test.d.ts +0 -1
- package/dist/TypescriptConverter.additionalProperties.test.js +0 -110
- package/dist/TypescriptConverter.additionalProperties.test.js.map +0 -1
- package/dist/TypescriptConverter.arrays.test.d.ts +0 -1
- package/dist/TypescriptConverter.arrays.test.js +0 -130
- package/dist/TypescriptConverter.arrays.test.js.map +0 -1
- package/dist/TypescriptConverter.composites.advanced.test.d.ts +0 -1
- package/dist/TypescriptConverter.composites.advanced.test.js +0 -1070
- package/dist/TypescriptConverter.composites.advanced.test.js.map +0 -1
- package/dist/TypescriptConverter.composites.test.d.ts +0 -1
- package/dist/TypescriptConverter.composites.test.js +0 -335
- package/dist/TypescriptConverter.composites.test.js.map +0 -1
- package/dist/TypescriptConverter.d.ts +0 -163
- package/dist/TypescriptConverter.js +0 -606
- package/dist/TypescriptConverter.js.map +0 -1
- package/dist/TypescriptConverter.jsdoc.test.d.ts +0 -1
- package/dist/TypescriptConverter.jsdoc.test.js +0 -194
- package/dist/TypescriptConverter.jsdoc.test.js.map +0 -1
- package/dist/TypescriptConverter.objects.test.d.ts +0 -1
- package/dist/TypescriptConverter.objects.test.js +0 -258
- package/dist/TypescriptConverter.objects.test.js.map +0 -1
- package/dist/TypescriptConverter.options.test.d.ts +0 -1
- package/dist/TypescriptConverter.options.test.js +0 -501
- package/dist/TypescriptConverter.options.test.js.map +0 -1
- package/dist/TypescriptConverter.primitives.test.d.ts +0 -1
- package/dist/TypescriptConverter.primitives.test.js +0 -26
- package/dist/TypescriptConverter.primitives.test.js.map +0 -1
- package/dist/utils/path-utils.test.d.ts +0 -1
- package/dist/utils/path-utils.test.js +0 -92
- 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":"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"}
|
|
@@ -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
|