Swift Biome: Versioned documentation, documenting extensions on external types, and dependency-graph aware API references

hi all! it’s been quite a while since the last swift-biome update, so here’s an overview of some major changes to the Biome documentation compiler that just landed in master.

over the past two months, swift-biome has undergone a near total rewrite which has given it quite a few new capabilities related to documentation versioning, cross-package extensions, and dependency graph evolution over time.

(keep in mind that these are very new features, and the CSS/visual design has not kept up with the tool’s capabilities, so the aesthetics are kind of un-polished.)

1. versioned documentation

from discussions on these forums, and the Swift Documentation Tooling Working Group, documentation versioning is a oft-requested feature, and we’re excited to announce that Swift Biome now has full support for versioning!

versioning is symbol-wise, so only version tags that a symbol actually exists in will appear in the version selection menu. in contrast to package-wide versioning, symbol-wise versioning enables API diffing, which we plan on surfacing in the web interface in the near future.

versioning-0

members/topics lists are also versioned:

versioning-1

2. version browsing and permalinks

swift-biome is fully aware of semantic versions, and can redirect versioned URLs accordingly. this means that you can link to “living API” at whatever level of precision you like!

for example, an unversioned URI prefix like swift-foo/ will always point to the most recent version of the requested documentation. a URI prefix with a major and minor version only (swift-foo/0.1) will redirect to the most recent version of the documentation up to the next minor version. et cetera, et cetera.

versioning-2

swift-biome encourages you to use living links instead of permalinks, so if you specify the most recent version explicitly, the engine will shorten the URL for you with a 308 redirect. however, if you really want to link to an exact version of a symbol, you can still specify the versions explicitly.

3. tags for documentation-only changes

as this was a requested feature from the last meeting of the SDTWG, swift-biome now supports tags for documentation-only changes. this is implemented as a fourth component of a semantic version tuple, e.g. 0.2.0.1.

in the demo GIF below, there was a broken symbol link in version 0.2.0 of swift-bar, which is fixed in version 0.2.0.1:

versioning-3

the fourth component is a semantic component, just like the first three, so all the permalinking/living linking features described in the previous section work for it as well. :)

4. support for non-standard versioning schemes

swift-biome is designed with the philosophy that the tooling should adapt to the ecosystem, not the other way around. because many swift packages use toolchain versioning (e.g. swift-DEVELOPMENT-SNAPSHOT-2022-03-13-a) instead of semantic versioning, swift-biome supports this schema as well:

versioning-4

5. documenting extensions on external types

swift-biome has supported cross-package extensions for a while, but now it has proper package graph awareness, and can group, version, and blame extensions accordingly:

(forgive the rough CSS, this is still a very new feature)

6. dependency-graph aware API documentation

when cross-package extensions compose with package versioning, a lot of subtleties can come up. fortunately, swift-biome can handle even the most pathologically-designed stacks out there!

the best way to demonstrate this capability is with an example:

  1. suppose there is a package swift-qux (version 0.1.1), which exposes a type Qux, that conforms to a protocol called Barable, in swift-bar (version 0.1.0).
// qux.swift @ 0.1.1
import Bar 

/// @import(Bar)
/// This type conforms to version `0.1.0` of ``Barable``
public
enum Qux:Barable 
{
}

  1. in version 0.2.0 of swift-qux, we bump the swift-bar dependency to version 0.2.0 as well. in swift-bar 0.2.0, Barable gains a protocol extension member bar(), which means Qux now inherits it as well:
// Package.swift 
dependencies: 
[
    .package(url: "https://github.com/swift-biome/swift-foo", exact: "0.3.0"),
    .package(url: "https://github.com/swift-biome/swift-bar", exact: "0.2.0"),
],
// qux.swift @ 0.2.0
import Bar 

/// @import(Bar)
/// In version `0.2.0` of ``/swift-qux``, the dependency on ``/swift-bar`` was 
/// upgraded to version `0.2.0` of ``/swift-bar`` as well. This means ``Qux``
/// now gains the ``Barable.bar()`` method.
public
enum Qux:Barable 
{
}

versioning-7

  1. swift-biome can also detect third-party API. in swift-qux 0.3.0, the file containing the conformance Qux:Barable was updated to import the module Baz from swift-baz. Baz extends Barable with its own third-party API, which Qux now inherits as well:
// Package.swift 
dependencies: 
[
    .package(url: "https://github.com/swift-biome/swift-foo", exact: "0.3.0"),
    .package(url: "https://github.com/swift-biome/swift-bar", exact: "0.2.0"),
    .package(url: "https://github.com/swift-biome/swift-baz", exact: "0.2.0"),
],
// qux.swift @ 0.3.0
import Bar 
import Baz

/// @import(Bar)
/// @import(Baz)
/// In version `0.2.0` of ``/swift-qux``, the dependency on ``/swift-bar`` was 
/// upgraded to version `0.2.0` of ``/swift-bar`` as well. This means ``Qux/Qux``
/// now gains the ``Barable.bar()`` method.
/// 
/// In version `0.3.0` of ``/swift-qux``, `qux.swift` now [`import`]()s ``Baz``.
/// This means ``Qux/Qux`` now gains the ``Barable.baz()`` method as well.
public
enum Qux:Barable 
{
}

versioning-8

  1. finally, swift-biome can detect “fourth-party” API, which is API that appears when a package extends an external type to conform to an external protocol, which trafficks API that could potentially originate from a external package.

    in the screenshot below, the Foo.Permanent type gains the Barable.bar() method from swift-bar, and the Barable.baz() method from swift-baz, and the new APIs are attributed to swift-qux, since the Qux module was responsible for the conformance.

// qux+foo+barable.swift 

import Foo
import Bar 

extension Foo.Permanent:Barable  
{
}

note that because Baz is a target-level dependency of Qux in swift-qux 0.3.0, the Baz APIs are also visible even though Baz was not explicitly imported. (this is the behavior of SymbolGraphGen.)

7. what’s next?

in the next week or so, we plan on rolling out the update to the swiftinit.org website, where you will be able to use these new features on real ecosystem packages (SwiftNIO, Swift Markdown, etc.)

in the meantime, you can view the example packages from this post in the swift-biome GitHub organization, and if you like, you can star the swift-biome repo itself.

thanks for reading!

17 Likes

hi all, the update is now live at swiftinit.org!

for an example of the new versioning features in action, check out @Max_Desiatov ’s contribution to NIOSingleStepByteToMessageDecoder!

you can also observe that HTTPResponseStatus became Hashable in swift-nio 2.40.0, as indicated by its release notes.

we’ve also upgraded our index with the latest versions of:

2 Likes