diff options
Diffstat (limited to 'dokka-subprojects/plugin-mathjax')
6 files changed, 241 insertions, 0 deletions
diff --git a/dokka-subprojects/plugin-mathjax/README.md b/dokka-subprojects/plugin-mathjax/README.md new file mode 100644 index 00000000..a12095ee --- /dev/null +++ b/dokka-subprojects/plugin-mathjax/README.md @@ -0,0 +1,27 @@ +# MathJax plugin + +[MathJax](https://docs.mathjax.org/) allows you to include mathematics in your web pages. The `mathjax` Dokka plugin +adds the ability to render mathematics found in source code comments. + +If MathJax plugin encounters the `@usesMathJax` KDoc tag, it adds `MathJax.js` (ver. 2) with `config=TeX-AMS_SVG` +to the generated HTML pages. + +Usage example: + +```kotlin +/** + * Some math \(\sqrt{3x-1}+(1+x)^2\) + * + * @usesMathJax + */ +class Foo {} +``` + +Note that the `@usesMathJax` tag is case-sensitive. + +The MathJax plugin is published to Maven Central as a +[separate artifact](https://mvnrepository.com/artifact/org.jetbrains.dokka/mathjax-plugin): + +```text +org.jetbrains.dokka:mathjax-plugin:1.9.10 +``` diff --git a/dokka-subprojects/plugin-mathjax/api/plugin-mathjax.api b/dokka-subprojects/plugin-mathjax/api/plugin-mathjax.api new file mode 100644 index 00000000..da5caeb2 --- /dev/null +++ b/dokka-subprojects/plugin-mathjax/api/plugin-mathjax.api @@ -0,0 +1,18 @@ +public final class org/jetbrains/dokka/mathjax/MathjaxPlugin : org/jetbrains/dokka/plugability/DokkaPlugin { + public fun <init> ()V + public final fun getMathjaxTagContentProvider ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getTransformer ()Lorg/jetbrains/dokka/plugability/Extension; +} + +public final class org/jetbrains/dokka/mathjax/MathjaxTagContentProvider : org/jetbrains/dokka/base/transformers/pages/tags/CustomTagContentProvider { + public static final field INSTANCE Lorg/jetbrains/dokka/mathjax/MathjaxTagContentProvider; + public fun contentForBrief (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/model/doc/CustomTagWrapper;)V + public fun contentForDescription (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/model/doc/CustomTagWrapper;)V + public fun isApplicable (Lorg/jetbrains/dokka/model/doc/CustomTagWrapper;)Z +} + +public final class org/jetbrains/dokka/mathjax/MathjaxTransformer : org/jetbrains/dokka/transformers/pages/PageTransformer { + public static final field INSTANCE Lorg/jetbrains/dokka/mathjax/MathjaxTransformer; + public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; +} + diff --git a/dokka-subprojects/plugin-mathjax/build.gradle.kts b/dokka-subprojects/plugin-mathjax/build.gradle.kts new file mode 100644 index 00000000..18146f6f --- /dev/null +++ b/dokka-subprojects/plugin-mathjax/build.gradle.kts @@ -0,0 +1,32 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +import dokkabuild.overridePublicationArtifactId + +plugins { + id("dokkabuild.kotlin-jvm") + id("dokkabuild.publish-jvm") + id("dokkabuild.test-k2") +} + +overridePublicationArtifactId("mathjax-plugin") + +dependencies { + compileOnly(projects.dokkaSubprojects.dokkaCore) + + implementation(projects.dokkaSubprojects.pluginBase) + + implementation(kotlin("reflect")) + + testImplementation(kotlin("test")) + testImplementation(libs.jsoup) + testImplementation(projects.dokkaSubprojects.coreContentMatcherTestUtils) + testImplementation(projects.dokkaSubprojects.coreTestApi) + + symbolsTestConfiguration(project(path = ":dokka-subprojects:analysis-kotlin-symbols", configuration = "shadow")) + descriptorsTestConfiguration(project(path = ":dokka-subprojects:analysis-kotlin-descriptors", configuration = "shadow")) + testImplementation(projects.dokkaSubprojects.pluginBaseTestUtils) { + exclude(module = "analysis-kotlin-descriptors") + } +} diff --git a/dokka-subprojects/plugin-mathjax/src/main/kotlin/org/jetbrains/dokka/mathjax/MathjaxPlugin.kt b/dokka-subprojects/plugin-mathjax/src/main/kotlin/org/jetbrains/dokka/mathjax/MathjaxPlugin.kt new file mode 100644 index 00000000..2a7ed6a4 --- /dev/null +++ b/dokka-subprojects/plugin-mathjax/src/main/kotlin/org/jetbrains/dokka/mathjax/MathjaxPlugin.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.mathjax + + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.transformers.pages.tags.CustomTagContentProvider +import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder.DocumentableContentBuilder +import org.jetbrains.dokka.model.doc.CustomTagWrapper +import org.jetbrains.dokka.pages.ContentPage +import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.pages.WithDocumentables +import org.jetbrains.dokka.plugability.DokkaPlugin +import org.jetbrains.dokka.plugability.DokkaPluginApiPreview +import org.jetbrains.dokka.plugability.Extension +import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement +import org.jetbrains.dokka.transformers.pages.PageTransformer + +public class MathjaxPlugin : DokkaPlugin() { + + public val transformer: Extension<PageTransformer, *, *> by extending { + CoreExtensions.pageTransformer with MathjaxTransformer + } + + public val mathjaxTagContentProvider: Extension<CustomTagContentProvider, *, *> by extending { + plugin<DokkaBase>().customTagContentProvider with MathjaxTagContentProvider order { + before(plugin<DokkaBase>().sinceKotlinTagContentProvider) + } + } + + @OptIn(DokkaPluginApiPreview::class) + override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = + PluginApiPreviewAcknowledgement +} + +private const val ANNOTATION = "usesMathJax" +internal const val LIB_PATH = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS_SVG&latest" + +public object MathjaxTransformer : PageTransformer { + + override fun invoke(input: RootPageNode): RootPageNode = input.transformContentPagesTree { + it.modified( + embeddedResources = it.embeddedResources + if (it.isNeedingMathjax) listOf(LIB_PATH) else emptyList() + ) + } + + private val ContentPage.isNeedingMathjax + get() = (this as WithDocumentables).documentables.any { it.documentation.values + .flatMap { it.children } + .any { (it as? CustomTagWrapper)?.name == ANNOTATION } } +} + +public object MathjaxTagContentProvider : CustomTagContentProvider { + + override fun isApplicable(customTag: CustomTagWrapper): Boolean = customTag.name == ANNOTATION + + override fun DocumentableContentBuilder.contentForDescription( + sourceSet: DokkaConfiguration.DokkaSourceSet, + customTag: CustomTagWrapper + ) { + comment(customTag.root, sourceSets = setOf(sourceSet)) + } +} diff --git a/dokka-subprojects/plugin-mathjax/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/dokka-subprojects/plugin-mathjax/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin new file mode 100644 index 00000000..4a9d7a9e --- /dev/null +++ b/dokka-subprojects/plugin-mathjax/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin @@ -0,0 +1,5 @@ +# +# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. +# + +org.jetbrains.dokka.mathjax.MathjaxPlugin diff --git a/dokka-subprojects/plugin-mathjax/src/test/kotlin/mathjaxTest/MathjaxPluginTest.kt b/dokka-subprojects/plugin-mathjax/src/test/kotlin/mathjaxTest/MathjaxPluginTest.kt new file mode 100644 index 00000000..905684d2 --- /dev/null +++ b/dokka-subprojects/plugin-mathjax/src/test/kotlin/mathjaxTest/MathjaxPluginTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package mathjaxTest + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.mathjax.LIB_PATH +import org.jetbrains.dokka.mathjax.MathjaxPlugin +import org.jsoup.Jsoup +import utils.TestOutputWriterPlugin +import kotlin.test.Test +import kotlin.test.assertTrue + +class MathjaxPluginTest : BaseAbstractTest() { + @Test + fun noMathjaxTest() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + val source = + """ + |/src/main/kotlin/test/Test.kt + |package example + | /** + | * Just a regular kdoc + | */ + | fun test(): String = "" + """.trimIndent() + val writerPlugin = TestOutputWriterPlugin() + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin, MathjaxPlugin()) + ) { + renderingStage = { + _, _ -> Jsoup + .parse(writerPlugin.writer.contents.getValue("root/example/test.html")) + .head() + .select("link, script") + .let { + assertTrue(!it.`is`("[href=$LIB_PATH], [src=$LIB_PATH]")) + } + } + } + } + + @Test + fun usingMathjaxTest() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + val math = "a^2 = b^2 + c^2" + val source = + """ + |/src/main/kotlin/test/Test.kt + |package example + | /** + | * @usesMathJax + | * + | * \($math\) + | */ + | fun test(): String = "" + """.trimIndent() + val writerPlugin = TestOutputWriterPlugin() + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin, MathjaxPlugin()) + ) { + renderingStage = { _, _ -> + val parsed = Jsoup.parse(writerPlugin.writer.contents.getValue("root/example/test.html")) + + // Ensure the MathJax CDN is loaded + assertTrue(parsed.select("link, script").`is`("[href=$LIB_PATH], [src=$LIB_PATH]")) + + // Ensure the contents are displayed + assertTrue(parsed.select("p").any { + it.text().contains(math) + }) + } + } + } +} |