Repository navigation
feat(tx3c): generate the first-party Swift client with --template swift-client - #365
Conversation
…ft-client
`tx3c codegen --template swift-client` renders a standalone SwiftPM package
(`Package.swift`, `Sources/<ProtocolName>Client/{Client,Types}.swift`,
`README.md`) whose typed client wraps the SDK's `Tx3Client`: embedded TIR
envelopes and profiles seed `Tx3ClientBuilder.fromParts`, a nested `Profile`
enum locks the profile in at construction, parties bind through typed
`with<Party>` setters, and every transaction method constructs the SDK's
canonical `ArgValue` values statically and hands them to `argTagged`. The
package carries no TII, schema, `ParamType` or dynamic loader.
The template lays its sources out with templated output paths. Static
argument construction is a planner and backend concern: the planner now
records an `Encoding` next to every member's type (resolving component
aliases to their targets), the Swift backend spells each record, tuple and
variant's `argValue` property from it, and the new `argValue` helper spells a
transaction parameter's expression from the same plan as its params
declaration, so templates never branch on schema shapes. `profile` spells the
SDK `Profile` value for one profile and `usesModule` lets `Package.swift`
depend on BigInt only when integers appear.
CI compiles the transfer and complex fixtures against tx3-lang/swift-sdk at
02fa0f2cc70d38f2623141035b3eb18509854b9a (no 0.15.0 tag exists yet): the
check clones that commit, tags it 0.15.0 locally and points a SwiftPM mirror
at the clone, so the generated Package.swift is built exactly as rendered.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`resolve_components` only detected an alias that aliased itself directly; an alias reached again through a list or map item recursed with a fresh visited set and overflowed the stack for any template. The visited path now follows the member down through containers, and an alias declaration starts with its own name on the path, so the value passes through as the comment already promised. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
QA (code-qa) review at head One correcting commit pushed, Everything else verified as delivered: |
|
Merge observed. Plan: Trellis will verify the human merge evidence, adopt the domain pin, and retire the plan. No further merge action is needed. |
Reconciles the java-client template with the swift-client template that landed in #365. Both added static argument construction to the codegen core in different shapes; the merge keeps main's `Encoding` model and `argValue`/`member` backend surface and ports the Java backend onto it: - `Backend::argument` spells from a member's `Encoding`; the shape-based `argument`/`accessor` pair and `Member::argument` are gone. Java overrides `member` for record accessors and keeps `sanitize` and `string_literal`. - `Backend::declares_aliases` (Java: true) tells component resolution that an alias is a wrapper record converting itself, so a reference to an alias component spells `.toArgValue()` instead of the target's encoding. - The Java template calls main's `argValue <tii> <tx> <param> <lang> <expr>`. - Both templates are registered, listed in the CLI help and error, and in the CI codegen matrix and compile-check script. Rendered java-client and swift-client output is byte-identical to the committed goldens. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Implements
plans/lang-codegen-swift-client.md(decisions 0015 and 0016): the first-party Swift client ships inside tx3c as the built-in templateswift-client.What it renders
tx3c codegen --template swift-clientemits a standalone SwiftPM package:Package.swift,README.md, andSources/<ProtocolName>Client/{Client,Types}.swift, where the package, product, module and facade are all<ProtocolName>Client.Types.swift: the merged Swift backend's declarations (Sendable structs, enums with associated values, keyword escaping, deterministic collision errors). Every record, tuple and variant now spells its ownargValue: ArgValueproperty, mirroring the SDK's encoder (records as constructor 0 in declared order, variants by case index, tuples positional, maps as key-sorted pairs).Client.swift:PROTOCOL_NAME/PROTOCOL_VERSION/TARGET_TII_VERSION, one public<TX>_TIRenvelope per transaction, one private<PROFILE>_PROFILESDKProfilevalue per profile, a nestedProfileenum when profiles exist (init(options:profile:), otherwiseinit(options:)), typedwith<Party>setters routed throughwithPartyUnchecked, and one typed transaction method pertxthat constructsArgValuevalues statically and callsargTagged. No TII, schema,ParamTypeor dynamic loader is embedded.Package.swift: depends onTx3SDKfromtx3-lang/swift-sdkfrom: "0.15.0", plusattaswift/BigIntfrom: "5.7.0"(the SDK's pinned version) only when integers appear. Every generated file states thev1beta0target and the sourcetii.version.Codegen changes
Sources/{{identifier tii.protocol.name 'swift' 'type'}}Client/. The path uses single-quoted Handlebars literals because the release workflow checks the repository out on Windows, where"cannot appear in a file name.Encodingnext to every member's type and resolves component aliases to their targets once all components are planned. The Swift backend spells conversions from it; templates never branch on schema shapes.argValue <tii> <transaction> <param> <language> <params-expr>(spelled from the same plan as the params declaration, so it always matches the declared field types),profile <profile> <language>(the SDKProfilevalue), andusesModule <tii> <language> <module>.expected/swift-client/. The existingcustom/swift,custom/compat-swiftandcustom/templated-pathsgoldens gain theargValueproperties (additive only).CI compile check
codegen compile (swift-client)runs onmacos-15with Xcode 16.4, the swift-sdk repository's own baseline. No swift-sdk0.15.0tag exists yet, so the script clonestx3-lang/swift-sdkat02fa0f2cc70d38f2623141035b3eb18509854b9a, tags that commit0.15.0locally and points a SwiftPM mirror at the clone; the generatedPackage.swiftis then built exactly as rendered.swift package edit --pathwas tried first but SwiftPM resolves before editing and fails on the missing tag. Once the tag exists, the block in.github/scripts/codegen-compile-check.shis deleted and the check resolves the published release directly (tracked in the Swift initiative plan).Verification
cargo fmt --all -- --check,cargo clippy --workspace --all-targets --all-features --locked -- -D warnings,cargo test -p tx3c --locked: pass..github/scripts/codegen-compile-check.sh swift-client: transfer and complex render andswift buildagainst the pinned SDK commit (Swift 6.2.3 locally)..tiifile constructsUnknownClientfor every profile, binds all three parties, and gets aTxBuilderfromtransfer(_:); it constructsComplexTypesClient(options:profile: .local)and assertsComplexParams(...).argValue == ArgEncoder.encode(sameNativeValue, as: ParamType.fromJSONSchema(...)), including a unit variant case. The edge fixture (no parties, no profiles) pins the no-profile constructor in the golden corpus.8d5d715f…da31, complex0a7195b2…ae83.🤖 Generated with Claude Code