Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Commit

Permalink
Merge pull request #21 from SwiftDocOrg/html
Browse files Browse the repository at this point in the history
Add support for HTML output
  • Loading branch information
mattt authored Apr 1, 2020
2 parents b5274fb + 746356f commit 85b5872
Show file tree
Hide file tree
Showing 35 changed files with 2,274 additions and 473 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Install System Dependencies
run: |
apt-get update
apt-get install -y libxml2-dev
- name: Build and Test
run: swift test --enable-test-discovery
48 changes: 42 additions & 6 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,31 @@
"repositoryURL": "https://github.com/SwiftDocOrg/GraphViz.git",
"state": {
"branch": null,
"revision": "08e0cddd013fa2272379d27ec3e0093db51f34fb",
"version": "0.1.0"
"revision": "03405c13dc1c31f50c08bbec6e7587cbee1c7fb3",
"version": null
}
},
{
"package": "HypertextLiteral",
"repositoryURL": "https://github.com/NSHipster/HypertextLiteral.git",
"state": {
"branch": null,
"revision": "3e45da849e507d171c7264146176bb834a01be4f",
"version": "0.0.2"
}
},
{
"package": "Markup",
"repositoryURL": "https://github.com/SwiftDocOrg/Markup.git",
"state": {
"branch": null,
"revision": "9a429d0011d738059bc94f5f92ee406689597a91",
"version": "0.0.3"
}
},
{
"package": "swift-argument-parser",
"repositoryURL": "https://github.com/apple/swift-argument-parser",
"repositoryURL": "https://github.com/apple/swift-argument-parser.git",
"state": {
"branch": null,
"revision": "8d31a0905c346a45c87773ad50862b5b3df8dff6",
Expand All @@ -37,6 +55,15 @@
"version": "0.28.3+20200207.1168665"
}
},
{
"package": "HTMLEntities",
"repositoryURL": "https://github.com/IBM-Swift/swift-html-entities.git",
"state": {
"branch": null,
"revision": "744c094976355aa96ca61b9b60ef0a38e979feb7",
"version": "3.0.14"
}
},
{
"package": "SwiftSyntax",
"repositoryURL": "https://github.com/apple/swift-syntax.git",
Expand All @@ -51,16 +78,25 @@
"repositoryURL": "https://github.com/SwiftDocOrg/SwiftMarkup.git",
"state": {
"branch": null,
"revision": "8e82d625b0342fc80525956c22f9f0defa0cffce",
"version": "0.0.4"
"revision": "431f418ae1833a312646e934a2891e778c1b03b0",
"version": "0.0.5"
}
},
{
"package": "SwiftSemantics",
"repositoryURL": "https://github.com/SwiftDocOrg/SwiftSemantics.git",
"state": {
"branch": "swift-5.2",
"branch": null,
"revision": "4fdc48bddbbb8311079ed111e5a4f2b92423b05c",
"version": "0.1.0"
}
},
{
"package": "SwiftSyntaxHighlighter",
"repositoryURL": "https://github.com/NSHipster/SwiftSyntaxHighlighter.git",
"state": {
"branch": "1.0.0",
"revision": "4a20d10bba17241b66650d99081801536146b43c",
"version": null
}
}
Expand Down
12 changes: 8 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,26 @@ import PackageDescription
let package = Package(
name: "swift-doc",
products: [
.executable(name: "swift-doc", targets: ["swift-doc"]),
.library(name: "SwiftDoc", targets: ["SwiftDoc"])
],
dependencies: [
.package(url: "https://github.com/apple/swift-syntax.git", .revision("0.50200.0")),
.package(url: "https://github.com/SwiftDocOrg/SwiftSemantics.git", .upToNextMinor(from: "0.1.0")),
.package(url: "https://github.com/SwiftDocOrg/CommonMark.git", .branch("master")),
.package(url: "https://github.com/SwiftDocOrg/SwiftMarkup.git", .upToNextMinor(from: "0.0.4")),
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .upToNextMinor(from: "0.1.0")),
.package(url: "https://github.com/apple/swift-argument-parser", .upToNextMinor(from: "0.0.2")),
.package(url: "https://github.com/SwiftDocOrg/SwiftMarkup.git", .upToNextMinor(from: "0.0.5")),
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .revision("03405c13dc1c31f50c08bbec6e7587cbee1c7fb3")),
.package(url: "https://github.com/NSHipster/HypertextLiteral.git", .upToNextMinor(from: "0.0.2")),
.package(url: "https://github.com/SwiftDocOrg/Markup.git", .upToNextMinor(from: "0.0.3")),
.package(url: "https://github.com/NSHipster/SwiftSyntaxHighlighter.git", .revision("1.0.0")),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.0.2")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "swift-doc",
dependencies: ["ArgumentParser", "SwiftDoc", "SwiftSemantics", "SwiftMarkup", "CommonMarkBuilder", "DCOV", "GraphViz"]
dependencies: ["ArgumentParser", "SwiftDoc", "SwiftSemantics", "SwiftMarkup", "CommonMarkBuilder", "HypertextLiteral", "Markup", "DCOV", "GraphViz", "SwiftSyntaxHighlighter"]
),
.target(
name: "DCOV",
Expand Down
139 changes: 19 additions & 120 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,15 @@

A package for generating documentation for Swift projects.

**This project is under active development
and is expected to change significantly before its first stable release.**

Given a directory of Swift files,
`swift-doc` generates CommonMark (Markdown) files
`swift-doc` generates HTML or CommonMark (Markdown) files
for each class, structure, enumeration, and protocol
as well as top-level type aliases, functions, and variables.

For an example of generated documentation,
[check out the Wiki for our fork of Alamofire][alamofire wiki].
**Example Output**

> **Note**:
> Output is currently limited to CommonMark,
> but the plan is to support HTML and other formats as well.
- [HTML][swiftsemantics html]
- [CommonMark / GitHub Wiki][alamofire wiki]

## Requirements

Expand Down Expand Up @@ -54,18 +49,26 @@ collecting all Swift files into a single "module"
and generating documentation accordingly.

```terminal
$ swift doc generate path/to/SwiftProject/Sources --output Documentation
$ tree Documentation
$ Documentation/
$ swift doc generate path/to/SwiftProject/Sources
$ tree .build/documentation
$ documentation/
├── Home
├── (...)
├── _Footer.md
└── _Sidebar.md
```

By default,
output files are written to `.build/documentation`,
but you can change that with the `--output` option flag.
output files are written to `.build/documentation`
in CommonMark / GitHub Wiki format,
but you can change that with the `--output` and `--format` option flags.

```terminal
$ swift doc generate path/to/SwiftProject/Sources --output Documentation --format html
$ Documentation/
├── (...)
└── index.html
```

#### swift-doc coverage

Expand Down Expand Up @@ -178,114 +181,9 @@ jobs:
with:
path: "Documentation"
env:
GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.GITHUB_PERSONAL_ACCESS_TOKEN }}
```
* * *
## Motivation
From its earliest days,
Swift has been fortunate to have [Jazzy][jazzy],
which is a fantastic tool for generating documentation
for both Swift and Objective-C projects.
Over time, however,
the way we write Swift code —
and indeed the language itself —
has evolved to incorporate patterns and features
that are difficult to understand using
the same documentation standards that served us well for Objective-C.
Whereas in Objective-C,
you could get a complete view of a type's functionality from its class hierarchy,
Swift code today tends to layer and distribute functionality across
[a network of types][swift number protocols diagram].
While adopting a
[protocol-oriented paradigm][protocol-oriented programming]
can make Swift easier and more expressive to write,
it can also make Swift code more difficult to understand.
Our primary goal for `swift-doc`
is to make Swift documentation more useful
by surfacing the information you need to understand how an API works
and presenting it in a way that can be easily searched and accessed.
We want developers to be empowered to use Swift packages to their full extent,
without being reliant on (often outdated) blog posts or Stack Overflow threads.
We want documentation coverage to become as important as test coverage:
a valuable metric for code quality,
and an expected part of first-rate open source projects.

Jazzy styles itself after Apple's official documentation circa 2014
(code-named "Jazz", as it were),
which was well-suited to understanding Swift code as we wrote it back then
when it was more similar to Objective-C.
But this design is less capable of documenting the behavior of
generically-constrained types,
default implementations,
[dynamic member lookup][se-0195],
[property wrappers][se-o258], or
[function builders][se-xxxx].
(Alas,
Apple's [most recent take][apple documentation] on reference documentation
hasn't improved matters,
having instead focused on perceived cosmetic issues.)

Without much in the way of strong design guidance,
we're not entirely sure what Swift documentation _should_ look like.
But we do think plain text is a good place to start.
We look forward to
soliciting feedback and ideas from everyone
so that we can identify those needs
and figure out the best ways to meet them.

In the meantime,
we've set ourselves up for success
by investing in the kind of foundation we'll need
to build whatever we decide best solves the problems at hand.
`swift-doc` is built on top of a constellation of projects
that take advantage of modern infrastructure and tooling:

- [SwiftSemantics][swiftsemantics]:
Parses Swift code into its constituent declarations
using [SwiftSyntax][swiftsyntax]
- [SwiftMarkup][swiftmarkup]:
Parses Swift documentation comments into structured entities
using [CommonMark][commonmark]
- [github-wiki-publish-action][github-wiki-publish-action]:
Publishes the contents of a directory to your project's wiki

These new technologies have already yielded some promising results.
`swift-doc` is built in Swift,
and can be installed on both macOS and Linux as a small, standalone binary.
Because it relies only on a syntactic reading of Swift source code,
without needing code first to be compiled,
`swift-doc` is quite fast.
As a baseline,
compare its performance to Jazzy
when generating documentation for [SwiftSemantics][swiftsemantics]:

```terminal
$ cd SwiftSemantics
$ time swift-doc Sources
0.21 real 0.16 user 0.02 sys
$ time jazzy # fresh build
jam out ♪♫ to your fresh new docs in `docs`
67.36 real 98.76 user 8.89 sys


