Skip to content

Research: evaluate user-written Swift as input to a codegen CLI (Tuist-style manifest execution) #154

Description

@leogdion

Background

Tuist lets users describe an Xcode project by writing a Project.swift manifest in plain Swift, then evaluates that manifest at CLI invocation time — without the user having to compile and run a full app themselves. SwiftPM does the same thing with Package.swift.

We should investigate whether SyntaxKit could expose an analogous flow: the user writes a Swift file that uses the SyntaxKit DSL, and a CLI compiles + executes it to emit generated Swift source. This would let people drive code generation declaratively from a checked-in .swift file without setting up an executable target per generator.

Goals of this research

  1. Understand exactly how Tuist (and, as a comparison point, SwiftPM) compiles and executes a user manifest.
  2. Identify which pieces of that pipeline are reusable for a SyntaxKit-driven codegen CLI.
  3. Surface the risks and open questions before we commit to a design.

Phase 1 — How Tuist does it

Source: tuist/tuist, primarily the ProjectDescription target and the manifest-loading subsystem.

Questions to answer (with file/line citations into the Tuist repo):

  • Compilation pipeline. What exact swiftc invocation compiles Project.swift? Flags, framework search paths, linker args, output type (dylib vs. executable)?
  • Execution model. Does Tuist (a) load a compiled dylib and call a known symbol, (b) run a compiled executable that dumps a description on stdout, or (c) something else? (SwiftPM uses (b) — confirm whether Tuist matches.)
  • Bridging format. What's the wire format between the manifest process and the host tool? ProjectDescription types are Codable — is JSON the boundary?
  • Helpers / shared code. How does ProjectDescriptionHelpers/ get compiled and made importable from the manifest?
  • Caching. Does Tuist hash the manifest + ProjectDescription version and skip recompilation? Where is the cache?
  • Failure modes. What happens when the manifest crashes, has a syntax error, or hangs?

Phase 2 — Map the pattern onto SyntaxKit

With Phase 1 in hand, sketch the equivalent for a SyntaxKit CLI:

  • Manifest shape. What does the user write? A top-level expression returning a Group of CodeBlocks? An @main struct?
  • What crosses the process boundary. SyntaxKit's output is generated Swift source, not a graph of Codable types. Two viable options:
    • Manifest executable prints generated Swift to stdout directly (simplest).
    • Manifest exports a Codable IR; host renders via SwiftSyntax (matches Tuist more closely, but duplicates rendering).
  • Linking SyntaxKit into the manifest. The manifest needs import SyntaxKit. Compare (a) shipping a precompiled SyntaxKit binary next to the CLI and passing -F/-I/-L, vs. (b) generating a throwaway SwiftPM package per run.
  • Helpers directory. Mirror Tuist's ProjectDescriptionHelpers so users can factor out reusable codegen.

Phase 3 — Open risks to probe early

  • SwiftSyntax link cost. SwiftSyntax is large; compiling a manifest that transitively links it could be slow. Measure on a hello-world manifest before committing.
  • macOS-only vs. Linux. Tuist is mac-focused. The SyntaxKit CLI should at least not paint itself into a macOS corner.
  • Toolchain resolution. How does Tuist locate swiftc (xcrun --find vs. explicit toolchain paths)?

Deliverables

  1. Phase 1 write-up: how Tuist's manifest pipeline works, with citations.
  2. Design sketch: compile command, execution model, IR boundary (or lack of one), helpers layout, caching strategy.
  3. Smallest possible proof-of-concept steps (enumerated, not yet implemented), e.g. "compile a manifest that imports SyntaxKit and prints a Hello.swift to stdout."

Out of scope (for this issue)

  • Implementation of the CLI itself — this issue is research only.
  • Choosing a CLI name or product surface.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    cliCommand-line interfaceenhancementNew feature or requestquestionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions