From b335ca0b738a821576b6569143d781da3a045090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20St=C3=BChrk?= Date: Sat, 17 Apr 2021 22:28:38 +0200 Subject: [PATCH] Add a user guide. --- Docs/00-introduction.md | 52 ++++++++ Docs/01-command-line-tool.md | 214 ++++++++++++++++++++++++++++++++ Docs/01-github-action.md | 150 ++++++++++++++++++++++ Docs/01-setup-swift-doc.md | 14 +++ Docs/02-documentation-format.md | 121 ++++++++++++++++++ Docs/03-common-problems.md | 37 ++++++ 6 files changed, 588 insertions(+) create mode 100644 Docs/00-introduction.md create mode 100644 Docs/01-command-line-tool.md create mode 100644 Docs/01-github-action.md create mode 100644 Docs/01-setup-swift-doc.md create mode 100644 Docs/02-documentation-format.md create mode 100644 Docs/03-common-problems.md diff --git a/Docs/00-introduction.md b/Docs/00-introduction.md new file mode 100644 index 00000000..b47361b3 --- /dev/null +++ b/Docs/00-introduction.md @@ -0,0 +1,52 @@ +`swift-doc` is a documentation generator for projects +which are written in the Swift programming language. +It collects all classes, structures, enumerations, and protocols +as well as top-level type aliases, functions, and variables +in a project's Swift source code. +It also reads the comments in the source code +and then renders a documentation +which lists all declared symbols combined with their explanatory comments. + +Because of this, `swift-doc` is the ideal tool to build documentation intended for the users of a Swift library, +but it can also be used to generate the documentation of an iOS or macOS app. + +Currently, there are two output formats available: + +- **html**: Generates a website. + + [Here you can find an example](https://swift-doc-preview.netlify.app/) of + [SwiftMarkup's](https://github.com/SwiftDocOrg/SwiftMarkup) documentation rendered as a website. + +- **commonmark**: Generates markdown files in the CommonMark markdown format. + The files generated by `swift-doc` are build with specific file names + and a specific folder structure, + so they can be used for publication to your project's + [GitHub Wiki](https://docs.github.com/en/communities/documenting-your-project-with-wikis/about-wikis). + + [Here you can find an example](https://github.com/SwiftDocOrg/Alamofire/wiki) of + [Alamofire's](https://github.com/Alamofire/Alamofire/) documentation rendered in a GitHub wiki. + +`swift-doc` only reads the Swift source code of a project. +It does not need to compile or run the project +to generate the documentation. +Because of this, creating documentation with `swift-doc` is very fast. +And you can run `swift-doc` on Linux to generate the documentation, +even if the project would require building with Xcode on macOS. +This can simplify building the documentation in your CI pipeline, +because you don't need to execute it on a machine with macOS. + +But this approach also comes with some downsides. +As `swift-doc` only operates on the source code, +it has some limitations: +It can build documentation only for projects that are fully written in Swift. +It can't build documentation for projects which have a codebase that has mixed Objective-C and Swift code. + +This guide leads you through all the needed steps to set up `swift-doc` +to generate a documentation for your project. +It's split into the following parts: + +1. [Set up swift-doc to generate documentation for your project](01-setup-swift-doc.md) + 1. [Using the GitHub action](01-github-action.md) + 2. [Using the command-line tool](01-command-line-tool.md) +2. [Understand documentation comments](02-documentation-format.md) +3. [Common problems when using swift-doc](03-common-problems.md) diff --git a/Docs/01-command-line-tool.md b/Docs/01-command-line-tool.md new file mode 100644 index 00000000..84d90592 --- /dev/null +++ b/Docs/01-command-line-tool.md @@ -0,0 +1,214 @@ +# Using the command-line tool + +`swift-doc` can be used from the command-line on macOS and Linux. + +Before you can use `swift-doc`, +you need to install it first. +It's available via Homebrew and as a Docker container. +Alternatively, you can always build it from sources. + +## Installation +### Homebrew + +[Homebrew](https://brew.sh/)is a free and open-source package management for macOS and Linux. +If you are using Homebrew, +run the following command to install `swift-doc` using Homebrew: + +```terminal +$ brew install swiftdocorg/formulae/swift-doc +``` + +### Docker + +You can run `swift-doc` from the latest [Docker](https://www.docker.com) image with the following commands: + +```terminal +$ docker pull swiftdoc/swift-doc:latest +$ docker run -it swiftdoc/swift-doc +``` + +### Building from source + +You can also build `swift-doc` from source. +It is written in Swift and requires Swift 5.3 or later. +Run the following commands to build and install from sources: + +```terminal +$ git clone https://github.com/SwiftDocOrg/swift-doc +$ cd swift-doc +$ make install +``` + +`swift-doc` has a dependency on [libxml2](https://en.wikipedia.org/wiki/Libxml2). +It also has an optional dependency on +[Graphviz](https://www.graphviz.org/) +if you want to generate the relationship graphs. + +If you're on Linux, +you may need to first install these prerequisites. +You can install it on Ubuntu or Debian by running +the following command: + +```terminal +$ apt-get update +$ apt-get install -y libxml2-dev graphviz +``` + +If you're on macOS, +Graphviz is available via Homebrew: + +```terminal +$ brew install graphviz +``` + +# Build your first documentation + +Let's build some documentation, +now that you have successfully installed `swift-doc`! +You need to provide two arguments +to build the documentation. + +The first argument is the name of the module +for which you build the documentation. +Usually, you will provide a name that matches your package name. +So if your Swift project is called `AwesomeSwiftLibrary`, +you'd provide `AwesomeSwiftLibrary` +as the name of the module. +The module name is provided via the `--module-name` option. + +Besides the module name, +you need to provide paths to directories containing the Swift source files of your project. +You need to provide at least one path to a directory, +but you can provide as many as you want +if your project is split into different directories. +However, you don't need to provide subdirectories +-- `swift-doc` will walk through all subdirectories in the provided directories +and collect all Swift files from there. + +> **Automatically excluded top-level directories**: +> `swift-doc` tries to do the right thing by default +> and it optimizes for use cases which are the most common in the Swift community. +> Therefore, some top-level directories are excluded by default +> because most likely you don't want to include those sources in your documentation. +> Those excluded directories are: +> - `./node-modules/` +> - `./Packages/` +> - `./Pods/` +> - `./Resources/` +> - `./Tests/` +> +> If you want to include those files in your documentation nevertheless, +> you can always include a direct path to the directory +> and they will be included. +> So let's say you have a document structure like this: +> ``` +> MyProject/ +> ├── Tests +> └── OtherDirectory +> ``` +> Then running +> `swift-doc --module-name MyProject ./MyProject` +> will only include the files in the subdirectory `OtherDirectory` +> and automatically exclude the `Tests` subdirectory. +> But running +> `swift-doc --module-name MyProject ./MyProject ./MyProject/Tests` +> will also include all files in the `Tests` subdirectory. + +Let's run the command in the directory of your project. + +```terminal +$ swift-doc generate --module-name AwesomeSwiftLibrary ./Sources/ +``` + +And that's it! +You successfully created the first documentation of your project. +But where can you find it? + +By default, `swift-doc` writes the generated documentation into the directory at `.build/documentation/`. +You can provide a different output directory with the `--output` option: + +```terminal +$ swift-doc generate --module-name AwesomeSwiftLibrary ./Sources/ --output some/other/directory +``` + +## Changing the output format to a rendered website. + +If you followed the steps until now +and checked the documentation which was created, +you could see that `swift-doc` generated a collection of markdown files as output your documentation. +Those markdown files are build with specific file names +and with a specific folder structure, +so they can be used for publication to your project's +[GitHub Wiki](https://docs.github.com/en/communities/documenting-your-project-with-wikis/about-wikis). + +This might be not what you expected. +Maybe you wanted to generate a website +which you could publish on the internet as a documentation for the end users of your library? + +This option is also provided by `swift-doc`. +It's called the _output format_ and you can change it by setting the`--format` option. +In order to generate a website, +you need to set the option to `html`: + +```terminal +$ swift-doc generate --module-name AwesomeSwiftLibrary --format html ./Sources/ +``` + +## Choose which symbols are included by setting the access level + +You might have noticed that the generated documentation contained less symbols that your library actually has. +This is because `swift-doc` only includes public symbols by default +— as this are also the symbols which are exposed to users of your library. + +But if you want to generate documentation for apps and not only for libraries +or if you want to generate a documentation for developers and not only end users of your library, +then you might want to include additional symbols. + +Therefore `swift-doc` also provides the possibility to decide which symbols are included +by setting the minimum access level from which symbols should be included. +This is done via the `--minimum-access-level` option. +Its possible values are: + +* `public` (default). + This will only include symbols which are declared `public` or `open`. + For example, given the following swift source file: + ```swift + + public func publicFunction() { } + + func internalFunction() { } + + private func privateFunction() { } + + public class PublicClass { + public func publicMethod() { } + + open func openMethod() { } + + func internalMethod() { } + } + + internal class InternalClass { + private func privateMethod() { } + } + ``` + + Then the generated documentation will include the function `publicFunction()` and the class `PublicClass`. + For the documentation of `PublicClass`, + it will only include the methods `publicMethod()` and `openMethod()`. + +* `internal`. + This will include all symbols which are declared `public`, `open`, and `internal`. + So in the example above, + it will additionally include the function `internalFunction()` and the class `InternalClass`. + But for the documentation of `InternalClass`, it will not include the method `privateMethod()`. + +* `private`. + This will also include all symbols which are declared `private` and `fileprivate` + and effectively include symbols. + +# Next: Understanding documentation comments + +Now you know which symbols appear in the generated documentation. +[Continue with the guide to understand how to write documentation comments in your source code +to make the best of your documentation](02-documentation-format.md). diff --git a/Docs/01-github-action.md b/Docs/01-github-action.md new file mode 100644 index 00000000..bf47c53d --- /dev/null +++ b/Docs/01-github-action.md @@ -0,0 +1,150 @@ +# Building documentation via the GitHub Action + +We assume that you already have a +[basic knowledge of GitHub actions](https://docs.github.com/en/actions/learn-github-actions/introduction-to-github-actions) +and understand how they work. + +## Creating documentation with a GitHub action + +Let's create a GitHub action which first checks out the source code of your project +and then it builds the documentation for your Project. +We assume that your awesome project has its Swift source files at the path `Sources/AwesomeProject` in your repository. + +Add the file `.github/workflows/documentation.yml` to your repository: + +# Setting a +```yaml +name: Documentation + +on: + push: + branches: + - main + paths: + - .github/workflows/documentation.yml + - Sources/AwesomeProject/**.swift + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Generate Documentation + uses: SwiftDocOrg/swift-doc@master + with: + inputs: "Sources/SwiftDoc" + output: "Documentation" +``` + +Then the next time you push a commit to your `main` branch, +the workflow is triggered +and builds the documentation. + +Now, building the documentation is already the first step. +But very likely you also want to publish the generated documentation somewhere. +That's why we also provide another GitHub action to automatically upload your documentation +to your project's [GitHub Wiki](https://docs.github.com/en/communities/documenting-your-project-with-wikis/about-wikis). + +### Automatically upload the generated documentation to your project's GitHub wiki. + +The [Github Wiki Publish Action](https://github.com/SwiftDocOrg/github-wiki-publish-action) +publishes the contents of a directory to your project's wiki from a GitHub action workflow +and is the ideal addition to the `swift-doc` action. + +We will extend the example from above and check out the project's source code in a first step, +then build the documentation in a second step +and then upload the created documentation to your project's wiki in a third step. + +```yaml + +name: Documentation + +on: + push: + branches: + - main + paths: + - .github/workflows/documentation.yml + - Sources/SwiftDoc/**.swift + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Generate Documentation + uses: SwiftDocOrg/swift-doc@master + with: + inputs: "Sources/SwiftDoc" + output: "Documentation" + - name: Upload Documentation to Wiki + uses: SwiftDocOrg/github-wiki-publish-action@v1 + with: + path: "Documentation" + env: + GH_PERSONAL_ACCESS_TOKEN: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} +``` + +## Choose which symbols are included by setting the access level + +You might have noticed that the generated documentation contained less symbols that your library actually has. +This is because `swift-doc` only includes public symbols by default +— as this are also the symbols which are exposed to users of your library. + +But if you want to generate documentation for apps and not only for libraries +or if you want to generate a documentation for developers and not only end users of your library, +then you might want to include additional symbols. + +Therefore `swift-doc` also provides the possibility to decide which symbols are included +by setting the minimum access level from which symbols should be included. +This is done via the `--minimum-access-level` option. +Its possible values are: + +* `public` (default). + This will only include symbols which are declared `public` or `open`. + For example, given the following swift source file: + ```swift + + public func publicFunction() { } + + func internalFunction() { } + + private func privateFunction() { } + + public class PublicClass { + public func publicMethod() { } + + open func openMethod() { } + + func internalMethod() { } + } + + internal class InternalClass { + private func privateMethod() { } + } + ``` + + Then the generated documentation will include the function `publicFunction()` and the class `PublicClass`. + For the documentation of `PublicClass`, + it will only include the methods `publicMethod()` and `openMethod()`. + +* `internal`. + This will include all symbols which are declared `public`, `open`, and `internal`. + So in the example above, + it will additionally include the function `internalFunction()` and the class `InternalClass`. + But for the documentation of `InternalClass`, it will not include the method `privateMethod()`. + +* `private`. + This will also include all symbols which are declared `private` and `fileprivate` + and effectively include symbols. + + +## Next: Understand documentation comments + +Now you know which symbols appear in the generated documentation. +[Continue with the guide to understand how to write documentation comments in your source code +to make the best of your documentation](02-documentation-format.md). diff --git a/Docs/01-setup-swift-doc.md b/Docs/01-setup-swift-doc.md new file mode 100644 index 00000000..71419f3c --- /dev/null +++ b/Docs/01-setup-swift-doc.md @@ -0,0 +1,14 @@ +# Setup swift-doc + +Let's get started by setting up `swift-doc` to build documentation for your project. +There are two different ways how you can use swift-doc +to create documentation for your project: +- If your project is hosted on GitHub, + you can use swift-docs' **GitHub action** + to build the documentation in a GitHub action workflow. + + [Please follow the guide for setting up the GitHub action then.](01-github-action.md) + +- Run swift-doc as **command-line tool** on your local machine or in your build pipeline. + + [Please follow the guide for using the command-line then.](01-command-line-tool.md) diff --git a/Docs/02-documentation-format.md b/Docs/02-documentation-format.md new file mode 100644 index 00000000..51e56e6a --- /dev/null +++ b/Docs/02-documentation-format.md @@ -0,0 +1,121 @@ +# Documentation format + +In general, `swift-doc` uses [Xcode's markup formatting](https://developer.apple.com/library/archive/documentation/Xcode/Reference/xcode_markup_formatting_ref/MarkupSyntax.html) +and does not add any additional syntax. +Therefore, all the rules which apply to writing documentation for Xcode's quick help feature also apply for writing documentation for `swift-doc`. + +## Documentation comments + +Swift has various ways how you can add comments to source code. +`swift-doc` will pick up so called _documentation comments_. +Documentation comments need to either start with three slashes `///` for single-line comments +or with an extra asterisk `/**` for multiline comments. +The documentation comments need to precede the symbol they are documenting, +but there can be additional whitespace between the documentation comment and its symbol: + +```swift +// This is a regular comment and will not appear in the documentation. +public func someUndocumentedFunction() { } + +/* + This is a regular multiline comment and will not appear in the documentation. + */ +public func alsoUndocumentedFunction() { + +} + +/// This is a documentation comment. +public func someDocumentedFunction() { } + +/// The documentation comment can +/// also span multiple lines. Every line +/// needs to start with three slashes. +public func anotherDocumentedFunction() { } + +/** + This is a multiline documentation comments. Note the extra asterisk. + */ +public func alsoDocumentedFunction() { } + + +/// This document comment has additional whitespace between the comment and the symbol declaration. This works. + +public func alsoDocumentedEvenWithWhitespace() { } +``` + +## Markup format + +There are many guides how you can write documentation comments for Swift. +There's a +[guide from Apple](https://developer.apple.com/library/archive/documentation/Xcode/Reference/xcode_markup_formatting_ref/SymbolDocumentation.html) +and also an [introduction from NSHipster](https://nshipster.com/swift-documentation/). + +Nevertheless, here are also the most important rules in order to write documentation. + + +### Documenting parameters + +Let's start by documenting parameters of functions and methods. +Start a line in a documentation comment with `-Parameter nameOfTheParameter:` +where `nameOfTheParamater` is the name of the parameter you want to document: + +```swift +/// - Parameter singleArgument: +func singleArgumentFunction(singleArgument: String) { } +``` + +Many functions have more than one parameter +and repeating `- Parameter ` all over again can add a lot of visual noise. +Luckily, you can also document parameters as bulleted list: + +```swift +/// This is the text of the documentation. +/// +/// - Parameters: +/// - firstArgument: This is the documentation which explains the first argument. +/// - secondArgument: This is the documentation which explains the second argument. +func generateSomeShit(firstArgument: String, secondArgument: Int) { + +} +``` + +Functions in Swift can have two different names for parameters: +An argument label and a parameter name. +The argument label is used when calling the function. +The parameter name is used inside the body of the function. +If no extra argument name is given, +the argument label is the same as the parameter name. + +To create documentation for parameters, +you need to use the name of the parameter (the second, internal name) and not the name of the label. + +```swift +/// - Parameters: +/// - argumentName: The documentation which explains the argument. +func functionWithLabelAndArgumentName(externalLabel argumentName: String) { + print(argumentName) +} +``` + +### Documenting return values + +Documenting return values is very similar to documenting parameters. + +Start a line in a documentation comment with `- Returns:` to document the return value of a method or a value: + +```swift +/// A function to create the sum of two numbers. +/// +/// - Returns: The sum of the two given numbers. +func sum(firstNumber: Int, secondNumber: Int) -> Int { + return firstNumber + secondNumber +} +``` + +## Continue + +Now you understand how you can write documentation comments to produce a good documentation. +You're all set to build good and beautiful documentation for users of your software. +However, we also know that all beginnings are difficult. +That's why we also [collected a list of common problems when using swift-doc](03-common-problems.md) +to provide some guidance for the first problems you might encounter while building your documentation. diff --git a/Docs/03-common-problems.md b/Docs/03-common-problems.md new file mode 100644 index 00000000..a4bde75e --- /dev/null +++ b/Docs/03-common-problems.md @@ -0,0 +1,37 @@ +# Common problems when using `swift-doc` + + +> I want to exclude certain classes / methods / properties from the generated documentation. + +Currently, setting the access level is the only one option to control which symbols will appear in the created documentation. +You can make a function, class, and so on `public` +to make it appear in the generated documentation. +Or you can set the `minimum-access-level` flag +to also include `internal` symbols in the created documentation. + +--- + +> The generated documentation is empty. `swift-doc` outputs the following warnings: +> ``` +> warning: No public API symbols were found at the specified path. No output was written. +> warning: By default, swift-doc only includes public declarations. Maybe you want to use --minimum-access-level to include non-public declarations? +> ``` + +By default, `swift-doc` only documents functions, classes, and so on which are declared `public`. +If `swift-doc` can't find any public symbol, +it doesn't have anything to generate documentation for. + +Very often this is the case for apps which use only `internal` declarations. + +You can use the `minimum-access-level` flag +to also include `internal` declarations in the created documentation. + +--- + +> I need to use a feature which is not implemented in `swift-doc`. + +We are very happy to hear your feedback! +Please feel free to +[open an issue on GitHub with a feature request](https://github.com/SwiftDocOrg/swift-doc/issues). +Please make sure to use the search first +and check if there might be some existing or closed issue describing your problem already.