$ time jazzy # with build cache
jam out ♪♫ to your fresh new docs in `docs`
17.70 real 2.17 user 0.88 sys
GH_PERSONAL_ACCESS_TOKEN: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
```
Of course,
some of that is simply Jazzy doing more,
generating HTML, CSS, and a search index instead of just text.
Compare its [generated HTML output][jazzy swiftsemantics]
to [a GitHub wiki generated with `swift-doc`][swift-doc swiftsemantics].

## License
MIT
Expand All @@ -297,6 +195,7 @@ Mattt ([@mattt](https://twitter.com/mattt))
[ci badge]: https://github.com/SwiftDocOrg/swift-doc/workflows/CI/badge.svg
[alamofire wiki]: https://github.com/SwiftDocOrg/Alamofire/wiki
[swiftsemantics html]: https://swift-doc-preview.netlify.app
[github wiki]: https://help.github.com/en/github/building-a-strong-community/about-wikis
[github actions]: https://github.com/features/actions
[swiftsyntax]: https://github.com/apple/swift-syntax
Expand Down
16 changes: 12 additions & 4 deletions Sources/SwiftDoc/Extensions/Array+Parallel.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import Dispatch

extension Array {
public extension RandomAccessCollection {
func parallelMap<T>(_ transform: (Element) throws -> T) throws -> [T] {
guard count > 1 else {
return try map(transform)
}

var results = [(index: Int, result: Result<T, Error>)]()
let indices = Array(self.indices)

var results = [(index: Index, result: Result<T, Error>)]()
results.reserveCapacity(count)

let queue = DispatchQueue(label: "org.swiftdoc.swift-doc.parallelMap")
let queue = DispatchQueue(label: #function)
withoutActuallyEscaping(transform) { escapingtransform in
DispatchQueue.concurrentPerform(iterations: count) { (index) in
DispatchQueue.concurrentPerform(iterations: count) { (iteration) in
let index = indices[iteration]

do {
let transformed = try escapingtransform(self[index])
queue.sync {
Expand All @@ -36,4 +40,8 @@ extension Array {
func parallelFlatMap<T>(transform: (Element) throws -> [T]) throws -> [T] {
return try parallelMap(transform).flatMap { $0 }
}

func parallelForEach(_ body: (Element) throws -> Void) throws {
_ = try parallelMap(body)
}
}
Loading

0 comments on commit 85b5872

Please sign in to comment.