aboutsummaryrefslogtreecommitdiff
path: root/mkdocs/src/doc/docs/developer_guide/architecture/extension_points
diff options
context:
space:
mode:
authorIgnat Beresnev <ignat.beresnev@jetbrains.com>2023-01-10 13:14:43 +0100
committerGitHub <noreply@github.com>2023-01-10 13:14:43 +0100
commit7544a215fb580ae0c47d1f397334f150d1a1ec65 (patch)
treea30aa62c827e3ba88a498a7406ac57fa7334b270 /mkdocs/src/doc/docs/developer_guide/architecture/extension_points
parent2161c397e1b1aadcf3d39c8518258e9bdb2b431a (diff)
downloaddokka-7544a215fb580ae0c47d1f397334f150d1a1ec65.tar.gz
dokka-7544a215fb580ae0c47d1f397334f150d1a1ec65.tar.bz2
dokka-7544a215fb580ae0c47d1f397334f150d1a1ec65.zip
Revise documentation (#2728)
Co-authored-by: Sarah Haggarty <sarahhaggarty@users.noreply.github.com>
Diffstat (limited to 'mkdocs/src/doc/docs/developer_guide/architecture/extension_points')
-rw-r--r--mkdocs/src/doc/docs/developer_guide/architecture/extension_points/base_extensions.md13
-rw-r--r--mkdocs/src/doc/docs/developer_guide/architecture/extension_points/core_extensions.md151
-rw-r--r--mkdocs/src/doc/docs/developer_guide/architecture/extension_points/introduction.md163
3 files changed, 327 insertions, 0 deletions
diff --git a/mkdocs/src/doc/docs/developer_guide/architecture/extension_points/base_extensions.md b/mkdocs/src/doc/docs/developer_guide/architecture/extension_points/base_extensions.md
new file mode 100644
index 00000000..16a52fab
--- /dev/null
+++ b/mkdocs/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/mkdocs/src/doc/docs/developer_guide/architecture/extension_points/core_extensions.md b/mkdocs/src/doc/docs/developer_guide/architecture/extension_points/core_extensions.md
new file mode 100644
index 00000000..381a9596
--- /dev/null
+++ b/mkdocs/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/mkdocs/src/doc/docs/developer_guide/architecture/extension_points/introduction.md b/mkdocs/src/doc/docs/developer_guide/architecture/extension_points/introduction.md
new file mode 100644
index 00000000..877d14e9
--- /dev/null
+++ b/mkdocs/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.