diff options
Diffstat (limited to 'docs/src/doc')
31 files changed, 1689 insertions, 546 deletions
diff --git a/docs/src/doc/docs/about/FAQ.md b/docs/src/doc/docs/about/FAQ.md deleted file mode 100644 index ba4a7acf..00000000 --- a/docs/src/doc/docs/about/FAQ.md +++ /dev/null @@ -1,2 +0,0 @@ -# FAQ -If you encounter any problems, please see the [FAQ](https://github.com/Kotlin/dokka/wiki/faq). diff --git a/docs/src/doc/docs/about/slack_channel.md b/docs/src/doc/docs/about/slack_channel.md deleted file mode 100644 index 6879dc7d..00000000 --- a/docs/src/doc/docs/about/slack_channel.md +++ /dev/null @@ -1,4 +0,0 @@ -# Slack channel - -For more information or help, feel free to ask questions in the [official Kotlin Slack Channel](https://kotlinlang.slack.com) - diff --git a/docs/src/doc/docs/community/plugins-list.md b/docs/src/doc/docs/community/plugins-list.md index 4a65965e..ed8993fc 100644 --- a/docs/src/doc/docs/community/plugins-list.md +++ b/docs/src/doc/docs/community/plugins-list.md @@ -1,18 +1,160 @@ # Dokka community plugins -Here is a list of plugins created by dokka team or community. +On this page you can find `Dokka` plugins which are supported by both `Dokka` maintainers and community members. -In order to add your plugin to this list it needs to be: +If you want to add your plugin to this list, get in touch with maintainers via [Slack](../community/slack.md) +or `GitHub`. - * an open source project - sharing is caring so let others learn and improve your plugin - * present in any public artefacts repository like bintray +If you want to learn how to develop plugins for `Dokka`, see +[Plugin development](../developer_guide/plugin-development/introduction.md) section. -| Plugin name | Description | Source | -| :--------- | :--------- | :------------ | -| [Kotlin as Java](https://kotlin.github.io/dokka/1.7.0/user_guide/introduction/#plugins) | Display Kotlin code as seen from Java | [Github](https://github.com/Kotlin/dokka/tree/master/plugins/kotlin-as-java) -| [GFM](https://kotlin.github.io/dokka/1.7.0/user_guide/introduction/#plugins) | Renders documentation in a GFM format | [Github](https://github.com/Kotlin/dokka/tree/master/plugins/gfm) -| [Javadoc](https://kotlin.github.io/dokka/1.7.0/user_guide/introduction/#plugins) | Renders documentation in a Javadoc format | [Github](https://github.com/Kotlin/dokka/tree/master/plugins/javadoc) -| [Jekyll](https://kotlin.github.io/dokka/1.7.0/user_guide/introduction/#plugins) | Renders documentation in a Jekyll format | [Github](https://github.com/Kotlin/dokka/tree/master/plugins/jekyll) -| [Mermaid-HTML](https://mermaid-js.github.io/mermaid/#/) | Renders Mermaid graphs for HTML renderer. | [Github](https://github.com/glureau/dokka-mermaid) +## Output Formats +### Javadoc (Alpha) +Javadoc plugin adds a `Javadoc` output format that looks like Java's `Javadoc`, but it's for the most part +a lookalike, so you may experience problems if you try to use it with a tool that expects native +`Javadoc` documentation generated by `Java`. + +`Javadoc` plugin does not support multiplatform projects and does not have a multi-module task. + +`Javadoc` plugin is shipped with `Dokka`, so you can start using it right away with one of the following tasks: + +* `dokkaJavadoc` - builds `Javadoc` documentation for single-module projects or for a specific module. +* `dokkaJavadocCollector` - collects generated `Javadoc` documentation from submodules and assembles it together. + +`Javadoc` plugin has its own signature provider that essentially translates `Kotlin` signatures to `Java` ones. + +**This plugin is at its early stages**, so you may experience issues and encounter bugs. Feel free to +[report](https://github.com/Kotlin/dokka/issues/new/choose) any errors you see. + +[Plugin source code on GitHub](https://github.com/Kotlin/dokka/tree/master/plugins/javadoc) + +### GFM (Alpha) + +`GFM` plugins adds the ability to generate documentation in `GitHub flavoured Markdown` format. Supports both +multimodule and multiplatform projects, and is shipped together with `Dokka`, so you can start using it +right away with one of the following tasks: + +* `dokkaGfm` - generate documentation for a non multi-module project or one specific module. +* `dokkaGfmMultiModule` - generate documentation for a multi-module project, assemble it together and + generate navigation page/menu for all the modules. + +Example: + +___ + +//[dokka-debug-kts](#gfm)/[org.jetbrains.dokka.test](#gfm)/[MyClass](#gfm) + +#### MyClass + +[jvm] +class [MyClass](#gfm) + +KDoc that describes this class + +##### Constructors + +| | | +|---|---| +| [MyClass](#gfm) | [jvm]<br>fun [MyClass](#gfm)() | + +##### Functions + +| Name | Summary | +|------------------|---| +| [function](#gfm) | [jvm]<br>fun [function](#gfm)(): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)<br>KDoc comment on top of this function | + +##### Properties + +| Name | Summary | +|---|------------------------------------------------------------------------------------------------------------------------------------------------| +| [property](#gfm) | [jvm]<br>val [property](#gfm): [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)<br>KDoc comment for a property | + +___ + +**This plugin is at its early stages**, so you may experience issues and encounter bugs. Feel free to +[report](https://github.com/Kotlin/dokka/issues/new/choose) any errors you see. + +[Plugin source code on GitHub](https://github.com/Kotlin/dokka/tree/master/plugins/gfm) + +### Jekyll (Alpha) + +`Jekyll` plugins adds the ability to generate documentation in `Jekyll flavoured Markdown` format. Supports both +multi-module and multiplatform projects, and is shipped together with `Dokka`, so you can start using it +right away with one of the following tasks: + +* `dokkaJekyll` - generate documentation for a non multi-module project or one specific module. +* `dokkaJekyllMultiModule` - generate documentation for a multi-module project, assemble it together and + generate navigation page/menu for all the modules. + +**This plugin is at its early stages**, so you may experience issues and encounter bugs. Feel free to +[report](https://github.com/Kotlin/dokka/issues/new/choose) any errors you see. + +[Plugin source code on GitHub](https://github.com/Kotlin/dokka/tree/master/plugins/jekyll) + +## Extensions + +### Mathjax + +[MathJax](https://docs.mathjax.org/) allows you to include mathematics in your web pages. `MathJax` plugin +adds the ability to render mathematics from source code comments. + +If `MathJax` plugin encounters `@usesMathJax` `KDoc` tag, it adds `MathJax.js` (ver. 2) with `config=TeX-AMS_SVG` +to generated `HTML` pages. + +Usage example: +```kotlin +/** + * Some math \(\sqrt{3x-1}+(1+x)^2\) + * + * @usesMathJax + */ +class Foo {} +``` + +Which results in: + +![Mathjax demo](../images/mathjax_demo.png){ width="400" } + +[Plugin source code on GitHub](https://github.com/Kotlin/dokka/tree/master/plugins/mathjax) + +### Mermaid + +[Mermaid JS](https://mermaid-js.github.io/mermaid/#/) lets you create diagrams and visualizations using text and code. +`Mermaid` plugin allows rendering such diagrams and visualizations found in source code documentation. + +Usage example: +```kotlin +/** + * See the graph for more details: + * \```mermaid + * graph LR + * A[Christmas] -->|Get money| B(Go shopping) + * B --> C{Let me think} + * C -->|One| D[Laptop] + * C -->|Two| E[iPhone] + * C -->|Three| F[fa:fa-car Car] + * \``` + */ +class CompositeSubscription +``` + +Which results in: + +![Mermaid demo](../images/mermaid_demo.png){ width="700" } + +For more information and examples, see +[Html Mermaid Dokka plugin](https://github.com/glureau/dokka-mermaid) repository on GitHub. + +### Kotlin as Java + +With `Kotlin as Java` plugin applied, all `Kotlin` signatures will be rendered as `Java` signatures. + +For instance, `fun foo(bar: Bar): Baz` will be rendered as `public final Baz foo(Bar bar)`. + +`Kotlin as Java` plugin is published to maven central as a +[separate artifact](https://mvnrepository.com/artifact/org.jetbrains.dokka/kotlin-as-java-plugin): +`org.jetbrains.dokka:kotlin-as-java-plugin:1.7.0`. + +[Plugin source code on GitHub](https://github.com/Kotlin/dokka/tree/master/plugins/kotlin-as-java) diff --git a/docs/src/doc/docs/community/slack.md b/docs/src/doc/docs/community/slack.md new file mode 100644 index 00000000..290d4a18 --- /dev/null +++ b/docs/src/doc/docs/community/slack.md @@ -0,0 +1,7 @@ +# Slack channel + +`Dokka` has a dedicated `#dokka` channel in the `Kotlin Community Slack`, where you can ask questions and chat +about using, customizing or contributing to `Dokka`. + +[Follow the instructions](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up) +to get an invite or [connect directly](https://kotlinlang.slack.com). diff --git a/docs/src/doc/docs/developer_guide/architecture/architecture_overview.md b/docs/src/doc/docs/developer_guide/architecture/architecture_overview.md new file mode 100644 index 00000000..fb11f32a --- /dev/null +++ b/docs/src/doc/docs/developer_guide/architecture/architecture_overview.md @@ -0,0 +1,123 @@ +# Architecture overview + +Normally, you would think that a tool like `Dokka` simply parses some programming language sources and generates +`HTML` pages for whatever it sees along the way, with little to no abstractions. That would be the simplest and +shortest way to implement an API documentation engine. + +However, it was clear that `Dokka` may need to generate documentation from various sources (not only `Kotlin`), that users +might request additional output formats (like `Markdown`), that users might need additional features like supporting +custom `KDoc` tags or rendering `mermaid.js` diagrams - all these things would require changing a lot of code inside +`Dokka` itself if all solutions were hardcoded. + +For this reason, `Dokka` was built from the ground up to be easily extensible and customizable by adding several layers +of abstractions to the data model, and by providing pluggable extension points, giving you the ability to introduce +selective changes on a single level. + +## Overview of data model + +Generating API documentation begins with `Input` source files (`.kts`, `.java`, etc) and ends with some `Output` files +(`.html`/`.md` pages, etc). However, to allow for extensibility and customization, several input and output independent +abstractions have been added to the data model. + +Below you can find the general pipeline of processing data gathered from sources and the explanation for each stage. + +```mermaid +flowchart TD + Input --> Documentables --> Pages --> Output +``` + +* `Input` - generalization of sources, by default `Kotlin`/`Java` sources, but could be virtually anything +* `Documentables` - unified data model that represents _any_ parsed sources as a tree, independent of the source + language. Examples of a `Documentable`: class, function, package, property, etc +* `Pages` - universal model that represents output pages (e.g a function/property page) and the content it's composed of + (lists, text, code blocks) that the users needs to see. Not to be confused with `.html` pages. Goes hand in hand + with so-called `Content` model. +* `Output` - specific output format like `HTML`/`Markdown`/`Javadoc`/etc. This is a mapping of pages/content model to + some human-readable and visual representation. For instance: + * `PageNode` is mapped as + * `.html` file for `HTML` format + * `.md` file for `Markdown` format + * `ContentList` is mapped as + * `<li>` / `<ul>` for `HTML` format + * `1.` / `*` for `Markdown` format + * `ContentCodeBlock` is mapped as + * `<code>` or `<pre>` with some CSS styles in `HTML` format + * Text wrapped in triple backticks for `Markdown` format + + +You, as a `Dokka` developer or a plugin writer, can use extension points to introduce selective changes to the +model on one particular level without touching everything else. + +For instance, if you wanted to make some annotation/function/class invisible in the final documentation, you would only +need to modify the `Documentables` model by filtering undesirable members out. If you wanted to display all overloaded +methods on the same page instead of on separate ones, you would only need to modify the `Page` model by merging multiple +pages into one, and so on. + +For a deeper dive into Dokka's model with more examples and details, +see sections about [Documentables](data_model/documentables.md) and [Page/Content](data_model/page_content.md) + +For an overview of existing extension points that let you transform Dokka's models, see +[Core extension points](extension_points/core_extensions.md) and [Base extensions](extension_points/base_extensions.md). + +## Overview of extension points + +An extension point usually represents some pluggable interface that performs an action during one of the stages of +generating documentation. An extension is therefore an implementation of that interface which is extending the +extension point. + +You can create extension points, provide your own implementations (extensions) and configure them. All of +this is possible with Dokka's plugin/extension point API. + +Here's a sneak peek of the DSL: + +```kotlin +class MyPlugin : DokkaPlugin() { + // create an extension point for other developers + val signatureProvider by extensionPoint<SignatureProvider>() + + // provide a default implementation + val defaultSignatureProvider by extending { + signatureProvider with KotlinSignatureProvider() + } + + // register our own extension in base plugin and override its default + val dokkaBasePlugin by lazy { plugin<DokkaBase>() } + val multimoduleLocationProvider by extending { + (dokkaBasePlugin.locationProviderFactory + providing MultimoduleLocationProvider::Factory + override dokkaBasePlugin.locationProvider) + } +} + +// use a registered extention, pretty much dependency injection +class MyExtension(val context: DokkaContext) { + + val signatureProvider: SignatureProvider = context.plugin<MyPlugin>().querySingle { signatureProvider } + + fun doSomething() { + signatureProvider.signature(..) + } +} + +interface SignatureProvider { + fun signature(documentable: Documentable): List<ContentNode> +} + +class KotlinSignatureProvider : SignatureProvider { + override fun signature(documentable: Documentable): List<ContentNode> = listOf() +} +``` + +For a deeper dive into extensions and extension points with more examples and details, see +[Introduction to Extensions](extension_points/introduction.md). + +For an overview of existing extension points, see [Core extension points](extension_points/core_extensions.md) and +[Base extensions](extension_points/base_extensions.md). + +## Historical context + +This is a second iteration of Dokka that was built from scratch. + +If you want to learn more about why Dokka has been designed this way, watch this great talk by Paweł Marks: +[New Dokka - Designed for Fearless Creativity](https://www.youtube.com/watch?v=OvFoTRhqaKg). The general principles +and general architecture are the same, although it may be outdated in some areas, so please double-check. diff --git a/docs/src/doc/docs/developer_guide/architecture/data_model/documentables.md b/docs/src/doc/docs/developer_guide/architecture/data_model/documentables.md new file mode 100644 index 00000000..5264553d --- /dev/null +++ b/docs/src/doc/docs/developer_guide/architecture/data_model/documentables.md @@ -0,0 +1,245 @@ +# Documentables Model + +Documentables represent data that is parsed from sources. Think of this data model as of something that could be +seen or produced by a compiler frontend, it's not far off from the truth. + +By default, documentables are parsed from `Descriptor` (for `Kotlin`) +and [Psi](https://plugins.jetbrains.com/docs/intellij/psi.html) +(for `Java`) models. Code-wise, you can have a look at following classes: + +* `DefaultDescriptorToDocumentableTranslator` - responsible for `Kotlin` -> `Documentable` mapping +* `DefaultPsiToDocumentableTranslator` - responsible for `Java` -> `Documentable` mapping + +Upon creation, it's a collection of trees, each with `DModule` as root. + +Take some arbitrary `Kotlin` source code that is located within the same module: + +```kotlin +// Package 1 +class Clazz(val property: String) { + fun function(parameter: String) {} +} + +fun topLevelFunction() {} + +// Package 2 +enum class Enum { } + +val topLevelProperty: String +``` + +This would be represented roughly as the following `Documentable` tree: + +```mermaid +flowchart TD + DModule --> firstPackage[DPackage] + firstPackage --> DClass + firstPackage --> toplevelfunction[DFunction] + DClass --> DProperty + DClass --> DFunction + DFunction --> DParameter + DModule --> secondPackage[DPackage] + secondPackage --> DEnum + secondPackage --> secondPackageProperty[DProperty] +``` + +At later stages of transformation, all trees are folded into one (by `DocumentableMerger`). + +## Documentable + +The main building block of documentables model is `Documentable` class. It's the base class for all more specific types +that represent elements of parsed sources with mostly self-explanatory names (`DFunction`, `DPackage`, `DProperty`, etc) +. +`DClasslike` is the base class for class-like documentables such as `DClass`, `DEnum`, `DAnnotation`, etc. + +The contents of each documentable normally represent what you would see in source code. For instance, if you open +`DClass`, you should find that it contains references to functions, properties, companion object, constructors and so +on. +`DEnum` should have references to enum entries, and `DPackage` can have references to both classlikes and top-level +functions and properties (`Kotlin`-specific). + +Here's an example of a documentable: + +```kotlin +data class DClass( + val dri: DRI, + val name: String, + val constructors: List<DFunction>, + val functions: List<DFunction>, + val properties: List<DProperty>, + val classlikes: List<DClasslike>, + val sources: SourceSetDependent<DocumentableSource>, + val visibility: SourceSetDependent<Visibility>, + val companion: DObject?, + val generics: List<DTypeParameter>, + val supertypes: SourceSetDependent<List<TypeConstructorWithKind>>, + val documentation: SourceSetDependent<DocumentationNode>, + val expectPresentInSet: DokkaSourceSet?, + val modifier: SourceSetDependent<Modifier>, + val sourceSets: Set<DokkaSourceSet>, + val isExpectActual: Boolean, + val extra: PropertyContainer<DClass> = PropertyContainer.empty() +) : DClasslike(), WithAbstraction, WithCompanion, WithConstructors, + WithGenerics, WithSupertypes, WithExtraProperties<DClass> +``` + +___ + +There are three non-documentable classes that important for this model: + +* `DRI` +* `SourceSetDependent` +* `ExtraProperty`. + +### DRI + +`DRI` stans for _Dokka Resource Identifier_ - a unique value that identifies a specific `Documentable`. +All references and relations between documentables (other than direct ownership) are described using `DRI`. + +For example, `DFunction` with a parameter of type `Foo` has only `Foo`'s `DRI`, not the actual reference +to `Foo`'s `Documentable` object. + +#### Example + +For an example of how a `DRI` can look like, let's take the `limitedParallelism` function from `kotlinx.coroutines`: + +```kotlin +package kotlinx.coroutines + +import ... + +public abstract class MainCoroutineDispatcher : CoroutineDispatcher() { + + override fun limitedParallelism(parallelism: Int): CoroutineDispatcher { + ... + } +} +``` + +If we were to re-create the DRI of this function in code, it would look something like this: + +```kotlin +DRI( + packageName = "kotlinx.coroutines", + classNames = "MainCoroutineDispatcher", + callable = Callable( + name = "limitedParallelism", + receiver = null, + params = listOf( + TypeConstructor( + fullyQualifiedName = "kotlin.Int", + params = emptyList() + ) + ) + ), + target = PointingToDeclaration, + extra = null +) +``` + +If you format it as `String`, it would look like this: + +``` +kotlinx.coroutines/MainCoroutineDispatcher/limitedParallelism/#kotlin.Int/PointingToDeclaration/ +``` + +### SourceSetDependent + +`SourceSetDependent` helps handling multiplatform data by associating platform-specific data (declared with either +`expect` or `actual` modifier) with particular +[source sets](https://kotlinlang.org/docs/multiplatform-discover-project.html#source-sets). + +This comes in handy if `expect`/`actual` declarations differ. For instance, the default value for `actual` might differ +from that declared in `expect`, or code comments written for `expect` might be different from what's written +for `actual`. + +Under the hood, it's a `typealias` to a `Map`: + +```kotlin +typealias SourceSetDependent<T> = Map<DokkaSourceSet, T> +``` + +### ExtraProperty + +`ExtraProperty` is used to store any additional information that falls outside of the regular model. It is highly +recommended to use extras to provide any additional information when creating custom Dokka plugins. + +This element is a bit more complex, so you can read more about how to use it +[in a separate section](extra.md). + +___ + +## Documentation model + +Documentation model is used alongside Documentables to store data obtained by parsing +code comments (such as `KDoc`/`Javadoc`). + +### DocTag + +`DocTag` describes a specific documentation syntax element. + +It's universal across source languages. For instance, DocTag `B` is the same for `**bold**` in `Kotlin` and +`<b>bold</b>` in `Java`. + +However, some `DocTag` elements are specific to a certain language, there are many such examples for `Java` +because it allows HTML tags inside `Javadoc` comments, some of which are simply not possible to reproduce with `Markdown`. + +`DocTag` elements can be deeply nested with other `DocTag` children elements. + +Examples: + +```kotlin +data class H1( + override val children: List<DocTag> = emptyList(), + override val params: Map<String, String> = emptyMap() +) : DocTag() + +data class H2( + override val children: List<DocTag> = emptyList(), + override val params: Map<String, String> = emptyMap() +) : DocTag() + +data class Strikethrough( + override val children: List<DocTag> = emptyList(), + override val params: Map<String, String> = emptyMap() +) : DocTag() + +data class Strong( + override val children: List<DocTag> = emptyList(), + override val params: Map<String, String> = emptyMap() +) : DocTag() + +data class CodeBlock( + override val children: List<DocTag> = emptyList(), + override val params: Map<String, String> = emptyMap() +) : Code() + +``` + +### TagWrapper + +`TagWrapper` describes the whole comment description or a specific comment tag. +For example: `@see` / `@author` / `@return`. + +Since each such section may contain formatted text inside of it, each `TagWrapper` has `DocTag` children. + +```kotlin +/** + * @author **Ben Affleck* + * @return nothing, except _sometimes_ it may throw an [Error] + */ +fun foo() {} +``` + +### DocumentationNode + +`DocumentationNode` acts as a container for multiple `TagWrapper` elements for a specific `Documentable`, usually +used like this: + +```kotlin +data class DFunction( + ... + val documentation: SourceSetDependent<DocumentationNode>, + ... +) +``` diff --git a/docs/src/doc/docs/developer_guide/architecture/data_model/extra.md b/docs/src/doc/docs/developer_guide/architecture/data_model/extra.md new file mode 100644 index 00000000..0abbc70e --- /dev/null +++ b/docs/src/doc/docs/developer_guide/architecture/data_model/extra.md @@ -0,0 +1,99 @@ +# Extra + +## Introduction + +`ExtraProperty` classes are used both by [Documentable](documentables.md) and [Content](page_content.md#content-model) +models. + +Source code for `ExtraProperty`: + +```kotlin +interface ExtraProperty<in C : Any> { + interface Key<in C : Any, T : Any> { + fun mergeStrategyFor(left: T, right: T): MergeStrategy<C> = MergeStrategy.Fail { + throw NotImplementedError("Property merging for $this is not implemented") + } + } + + val key: Key<C, *> +} +``` + +To declare a new extra, you need to implement `ExtraProperty` interface. It is advised to use following pattern +when declaring new extras: + +```kotlin +data class CustomExtra( + [any data relevant to your extra], + [any data relevant to your extra] +): ExtraProperty<Documentable> { + override val key: CustomExtra.Key<Documentable, *> = CustomExtra + companion object : CustomExtra.Key<Documentable, CustomExtra> +} +``` + +Merge strategy (`mergeStrategyFor` method) for extras is invoked during +[merging](../extension_points/core_extensions.md#documentablemerger) if documentables from different +[source sets](https://kotlinlang.org/docs/multiplatform-discover-project.html#source-sets) each +have their own `Extra` of the same type. + +## PropertyContainer + +All extras for `ContentNode` and `Documentable` classes are stored in `PropertyContainer<C : Any>` class instances. + +```kotlin +data class DFunction( + ... + override val extra: PropertyContainer<DFunction> = PropertyContainer.empty() + ... +) : WithExtraProperties<DFunction> +``` + +`PropertyContainer` has a number of convenient functions for handling extras in a collection-like manner. + +The `C` generic class parameter limits the type of properties that can be stored in the container - it must +match generic `C` class parameter from `ExtraProperty` interface. This allows creating extra properties +which can only be stored in a specific `Documentable`. + +## Usage example + +In following example we will create a `DFunction`-only property, store it and then retrieve its value: + +```kotlin +data class CustomExtra(val customExtraValue: String) : ExtraProperty<DFunction> { + override val key: ExtraProperty.Key<Documentable, *> = CustomExtra + companion object: ExtraProperty.Key<Documentable, CustomExtra> +} + +fun DFunction.withCustomExtraProperty(data: String): DFunction { + return this.copy( + extra = extra + CustomExtra(data) + ) +} + +fun DFunction.getCustomExtraPropertyValue(): String? { + return this.extra[CustomExtra]?.customExtraValue +} +``` + +___ + +You can also use extras as markers, without storing any data in them: + +```kotlin + +object MarkerExtra : ExtraProperty<Any>, ExtraProperty.Key<Any, MarkerExtra> { + override val key: ExtraProperty.Key<Any, *> = this +} + +fun Documentable.markIfFunction(): Documentable { + return when(this) { + is DFunction -> this.copy(extra = extra + MarkerExtra) + else -> this + } +} + +fun WithExtraProperties<Documentable>.isMarked(): Boolean { + return this.extra[MarkerExtra] != null +} +``` diff --git a/docs/src/doc/docs/developer_guide/architecture/data_model/page_content.md b/docs/src/doc/docs/developer_guide/architecture/data_model/page_content.md new file mode 100644 index 00000000..54ded235 --- /dev/null +++ b/docs/src/doc/docs/developer_guide/architecture/data_model/page_content.md @@ -0,0 +1,140 @@ +# Page / Content Model + +Even though `Page` and `Content` models reside on the same level (under `Page`), it's easier to view it as two different +models altogether, even though `Content` is only used in conjunction with and inside `Page` model. + +## Page + +Page model represents the structure of documentation pages to be generated. During rendering, each page +is processed separately, so one page corresponds to exactly one output file. + +Page model is independent of the final output format, in other words it's universal. Which extension the pages +should be created as (`.html`, `.md`, etc) and how is up to the `Renderer`. + +Subclasses of `PageNode` represent different kinds of rendered pages, such as `ModulePage`, `PackagePage`, +`ClasslikePage`, `MemberPage` (properties, functions), etc. + +The Page Model is a tree structure, with `RootPageNode` at the root. + +Here's an example of how an arbitrary `Page` tree might look like for a module with 3 packages, one of which contains +a top level function, top level property and a class, inside which there's a function and a property: + +```mermaid +flowchart TD + RootPageNode --> firstPackage[PackagePageNode] + RootPageNode --> secondPackage[PackagePageNode] + RootPageNode --> thirdPackage[PackagePageNode] + firstPackage --> firstPackageFirstMember[MemberPageNode - Function] + firstPackage --> firstPackageSecondMember[MemberPageNode - Property] + firstPackage ---> firstPackageClasslike[ClasslikePageNode - Class] + firstPackageClasslike --> firstPackageClasslikeFirstMember[MemberPageNode - Function] + firstPackageClasslike --> firstPackageClasslikeSecondMember[MemberPageNode - Property] + secondPackage --> etcOne[...] + thirdPackage --> etcTwo[...] +``` + +Almost all pages are derivatives of `ContentPage` - it's the type of `Page` that has `Content` on it. + +## Content Model + +Content model describes how the actual `Page` content is presented. The important thing to understand is that it's +also output-format independent and is universal. + +Content model is essentially a set of building blocks that you can put together to represent some content. +Have a look at subclasses of `ContentNode`: `ContentText`, `ContentList`, `ContentTable`, `ContentCodeBlock`, +`ContentHeader` and so on. You can group content together with `ContentGroup` - for instance, +to wrap all children with some style. + +```kotlin +// real example of composing content using `DocumentableContentBuilder` DSL +orderedList { + item { + text("This list contains a nested table:") + table { + header { + text("Col1") + text("Col2") + } + row { + text("Text1") + text("Text2") + } + } + } + item { + group(styles = setOf(TextStyle.Bold)) { + text("This is bald") + text("This is also bald") + } + } +} +``` + +It is then responsibility of `Renderer` (i.e specific output format) to render it the way it wants. + +For instance, `HtmlRenderer` might render `ContentCodeBlock` as `<code>text</code>`, but `CommonmarkRenderer` might +render it using backticks. + +___ + +### DCI + +Each node is identified by unique `DCI`, which stands for _Dokka Content Identifier_. `DCI` aggregates `DRI`s of all +`Documentables` that make up a specific `ContentNode`. + +```kotlin +data class DCI(val dri: Set<DRI>, val kind: Kind) +``` + +All references to other nodes (other than direct ownership) are described using `DCI`. + +### ContentKind + +`ContentKind` represents a grouping of content of one kind that can can be rendered as part of a composite +page (one tab/block within a class's page, for instance). + +For instance, on the same page that describes a class you can have multiple sections (== `ContentKind`). +One to describe functions, one to describe properties, another one to describe constructors and so on. + +### Styles + +Each `ContentNode` has `styles` property in case you want to incidate to `Renderer` that this content needs to be +displayed in a certain way. + +```kotlin +group(styles = setOf(TextStyle.Paragraph)) { + text("Text1", styles = setOf(TextStyle.Bold)) + text("Text2", styles = setOf(TextStyle.Italic)) +} +``` + +It is then responsibility of `Renderer` (i.e specific output format) to render it the way it wants. For instance, +`HtmlRenderer` might render `TextStyle.Bold` as `<b>text</b>`, but `CommonmarkRenderer` might render it as `**text**`. + +There's a number of existing styles that you can use, most of them are supported by `HtmlRenderer` out of the box: + +```kotlin +// for code highlighting +enum class TokenStyle : Style { + Keyword, Punctuation, Function, Operator, Annotation, + Number, String, Boolean, Constant, Builtin, ... +} + +enum class TextStyle : Style { + Bold, Italic, Strong, Strikethrough, Paragraph, ... +} + +enum class ContentStyle : Style { + TabbedContent, RunnableSample, Wrapped, Indented, ... +} +``` + +### Extra + +`ExtraProperty` is used to store any additional information that falls outside of the regular model. It is highly +recommended to use extras to provide any additional information when creating custom Dokka plugins. + +All `ExtraProperty` elements from `Documentable` model are propagated into `Content` model and are available +for `Renderer`. + +This element is a bit complex, so you can read more about how to use it [in a separate section](extra.md). diff --git a/docs/src/doc/docs/developer_guide/architecture/extension_points/base_extensions.md b/docs/src/doc/docs/developer_guide/architecture/extension_points/base_extensions.md new file mode 100644 index 00000000..16a52fab --- /dev/null +++ b/docs/src/doc/docs/developer_guide/architecture/extension_points/base_extensions.md @@ -0,0 +1,13 @@ +# Base extensions + +`DokkaBase` class is a base plugin which defines a number of default implementations for `CoreExtensions` as well as +declares its own, more high-level extension points to be used from other plugins and output formats. + +It's very convenient to use extension points and defaults defined in `DokkaBase` if you have an idea for a simple +plugin that only needs to provide a few extensions or change a single extension point and have everything else be the +default. + +`DokkaBase` is used extensively for Dokka's own output formats such as `HTML`, `Markdown`, `Mathjax` and others. + +You can learn how to add/use/override/configure extensions and extension points in +[Introduction to Extensions](introduction.md), all the information is applicable to `DokkaBase` plugin as well. diff --git a/docs/src/doc/docs/developer_guide/architecture/extension_points/core_extensions.md b/docs/src/doc/docs/developer_guide/architecture/extension_points/core_extensions.md new file mode 100644 index 00000000..381a9596 --- /dev/null +++ b/docs/src/doc/docs/developer_guide/architecture/extension_points/core_extensions.md @@ -0,0 +1,151 @@ +# Core extension points + +Core extension points represent the main stages of generating documentation. + +These extension points are plugin and output format independent, meaning it's the very core functionality and as +low-level as can get. For higher-level extension functions that can be used in different output formats, have a look at +[Base extensions](base_extensions.md) defined in `DokkaBase`. + +You can find all core extensions in `CoreExtensions` class: +```kotlin +object CoreExtensions { + val preGenerationCheck by coreExtensionPoint<PreGenerationChecker>() + val generation by coreExtensionPoint<Generation>() + val sourceToDocumentableTranslator by coreExtensionPoint<SourceToDocumentableTranslator>() + val documentableMerger by coreExtensionPoint<DocumentableMerger>() + val documentableTransformer by coreExtensionPoint<DocumentableTransformer>() + val documentableToPageTranslator by coreExtensionPoint<DocumentableToPageTranslator>() + val pageTransformer by coreExtensionPoint<PageTransformer>() + val renderer by coreExtensionPoint<Renderer>() + val postActions by coreExtensionPoint<PostAction>() +} +``` + +On this page we'll go over each extension point individually. + +## PreGenerationChecker + +`PreGenerationChecker` can be used to run some checks and constraints. + +For instance, `Javadoc` plugin does not support generating documentation for multi-platform projects, so it uses +`PreGenerationChecker` to check for multi-platform +[source sets](https://kotlinlang.org/docs/multiplatform-discover-project.html#source-sets) and fails if it finds any. + +## Generation + +`Generation` is responsible for generating documentation as a whole, utilizing other extension points where applicable. + +There are two implementations at the moment: + +* `AllModulesPageGeneration` - generates multimodule documentation, for instance when `dokkaHtmlMultiModule` task is + invoked. +* `SingleModuleGeneration` - generates documentation for a single module, for instance when `dokkaHtml` task is invoked + +### AllModulesPageGeneration + +`AllModulesPageGeneration` utilizes output generated by `SingleModuleGeneration`. Under the hood it just collects all +pages generated for individual modules and assembles everything together, creating navigation pages between the +modules and so on. + +### SingleModuleGeneration stages + +When developing a feature or a plugin, it's more convenient to think that you are generating documentation for single +module projects, believing that Dokka will somehow take care of the rest in multimodule environment. + +`SingleModuleGeneration` is at heart of generating documentation and utilizes other core extension points, so +it's worth going over its stages. + +Below you can see the transformations of [Dokka's models](../architecture_overview.md#overview-of-data-model) and +extension interfaces responsible for each one. Notice how `Documentables` and `Pages` are transformed multiple times. + +```mermaid +flowchart TD + Input -- SourceToDocumentableTranslator --> doc1[Documentables] + subgraph documentables [ ] + doc1 -- PreMergeDocumentableTransformer --> doc2[Documentables] + doc2 -- DocumentableMerger --> doc3[Documentables] + doc3 -- DocumentableTransformer --> doc4[Documentables] + end + doc4 -- DocumentableToPageTranslator --> page1[Pages] + subgraph ide2 [ ] + page1 -- PageTransformer --> page2[Pages] + end + page2 -- Renderer --> Output +``` + +#### SourceToDocumentableTranslator + +`SourceToDocumentableTranslator` translates sources into documentable model. + +`Kotlin` and `Java` sources are supported by default, but you can analyze any language as long as you can map +it to the [Documentable](../data_model/documentables.md) model. + +For reference, see + +* `DefaultDescriptorToDocumentableTranslator` for `Kotlin` sources translation +* `DefaultPsiToDocumentableTranslator` for `Java` sources translation + +#### PreMergeDocumentableTransformer + +This extension point actually comes from `DokkaBase` and is not a core extension point, but it's used in +`SingleModuleGeneration` nonetheless. If you are implementing your own plugin without relying on `DokkaBase`, +you can either introduce a similar extension point or rely on [DocumentableTransformer](#documentabletransformer) which +will be discussed below. + +`PreMergeDocumentableTransformer` allows applying any transformation to +[Documentables model](../data_model/documentables.md) before different +[source sets](https://kotlinlang.org/docs/multiplatform-discover-project.html#source-sets) are merged. + +Useful if you want to filter/map existing documentables. For instance, if you want to exclude members annotated with +`@Internal`, you most likely need an implementation of `PreMergeDocumentableTransformer`. + +For simple condition-based filtering of documentables consider extending +`SuppressedByConditionDocumentableFilterTransformer` - it implements `PreMergeDocumentableTransformer` and only +requires one function to be overridden. The rest is taken care of. + +#### DocumentableMerger + +`DocumentableMerger` merges all `DModule` instances into one. Only one extension is expected of this type. + +#### DocumentableTransformer + +`DocumentableTransformer` performs the same function as `PreMergeDocumentableTransformer`, but after merging source +sets. + +Notable example is `InheritorsExtractorTransformer`, it extracts inherited classes data across +[source sets](https://kotlinlang.org/docs/multiplatform-discover-project.html#source-sets) and creates an inheritance +map. + +#### DocumentableToPageTranslator + +`DocumentableToPageTranslator` is responsible for creating pages and their content. See +[Page/Content model](../data_model/page_content.md) section for more information and examples. + +Different output formats can either use the same page structure or define their own in case it needs to be different. + +Only a single extension of this type is expected to be registered. + +#### PageTransformer + +`PageTransformer` is useful if you need to add/remove/modify generated pages or their content. + +Plugins like `mathjax` can add `.js` scripts to pages using this extension point. + +If you want all overloaded functions to be rendered on the same page (instead of separate ones), +you can also use `PageTransformer` to delete excessive pages and combine them into a new single one. + +#### Renderer + +`Renderer` - defines rules on what to do with pages and their content, which files to create and how to display +it properly. + +Output format implementations should use `Renderer` extension point. Notable examples are `HtmlRenderer` +and `CommonmarkRenderer`. + +## PostAction + +`PostAction` is useful for when you want to run some actions after the documentation has been generated - for instance +if you want to move some files around. + +[Versioning plugin](../../../user_guide/plugins/versioning-plugin.md) utilizes `PostAction` in order to move +generated documentation to versioned folders. diff --git a/docs/src/doc/docs/developer_guide/architecture/extension_points/introduction.md b/docs/src/doc/docs/developer_guide/architecture/extension_points/introduction.md new file mode 100644 index 00000000..877d14e9 --- /dev/null +++ b/docs/src/doc/docs/developer_guide/architecture/extension_points/introduction.md @@ -0,0 +1,163 @@ +# Introduction to extension points + +In this section you can learn how to create new extension points, how to use and configure existing ones and +how to query for extensions when generating documentation. + +## Declaring extension points + +If you are writing a plugin, you can create your own extension point that other developers (or you) can use later on +in some other part of code. + +```kotlin +class MyPlugin : DokkaPlugin() { + val sampleExtensionPoint by extensionPoint<SampleExtensionPointInterface>() +} + +interface SampleExtensionPointInterface { + fun doSomething(input: Input): List<Output> +} + +class Input +class Output +``` + +Usually you would want to provide some default implementation(s) for your extension point, you can do that +within the same plugin class by extending an extension point you've just created. +See [Extending from extension points](#extending-from-extension-points) for examples. + +## Extending from extension points + +You can use extension points to provide your own implementation(s) in order to customize plugin's behaviour. + +You can do that within the same class as the extension point itself: + +```kotlin +open class MyPlugin : DokkaPlugin() { + val sampleExtensionPoint by extensionPoint<SampleExtensionPointInterface>() + + val defaultSampleExtension by extending { + sampleExtensionPoint with DefaultSampleExtension() + } +} + +... + +class DefaultSampleExtension : SampleExtensionPointInterface { + override fun doSomething(input: Input): List<Output> = listOf() +} +``` + +___ + +If you want to extend someone else's plugin (including `DokkaBase`), you can use plugin querying API to do that. +In the example below we will extend `MyPlugin` that was created above with our own implementation of +`SampleExtensionPointInterface`. + +```kotlin +class MyExtendedPlugin : DokkaPlugin() { + val mySampleExtensionImplementation by extending { + plugin<MyPlugin>().sampleExtensionPoint with SampleExtensionImpl() + } +} + +class SampleExtensionImpl : SampleExtensionPointInterface { + override fun doSomething(input: Input): List<Output> = listOf() +} + +``` + +### Providing + +If you need to have access to `DokkaContext` in order to create an extension, you can use `providing` instead. + +```kotlin +val defaultSampleExtension by extending { + sampleExtensionPoint providing { context -> + // can use context to query other extensions or get configuration + DefaultSampleExtension() + } +} +``` + +You can read more on what you can do with `context` in [Obtaining extension instance](#obtaining-extension-instance). + +### Override + +By extending an extension point, you are registering an _additional_ extension. This behaviour is expected for some +extension points, for instance `Documentable` transformers, since all transformers do their own transformations and all +of them will be invoked before proceeding. + +However, a plugin can expect only a single registered extension for an extension point. In this case, you can `override` +existing registered extensions: + +```kotlin +class MyExtendedPlugin : DokkaPlugin() { + private val myPlugin by lazy { plugin<MyPlugin>() } + + val mySampleExtensionImplementation by extending { + (myPlugin.sampleExtensionPoint + with SampleExtensionImpl() + override myPlugin.defaultSampleExtension) + } +} +``` + +This is also useful if you wish to override some extension from `DokkaBase` to disable or alter it. + +### Order + +Sometimes the order in which extensions are invoked matters. This is something you can control as well using `order`: + +```kotlin +class MyExtendedPlugin : DokkaPlugin() { + private val myPlugin by lazy { plugin<MyPlugin>() } + + val mySampleExtensionImplementation by extending { + myPlugin.sampleExtensionPoint with SampleExtensionImpl() order { + before(myPlugin.firstExtension) + after(myPlugin.thirdExtension) + } + } +} +``` + +### Conditional apply + +If you want your extension to be registered only if some condition is `true`, you can use `applyIf`: + +```kotlin +class MyExtendedPlugin : DokkaPlugin() { + private val myPlugin by lazy { plugin<MyPlugin>() } + + val mySampleExtensionImplementation by extending { + myPlugin.sampleExtensionPoint with SampleExtensionImpl() applyIf { + Random.Default.nextBoolean() + } + } +} +``` + +## Obtaining extension instance + +After an extension point has been [created](#declaring-extension-points) and some extension has been +[registered](#extending-from-extension-points), you can use `query` and `querySingle` to find all or just a single +implementation for it. + +```kotlin +class MyExtension(context: DokkaContext) { + // returns all registered extensions for this extension point + val allSampleExtensions = context.plugin<MyPlugin>().query { sampleExtensionPoint } + + // will throw an exception if more than one extension is found + // use if you expect only a single extension to be registered for this extension point + val singleSampleExtensions = context.plugin<MyPlugin>().querySingle { sampleExtensionPoint } + + fun invoke() { + allSampleExtensions.forEach { it.doSomething(Input()) } + + singleSampleExtensions.doSomething(Input()) + } +} +``` + +In order to have access to context you can use [providing](#providing) when registering this as an extension. diff --git a/docs/src/doc/docs/developer_guide/data_model.md b/docs/src/doc/docs/developer_guide/data_model.md deleted file mode 100644 index ce0b98ad..00000000 --- a/docs/src/doc/docs/developer_guide/data_model.md +++ /dev/null @@ -1,103 +0,0 @@ -# Dokka Data Model - -There a four data models that Dokka uses: Documentable Model, Documentation Model, Page Model and Content Model. - -## Documentable Model - -Documentable model represents parsed data, returned by compiler analysis. It retains basic order structure of parsed `Psi` or `Descriptor` models. - -After creation, it is a collection of trees, each with `DModule` as a root. After the Merge step, all trees are folded into one. - -The main building block of this model is `Documentable` class, that is a base class for all more specific types that represents elements of parsed Kotlin and Java classes with pretty self-explanatory names: `DPackage`, `DFunction` and so on. `DClasslike` is a base for class-like elements, such as Classes, Enums, Interfaces and so on. - -There are three non-documentable classes important for the model: `DRI`, `SourceSetDependent` and `ExtraProperty`. - -* `DRI` (Dokka Resource Identifier) is a unique value that identifies specific `Documentable`. All references to other documentables different than direct ownership are described using DRIs. For example, `DFunction` with parameter of type `X` has only X's DRI, not the actual reference to X's Documentable object. -* `SourceSetDependent` is a map that handles multiplatform data, by connecting platform-specific data, declared with either `expect` or `actual` modifier, to a particular Source Set -* `ExtraProperty` is used to store any additional information that falls outside of regular model. It is highly recommended to use extras to provide any additional information when creating custom Dokka plugins. This element is a bit more complex, so you can read more about how to use it below. - -### `ExtraProperty` class usage - -`ExtraProperty` classes are used both by Documentable and Content models. To declare a new extra, you need to implement `ExtraProperty` interface. - -```kotlin -interface ExtraProperty<in C : Any> { - interface Key<in C : Any, T : Any> { - fun mergeStrategyFor(left: T, right: T): MergeStrategy<C> = MergeStrategy.Fail { - throw NotImplementedError("Property merging for $this is not implemented") - } - } - - val key: Key<C, *> -} -``` - -It is advised to use following pattern when declaring new extras: - -```kotlin -data class CustomExtra( [any values relevant to your extra ] ): ExtraProperty<Documentable> { - companion object : CustomExtra.Key<Documentable, CustomExtra> - override val key: CustomExtra.Key<Documentable, *> = CustomExtra -} -``` -Merge strategy for extras is invoked only if merged objects have different values for same Extra. If you don't expect it to happen, you can omit implementing `mergeStrategyFor` function. - -All extras for `ContentNode` and `Documentable` classes are stored in `PropertyContainer<C : Any>` class instances. The `C` generic class parameter limits the type of properties, that can be stored in the container - it must match generic `C` class parameter from `ExtraProperty` interface. For example, if you would create `DFunction`-only `ExtraProperty`, it will be limited to be added only to `PropertyContainer<DFunction>`. - -In following example we will create `Documentable`-only property, store it in the container and then retrieve its value: - -```kotlin -data class CustomExtra(val customExtraValue: String) : ExtraProperty<Documentable> { - - companion object: ExtraProperty.Key<Documentable, CustomExtra> - - override val key: ExtraProperty.Key<Documentable, *> = CustomExtra -} - -val extra : PropertyContainer<DFunction> = PropertyContainer.withAll( - CustomExtra("our value") -) - -val customExtraValue : String? = extra[CustomProperty]?.customExtraValue -``` - -You can also use extras as markers, without storing any data in them: - -```kotlin - -object MarkerExtra : ExtraProperty<Any>, ExtraProperty.Key<Any, MarkerExtra> { - override val key: ExtraProperty.Key<Any, *> = this -} - -val extra : PropertyContainer<Any> = PropertyContainer.withAll(MarkerExtra) - -val isMarked : Boolean = extra[MarkerExtra] != null - -``` - -## Documentation Model - -Documentation model is used along Documentable Model to store data obtained by parsing code commentaries. - -There are three important classes here: - -* `DocTag` describes a specific documentation syntax element, for example: header, footer, list, link, raw text, paragraph, etc. -* `TagWrapper` described a whole comment description or a specific comment tag, for example: @See, @Returns, @Author; and holds consisting `DocTag` elements -* `DocumentationNode` acts as a container for `TagWrappers` for a specific `Documentable` - -DocumentationNodes are references by a specific `Documentable` - -## Page Model - -Page Model represents the structure of future generated documentation pages and is independent of the final output format, which each node corresponding to exactly one output file. `Renderer` is processing each page separately.Subclasses of `PageNode` represents different kinds of rendered pages for Modules, Packages, Classes etc. - -The Page Model is a tree structure, with `RootPageNode` being the root. - -## Content Model - -Content Model describes how the actual page content is presented. It organizes it's structure into groups, tables, links, etc. Each node is identified by unique `DCI` (Dokka Content Identifier) and all references to other nodes different than direct ownership are described using DCIs. - -`DCI` aggregates `DRI`s of all `Documentables` that make up specific `ContentNode`. - -Also, all `ExtraProperty` info from consisting `Documentable`s is propagated into Content Model and available for `Renderer`. - diff --git a/docs/src/doc/docs/developer_guide/extension_points.md b/docs/src/doc/docs/developer_guide/extension_points.md deleted file mode 100644 index 08b05e20..00000000 --- a/docs/src/doc/docs/developer_guide/extension_points.md +++ /dev/null @@ -1,223 +0,0 @@ -# Extension points - -## Core extension points - -We will discuss all base extension points along with the steps, that `DokkaGenerator` does to build a documentation. - -### Setting up Kotlin and Java analysis process and initializing plugins - -The provided Maven / CLI / Gradle configuration is read.Then, all the `DokkaPlugin` classes are loaded and the extensions are created. - - No entry points here. - -### Creating documentation models - -The documentation models are created. - -This step uses `DokkaCore.sourceToDocumentableTranslator` entry point. All extensions registered using this entry point will be invoked. Each of them is required to implement `SourceToDocumentableTranslator` interface: - -```kotlin -interface SourceToDocumentableTranslator { - fun invoke(sourceSet: SourceSetData, context: DokkaContext): DModule -} -``` -By default, two translators are created: - -* `DefaultDescriptorToDocumentableTranslator` that handles Kotlin files -* `DefaultPsiToDocumentableTranslator` that handles Java files - -After this step, all data from different source sets and languages are kept separately. - -If you are using Kotlin it is recommended to make use of the asynchronous version, providing you implementation of `invokeSuspending`: - -```kotlin -interface AsyncSourceToDocumentableTranslator : SourceToDocumentableTranslator { - suspend fun invokeSuspending(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext): DModule -} -``` - -### Pre-merge documentation transform - -Here you can apply any transformation to model data before different source sets are merged. - -This step uses `DokkaCore.preMergeDocumentableTransformer` entry point. All extensions registered using this entry point will be invoked. Each of them is required to implement `PreMergeDocumentableTransformer` interface: - -```kotlin -interface PreMergeDocumentableTransformer { - operator fun invoke(modules: List<DModule>, context: DokkaContext): List<DModule> -} -``` -By default, three transformers are created: - -* `DocumentableVisibilityFilter` that, depending on configuration, filters out all private members from declared packages -* `ActualTypealiasAdder` that handles Kotlin typealiases -* `ModuleAndPackageDocumentationTransformer` that creates documentation content for models and packages itself - -### Merging - -All `DModule` instances are merged into one. - -This step uses `DokkaCore.documentableMerger` entry point. It is required to have exactly one extension registered for this entry point. Having more will trigger an error, unless only one is not overridden. - -The extension is required to implement `DocumentableMerger` interface: - -```kotlin -interface DocumentableMerger { - operator fun invoke(modules: Collection<DModule>, context: DokkaContext): DModule -} -``` - -By default, `DefaultDocumentableMerger` is created. This extension is treated as a fallback, so it can be overridden by a custom one. - -### Merged data transformation - -You can apply any transformation to already merged data - -This step uses `DokkaCore.documentableTransformer` entry point. All extensions registered using this entry point will be invoked. Each of them is required to implement `DocumentableTransformer` interface: - -```kotlin -interface DocumentableTransformer { - operator fun invoke(original: DModule, context: DokkaContext): DModule -} -``` - -By default, `InheritorsExtractorTransformer` is created, that extracts inherited classes data across source sets and creates inheritance map. - -### Creating page models - -The documentable model is translated into page format, that aggregates all tha data that will be available for different pages of documentation. - -This step uses `DokkaCore.documentableToPageTranslator` entry point. It is required to have exactly one extension registered for this entry point. Having more will trigger an error, unless only one is not overridden. - -The extension is required to implement `DocumentableToPageTranslator` interface: - -```kotlin -interface DocumentableToPageTranslator { - operator fun invoke(module: DModule): ModulePageNode -} -``` - -By default, `DefaultDocumentableToPageTranslator` is created. This extension is treated as a fallback, so it can be overridden by a custom one. - -### Transforming page models - -You can apply any transformations to paged data. - -This step uses `DokkaCore.pageTransformer` entry point. All extensions registered using this entry point will be invoked. Each of them is required to implement `PageTransformer` interface: - -```kotlin -interface PageTransformer { - operator fun invoke(input: RootPageNode): RootPageNode -} -``` -By default, two transformers are created: - -* `PageMerger` merges some pages depending on `MergeStrategy` -* `DeprecatedStrikethroughTransformer` marks all deprecated members on every page - -### Rendering - -All pages are rendered to desired format. - -This step uses `DokkaCore.renderer` entry point. It is required to have exactly one extension registered for this entry point. Having more will trigger an error, unless only one is not overridden. - -The extension is required to implement `Renderer` interface: - -```kotlin -interface Renderer { - fun render(root: RootPageNode) -} -``` - -By default, only `HtmlRenderer`, that extends basic `DefaultRenderer`, is created, but it will be registered only if configuration parameter `format` is set to `html`. Using any other value without providing valid renderer will cause Dokka to fail. - -## Multimodule page generation endpoints - -Multimodule page generation is a separate process, that declares two additional entry points: - -### Multimodule page creation - -Generation of the page that points to all module for which we generates documentation. - -This step uses `CoreExtensions.allModulePageCreator` entry point. It is required to have exactly one extension registered for this entry point. Having more will trigger an error, unless only one is not overridden. - -The extension is required to implement `PageCreator` interface: - -```kotlin -interface PageCreator { - operator fun invoke(): RootPageNode -} -``` - -By default, `MultimodulePageCreator` is created. This extension is treated as a fallback, so it can be replaced by a custom one. - -### Multimodule page transformation - -Additional transformation that we might apply for multimodule page. - -This step uses `CoreExtensions.allModulePageTransformer` entry point. All extensions registered using this entry point will be invoked. Each of them is required to implement common `PageTransformer` interface. - -## Default extensions' extension points - -Default core extension points already have an implementation for providing basic Dokka functionality. All of them are declared in `DokkaBase` plugin. If you don't want this default extensions to load, all you need to do is not load Dokka base and load your plugin instead. - -```kotlin -val customPlugin by configurations.creating - -dependencies { - customPlugin("[custom plugin load signature]") -} -tasks { - val dokka by getting(DokkaTask::class) { - pluginsConfig = alternativeAndIndependentPlugins - outputDirectory = dokkaOutputDir - outputFormat = "html" - [...] - } -} -``` - - You will then need to implement extensions for all core extension points. - -`DokkaBase` also register several new extension points, with which you can change default behaviour of `DokkaBase` extensions. In order to use them, you need to add `dokka-base` to you dependencies: - -```kotlin -compileOnly("org.jetbrains.dokka:dokka-base:<dokka_version>") -``` - -Then, you need to obtain `DokkaBase` instance using `plugin` function: - -```kotlin -class SamplePlugin : DokkaPlugin() { - - val dokkaBase = plugin<DokkaBase>() - - val extension by extending { - dokkaBase.pageMergerStrategy with SamplePageMergerStrategy order { - before(dokkaBase.fallbackMerger) - } - } -} - -object SamplePageMergerStrategy: PageMergerStrategy { - override fun tryMerge(pages: List<PageNode>, path: List<String>): List<PageNode> { - ... - } - -} -``` - -### Following extension points are available with base plugin - -| Entry point | Function | Required interface | Used by | Singular | Preregistered extensions -|---|:---|:---:|:---:|:---:|:---:| -| `pageMergerStrategy` | determines what kind of pages should be merged | `PageMergerStrategy` | `PageMerger` | false | `FallbackPageMergerStrategy` `SameMethodNamePageMergerStrategy` | -| `commentsToContentConverter` | transforms comment model into page content model | `CommentsToContentConverter` | `DefaultDocumentableToPageTransformer` `SignatureProvider` | true | `DocTagToContentConverter` | -| `signatureProvider` | provides representation of methods signatures | `SignatureProvider` | `DefaultDocumentableToPageTransformer` | true | `KotlinSignatureProvider` | -| `locationProviderFactory` | provides `LocationProvider` instance that returns paths for requested elements | `LocationProviderFactory` | `DefaultRenderer` `HtmlRenderer` `PackageListService` | true | `DefaultLocationProviderFactory` which returns `DefaultLocationProvider` | -| `externalLocationProviderFactory` | provides `ExternalLocationProvider` instance that returns paths for elements that are not part of generated documentation | `ExternalLocationProviderFactory` | `DefaultLocationProvider` | false | `JavadocExternalLocationProviderFactory` `DokkaExternalLocationProviderFactory` | -| `outputWriter` | writes rendered pages files | `OutputWriter` | `DefaultRenderer` `HtmlRenderer` | true | `FileWriter`| -| `htmlPreprocessors` | transforms page content before HTML rendering | `PageTransformer`| `DefaultRenderer` `HtmlRenderer` | false | `RootCreator` `SourceLinksTransformer` `NavigationPageInstaller` `SearchPageInstaller` `ResourceInstaller` `StyleAndScriptsAppender` `PackageListCreator` | -| `samplesTransformer` | transforms content for code samples for HTML rendering | `SamplesTransformer` | `HtmlRenderer` | true | `DefaultSamplesTransformer` | - - diff --git a/docs/src/doc/docs/developer_guide/introduction.md b/docs/src/doc/docs/developer_guide/introduction.md index f8e5e6c7..feb601fe 100644 --- a/docs/src/doc/docs/developer_guide/introduction.md +++ b/docs/src/doc/docs/developer_guide/introduction.md @@ -1,124 +1,19 @@ -# Guide to Dokka Plugin development +# Developer guides -## Building Dokka +The purpose of `Developer guides` section is to get you acquainted with Dokka's internals so that you can start developing +your own plugins or contributing features and fixes to Dokka itself. -Dokka is built with Gradle. To build it, use `./gradlew build`. -Alternatively, open the project directory in IntelliJ IDEA and use the IDE to build and run Dokka. +If you want to start hacking on Dokka right away, the only thing you need to be aware of is the +[general workflow](workflow.md), it will teach you how to build, debug and test Dokka locally. -Here's how to import and configure Dokka in IntelliJ IDEA 2019.3: +If you want to get into plugin development quick, see +[Introduction to plugin development](plugin-development/introduction.md). -* Select "Open" from the IDEA welcome screen, or File > Open if a project is - already open -* Select the directory with your clone of Dokka - -!!! note - IDEA may have an error after the project is initally opened; it is OK - to ignore this as the next step will address this error +If you have time to spare and want to know more about Dokka's internals, its architecture and capabilities, follow +[Architecture overview](architecture/architecture_overview.md) and subsequent sections inside `Internals`. -* After IDEA opens the project, select File > New > Module from existing sources - and select the `build.gradle.kts` file from the root directory of your Dokka clone -* After Dokka is loaded into IDEA, open the Gradle tool window (View > Tool - Windows > Gradle) and click on the top left "Refresh all Gradle projects" - button - - -## Configuration - -tldr: you can use a convenient [plugin template](https://github.com/Kotlin/dokka-plugin-template) to speed up the setup. - -Dokka requires configured `Kotlin plugin` and `dokka-core` dependency. - -```kotlin -plugins { - kotlin("jvm") version "<kotlin_version>" -} - -dependencies { - compileOnly("org.jetbrains.dokka:dokka-core:<dokka_version>") -} - -tasks.withType<KotlinCompile> { - kotlinOptions.jvmTarget = "1.8" -} -``` - -## Building sample plugin - -In order to load a plugin into Dokka, your class must extend `DokkaPlugin` class. A fully qualified name of that class must be placed in a file named `org.jetbrains.dokka.plugability.DokkaPlugin` under `resources/META-INF/services`. -All instances are automatically loaded during Dokka setup using `java.util.ServiceLoader`. - -Dokka provides a set of entry points, for which user can create their own implementations. They must be delegated using `DokkaPlugin.extending(definition: ExtendingDSL.() -> Extension<T, *, *>)` function,that returns a delegate `ExtensionProvider` with supplied definition. - -To create a definition, you can use one of two infix functions`with(T)` or `providing( (DokkaContext) -> T)` where `T` is the type of an extended endpoint. You can also use infix functions: - -* `applyIf( () -> Boolean )` to add additional condition specifying whether or not the extension should be used -* `order((OrderDsl.() -> Unit))` to determine if your extension should be used before or after another particular extension for the same endpoint -* `override( Extension<T, *, *> )` to override other extension. Overridden extension won't be loaded and overridding one will inherit ordering from it. - -Following sample provides custom translator object as a `DokkaCore.sourceToDocumentableTranslator` - -```kotlin -package org.jetbrains.dokka.sample - -import org.jetbrains.dokka.plugability.DokkaPlugin - -class SamplePlugin : DokkaPlugin() { - extension by extending { - DokkaCore.sourceToDocumentableTranslator with CustomSourceToDocumentableTranslator - } -} - -object CustomSourceToDocumentableTranslator: SourceToDocumentableTranslator { - override fun invoke(sourceSet: SourceSetData, context: DokkaContext): DModule -} -``` - -### Registering extension point - -You can register your own extension point using `extensionPoint` function declared in `DokkaPlugin` class - -```kotlin -class SamplePlugin : DokkaPlugin() { - val extensionPoint by extensionPoint<SampleExtensionPointInterface>() -} - -interface SampleExtensionPointInterface -``` - -### Obtaining extension instance - -All registered plugins are accessible with `DokkaContext.plugin` function. All plugins that extends `DokkaPlugin` can use `DokkaPlugin.plugin` function, that uses underlying `DokkaContext` instance. If you want to pass context to your extension, you can obtain it using aforementioned `providing` infix function. - -With plugin instance obtained, you can browse extensions registered for this plugins' extension points using `querySingle` and `query` methods: - -```kotlin - context.plugin<DokkaBase>().query { htmlPreprocessors } - context.plugin<DokkaBase>().querySingle { samplesTransformer } -``` - -You can also browse `DokkaContext` directly, using `single` and `get` methods: - -```kotlin -class SamplePlugin : DokkaPlugin() { - - val extensionPoint by extensionPoint<SampleExtensionPointInterface>() - val anotherExtensionPoint by extensionPoint<AnotherSampleExtensionPointInterface>() - - val extension by extending { - extensionPoint with SampleExtension() - } - - val anotherExtension by extending { - anotherExtensionPoint providing { context -> - AnotherSampleExtension(context.single(extensionPoint)) - } - } -} - -interface SampleExtensionPointInterface -interface AnotherSampleExtensionPointInterface - -class SampleExtension: SampleExtensionPointInterface -class AnotherSampleExtension(sampleExtension: SampleExtensionPointInterface): AnotherSampleExtensionPointInterface -``` +Having read through all the developer guides, you'll have a pretty good unrestanding of Dokka and how to develop +for it. +If you have any questions, feel free to get in touch with maintainers via [Slack](../community/slack.md) or +[GitHub](https://github.com/kotlin/dokka). diff --git a/docs/src/doc/docs/developer_guide/plugin-development/introduction.md b/docs/src/doc/docs/developer_guide/plugin-development/introduction.md new file mode 100644 index 00000000..fbfb32ac --- /dev/null +++ b/docs/src/doc/docs/developer_guide/plugin-development/introduction.md @@ -0,0 +1,59 @@ +# Introduction to plugin development + +In order to have an easier time developing plugins, it's a good idea to go through +[Dokka's internals](../architecture/architecture_overview.md) first to learn more about its +[data model](../architecture/data_model/documentables.md) and +[extensions](../architecture/extension_points/introduction.md). + +## Setup + +### Template + +The easiest way to start is to use the convenient [Dokka plugin template](https://github.com/Kotlin/dokka-plugin-template). +It has pre-configured dependencies, publishing and signing of your artifacts. + +### Manual + +At a bare minimum, Dokka requires `Kotlin Gradle Plugin` and `dokka-core` dependencies: + +```kotlin +plugins { + kotlin("jvm") version "<kotlin_version>" +} + +dependencies { + compileOnly("org.jetbrains.dokka:dokka-core:<dokka_version>") +} + +tasks.withType<KotlinCompile> { + kotlinOptions.jvmTarget = "1.8" +} +``` + +In order to load a plugin into Dokka, your class must extend `DokkaPlugin` class. A fully qualified name of that class +must be placed in a file named `org.jetbrains.dokka.plugability.DokkaPlugin` under `resources/META-INF/services`. +All instances are automatically loaded during Dokka setup using `java.util.ServiceLoader`. + +## Extension points + +Dokka provides a set of entry points for which you can create your own implementations. If you are not sure which +extension point to use, have a look at [core extensions](../architecture/extension_points/core_extensions.md) and +[base extensions](../architecture/extension_points/base_extensions.md). + +You can learn how to declare extension points and use extensions in +[Introduction to Extension points](../architecture/extension_points/introduction.md). + +In case no suitable extension point exists for your use case, do share the details - it might be added in future +versions of Dokka. + +## Example + +You can follow the [sample plugin tutorial](sample-plugin-tutorial.md) which covers creation of a simple plugin: hide members +annotated with your own `@Internal` annotation, that is exclude these members from generated documentation. + +Fore more practical examples, have a look at sources of [community plugins](../../community/plugins-list.md). + +## Help + +If you have any further questions, feel free to get in touch with maintainers via [Slack](../../community/slack.md) or +[GitHub](https://github.com/kotlin/dokka). diff --git a/docs/src/doc/docs/developer_guide/plugin-development/sample-plugin-tutorial.md b/docs/src/doc/docs/developer_guide/plugin-development/sample-plugin-tutorial.md new file mode 100644 index 00000000..fdea0207 --- /dev/null +++ b/docs/src/doc/docs/developer_guide/plugin-development/sample-plugin-tutorial.md @@ -0,0 +1,292 @@ +# Sample plugin tutorial + +We'll go over creating a simple plugin that covers a very common use case: generate documentation for everything except +for members annotated with a custom `@Internal` annotation - they should be hidden. + +The plugin will be tested with the following code: + +```kotlin +package org.jetbrains.dokka.internal.test + +annotation class Internal + +fun shouldBeVisible() {} + +@Internal +fun shouldBeExcludedFromDocumentation() {} +``` + +Expected behavior: function `shouldBeExcludedFromDocumentation` should not be visible in generated documentation. + +Full source code of this tutorial can be found in Dokka's examples under +[hide-internal-api](https://github.com/Kotlin/dokka/examples/plugin/hide-internal-api). + +## Preparing the project + +We'll begin by using [Dokka plugin template](https://github.com/Kotlin/dokka-plugin-template). Press the +`Use this template` button and +[open this project in IntelliJ IDEA](https://www.jetbrains.com/idea/guide/tutorials/working-with-gradle/opening-a-gradle-project/). + +First, let's rename the pre-made `template` package and `MyAwesomeDokkaPlugin` class to something of our own. + +For instance, package can be renamed to `org.example.dokka.plugin` and the class to `HideInternalApiPlugin`: + +```kotlin +package org.example.dokka.plugin + +import org.jetbrains.dokka.plugability.DokkaPlugin + +class HideInternalApiPlugin : DokkaPlugin() { + +} +``` + +After you do that, make sure to update the path to this class in +`resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin`: +```kotlin +org.example.dokka.plugin.HideInternalApiPlugin +``` + +At this point you can also change project name in `settings.gradle.kts` (to `hide-internal-api` in our case) +and `groupId` in `build.gradle.kts`. + +## Extending Dokka + +After preparing the project we can begin extending Dokka with our own extension. + +Having read through [Core extensions](../architecture/extension_points/core_extensions.md), it's clear that we need +a `PreMergeDocumentableTransformer` extension in order to filter out undesired documentables. + +Moreover, the article mentioned a convenient abstract transformer `SuppressedByConditionDocumentableFilterTransformer` +which is perfect for our use case, so we can try to implement it. + +Create a new class, place it next to your plugin and implement the abstract method. You should end up with this: + +```kotlin +package org.example.dokka.plugin + +import org.jetbrains.dokka.base.transformers.documentables.SuppressedByConditionDocumentableFilterTransformer +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.DokkaPlugin + +class HideInternalApiPlugin : DokkaPlugin() {} + +class HideInternalApiTransformer(context: DokkaContext) : SuppressedByConditionDocumentableFilterTransformer(context) { + + override fun shouldBeSuppressed(d: Documentable): Boolean { + return false + } +} +``` + +Now we somehow need to find all annotations applied to `d: Documentable` and see if our `@Internal` annotation is present. +However, it's not very clear how to do that. What usually helps is stopping in debugger and having a look at what fields +and values a given `Documentable` has. + +To do that, we'll need to register our extension point first, then we can publish our plugin and set the breakpoint. + +Having read through [Introduction to extensions](../architecture/extension_points/introduction.md), we now know +how to register our extensions: + +```kotlin +class HideInternalApiPlugin : DokkaPlugin() { + val myFilterExtension by extending { + plugin<DokkaBase>().preMergeDocumentableTransformer providing ::HideInternalApiTransformer + } +} +``` + +At this point we're ready to debug our plugin locally, it should already work, but do nothing. + +## Debugging + +Please read through [Debugging Dokka](../workflow.md#debugging-dokka), it goes over the same steps in more detail +and with examples. Below you will find rough instructions. + +First, let's begin by publishing our plugin to `mavenLocal()`. + +```bash +./gradlew publishToMavenLocal +``` + +This will publish your plugin under the `groupId`, `artifactId` and `version` that you've specified in your +`build.gradle.kts`. In our case it's `org.example:hide-internal-api:1.0-SNAPSHOT`. + +Open a debug project of your choosing that has Dokka configured, and add our plugin to dependencies: + +```kotlin +dependencies { + dokkaPlugin("org.example:hide-internal-api:1.0-SNAPSHOT") +} +``` + +Next, in that project let's run `dokkaHtml` with debug enabled: + +```bash +./gradlew clean dokkaHtml -Dorg.gradle.debug=true --no-daemon +``` + +Switch to the plugin project, set a breakpoint inside `shouldBeSuppressed` and run jvm remote debug. + +If you've done everything correctly, it should stop in debugger and you should be able to observe the values contained +inside `d: Documentable`. + +## Implementing plugin logic + +Now that we've stopped at our breakpoint, let's skip until we see `shouldBeExcludedFromDocumentation` function in the +place of `d: Documentable` (observe the changing `name` property). + +Looking at what's inside the object, you might notice it has 3 values in `extra`, one of which is `Annotations`. +Sounds like something we need! + +Having poked around, we come up with the following monstrosity of a code for determining if a given documentable has +`@Internal` annotation (it can of course be refactored.. later): + +```kotlin +override fun shouldBeSuppressed(d: Documentable): Boolean { + + val annotations: List<Annotations.Annotation> = + (d as? WithExtraProperties<*>) + ?.extra + ?.allOfType<Annotations>() + ?.flatMap { it.directAnnotations.values.flatten() } + ?: emptyList() + + return annotations.any { isInternalAnnotation(it) } +} + +private fun isInternalAnnotation(annotation: Annotations.Annotation): Boolean { + return annotation.dri.packageName == "org.jetbrains.dokka.internal.test" + && annotation.dri.classNames == "Internal" +} +``` + +Seems like we're done with writing our plugin and can begin testing it manually. + +## Manual testing + +At this point, the implementation of your plugin should look roughly like this: + +```kotlin +package org.example.dokka.plugin + +import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.transformers.documentables.SuppressedByConditionDocumentableFilterTransformer +import org.jetbrains.dokka.model.Annotations +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.properties.WithExtraProperties +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.DokkaPlugin + +class HideInternalApiPlugin : DokkaPlugin() { + val myFilterExtension by extending { + plugin<DokkaBase>().preMergeDocumentableTransformer providing ::HideInternalApiTransformer + } +} + +class HideInternalApiTransformer(context: DokkaContext) : SuppressedByConditionDocumentableFilterTransformer(context) { + + override fun shouldBeSuppressed(d: Documentable): Boolean { + val annotations: List<Annotations.Annotation> = + (d as? WithExtraProperties<*>) + ?.extra + ?.allOfType<Annotations>() + ?.flatMap { it.directAnnotations.values.flatten() } + ?: emptyList() + + return annotations.any { isInternalAnnotation(it) } + } + + private fun isInternalAnnotation(annotation: Annotations.Annotation): Boolean { + return annotation.dri.packageName == "org.jetbrains.dokka.internal.test" + && annotation.dri.classNames == "Internal" + } +} +``` + +Bump plugin version in `gradle.build.kts`, publish it to maven local, open the debug project and run `dokkaHtml` +(without debug this time). It should work, you should **not** be able to see `shouldBeExcludedFromDocumentation` +function in generated documentation. + +Manual testing is cool and all, but wouldn't it be better if we could somehow write unit tests for it? Indeed! + +## Unit testing + +You might've noticed that plugin template comes with a pre-made test class. Feel free to move it to another package +and rename it. + +We are mostly interested in a single test case - functions annotated with `@Internal` should be hidden, while all other +public functions should be visible. + +Plugin API comes with a set of convenient test utilities that are used to test Dokka itself, so it covers a wide range +of use cases. When in doubt, see Dokka's tests for reference. + +Below you will find a complete unit test that passes, and the main takeaways below that. + +```kotlin +package org.example.dokka.plugin + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.junit.Test +import kotlin.test.assertEquals + +class HideInternalApiPluginTest : BaseAbstractTest() { + + @Test + fun `should hide annotated functions`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin/basic/Test.kt") + } + } + } + val hideInternalPlugin = HideInternalApiPlugin() + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package org.jetbrains.dokka.internal.test + | + |annotation class Internal + | + |fun shouldBeVisible() {} + | + |@Internal + |fun shouldBeExcludedFromDocumentation() {} + """.trimMargin(), + configuration = configuration, + pluginOverrides = listOf(hideInternalPlugin) + ) { + preMergeDocumentablesTransformationStage = { modules -> + val testModule = modules.single { it.name == "root" } + val testPackage = testModule.packages.single { it.name == "org.jetbrains.dokka.internal.test" } + + val packageFunctions = testPackage.functions + assertEquals(1, packageFunctions.size) + assertEquals("shouldBeVisible", packageFunctions[0].name) + } + } + } +} +``` + +Note that the package of the tested code (inside `testInline` function) is the same as the package that we have +hardcoded in our plugin. Make sure to change that to your own if you are following along, otherwise it will fail. + +Things to note and remember: + +1. Your test class should extend `BaseAbstractTest`, which contains base utility methods for testing. +2. You can configure Dokka to your liking, enable some specific settings, configure + [source sets](https://kotlinlang.org/docs/multiplatform-discover-project.html#source-sets), etc. All done via + `dokkaConfiguration` DSL. +3. `testInline` function is the main entry point for unit tests +4. You can pass plugins to be used in a test, notice `pluginOverrides` parameter +5. You can write asserts for different stages of generating documentation, the main ones being `Documentables` model + generation, `Pages` generation and `Output` generation. Since we implemented our plugin to work during + `PreMergeDocumentableTransformer` stage, we can test it on the same level (that is + `preMergeDocumentablesTransformationStage`). +6. You will need to write asserts using the model of whatever stage you choose. For `Documentable` transformation stage + it's `Documentable`, for `Page` generation stage you would have `Page` model, and for `Output` you can have `.html` + files that you will need to parse with `JSoup` (there are also utilities for that). diff --git a/docs/src/doc/docs/developer_guide/workflow.md b/docs/src/doc/docs/developer_guide/workflow.md new file mode 100644 index 00000000..d5ebdd80 --- /dev/null +++ b/docs/src/doc/docs/developer_guide/workflow.md @@ -0,0 +1,100 @@ +# Workflow + +Whether you're contributing a feature/fix to Dokka itself or developing a separate plugin, there's 3 things +you'll be doing: + +1. Building Dokka / Plugins +2. Using/Testing locally built Dokka in a (debug) project +3. Debugging Dokka / Plugin code + +We'll go over each step individually in this section. + +Examples below will be specific to Gradle and [Gradle’s Kotlin DSL](https://docs.gradle.org/current/userguide/kotlin_dsl.html), +but you can apply the same principles and run/test/debug with CLI/Maven runners and build configurations if you wish. + +## Building Dokka + +Building Dokka is pretty straightforward, with one small caveat: when you run `./gradlew build`, it will run +integration tests as well, which might take some time and will consume a lot of RAM, so you would usually want +to exclude integration tests when building locally. + +```shell +./gradlew build -x integrationTest +``` + +Unit tests which are run as part of `build` should not take much time, but you can also skip it with `-x test`. + +### Troubleshooting build + +#### API check failed for project .. + +If you see messages like `API check failed for project ..` during `build` phase, it indicates that +[binary compatibility check](https://github.com/Kotlin/binary-compatibility-validator) has failed, meaning you've +changed/added/removed some public API. + +If the change was intentional, run `./gradlew apiDump` - it will re-generate `.api` files with signatures, +and you should be able to `build` Dokka with no errors. These updated files need to be committed as well. Maintainers +will review API changes thoroughly, so please make sure it's intentional and rational. + +## Using/testing locally built Dokka + +Having built Dokka locally, you can publish it to `mavenLocal()`. This will allow you to test your changes in another +project as well as debug code remotely. + +1. Change `dokka_version` in `gradle.properties` to something that you will use later on as the dependency version. + For instance, you can set it to something like `1.7.0-my-fix-SNAPSHOT`. This version will be propagated to plugins + that reside inside Dokka's project (such as `mathjax`, `kotlin-as-java`, etc). +2. Publish it to maven local (`./gradlew publishToMavenLocal`). Corresponding artifacts should appear in `~/.m2` +3. In the project you want to generate documentation for or debug on, add maven local as a plugin/dependency + repository: +```kotlin +repositories { + mavenLocal() +} +``` +4. Update your dokka dependency to the version you've just published: +```kotlin +plugins { + id("org.jetbrains.dokka") version "1.7.0-my-fix-SNAPSHOT" +} +``` + +After completing these steps, you should be able to build documentation using your own version of Dokka. + +## Debugging Dokka + +Dokka is essentially a gradle plugin, so you can debug it the same way you would any other gradle plugin. + +Below you'll find instructions on how to debug Dokka's internal logic, but you can apply the same principles if you +wish to debug a plugin which resides in a separate project. + +1. Choose a project to debug on, it needs to have some code for which documentation will be generated. + Prefer using smaller projects that reproduce the exact problem or behaviour you want + since the less code you have, the easier it will be to understand what's going on. You can use example projects + found in [dokka/examples/gradle](https://github.com/Kotlin/dokka/tree/master/examples/gradle), there's both simple + single-module and more complex multimodule/multiplatform examples. +2. For the debug project, set `org.gradle.debug` to `true` in one of the following ways: + + * In your `gradle.properties` add `org.gradle.debug=true` + * When running Dokka tasks:<br/>`./gradlew dokkaHtml -Dorg.gradle.debug=true --no-daemon` + +3. Run desired Dokka task with `--no-daemon`. Gradle should wait until you attach with debugger before proceeding + with the task, so no need to hurry here. + <br/>Example: `./gradlew dokkaHtml -Dorg.gradle.debug=true --no-daemon`. + +4. Open Dokka in IntelliJ IDEA, set a breakpoint and, using remote debug in IntelliJ IDEA, + [Attach to process](https://www.jetbrains.com/help/idea/attaching-to-local-process.html#attach-to-remote) + running on the default port 5005. You can do that either by creating a `Remote JVM Debug` Run/Debug configuration + or by attaching to the process via `Run` -> `Attach to process` + +!!! note + The reason for `--no-daemon` is that + [Gradle daemons](https://docs.gradle.org/current/userguide/gradle_daemon.html) continue to exist even after the task + has completed execution, so you might hang in debug or experience issues with `port was already in use` if you try + to run it again. + + If you previously ran Dokka with daemons and you are already encountering problems with it, try killing + gradle daemons. For instance, via `pkill -f gradle.*daemon` + +In case you need to debug some other part of the build - consult the official Gradle +tutorials on [Troubleshooting Builds](https://docs.gradle.org/current/userguide/troubleshooting.html). diff --git a/docs/src/doc/docs/dokka_colors.css b/docs/src/doc/docs/dokka_colors.css index 9e45c919..69a24359 100644 --- a/docs/src/doc/docs/dokka_colors.css +++ b/docs/src/doc/docs/dokka_colors.css @@ -1,3 +1,3 @@ -.md-header { - background-color: #F8873C; +.md-header, .md-tabs { + background-color: #27282c } diff --git a/docs/src/doc/docs/expand_navigation.js b/docs/src/doc/docs/expand_navigation.js deleted file mode 100644 index cef32f2c..00000000 --- a/docs/src/doc/docs/expand_navigation.js +++ /dev/null @@ -1,14 +0,0 @@ -document.addEventListener("DOMContentLoaded", function() { - let nav = document.getElementsByClassName("md-nav"); - for(let i = 0; i < nav.length; i++) { - if (nav.item(i).getAttribute("data-md-level")) { - nav.item(i).style.display = 'block'; - nav.item(i).style.overflow = 'visible'; - } - } - - nav = document.getElementsByClassName("md-nav__toggle"); - for(let i = 0; i < nav.length; i++) { - nav.item(i).checked = true; - } -}); diff --git a/docs/src/doc/docs/faq.md b/docs/src/doc/docs/faq.md new file mode 100644 index 00000000..ef728ca0 --- /dev/null +++ b/docs/src/doc/docs/faq.md @@ -0,0 +1,2 @@ +# FAQ +If you encounter any problems, please see [FAQ](https://github.com/Kotlin/dokka/wiki/faq). diff --git a/docs/src/doc/docs/favicon.svg b/docs/src/doc/docs/favicon.svg index 1b3b3670..1fea0877 100644..100755 --- a/docs/src/doc/docs/favicon.svg +++ b/docs/src/doc/docs/favicon.svg @@ -1,3 +1,10 @@ -<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> -</svg> +<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M64 64H0V0H64L31.3373 31.5369L64 64Z" fill="url(#paint0_radial)"/> + <defs> + <radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(61.8732 2.63097) scale(73.3111)"> + <stop offset="0.00343514" stop-color="#EF4857"/> + <stop offset="0.4689" stop-color="#D211EC"/> + <stop offset="1" stop-color="#7F52FF"/> + </radialGradient> + </defs> +</svg>
\ No newline at end of file diff --git a/docs/src/doc/docs/images/mathjax_demo.png b/docs/src/doc/docs/images/mathjax_demo.png Binary files differnew file mode 100644 index 00000000..9b14a704 --- /dev/null +++ b/docs/src/doc/docs/images/mathjax_demo.png diff --git a/docs/src/doc/docs/images/mermaid_demo.png b/docs/src/doc/docs/images/mermaid_demo.png Binary files differnew file mode 100644 index 00000000..0d0e27b6 --- /dev/null +++ b/docs/src/doc/docs/images/mermaid_demo.png diff --git a/docs/src/doc/docs/index.md b/docs/src/doc/docs/index.md index d730e11d..238fb405 100644 --- a/docs/src/doc/docs/index.md +++ b/docs/src/doc/docs/index.md @@ -1,16 +1,38 @@ -# Dokka [![official JetBrains project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![TeamCity (build status)](https://teamcity.jetbrains.com/app/rest/builds/buildType:(id:Kotlin_Dokka_DokkaAntMavenGradle)/statusIcon)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=Kotlin_Dokka_DokkaAntMavenGradle&branch_KotlinTools_Dokka=%3Cdefault%3E&tab=buildTypeStatusDiv) +# Dokka -Dokka is a documentation engine for Kotlin, performing the same function as javadoc for Java. -Just like Kotlin itself, Dokka fully supports mixed-language Java/Kotlin projects. It understands -standard Javadoc comments in Java files and [KDoc comments](https://kotlinlang.org/docs/reference/kotlin-doc.html) in Kotlin files, -and can generate documentation in multiple formats including standard Javadoc, HTML and Markdown. +`Dokka` is an API documentation engine for `Kotlin` that performs the same function as the `Javadoc` tool for `Java`, +but it's modern and highly pluggable. -## Integrations -Dokka provides support for the following build systems: +Just like `Kotlin` itself, `Dokka` supports mixed-language projects (`Kotlin`/`Java`). It understands +[KDoc comments](https://kotlinlang.org/docs/reference/kotlin-doc.html) in `Kotlin` source files as well +as [Javadoc comments](https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html#format) in `Java` +files, and can generate documentation in multiple formats including its own `HTML` format, Java's `Javadoc` lookalike +and `Markdown`. -* [Gradle](user_guide/gradle/usage.md) -* [Maven](user_guide/maven/usage.md) -* [Command line](user_guide/cli/usage.md) +Some libraries that use `Dokka` for API reference docs: -!!! note - The Gradle plugin is the preferred way to use Dokka +* [kotlinx.coroutines](https://kotlinlang.org/api/kotlinx.coroutines/) +* [kotlinx.serialization](https://kotlinlang.org/api/kotlinx.serialization/) +* [Ktor](https://api.ktor.io/) +* [Spring Framework](https://docs.spring.io/spring-framework/docs/current/kdoc-api/) + +___ + +`Dokka` provides support for the following build systems: + +* [Gradle](user_guide/applying/gradle.md) (preffered) +* [Maven](user_guide/applying/maven.md) +* [Command line](user_guide/applying/cli.md) + +___ + +`Dokka` is also very pluggable and comes with convenient plugin and extension point API. + +You can write a plugin to support [mermaid.js](community/plugins-list.md#mermaid) diagrams, +[mathjax](community/plugins-list.md#mathjax) formulas or even write custom processing of your own tags and annotations. + +For more info, see: + +* [Sample plugin tutorial](developer_guide/plugin-development/sample-plugin-tutorial.md) +* [Community plugins](community/plugins-list.md) +* [Developer guides](developer_guide/introduction.md) diff --git a/docs/src/doc/docs/user_guide/cli/usage.md b/docs/src/doc/docs/user_guide/applying/cli.md index a489979d..219411b1 100644 --- a/docs/src/doc/docs/user_guide/cli/usage.md +++ b/docs/src/doc/docs/user_guide/applying/cli.md @@ -10,19 +10,19 @@ java -jar dokka-cli.jar <arguments> Dokka supports the following command line arguments: - * `-outputDir` - the output directory where the documentation is generated - * `-moduleName` - (required) - module name used as a part of source set ID when declaring dependent source sets - * `-cacheRoot` - cache directory to enable package-list caching - * `-pluginsClasspath` - artifacts with Dokka plugins, separated by `;`. At least `dokka-base` and all its dependencies must be added there - * `-pluginsConfiguration` - configuration for plugins in format `fqPluginName=json^^fqPluginName=json...` - * `-offlineMode` - do not resolve package-lists online - * `-failOnWarning` - throw an exception instead of a warning - * `-globalPackageOptions` - per package options added to all source sets - * `-globalLinks` - external documentation links added to all source sets - * `-globalSrcLink` - source links added to all source sets - * `-noSuppressObviousFunctions` - don't suppress obvious functions like default `toString` or `equals` - * `-suppressInheritedMembers` - suppress all inherited members that were not overriden in a given class. Eg. using it you can suppress toString or equals functions but you can't suppress componentN or copy on data class - * `-sourceSet` - (repeatable) - configuration for a single source set. Following this argument, you can pass other arguments: +* `-outputDir` - the output directory where the documentation is generated +* `-moduleName` - (required) - module name used as a part of source set ID when declaring dependent source sets +* `-cacheRoot` - cache directory to enable package-list caching +* `-pluginsClasspath` - artifacts with Dokka plugins, separated by `;`. At least `dokka-base` and all its dependencies must be added there +* `-pluginsConfiguration` - configuration for plugins in format `fqPluginName=json^^fqPluginName=json...` +* `-offlineMode` - do not resolve package-lists online +* `-failOnWarning` - throw an exception instead of a warning +* `-globalPackageOptions` - per package options added to all source sets +* `-globalLinks` - external documentation links added to all source sets +* `-globalSrcLink` - source links added to all source sets +* `-noSuppressObviousFunctions` - don't suppress obvious functions like default `toString` or `equals` +* `-suppressInheritedMembers` - suppress all inherited members that were not overriden in a given class. Eg. using it you can suppress toString or equals functions but you can't suppress componentN or copy on data class +* `-sourceSet` - (repeatable) - configuration for a single source set. Following this argument, you can pass other arguments: * `-sourceSetName` - source set name as a part of source set ID when declaring dependent source sets * `-displayName` - source set name displayed in the generated documentation * `-src` - list of source files or directories separated by `;` @@ -42,7 +42,7 @@ Dokka supports the following command line arguments: * `-jdkVersion` - version of JDK to use for linking to JDK JavaDoc * `-analysisPlatform` - platform used for analysis, see the [Platforms](#platforms) section * `-dependentSourceSets` - list of dependent source sets in format `moduleName/sourceSetName`, separated by `;` - * `-loggingLevel` - one of `DEBUG`, `PROGRESS`, `INFO`, `WARN`, `ERROR`. Defaults to `DEBUG`. Please note that this argument can't be passed in JSON. +* `-loggingLevel` - one of `DEBUG`, `PROGRESS`, `INFO`, `WARN`, `ERROR`. Defaults to `DEBUG`. Please note that this argument can't be passed in JSON. You can also use a JSON file with Dokka configuration: diff --git a/docs/src/doc/docs/user_guide/gradle/usage.md b/docs/src/doc/docs/user_guide/applying/gradle.md index 399075a5..3d0c8fa1 100644 --- a/docs/src/doc/docs/user_guide/gradle/usage.md +++ b/docs/src/doc/docs/user_guide/applying/gradle.md @@ -1,7 +1,7 @@ # Using the Gradle plugin !!! important - If you are upgrading from 0.10.x to a current release of Dokka, please have a look at our + If you are upgrading from 0.10.x to a current release of Dokka, please have a look at our [migration guide](https://github.com/Kotlin/dokka/blob/master/runners/gradle-plugin/MIGRATION.md) ### Supported versions @@ -9,7 +9,7 @@ Dokka should work on gradle newer than 5.6 ### Setup -The preferred way is to use `plugins` block. +The preferred way is to use `plugins` block. build.gradle.kts: ```kotlin @@ -37,7 +37,7 @@ apply(plugin="org.jetbrains.dokka") ``` The plugin adds `dokkaHtml`, `dokkaJavadoc`, `dokkaGfm` and `dokkaJekyll` tasks to the project. - + Each task corresponds to one output format, so you should run `dokkaGfm` when you want to have a documentation in `GFM` format. Output formats are explained in [the introduction](../introduction.md#output-formats) @@ -60,15 +60,15 @@ dokkaHtml { } ``` -!!! note +!!! note Dokka extracts the information about sourcesets from the Kotlin Gradle plugin. - Therefore, if you are using Dokka in a [precompiled script plugin](https://docs.gradle.org/current/userguide/custom_plugins.html#sec:precompiled_plugins), + Therefore, if you are using Dokka in a [precompiled script plugin](https://docs.gradle.org/current/userguide/custom_plugins.html#sec:precompiled_plugins), you will have to add a depencency to the Kotlin Gradle Plugin as well (`implementation(kotlin("gradle-plugin", "<kotlin-version>"))` resp. `implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:<kotlin-version>")`). ## Configuration options -Dokka documents single-platform as well as multi-platform projects. +Dokka documents single-platform as well as multi-platform projects. Most of the configuration options are set per one source set. The available configuration options are shown below: diff --git a/docs/src/doc/docs/user_guide/maven/usage.md b/docs/src/doc/docs/user_guide/applying/maven.md index d799396a..cde6e927 100644 --- a/docs/src/doc/docs/user_guide/maven/usage.md +++ b/docs/src/doc/docs/user_guide/applying/maven.md @@ -1,10 +1,8 @@ # Using the Maven plugin -!!! note +!!! note Dokka Maven plugin does not support multi-platform projects. -The Maven plugin does not support multi-platform projects. - Minimal Maven configuration is ```xml @@ -27,9 +25,9 @@ By default files will be generated in `target/dokka`. The following goals are provided by the plugin: - * `dokka:dokka` - generate HTML documentation in Dokka format (showing declarations in Kotlin syntax) - * `dokka:javadoc` - generate HTML documentation in Javadoc format (showing declarations in Java syntax) - * `dokka:javadocJar` - generate a .jar file with Javadoc format documentation +* `dokka:dokka` - generate HTML documentation in Dokka format (showing declarations in Kotlin syntax) +* `dokka:javadoc` - generate HTML documentation in Javadoc format (showing declarations in Java syntax) +* `dokka:javadocJar` - generate a .jar file with Javadoc format documentation ## Configuration options diff --git a/docs/src/doc/docs/user_guide/base-specific/frontend.md b/docs/src/doc/docs/user_guide/output-formats/html.md index f1de420d..9a80a5d2 100644 --- a/docs/src/doc/docs/user_guide/base-specific/frontend.md +++ b/docs/src/doc/docs/user_guide/output-formats/html.md @@ -70,7 +70,7 @@ In order to override a logo and style it accordingly a css file named `logo-styl ``` -For build system specific instructions please visit dedicated pages: [gradle](../gradle/usage.md#applying-plugins), [maven](../maven/usage.md#applying-plugins) and [cli](../cli/usage.md#configuration-options) +For build system specific instructions please visit dedicated pages: [gradle](../applying/gradle.md#applying-plugins), [maven](../applying/maven.md#applying-plugins) and [cli](../applying/cli.md#configuration-options) ## Custom HTML pages @@ -83,6 +83,7 @@ To customize HTML output, you can use the [default template](https://github.com/ There is a template file with predefined name `base.ftl`. It defines general design of all pages to render. `base.ftl` can import another templates that can be set by user as well: + * `includes/header.ftl` * `includes/footer.ftl` * `includes/page_metadata.ftl` @@ -92,14 +93,16 @@ If `templatesDir` is defined, Dokka will find a template file there. If the file is not found, a default one will be used. Variables given below are available to the template: + * `${pageName}` - the page name * `${footerMessage}` - text that is set by the `footerMessage` property * `${sourceSets}` - a nullable list of source sets, only for multi-platform pages. Each source set has `name`, `platfrom` and `filter` properties. Also, Dokka-defined [directives](https://freemarker.apache.org/docs/ref_directive_userDefined.html) can be used: + * `<@content/>` - main content * `<@resources/>` - scripts, stylesheets -* `<@version/>` - version ([versioning-plugin](https://kotlin.github.io/dokka/1.7.0/user_guide/versioning/versioning/) will replace this with a version navigator) +* `<@version/>` - version ([versioning-plugin](../plugins/versioning-plugin.md) will replace this with a version navigator) * `<@template_cmd name="...""> ...</@template_cmd>` - is used for variables that depend on the root project (such `pathToRoot`, `projectName`). They are available only inside the directive. This is processed by a multi-module task that assembles partial outputs from modules. Example: ``` diff --git a/docs/src/doc/docs/user_guide/android-plugin/android-plugin.md b/docs/src/doc/docs/user_guide/plugins/android-plugin.md index d52c2e5a..d52c2e5a 100644 --- a/docs/src/doc/docs/user_guide/android-plugin/android-plugin.md +++ b/docs/src/doc/docs/user_guide/plugins/android-plugin.md diff --git a/docs/src/doc/docs/user_guide/versioning/versioning.md b/docs/src/doc/docs/user_guide/plugins/versioning-plugin.md index f323d8a8..876ec436 100644 --- a/docs/src/doc/docs/user_guide/versioning/versioning.md +++ b/docs/src/doc/docs/user_guide/plugins/versioning-plugin.md @@ -79,8 +79,8 @@ Alternatively, without adding plugin to classpath: pluginsMapConfiguration.set(mapOf("org.jetbrains.dokka.versioning.VersioningPlugin" to """{ "version": "1.0" }""")) ``` -Please consult the [Gradle documentation](../gradle/usage.md#applying-plugins) for more information about configuring Dokka with this build tool. +Please consult the [Gradle documentation](../applying/gradle.md#applying-plugins) for more information about configuring Dokka with this build tool. Please see the [Dokka Gradle versioning multi modules example project](https://github.com/Kotlin/dokka/tree/master/examples/gradle/dokka-versioning-multimodule-example). -Also see the [generated documentation](https://Kotlin.github.io/dokka/examples/dokka-versioning-multimodule-example/htmlMultiModule).
\ No newline at end of file +Also see the [generated documentation](https://Kotlin.github.io/dokka/examples/dokka-versioning-multimodule-example/htmlMultiModule). diff --git a/docs/src/doc/mkdocs.yml b/docs/src/doc/mkdocs.yml index 139c2297..d8aba618 100644 --- a/docs/src/doc/mkdocs.yml +++ b/docs/src/doc/mkdocs.yml @@ -1,8 +1,8 @@ -site_name: Dokka +site_name: Dokka documentation # Meta tags (placed in header) -site_description: Dokka is a documentation engine for Kotlin, performing the same function as javadoc for Java -site_author: Jetbrains +site_description: Dokka is an API documentation engine for Kotlin, performing the same function as the Javadoc tool for Java +site_author: JetBrains site_url: https://github.com/Kotlin/dokka # Repository (add link to repository on each page) @@ -11,7 +11,7 @@ repo_url: https://github.com/Kotlin/dokka edit_uri: edit/master/docs/src/doc/docs/ # Copyright (shown at the footer) -copyright: 'Copyright © 2020 Jetbrains' +copyright: 'Copyright © 2022 JetBrains' # Material theme theme: @@ -20,6 +20,12 @@ theme: social: - type: 'github' link: 'https://github.com/Kotlin/dokka' + features: + - navigation.expand + - navigation.tabs + - navigation.instant + - navigation.indexes + - navigation.top # Extensions markdown_extensions: @@ -37,33 +43,55 @@ markdown_extensions: - pymdownx.inlinehilite - pymdownx.magiclink - pymdownx.smartsymbols - - pymdownx.superfences + - attr_list + - md_in_html + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format # Dev server binding #dev_addr: 127.0.0.1:3001 nav: - - Home: index.md - - User guide: - - Introduction: user_guide/introduction.md - - Gradle: user_guide/gradle/usage.md - - Maven: user_guide/maven/usage.md - - Command line: user_guide/cli/usage.md - - Html frontend: user_guide/base-specific/frontend.md - - Versioning: user_guide/versioning/versioning.md - - Android plugin: user_guide/android-plugin/android-plugin.md - - Plugin development: - - Introduction: developer_guide/introduction.md - - Data model: developer_guide/data_model.md - - Extension points: developer_guide/extension_points.md + - Home: + - index.md + - User guides: user_guide/introduction.md + - Developer guides: developer_guide/introduction.md + - Community: community/slack.md + - FAQ: faq.md + - User guides: + - User guides: user_guide/introduction.md + - Applying Dokka: + - Gradle: user_guide/applying/gradle.md + - Maven: user_guide/applying/maven.md + - Command line: user_guide/applying/cli.md + - Output formats: + - HTML: user_guide/output-formats/html.md + - Plugins: + - Versioning plugin: user_guide/plugins/versioning-plugin.md + - Android plugin: user_guide/plugins/android-plugin.md + - Developer guides: + - Developer guides: developer_guide/introduction.md + - Workflow: developer_guide/workflow.md + - Internals: + - Architecture: developer_guide/architecture/architecture_overview.md + - Data model: + - Documentables: developer_guide/architecture/data_model/documentables.md + - Page & Content: developer_guide/architecture/data_model/page_content.md + - Extra properties: developer_guide/architecture/data_model/extra.md + - Extension points: + - Extension points: developer_guide/architecture/extension_points/introduction.md + - Core extension points: developer_guide/architecture/extension_points/core_extensions.md + - Base extensions: developer_guide/architecture/extension_points/base_extensions.md + - Plugin development: + - Plugin development: developer_guide/plugin-development/introduction.md + - Sample plugin tutorial: developer_guide/plugin-development/sample-plugin-tutorial.md - Community: + - Slack: community/slack.md - Community plugins: community/plugins-list.md - - About: - - FAQ: about/FAQ.md - - Slack channel: about/slack_channel.md - -extra_javascript: - - expand_navigation.js + - FAQ: faq.md extra_css: - dokka_colors.css |