Replies: 1 comment
|
Repurposed from a generic "macros" idea into a concrete design: |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Overview
@Endpoint— an attached macro that turns a lightweight, attribute-annotated struct into a fullProperty, generating thePropertyModifierboilerplate that would otherwise be hand-written for every endpoint.Usage —
FetchUseris a plainProperty, usable standalone with nothing before it:How the expansion works
@URL/@Headers/@Method/@Queriesare attribute syntax@Endpoint's own macro expansion reads off thecallAsFunctiondeclaration via SwiftSyntax — they don't need to be independently functioning macros themselves, only valid attribute syntax the compiler accepts.The macro generates two things, both built entirely from existing public API — no changes to
Property,PropertyModifier, or the graph engine are needed:A nested
Modifier: PropertyModifier, mirroring the modifier boilerplate already written by hand for every existingPropertyModifierconformance in the codebase:Propertyconformance onFetchUseritself, feedingModifieran empty base via the existingEmptyPropertyleaf (Properties/Sources/Extra Properties/Empty/EmptyProperty.swift) — this is the part that makesFetchUser(payload: model)usable standalone, with nothing composed before it:callAsFunction'scontentparameter is the macro-assembled scaffolding (FlexibleURL+HeaderGroup+RequestMethod+QueryGroup), and the author's owncallAsFunctionbody is the escape hatch for layering extra properties (likePayload(payload)) on top of it.Constraint that shaped this design
callAsFunctionmust be synchronous and non-throwing —Property.body: Body { get }andPropertyModifier.body(content:) -> Self.Bodyare both plain, non-async, non-throwsrequirements. The async/throwing part of this package's pipeline isPropertyNode.make(_ make: inout Make) async throws, which runs later, during resolution of already-built leaf nodes — not during graph composition. An endpoint needing genuine async/throwing work (e.g. an async token fetch) isn't expressible throughcallAsFunction; it would need its ownPropertyNodeleaf with a realmake(), not this macro.Infra cost
No macro target exists in
Package.swifttoday. This needs a new SwiftPM target depending onswift-syntax+SwiftCompilerPlugin, exposed from the mainRequestDLtarget via@attached(...) public macro Endpoint() = #externalMacro(...). Macro plugins are host-tool executables — needs verifying they build cleanly on the Linux CI runners this project already runs (swift-ci.yaml), not just assumed to work.Milestone: 4.5.0
All reactions