Skip to content

Zerk 2.1

Latest

Choose a tag to compare

@ofgokce ofgokce released this 10 Sep 13:03
9765848

Naming and name resolution. Every change here is a compiler error rather than a silent behaviour
change, so the build says where. See Changes in 2.1.

Removed

  • #ZerkImport(module:). The generated file now takes its imports from the files it reads:
    every module imported by a file that names a type from outside this one. Restating them by hand
    was the part that could be forgotten, and forgetting it was a build failure in generated code.
    Delete the declarations; nothing replaces them.

Renamed

  • @ZerkAlias and #ZerkAlias<A, B>() are now @InjectableAlias and
    #InjectableAlias<A, B>().
    Behaviour is unchanged. No macro carries Zerk in its name any
    more, so the whole set reads the same way.
  • The documented namespace for imported declarations is spelled ImportedInjectables rather than
    ZerkImports throughout the examples. It is a name you choose — Zerk never reads it — so
    nothing breaks either way.

Fixed

  • A key's name is now read in the scope it was written in. Swift looks a bare type name up
    innermost-first, and the generated file lives at file scope, so the two disagreed for anything
    nested: init(config: Config) inside LiveFeed emitted config: Config, which fails to
    compile as cannot find type 'Config' in scope. The name is now qualified —
    config: LiveFeed.Config — with only the base of a dotted path moving, since that is the part
    Swift looks up. Where the bare name also existed at file scope, Zerk had been matching the
    wrong key and running its effect and conditional-compilation checks against the wrong provider.
  • Two imported keys sharing a bare name stay two keys. ModuleA.Config and ModuleB.Config
    were merged and then reported as 'Config' is imported more than once, against two imports
    naming different types.
  • A local declaration shadows an imported name of the same spelling. A module declaring
    Serving and importing a Core.Serving was told the key was both imported and declared —
    for source Swift compiles as written, where the local declaration simply shadows the import.
  • A type named after a module is no longer read as a module qualifier. Declaring Core
    shadows the module everywhere in that module, so Core.Serving names that type's member;
    stripping the qualifier emitted an extension over a different type than the call site used.
  • A cancelled caller no longer builds a second kept instance. ZerkAsyncBox's non-throwing
    path let a cancelled caller build its own instance, which the box never publishes — correct on
    an empty box, wrong while a build is in flight, where it produced a private second instance of
    something kept while every other caller shared the first. A cancelled caller now builds its own
    only when there is nothing to join.
  • @Injected on a property of an @Observable type reported a global has no such moment,
    naming storage the developer never wrote. It now names the problem and the fix: mark the
    property @ObservationIgnored, which leaves it stored.
  • @Injected alongside a property wrapper produced only the compiler's
    init accessor cannot refer to property, which mentions neither the wrapper nor Zerk. It now
    names the wrapper and the spelling that works —
    @StateObject var model = Zerk<Key>.inject().

Added

  • swift package zerk settings — writes ZerkSettings.json from an Xcode target's build
    settings instead of from memory. The plugin API cannot read build settings, which is why the
    file exists at all; xcodebuild -showBuildSettings can, so this maps its answer onto the four
    keys that mirror one and leaves valueInjectionMethod, which mirrors nothing, alone. A setting
    the target does not set is left out, so Zerk's default applies. Needs Xcode. See
    zerk settings.

Changed

  • swift-tools-version is 6.2, up from 6.1. It was never the real floor: a Swift 6.2
    toolchain has always been required, because interjection points are named with raw identifiers
    (SE-0451) that land in the generated file your toolchain compiles. The manifest now says so, so
    an older SwiftPM refuses it up front instead of failing later inside generated code.
  • ZerkSettings.json is decoded rather than deserialized and cast. The type guards used to
    read a JSONSerialization Any, where a JSON boolean and a JSON number are indistinguishable
    in both directions — true as? Int is 1 and 1 as? Bool is true — so telling them apart
    needed CFGetTypeID(value as CFTypeRef) == CFBooleanGetTypeID(). JSONDecoder draws the
    distinction in the language instead, and the messages for a malformed key are unchanged.
  • That was also the one thing in Zerk only Darwin could answer, so the package now has no
    Apple-only dependency outside #if canImport guards. CI builds and tests it on Linux.

Documentation

  • New SwiftUI and @Observable page: @ObservationIgnored, property
    wrappers, and registering a view model.
  • New "Storage a property does not have" section in
    Diagnostics, covering all four cases where @Injected has no
    storage to initialize.
  • A "Changes in 2.1" section in Migration.
  • This file.

Full Changelog: 2.0.0...2.1.0