primitive-admin 1.1.0-alpha.47 → 1.1.0-alpha.49
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/dist/bin/primitive.js +2 -0
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/apps.js +54 -2
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/databases.js +31 -10
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.js +77 -0
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/guides.d.ts +15 -12
- package/dist/src/commands/guides.js +22 -15
- package/dist/src/commands/guides.js.map +1 -1
- package/dist/src/commands/settings.d.ts +15 -0
- package/dist/src/commands/settings.js +102 -0
- package/dist/src/commands/settings.js.map +1 -0
- package/dist/src/commands/sync-app-settings.d.ts +105 -0
- package/dist/src/commands/sync-app-settings.js +339 -0
- package/dist/src/commands/sync-app-settings.js.map +1 -0
- package/dist/src/commands/sync.d.ts +34 -19
- package/dist/src/commands/sync.js +373 -200
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/workflows.js +32 -10
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +2 -0
- package/dist/src/lib/api-client.js +6 -0
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/app-settings-descriptor.d.ts +108 -0
- package/dist/src/lib/app-settings-descriptor.js +250 -0
- package/dist/src/lib/app-settings-descriptor.js.map +1 -0
- package/dist/src/lib/codegen-shared/generatedFiles.d.ts +15 -0
- package/dist/src/lib/codegen-shared/generatedFiles.js +27 -10
- package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
- package/dist/src/lib/db-codegen/dbGenerator.d.ts +11 -83
- package/dist/src/lib/db-codegen/dbGenerator.js +93 -556
- package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/db-codegen/dbNaming.d.ts +15 -7
- package/dist/src/lib/db-codegen/dbNaming.js +25 -13
- package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTemplates.d.ts +55 -4
- package/dist/src/lib/db-codegen/dbTemplates.js +169 -40
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +101 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +200 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbGenerator.d.ts +68 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js +380 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
- package/dist/src/lib/swift-codegen/generator.d.ts +84 -0
- package/dist/src/lib/swift-codegen/generator.js +178 -0
- package/dist/src/lib/swift-codegen/generator.js.map +1 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
- package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
- package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
- package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
- package/dist/src/lib/sync-resource-types.d.ts +225 -0
- package/dist/src/lib/sync-resource-types.js +394 -0
- package/dist/src/lib/sync-resource-types.js.map +1 -0
- package/dist/src/lib/template.d.ts +1 -1
- package/dist/src/lib/template.js +6 -3
- package/dist/src/lib/template.js.map +1 -1
- package/dist/src/lib/workflow-codegen/generator.d.ts +18 -5
- package/dist/src/lib/workflow-codegen/generator.js +116 -41
- package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
- package/dist/src/lib/workflow-codegen/invokerIR.d.ts +85 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js +71 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `workflows codegen --lang swift` orchestrator (issue #1547, Phases 2-3).
|
|
3
|
+
*
|
|
4
|
+
* The Swift counterpart of `workflow-codegen/generator.ts`. Reads the SAME
|
|
5
|
+
* synced workflow TOMLs (`.primitive/sync/<env>/<appId>/workflows/*.toml`) and
|
|
6
|
+
* emits ONE `<key>.generated.swift` per workflow. Each file carries the
|
|
7
|
+
* workflow's `<Key>Input`/`<Key>Output` Swift `Codable` types (Phase 1's
|
|
8
|
+
* `renderSwiftRootType`) plus — Phase 3 — a typed invoker factory: a free
|
|
9
|
+
* function `func <key>(_ client:) -> <Key>Workflow` returning a struct with
|
|
10
|
+
* `async throws` `runSync`/`start`/`getStatus` methods (Fork 2 = A). The
|
|
11
|
+
* factory binds `<Key>Input`/`<Key>Output` over the additive generic overloads
|
|
12
|
+
* on `WorkflowsAPI` (the only published SDK surface).
|
|
13
|
+
*
|
|
14
|
+
* Design decisions realized (maintainer decision, issue #1547):
|
|
15
|
+
* - Schemas are interpreted through the SAME drift-guarded descriptor the TS
|
|
16
|
+
* emitter reads (Fork 1 = A), via `renderSwiftRootType`, so a generated
|
|
17
|
+
* Swift type can never promise a shape the runtime validator rejects.
|
|
18
|
+
* - Operation metadata (key, `syncCallable`, required-vs-optional `input`) is
|
|
19
|
+
* read from the SHARED `describeWorkflowInvoker` IR — the SAME source the TS
|
|
20
|
+
* invoker uses. The Swift renderer reconstructs none of it (#1547 binding 5),
|
|
21
|
+
* so the two clients can never disagree on which operations a workflow
|
|
22
|
+
* exposes or whether its input is required.
|
|
23
|
+
* - `runSync` is emitted ONLY for `syncCallable: true` workflows (the server
|
|
24
|
+
* rejects run-sync otherwise), matching the TS factory. `start` + `getStatus`
|
|
25
|
+
* are emitted for every non-reserved workflow.
|
|
26
|
+
* - Disk lifecycle (write / `--check` / orphan cleanup) delegates to the shared
|
|
27
|
+
* `writeOrCheckGeneratedFiles`, scoped by an ownership BANNER (the "banner
|
|
28
|
+
* namespacing" edge case) so a shared Swift output dir stays safe.
|
|
29
|
+
*/
|
|
30
|
+
import * as path from "path";
|
|
31
|
+
import { writeOrCheckGeneratedFiles, } from "../codegen-shared/generatedFiles.js";
|
|
32
|
+
import { fingerprintToml } from "../db-codegen/dbFingerprint.js";
|
|
33
|
+
import { describeWorkflowInvoker } from "../workflow-codegen/invokerIR.js";
|
|
34
|
+
import { renderSwiftRootType } from "./schemaToSwift.js";
|
|
35
|
+
import { structTypeName, workflowSwiftFactoryName } from "./swiftNaming.js";
|
|
36
|
+
/** Suffix identifying a generated Swift file. */
|
|
37
|
+
export const GENERATED_SWIFT_FILE_SUFFIX = ".generated.swift";
|
|
38
|
+
/**
|
|
39
|
+
* Banner prefix stamped at the top of every CLI-emitted `.generated.swift`
|
|
40
|
+
* file. Deliberately DISTINCT from the Swift model codegen's
|
|
41
|
+
* `// Generated by swift-bao-codegen` header so that:
|
|
42
|
+
* - the model codegen's stale-sweep (which only removes files starting with
|
|
43
|
+
* its own header) never deletes these; and
|
|
44
|
+
* - this generator's cleanup (scoped to this prefix) never deletes a
|
|
45
|
+
* model-codegen file that shares the `.generated.swift` suffix.
|
|
46
|
+
* The prefix is common to every workflow file, so it is a safe ownership key.
|
|
47
|
+
*/
|
|
48
|
+
export const SWIFT_BANNER_PREFIX = "// AUTO-GENERATED FROM workflows/";
|
|
49
|
+
/** The Swift module the generated types + invoker import (`JSONValue`,
|
|
50
|
+
* `JsBaoClient`, the `WorkflowsAPI` generics, and the typed result structs all
|
|
51
|
+
* live there). */
|
|
52
|
+
const CLIENT_MODULE = "JsBaoClient";
|
|
53
|
+
const INDENT = " ";
|
|
54
|
+
/** PascalCase, sanitized, non-keyword base type name for a workflow key.
|
|
55
|
+
* `create-checkout-session` → `CreateCheckoutSession`; `123-job` → `_123Job`
|
|
56
|
+
* (digit-leading prefixed, parity with the TS `ensureValidIdentifierStart`). */
|
|
57
|
+
export function workflowSwiftTypeBaseName(key) {
|
|
58
|
+
return structTypeName(key);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Parse a single workflow TOML into the data the Swift emitter needs. The
|
|
62
|
+
* operation metadata comes from the SHARED `describeWorkflowInvoker` IR (the
|
|
63
|
+
* SAME source the TS invoker uses); only the Swift-specific naming +
|
|
64
|
+
* type-declaration rendering happens here. Throws on malformed schema JSON
|
|
65
|
+
* (fail-and-exit). Returns null for a reserved workflow.
|
|
66
|
+
*/
|
|
67
|
+
function parseWorkflow(input) {
|
|
68
|
+
const ir = describeWorkflowInvoker({
|
|
69
|
+
fileStem: input.fileStem,
|
|
70
|
+
tomlContent: input.tomlContent,
|
|
71
|
+
});
|
|
72
|
+
if (!ir)
|
|
73
|
+
return null; // reserved workflow
|
|
74
|
+
const base = workflowSwiftTypeBaseName(ir.key);
|
|
75
|
+
const inputTypeName = `${base}Input`;
|
|
76
|
+
const outputTypeName = `${base}Output`;
|
|
77
|
+
const sourceFile = `workflows/${ir.key}.toml`;
|
|
78
|
+
return {
|
|
79
|
+
key: ir.key,
|
|
80
|
+
base,
|
|
81
|
+
inputTypeName,
|
|
82
|
+
outputTypeName,
|
|
83
|
+
syncCallable: ir.syncCallable,
|
|
84
|
+
inputRequired: ir.inputRequired,
|
|
85
|
+
inputDecl: renderSwiftRootType(inputTypeName, ir.inputSchema, { sourceFile }),
|
|
86
|
+
outputDecl: renderSwiftRootType(outputTypeName, ir.outputSchema, {
|
|
87
|
+
sourceFile,
|
|
88
|
+
}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** A Swift string literal for the workflow key (runtime call passes it verbatim). */
|
|
92
|
+
function swiftKeyLiteral(key) {
|
|
93
|
+
const escaped = key
|
|
94
|
+
.replace(/\\/g, "\\\\")
|
|
95
|
+
.replace(/"/g, '\\"')
|
|
96
|
+
.replace(/\n/g, "\\n")
|
|
97
|
+
.replace(/\r/g, "\\r")
|
|
98
|
+
.replace(/\t/g, "\\t");
|
|
99
|
+
return `"${escaped}"`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Render the typed Swift invoker for one workflow (Fork 2 = A): a free function
|
|
103
|
+
* returning a small struct with `async throws` methods, mirroring the JS
|
|
104
|
+
* factory. `runSync` is emitted only when the shared IR says `syncCallable`;
|
|
105
|
+
* `start` + `getStatus` always. The `input` argument is required or optional
|
|
106
|
+
* per the shared IR's `inputRequired` (the SAME decision the TS factory makes).
|
|
107
|
+
*
|
|
108
|
+
* Each method delegates to the additive generic overloads on `WorkflowsAPI`
|
|
109
|
+
* (`runSync<Input,Output>` / `start<Input>` / `getStatus<Output>`), binding
|
|
110
|
+
* `<Key>Input`/`<Key>Output`. Those overloads are the only published SDK
|
|
111
|
+
* surface; this generated struct is app-target code.
|
|
112
|
+
*/
|
|
113
|
+
function renderInvoker(wf) {
|
|
114
|
+
const structName = `${wf.base}Workflow`;
|
|
115
|
+
const factoryName = workflowSwiftFactoryName(wf.key);
|
|
116
|
+
const keyLiteral = swiftKeyLiteral(wf.key);
|
|
117
|
+
// Required `input` → `input: <Key>Input`; optional → `input: <Key>Input? = nil`.
|
|
118
|
+
// The generic overloads take `Input?`, so a required value auto-promotes and
|
|
119
|
+
// an omitted optional sends the server `{}` (parity with the JS `input ?? {}`).
|
|
120
|
+
const inputParam = wf.inputRequired
|
|
121
|
+
? `input: ${wf.inputTypeName}`
|
|
122
|
+
: `input: ${wf.inputTypeName}? = nil`;
|
|
123
|
+
const lines = [];
|
|
124
|
+
lines.push(`/// Typed invoker for the \`${wf.key}\` workflow. Bind its \`${wf.inputTypeName}\` /`, `/// \`${wf.outputTypeName}\` over the generic \`WorkflowsAPI\` overloads. Obtain one`, `/// with \`${factoryName}(client)\`.`, `public struct ${structName}: Sendable {`, `${INDENT}public let client: JsBaoClient`, ``, `${INDENT}public init(client: JsBaoClient) {`, `${INDENT}${INDENT}self.client = client`, `${INDENT}}`);
|
|
125
|
+
if (wf.syncCallable) {
|
|
126
|
+
lines.push(``, `${INDENT}/// Run the workflow synchronously and wait for its terminal status.`, `${INDENT}/// Emitted only because \`${wf.key}\` is \`syncCallable\` (parity with JS).`, `${INDENT}public func runSync(`, `${INDENT}${INDENT}${inputParam},`, `${INDENT}${INDENT}runKey: String? = nil,`, `${INDENT}${INDENT}contextDocId: String? = nil,`, `${INDENT}${INDENT}meta: [String: Any]? = nil,`, `${INDENT}${INDENT}timeoutMs: Int? = nil`, `${INDENT}) async throws -> RunSyncResult<${wf.outputTypeName}> {`, `${INDENT}${INDENT}try await client.workflows.runSync(`, `${INDENT}${INDENT}${INDENT}workflowKey: ${keyLiteral},`, `${INDENT}${INDENT}${INDENT}input: input,`, `${INDENT}${INDENT}${INDENT}runKey: runKey,`, `${INDENT}${INDENT}${INDENT}contextDocId: contextDocId,`, `${INDENT}${INDENT}${INDENT}meta: meta,`, `${INDENT}${INDENT}${INDENT}timeoutMs: timeoutMs`, `${INDENT}${INDENT})`, `${INDENT}}`);
|
|
127
|
+
}
|
|
128
|
+
lines.push(``, `${INDENT}/// Start the workflow asynchronously; returns the run handle.`, `${INDENT}@discardableResult`, `${INDENT}public func start(`, `${INDENT}${INDENT}${inputParam},`, `${INDENT}${INDENT}runKey: String? = nil,`, `${INDENT}${INDENT}contextDocId: String? = nil,`, `${INDENT}${INDENT}meta: [String: Any]? = nil,`, `${INDENT}${INDENT}forceRerun: Bool? = nil`, `${INDENT}) async throws -> StartWorkflowResult {`, `${INDENT}${INDENT}try await client.workflows.start(`, `${INDENT}${INDENT}${INDENT}workflowKey: ${keyLiteral},`, `${INDENT}${INDENT}${INDENT}input: input,`, `${INDENT}${INDENT}${INDENT}runKey: runKey,`, `${INDENT}${INDENT}${INDENT}contextDocId: contextDocId,`, `${INDENT}${INDENT}${INDENT}meta: meta,`, `${INDENT}${INDENT}${INDENT}forceRerun: forceRerun`, `${INDENT}${INDENT})`, `${INDENT}}`);
|
|
129
|
+
lines.push(``, `${INDENT}/// Fetch a run's status with a typed \`output\` bound to \`${wf.outputTypeName}\`.`, `${INDENT}public func getStatus(`, `${INDENT}${INDENT}runKey: String,`, `${INDENT}${INDENT}contextDocId: String? = nil`, `${INDENT}) async throws -> WorkflowStatus<${wf.outputTypeName}> {`, `${INDENT}${INDENT}try await client.workflows.getStatus(`, `${INDENT}${INDENT}${INDENT}workflowKey: ${keyLiteral},`, `${INDENT}${INDENT}${INDENT}runKey: runKey,`, `${INDENT}${INDENT}${INDENT}contextDocId: contextDocId`, `${INDENT}${INDENT})`, `${INDENT}}`);
|
|
130
|
+
lines.push(`}`);
|
|
131
|
+
// The free-function factory (Fork 2 = A call shape: `<key>(client).runSync(...)`).
|
|
132
|
+
lines.push(``, `/// Typed invoker factory for the \`${wf.key}\` workflow.`, `public func ${factoryName}(_ client: JsBaoClient) -> ${structName} {`, `${INDENT}${structName}(client: client)`, `}`);
|
|
133
|
+
return lines.join("\n");
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Render the full `<key>.generated.swift` content for a single workflow TOML.
|
|
137
|
+
* Returns null for a reserved (`__internal.*`) workflow. Pure — exported so
|
|
138
|
+
* tests can assert on the string directly.
|
|
139
|
+
*/
|
|
140
|
+
export function renderWorkflowSwiftFile(input) {
|
|
141
|
+
const wf = parseWorkflow(input);
|
|
142
|
+
if (!wf)
|
|
143
|
+
return null;
|
|
144
|
+
const fingerprint = fingerprintToml(input.tomlContent);
|
|
145
|
+
const banner = [
|
|
146
|
+
`// AUTO-GENERATED FROM workflows/${wf.key}.toml — DO NOT EDIT.`,
|
|
147
|
+
"// Run `primitive workflows codegen --lang swift` to regenerate.",
|
|
148
|
+
`// fingerprint: ${fingerprint}`,
|
|
149
|
+
].join("\n");
|
|
150
|
+
const imports = ["import Foundation", `import ${CLIENT_MODULE}`].join("\n");
|
|
151
|
+
const content = [banner, imports, wf.inputDecl, wf.outputDecl, renderInvoker(wf)].join("\n\n") + "\n";
|
|
152
|
+
return { key: wf.key, content };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Run Swift workflow codegen end-to-end. One `<key>.generated.swift` per
|
|
156
|
+
* workflow; delegates the disk lifecycle to the shared writer/checker with
|
|
157
|
+
* banner-scoped ownership so a shared Swift output dir stays safe.
|
|
158
|
+
*/
|
|
159
|
+
export async function generateWorkflowSwiftTypes(options) {
|
|
160
|
+
const outAbs = path.resolve(options.outputDir);
|
|
161
|
+
const filesToWrite = new Map();
|
|
162
|
+
for (const input of options.inputs) {
|
|
163
|
+
const rendered = renderWorkflowSwiftFile(input);
|
|
164
|
+
if (!rendered)
|
|
165
|
+
continue; // reserved workflow — no file
|
|
166
|
+
const filePath = path.join(outAbs, `${rendered.key}${GENERATED_SWIFT_FILE_SUFFIX}`);
|
|
167
|
+
filesToWrite.set(filePath, rendered.content);
|
|
168
|
+
}
|
|
169
|
+
return await writeOrCheckGeneratedFiles({
|
|
170
|
+
outputDir: outAbs,
|
|
171
|
+
filesToWrite,
|
|
172
|
+
check: options.check,
|
|
173
|
+
fullOwnership: options.singleWorkflow !== true,
|
|
174
|
+
generatedSuffix: GENERATED_SWIFT_FILE_SUFFIX,
|
|
175
|
+
ownershipBanner: SWIFT_BANNER_PREFIX,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../src/lib/swift-codegen/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-Schema → Swift `Codable` converter for `swift-codegen` (issue #1547,
|
|
3
|
+
* Phase 1). The Swift counterpart of `workflow-codegen/schemaToTs.ts`.
|
|
4
|
+
*
|
|
5
|
+
* Both emitters read the SAME drift-guarded interpretation of the JSON-Schema
|
|
6
|
+
* subset the workflow platform supports — the vendored `SchemaDescriptor`
|
|
7
|
+
* (`workflow-codegen/generated-schema-descriptor.ts`, a byte copy of the server
|
|
8
|
+
* validator). Only the emitted syntax differs, so a generated Swift type can
|
|
9
|
+
* never promise a shape the runtime validator rejects. See the design and
|
|
10
|
+
* maintainer decision on issue #1547.
|
|
11
|
+
*
|
|
12
|
+
* Where Swift diverges from TypeScript:
|
|
13
|
+
*
|
|
14
|
+
* - **Named types, not anonymous.** TS renders nested object/enum/`oneOf`
|
|
15
|
+
* types inline; Swift `Codable` needs a NAMED `struct`/`enum` for each, so
|
|
16
|
+
* this emitter declares nested types inside their enclosing type.
|
|
17
|
+
* - **Scalars** (Fork 4, maintainer-confirmed): `string`→`String`,
|
|
18
|
+
* `number`→`Double`, `integer`→`Int` (ergonomic divergence from TS
|
|
19
|
+
* `number`), `boolean`→`Bool`.
|
|
20
|
+
* - **Un-descended nodes** (`$ref`, `allOf`, `format`, tuple `items`,
|
|
21
|
+
* `patternProperties`, numeric constraints, multi-scalar non-null unions,
|
|
22
|
+
* mixed-type enums, open-object extra values) → `JSONValue`, the Swift
|
|
23
|
+
* analog of TS `unknown`.
|
|
24
|
+
* - **`never`** (an uninhabitable enum after the type gate) → a strict codegen
|
|
25
|
+
* error, since the field can never be constructed (Fork 4).
|
|
26
|
+
* - **Scalar `enum`, all strings** → a nested `enum … : String, Codable,
|
|
27
|
+
* CaseIterable, Sendable`, the same form the Swift model codegen emits.
|
|
28
|
+
* - **`oneOf` discriminated union** → an `enum` with associated values plus a
|
|
29
|
+
* generated `init(from:)`/`encode(to:)` keyed on the discriminator.
|
|
30
|
+
*
|
|
31
|
+
* Codable semantics adopted from the maintainer decision (binding item 4):
|
|
32
|
+
*
|
|
33
|
+
* - Every generated `struct` gets a generated **public memberwise
|
|
34
|
+
* initializer** (Swift's synthesized memberwise init is not `public` across
|
|
35
|
+
* module boundaries).
|
|
36
|
+
* - A **required-nullable** property (required, but its value may be `null`)
|
|
37
|
+
* is encoded with an EXPLICIT null (not omitted) so server-side
|
|
38
|
+
* required-key validation still sees the key; decode is lenient (a missing
|
|
39
|
+
* key decodes to `nil`).
|
|
40
|
+
* - An **open object** stores unknown keys in an `extra: [String: JSONValue]`
|
|
41
|
+
* catch-all via custom Codable that separates known keys from extras; a key
|
|
42
|
+
* that collides with a known property is owned by the known property (the
|
|
43
|
+
* extra copy is dropped on encode, and never captured on decode).
|
|
44
|
+
* - A `oneOf` branch `struct` CARRIES the discriminator as a single-case
|
|
45
|
+
* `String` enum property, so decoding a branch rejects a conflicting
|
|
46
|
+
* discriminator value, and encoding re-emits the tag from the branch.
|
|
47
|
+
*
|
|
48
|
+
* Errors are named (`SwiftCodegenError`) and carry the source file and schema
|
|
49
|
+
* path for diagnostics (binding item 6).
|
|
50
|
+
*/
|
|
51
|
+
import { schemaRejectsEmptyObject } from "../workflow-codegen/schemaToTs.js";
|
|
52
|
+
/** Re-exported so the invoker phases share ONE required-vs-optional decision. */
|
|
53
|
+
export { schemaRejectsEmptyObject };
|
|
54
|
+
/** A named codegen error carrying the source file + schema path (binding 6). */
|
|
55
|
+
export declare class SwiftCodegenError extends Error {
|
|
56
|
+
readonly sourceFile?: string;
|
|
57
|
+
readonly schemaPath?: string;
|
|
58
|
+
constructor(message: string, opts?: {
|
|
59
|
+
sourceFile?: string;
|
|
60
|
+
schemaPath?: string;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export interface SwiftCodegenContext {
|
|
64
|
+
/** The `.toml`/schema file this type was generated from, for diagnostics. */
|
|
65
|
+
sourceFile?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Render a full Swift type declaration for a ROOT schema (e.g. a workflow's
|
|
69
|
+
* `<Key>Input`/`<Key>Output`), including every nested type it needs. Returns the
|
|
70
|
+
* Swift source for the type only — the CLI adds the import/banner (Phase 2).
|
|
71
|
+
*/
|
|
72
|
+
export declare function renderSwiftRootType(rootTypeName: string, schema: any, ctx?: SwiftCodegenContext): string;
|