diff options
Diffstat (limited to 'core/src/main/kotlin')
7 files changed, 3 insertions, 614 deletions
diff --git a/core/src/main/kotlin/CoreExtensions.kt b/core/src/main/kotlin/CoreExtensions.kt index 8ae333ee..2d705c1b 100644 --- a/core/src/main/kotlin/CoreExtensions.kt +++ b/core/src/main/kotlin/CoreExtensions.kt @@ -24,12 +24,13 @@ object CoreExtensions { val psiToDocumentationTranslator by coreExtension<PsiToDocumentationTranslator>() val documentableMerger by coreExtension<DocumentableMerger>() val documentationTransformer by coreExtension<DocumentationNodeTransformer>() - val commentsToContentConverter by coreExtension<CommentsToContentConverter>() val documentablesToPageTranslator by coreExtension<DocumentablesToPageTranslator>() val pageTransformer by coreExtension<PageNodeTransformer>() + val renderer by coreExtension<Renderer>() + + val commentsToContentConverter by coreExtension<CommentsToContentConverter>() val locationProviderFactory by coreExtension<LocationProviderFactory>() val outputWriter by coreExtension<OutputWriter>() - val renderer by coreExtension<Renderer>() val pageMergerStrategy by coreExtension<PageMergerStrategy>() private fun <T: Any> coreExtension() = object { diff --git a/core/src/main/kotlin/plugability/DefaultExtensions.kt b/core/src/main/kotlin/plugability/DefaultExtensions.kt index 7c76afe7..828d1bf1 100644 --- a/core/src/main/kotlin/plugability/DefaultExtensions.kt +++ b/core/src/main/kotlin/plugability/DefaultExtensions.kt @@ -4,20 +4,12 @@ import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.pages.DocTagToContentConverter import org.jetbrains.dokka.renderers.FileWriter import org.jetbrains.dokka.renderers.OutputWriter -import org.jetbrains.dokka.renderers.html.HtmlRenderer import org.jetbrains.dokka.resolvers.DefaultLocationProviderFactory import org.jetbrains.dokka.transformers.pages.DefaultPageMergerStrategy -import org.jetbrains.dokka.transformers.psi.DefaultPsiToDocumentationTranslator import org.jetbrains.dokka.transformers.pages.DefaultPageNodeMerger internal object DefaultExtensions { - private val renderer: LazyEvaluated<HtmlRenderer> = LazyEvaluated.fromRecipe { - HtmlRenderer( - it.single(CoreExtensions.outputWriter), - it - ) - } private val converter: LazyEvaluated<DocTagToContentConverter> = LazyEvaluated.fromRecipe { DocTagToContentConverter(it) } private val providerFactory: LazyEvaluated<DefaultLocationProviderFactory> = LazyEvaluated.fromRecipe { DefaultLocationProviderFactory(it) } private val outputWriter: LazyEvaluated<OutputWriter> = LazyEvaluated.fromRecipe { FileWriter(it) } @@ -25,10 +17,8 @@ internal object DefaultExtensions { @Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST") internal fun <T : Any, E : ExtensionPoint<T>> get(point: E, fullContext: DokkaContext): List<T> = when (point) { - CoreExtensions.psiToDocumentationTranslator -> DefaultPsiToDocumentationTranslator CoreExtensions.commentsToContentConverter -> converter.get(fullContext) CoreExtensions.pageTransformer -> DefaultPageNodeMerger(fullContext) - CoreExtensions.renderer -> renderer.get(fullContext) CoreExtensions.locationProviderFactory -> providerFactory.get(fullContext) CoreExtensions.outputWriter -> outputWriter.get(fullContext) CoreExtensions.pageMergerStrategy -> DefaultPageMergerStrategy(fullContext.logger) diff --git a/core/src/main/kotlin/renderers/DefaultRenderer.kt b/core/src/main/kotlin/renderers/DefaultRenderer.kt deleted file mode 100644 index d09d9ded..00000000 --- a/core/src/main/kotlin/renderers/DefaultRenderer.kt +++ /dev/null @@ -1,124 +0,0 @@ -package org.jetbrains.dokka.renderers - -import org.jetbrains.dokka.CoreExtensions -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.resolvers.LocationProvider -import org.jetbrains.dokka.transformers.pages.PageNodeTransformer - -abstract class DefaultRenderer<T>( - protected val outputWriter: OutputWriter, - protected val context: DokkaContext -) : Renderer { - - protected lateinit var locationProvider: LocationProvider - private set - - protected open val preprocessors: Iterable<PageNodeTransformer> = emptyList() - - abstract fun T.buildHeader(level: Int, content: T.() -> Unit) - abstract fun T.buildLink(address: String, content: T.() -> Unit) - abstract fun T.buildList(node: ContentList, pageContext: ContentPage) - abstract fun T.buildNewLine() - abstract fun T.buildResource(node: ContentEmbeddedResource, pageContext: ContentPage) - abstract fun T.buildTable(node: ContentTable, pageContext: ContentPage) - abstract fun T.buildText(textNode: ContentText) - abstract fun T.buildNavigation(page: PageNode) - - abstract fun buildPage(page: ContentPage, content: (T, ContentPage) -> Unit): String - abstract fun buildError(node: ContentNode) - - open fun T.buildGroup(node: ContentGroup, pageContext: ContentPage) { - node.children.forEach { it.build(this, pageContext) } - } - - open fun T.buildLinkText(nodes: List<ContentNode>, pageContext: ContentPage) { - nodes.forEach { it.build(this, pageContext) } - } - - open fun T.buildCode(code: List<ContentNode>, language: String, pageContext: ContentPage) { - code.forEach { it.build(this, pageContext) } - } - - open fun T.buildHeader(node: ContentHeader, pageContext: ContentPage) { - buildHeader(node.level) { node.children.forEach { it.build(this, pageContext) } } - } - - open fun ContentNode.build(builder: T, pageContext: ContentPage) = - builder.buildContentNode(this, pageContext) - - open fun T.buildContentNode(node: ContentNode, pageContext: ContentPage) { - when (node) { - is ContentText -> buildText(node) - is ContentHeader -> buildHeader(node, pageContext) - is ContentCode -> buildCode(node.children, node.language, pageContext) - is ContentDRILink -> buildLink( - locationProvider.resolve(node.address, node.platforms.toList(), pageContext) - ) { - buildLinkText(node.children, pageContext) - } - is ContentResolvedLink -> buildLink(node.address) { buildLinkText(node.children, pageContext) } - is ContentEmbeddedResource -> buildResource(node, pageContext) - is ContentList -> buildList(node, pageContext) - is ContentTable -> buildTable(node, pageContext) - is ContentGroup -> buildGroup(node, pageContext) - else -> buildError(node) - } - } - - open fun buildPageContent(context: T, page: ContentPage) { - context.buildNavigation(page) - page.content.build(context, page) - } - - open fun renderPage(page: PageNode) { - val path by lazy { locationProvider.resolve(page, skipExtension = true) } - when (page) { - is ContentPage -> outputWriter.write(path, buildPage(page) { c, p -> buildPageContent(c, p) }, ".html") - is RendererSpecificPage -> when (val strategy = page.strategy) { - is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, path) - is RenderingStrategy.Write -> outputWriter.write(path, strategy.text, "") - is RenderingStrategy.Callback -> outputWriter.write(path, strategy.instructions(this, page), ".html") - RenderingStrategy.DoNothing -> Unit - } - else -> throw AssertionError( - "Page ${page.name} cannot be rendered by renderer as it is not renderer specific nor contains content" - ) - } - } - - open fun renderPages(root: PageNode) { - renderPage(root) - root.children.forEach { renderPages(it) } - } - - // reimplement this as preprocessor - open fun renderPackageList(root: ContentPage) = - getPackageNamesAndPlatforms(root) - .keys - .joinToString("\n") - .also { outputWriter.write("${root.name}/package-list", it, "") } - - open fun getPackageNamesAndPlatforms(root: PageNode): Map<String, List<PlatformData>> = - root.children - .map(::getPackageNamesAndPlatforms) - .fold(emptyMap<String, List<PlatformData>>()) { e, acc -> acc + e } + - if (root is PackagePageNode) { - mapOf(root.name to root.platforms()) - } else { - emptyMap() - } - - override fun render(root: RootPageNode) { - val newRoot = preprocessors.fold(root) { acc, t -> t(acc) } - - locationProvider = - context.single(CoreExtensions.locationProviderFactory).getLocationProvider(newRoot) - - root.children<ModulePageNode>().forEach { renderPackageList(it) } - - renderPages(newRoot) - } -} - -fun ContentPage.platforms() = this.content.platforms.toList()
\ No newline at end of file diff --git a/core/src/main/kotlin/renderers/html/HtmlRenderer.kt b/core/src/main/kotlin/renderers/html/HtmlRenderer.kt deleted file mode 100644 index 376ce5c8..00000000 --- a/core/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ /dev/null @@ -1,217 +0,0 @@ -package org.jetbrains.dokka.renderers.html - -import kotlinx.html.* -import kotlinx.html.stream.createHTML -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.Function -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.renderers.DefaultRenderer -import org.jetbrains.dokka.renderers.OutputWriter -import java.io.File - -open class HtmlRenderer( - outputWriter: OutputWriter, - context: DokkaContext -) : DefaultRenderer<FlowContent>(outputWriter, context) { - - private val pageList = mutableListOf<String>() - - override val preprocessors = listOf( - RootCreator, - SearchPageInstaller, - ResourceInstaller, - NavigationPageInstaller, - StyleAndScriptsAppender - ) - - override fun FlowContent.buildList(node: ContentList, pageContext: ContentPage) = - if (node.ordered) ol { - buildListItems(node.children, pageContext) - } - else ul { - buildListItems(node.children, pageContext) - } - - open fun OL.buildListItems(items: List<ContentNode>, pageContext: ContentPage) { - items.forEach { - if (it is ContentList) - buildList(it, pageContext) - else - li { it.build(this, pageContext) } - } - } - - open fun UL.buildListItems(items: List<ContentNode>, pageContext: ContentPage) { - items.forEach { - if (it is ContentList) - buildList(it, pageContext) - else - li { it.build(this, pageContext) } - } - } - - override fun FlowContent.buildResource( - node: ContentEmbeddedResource, - pageContext: ContentPage - ) { // TODO: extension point there - val imageExtensions = setOf("png", "jpg", "jpeg", "gif", "bmp", "tif", "webp", "svg") - return if (File(node.address).extension.toLowerCase() in imageExtensions) { - //TODO: add imgAttrs parsing - val imgAttrs = node.extras.filterIsInstance<HTMLSimpleAttr>().joinAttr() - img(src = node.address, alt = node.altText) - } else { - println("Unrecognized resource type: $node") - } - } - - override fun FlowContent.buildTable(node: ContentTable, pageContext: ContentPage) { - table { - thead { - node.header.forEach { - tr { - it.children.forEach { - th { - it.build(this@table, pageContext) - } - } - } - } - } - tbody { - node.children.forEach { - tr { - it.children.forEach { - td { - it.build(this, pageContext) - } - } - } - } - } - } - } - - override fun FlowContent.buildHeader(level: Int, content: FlowContent.() -> Unit) { - when (level) { - 1 -> h1(block = content) - 2 -> h2(block = content) - 3 -> h3(block = content) - 4 -> h4(block = content) - 5 -> h5(block = content) - else -> h6(block = content) - } - } - - override fun FlowContent.buildNavigation(page: PageNode) = - locationProvider.ancestors(page).asReversed().forEach { node -> - text("/") - if (node.isNavigable) buildLink(node, page) - else text(node.name) - } - - private fun FlowContent.buildLink(to: PageNode, from: PageNode) = - buildLink(locationProvider.resolve(to, from)) { - text(to.name) - } - - fun FlowContent.buildLink( - to: DRI, - platforms: List<PlatformData>, - from: PageNode? = null, - block: FlowContent.() -> Unit - ) = buildLink(locationProvider.resolve(to, platforms, from), block) - - override fun buildError(node: ContentNode) { - context.logger.error("Unknown ContentNode type: $node") - } - - override fun FlowContent.buildNewLine() { - br() - } - - override fun FlowContent.buildLink(address: String, content: FlowContent.() -> Unit) = - a(href = address, block = content) - - override fun FlowContent.buildCode(code: List<ContentNode>, language: String, pageContext: ContentPage) { - buildNewLine() - code.forEach { - +((it as? ContentText)?.text ?: run { context.logger.error("Cannot cast $it as ContentText!"); "" }) - buildNewLine() - } - } - - override fun renderPage(page: PageNode) { - super.renderPage(page) - if (page is ContentPage) { - pageList.add( - """{ "name": "${page.name}", ${if (page is ClasslikePageNode) "\"class\": \"${page.name}\"," else ""} "location": "${locationProvider.resolve( - page - )}" }""" - ) - } - } - - override fun FlowContent.buildText(textNode: ContentText) { - text(textNode.text) - } - - override fun render(root: RootPageNode) { - super.render(root) - outputWriter.write("scripts/pages", "var pages = [\n${pageList.joinToString(",\n")}\n]", ".js") - } - - private fun PageNode.root(path: String) = locationProvider.resolveRoot(this) + path - - override fun buildPage(page: ContentPage, content: (FlowContent, ContentPage) -> Unit): String = - buildHtml(page, page.embeddedResources) { content(this, page) } - - open fun buildHtml(page: PageNode, resources: List<String>, content: FlowContent.() -> Unit) = - createHTML().html { - head { - title(page.name) - with(resources) { - filter { it.substringBefore('?').substringAfterLast('.') == "css" } - .forEach { link(rel = LinkRel.stylesheet, href = page.root(it)) } - filter { it.substringBefore('?').substringAfterLast('.') == "js" } - .forEach { script(type = ScriptType.textJavaScript, src = page.root(it)) { async = true } } - } - script { unsafe { +"""var pathToRoot = "${locationProvider.resolveRoot(page)}";""" } } - } - body { - div { - id = "navigation" - div { - id = "searchBar" - form(action = page.root("-search.html"), method = FormMethod.get) { - id = "searchForm" - input(type = InputType.search, name = "query") - input(type = InputType.submit) { value = "Search" } - } - } - div { - id = "sideMenu" - } - } - div { - id = "content" - content() - } - } - } -} - -fun List<HTMLMetadata>.joinAttr() = joinToString(" ") { it.key + "=" + it.value } - -private fun PageNode.pageKind() = when (this) { - is PackagePageNode -> "package" - is ClasslikePageNode -> "class" - is MemberPageNode -> when (this.documentable) { - is Function -> "function" - else -> "other" - } - else -> "other" -} - -private val PageNode.isNavigable: Boolean - get() = this !is RendererSpecificPage || strategy != RenderingStrategy.DoNothing
\ No newline at end of file diff --git a/core/src/main/kotlin/renderers/html/NavigationPage.kt b/core/src/main/kotlin/renderers/html/NavigationPage.kt deleted file mode 100644 index 4a2fb40d..00000000 --- a/core/src/main/kotlin/renderers/html/NavigationPage.kt +++ /dev/null @@ -1,50 +0,0 @@ -package org.jetbrains.dokka.renderers.html - -import kotlinx.html.* -import kotlinx.html.stream.createHTML -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.pages.PageNode -import org.jetbrains.dokka.pages.PlatformData -import org.jetbrains.dokka.pages.RendererSpecificPage -import org.jetbrains.dokka.pages.RenderingStrategy - -class NavigationPage(val root: NavigationNode) : RendererSpecificPage { - override val name = "navigation" - - override val children = emptyList<PageNode>() - - override fun modified(name: String, children: List<PageNode>) = this - - override val strategy = RenderingStrategy<HtmlRenderer> { - createHTML().visit(root, "nav-submenu", this) - } - - private fun <R> TagConsumer<R>.visit(node: NavigationNode, navId: String, renderer: HtmlRenderer): R = - with(renderer) { - div("sideMenuPart") { - id = navId - div("overview") { - buildLink(node.dri, node.platforms) { +node.name } - if (node.children.isNotEmpty()) { - span("navButton") { - onClick = """document.getElementById("$navId").classList.toggle("hidden");""" - span("navButtonContent") - } - } - } - node.children.withIndex().forEach { (n, p) -> visit(p, "$navId-$n", renderer) } - } - } -} - -class NavigationNode( - val name: String, - val dri: DRI, - val platforms: List<PlatformData>, - val children: List<NavigationNode> -) - -fun NavigationPage.transform(block: (NavigationNode) -> NavigationNode) = NavigationPage(root.transform(block)) - -fun NavigationNode.transform(block: (NavigationNode) -> NavigationNode) = - run(block).let { NavigationNode(it.name, it.dri, it.platforms, it.children.map(block)) } diff --git a/core/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/core/src/main/kotlin/renderers/html/htmlPreprocessors.kt deleted file mode 100644 index 4ee67448..00000000 --- a/core/src/main/kotlin/renderers/html/htmlPreprocessors.kt +++ /dev/null @@ -1,68 +0,0 @@ -package org.jetbrains.dokka.renderers.html - -import kotlinx.html.h1 -import kotlinx.html.id -import kotlinx.html.table -import kotlinx.html.tbody -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.renderers.platforms -import org.jetbrains.dokka.transformers.pages.PageNodeTransformer - -object RootCreator : PageNodeTransformer { - override fun invoke(input: RootPageNode) = - RendererSpecificRootPage("", listOf(input), RenderingStrategy.DoNothing) -} - -object SearchPageInstaller : PageNodeTransformer { - override fun invoke(input: RootPageNode) = input.modified(children = input.children + searchPage) - - private val searchPage = RendererSpecificResourcePage( - name = "Search", - children = emptyList(), - strategy = RenderingStrategy<HtmlRenderer> { - buildHtml(it, listOf("styles/style.css", "scripts/pages.js")) { - h1 { - id = "searchTitle" - text("Search results for ") - } - table { - tbody { - id = "searchTable" - } - } - } - }) -} - -object NavigationPageInstaller : PageNodeTransformer { - override fun invoke(input: RootPageNode) = input.modified( - children = input.children + NavigationPage( - input.children.filterIsInstance<ContentPage>().single().let(::visit) - ) - ) - - private fun visit(page: ContentPage): NavigationNode = NavigationNode( - page.name, - page.dri.first(), - page.platforms(), - page.children.filterIsInstance<ContentPage>().map { visit(it) }) -} - -object ResourceInstaller : PageNodeTransformer { - override fun invoke(input: RootPageNode) = input.modified(children = input.children + resourcePages) - - private val resourcePages = listOf("styles", "scripts", "images").map { - RendererSpecificResourcePage(it, emptyList(), RenderingStrategy.Copy("/dokka/$it")) - } -} - -object StyleAndScriptsAppender : PageNodeTransformer { - override fun invoke(input: RootPageNode) = input.transformContentPagesTree { - it.modified( - embeddedResources = it.embeddedResources + listOf( - "styles/style.css", - "scripts/navigationLoader.js" - ) - ) - } -} diff --git a/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt deleted file mode 100644 index 055df0b2..00000000 --- a/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt +++ /dev/null @@ -1,143 +0,0 @@ -package org.jetbrains.dokka.transformers.psi - -import com.intellij.psi.* -import com.intellij.psi.impl.source.PsiClassReferenceType -import org.jetbrains.dokka.JavadocParser -import org.jetbrains.dokka.links.Callable -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.JavaClassReference -import org.jetbrains.dokka.links.withClass -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Function -import org.jetbrains.dokka.pages.PlatformData -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.idea.caches.project.getPlatformModuleInfo -import org.jetbrains.kotlin.platform.TargetPlatform - -object DefaultPsiToDocumentationTranslator : PsiToDocumentationTranslator { - - override fun invoke( - moduleName: String, - psiFiles: List<PsiJavaFile>, - platformData: PlatformData, - context: DokkaContext - ): Module { - val docParser = DokkaPsiParser(platformData, context.logger) - return Module(moduleName, - psiFiles.map { psiFile -> - val dri = DRI(packageName = psiFile.packageName) - Package( - dri, - emptyList(), - emptyList(), - psiFile.classes.map { docParser.parseClass(it, dri) } - ) - } - ) - } - - class DokkaPsiParser( - private val platformData: PlatformData, - logger: DokkaLogger - ) { - - private val javadocParser: JavadocParser = JavadocParser(logger) - - private fun getComment(psi: PsiNamedElement): List<PlatformInfo> { - val comment = javadocParser.parseDocumentation(psi) - return listOf(BasePlatformInfo(comment, listOf(platformData))) - } - - private fun PsiModifierListOwner.getVisibility() = modifierList?.children?.toList()?.let { ml -> - when { - ml.any { it.text == PsiKeyword.PUBLIC } -> Visibilities.PUBLIC - ml.any { it.text == PsiKeyword.PROTECTED } -> Visibilities.PROTECTED - else -> Visibilities.PRIVATE - } - } ?: Visibilities.PRIVATE - - fun parseClass(psi: PsiClass, parent: DRI): Class = with(psi) { - val kind = when { - isAnnotationType -> JavaClassKindTypes.ANNOTATION_CLASS - isInterface -> JavaClassKindTypes.INTERFACE - isEnum -> JavaClassKindTypes.ENUM_CLASS - else -> JavaClassKindTypes.CLASS - } - val dri = parent.withClass(name.toString()) - /*superTypes.filter { !ignoreSupertype(it) }.forEach { - node.appendType(it, NodeKind.Supertype) - val superClass = it.resolve() - if (superClass != null) { - link(superClass, node, RefKind.Inheritor) - } - }*/ - val inherited = emptyList<DRI>() //listOf(psi.superClass) + psi.interfaces // TODO DRIs of inherited - val actual = getComment(psi).map { ClassPlatformInfo(it, inherited) } - - return Class( - dri = dri, - name = name.orEmpty(), - kind = kind, - constructors = constructors.map { parseFunction(it, dri, true) }, - functions = methods.mapNotNull { if (!it.isConstructor) parseFunction(it, dri) else null }, - properties = fields.mapNotNull { parseField(it, dri) }, - classlikes = innerClasses.map { parseClass(it, dri) }, - expected = null, - actual = actual, - extra = mutableSetOf(), - visibility = mapOf(platformData to psi.getVisibility()) - ) - } - - private fun parseFunction(psi: PsiMethod, parent: DRI, isConstructor: Boolean = false): Function { - val dri = parent.copy(callable = Callable( - psi.name, - JavaClassReference(psi.containingClass?.name.orEmpty()), - psi.parameterList.parameters.map { parameter -> - JavaClassReference(parameter.type.canonicalText) - } - ) - ) - return Function( - dri, - if (isConstructor) "<init>" else psi.name, - psi.returnType?.let { JavaTypeWrapper(type = it) }, - isConstructor, - null, - psi.parameterList.parameters.mapIndexed { index, psiParameter -> - Parameter( - dri.copy(target = index + 1), - psiParameter.name, - JavaTypeWrapper(psiParameter.type), - null, - getComment(psi) - ) - }, - null, - getComment(psi), - visibility = mapOf(platformData to psi.getVisibility()) - ) - } - - private fun parseField(psi: PsiField, parent: DRI): Property { - val dri = parent.copy( - callable = Callable( - psi.name, - JavaClassReference(psi.containingClass?.name.orEmpty()), - emptyList() - ) - ) - return Property( - dri, - psi.name, - null, - null, - getComment(psi), - accessors = emptyList(), - visibility = mapOf(platformData to psi.getVisibility()) - ) - } - } -} |