Why it is shaped this way
Marker macros carry the GraphQL
Status: accepted, 2026-10-02. Serves A fragment is a lens. Reopen when Swift offers a way to attach a literal to a property without a macro, or when the macro trust prompt proves prohibitive for adopters; .graphql files remain the macro-free path either way.
Status: accepted, 2026-10-02. Serves
A fragment is a lens. Reopen when
Swift offers a way to attach a literal to a property without a macro, or when
the macro trust prompt proves prohibitive for adopters; .graphql files
remain the macro-free path either way.
Context#
GraphQL belongs beside the view that reads it, as a full, valid document in
the Swift file, found by the compiler. Something has to attach the text to
the property that holds the lens. Candidates: a property wrapper with a
string argument, an attached macro, a separate graphql("…") declaration, a
doc comment, or .graphql files only.
Decision#
Attached macros: @Fragment("…"), @Query("…"), @Mutation("…"),
@Subscription("…"). @Fragment is a peer macro that expands to nothing,
so the property stays stored and the memberwise initializer takes the lens.
@Query is an accessor-plus-peer macro: the peer is the operation storage,
the accessors are an init accessor and a getter, so a parent passes the
variables and the body reads the resolved handle. The compiler finds the
text by the attribute, never by expanding the macro. .graphql files are
accepted alongside.
Evidence#
- A property wrapper cannot do it:
@Fragment("…") var user: Twithinit(wrappedValue:_:)fails with "missing argument for parameter 'wrappedValue'", because attribute arguments initialize the wrapper directly (spike, 2026-10-02). - The macro form builds and runs:
CharacterRow(character:)takes the lens;CharactersScreen(characters: CharactersScreenQuery(page: 1))takes the variables andcharacters.phasereads the handle. The declaration must listnames: named(init), named(get)or the compiler rejects the init accessor. - Prebuilt swift-syntax applies in SwiftPM and Xcode 26, so the macro package costs seconds, not minutes.
- Apple's own
@Statebecame an accessor-plus-peer macro in Xcode 27; the shape is the platform's.
Not chosen#
- A property wrapper: the compile error above.
- A separate
graphql("…")declaration: two constructs for one thing, and the property's type and its document drift apart. - GraphQL in doc comments: invisible to tooling and formatters.
.graphqlfiles only: no colocation.
Baton