aboutsummaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorPaweł Marks <pmarks@virtuslab.com>2020-07-17 16:36:09 +0200
committerPaweł Marks <pmarks@virtuslab.com>2020-07-17 16:36:09 +0200
commit6996b1135f61c7d2cb60b0652c6a2691dda31990 (patch)
treed568096c25e31c28d14d518a63458b5a7526b896 /core/src
parentde56cab76f556e5b4af0b8c8cb08d8b482b86d0a (diff)
parent1c3530dcbb50c347f80bef694829dbefe89eca77 (diff)
downloaddokka-6996b1135f61c7d2cb60b0652c6a2691dda31990.tar.gz
dokka-6996b1135f61c7d2cb60b0652c6a2691dda31990.tar.bz2
dokka-6996b1135f61c7d2cb60b0652c6a2691dda31990.zip
Merge branch 'dev-0.11.0'
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/kotlin/Analysis/AnalysisEnvironment.kt592
-rw-r--r--core/src/main/kotlin/Analysis/CoreKotlinCacheService.kt42
-rw-r--r--core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt569
-rw-r--r--core/src/main/kotlin/Analysis/JavaResolveExtension.kt128
-rw-r--r--core/src/main/kotlin/CoreExtensions.kt29
-rw-r--r--core/src/main/kotlin/DokkaBootstrap.kt11
-rw-r--r--core/src/main/kotlin/DokkaBootstrapImpl.kt90
-rw-r--r--core/src/main/kotlin/DokkaException.kt3
-rw-r--r--core/src/main/kotlin/DokkaGenerator.kt164
-rw-r--r--core/src/main/kotlin/DokkaMultimoduleBootstrapImpl.kt29
-rw-r--r--core/src/main/kotlin/DokkaVersion.kt10
-rw-r--r--core/src/main/kotlin/Formats/AnalysisComponents.kt45
-rw-r--r--core/src/main/kotlin/Formats/FormatDescriptor.kt43
-rw-r--r--core/src/main/kotlin/Formats/FormatService.kt32
-rw-r--r--core/src/main/kotlin/Formats/GFMFormatService.kt61
-rw-r--r--core/src/main/kotlin/Formats/HtmlFormatService.kt166
-rw-r--r--core/src/main/kotlin/Formats/HtmlTemplateService.kt38
-rw-r--r--core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlPackageListService.kt117
-rw-r--r--core/src/main/kotlin/Formats/JavaLayoutHtmlFormat.kt91
-rw-r--r--core/src/main/kotlin/Formats/JekyllFormatService.kt44
-rw-r--r--core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt264
-rw-r--r--core/src/main/kotlin/Formats/MarkdownFormatService.kt250
-rw-r--r--core/src/main/kotlin/Formats/OutlineService.kt29
-rw-r--r--core/src/main/kotlin/Formats/PackageListService.kt66
-rw-r--r--core/src/main/kotlin/Formats/StandardFormats.kt55
-rw-r--r--core/src/main/kotlin/Formats/StructuredFormatService.kt1014
-rw-r--r--core/src/main/kotlin/Formats/YamlOutlineService.kt26
-rw-r--r--core/src/main/kotlin/Generation/DocumentationMerger.kt235
-rw-r--r--core/src/main/kotlin/Generation/DokkaGenerator.kt223
-rw-r--r--core/src/main/kotlin/Generation/FileGenerator.kt108
-rw-r--r--core/src/main/kotlin/Generation/Generator.kt29
-rw-r--r--core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt361
-rw-r--r--core/src/main/kotlin/Java/JavadocParser.kt401
-rw-r--r--core/src/main/kotlin/Kotlin/ContentBuilder.kt188
-rw-r--r--core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt73
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt177
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt1166
-rw-r--r--core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt305
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt68
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinAsJavaElementSignatureProvider.kt25
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt33
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinLanguageService.kt473
-rw-r--r--core/src/main/kotlin/Languages/CommonLanguageService.kt84
-rw-r--r--core/src/main/kotlin/Languages/JavaLanguageService.kt171
-rw-r--r--core/src/main/kotlin/Languages/LanguageService.kt41
-rw-r--r--core/src/main/kotlin/Languages/NewJavaLanguageService.kt197
-rw-r--r--core/src/main/kotlin/Locations/Location.kt76
-rw-r--r--core/src/main/kotlin/Markdown/MarkdownProcessor.kt53
-rw-r--r--core/src/main/kotlin/Model/Content.kt290
-rw-r--r--core/src/main/kotlin/Model/DocumentationNode.kt276
-rw-r--r--core/src/main/kotlin/Model/DocumentationReference.kt126
-rw-r--r--core/src/main/kotlin/Model/ElementSignatureProvider.kt9
-rw-r--r--core/src/main/kotlin/Model/PackageDocs.kt136
-rw-r--r--core/src/main/kotlin/Model/SourceLinks.kt78
-rw-r--r--core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt103
-rw-r--r--core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt197
-rw-r--r--core/src/main/kotlin/Samples/SampleProcessingService.kt9
-rw-r--r--core/src/main/kotlin/Utilities/DokkaLogging.kt27
-rw-r--r--core/src/main/kotlin/Utilities/DokkaModules.kt85
-rw-r--r--core/src/main/kotlin/Utilities/Links.kt18
-rw-r--r--core/src/main/kotlin/Utilities/Path.kt5
-rw-r--r--core/src/main/kotlin/configuration.kt149
-rw-r--r--core/src/main/kotlin/defaultConfiguration.kt83
-rw-r--r--core/src/main/kotlin/javadoc/docbase.kt539
-rw-r--r--core/src/main/kotlin/javadoc/dokka-adapters.kt42
-rw-r--r--core/src/main/kotlin/javadoc/reporter.kt34
-rw-r--r--core/src/main/kotlin/javadoc/source-position.kt19
-rw-r--r--core/src/main/kotlin/javadoc/tags.kt228
-rw-r--r--core/src/main/kotlin/links/DRI.kt105
-rw-r--r--core/src/main/kotlin/model/Documentable.kt398
-rw-r--r--core/src/main/kotlin/model/WithChildren.kt64
-rw-r--r--core/src/main/kotlin/model/additionalExtras.kt75
-rw-r--r--core/src/main/kotlin/model/classKinds.kt20
-rw-r--r--core/src/main/kotlin/model/defaultValues.kt13
-rw-r--r--core/src/main/kotlin/model/doc/DocTag.kt96
-rw-r--r--core/src/main/kotlin/model/doc/DocumentationNode.kt5
-rw-r--r--core/src/main/kotlin/model/doc/TagWrapper.kt39
-rw-r--r--core/src/main/kotlin/model/documentableProperties.kt27
-rw-r--r--core/src/main/kotlin/model/documentableUtils.kt22
-rw-r--r--core/src/main/kotlin/model/extraModifiers.kt62
-rw-r--r--core/src/main/kotlin/model/properties/PropertyContainer.kt60
-rw-r--r--core/src/main/kotlin/model/properties/properties.kt22
-rw-r--r--core/src/main/kotlin/pages/ContentNodes.kt266
-rw-r--r--core/src/main/kotlin/pages/PageNodes.kt181
-rw-r--r--core/src/main/kotlin/pages/RendererSpecificPage.kt40
-rw-r--r--core/src/main/kotlin/pages/contentNodeProperties.kt12
-rw-r--r--core/src/main/kotlin/pages/utils.kt31
-rw-r--r--core/src/main/kotlin/plugability/DefaultExtensions.kt0
-rw-r--r--core/src/main/kotlin/plugability/DokkaContext.kt223
-rw-r--r--core/src/main/kotlin/plugability/DokkaPlugin.kt82
-rw-r--r--core/src/main/kotlin/plugability/LazyEvaluated.kt16
-rw-r--r--core/src/main/kotlin/plugability/extensions.kt87
-rw-r--r--core/src/main/kotlin/renderers/Renderer.kt7
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt8
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt9
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt8
-rw-r--r--core/src/main/kotlin/transformers/documentation/PreMergeDocumentableTransformer.kt8
-rw-r--r--core/src/main/kotlin/transformers/pages/PageCreator.kt8
-rw-r--r--core/src/main/kotlin/transformers/pages/PageTransformer.kt7
-rw-r--r--core/src/main/kotlin/transformers/pages/PageTransformerBuilders.kt22
-rw-r--r--core/src/main/kotlin/transformers/sources/SourceToDocumentableTranslator.kt9
-rw-r--r--core/src/main/kotlin/utilities/DokkaLogging.kt38
-rw-r--r--core/src/main/kotlin/utilities/Html.kt (renamed from core/src/main/kotlin/Utilities/Html.kt)7
-rw-r--r--core/src/main/kotlin/utilities/ServiceLocator.kt (renamed from core/src/main/kotlin/Utilities/ServiceLocator.kt)2
-rw-r--r--core/src/main/kotlin/utilities/Uri.kt (renamed from core/src/main/kotlin/Utilities/Uri.kt)2
-rw-r--r--core/src/main/kotlin/utilities/cast.kt5
-rw-r--r--core/src/main/kotlin/utilities/nodeDebug.kt50
-rw-r--r--core/src/main/resources/META-INF/MANIFEST.MF3
-rw-r--r--core/src/main/resources/META-INF/dokka/dokka-version.properties1
-rw-r--r--core/src/main/resources/dokka/format/gfm.properties2
-rw-r--r--core/src/main/resources/dokka/format/html-as-java.properties2
-rw-r--r--core/src/main/resources/dokka/format/html.properties2
-rw-r--r--core/src/main/resources/dokka/format/java-layout-html.properties2
-rw-r--r--core/src/main/resources/dokka/format/javadoc.properties2
-rw-r--r--core/src/main/resources/dokka/format/jekyll.properties2
-rw-r--r--core/src/main/resources/dokka/format/kotlin-website-html.properties2
-rw-r--r--core/src/main/resources/dokka/format/markdown.properties2
-rw-r--r--core/src/main/resources/dokka/inbound-link-resolver/dokka-default.properties2
-rw-r--r--core/src/main/resources/dokka/inbound-link-resolver/java-layout-html.properties2
-rw-r--r--core/src/main/resources/dokka/inbound-link-resolver/javadoc.properties2
-rw-r--r--core/src/main/resources/dokka/styles/style.css283
-rw-r--r--core/src/test/kotlin/DokkaConfigurationTestImplementations.kt81
-rw-r--r--core/src/test/kotlin/NodeSelect.kt90
-rw-r--r--core/src/test/kotlin/TestAPI.kt353
-rw-r--r--core/src/test/kotlin/format/FileGeneratorTestCase.kt35
-rw-r--r--core/src/test/kotlin/format/GFMFormatTest.kt36
-rw-r--r--core/src/test/kotlin/format/HtmlFormatTest.kt192
-rw-r--r--core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt123
-rw-r--r--core/src/test/kotlin/format/MarkdownFormatTest.kt615
-rw-r--r--core/src/test/kotlin/format/PackageDocsTest.kt92
-rw-r--r--core/src/test/kotlin/issues/IssuesTest.kt34
-rw-r--r--core/src/test/kotlin/javadoc/JavadocTest.kt333
-rw-r--r--core/src/test/kotlin/markdown/ParserTest.kt154
-rw-r--r--core/src/test/kotlin/model/ClassTest.kt318
-rw-r--r--core/src/test/kotlin/model/CommentTest.kt190
-rw-r--r--core/src/test/kotlin/model/DocumentableTest.kt108
-rw-r--r--core/src/test/kotlin/model/FunctionTest.kt281
-rw-r--r--core/src/test/kotlin/model/JavaTest.kt210
-rw-r--r--core/src/test/kotlin/model/KotlinAsJavaTest.kt64
-rw-r--r--core/src/test/kotlin/model/LinkTest.kt91
-rw-r--r--core/src/test/kotlin/model/PackageTest.kt136
-rw-r--r--core/src/test/kotlin/model/PropertyTest.kt129
-rw-r--r--core/src/test/kotlin/model/SourceLinksErrorTest.kt35
-rw-r--r--core/src/test/kotlin/model/SourceLinksTest.kt75
-rw-r--r--core/src/test/kotlin/model/TypeAliasTest.kt132
-rw-r--r--core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker1
146 files changed, 2779 insertions, 14522 deletions
diff --git a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
deleted file mode 100644
index f5705c89..00000000
--- a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
+++ /dev/null
@@ -1,592 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.common.collect.ImmutableMap
-import com.intellij.core.CoreApplicationEnvironment
-import com.intellij.core.CoreModuleManager
-import com.intellij.mock.MockApplication
-import com.intellij.mock.MockComponentManager
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.extensions.Extensions
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.module.ModuleManager
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.roots.OrderEnumerationHandler
-import com.intellij.openapi.roots.ProjectFileIndex
-import com.intellij.openapi.roots.ProjectRootManager
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.vfs.StandardFileSystems
-import com.intellij.psi.PsiElement
-import com.intellij.psi.search.GlobalSearchScope
-import org.jetbrains.kotlin.analyzer.*
-import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
-import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
-import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
-import org.jetbrains.kotlin.builtins.DefaultBuiltIns
-import org.jetbrains.kotlin.builtins.KotlinBuiltIns
-import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
-import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
-import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
-import org.jetbrains.kotlin.cli.common.config.ContentRoot
-import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
-import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
-import org.jetbrains.kotlin.cli.common.messages.MessageCollector
-import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
-import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
-import org.jetbrains.kotlin.cli.jvm.config.*
-import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
-import org.jetbrains.kotlin.config.*
-import org.jetbrains.kotlin.container.getService
-import org.jetbrains.kotlin.container.tryGetService
-import org.jetbrains.kotlin.context.ProjectContext
-import org.jetbrains.kotlin.context.withModule
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.descriptors.ModuleDescriptor
-import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
-import org.jetbrains.kotlin.ide.konan.NativeLibraryInfo
-import org.jetbrains.kotlin.ide.konan.analyzer.NativeResolverForModuleFactory
-import org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeLoadingMetadataCache
-import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
-import org.jetbrains.kotlin.js.config.JSConfigurationKeys
-import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
-import org.jetbrains.kotlin.js.resolve.JsResolverForModuleFactory
-import org.jetbrains.kotlin.library.impl.createKotlinLibrary
-import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
-import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.platform.CommonPlatforms
-import org.jetbrains.kotlin.platform.TargetPlatform
-import org.jetbrains.kotlin.platform.js.JsPlatforms
-import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
-import org.jetbrains.kotlin.platform.jvm.JvmPlatforms.unspecifiedJvmPlatform
-import org.jetbrains.kotlin.platform.konan.KonanPlatforms
-import org.jetbrains.kotlin.psi.*
-import org.jetbrains.kotlin.resolve.BindingContext
-import org.jetbrains.kotlin.resolve.BindingTrace
-import org.jetbrains.kotlin.resolve.CompilerEnvironment
-import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
-import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
-import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
-import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory
-import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
-import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices
-import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
-import org.jetbrains.kotlin.resolve.lazy.ResolveSession
-import org.jetbrains.kotlin.types.KotlinType
-import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
-import org.jetbrains.kotlin.util.slicedMap.WritableSlice
-import java.io.File
-
-const val JAR_SEPARATOR = "!/"
-const val KLIB_EXTENSION = "klib"
-
-/**
- * Kotlin as a service entry point
- *
- * Configures environment, analyses files and provides facilities to perform code processing without emitting bytecode
- *
- * $messageCollector: required by compiler infrastructure and will receive all compiler messages
- * $body: optional and can be used to configure environment without creating local variable
- */
-class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPlatform: Platform) : Disposable {
- val configuration = CompilerConfiguration()
-
- init {
- configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
- }
-
- fun createCoreEnvironment(): KotlinCoreEnvironment {
- System.setProperty("idea.io.use.fallback", "true")
-
- val configFiles = when (analysisPlatform) {
- Platform.jvm, Platform.common -> EnvironmentConfigFiles.JVM_CONFIG_FILES
- Platform.native -> EnvironmentConfigFiles.NATIVE_CONFIG_FILES
- Platform.js -> EnvironmentConfigFiles.JS_CONFIG_FILES
- }
-
- val environment = KotlinCoreEnvironment.createForProduction(this, configuration, configFiles)
- val projectComponentManager = environment.project as MockComponentManager
-
- val projectFileIndex = CoreProjectFileIndex(
- environment.project,
- environment.configuration.getList(CLIConfigurationKeys.CONTENT_ROOTS)
- )
-
- val moduleManager = object : CoreModuleManager(environment.project, this) {
- override fun getModules(): Array<out Module> = arrayOf(projectFileIndex.module)
- }
-
- CoreApplicationEnvironment.registerComponentInstance(
- projectComponentManager.picoContainer,
- ModuleManager::class.java, moduleManager
- )
-
- Extensions.registerAreaClass("IDEA_MODULE", null)
- CoreApplicationEnvironment.registerExtensionPoint(
- Extensions.getRootArea(),
- OrderEnumerationHandler.EP_NAME, OrderEnumerationHandler.Factory::class.java
- )
-
- projectComponentManager.registerService(
- ProjectFileIndex::class.java,
- projectFileIndex
- )
-
- projectComponentManager.registerService(
- ProjectRootManager::class.java,
- CoreProjectRootManager(projectFileIndex)
- )
-
- return environment
- }
-
- private fun createSourceModuleSearchScope(project: Project, sourceFiles: List<KtFile>): GlobalSearchScope =
- when (analysisPlatform) {
- Platform.jvm -> TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, sourceFiles)
- Platform.js, Platform.common, Platform.native -> GlobalSearchScope.filesScope(
- project,
- sourceFiles.map { it.virtualFile }.toSet()
- )
- }
-
- fun createResolutionFacade(environment: KotlinCoreEnvironment): Pair<DokkaResolutionFacade, DokkaResolutionFacade> {
- val projectContext = ProjectContext(environment.project, "Dokka")
- val sourceFiles = environment.getSourceFiles()
-
-
- val targetPlatform = when (analysisPlatform) {
- Platform.js -> JsPlatforms.defaultJsPlatform
- Platform.common -> CommonPlatforms.defaultCommonPlatform
- Platform.native -> KonanPlatforms.defaultKonanPlatform
- Platform.jvm -> JvmPlatforms.defaultJvmPlatform
- }
-
- val nativeLibraries = classpath.filter { it.extension == KLIB_EXTENSION }
- .map { createNativeLibraryModuleInfo(it) }
-
- val library = object : LibraryModuleInfo {
- override val analyzerServices: PlatformDependentAnalyzerServices =
- analysisPlatform.analyzerServices()
- override val name: Name = Name.special("<library>")
- override val platform: TargetPlatform = targetPlatform
- override fun dependencies(): List<ModuleInfo> = listOf(this)
- override fun getLibraryRoots(): Collection<String> =
- classpath.filterNot { it.extension == KLIB_EXTENSION }.map { it.absolutePath }
- }
-
- val module = object : ModuleInfo {
- override val analyzerServices: PlatformDependentAnalyzerServices =
- analysisPlatform.analyzerServices()
- override val name: Name = Name.special("<module>")
- override val platform: TargetPlatform = targetPlatform
- override fun dependencies(): List<ModuleInfo> = listOf(this, library) + nativeLibraries
- }
-
- val sourcesScope = createSourceModuleSearchScope(environment.project, sourceFiles)
- val modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo> = {
- when (it) {
- library -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope))
- module -> ModuleContent(it, emptyList(), GlobalSearchScope.allScope(environment.project))
- in nativeLibraries -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope))
- else -> throw IllegalArgumentException("Unexpected module info")
- }
- }
-
- var builtIns: JvmBuiltIns? = null
-
- val resolverForProject = when (analysisPlatform) {
- Platform.jvm -> {
- builtIns = JvmBuiltIns(
- projectContext.storageManager,
- JvmBuiltIns.Kind.FROM_CLASS_LOADER
- ) // TODO we should use FROM_DEPENDENCIES
- createJvmResolverForProject(
- projectContext,
- module,
- library,
- modulesContent,
- sourcesScope,
- builtIns
- )
- }
- Platform.common -> createCommonResolverForProject(
- projectContext,
- module,
- library,
- modulesContent,
- environment
- )
- Platform.js -> createJsResolverForProject(projectContext, module, library, modulesContent)
- Platform.native -> createNativeResolverForProject(projectContext, module, library, modulesContent)
-
- }
- val libraryModuleDescriptor = resolverForProject.descriptorForModule(library)
- val moduleDescriptor = resolverForProject.descriptorForModule(module)
- builtIns?.initialize(moduleDescriptor, true)
-
- val resolverForLibrary =
- resolverForProject.resolverForModule(library) // Required before module to initialize library properly
- val resolverForModule = resolverForProject.resolverForModule(module)
- val libraryResolutionFacade =
- DokkaResolutionFacade(environment.project, libraryModuleDescriptor, resolverForLibrary)
- val created = DokkaResolutionFacade(environment.project, moduleDescriptor, resolverForModule)
- val projectComponentManager = environment.project as MockComponentManager
- projectComponentManager.registerService(KotlinCacheService::class.java, CoreKotlinCacheService(created))
-
- return created to libraryResolutionFacade
- }
-
- private fun Platform.analyzerServices() = when (this) {
- Platform.js -> JsPlatformAnalyzerServices
- Platform.common -> CommonPlatformAnalyzerServices
- Platform.native -> NativePlatformAnalyzerServices
- Platform.jvm -> JvmPlatformAnalyzerServices
- }
-
- private fun createNativeLibraryModuleInfo(libraryFile: File): LibraryModuleInfo {
- val kotlinLibrary = createKotlinLibrary(org.jetbrains.kotlin.konan.file.File(libraryFile.absolutePath), false)
- return object : LibraryModuleInfo {
- override val analyzerServices: PlatformDependentAnalyzerServices =
- analysisPlatform.analyzerServices()
- override val name: Name = Name.special("<klib>")
- override val platform: TargetPlatform = KonanPlatforms.defaultKonanPlatform
- override fun dependencies(): List<ModuleInfo> = listOf(this)
- override fun getLibraryRoots(): Collection<String> = listOf(libraryFile.absolutePath)
- override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
- get() = super.capabilities + (NativeLibraryInfo.NATIVE_LIBRARY_CAPABILITY to kotlinLibrary)
- }
- }
-
- private fun createCommonResolverForProject(
- projectContext: ProjectContext,
- module: ModuleInfo,
- library: LibraryModuleInfo,
- modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>,
- environment: KotlinCoreEnvironment
- ): ResolverForProject<ModuleInfo> {
- return object : AbstractResolverForProject<ModuleInfo>(
- "Dokka",
- projectContext,
- modules = listOf(module, library)
- ) {
- override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null
-
- override fun modulesContent(module: ModuleInfo): ModuleContent<ModuleInfo> = modulesContent(module)
-
- override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance
-
- override fun createResolverForModule(
- descriptor: ModuleDescriptor,
- moduleInfo: ModuleInfo
- ): ResolverForModule =
- CommonResolverForModuleFactory(
- CommonAnalysisParameters { content ->
- environment.createPackagePartProvider(content.moduleContentScope)
- },
- CompilerEnvironment,
- unspecifiedJvmPlatform,
- true
- ).createResolverForModule(
- descriptor as ModuleDescriptorImpl,
- projectContext.withModule(descriptor),
- modulesContent(moduleInfo),
- this,
- LanguageVersionSettingsImpl.DEFAULT
- )
- }
- }
-
- private fun createJsResolverForProject(
- projectContext: ProjectContext,
- module: ModuleInfo,
- library: LibraryModuleInfo,
- modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>
- ): ResolverForProject<ModuleInfo> {
- return object : AbstractResolverForProject<ModuleInfo>(
- "Dokka",
- projectContext,
- modules = listOf(module, library)
- ) {
- override fun modulesContent(module: ModuleInfo): ModuleContent<ModuleInfo> = modulesContent(module)
- override fun createResolverForModule(
- descriptor: ModuleDescriptor,
- moduleInfo: ModuleInfo
- ): ResolverForModule = JsResolverForModuleFactory(
- CompilerEnvironment
- ).createResolverForModule(
- descriptor as ModuleDescriptorImpl,
- projectContext.withModule(descriptor),
- modulesContent(moduleInfo),
- this,
- LanguageVersionSettingsImpl.DEFAULT
- )
-
- override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance
-
- override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null
- }
- }
-
- private fun createNativeResolverForProject(
- projectContext: ProjectContext,
- module: ModuleInfo,
- library: LibraryModuleInfo,
- modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>
- ): ResolverForProject<ModuleInfo> {
- return object : AbstractResolverForProject<ModuleInfo>(
- "Dokka",
- projectContext,
- modules = module.dependencies()
- ) {
- override fun modulesContent(module: ModuleInfo): ModuleContent<ModuleInfo> = modulesContent(module)
- override fun createResolverForModule(
- descriptor: ModuleDescriptor,
- moduleInfo: ModuleInfo
- ): ResolverForModule {
- (ApplicationManager.getApplication() as MockApplication).addComponent(
- KotlinNativeLoadingMetadataCache::class.java,
- KotlinNativeLoadingMetadataCache()
- )
-
- return NativeResolverForModuleFactory(
- PlatformAnalysisParameters.Empty,
- CompilerEnvironment,
- KonanPlatforms.defaultKonanPlatform
- ).createResolverForModule(
- descriptor as ModuleDescriptorImpl,
- projectContext.withModule(descriptor),
- modulesContent(moduleInfo),
- this,
- LanguageVersionSettingsImpl.DEFAULT
- )
- }
-
- override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance
-
- override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null
- }
- }
-
- private fun createJvmResolverForProject(
- projectContext: ProjectContext,
- module: ModuleInfo,
- library: LibraryModuleInfo,
- modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>,
- sourcesScope: GlobalSearchScope,
- builtIns: KotlinBuiltIns
- ): ResolverForProject<ModuleInfo> {
- val javaRoots = classpath
- .mapNotNull {
- val rootFile = when (it.extension) {
- "jar" -> StandardFileSystems.jar().findFileByPath("${it.absolutePath}${JAR_SEPARATOR}")
- else -> StandardFileSystems.local().findFileByPath(it.absolutePath)
- }
- rootFile?.let { JavaRoot(it, JavaRoot.RootType.BINARY) }
- }
-
- return object : AbstractResolverForProject<ModuleInfo>(
- "Dokka",
- projectContext,
- modules = listOf(module, library)
- ) {
- override fun modulesContent(module: ModuleInfo): ModuleContent<ModuleInfo> =
- when (module) {
- library -> ModuleContent(module, emptyList(), GlobalSearchScope.notScope(sourcesScope))
- module -> ModuleContent(module, emptyList(), sourcesScope)
- else -> throw IllegalArgumentException("Unexpected module info")
- }
-
- override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = builtIns
-
- override fun createResolverForModule(
- descriptor: ModuleDescriptor,
- moduleInfo: ModuleInfo
- ): ResolverForModule = JvmResolverForModuleFactory(
- JvmPlatformParameters({ content ->
- JvmPackagePartProvider(
- configuration.languageVersionSettings,
- content.moduleContentScope
- )
- .apply {
- addRoots(javaRoots, messageCollector)
- }
- }, {
- val file = (it as JavaClassImpl).psi.containingFile.virtualFile
- if (file in sourcesScope)
- module
- else
- library
- }),
- CompilerEnvironment,
- KonanPlatforms.defaultKonanPlatform
- ).createResolverForModule(
- descriptor as ModuleDescriptorImpl,
- projectContext.withModule(descriptor),
- modulesContent(moduleInfo),
- this,
- LanguageVersionSettingsImpl.DEFAULT
- )
-
- override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null
- }
- }
-
- fun loadLanguageVersionSettings(languageVersionString: String?, apiVersionString: String?) {
- val languageVersion = LanguageVersion.fromVersionString(languageVersionString) ?: LanguageVersion.LATEST_STABLE
- val apiVersion =
- apiVersionString?.let { ApiVersion.parse(it) } ?: ApiVersion.createByLanguageVersion(languageVersion)
- configuration.languageVersionSettings = LanguageVersionSettingsImpl(languageVersion, apiVersion)
- }
-
- /**
- * Classpath for this environment.
- */
- val classpath: List<File>
- get() = configuration.jvmClasspathRoots
-
- /**
- * Adds list of paths to classpath.
- * $paths: collection of files to add
- */
- fun addClasspath(paths: List<File>) {
- if (analysisPlatform == Platform.js) {
- configuration.addAll(JSConfigurationKeys.LIBRARIES, paths.map { it.absolutePath })
- }
- configuration.addJvmClasspathRoots(paths)
- }
-
- /**
- * Adds path to classpath.
- * $path: path to add
- */
- fun addClasspath(path: File) {
- if (analysisPlatform == Platform.js) {
- configuration.add(JSConfigurationKeys.LIBRARIES, path.absolutePath)
- }
- configuration.addJvmClasspathRoot(path)
- }
-
- /**
- * List of source roots for this environment.
- */
- val sources: List<String>
- get() = configuration.get(CLIConfigurationKeys.CONTENT_ROOTS)
- ?.filterIsInstance<KotlinSourceRoot>()
- ?.map { it.path } ?: emptyList()
-
- /**
- * Adds list of paths to source roots.
- * $list: collection of files to add
- */
- fun addSources(list: List<String>) {
- list.forEach {
- configuration.addKotlinSourceRoot(it)
- val file = File(it)
- if (file.isDirectory || file.extension == ".java") {
- configuration.addJavaSourceRoot(file)
- }
- }
- }
-
- fun addRoots(list: List<ContentRoot>) {
- configuration.addAll(CLIConfigurationKeys.CONTENT_ROOTS, list)
- }
-
- /**
- * Disposes the environment and frees all associated resources.
- */
- override fun dispose() {
- Disposer.dispose(this)
- }
-}
-
-fun contentRootFromPath(path: String): ContentRoot {
- val file = File(path)
- return if (file.extension == "java") JavaSourceRoot(file, null) else KotlinSourceRoot(path, false)
-}
-
-
-class DokkaResolutionFacade(
- override val project: Project,
- override val moduleDescriptor: ModuleDescriptor,
- val resolverForModule: ResolverForModule
-) : ResolutionFacade {
- override fun analyzeWithAllCompilerChecks(elements: Collection<KtElement>): AnalysisResult {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any> tryGetFrontendService(element: PsiElement, serviceClass: Class<T>): T? {
- return resolverForModule.componentProvider.tryGetService(serviceClass)
- }
-
- override fun resolveToDescriptor(
- declaration: KtDeclaration,
- bodyResolveMode: BodyResolveMode
- ): DeclarationDescriptor {
- return resolveSession.resolveToDescriptor(declaration)
- }
-
- override fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext {
- throw UnsupportedOperationException()
- }
-
- val resolveSession: ResolveSession get() = getFrontendService(ResolveSession::class.java)
-
- override fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode): BindingContext {
- if (element is KtDeclaration) {
- val descriptor = resolveToDescriptor(element)
- return object : BindingContext {
- override fun <K : Any?, V : Any?> getKeys(p0: WritableSlice<K, V>?): Collection<K> {
- throw UnsupportedOperationException()
- }
-
- override fun getType(p0: KtExpression): KotlinType? {
- throw UnsupportedOperationException()
- }
-
- override fun <K : Any?, V : Any?> get(slice: ReadOnlySlice<K, V>?, key: K): V? {
- if (key != element) {
- throw UnsupportedOperationException()
- }
- return when {
- slice == BindingContext.DECLARATION_TO_DESCRIPTOR -> descriptor as V
- slice == BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER && (element as KtParameter).hasValOrVar() -> descriptor as V
- else -> null
- }
- }
-
- override fun getDiagnostics(): Diagnostics {
- throw UnsupportedOperationException()
- }
-
- override fun addOwnDataTo(p0: BindingTrace, p1: Boolean) {
- throw UnsupportedOperationException()
- }
-
- override fun <K : Any?, V : Any?> getSliceContents(p0: ReadOnlySlice<K, V>): ImmutableMap<K, V> {
- throw UnsupportedOperationException()
- }
-
- }
- }
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any> getFrontendService(serviceClass: Class<T>): T {
- return resolverForModule.componentProvider.getService(serviceClass)
- }
-
- override fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T {
- return resolverForModule.componentProvider.getService(serviceClass)
- }
-
- override fun <T : Any> getIdeService(serviceClass: Class<T>): T {
- throw UnsupportedOperationException()
- }
-
-}
diff --git a/core/src/main/kotlin/Analysis/CoreKotlinCacheService.kt b/core/src/main/kotlin/Analysis/CoreKotlinCacheService.kt
deleted file mode 100644
index d9093760..00000000
--- a/core/src/main/kotlin/Analysis/CoreKotlinCacheService.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.PsiFile
-import org.jetbrains.kotlin.analyzer.ModuleInfo
-import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
-import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
-import org.jetbrains.kotlin.psi.KtElement
-import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
-
-
-class CoreKotlinCacheService(private val resolutionFacade: DokkaResolutionFacade) : KotlinCacheService {
- override fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade {
- return resolutionFacade
- }
-
- override fun getResolutionFacade(
- elements: List<KtElement>,
- platform: org.jetbrains.kotlin.platform.TargetPlatform
- ): ResolutionFacade {
- return resolutionFacade
- }
-
- override fun getResolutionFacadeByFile(
- file: PsiFile,
- platform: org.jetbrains.kotlin.platform.TargetPlatform
- ): ResolutionFacade? {
- return resolutionFacade
- }
-
- override fun getResolutionFacadeByModuleInfo(
- moduleInfo: ModuleInfo,
- platform: org.jetbrains.kotlin.platform.TargetPlatform
- ): ResolutionFacade? {
- return resolutionFacade
- }
-
- override fun getSuppressionCache(): KotlinSuppressCache {
- throw UnsupportedOperationException()
- }
-
-}
-
diff --git a/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt b/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt
deleted file mode 100644
index ef45e840..00000000
--- a/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt
+++ /dev/null
@@ -1,569 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.components.BaseComponent
-import com.intellij.openapi.extensions.ExtensionPointName
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.projectRoots.Sdk
-import com.intellij.openapi.projectRoots.SdkAdditionalData
-import com.intellij.openapi.projectRoots.SdkModificator
-import com.intellij.openapi.projectRoots.SdkTypeId
-import com.intellij.openapi.roots.*
-import com.intellij.openapi.roots.impl.ProjectOrderEnumerator
-import com.intellij.openapi.util.Condition
-import com.intellij.openapi.util.Key
-import com.intellij.openapi.util.UserDataHolderBase
-import com.intellij.openapi.vfs.StandardFileSystems
-import com.intellij.openapi.vfs.VfsUtilCore.getVirtualFileForJar
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.openapi.vfs.VirtualFileFilter
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.util.messages.MessageBus
-import org.jetbrains.jps.model.module.JpsModuleSourceRootType
-import org.jetbrains.kotlin.cli.common.config.ContentRoot
-import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
-import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
-import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot
-import org.picocontainer.PicoContainer
-import java.io.File
-
-/**
- * Workaround for the lack of ability to create a ProjectFileIndex implementation using only
- * classes from projectModel-{api,impl}.
- */
-class CoreProjectFileIndex(private val project: Project, contentRoots: List<ContentRoot>) : ProjectFileIndex, ModuleFileIndex {
- override fun iterateContent(p0: ContentIterator, p1: VirtualFileFilter?): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun iterateContentUnderDirectory(p0: VirtualFile, p1: ContentIterator, p2: VirtualFileFilter?): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isInLibrary(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- val sourceRoots = contentRoots.filter { it !is JvmClasspathRoot }
- val classpathRoots = contentRoots.filterIsInstance<JvmClasspathRoot>()
-
- val module: Module = object : UserDataHolderBase(), Module {
- override fun isDisposed(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getOptionValue(p0: String): String? {
- throw UnsupportedOperationException()
- }
-
- override fun clearOption(p0: String) {
- throw UnsupportedOperationException()
- }
-
- override fun getName(): String = "<Dokka module>"
-
- override fun getModuleWithLibrariesScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleWithDependentsScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleContentScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun isLoaded(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun setOption(p0: String, p1: String?) {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleWithDependenciesScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleWithDependenciesAndLibrariesScope(p0: Boolean): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getProject(): Project = this@CoreProjectFileIndex.project
-
- override fun getModuleContentWithDependenciesScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleFilePath(): String {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleTestsWithDependentsScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleScope(p0: Boolean): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleRuntimeScope(p0: Boolean): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleFile(): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getExtensions(p0: ExtensionPointName<T>): Array<out T> {
- throw UnsupportedOperationException()
- }
-
- override fun getComponent(p0: String): BaseComponent? {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getComponent(p0: Class<T>, p1: T): T {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getComponent(interfaceClass: Class<T>): T? {
- if (interfaceClass == ModuleRootManager::class.java) {
- return moduleRootManager as T
- }
- throw UnsupportedOperationException()
- }
-
- override fun getDisposed(): Condition<*> {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getComponents(p0: Class<T>): Array<out T> {
- throw UnsupportedOperationException()
- }
-
- override fun getPicoContainer(): PicoContainer {
- throw UnsupportedOperationException()
- }
-
- override fun hasComponent(p0: Class<*>): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getMessageBus(): MessageBus {
- throw UnsupportedOperationException()
- }
-
- override fun dispose() {
- throw UnsupportedOperationException()
- }
- }
-
- private val sdk: Sdk = object : Sdk, RootProvider {
- override fun getFiles(rootType: OrderRootType): Array<out VirtualFile> = classpathRoots
- .mapNotNull { StandardFileSystems.local().findFileByPath(it.file.path) }
- .toTypedArray()
-
- override fun addRootSetChangedListener(p0: RootProvider.RootSetChangedListener) {
- throw UnsupportedOperationException()
- }
-
- override fun addRootSetChangedListener(p0: RootProvider.RootSetChangedListener, p1: Disposable) {
- throw UnsupportedOperationException()
- }
-
- override fun getUrls(p0: OrderRootType): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun removeRootSetChangedListener(p0: RootProvider.RootSetChangedListener) {
- throw UnsupportedOperationException()
- }
-
- override fun getSdkModificator(): SdkModificator {
- throw UnsupportedOperationException()
- }
-
- override fun getName(): String = "<dokka SDK>"
-
- override fun getRootProvider(): RootProvider = this
-
- override fun getHomePath(): String? {
- throw UnsupportedOperationException()
- }
-
- override fun getVersionString(): String? {
- throw UnsupportedOperationException()
- }
-
- override fun getSdkAdditionalData(): SdkAdditionalData? {
- throw UnsupportedOperationException()
- }
-
- override fun clone(): Any {
- throw UnsupportedOperationException()
- }
-
- override fun getSdkType(): SdkTypeId {
- throw UnsupportedOperationException()
- }
-
- override fun getHomeDirectory(): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getUserData(p0: Key<T>): T? {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> putUserData(p0: Key<T>, p1: T?) {
- throw UnsupportedOperationException()
- }
- }
-
- private val moduleSourceOrderEntry = object : ModuleSourceOrderEntry {
- override fun getFiles(p0: OrderRootType): Array<VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getUrls(p0: OrderRootType): Array<String> {
- throw UnsupportedOperationException()
- }
-
- override fun <R : Any?> accept(p0: RootPolicy<R>, p1: R?): R {
- throw UnsupportedOperationException()
- }
-
-
- override fun getPresentableName(): String {
- throw UnsupportedOperationException()
- }
-
- override fun getOwnerModule(): Module = module
-
-
- override fun isValid(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun compareTo(other: OrderEntry?): Int {
- throw UnsupportedOperationException()
- }
-
- override fun getRootModel(): ModuleRootModel = moduleRootManager
-
- override fun isSynthetic(): Boolean {
- throw UnsupportedOperationException()
- }
- }
-
- private val sdkOrderEntry = object : JdkOrderEntry {
- override fun getFiles(p0: OrderRootType): Array<VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getUrls(p0: OrderRootType): Array<String> {
- throw UnsupportedOperationException()
- }
-
- override fun <R : Any?> accept(p0: RootPolicy<R>, p1: R?): R {
- throw UnsupportedOperationException()
- }
-
- override fun getJdkName(): String? {
- throw UnsupportedOperationException()
- }
-
- override fun getJdk(): Sdk = sdk
-
- override fun getPresentableName(): String {
- throw UnsupportedOperationException()
- }
-
- override fun getOwnerModule(): Module {
- throw UnsupportedOperationException()
- }
-
- override fun isValid(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getRootFiles(p0: OrderRootType): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getRootUrls(p0: OrderRootType): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun compareTo(other: OrderEntry?): Int {
- throw UnsupportedOperationException()
- }
-
- override fun isSynthetic(): Boolean {
- throw UnsupportedOperationException()
- }
-
- }
-
- inner class MyModuleRootManager : ModuleRootManager() {
- override fun getExternalSource(): ProjectModelExternalSource? {
- throw UnsupportedOperationException()
- }
-
- override fun getExcludeRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getContentEntries(): Array<out ContentEntry> {
- throw UnsupportedOperationException()
- }
-
- override fun getExcludeRootUrls(): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun <R : Any?> processOrder(p0: RootPolicy<R>, p1: R): R {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRoots(p0: Boolean): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRoots(p0: JpsModuleSourceRootType<*>): MutableList<VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRoots(p0: MutableSet<out JpsModuleSourceRootType<*>>): MutableList<VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun orderEntries(): OrderEnumerator =
- ProjectOrderEnumerator(project, null).using(object : RootModelProvider {
- override fun getModules(): Array<out Module> = arrayOf(module)
-
- override fun getRootModel(p0: Module): ModuleRootModel = this@MyModuleRootManager
- })
-
- override fun <T : Any?> getModuleExtension(p0: Class<T>): T {
- throw UnsupportedOperationException()
- }
-
- override fun getDependencyModuleNames(): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getModule(): Module = this@CoreProjectFileIndex.module
-
- override fun isSdkInherited(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getOrderEntries(): Array<out OrderEntry> = arrayOf(moduleSourceOrderEntry, sdkOrderEntry)
-
- override fun getSourceRootUrls(): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRootUrls(p0: Boolean): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getSdk(): Sdk? {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRootUrls(): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleDependencies(): Array<out Module> {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleDependencies(p0: Boolean): Array<out Module> {
- throw UnsupportedOperationException()
- }
-
- override fun getModifiableModel(): ModifiableRootModel {
- throw UnsupportedOperationException()
- }
-
- override fun isDependsOn(p0: Module): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getFileIndex(): ModuleFileIndex {
- return this@CoreProjectFileIndex
- }
-
- override fun getDependencies(): Array<out Module> {
- throw UnsupportedOperationException()
- }
-
- override fun getDependencies(p0: Boolean): Array<out Module> {
- throw UnsupportedOperationException()
- }
- }
-
- val moduleRootManager = MyModuleRootManager()
-
- override fun getContentRootForFile(p0: VirtualFile): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRootForFile(p0: VirtualFile, p1: Boolean): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun getPackageNameByDirectory(p0: VirtualFile): String? {
- throw UnsupportedOperationException()
- }
-
- override fun isInLibrarySource(file: VirtualFile): Boolean = false
-
- override fun getClassRootForFile(file: VirtualFile): VirtualFile? =
- classpathRoots.firstOrNull { it.contains(file) }?.let { StandardFileSystems.local().findFileByPath(it.file.path) }
-
- override fun getOrderEntriesForFile(file: VirtualFile): List<OrderEntry> =
- if (classpathRoots.contains(file)) listOf(sdkOrderEntry) else emptyList()
-
- override fun isInLibraryClasses(file: VirtualFile): Boolean = classpathRoots.contains(file)
-
- override fun isExcluded(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRootForFile(p0: VirtualFile): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun isUnderIgnored(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isLibraryClassFile(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleForFile(file: VirtualFile): Module? =
- if (sourceRoots.contains(file)) module else null
-
- private fun List<ContentRoot>.contains(file: VirtualFile): Boolean = any { it.contains(file) }
-
- override fun getModuleForFile(p0: VirtualFile, p1: Boolean): Module? {
- throw UnsupportedOperationException()
- }
-
- override fun isInSource(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isIgnored(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isContentSourceFile(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isInSourceContent(file: VirtualFile): Boolean = sourceRoots.contains(file)
-
- override fun iterateContent(p0: ContentIterator): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isInContent(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun iterateContentUnderDirectory(p0: VirtualFile, p1: ContentIterator): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isInTestSourceContent(file: VirtualFile): Boolean = false
-
- override fun isUnderSourceRootOfType(p0: VirtualFile, p1: MutableSet<out JpsModuleSourceRootType<*>>): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getOrderEntryForFile(p0: VirtualFile): OrderEntry? {
- throw UnsupportedOperationException()
- }
-}
-
-class CoreProjectRootManager(val projectFileIndex: CoreProjectFileIndex) : ProjectRootManager() {
- override fun orderEntries(): OrderEnumerator {
- throw UnsupportedOperationException()
- }
-
- override fun orderEntries(p0: MutableCollection<out Module>): OrderEnumerator {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRootsFromAllModules(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun setProjectSdk(p0: Sdk?) {
- throw UnsupportedOperationException()
- }
-
- override fun setProjectSdkName(p0: String) {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleSourceRoots(p0: MutableSet<out JpsModuleSourceRootType<*>>): MutableList<VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getContentSourceRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getFileIndex(): ProjectFileIndex = projectFileIndex
-
- override fun getProjectSdkName(): String? {
- throw UnsupportedOperationException()
- }
-
- override fun getProjectSdk(): Sdk? {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRootUrls(): MutableList<String> {
- throw UnsupportedOperationException()
- }
-
-}
-
-fun ContentRoot.contains(file: VirtualFile) = when (this) {
- is JvmContentRoot -> {
- val path = if (file.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL)
- getVirtualFileForJar(file)?.path ?: file.path
- else
- file.path
- File(path).startsWith(this.file.absoluteFile)
- }
- is KotlinSourceRoot -> File(file.path).startsWith(File(this.path).absoluteFile)
- else -> false
-}
diff --git a/core/src/main/kotlin/Analysis/JavaResolveExtension.kt b/core/src/main/kotlin/Analysis/JavaResolveExtension.kt
deleted file mode 100644
index 4a4c78e5..00000000
--- a/core/src/main/kotlin/Analysis/JavaResolveExtension.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2010-2017 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-@file:JvmName("JavaResolutionUtils")
-
-package org.jetbrains.dokka
-
-import com.intellij.psi.*
-import org.jetbrains.kotlin.asJava.unwrapped
-import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
-import org.jetbrains.kotlin.incremental.components.NoLookupLocation
-import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
-import org.jetbrains.kotlin.load.java.structure.*
-import org.jetbrains.kotlin.load.java.structure.impl.*
-import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
-import org.jetbrains.kotlin.psi.KtDeclaration
-import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
-import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.MemberScope
-
-// TODO: Remove that file
-
-@JvmOverloads
-fun PsiMethod.getJavaMethodDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): DeclarationDescriptor? {
- val method = originalElement as? PsiMethod ?: return null
- if (method.containingClass == null || !Name.isValidIdentifier(method.name)) return null
- val resolver = method.getJavaDescriptorResolver(resolutionFacade)
- return when {
- method.isConstructor -> resolver?.resolveConstructor(JavaConstructorImpl(method))
- else -> resolver?.resolveMethod(JavaMethodImpl(method))
- }
-}
-
-@JvmOverloads
-fun PsiClass.getJavaClassDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): ClassDescriptor? {
- val psiClass = originalElement as? PsiClass ?: return null
- return psiClass.getJavaDescriptorResolver(resolutionFacade)?.resolveClass(JavaClassImpl(psiClass))
-}
-
-@JvmOverloads
-fun PsiField.getJavaFieldDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): PropertyDescriptor? {
- val field = originalElement as? PsiField ?: return null
- return field.getJavaDescriptorResolver(resolutionFacade)?.resolveField(JavaFieldImpl(field))
-}
-
-@JvmOverloads
-fun PsiMember.getJavaMemberDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): DeclarationDescriptor? {
- return when (this) {
- is PsiEnumConstant -> containingClass?.getJavaClassDescriptor(resolutionFacade)
- is PsiClass -> getJavaClassDescriptor(resolutionFacade)
- is PsiMethod -> getJavaMethodDescriptor(resolutionFacade)
- is PsiField -> getJavaFieldDescriptor(resolutionFacade)
- else -> null
- }
-}
-
-@JvmOverloads
-fun PsiMember.getJavaOrKotlinMemberDescriptor(resolutionFacade: ResolutionFacade = javaResolutionFacade()): DeclarationDescriptor? {
- val callable = unwrapped
- return when (callable) {
- is PsiMember -> getJavaMemberDescriptor(resolutionFacade)
- is KtDeclaration -> {
- val descriptor = resolutionFacade.resolveToDescriptor(callable)
- if (descriptor is ClassDescriptor && this is PsiMethod) descriptor.unsubstitutedPrimaryConstructor else descriptor
- }
- else -> null
- }
-}
-
-private fun PsiElement.getJavaDescriptorResolver(resolutionFacade: ResolutionFacade): JavaDescriptorResolver? {
- return resolutionFacade.tryGetFrontendService(this, JavaDescriptorResolver::class.java)
-}
-
-private fun JavaDescriptorResolver.resolveMethod(method: JavaMethod): DeclarationDescriptor? {
- return getContainingScope(method)
- ?.getContributedDescriptors(nameFilter = { true }, kindFilter = DescriptorKindFilter.CALLABLES)
- ?.filterIsInstance<DeclarationDescriptorWithSource>()
- ?.findByJavaElement(method)
-}
-
-private fun JavaDescriptorResolver.resolveConstructor(constructor: JavaConstructor): ConstructorDescriptor? {
- return resolveClass(constructor.containingClass)?.constructors?.findByJavaElement(constructor)
-}
-
-private fun JavaDescriptorResolver.resolveField(field: JavaField): PropertyDescriptor? {
- return getContainingScope(field)?.getContributedVariables(field.name, NoLookupLocation.FROM_IDE)?.findByJavaElement(field)
-}
-
-private fun JavaDescriptorResolver.getContainingScope(member: JavaMember): MemberScope? {
- val containingClass = resolveClass(member.containingClass)
- return if (member.isStatic)
- containingClass?.staticScope
- else
- containingClass?.defaultType?.memberScope
-}
-
-private fun <T : DeclarationDescriptorWithSource> Collection<T>.findByJavaElement(javaElement: JavaElement): T? {
- return firstOrNull { member ->
- val memberJavaElement = (member.original.source as? JavaSourceElement)?.javaElement
- when {
- memberJavaElement == javaElement ->
- true
- memberJavaElement is JavaElementImpl<*> && javaElement is JavaElementImpl<*> ->
- memberJavaElement.psi.isEquivalentTo(javaElement.psi)
- else ->
- false
- }
- }
-}
-
-fun PsiElement.javaResolutionFacade() =
- KotlinCacheService.getInstance(project).getResolutionFacadeByFile(this.originalElement.containingFile, JvmPlatforms.defaultJvmPlatform)!!
diff --git a/core/src/main/kotlin/CoreExtensions.kt b/core/src/main/kotlin/CoreExtensions.kt
new file mode 100644
index 00000000..b8689154
--- /dev/null
+++ b/core/src/main/kotlin/CoreExtensions.kt
@@ -0,0 +1,29 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.dokka.plugability.ExtensionPoint
+import org.jetbrains.dokka.renderers.Renderer
+import org.jetbrains.dokka.transformers.documentation.DocumentableMerger
+import org.jetbrains.dokka.transformers.documentation.DocumentableToPageTranslator
+import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer
+import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer
+import org.jetbrains.dokka.transformers.pages.PageCreator
+import org.jetbrains.dokka.transformers.pages.PageTransformer
+import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator
+import kotlin.reflect.KProperty
+
+object CoreExtensions {
+ val sourceToDocumentableTranslator by coreExtension<SourceToDocumentableTranslator>()
+ val preMergeDocumentableTransformer by coreExtension<PreMergeDocumentableTransformer>()
+ val documentableMerger by coreExtension<DocumentableMerger>()
+ val documentableTransformer by coreExtension<DocumentableTransformer>()
+ val documentableToPageTranslator by coreExtension<DocumentableToPageTranslator>()
+ val allModulePageCreator by coreExtension<PageCreator>()
+ val pageTransformer by coreExtension<PageTransformer>()
+ val allModulePageTransformer by coreExtension<PageTransformer>()
+ val renderer by coreExtension<Renderer>()
+
+ private fun <T : Any> coreExtension() = object {
+ operator fun provideDelegate(thisRef: CoreExtensions, property: KProperty<*>): Lazy<ExtensionPoint<T>> =
+ lazy { ExtensionPoint<T>(thisRef::class.qualifiedName!!, property.name) }
+ }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/DokkaBootstrap.kt b/core/src/main/kotlin/DokkaBootstrap.kt
new file mode 100644
index 00000000..159172a5
--- /dev/null
+++ b/core/src/main/kotlin/DokkaBootstrap.kt
@@ -0,0 +1,11 @@
+package org.jetbrains.dokka
+
+import java.util.function.BiConsumer
+import kotlin.jvm.Throws
+
+interface DokkaBootstrap {
+ fun configure(serializedConfigurationJSON: String, logger: BiConsumer<String, String>)
+
+ @Throws(Throwable::class)
+ fun generate()
+}
diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt
index b48b62d4..fabbc889 100644
--- a/core/src/main/kotlin/DokkaBootstrapImpl.kt
+++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt
@@ -1,49 +1,78 @@
package org.jetbrains.dokka
-import com.google.gson.Gson
import org.jetbrains.dokka.DokkaConfiguration.PackageOptions
+import org.jetbrains.dokka.utilities.DokkaLogger
import java.util.function.BiConsumer
-fun parsePerPackageOptions(arg: String): List<PackageOptions> {
- if (arg.isBlank()) return emptyList()
+fun parsePerPackageOptions(args: List<String>): List<PackageOptions> = args.map { it.split(",") }.map {
+ val prefix = it.first()
+ if (prefix == "")
+ throw IllegalArgumentException(
+ "Please do not register packageOptions with all match pattern, use global settings instead"
+ )
- return arg.split(";").map { it.split(",") }.map {
- val prefix = it.first()
- if (prefix == "")
- throw IllegalArgumentException("Please do not register packageOptions with all match pattern, use global settings instead")
- val args = it.subList(1, it.size)
- val deprecated = args.find { it.endsWith("deprecated") }?.startsWith("+") ?: true
- val reportUndocumented = args.find { it.endsWith("warnUndocumented") }?.startsWith("+") ?: true
- val privateApi = args.find { it.endsWith("privateApi") }?.startsWith("+") ?: false
- val suppress = args.find { it.endsWith("suppress") }?.startsWith("+") ?: false
- PackageOptionsImpl(prefix, includeNonPublic = privateApi, reportUndocumented = reportUndocumented, skipDeprecated = !deprecated, suppress = suppress)
- }
+ val args = it.subList(1, it.size)
+
+ val deprecated = args.find { it.endsWith("skipDeprecated") }?.startsWith("+")
+ ?: DokkaDefaults.skipDeprecated
+
+ val reportUndocumented = args.find { it.endsWith("reportUndocumented") }?.startsWith("+")
+ ?: DokkaDefaults.reportUndocumented
+
+ val privateApi = args.find { it.endsWith("includeNonPublic") }?.startsWith("+")
+ ?: DokkaDefaults.includeNonPublic
+
+ val suppress = args.find { it.endsWith("suppress") }?.startsWith("+")
+ ?: DokkaDefaults.suppress
+
+ PackageOptionsImpl(
+ prefix,
+ includeNonPublic = privateApi,
+ reportUndocumented = reportUndocumented,
+ skipDeprecated = !deprecated,
+ suppress = suppress
+ )
}
+
+/**
+ * Accessed with reflection
+ */
+@Suppress("unused")
class DokkaBootstrapImpl : DokkaBootstrap {
- private class DokkaProxyLogger(val consumer: BiConsumer<String, String>) : DokkaLogger {
+ class DokkaProxyLogger(val consumer: BiConsumer<String, String>) : DokkaLogger {
+ override var warningsCount: Int = 0
+ override var errorsCount: Int = 0
+
+ override fun debug(message: String) {
+ consumer.accept("debug", message)
+ }
+
override fun info(message: String) {
consumer.accept("info", message)
}
+ override fun progress(message: String) {
+ consumer.accept("progress", message)
+ }
+
override fun warn(message: String) {
- consumer.accept("warn", message)
+ consumer.accept("warn", message).also { warningsCount++ }
}
override fun error(message: String) {
- consumer.accept("error", message)
+ consumer.accept("error", message).also { errorsCount++ }
}
}
- lateinit var generator: DokkaGenerator
- val gson = Gson()
+ private lateinit var generator: DokkaGenerator
fun configure(logger: DokkaLogger, configuration: DokkaConfigurationImpl) = with(configuration) {
- fun defaultLinks(config: PassConfigurationImpl): List<ExternalDocumentationLinkImpl> {
+ fun defaultLinks(config: DokkaSourceSetImpl): List<ExternalDocumentationLinkImpl> {
val links = mutableListOf<ExternalDocumentationLinkImpl>()
if (!config.noJdkLink)
links += DokkaConfiguration.ExternalDocumentationLink
@@ -57,20 +86,21 @@ class DokkaBootstrapImpl : DokkaBootstrap {
return links
}
- val configurationWithLinks =
- configuration.copy(passesConfigurations =
- passesConfigurations
- .map {
- val links: List<ExternalDocumentationLinkImpl> = it.externalDocumentationLinks + defaultLinks(it)
- it.copy(externalDocumentationLinks = links)
- }
- )
+ val configurationWithLinks = configuration.copy(
+ sourceSets = sourceSets.map {
+ val links: List<ExternalDocumentationLinkImpl> =
+ it.externalDocumentationLinks + defaultLinks(it)
+ it.copy(externalDocumentationLinks = links)
+ }
+ )
generator = DokkaGenerator(configurationWithLinks, logger)
}
- override fun configure(logger: BiConsumer<String, String>, serializedConfigurationJSON: String)
- = configure(DokkaProxyLogger(logger), gson.fromJson(serializedConfigurationJSON, DokkaConfigurationImpl::class.java))
+ override fun configure(serializedConfigurationJSON: String, logger: BiConsumer<String, String>) = configure(
+ DokkaProxyLogger(logger),
+ DokkaConfigurationImpl(serializedConfigurationJSON)
+ )
override fun generate() = generator.generate()
}
diff --git a/core/src/main/kotlin/DokkaException.kt b/core/src/main/kotlin/DokkaException.kt
new file mode 100644
index 00000000..0010249c
--- /dev/null
+++ b/core/src/main/kotlin/DokkaException.kt
@@ -0,0 +1,3 @@
+package org.jetbrains.dokka
+
+class DokkaException(message: String) : RuntimeException(message)
diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt
new file mode 100644
index 00000000..4262d890
--- /dev/null
+++ b/core/src/main/kotlin/DokkaGenerator.kt
@@ -0,0 +1,164 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.DokkaConfiguration.*
+import org.jetbrains.dokka.pages.RootPageNode
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.jetbrains.dokka.utilities.DokkaLogger
+import org.jetbrains.dokka.utilities.report
+
+
+/**
+ * DokkaGenerator is the main entry point for generating documentation
+ *
+ * [generate] method has been split into submethods for test reasons
+ */
+class DokkaGenerator(
+ private val configuration: DokkaConfiguration,
+ private val logger: DokkaLogger
+) {
+ fun generate() = timed(logger) {
+ report("Initializing plugins")
+ val context = initializePlugins(configuration, logger)
+
+ report("Creating documentation models")
+ val modulesFromPlatforms = createDocumentationModels(context)
+
+ report("Transforming documentation model before merging")
+ val transformedDocumentationBeforeMerge = transformDocumentationModelBeforeMerge(modulesFromPlatforms, context)
+
+ report("Merging documentation models")
+ val documentationModel = mergeDocumentationModels(transformedDocumentationBeforeMerge, context)
+
+ report("Transforming documentation model after merging")
+ val transformedDocumentation = transformDocumentationModelAfterMerge(documentationModel, context)
+
+ report("Creating pages")
+ val pages = createPages(transformedDocumentation, context)
+
+ report("Transforming pages")
+ val transformedPages = transformPages(pages, context)
+
+ report("Rendering")
+ render(transformedPages, context)
+
+ reportAfterRendering(context)
+ }.dump("\n\n === TIME MEASUREMENT ===\n")
+
+ fun generateAllModulesPage() = timed {
+ report("Initializing plugins")
+ val context = initializePlugins(configuration, logger)
+
+ report("Creating all modules page")
+ val pages = createAllModulePage(context)
+
+ report("Transforming pages")
+ val transformedPages = transformAllModulesPage(pages, context)
+
+ report("Rendering")
+ render(transformedPages, context)
+ }.dump("\n\n === TIME MEASUREMENT ===\n")
+
+
+ fun initializePlugins(
+ configuration: DokkaConfiguration,
+ logger: DokkaLogger,
+ additionalPlugins: List<DokkaPlugin> = emptyList()
+ ) = DokkaContext.create(configuration, logger, additionalPlugins)
+
+ fun createDocumentationModels(
+ context: DokkaContext
+ ) = context.configuration.sourceSets
+ .flatMap { sourceSet -> translateSources(sourceSet, context) }
+
+ fun transformDocumentationModelBeforeMerge(
+ modulesFromPlatforms: List<DModule>,
+ context: DokkaContext
+ ) = context[CoreExtensions.preMergeDocumentableTransformer].fold(modulesFromPlatforms) { acc, t -> t(acc) }
+
+ fun mergeDocumentationModels(
+ modulesFromPlatforms: List<DModule>,
+ context: DokkaContext
+ ) = context.single(CoreExtensions.documentableMerger).invoke(modulesFromPlatforms, context)
+
+ fun transformDocumentationModelAfterMerge(
+ documentationModel: DModule,
+ context: DokkaContext
+ ) = context[CoreExtensions.documentableTransformer].fold(documentationModel) { acc, t -> t(acc, context) }
+
+ fun createPages(
+ transformedDocumentation: DModule,
+ context: DokkaContext
+ ) = context.single(CoreExtensions.documentableToPageTranslator).invoke(transformedDocumentation)
+
+ fun createAllModulePage(
+ context: DokkaContext
+ ) = context.single(CoreExtensions.allModulePageCreator).invoke()
+
+ fun transformPages(
+ pages: RootPageNode,
+ context: DokkaContext
+ ) = context[CoreExtensions.pageTransformer].fold(pages) { acc, t -> t(acc) }
+
+ fun transformAllModulesPage(
+ pages: RootPageNode,
+ context: DokkaContext
+ ) = context[CoreExtensions.allModulePageTransformer].fold(pages) { acc, t -> t(acc) }
+
+ fun render(
+ transformedPages: RootPageNode,
+ context: DokkaContext
+ ) {
+ val renderer = context.single(CoreExtensions.renderer)
+ renderer.render(transformedPages)
+ }
+
+ fun reportAfterRendering(context: DokkaContext) {
+ context.unusedPoints.takeIf { it.isNotEmpty() }?.also {
+ logger.info("Unused extension points found: ${it.joinToString(", ")}")
+ }
+
+ logger.report()
+
+ if (context.configuration.failOnWarning && (logger.warningsCount > 0 || logger.errorsCount > 0)) {
+ throw DokkaException(
+ "Failed with warningCount=${logger.warningsCount} and errorCount=${logger.errorsCount}"
+ )
+ }
+ }
+
+ private fun translateSources(sourceSet: DokkaSourceSet, context: DokkaContext) =
+ context[CoreExtensions.sourceToDocumentableTranslator].map {
+ it.invoke(sourceSet, context)
+ }
+}
+
+private class Timer(startTime: Long, private val logger: DokkaLogger?) {
+ private val steps = mutableListOf("" to startTime)
+
+ fun report(name: String) {
+ logger?.progress(name)
+ steps += (name to System.currentTimeMillis())
+ }
+
+ fun dump(prefix: String = "") {
+ logger?.info(prefix)
+ val namePad = steps.map { it.first.length }.max() ?: 0
+ val timePad = steps.windowed(2).map { (p1, p2) -> p2.second - p1.second }.max()?.toString()?.length ?: 0
+ steps.windowed(2).forEach { (p1, p2) ->
+ if (p1.first.isNotBlank()) {
+ logger?.info("${p1.first.padStart(namePad)}: ${(p2.second - p1.second).toString().padStart(timePad)}")
+ }
+ }
+ }
+}
+
+private fun timed(logger: DokkaLogger? = null, block: Timer.() -> Unit): Timer =
+ Timer(System.currentTimeMillis(), logger).apply {
+ try {
+ block()
+ } finally {
+ report("")
+ }
+ }
diff --git a/core/src/main/kotlin/DokkaMultimoduleBootstrapImpl.kt b/core/src/main/kotlin/DokkaMultimoduleBootstrapImpl.kt
new file mode 100644
index 00000000..c0726584
--- /dev/null
+++ b/core/src/main/kotlin/DokkaMultimoduleBootstrapImpl.kt
@@ -0,0 +1,29 @@
+/**
+ * Accessed with reflection
+ */
+@file:Suppress("unused")
+
+package org.jetbrains.dokka
+
+import org.jetbrains.dokka.DokkaBootstrapImpl.DokkaProxyLogger
+import org.jetbrains.dokka.utilities.DokkaLogger
+import java.util.function.BiConsumer
+
+class DokkaMultimoduleBootstrapImpl : DokkaBootstrap {
+
+ private lateinit var generator: DokkaGenerator
+
+ fun configure(logger: DokkaLogger, configuration: DokkaConfiguration) {
+ generator = DokkaGenerator(configuration, logger)
+ }
+
+ override fun configure(serializedConfigurationJSON: String, logger: BiConsumer<String, String>) = configure(
+ DokkaProxyLogger(logger),
+ DokkaConfigurationImpl(serializedConfigurationJSON)
+ )
+
+ override fun generate() {
+ generator.generateAllModulesPage()
+ }
+
+}
diff --git a/core/src/main/kotlin/DokkaVersion.kt b/core/src/main/kotlin/DokkaVersion.kt
new file mode 100644
index 00000000..410058f3
--- /dev/null
+++ b/core/src/main/kotlin/DokkaVersion.kt
@@ -0,0 +1,10 @@
+package org.jetbrains.dokka
+
+import java.util.*
+
+object DokkaVersion {
+ val version: String by lazy {
+ val stream = javaClass.getResourceAsStream("/META-INF/dokka/dokka-version.properties")
+ Properties().apply { load(stream) }.getProperty("dokka-version")
+ }
+}
diff --git a/core/src/main/kotlin/Formats/AnalysisComponents.kt b/core/src/main/kotlin/Formats/AnalysisComponents.kt
deleted file mode 100644
index d78d4a0c..00000000
--- a/core/src/main/kotlin/Formats/AnalysisComponents.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import com.google.inject.Binder
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.KotlinAsJavaElementSignatureProvider
-import org.jetbrains.dokka.KotlinElementSignatureProvider
-import org.jetbrains.dokka.ElementSignatureProvider
-import org.jetbrains.dokka.Samples.DefaultSampleProcessingService
-import org.jetbrains.dokka.Samples.SampleProcessingService
-import org.jetbrains.dokka.Utilities.bind
-import org.jetbrains.dokka.Utilities.toType
-import kotlin.reflect.KClass
-
-
-interface DefaultAnalysisComponentServices {
- val packageDocumentationBuilderClass: KClass<out PackageDocumentationBuilder>
- val javaDocumentationBuilderClass: KClass<out JavaDocumentationBuilder>
- val sampleProcessingService: KClass<out SampleProcessingService>
- val elementSignatureProvider: KClass<out ElementSignatureProvider>
-}
-
-interface DefaultAnalysisComponent : FormatDescriptorAnalysisComponent, DefaultAnalysisComponentServices {
- override fun configureAnalysis(binder: Binder): Unit = with(binder) {
- bind<ElementSignatureProvider>() toType elementSignatureProvider
- bind<PackageDocumentationBuilder>() toType packageDocumentationBuilderClass
- bind<JavaDocumentationBuilder>() toType javaDocumentationBuilderClass
- bind<SampleProcessingService>() toType sampleProcessingService
- }
-}
-
-
-object KotlinAsJava : DefaultAnalysisComponentServices {
- override val packageDocumentationBuilderClass = KotlinAsJavaDocumentationBuilder::class
- override val javaDocumentationBuilderClass = JavaPsiDocumentationBuilder::class
- override val sampleProcessingService = DefaultSampleProcessingService::class
- override val elementSignatureProvider = KotlinAsJavaElementSignatureProvider::class
-}
-
-
-object KotlinAsKotlin : DefaultAnalysisComponentServices {
- override val packageDocumentationBuilderClass = KotlinPackageDocumentationBuilder::class
- override val javaDocumentationBuilderClass = KotlinJavaDocumentationBuilder::class
- override val sampleProcessingService = DefaultSampleProcessingService::class
- override val elementSignatureProvider = KotlinElementSignatureProvider::class
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/FormatDescriptor.kt b/core/src/main/kotlin/Formats/FormatDescriptor.kt
deleted file mode 100644
index 4bac8aa0..00000000
--- a/core/src/main/kotlin/Formats/FormatDescriptor.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import com.google.inject.Binder
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Utilities.bind
-import org.jetbrains.dokka.Utilities.lazyBind
-import org.jetbrains.dokka.Utilities.toOptional
-import org.jetbrains.dokka.Utilities.toType
-import kotlin.reflect.KClass
-
-
-interface FormatDescriptorAnalysisComponent {
- fun configureAnalysis(binder: Binder)
-}
-
-interface FormatDescriptorOutputComponent {
- fun configureOutput(binder: Binder)
-}
-
-interface FormatDescriptor : FormatDescriptorAnalysisComponent, FormatDescriptorOutputComponent
-
-
-abstract class FileGeneratorBasedFormatDescriptor : FormatDescriptor {
-
- override fun configureOutput(binder: Binder): Unit = with(binder) {
- bind<Generator>() toType NodeLocationAwareGenerator::class
- bind<NodeLocationAwareGenerator>() toType generatorServiceClass
- bind(generatorServiceClass.java) // https://github.com/google/guice/issues/847
-
- bind<LanguageService>() toType languageServiceClass
-
- lazyBind<OutlineFormatService>() toOptional (outlineServiceClass)
- lazyBind<FormatService>() toOptional formatServiceClass
- lazyBind<PackageListService>() toOptional packageListServiceClass
- }
-
- abstract val formatServiceClass: KClass<out FormatService>?
- abstract val outlineServiceClass: KClass<out OutlineFormatService>?
- abstract val generatorServiceClass: KClass<out FileGenerator>
- abstract val packageListServiceClass: KClass<out PackageListService>?
-
- open val languageServiceClass: KClass<out LanguageService> = KotlinLanguageService::class
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/FormatService.kt b/core/src/main/kotlin/Formats/FormatService.kt
deleted file mode 100644
index 8f4855e3..00000000
--- a/core/src/main/kotlin/Formats/FormatService.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.jetbrains.dokka
-
-/**
- * Abstract representation of a formatting service used to output documentation in desired format
- *
- * Bundled Formatters:
- * * [HtmlFormatService] – outputs documentation to HTML format
- * * [MarkdownFormatService] – outputs documentation in Markdown format
- */
-interface FormatService {
- /** Returns extension for output files */
- val extension: String
-
- /** extension which will be used for internal and external linking */
- val linkExtension: String
- get() = extension
-
- fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder
-
- fun enumerateSupportFiles(callback: (resource: String, targetPath: String) -> Unit) {
- }
-}
-
-interface FormattedOutputBuilder {
- /** Appends formatted content */
- fun appendNodes(nodes: Iterable<DocumentationNode>)
-}
-
-/** Format content to [String] using specified [location] */
-fun FormatService.format(location: Location, nodes: Iterable<DocumentationNode>): String = StringBuilder().apply {
- createOutputBuilder(this, location).appendNodes(nodes)
-}.toString()
diff --git a/core/src/main/kotlin/Formats/GFMFormatService.kt b/core/src/main/kotlin/Formats/GFMFormatService.kt
deleted file mode 100644
index 036ec856..00000000
--- a/core/src/main/kotlin/Formats/GFMFormatService.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import org.jetbrains.dokka.Utilities.impliedPlatformsName
-
-open class GFMOutputBuilder(
- to: StringBuilder,
- location: Location,
- generator: NodeLocationAwareGenerator,
- languageService: LanguageService,
- extension: String,
- impliedPlatforms: List<String>
-) : MarkdownOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms) {
- override fun appendTable(vararg columns: String, body: () -> Unit) {
- to.appendln(columns.joinToString(" | ", "| ", " |"))
- to.appendln("|" + "---|".repeat(columns.size))
- body()
- }
-
- override fun appendUnorderedList(body: () -> Unit) {
- if (inTableCell) {
- wrapInTag("ul", body)
- } else {
- super.appendUnorderedList(body)
- }
- }
-
- override fun appendOrderedList(body: () -> Unit) {
- if (inTableCell) {
- wrapInTag("ol", body)
- } else {
- super.appendOrderedList(body)
- }
- }
-
- override fun appendListItem(body: () -> Unit) {
- if (inTableCell) {
- wrapInTag("li", body)
- } else {
- super.appendListItem(body)
- }
- }
-}
-
-open class GFMFormatService(
- generator: NodeLocationAwareGenerator,
- signatureGenerator: LanguageService,
- linkExtension: String,
- impliedPlatforms: List<String>
-) : MarkdownFormatService(generator, signatureGenerator, linkExtension, impliedPlatforms) {
-
- @Inject constructor(
- generator: NodeLocationAwareGenerator,
- signatureGenerator: LanguageService,
- @Named(impliedPlatformsName) impliedPlatforms: List<String>
- ) : this(generator, signatureGenerator, "md", impliedPlatforms)
-
- override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- GFMOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms)
-}
diff --git a/core/src/main/kotlin/Formats/HtmlFormatService.kt b/core/src/main/kotlin/Formats/HtmlFormatService.kt
deleted file mode 100644
index d36ea0a2..00000000
--- a/core/src/main/kotlin/Formats/HtmlFormatService.kt
+++ /dev/null
@@ -1,166 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import org.jetbrains.dokka.Utilities.impliedPlatformsName
-import java.io.File
-
-open class HtmlOutputBuilder(to: StringBuilder,
- location: Location,
- generator: NodeLocationAwareGenerator,
- languageService: LanguageService,
- extension: String,
- impliedPlatforms: List<String>,
- val templateService: HtmlTemplateService)
- : StructuredOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms)
-{
- override fun appendText(text: String) {
- to.append(text.htmlEscape())
- }
-
- override fun appendSymbol(text: String) {
- to.append("<span class=\"symbol\">${text.htmlEscape()}</span>")
- }
-
- override fun appendKeyword(text: String) {
- to.append("<span class=\"keyword\">${text.htmlEscape()}</span>")
- }
-
- override fun appendIdentifier(text: String, kind: IdentifierKind, signature: String?) {
- val id = signature?.let { " id=\"$it\"" }.orEmpty()
- to.append("<span class=\"identifier\"$id>${text.htmlEscape()}</span>")
- }
-
- override fun appendBlockCode(language: String, body: () -> Unit) {
- val openTags = if (language.isNotBlank())
- "<pre><code class=\"lang-$language\">"
- else
- "<pre><code>"
- wrap(openTags, "</code></pre>", body)
- }
-
- override fun appendHeader(level: Int, body: () -> Unit) =
- wrapInTag("h$level", body, newlineBeforeOpen = true, newlineAfterClose = true)
- override fun appendParagraph(body: () -> Unit) =
- wrapInTag("p", body, newlineBeforeOpen = true, newlineAfterClose = true)
-
- override fun appendSoftParagraph(body: () -> Unit) = appendParagraph(body)
-
- override fun appendLine() {
- to.appendln("<br/>")
- }
-
- override fun appendAnchor(anchor: String) {
- to.appendln("<a name=\"${anchor.htmlEscape()}\"></a>")
- }
-
- override fun appendTable(vararg columns: String, body: () -> Unit) =
- wrapInTag("table", body, newlineAfterOpen = true, newlineAfterClose = true)
- override fun appendTableBody(body: () -> Unit) =
- wrapInTag("tbody", body, newlineAfterOpen = true, newlineAfterClose = true)
- override fun appendTableRow(body: () -> Unit) =
- wrapInTag("tr", body, newlineAfterOpen = true, newlineAfterClose = true)
- override fun appendTableCell(body: () -> Unit) =
- wrapInTag("td", body, newlineAfterOpen = true, newlineAfterClose = true)
-
- override fun appendLink(href: String, body: () -> Unit) = wrap("<a href=\"$href\">", "</a>", body)
-
- override fun appendStrong(body: () -> Unit) = wrapInTag("strong", body)
- override fun appendEmphasis(body: () -> Unit) = wrapInTag("em", body)
- override fun appendStrikethrough(body: () -> Unit) = wrapInTag("s", body)
- override fun appendCode(body: () -> Unit) = wrapInTag("code", body)
-
- override fun appendUnorderedList(body: () -> Unit) = wrapInTag("ul", body, newlineAfterClose = true)
- override fun appendOrderedList(body: () -> Unit) = wrapInTag("ol", body, newlineAfterClose = true)
- override fun appendListItem(body: () -> Unit) = wrapInTag("li", body, newlineAfterClose = true)
-
- override fun appendBreadcrumbSeparator() {
- to.append("&nbsp;/&nbsp;")
- }
-
- override fun appendNodes(nodes: Iterable<DocumentationNode>) {
- templateService.appendHeader(to, getPageTitle(nodes), generator.relativePathToRoot(location))
- super.appendNodes(nodes)
- templateService.appendFooter(to)
- }
-
- override fun appendNonBreakingSpace() {
- to.append("&nbsp;")
- }
-
- override fun ensureParagraph() {}
-}
-
-open class HtmlFormatService @Inject constructor(generator: NodeLocationAwareGenerator,
- signatureGenerator: LanguageService,
- val templateService: HtmlTemplateService,
- @Named(impliedPlatformsName) val impliedPlatforms: List<String>)
-: StructuredFormatService(generator, signatureGenerator, "html"), OutlineFormatService {
-
- override fun enumerateSupportFiles(callback: (String, String) -> Unit) {
- callback("/dokka/styles/style.css", "style.css")
- }
-
- override fun createOutputBuilder(to: StringBuilder, location: Location) =
- HtmlOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms, templateService)
-
- override fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- templateService.appendHeader(to, "Module Contents", generator.relativePathToRoot(location))
- super.appendOutline(location, to, nodes)
- templateService.appendFooter(to)
- }
-
- override fun getOutlineFileName(location: Location): File {
- return File("${location.path}-outline.html")
- }
-
- override fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) {
- val link = ContentNodeDirectLink(node)
- link.append(languageService.render(node, LanguageService.RenderMode.FULL))
- val tempBuilder = StringBuilder()
- createOutputBuilder(tempBuilder, location).appendContent(link)
- to.appendln("<a href=\"${location.path}\">$tempBuilder</a><br/>")
- }
-
- override fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) {
- to.appendln("<ul>")
- body()
- to.appendln("</ul>")
- }
-}
-
-fun getPageTitle(nodes: Iterable<DocumentationNode>): String? {
- val breakdownByLocation = nodes.groupBy { node -> formatPageTitle(node) }
- return breakdownByLocation.keys.singleOrNull()
-}
-
-fun formatPageTitle(node: DocumentationNode): String {
- val path = node.path
- val moduleName = path.first().name
- if (path.size == 1) {
- return moduleName
- }
-
- val qName = qualifiedNameForPageTitle(node)
- return "$qName - $moduleName"
-}
-
-private fun qualifiedNameForPageTitle(node: DocumentationNode): String {
- if (node.kind == NodeKind.Package) {
- var packageName = node.qualifiedName()
- if (packageName.isEmpty()) {
- packageName = "root package"
- }
- return packageName
- }
-
- val path = node.path
- var pathFromToplevelMember = path.dropWhile { it.kind !in NodeKind.classLike }
- if (pathFromToplevelMember.isEmpty()) {
- pathFromToplevelMember = path.dropWhile { it.kind != NodeKind.Property && it.kind != NodeKind.Function }
- }
- if (pathFromToplevelMember.isNotEmpty()) {
- return pathFromToplevelMember.map { it.name }.filter { it.length > 0 }.joinToString(".")
- }
- return node.qualifiedName()
-}
diff --git a/core/src/main/kotlin/Formats/HtmlTemplateService.kt b/core/src/main/kotlin/Formats/HtmlTemplateService.kt
deleted file mode 100644
index a65a7b18..00000000
--- a/core/src/main/kotlin/Formats/HtmlTemplateService.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.jetbrains.dokka
-
-import java.io.File
-
-interface HtmlTemplateService {
- fun appendHeader(to: StringBuilder, title: String?, basePath: File)
- fun appendFooter(to: StringBuilder)
-
- companion object {
- fun default(css: String? = null): HtmlTemplateService {
- return object : HtmlTemplateService {
- override fun appendFooter(to: StringBuilder) {
- if (!to.endsWith('\n')) {
- to.append('\n')
- }
- to.appendln("</BODY>")
- to.appendln("</HTML>")
- }
- override fun appendHeader(to: StringBuilder, title: String?, basePath: File) {
- to.appendln("<HTML>")
- to.appendln("<HEAD>")
- to.appendln("<meta charset=\"UTF-8\">")
- if (title != null) {
- to.appendln("<title>$title</title>")
- }
- if (css != null) {
- val cssPath = basePath.resolve(css).toUnixString()
- to.appendln("<link rel=\"stylesheet\" href=\"$cssPath\">")
- }
- to.appendln("</HEAD>")
- to.appendln("<BODY>")
- }
- }
- }
- }
-}
-
-
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlPackageListService.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlPackageListService.kt
deleted file mode 100644
index 09bb2602..00000000
--- a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlPackageListService.kt
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.ExternalDocumentationLinkResolver.Companion.DOKKA_PARAM_PREFIX
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
-import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
-import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
-import org.jetbrains.kotlin.types.KotlinType
-
-class JavaLayoutHtmlPackageListService: PackageListService {
-
- private fun StringBuilder.appendParam(name: String, value: String) {
- append(DOKKA_PARAM_PREFIX)
- append(name)
- append(":")
- appendln(value)
- }
-
- override fun formatPackageList(module: DocumentationModule): String {
- val packages = module.members(NodeKind.Package).map { it.name }
-
- return buildString {
- appendParam("format", "java-layout-html")
- appendParam("mode", "kotlin")
- for (p in packages) {
- appendln(p)
- }
- }
- }
-
-}
-
-class JavaLayoutHtmlInboundLinkResolutionService(private val paramMap: Map<String, List<String>>) : InboundExternalLinkResolutionService {
- private fun getContainerPath(symbol: DeclarationDescriptor): String? {
- return when (symbol) {
- is PackageFragmentDescriptor -> symbol.fqName.asString().replace('.', '/') + "/"
- is ClassifierDescriptor -> getContainerPath(symbol.findPackage()) + symbol.nameWithOuter() + ".html"
- else -> null
- }
- }
-
- private fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor =
- generateSequence(this) { it.containingDeclaration }.filterIsInstance<PackageFragmentDescriptor>().first()
-
- private fun ClassifierDescriptor.nameWithOuter(): String =
- generateSequence(this) { it.containingDeclaration as? ClassifierDescriptor }
- .toList().asReversed().joinToString(".") { it.name.asString() }
-
- private fun getPagePath(symbol: DeclarationDescriptor): String? {
- return when (symbol) {
- is PackageFragmentDescriptor -> getContainerPath(symbol) + "package-summary.html"
- is EnumEntrySyntheticClassDescriptor -> getContainerPath(symbol.containingDeclaration) + "#" + symbol.signatureForAnchorUrlEncoded()
- is ClassifierDescriptor -> getContainerPath(symbol) + "#"
- is FunctionDescriptor, is PropertyDescriptor -> getContainerPath(symbol.containingDeclaration!!) + "#" + symbol.signatureForAnchorUrlEncoded()
- else -> null
- }
- }
-
- private fun DeclarationDescriptor.signatureForAnchor(): String? {
-
- fun ReceiverParameterDescriptor.extractReceiverName(): String {
- var receiverClass: DeclarationDescriptor = type.constructor.declarationDescriptor!!
- if (receiverClass.isCompanionObject()) {
- receiverClass = receiverClass.containingDeclaration!!
- } else if (receiverClass is TypeParameterDescriptor) {
- val upperBoundClass = receiverClass.upperBounds.singleOrNull()?.constructor?.declarationDescriptor
- if (upperBoundClass != null) {
- receiverClass = upperBoundClass
- }
- }
-
- return receiverClass.name.asString()
- }
-
- fun KotlinType.qualifiedNameForSignature(): String {
- val desc = constructor.declarationDescriptor
- return desc?.fqNameUnsafe?.asString() ?: "<ERROR TYPE NAME>"
- }
-
- fun StringBuilder.appendReceiverAndCompanion(desc: CallableDescriptor) {
- if (desc.containingDeclaration.isCompanionObject()) {
- append("Companion.")
- }
- desc.extensionReceiverParameter?.let {
- append("(")
- append(it.extractReceiverName())
- append(").")
- }
- }
-
- return when(this) {
- is EnumEntrySyntheticClassDescriptor -> buildString {
- append("ENUM_VALUE:")
- append(name.asString())
- }
- is FunctionDescriptor -> buildString {
- appendReceiverAndCompanion(this@signatureForAnchor)
- append(name.asString())
- valueParameters.joinTo(this, prefix = "(", postfix = ")") {
- it.type.qualifiedNameForSignature()
- }
- }
- is PropertyDescriptor -> buildString {
- appendReceiverAndCompanion(this@signatureForAnchor)
- append(name.asString())
- append(":")
- append(returnType?.qualifiedNameForSignature())
- }
- else -> null
- }
- }
-
- private fun DeclarationDescriptor.signatureForAnchorUrlEncoded(): String? = signatureForAnchor()?.urlEncoded()
-
- override fun getPath(symbol: DeclarationDescriptor) = getPagePath(symbol)
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtmlFormat.kt b/core/src/main/kotlin/Formats/JavaLayoutHtmlFormat.kt
deleted file mode 100644
index 885cdf6c..00000000
--- a/core/src/main/kotlin/Formats/JavaLayoutHtmlFormat.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import com.google.inject.Binder
-import com.google.inject.Inject
-import kotlinx.html.li
-import kotlinx.html.stream.appendHTML
-import kotlinx.html.ul
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Samples.DefaultSampleProcessingService
-import org.jetbrains.dokka.Utilities.bind
-import org.jetbrains.dokka.Utilities.toType
-import java.io.File
-
-
-class JavaLayoutHtmlFormatDescriptor : FormatDescriptor, DefaultAnalysisComponent {
- override val packageDocumentationBuilderClass = KotlinPackageDocumentationBuilder::class
- override val javaDocumentationBuilderClass = KotlinJavaDocumentationBuilder::class
- override val sampleProcessingService = DefaultSampleProcessingService::class
- override val elementSignatureProvider = KotlinElementSignatureProvider::class
-
- override fun configureOutput(binder: Binder): Unit = with(binder) {
- bind<Generator>() toType generatorServiceClass
- }
-
- val formatServiceClass = JavaLayoutHtmlFormatService::class
- val generatorServiceClass = JavaLayoutHtmlFormatGenerator::class
-}
-
-
-class JavaLayoutHtmlFormatService : FormatService {
- override val extension: String
- get() = TODO("not implemented")
-
-
- override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder {
- TODO("not implemented")
- }
-}
-
-class JavaLayoutHtmlFormatOutputBuilder : FormattedOutputBuilder {
- override fun appendNodes(nodes: Iterable<DocumentationNode>) {
-
- }
-}
-
-
-class JavaLayoutHtmlFormatNavListBuilder @Inject constructor() : OutlineFormatService {
- override fun getOutlineFileName(location: Location): File {
- TODO()
- }
-
- override fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) {
- with(to.appendHTML()) {
- //a(href = )
- li {
- when {
- node.kind == NodeKind.Package -> appendOutline(location, to, node.members)
- }
- }
- }
- }
-
- override fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) {
- with(to.appendHTML()) {
- ul { body() }
- }
- }
-
-}
-
-class JavaLayoutHtmlFormatGenerator @Inject constructor(
- private val outlineFormatService: OutlineFormatService
-) : Generator {
- override fun buildPages(nodes: Iterable<DocumentationNode>) {
-
- }
-
- override fun buildOutlines(nodes: Iterable<DocumentationNode>) {
- for (node in nodes) {
- if (node.kind == NodeKind.Module) {
- //outlineFormatService.formatOutline()
- }
- }
- }
-
- override fun buildSupportFiles() {}
-
- override fun buildPackageList(nodes: Iterable<DocumentationNode>) {
-
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/JekyllFormatService.kt b/core/src/main/kotlin/Formats/JekyllFormatService.kt
deleted file mode 100644
index a948dfa9..00000000
--- a/core/src/main/kotlin/Formats/JekyllFormatService.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import org.jetbrains.dokka.Utilities.impliedPlatformsName
-
-open class JekyllOutputBuilder(to: StringBuilder,
- location: Location,
- generator: NodeLocationAwareGenerator,
- languageService: LanguageService,
- extension: String,
- impliedPlatforms: List<String>)
- : MarkdownOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms) {
- override fun appendNodes(nodes: Iterable<DocumentationNode>) {
- to.appendln("---")
- appendFrontMatter(nodes, to)
- to.appendln("---")
- to.appendln("")
- super.appendNodes(nodes)
- }
-
- protected open fun appendFrontMatter(nodes: Iterable<DocumentationNode>, to: StringBuilder) {
- to.appendln("title: ${getPageTitle(nodes)}")
- }
-}
-
-
-open class JekyllFormatService(
- generator: NodeLocationAwareGenerator,
- signatureGenerator: LanguageService,
- linkExtension: String,
- impliedPlatforms: List<String>
-) : MarkdownFormatService(generator, signatureGenerator, linkExtension, impliedPlatforms) {
-
- @Inject constructor(
- generator: NodeLocationAwareGenerator,
- signatureGenerator: LanguageService,
- @Named(impliedPlatformsName) impliedPlatforms: List<String>
- ) : this(generator, signatureGenerator, "html", impliedPlatforms)
-
- override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- JekyllOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms)
-
-}
diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt
deleted file mode 100644
index 3cdea156..00000000
--- a/core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt
+++ /dev/null
@@ -1,264 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import org.jetbrains.dokka.Utilities.impliedPlatformsName
-import java.io.File
-
-
-object EmptyHtmlTemplateService : HtmlTemplateService {
- override fun appendFooter(to: StringBuilder) {}
-
- override fun appendHeader(to: StringBuilder, title: String?, basePath: File) {}
-}
-
-
-open class KotlinWebsiteHtmlOutputBuilder(
- to: StringBuilder,
- location: Location,
- generator: NodeLocationAwareGenerator,
- languageService: LanguageService,
- extension: String,
- val impliedPlatforms: List<String>,
- templateService: HtmlTemplateService
-) : HtmlOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms, templateService) {
- private var needHardLineBreaks = false
- private var insideDiv = 0
-
- override fun appendLine() {}
-
- override fun appendBreadcrumbs(path: Iterable<FormatLink>) {
- if (path.count() > 1) {
- to.append("<div class='api-docs-breadcrumbs'>")
- super.appendBreadcrumbs(path)
- to.append("</div>")
- }
- }
-
- override fun appendSinceKotlin(version: String) {
- }
-
- override fun appendSinceKotlinWrapped(version: String) {
- }
-
- override fun appendCode(body: () -> Unit) = wrapIfNotEmpty("<code>", "</code>", body)
-
- protected fun div(to: StringBuilder, cssClass: String, otherAttributes: String = "", block: () -> Unit) {
- to.append("<div class=\"$cssClass\"$otherAttributes")
- to.append(">")
- insideDiv++
- block()
- insideDiv--
- to.append("</div>\n")
- }
-
- override fun appendAsSignature(node: ContentNode, block: () -> Unit) {
- val contentLength = node.textLength
- if (contentLength == 0) return
- div(to, "signature") {
- needHardLineBreaks = contentLength >= 62
- try {
- block()
- } finally {
- needHardLineBreaks = false
- }
- }
- }
-
- override fun appendAsOverloadGroup(to: StringBuilder, platforms: PlatformsData, block: () -> Unit) {
- div(to, "overload-group", calculateDataAttributes(platforms)) {
- block()
- }
- }
-
- override fun appendLink(href: String, body: () -> Unit) = wrap("<a href=\"$href\">", "</a>", body)
-
- override fun appendTable(vararg columns: String, body: () -> Unit) {
- //to.appendln("<table class=\"api-docs-table\">")
- div(to, "api-declarations-list") {
- body()
- }
- //to.appendln("</table>")
- }
-
- override fun appendTableBody(body: () -> Unit) {
- //to.appendln("<tbody>")
- body()
- //to.appendln("</tbody>")
- }
-
- override fun appendTableRow(body: () -> Unit) {
- //to.appendln("<tr>")
- body()
- //to.appendln("</tr>")
- }
-
- override fun appendTableCell(body: () -> Unit) {
-// to.appendln("<td>")
- body()
-// to.appendln("\n</td>")
- }
-
- override fun appendSymbol(text: String) {
- to.append("<span class=\"symbol\">${text.htmlEscape()}</span>")
- }
-
- override fun appendKeyword(text: String) {
- to.append("<span class=\"keyword\">${text.htmlEscape()}</span>")
- }
-
- override fun appendIdentifier(text: String, kind: IdentifierKind, signature: String?) {
- val id = signature?.let { " id=\"$it\"" }.orEmpty()
- to.append("<span class=\"${identifierClassName(kind)}\"$id>${text.htmlEscape()}</span>")
- }
-
- override fun appendSoftLineBreak() {
- if (needHardLineBreaks)
- to.append("<br/>")
- }
-
- override fun appendIndentedSoftLineBreak() {
- if (needHardLineBreaks) {
- to.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;")
- }
- }
-
- private fun identifierClassName(kind: IdentifierKind) = when (kind) {
- IdentifierKind.ParameterName -> "parameterName"
- IdentifierKind.SummarizedTypeName -> "summarizedTypeName"
- else -> "identifier"
- }
-
- private data class PlatformsForElement(
- val platformToVersion: Map<String, String>
- )
-
- private fun calculatePlatforms(platforms: PlatformsData): PlatformsForElement {
- //val kotlinVersion = platforms.singleOrNull(String::isKotlinVersion)?.removePrefix("Kotlin ")
- val jreVersion = platforms.keys.filter(String::isJREVersion).min()?.takeUnless { it.endsWith("6") }
- val targetPlatforms = platforms.filterNot { it.key.isJREVersion() } +
- listOfNotNull(jreVersion?.let { it to platforms[it]!! })
-
- return PlatformsForElement(
- targetPlatforms.mapValues { (_, nodes) -> effectiveSinceKotlinForNodes(nodes) }
- )
- }
-
- private fun calculateDataAttributes(platforms: PlatformsData): String {
- val platformToVersion = calculatePlatforms(platforms).platformToVersion
- val (platformNames, versions) = platformToVersion.toList().unzip()
- return "data-platform=\"${platformNames.joinToString()}\" "+
- "data-kotlin-version=\"${versions.joinToString()}\""
- }
-
- override fun appendIndexRow(platforms: PlatformsData, block: () -> Unit) {
-// if (platforms.isNotEmpty())
-// wrap("<tr${calculateDataAttributes(platforms)}>", "</tr>", block)
-// else
-// appendTableRow(block)
- div(to, "declarations", otherAttributes = " ${calculateDataAttributes(platforms)}") {
- block()
- }
- }
-
- override fun appendPlatforms(platforms: PlatformsData) {
- val platformToVersion = calculatePlatforms(platforms).platformToVersion
- div(to, "tags") {
- div(to, "spacer") {}
- platformToVersion.entries.sortedBy {
- platformSortWeight(it.key)
- }.forEach { (platform, version) ->
- div(to, "tags__tag platform tag-value-$platform",
- otherAttributes = " data-tag-version=\"$version\"") {
- to.append(platform)
- }
- }
- div(to, "tags__tag kotlin-version") {
- to.append(mergeVersions(platformToVersion.values.toList()))
- }
- }
- }
-
- override fun appendAsNodeDescription(platforms: PlatformsData, block: () -> Unit) {
- div(to, "node-page-main", otherAttributes = " ${calculateDataAttributes(platforms)}") {
- block()
- }
-
- }
-
- override fun appendBreadcrumbSeparator() {
- to.append(" / ")
- }
-
- override fun appendPlatformsAsText(platforms: PlatformsData) {
- appendHeader(5) {
- val filtered = platforms.keys.filterNot { it.isJREVersion() }.sortedBy { platformSortWeight(it) }
- if (filtered.isNotEmpty()) {
- to.append("For ")
- filtered.joinTo(to)
- }
- }
- }
-
- override fun appendSampleBlockCode(language: String, imports: () -> Unit, body: () -> Unit) {
- div(to, "sample", otherAttributes = " data-min-compiler-version=\"1.3\"") {
- appendBlockCode(language) {
- imports()
- wrap("\n\nfun main(args: Array<String>) {".htmlEscape(), "}") {
- wrap("\n//sampleStart\n", "\n//sampleEnd\n", body)
- }
- }
- }
- }
-
- override fun appendSoftParagraph(body: () -> Unit) = appendParagraph(body)
-
-
- override fun appendSectionWithTag(section: ContentSection) {
- appendParagraph {
- appendStrong { appendText(section.tag) }
- appendText(" ")
- appendContent(section)
- }
- }
-
- override fun appendAsPlatformDependentBlock(platforms: PlatformsData, block: (PlatformsData) -> Unit) {
- if (platforms.isNotEmpty())
- wrap("<div ${calculateDataAttributes(platforms)}>", "</div>") {
- block(platforms)
- }
- else
- block(platforms)
- }
-
- override fun appendAsSummaryGroup(platforms: PlatformsData, block: (PlatformsData) -> Unit) {
- div(to, "summary-group", otherAttributes = " ${calculateDataAttributes(platforms)}") {
- block(platforms)
- }
- }
-
- fun platformSortWeight(name: String) = when(name.toLowerCase()) {
- "common" -> 0
- "jvm" -> 1
- "js" -> 3
- "native" -> 4
- else -> 2 // This is hack to support JRE/JUnit and so on
- }
-}
-
-class KotlinWebsiteHtmlFormatService @Inject constructor(
- generator: NodeLocationAwareGenerator,
- signatureGenerator: LanguageService,
- @Named(impliedPlatformsName) impliedPlatforms: List<String>,
- templateService: HtmlTemplateService
-) : HtmlFormatService(generator, signatureGenerator, templateService, impliedPlatforms) {
-
- override fun enumerateSupportFiles(callback: (String, String) -> Unit) {}
-
- override fun createOutputBuilder(to: StringBuilder, location: Location) =
- KotlinWebsiteHtmlOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms, templateService)
-}
-
-
-private fun String.isKotlinVersion() = this.startsWith("Kotlin")
-private fun String.isJREVersion() = this.startsWith("JRE", ignoreCase=true) \ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/MarkdownFormatService.kt b/core/src/main/kotlin/Formats/MarkdownFormatService.kt
deleted file mode 100644
index 216dd2ef..00000000
--- a/core/src/main/kotlin/Formats/MarkdownFormatService.kt
+++ /dev/null
@@ -1,250 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import org.jetbrains.dokka.Utilities.impliedPlatformsName
-import java.util.*
-
-enum class ListKind {
- Ordered,
- Unordered
-}
-
-private class ListState(val kind: ListKind, var size: Int = 1) {
- fun getTagAndIncrement() = when (kind) {
- ListKind.Ordered -> "${size++}. "
- else -> "* "
- }
-}
-
-private val TWO_LINE_BREAKS = System.lineSeparator() + System.lineSeparator()
-
-open class MarkdownOutputBuilder(to: StringBuilder,
- location: Location,
- generator: NodeLocationAwareGenerator,
- languageService: LanguageService,
- extension: String,
- impliedPlatforms: List<String>)
- : StructuredOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms)
-{
- private val listStack = ArrayDeque<ListState>()
- protected var inTableCell = false
- protected var inCodeBlock = false
- private var lastTableCellStart = -1
- private var maxBackticksInCodeBlock = 0
-
- private fun appendNewline() {
- while (to.endsWith(' ')) {
- to.setLength(to.length - 1)
- }
- to.appendln()
- }
-
- private fun ensureNewline() {
- if (inTableCell && listStack.isEmpty()) {
- if (to.length != lastTableCellStart && !to.endsWith("<br>")) {
- to.append("<br>")
- }
- }
- else {
- if (!endsWithNewline()) {
- appendNewline()
- }
- }
- }
-
- private fun endsWithNewline(): Boolean {
- var index = to.length - 1
- while (index > 0) {
- val c = to[index]
- if (c != ' ') {
- return c == '\n'
- }
- index--
- }
- return false
- }
-
- override fun ensureParagraph() {
- if (!to.endsWith(TWO_LINE_BREAKS)) {
- if (!to.endsWith('\n')) {
- appendNewline()
- }
- appendNewline()
- }
- }
- override fun appendBreadcrumbSeparator() {
- to.append(" / ")
- }
-
- private val backTickFindingRegex = """(`+)""".toRegex()
-
- override fun appendText(text: String) {
- if (inCodeBlock) {
- to.append(text)
- val backTicks = backTickFindingRegex.findAll(text)
- val longestBackTickRun = backTicks.map { it.value.length }.max() ?: 0
- maxBackticksInCodeBlock = maxBackticksInCodeBlock.coerceAtLeast(longestBackTickRun)
- }
- else {
- if (text == "\n" && inTableCell) {
- to.append(" ")
- } else {
- to.append(text.htmlEscape())
- }
- }
- }
-
- override fun appendCode(body: () -> Unit) {
- inCodeBlock = true
- val codeBlockStart = to.length
- maxBackticksInCodeBlock = 0
-
- wrapIfNotEmpty("`", "`", body, checkEndsWith = true)
-
- if (maxBackticksInCodeBlock > 0) {
- val extraBackticks = "`".repeat(maxBackticksInCodeBlock)
- to.insert(codeBlockStart, extraBackticks)
- to.append(extraBackticks)
- }
-
- inCodeBlock = false
- }
-
- override fun appendUnorderedList(body: () -> Unit) {
- listStack.push(ListState(ListKind.Unordered))
- body()
- listStack.pop()
- ensureNewline()
- }
-
- override fun appendOrderedList(body: () -> Unit) {
- listStack.push(ListState(ListKind.Ordered))
- body()
- listStack.pop()
- ensureNewline()
- }
-
- override fun appendListItem(body: () -> Unit) {
- ensureNewline()
- to.append(listStack.peek()?.getTagAndIncrement())
- body()
- ensureNewline()
- }
-
- override fun appendStrong(body: () -> Unit) = wrap("**", "**", body)
- override fun appendEmphasis(body: () -> Unit) = wrap("*", "*", body)
- override fun appendStrikethrough(body: () -> Unit) = wrap("~~", "~~", body)
-
- override fun appendLink(href: String, body: () -> Unit) {
- if (inCodeBlock) {
- wrap("`[`", "`]($href)`", body)
- }
- else {
- wrap("[", "]($href)", body)
- }
- }
-
- override fun appendLine() {
- if (inTableCell) {
- to.append("<br>")
- }
- else {
- appendNewline()
- }
- }
-
- override fun appendAnchor(anchor: String) {
- // no anchors in Markdown
- }
-
- override fun appendParagraph(body: () -> Unit) {
- when {
- inTableCell -> {
- ensureNewline()
- body()
- }
- listStack.isNotEmpty() -> {
- body()
- ensureNewline()
- }
- else -> {
- ensureParagraph()
- body()
- ensureParagraph()
- }
- }
- }
-
- override fun appendHeader(level: Int, body: () -> Unit) {
- when {
- inTableCell -> {
- body()
- }
- else -> {
- ensureParagraph()
- to.append("${"#".repeat(level)} ")
- body()
- ensureParagraph()
- }
- }
- }
-
- override fun appendBlockCode(language: String, body: () -> Unit) {
- inCodeBlock = true
- ensureParagraph()
- to.appendln(if (language.isEmpty()) "```" else "``` $language")
- body()
- ensureNewline()
- to.appendln("```")
- appendLine()
- inCodeBlock = false
- }
-
- override fun appendTable(vararg columns: String, body: () -> Unit) {
- ensureParagraph()
- body()
- ensureParagraph()
- }
-
- override fun appendTableBody(body: () -> Unit) {
- body()
- }
-
- override fun appendTableRow(body: () -> Unit) {
- to.append("|")
- body()
- appendNewline()
- }
-
- override fun appendTableCell(body: () -> Unit) {
- to.append(" ")
- inTableCell = true
- lastTableCellStart = to.length
- body()
- inTableCell = false
- to.append(" |")
- }
-
- override fun appendNonBreakingSpace() {
- if (inCodeBlock) {
- to.append(" ")
- }
- else {
- to.append("&nbsp;")
- }
- }
-}
-
-open class MarkdownFormatService(generator: NodeLocationAwareGenerator,
- signatureGenerator: LanguageService,
- linkExtension: String,
- val impliedPlatforms: List<String>)
-: StructuredFormatService(generator, signatureGenerator, "md", linkExtension) {
- @Inject constructor(generator: NodeLocationAwareGenerator,
- signatureGenerator: LanguageService,
- @Named(impliedPlatformsName) impliedPlatforms: List<String>): this(generator, signatureGenerator, "md", impliedPlatforms)
-
- override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- MarkdownOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms)
-}
diff --git a/core/src/main/kotlin/Formats/OutlineService.kt b/core/src/main/kotlin/Formats/OutlineService.kt
deleted file mode 100644
index 958e93af..00000000
--- a/core/src/main/kotlin/Formats/OutlineService.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.jetbrains.dokka
-
-import java.io.File
-
-/**
- * Service for building the outline of the package contents.
- */
-interface OutlineFormatService {
- fun getOutlineFileName(location: Location): File
-
- fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder)
- fun appendOutlineLevel(to: StringBuilder, body: () -> Unit)
-
- /** Appends formatted outline to [StringBuilder](to) using specified [location] */
- fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- for (node in nodes) {
- appendOutlineHeader(location, node, to)
- if (node.members.any()) {
- val sortedMembers = node.members.sortedBy { it.name.toLowerCase() }
- appendOutlineLevel(to) {
- appendOutline(location, to, sortedMembers)
- }
- }
- }
- }
-
- fun formatOutline(location: Location, nodes: Iterable<DocumentationNode>): String =
- StringBuilder().apply { appendOutline(location, this, nodes) }.toString()
-}
diff --git a/core/src/main/kotlin/Formats/PackageListService.kt b/core/src/main/kotlin/Formats/PackageListService.kt
deleted file mode 100644
index e675d927..00000000
--- a/core/src/main/kotlin/Formats/PackageListService.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-
-
-interface PackageListService {
- fun formatPackageList(module: DocumentationModule): String
-}
-
-class DefaultPackageListService @Inject constructor(
- val generator: NodeLocationAwareGenerator,
- val formatService: FormatService
-) : PackageListService {
-
- override fun formatPackageList(module: DocumentationModule): String {
- val packages = mutableSetOf<String>()
- val nonStandardLocations = mutableMapOf<String, String>()
-
- fun visit(node: DocumentationNode, relocated: Boolean = false) {
- val nodeKind = node.kind
-
- when (nodeKind) {
- NodeKind.Package -> {
- packages.add(node.qualifiedName())
- node.members.forEach { visit(it) }
- }
- NodeKind.Signature -> {
- if (relocated)
- nonStandardLocations[node.name] = generator.relativePathToLocation(module, node.owner!!)
- }
- NodeKind.ExternalClass -> {
- node.members.forEach { visit(it, relocated = true) }
- }
- NodeKind.GroupNode -> {
- if (node.members.isNotEmpty()) {
- // Only nodes only has single file is need to be relocated
- // TypeAliases for example
- node.origins
- .filter { it.members.isEmpty() }
- .forEach { visit(it, relocated = true) }
- }
- }
- else -> {
- if (nodeKind in NodeKind.classLike || nodeKind in NodeKind.memberLike) {
- node.details(NodeKind.Signature).forEach { visit(it, relocated) }
- node.members.forEach { visit(it, relocated) }
- }
- }
- }
- }
-
- module.members.forEach { visit(it) }
-
- return buildString {
- appendln("\$dokka.linkExtension:${formatService.linkExtension}")
-
- nonStandardLocations.map { (signature, location) -> "\$dokka.location:$signature\u001f$location" }
- .sorted().joinTo(this, separator = "\n", postfix = "\n")
-
- packages.sorted().joinTo(this, separator = "\n", postfix = "\n")
- }
-
- }
-
-}
-
diff --git a/core/src/main/kotlin/Formats/StandardFormats.kt b/core/src/main/kotlin/Formats/StandardFormats.kt
deleted file mode 100644
index 86f70a37..00000000
--- a/core/src/main/kotlin/Formats/StandardFormats.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import com.google.inject.Binder
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Samples.KotlinWebsiteSampleProcessingService
-import org.jetbrains.dokka.Utilities.bind
-import kotlin.reflect.KClass
-
-abstract class KotlinFormatDescriptorBase
- : FileGeneratorBasedFormatDescriptor(),
- DefaultAnalysisComponent,
- DefaultAnalysisComponentServices by KotlinAsKotlin {
- override val generatorServiceClass = FileGenerator::class
- override val outlineServiceClass: KClass<out OutlineFormatService>? = null
- override val packageListServiceClass: KClass<out PackageListService>? = DefaultPackageListService::class
-}
-
-abstract class HtmlFormatDescriptorBase : FileGeneratorBasedFormatDescriptor(), DefaultAnalysisComponent {
- override val formatServiceClass = HtmlFormatService::class
- override val outlineServiceClass = HtmlFormatService::class
- override val generatorServiceClass = FileGenerator::class
- override val packageListServiceClass = DefaultPackageListService::class
-
- override fun configureOutput(binder: Binder): Unit = with(binder) {
- super.configureOutput(binder)
- bind<HtmlTemplateService>().toProvider { HtmlTemplateService.default("style.css") }
- }
-}
-
-class HtmlFormatDescriptor : HtmlFormatDescriptorBase(), DefaultAnalysisComponentServices by KotlinAsKotlin
-
-class HtmlAsJavaFormatDescriptor : HtmlFormatDescriptorBase(), DefaultAnalysisComponentServices by KotlinAsJava
-
-class KotlinWebsiteHtmlFormatDescriptor : KotlinFormatDescriptorBase() {
- override val formatServiceClass = KotlinWebsiteHtmlFormatService::class
- override val sampleProcessingService = KotlinWebsiteSampleProcessingService::class
- override val outlineServiceClass = YamlOutlineService::class
-
- override fun configureOutput(binder: Binder) = with(binder) {
- super.configureOutput(binder)
- bind<HtmlTemplateService>().toInstance(EmptyHtmlTemplateService)
- }
-}
-
-class JekyllFormatDescriptor : KotlinFormatDescriptorBase() {
- override val formatServiceClass = JekyllFormatService::class
-}
-
-class MarkdownFormatDescriptor : KotlinFormatDescriptorBase() {
- override val formatServiceClass = MarkdownFormatService::class
-}
-
-class GFMFormatDescriptor : KotlinFormatDescriptorBase() {
- override val formatServiceClass = GFMFormatService::class
-}
diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt
deleted file mode 100644
index 76f9366f..00000000
--- a/core/src/main/kotlin/Formats/StructuredFormatService.kt
+++ /dev/null
@@ -1,1014 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.LanguageService.RenderMode
-import org.jetbrains.kotlin.utils.keysToMap
-import java.util.*
-
-data class FormatLink(val text: String, val href: String)
-
-private data class Summarized(
- val data: List<SummarizedBySummary>
-) {
-
- constructor(data: Map<ContentNode, Map<ContentNode, List<DocumentationNode>>>) : this(
- data.entries.map { (summary, signatureToMember) ->
- SummarizedBySummary(
- summary,
- signatureToMember.map { (signature, nodes) ->
- SummarizedNodes(signature, nodes)
- }
- )
- }
- )
-
- data class SummarizedNodes(val content: ContentNode, val nodes: List<DocumentationNode>) {
- val platforms = effectivePlatformsForMembers(nodes)
- }
- data class SummarizedBySummary(val content: ContentNode, val signatures: List<SummarizedNodes>) {
- val platforms = effectivePlatformsForMembers(signatures.flatMap { it.nodes })
- val platformsOnSignature = !samePlatforms(signatures.map { it.platforms })
- }
-
-
- fun computePlatformLevel(): PlatformPlacement {
- if (data.any { it.platformsOnSignature }) {
- return PlatformPlacement.Signature
- }
- if (samePlatforms(data.map { it.platforms })) {
- return PlatformPlacement.Row
- }
- return PlatformPlacement.Summary
- }
- val platformPlacement: PlatformPlacement = computePlatformLevel()
- val platforms = effectivePlatformsForMembers(data.flatMap { it.signatures.flatMap { it.nodes } })
-
-
- enum class PlatformPlacement {
- Row, Summary, Signature
- }
-}
-
-abstract class StructuredOutputBuilder(val to: StringBuilder,
- val location: Location,
- val generator: NodeLocationAwareGenerator,
- val languageService: LanguageService,
- val extension: String,
- impliedPlatforms: List<String>) : FormattedOutputBuilder {
-
- protected fun wrap(prefix: String, suffix: String, body: () -> Unit) {
- to.append(prefix)
- body()
- to.append(suffix)
- }
-
- protected fun wrapIfNotEmpty(prefix: String, suffix: String, body: () -> Unit, checkEndsWith: Boolean = false) {
- val startLength = to.length
- to.append(prefix)
- body()
- if (checkEndsWith && to.endsWith(suffix)) {
- to.setLength(to.length - suffix.length)
- } else if (to.length > startLength + prefix.length) {
- to.append(suffix)
- } else {
- to.setLength(startLength)
- }
- }
-
- protected fun wrapInTag(tag: String,
- body: () -> Unit,
- newlineBeforeOpen: Boolean = false,
- newlineAfterOpen: Boolean = false,
- newlineAfterClose: Boolean = false) {
- if (newlineBeforeOpen && !to.endsWith('\n')) to.appendln()
- to.append("<$tag>")
- if (newlineAfterOpen) to.appendln()
- body()
- to.append("</$tag>")
- if (newlineAfterClose) to.appendln()
- }
-
- protected abstract fun ensureParagraph()
-
- open fun appendSampleBlockCode(language: String, imports: () -> Unit, body: () -> Unit) = appendBlockCode(language, body)
- abstract fun appendBlockCode(language: String, body: () -> Unit)
- abstract fun appendHeader(level: Int = 1, body: () -> Unit)
- abstract fun appendParagraph(body: () -> Unit)
-
- open fun appendSoftParagraph(body: () -> Unit) {
- ensureParagraph()
- body()
- }
-
- abstract fun appendLine()
- abstract fun appendAnchor(anchor: String)
-
- abstract fun appendTable(vararg columns: String, body: () -> Unit)
- abstract fun appendTableBody(body: () -> Unit)
- abstract fun appendTableRow(body: () -> Unit)
- abstract fun appendTableCell(body: () -> Unit)
-
- abstract fun appendText(text: String)
-
- open fun appendSinceKotlin(version: String) {
- appendText("Since: ")
- appendCode { appendText(version) }
- }
-
- open fun appendSinceKotlinWrapped(version: String) {
- wrap(" (", ")") {
- appendSinceKotlin(version)
- }
- }
-
- open fun appendSectionWithTag(section: ContentSection) {
- appendParagraph {
- appendStrong { appendText(section.tag) }
- appendLine()
- appendContent(section)
- }
- }
-
- open fun appendAsPlatformDependentBlock(platforms: PlatformsData, block: (PlatformsData) -> Unit) {
- block(platforms)
- }
-
- open fun appendAsSummaryGroup(platforms: PlatformsData, block: (PlatformsData) -> Unit) {
- appendAsPlatformDependentBlock(platforms, block)
- }
-
- open fun appendSymbol(text: String) {
- appendText(text)
- }
-
- open fun appendKeyword(text: String) {
- appendText(text)
- }
-
- open fun appendIdentifier(text: String, kind: IdentifierKind, signature: String?) {
- appendText(text)
- }
-
- open fun appendAsNodeDescription(platforms: PlatformsData, block: () -> Unit) {
- block()
- }
-
- fun appendEntity(text: String) {
- to.append(text)
- }
-
- abstract fun appendLink(href: String, body: () -> Unit)
-
- open fun appendLink(link: FormatLink) {
- appendLink(link.href) { appendText(link.text) }
- }
-
- abstract fun appendStrong(body: () -> Unit)
- abstract fun appendStrikethrough(body: () -> Unit)
- abstract fun appendEmphasis(body: () -> Unit)
- abstract fun appendCode(body: () -> Unit)
- abstract fun appendUnorderedList(body: () -> Unit)
- abstract fun appendOrderedList(body: () -> Unit)
- abstract fun appendListItem(body: () -> Unit)
-
- abstract fun appendBreadcrumbSeparator()
- abstract fun appendNonBreakingSpace()
- open fun appendSoftLineBreak() {
- }
-
- open fun appendIndentedSoftLineBreak() {
- }
-
- fun appendContent(content: List<ContentNode>) {
- for (contentNode in content) {
- appendContent(contentNode)
- }
- }
-
- open fun appendContent(content: ContentNode) {
- when (content) {
- is ContentText -> appendText(content.text)
- is ContentSymbol -> appendSymbol(content.text)
- is ContentKeyword -> appendKeyword(content.text)
- is ContentIdentifier -> appendIdentifier(content.text, content.kind, content.signature)
- is ContentNonBreakingSpace -> appendNonBreakingSpace()
- is ContentSoftLineBreak -> appendSoftLineBreak()
- is ContentIndentedSoftLineBreak -> appendIndentedSoftLineBreak()
- is ContentEntity -> appendEntity(content.text)
- is ContentStrong -> appendStrong { appendContent(content.children) }
- is ContentStrikethrough -> appendStrikethrough { appendContent(content.children) }
- is ContentCode -> appendCode { appendContent(content.children) }
- is ContentEmphasis -> appendEmphasis { appendContent(content.children) }
- is ContentUnorderedList -> appendUnorderedList { appendContent(content.children) }
- is ContentOrderedList -> appendOrderedList { appendContent(content.children) }
- is ContentListItem -> appendListItem {
- val child = content.children.singleOrNull()
- if (child is ContentParagraph) {
- appendContent(child.children)
- } else {
- appendContent(content.children)
- }
- }
-
- is NodeRenderContent -> {
- val node = content.node
- appendContent(languageService.render(node, content.mode))
- }
- is ContentNodeLink -> {
- val node = content.node
- val linkTo = if (node != null) locationHref(location, node, generator) else "#"
- appendLinkIfNotThisPage(linkTo, content)
- }
- is ContentExternalLink -> appendLinkIfNotThisPage(content.href, content)
-
- is ContentParagraph -> {
- if (!content.isEmpty()) {
- appendParagraph { appendContent(content.children) }
- }
- }
-
- is ContentBlockSampleCode, is ContentBlockCode -> {
- content as ContentBlockCode
- fun ContentBlockCode.appendBlockCodeContent() {
- children
- .dropWhile { it is ContentText && it.text.isBlank() }
- .forEach { appendContent(it) }
- }
- when (content) {
- is ContentBlockSampleCode ->
- appendSampleBlockCode(content.language, content.importsBlock::appendBlockCodeContent) { content.appendBlockCodeContent() }
- is ContentBlockCode ->
- appendBlockCode(content.language) { content.appendBlockCodeContent() }
- }
- }
- is ContentHeading -> appendHeader(content.level) { appendContent(content.children) }
- is ContentBlock -> appendContent(content.children)
- }
- }
-
- private fun appendLinkIfNotThisPage(href: String, content: ContentBlock) {
- if (href == ".") {
- appendContent(content.children)
- } else {
- appendLink(href) { appendContent(content.children) }
- }
- }
-
- open fun link(
- from: DocumentationNode,
- to: DocumentationNode,
- name: (DocumentationNode) -> String = DocumentationNode::name
- ): FormatLink = link(from, to, extension, name)
-
- open fun link(
- from: DocumentationNode,
- to: DocumentationNode,
- extension: String,
- name: (DocumentationNode) -> String = DocumentationNode::name
- ): FormatLink =
- FormatLink(name(to), generator.relativePathToLocation(from, to))
-
- private fun DocumentationNode.isModuleOrPackage(): Boolean =
- kind == NodeKind.Module || kind == NodeKind.Package
-
- protected open fun appendAsSignature(node: ContentNode, block: () -> Unit) {
- block()
- }
-
- protected open fun appendAsOverloadGroup(to: StringBuilder, platforms: PlatformsData, block: () -> Unit) {
- block()
- }
-
- protected open fun appendIndexRow(platforms: PlatformsData, block: () -> Unit) {
- appendTableRow(block)
- }
-
- protected open fun appendPlatformsAsText(platforms: PlatformsData) {
- appendPlatforms(platforms)
- }
-
- protected open fun appendPlatforms(platforms: PlatformsData) {
- if (platforms.isNotEmpty()) {
- appendText(platforms.keys.joinToString(prefix = "(", postfix = ") "))
- }
- }
-
- protected open fun appendBreadcrumbs(path: Iterable<FormatLink>) {
- for ((index, item) in path.withIndex()) {
- if (index > 0) {
- appendBreadcrumbSeparator()
- }
- appendLink(item)
- }
- }
-
- fun Content.getSectionsWithSubjects(): Map<String, List<ContentSection>> =
- sections.filter { it.subjectName != null }.groupBy { it.tag }
-
- private fun ContentNode.appendSignature() {
- if (this is ContentBlock && this.isEmpty()) {
- return
- }
-
- val signatureAsCode = ContentCode()
- signatureAsCode.append(this)
- appendContent(signatureAsCode)
- }
-
- open inner class PageBuilder(val nodes: Iterable<DocumentationNode>, val noHeader: Boolean = false) {
- open fun build() {
- val breakdownByLocation = nodes.groupBy { node ->
- node.path.filterNot { it.name.isEmpty() }.map { link(node, it) }.distinct()
- }
-
- for ((path, nodes) in breakdownByLocation) {
- if (!noHeader && path.isNotEmpty()) {
- appendBreadcrumbs(path)
- appendLine()
- appendLine()
- }
- appendLocation(nodes.filter { it.kind != NodeKind.ExternalClass })
- }
- }
-
- private fun appendLocation(nodes: Iterable<DocumentationNode>) {
- val singleNode = nodes.singleOrNull()
- if (singleNode != null && singleNode.isModuleOrPackage()) {
- if (singleNode.kind == NodeKind.Package) {
- val packageName = if (singleNode.name.isEmpty()) "<root>" else singleNode.name
- appendHeader(2) { appendText("Package $packageName") }
- }
- appendContent(singleNode.content)
- } else {
- val breakdownByName = nodes.groupBy { node -> node.name }
- for ((name, items) in breakdownByName) {
- if (!noHeader)
- appendHeader { appendText(name) }
- appendDocumentation(items, singleNode != null)
- }
- }
- }
-
- private fun appendDocumentation(overloads: Iterable<DocumentationNode>, isSingleNode: Boolean) {
- val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node ->
- when (node.kind) {
- NodeKind.GroupNode -> node.origins.map { it.content }
- else -> node.content
- }
- }
-
- if (breakdownBySummary.size == 1) {
- val node = breakdownBySummary.values.single()
- appendAsNodeDescription(effectivePlatformsForMembers(node)) {
- formatOverloadGroup(node, isSingleNode)
- }
- } else {
- for ((_, items) in breakdownBySummary) {
- appendAsOverloadGroup(to, effectivePlatformsForMembers(items)) {
- formatOverloadGroup(items)
- }
- }
- }
- }
-
- private fun formatOverloadGroup(items: List<DocumentationNode>, isSingleNode: Boolean = false) {
-
- val platformsPerGroup = samePlatforms(
- items.flatMap {
- if (it.kind == NodeKind.GroupNode) {
- it.origins.groupBy { origin ->
- languageService.render(origin)
- }.values.map { origins -> effectivePlatformsForMembers(origins) }
- } else {
- listOf(effectivePlatformsForNode(it))
- }
- }
- )
-
- if (platformsPerGroup) {
- appendAsPlatformDependentBlock(effectivePlatformsForMembers(items)) { platforms ->
- appendPlatforms(platforms)
- }
- }
- for ((index, item) in items.withIndex()) {
- if (index > 0) appendLine()
-
- if (item.kind == NodeKind.GroupNode) {
- renderGroupNode(item, isSingleNode, !platformsPerGroup)
- } else {
- renderSimpleNode(item, isSingleNode, !platformsPerGroup)
- }
-
- }
- // All items have exactly the same documentation, so we can use any item to render it
- val item = items.first()
- // TODO: remove this block cause there is no one node with OverloadGroupNote detail
- item.details(NodeKind.OverloadGroupNote).forEach {
- appendContent(it.content)
- }
-
- if (item.kind == NodeKind.GroupNode) {
- val groupByContent = item.origins.groupBy { it.content }
- if (groupByContent.count { !it.key.isEmpty() } > 1) {
- if (groupByContent.size > 1) println("[mult] Found ov diff: ${generator.location(item).path}")
- }
- for ((content, origins) in groupByContent) {
- if (content.isEmpty()) continue
- appendAsPlatformDependentBlock(effectivePlatformsForMembers(origins)) { platforms ->
- if (groupByContent.count { !it.key.isEmpty() } > 1) {
- appendPlatformsAsText(platforms)
- }
- appendContent(content.summary)
- content.appendDescription()
- }
- }
- } else {
- val platforms = effectivePlatformsForNode(item)
- appendAsPlatformDependentBlock(platforms) {
- appendContent(item.summary)
- item.content.appendDescription()
- }
- }
- }
-
-
- fun renderSimpleNode(item: DocumentationNode, isSingleNode: Boolean, withPlatforms: Boolean = true) {
- appendAsPlatformDependentBlock(effectivePlatformsForMembers(listOf(item))) { platforms ->
- // TODO: use summarizesignatures
- val rendered = languageService.render(item)
- item.detailOrNull(NodeKind.Signature)?.let {
- if (item.kind !in NodeKind.classLike || !isSingleNode)
- appendAnchor(it.name)
- }
- if (withPlatforms) {
- appendPlatforms(platforms)
- }
- appendAsSignature(rendered) {
- appendCode { appendContent(rendered) }
- item.appendSourceLink()
- }
- item.appendOverrides()
- item.appendDeprecation()
- }
- }
-
- fun renderGroupNode(item: DocumentationNode, isSingleNode: Boolean, withPlatforms: Boolean = true) {
- // TODO: use summarizesignatures
- val groupBySignature = item.origins.groupBy {
- languageService.render(it)
- }
-
- for ((sign, nodes) in groupBySignature) {
- appendAsPlatformDependentBlock(effectivePlatformsForMembers(nodes)) { platforms ->
- val first = nodes.first()
- first.detailOrNull(NodeKind.Signature)?.let {
- if (item.kind !in NodeKind.classLike || !isSingleNode)
- appendAnchor(it.name)
- }
-
- if (withPlatforms) {
- appendPlatforms(platforms)
- }
-
- appendAsSignature(sign) {
- appendCode { appendContent(sign) }
- }
- first.appendOverrides()
- first.appendDeprecation()
- }
-
- }
- }
-
- private fun DocumentationNode.appendSourceLink() {
- val sourceUrl = details(NodeKind.SourceUrl).firstOrNull()
- if (sourceUrl != null) {
- to.append(" ")
- appendLink(sourceUrl.name) { to.append("(source)") }
- }
- }
-
- private fun DocumentationNode.appendOverrides() {
- overrides.forEach {
- appendParagraph {
- to.append("Overrides ")
- val location = generator.relativePathToLocation(this, it)
-
- appendLink(FormatLink(it.owner!!.name + "." + it.name, location))
- }
- }
- }
-
- private fun DocumentationNode.appendDeprecation() {
- if (deprecation != null) {
- val deprecationParameter = deprecation!!.details(NodeKind.Parameter).firstOrNull()
- val deprecationValue = deprecationParameter?.details(NodeKind.Value)?.firstOrNull()
- appendLine()
- when {
- deprecationValue != null -> {
- appendStrong { to.append("Deprecated:") }
- appendText(" " + deprecationValue.name.removeSurrounding("\""))
- appendLine()
- appendLine()
- }
- deprecation?.content != Content.Empty -> {
- appendStrong { to.append("Deprecated:") }
- to.append(" ")
- appendContent(deprecation!!.content)
- }
- else -> {
- appendStrong { to.append("Deprecated") }
- appendLine()
- appendLine()
- }
- }
- }
- }
-
-
-// protected fun platformsOfItems(items: List<DocumentationNode>): Set<String> {
-// val platforms = items.asSequence().map {
-// when (it.kind) {
-// NodeKind.ExternalClass, NodeKind.Package, NodeKind.Module -> platformsOfItems(it.members)
-// NodeKind.GroupNode -> platformsOfItems(it.origins)
-// else -> it.platformsToShow.toSet()
-// }
-// }
-//
-// fun String.isKotlinVersion() = this.startsWith("Kotlin")
-//
-// if (platforms.count() == 0) return emptySet()
-//
-// // Calculating common platforms for items
-// return platforms.reduce { result, platformsOfItem ->
-// val otherKotlinVersion = result.find { it.isKotlinVersion() }
-// val (kotlinVersions, otherPlatforms) = platformsOfItem.partition { it.isKotlinVersion() }
-//
-// // When no Kotlin version specified, it means that version is 1.0
-// if (otherKotlinVersion != null && kotlinVersions.isNotEmpty()) {
-// result.intersect(platformsOfItem) + mergeVersions(otherKotlinVersion, kotlinVersions)
-// } else {
-// result.intersect(platformsOfItem)
-// }
-// }
-// }
-//
-// protected fun unionPlatformsOfItems(items: List<DocumentationNode>): Set<String> {
-// val platforms = items.asSequence().map {
-// when (it.kind) {
-// NodeKind.GroupNode -> unionPlatformsOfItems(it.origins)
-// else -> it.platformsToShow.toSet()
-// }
-// }
-//
-// fun String.isKotlinVersion() = this.startsWith("Kotlin")
-//
-// if (platforms.count() == 0) return emptySet()
-//
-// // Calculating common platforms for items
-// return platforms.reduce { result, platformsOfItem ->
-// val otherKotlinVersion = result.find { it.isKotlinVersion() }
-// val (kotlinVersions, otherPlatforms) = platformsOfItem.partition { it.isKotlinVersion() }
-//
-// // When no Kotlin version specified, it means that version is 1.0
-// if (otherKotlinVersion != null && kotlinVersions.isNotEmpty()) {
-// result.union(otherPlatforms) + mergeVersions(otherKotlinVersion, kotlinVersions)
-// } else {
-// result.union(otherPlatforms)
-// }
-// }
-// }
-
-// val DocumentationNode.platformsToShow: List<String>
-// get() = platforms
-
- private fun Content.appendDescription() {
- if (description != ContentEmpty) {
- appendContent(description)
- }
-
-
- getSectionsWithSubjects().forEach {
- appendSectionWithSubject(it.key, it.value)
- }
-
- for (section in sections.filter { it.subjectName == null }) {
- appendSectionWithTag(section)
- }
- }
-
- fun appendSectionWithSubject(title: String, subjectSections: List<ContentSection>) {
- appendHeader(3) { appendText(title) }
- subjectSections.forEach {
- val subjectName = it.subjectName
- if (subjectName != null) {
- appendSoftParagraph {
- appendAnchor(subjectName)
- appendCode { to.append(subjectName) }
- to.append(" - ")
- appendContent(it)
- }
- }
- }
- }
-
- fun appendOriginsGroupByContent(node: DocumentationNode) {
- require(node.kind == NodeKind.GroupNode)
- val groupByContent =
- node.origins.groupBy { it.content }
- .mapValues { (_, origins) ->
- effectivePlatformsForMembers(origins)
- }
- .filterNot { it.key.isEmpty() }
- .toList()
- .sortedByDescending { it.second.size }
-
- if (groupByContent.size > 1) println("[mult] Found diff: ${generator.location(node).path}")
- for ((content, platforms) in groupByContent) {
- appendAsPlatformDependentBlock(platforms) {
- if (groupByContent.size > 1) {
- appendPlatformsAsText(platforms)
- }
- appendContent(content.summary)
- content.appendDescription()
- }
- }
- }
- }
-
- inner class SingleNodePageBuilder(val node: DocumentationNode, noHeader: Boolean = false) :
- PageBuilder(listOf(node), noHeader) {
-
- override fun build() {
- super.build()
- SectionsBuilder(node).build()
- }
- }
-
- inner class GroupNodePageBuilder(val node: DocumentationNode) : PageBuilder(listOf(node)) {
-
- override fun build() {
- val breakdownByLocation = node.path.filterNot { it.name.isEmpty() }.map { link(node, it) }
-
- appendBreadcrumbs(breakdownByLocation)
- appendLine()
- appendLine()
- appendHeader { appendText(node.name) }
-
- appendAsNodeDescription(effectivePlatformsForNode(node)) {
- renderGroupNode(node, true)
-
- appendOriginsGroupByContent(node)
- }
-
- SectionsBuilder(node).build()
- }
- }
-//
-// private fun unionPlatformsOfItems(items: List<DocumentationNode>): Set<String> {
-// val platforms = items.flatMapTo(mutableSetOf<String>()) {
-// when (it.kind) {
-// NodeKind.GroupNode -> unionPlatformsOfItems(it.origins)
-// else -> it.platforms
-// }
-// }
-//
-// return platforms
-// }
-
-
- inner class SectionsBuilder(val node: DocumentationNode): PageBuilder(listOf(node)) {
- override fun build() {
- if (node.kind == NodeKind.ExternalClass) {
- appendSection("Extensions for ${node.name}", node.members)
- return
- }
-
- fun DocumentationNode.membersOrGroupMembers(predicate: (DocumentationNode) -> Boolean): List<DocumentationNode> {
- return members.filter(predicate) + members(NodeKind.GroupNode).filter{ it.origins.isNotEmpty() && predicate(it.origins.first()) }
- }
-
- fun DocumentationNode.membersOrGroupMembers(kind: NodeKind): List<DocumentationNode> {
- return membersOrGroupMembers { it.kind == kind }
- }
-
- appendSection("Packages", node.members(NodeKind.Package), platformsBasedOnMembers = true)
- appendSection("Types", node.membersOrGroupMembers { it.kind in NodeKind.classLike /*&& it.kind != NodeKind.TypeAlias*/ && it.kind != NodeKind.AnnotationClass && it.kind != NodeKind.Exception })
- appendSection("Annotations", node.membersOrGroupMembers(NodeKind.AnnotationClass))
- appendSection("Exceptions", node.membersOrGroupMembers(NodeKind.Exception))
- appendSection("Extensions for External Classes", node.members(NodeKind.ExternalClass))
- appendSection("Enum Values", node.membersOrGroupMembers(NodeKind.EnumItem), sortMembers = false, omitSamePlatforms = true)
- appendSection("Constructors", node.membersOrGroupMembers(NodeKind.Constructor), omitSamePlatforms = true)
- appendSection("Properties", node.membersOrGroupMembers(NodeKind.Property), omitSamePlatforms = true)
- appendSection("Inherited Properties", node.inheritedMembers(NodeKind.Property))
- appendSection("Functions", node.membersOrGroupMembers(NodeKind.Function), omitSamePlatforms = true)
- appendSection("Inherited Functions", node.inheritedMembers(NodeKind.Function))
- appendSection("Companion Object Properties", node.membersOrGroupMembers(NodeKind.CompanionObjectProperty), omitSamePlatforms = true)
- appendSection("Inherited Companion Object Properties", node.inheritedCompanionObjectMembers(NodeKind.Property))
- appendSection("Companion Object Functions", node.membersOrGroupMembers(NodeKind.CompanionObjectFunction), omitSamePlatforms = true)
- appendSection("Inherited Companion Object Functions", node.inheritedCompanionObjectMembers(NodeKind.Function))
- appendSection("Other members", node.members.filter {
- it.kind !in setOf(
- NodeKind.Class,
- NodeKind.Interface,
- NodeKind.Enum,
- NodeKind.Object,
- NodeKind.AnnotationClass,
- NodeKind.Exception,
- NodeKind.TypeAlias,
- NodeKind.Constructor,
- NodeKind.Property,
- NodeKind.Package,
- NodeKind.Function,
- NodeKind.CompanionObjectProperty,
- NodeKind.CompanionObjectFunction,
- NodeKind.ExternalClass,
- NodeKind.EnumItem,
- NodeKind.AllTypes,
- NodeKind.GroupNode
- )
- })
-
- val allExtensions = node.extensions
- appendSection("Extension Properties", allExtensions.filter { it.kind == NodeKind.Property })
- appendSection("Extension Functions", allExtensions.filter { it.kind == NodeKind.Function })
- appendSection("Companion Object Extension Properties", allExtensions.filter { it.kind == NodeKind.CompanionObjectProperty })
- appendSection("Companion Object Extension Functions", allExtensions.filter { it.kind == NodeKind.CompanionObjectFunction })
- appendSection("Inheritors",
- node.inheritors.filter { it.kind != NodeKind.EnumItem })
-
- if (node.kind == NodeKind.Module) {
- appendHeader(3) { to.append("Index") }
- node.members(NodeKind.AllTypes).singleOrNull()?.let { allTypes ->
- appendLink(link(node, allTypes) { "All Types" })
- }
- }
- }
-
- private fun appendSection(caption: String, members: List<DocumentationNode>,
- sortMembers: Boolean = true,
- omitSamePlatforms: Boolean = false,
- platformsBasedOnMembers: Boolean = false) {
- if (members.isEmpty()) return
-
- appendHeader(3) { appendText(caption) }
-
- val children = if (sortMembers) members.sortedBy { it.name.toLowerCase() } else members
- val membersMap = children.groupBy { link(node, it) }
-
-
-
- appendTable("Name", "Summary") {
- appendTableBody {
- for ((memberLocation, membersList) in membersMap) {
- val platforms = effectivePlatformsForMembers(membersList)
-// val platforms = if (platformsBasedOnMembers)
-// members.flatMapTo(mutableSetOf()) { platformsOfItems(it.members) } + elementPlatforms
-// else
-// elementPlatforms
-
- val summarized = computeSummarySignatures(membersList)
-
- appendIndexRow(platforms) {
- appendTableCell {
- if (summarized.platformPlacement == Summarized.PlatformPlacement.Row) {
- appendPlatforms(platforms)
- }
- appendHeader(level = 4) {
- // appendParagraph {
- appendLink(memberLocation)
- }
- if (node.sinceKotlin != null) {
- appendSinceKotlin(node.sinceKotlin.toString())
- }
-
- if (membersList.singleOrNull()?.sinceKotlin != null){
- appendSinceKotlinWrapped(membersList.single().sinceKotlin.toString())
- }
-// }
-// if (members.singleOrNull()?.kind != NodeKind.ExternalClass) {
-// appendPlatforms(platforms)
-// }
-// }
- }
- appendTableCell {
- appendSummarySignatures(summarized)
- }
- }
- }
- }
- }
- }
-
-//
-// private fun platformsOfItems(items: List<DocumentationNode>, omitSamePlatforms: Boolean = true): Set<String> {
-// if (items.all { it.kind != NodeKind.Package && it.kind != NodeKind.Module && it.kind != NodeKind.ExternalClass }) {
-// return unionPlatformsOfItems(items)
-// }
-//
-// val platforms = platformsOfItems(items)
-// if (platforms.isNotEmpty() && (platforms != node.platformsToShow.toSet() || !omitSamePlatforms)) {
-// return platforms
-// }
-// return emptySet()
-// }
-
-
-
- private fun computeSummarySignatures(items: List<DocumentationNode>): Summarized =
- Summarized(items.groupBy { it.summary }.mapValues { (_, nodes) ->
- val nodesToAppend = nodes.flatMap { if(it.kind == NodeKind.GroupNode) it.origins else listOf(it) }
-
- val summarySignature = languageService.summarizeSignatures(nodesToAppend)
- if (summarySignature != null) {
- mapOf(summarySignature to nodesToAppend)
- } else {
- nodesToAppend.groupBy {
- languageService.render(it, RenderMode.SUMMARY)
- }
- }
- })
-
-
- private fun appendSummarySignatures(
- summarized: Summarized
- ) {
- for(summary in summarized.data) {
-
- appendAsSummaryGroup(summary.platforms) {
- if (summarized.platformPlacement == Summarized.PlatformPlacement.Summary) {
- appendPlatforms(summary.platforms)
- }
- appendContent(summary.content)
- summary.signatures.subList(0, summary.signatures.size - 1).forEach {
- appendSignatures(
- it,
- summarized.platformPlacement == Summarized.PlatformPlacement.Signature
- )
- appendLine()
- }
- appendSignatures(
- summary.signatures.last(),
- summarized.platformPlacement == Summarized.PlatformPlacement.Signature
- )
- }
-
- }
- }
-
- private fun appendSignatures(
- signature: Summarized.SummarizedNodes,
- withPlatforms: Boolean
- ) {
-
-// val platforms = if (platformsBasedOnMembers)
-// items.flatMapTo(mutableSetOf()) { platformsOfItems(it.members) } + elementPlatforms
-// else
-// elementPlatforms
-
-
- appendAsPlatformDependentBlock(signature.platforms) {
- if (withPlatforms) {
- appendPlatforms(signature.platforms)
- }
- appendAsSignature(signature.content) {
- signature.content.appendSignature()
- }
- appendSoftLineBreak()
- }
- }
- }
-
- private fun DocumentationNode.isClassLikeGroupNode(): Boolean {
- if (kind != NodeKind.GroupNode) {
- return false
- }
-
- return origins.all { it.kind in NodeKind.classLike }
- }
-
-
- inner class AllTypesNodeBuilder(val node: DocumentationNode)
- : PageBuilder(listOf(node)) {
-
- override fun build() {
- appendContent(node.owner!!.summary)
- appendHeader(3) { to.append("All Types") }
-
- appendTable("Name", "Summary") {
- appendTableBody {
- for (type in node.members) {
- val platforms = effectivePlatformsForNode(type)
- appendIndexRow(platforms) {
- appendPlatforms(platforms)
- if (type.kind == NodeKind.ExternalClass) {
- val packageName = type.owner?.name
- if (packageName != null) {
- appendText(" (extensions in package $packageName)")
- }
- }
- appendHeader(level = 5) {
- appendLink(link(node, type) {
- if (it.kind == NodeKind.ExternalClass) it.name else it.qualifiedName()
- })
- }
-
- appendContent(type.summary)
- }
- }
- }
- }
- }
- }
-
- override fun appendNodes(nodes: Iterable<DocumentationNode>) {
- val singleNode = nodes.singleOrNull()
- when (singleNode?.kind) {
- NodeKind.AllTypes -> AllTypesNodeBuilder(singleNode).build()
- NodeKind.GroupNode -> GroupNodePageBuilder(singleNode).build()
- null -> PageBuilder(nodes).build()
- else -> SingleNodePageBuilder(singleNode).build()
- }
- }
-}
-
-abstract class StructuredFormatService(val generator: NodeLocationAwareGenerator,
- val languageService: LanguageService,
- override val extension: String,
- override final val linkExtension: String = extension) : FormatService {
-
-}
-
-typealias PlatformsData = Map<String, Set<DocumentationNode>>
-
-fun memberPlatforms(node: DocumentationNode): PlatformsData {
- val members = when {
- node.kind == NodeKind.GroupNode -> node.origins
- node.kind in NodeKind.classLike -> emptyList()
- node.kind in NodeKind.memberLike -> emptyList()
- else -> node.members
- }
-
- return members.map(::effectivePlatformsForNode).fold(mapOf(), ::mergePlatforms)
-}
-
-fun mergePlatforms(a: PlatformsData, b: PlatformsData): PlatformsData {
- val mutable = a.toMutableMap()
- b.forEach { (name, declarations) ->
- mutable.merge(name, declarations) { a, b -> a.union(b) }
- }
- return mutable
-}
-
-fun effectivePlatformsForNode(node: DocumentationNode): PlatformsData {
- val platforms = node.platforms + memberPlatforms(node).keys
- return platforms.keysToMap { setOf(node) }
-}
-
-fun effectivePlatformsForMembers(nodes: Collection<DocumentationNode>): PlatformsData {
- return nodes.map { effectivePlatformsForNode(it) }.reduce(::mergePlatforms)
-}
-
-fun mergeVersions(kotlinVersions: List<String>): String {
- return kotlinVersions.distinct().min().orEmpty()
-}
-
-fun effectiveSinceKotlinForNode(node: DocumentationNode, baseVersion: String = "1.0"): String {
- val members = when {
- node.kind == NodeKind.GroupNode -> node.origins
- node.kind in NodeKind.classLike -> emptyList()
- node.kind in NodeKind.memberLike -> emptyList()
- else -> node.members
- }
- val newBase = node.sinceKotlin ?: baseVersion
- val memberVersion = if (members.isNotEmpty()) effectiveSinceKotlinForNodes(members, newBase) else newBase
-
- return node.sinceKotlin ?: memberVersion
-}
-
-fun effectiveSinceKotlinForNodes(nodes: Collection<DocumentationNode>, baseVersion: String = "1.0"): String {
- val map = nodes.map { effectiveSinceKotlinForNode(it, baseVersion) }
- return mergeVersions(map)
-}
-
-fun samePlatforms(platformsPerNode: Collection<PlatformsData>): Boolean {
-
- val first = platformsPerNode.firstOrNull()?.keys ?: return true
- return platformsPerNode.all { it.keys == first }
-}
-
-fun locationHref(
- from: Location,
- to: DocumentationNode,
- generator: NodeLocationAwareGenerator,
- pathOnly: Boolean = false
-): String {
- val topLevelPage = to.references(RefKind.TopLevelPage).singleOrNull()?.to
- if (topLevelPage != null) {
- val signature = to.detailOrNull(NodeKind.Signature)
- return from.relativePathTo(
- generator.location(topLevelPage),
- (signature?.name ?: to.name).takeUnless { pathOnly }
- )
- }
- return from.relativePathTo(generator.location(to))
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/YamlOutlineService.kt b/core/src/main/kotlin/Formats/YamlOutlineService.kt
deleted file mode 100644
index 3c92d8ff..00000000
--- a/core/src/main/kotlin/Formats/YamlOutlineService.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import java.io.File
-
-class YamlOutlineService @Inject constructor(
- val generator: NodeLocationAwareGenerator,
- val languageService: LanguageService
-) : OutlineFormatService {
- override fun getOutlineFileName(location: Location): File = File("${location.path}.yml")
-
- var outlineLevel = 0
- override fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) {
- val indent = " ".repeat(outlineLevel)
- to.appendln("$indent- title: ${languageService.renderName(node)}")
- to.appendln("$indent url: ${generator.relativePathToLocation(node.path.first(), node)}")
- }
-
- override fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) {
- val indent = " ".repeat(outlineLevel)
- to.appendln("$indent content:")
- outlineLevel++
- body()
- outlineLevel--
- }
-}
diff --git a/core/src/main/kotlin/Generation/DocumentationMerger.kt b/core/src/main/kotlin/Generation/DocumentationMerger.kt
deleted file mode 100644
index 53dc23a9..00000000
--- a/core/src/main/kotlin/Generation/DocumentationMerger.kt
+++ /dev/null
@@ -1,235 +0,0 @@
-package org.jetbrains.dokka.Generation
-
-import org.jetbrains.dokka.*
-
-class DocumentationMerger(
- private val documentationModules: List<DocumentationModule>,
- val logger: DokkaLogger
-) {
- private val producedNodeRefGraph: NodeReferenceGraph = NodeReferenceGraph()
- private val signatureMap: Map<DocumentationNode, String>
- private val oldToNewNodeMap: MutableMap<DocumentationNode, DocumentationNode> = mutableMapOf()
-
- init {
- if (documentationModules.groupBy { it.name }.size > 1) {
- throw IllegalArgumentException("Modules should have similar names: ${documentationModules.joinToString(", ") {it.name}}")
- }
-
- signatureMap = documentationModules
- .flatMap { it.nodeRefGraph.nodeMapView.entries }
- .associate { (k, v) -> v to k }
-
-
- documentationModules.map { it.nodeRefGraph }
- .flatMap { it.references }
- .forEach { producedNodeRefGraph.addReference(it) }
- }
-
- private fun mergePackageReferences(
- from: DocumentationNode,
- packages: List<DocumentationReference>
- ): List<DocumentationReference> {
- val packagesByName = packages
- .map { it.to }
- .groupBy { it.name }
-
- val resultReferences = mutableListOf<DocumentationReference>()
- for ((name, listOfPackages) in packagesByName) {
- try {
- val producedPackage = mergePackagesWithEqualNames(name, from, listOfPackages)
- updatePendingReferences()
-
- resultReferences.add(
- DocumentationReference(from, producedPackage, RefKind.Member)
- )
- } catch (t: Throwable) {
- val entries = listOfPackages.joinToString(",") { "references:${it.allReferences().size}" }
- throw Error("Failed to merge package $name from $from with entries $entries. ${t.message}", t)
- }
- }
-
- return resultReferences
- }
-
- private fun mergePackagesWithEqualNames(
- name: String,
- from: DocumentationNode,
- packages: List<DocumentationNode>
- ): DocumentationNode {
- val mergedPackage = DocumentationNode(name, Content.Empty, NodeKind.Package)
-
- for (contentToAppend in packages.map { it.content }.distinct()) {
- mergedPackage.updateContent {
- for (otherChild in contentToAppend.children) {
- children.add(otherChild)
- }
- }
- }
-
- for (node in packages) {
- oldToNewNodeMap[node] = mergedPackage
- }
-
- val references = packages.flatMap { it.allReferences() }
- val mergedReferences = mergeReferences(mergedPackage, references)
- for (ref in mergedReferences) {
- if (ref.kind == RefKind.Owner) {
- continue
- }
- mergedPackage.addReference(ref)
- }
-
- from.append(mergedPackage, RefKind.Member)
-
- return mergedPackage
- }
-
- private fun mergeMemberGroupBy(it: DocumentationNode): String {
- val signature = signatureMap[it]
-
- if (signature != null) {
- return signature
- }
-
- logger.error("Failed to find signature for $it in \n${it.allReferences().joinToString { "\n ${it.kind} ${it.to}" }}")
- return "<ERROR>"
- }
-
- private fun mergeMemberReferences(
- from: DocumentationNode,
- refs: List<DocumentationReference>
- ): List<DocumentationReference> {
- val membersBySignature: Map<String, List<DocumentationNode>> = refs.map { it.to }
- .groupBy(this::mergeMemberGroupBy)
-
- val mergedMembers: MutableList<DocumentationReference> = mutableListOf()
- for ((signature, members) in membersBySignature) {
- val newNode = mergeMembersWithEqualSignature(signature, members)
-
- producedNodeRefGraph.register(signature, newNode)
- updatePendingReferences()
- from.append(newNode, RefKind.Member)
-
- mergedMembers.add(DocumentationReference(from, newNode, RefKind.Member))
- }
-
- return mergedMembers
- }
-
- private fun mergeMembersWithEqualSignature(
- signature: String,
- nodes: List<DocumentationNode>
- ): DocumentationNode {
- require(nodes.isNotEmpty())
-
- val singleNode = nodes.singleOrNull()
- if (singleNode != null) {
- singleNode.dropReferences { it.kind == RefKind.Owner }
- return singleNode
- }
-
- // Specialization processing
- // Given (Common, JVM, JRE6, JS) and (JVM, JRE6) and (JVM, JRE7)
- // Sorted: (JVM, JRE6), (JVM, JRE7), (Common, JVM, JRE6, JS)
- // Should output: (JVM, JRE6), (JVM, JRE7), (Common, JS)
- // Should not remove first platform
- val nodesSortedByPlatformCount = nodes.sortedBy { it.platforms.size }
- val allPlatforms = mutableSetOf<String>()
- nodesSortedByPlatformCount.forEach { node ->
- node.platforms
- .filterNot { allPlatforms.add(it) }
- .filter { it != node.platforms.first() }
- .forEach { platform ->
- node.dropReferences { it.kind == RefKind.Platform && it.to.name == platform }
- }
- }
-
- // TODO: Quick and dirty fox for merging extensions for external classes. Fix this probably in StructuredFormatService
- // TODO: while refactoring documentation model
-
- val groupNode = if(nodes.first().kind == NodeKind.ExternalClass){
- DocumentationNode(nodes.first().name, Content.Empty, NodeKind.ExternalClass)
- } else {
- DocumentationNode(nodes.first().name, Content.Empty, NodeKind.GroupNode)
- }
- groupNode.appendTextNode(signature, NodeKind.Signature, RefKind.Detail)
-
- for (node in nodes) {
- node.dropReferences { it.kind == RefKind.Owner }
- groupNode.append(node, RefKind.Origin)
- node.append(groupNode, RefKind.TopLevelPage)
-
- oldToNewNodeMap[node] = groupNode
- }
-
- if (groupNode.kind == NodeKind.ExternalClass){
- val refs = nodes.flatMap { it.allReferences() }.filter { it.kind != RefKind.Owner && it.kind != RefKind.TopLevelPage }
- refs.forEach {
- if (it.kind != RefKind.Link) {
- it.to.dropReferences { ref -> ref.kind == RefKind.Owner }
- it.to.append(groupNode, RefKind.Owner)
- }
- groupNode.append(it.to, it.kind)
- }
- }
-
- // if nodes are classes, nested members should be also merged and
- // inserted at the same level with class
- if (nodes.all { it.kind in NodeKind.classLike }) {
- val members = nodes.flatMap { it.allReferences() }.filter { it.kind == RefKind.Member }
- val mergedMembers = mergeMemberReferences(groupNode, members)
-
- for (ref in mergedMembers) {
- if (ref.kind == RefKind.Owner) {
- continue
- }
-
- groupNode.append(ref.to, RefKind.Member)
- }
- }
-
- return groupNode
- }
-
-
- private fun mergeReferences(
- from: DocumentationNode,
- refs: List<DocumentationReference>
- ): List<DocumentationReference> {
- val (refsToPackages, otherRefs) = refs.partition { it.to.kind == NodeKind.Package }
- val mergedPackages = mergePackageReferences(from, refsToPackages)
-
- val (refsToMembers, refsNotToMembers) = otherRefs.partition { it.kind == RefKind.Member }
- val mergedMembers = mergeMemberReferences(from, refsToMembers)
-
- return mergedPackages + mergedMembers + refsNotToMembers
- }
-
- fun merge(): DocumentationModule {
- val mergedDocumentationModule = DocumentationModule(
- name = documentationModules.first().name,
- content = documentationModules.first().content,
- nodeRefGraph = producedNodeRefGraph
- )
-
- val refs = documentationModules.flatMap {
- it.allReferences()
- }
- mergeReferences(mergedDocumentationModule, refs)
-
- return mergedDocumentationModule
- }
-
- private fun updatePendingReferences() {
- for (ref in producedNodeRefGraph.references) {
- ref.lazyNodeFrom.update()
- ref.lazyNodeTo.update()
- }
- }
-
- private fun NodeResolver.update() {
- if (this is NodeResolver.Exact && exactNode in oldToNewNodeMap) {
- exactNode = oldToNewNodeMap[exactNode]!!
- }
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Generation/DokkaGenerator.kt b/core/src/main/kotlin/Generation/DokkaGenerator.kt
deleted file mode 100644
index 90d7cfcc..00000000
--- a/core/src/main/kotlin/Generation/DokkaGenerator.kt
+++ /dev/null
@@ -1,223 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Guice
-import com.google.inject.Injector
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiJavaFile
-import com.intellij.psi.PsiManager
-import org.jetbrains.dokka.Generation.DocumentationMerger
-import org.jetbrains.dokka.Utilities.DokkaAnalysisModule
-import org.jetbrains.dokka.Utilities.DokkaOutputModule
-import org.jetbrains.dokka.Utilities.DokkaRunModule
-import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
-import org.jetbrains.kotlin.cli.common.messages.MessageCollector
-import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.descriptors.MemberDescriptor
-import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer
-import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
-import org.jetbrains.kotlin.utils.PathUtil
-import java.io.File
-import kotlin.system.measureTimeMillis
-
-class DokkaGenerator(val dokkaConfiguration: DokkaConfiguration,
- val logger: DokkaLogger) {
-
- private val documentationModules: MutableList<DocumentationModule> = mutableListOf()
- private val globalInjector = Guice.createInjector(DokkaRunModule(dokkaConfiguration))
-
-
- fun generate() = with(dokkaConfiguration) {
-
-
- for (pass in passesConfigurations) {
- val documentationModule = DocumentationModule(pass.moduleName)
- appendSourceModule(pass, documentationModule)
- documentationModules.add(documentationModule)
- }
-
- val totalDocumentationModule = DocumentationMerger(documentationModules, logger).merge()
- totalDocumentationModule.prepareForGeneration(dokkaConfiguration)
-
- val timeBuild = measureTimeMillis {
- logger.info("Generating pages... ")
- val outputInjector = globalInjector.createChildInjector(DokkaOutputModule(dokkaConfiguration, logger))
- val instance = outputInjector.getInstance(Generator::class.java)
- instance.buildAll(totalDocumentationModule)
- }
- logger.info("done in ${timeBuild / 1000} secs")
- }
-
- private fun appendSourceModule(
- passConfiguration: DokkaConfiguration.PassConfiguration,
- documentationModule: DocumentationModule
- ) = with(passConfiguration) {
-
- val sourcePaths = passConfiguration.sourceRoots.map { it.path }
- val environment = createAnalysisEnvironment(sourcePaths, passConfiguration)
-
- logger.info("Module: $moduleName")
- logger.info("Output: ${File(dokkaConfiguration.outputDir)}")
- logger.info("Sources: ${sourcePaths.joinToString()}")
- logger.info("Classpath: ${environment.classpath.joinToString()}")
-
- logger.info("Analysing sources and libraries... ")
- val startAnalyse = System.currentTimeMillis()
-
- val defaultPlatformAsList = passConfiguration.targets
- val defaultPlatformsProvider = object : DefaultPlatformsProvider {
- override fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String> {
-// val containingFilePath = descriptor.sourcePsi()?.containingFile?.virtualFile?.canonicalPath
-// ?.let { File(it).absolutePath }
-// val sourceRoot = containingFilePath?.let { path -> sourceRoots.find { path.startsWith(it.path) } }
- if (descriptor is MemberDescriptor && descriptor.isExpect) {
- return defaultPlatformAsList.take(1)
- }
- return /*sourceRoot?.platforms ?: */defaultPlatformAsList
- }
- }
-
- val injector = globalInjector.createChildInjector(
- DokkaAnalysisModule(environment, dokkaConfiguration, defaultPlatformsProvider, documentationModule.nodeRefGraph, passConfiguration, logger))
-
- buildDocumentationModule(injector, documentationModule, { isNotSample(it, passConfiguration.samples) }, includes)
-
- val timeAnalyse = System.currentTimeMillis() - startAnalyse
- logger.info("done in ${timeAnalyse / 1000} secs")
-
- Disposer.dispose(environment)
- }
-
- fun createAnalysisEnvironment(
- sourcePaths: List<String>,
- passConfiguration: DokkaConfiguration.PassConfiguration
- ): AnalysisEnvironment {
- val environment = AnalysisEnvironment(DokkaMessageCollector(logger), passConfiguration.analysisPlatform)
-
- environment.apply {
- if (analysisPlatform == Platform.jvm) {
- addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
- }
- // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath())
- for (element in passConfiguration.classpath) {
- addClasspath(File(element))
- }
-
- addSources(sourcePaths)
- addSources(passConfiguration.samples)
-
- loadLanguageVersionSettings(passConfiguration.languageVersion, passConfiguration.apiVersion)
- }
-
- return environment
- }
-
- private fun isNotSample(file: PsiFile, samples: List<String>): Boolean {
- val sourceFile = File(file.virtualFile!!.path)
- return samples.none { sample ->
- val canonicalSample = File(sample).canonicalPath
- val canonicalSource = sourceFile.canonicalPath
- canonicalSource.startsWith(canonicalSample)
- }
- }
-}
-
-class DokkaMessageCollector(val logger: DokkaLogger) : MessageCollector {
- override fun clear() {
- seenErrors = false
- }
-
- private var seenErrors = false
-
- override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
- if (severity == CompilerMessageSeverity.ERROR) {
- seenErrors = true
- }
- logger.error(MessageRenderer.PLAIN_FULL_PATHS.render(severity, message, location))
- }
-
- override fun hasErrors() = seenErrors
-}
-
-fun buildDocumentationModule(injector: Injector,
- documentationModule: DocumentationModule,
- filesToDocumentFilter: (PsiFile) -> Boolean = { file -> true },
- includes: List<String> = listOf()) {
-
- val coreEnvironment = injector.getInstance(KotlinCoreEnvironment::class.java)
- val fragmentFiles = coreEnvironment.getSourceFiles().filter(filesToDocumentFilter)
-
- val resolutionFacade = injector.getInstance(DokkaResolutionFacade::class.java)
- val analyzer = resolutionFacade.getFrontendService(LazyTopDownAnalyzer::class.java)
- analyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, fragmentFiles)
-
- val fragments = fragmentFiles.mapNotNull { resolutionFacade.resolveSession.getPackageFragment(it.packageFqName) }
- .distinct()
-
- val packageDocs = injector.getInstance(PackageDocs::class.java)
- for (include in includes) {
- packageDocs.parse(include, fragments)
- }
- if (documentationModule.content.isEmpty()) {
- documentationModule.updateContent {
- for (node in packageDocs.moduleContent.children) {
- append(node)
- }
- }
- }
-
- parseJavaPackageDocs(packageDocs, coreEnvironment)
-
- with(injector.getInstance(DocumentationBuilder::class.java)) {
- documentationModule.appendFragments(fragments, packageDocs.packageContent,
- injector.getInstance(PackageDocumentationBuilder::class.java))
-
- propagateExtensionFunctionsToSubclasses(fragments, resolutionFacade)
- }
-
- val javaFiles = coreEnvironment.getJavaSourceFiles().filter(filesToDocumentFilter)
- with(injector.getInstance(JavaDocumentationBuilder::class.java)) {
- javaFiles.map { appendFile(it, documentationModule, packageDocs.packageContent) }
- }
-}
-
-fun parseJavaPackageDocs(packageDocs: PackageDocs, coreEnvironment: KotlinCoreEnvironment) {
- val contentRoots = coreEnvironment.configuration.get(CLIConfigurationKeys.CONTENT_ROOTS)
- ?.filterIsInstance<JavaSourceRoot>()
- ?.map { it.file }
- ?: listOf()
- contentRoots.forEach { root ->
- root.walkTopDown().filter { it.name == "overview.html" }.forEach {
- packageDocs.parseJava(it.path, it.relativeTo(root).parent.replace("/", "."))
- }
- }
-}
-
-
-fun KotlinCoreEnvironment.getJavaSourceFiles(): List<PsiJavaFile> {
- val sourceRoots = configuration.get(CLIConfigurationKeys.CONTENT_ROOTS)
- ?.filterIsInstance<JavaSourceRoot>()
- ?.map { it.file }
- ?: listOf()
-
- val result = arrayListOf<PsiJavaFile>()
- val localFileSystem = VirtualFileManager.getInstance().getFileSystem("file")
- sourceRoots.forEach { sourceRoot ->
- sourceRoot.absoluteFile.walkTopDown().forEach {
- val vFile = localFileSystem.findFileByPath(it.path)
- if (vFile != null) {
- val psiFile = PsiManager.getInstance(project).findFile(vFile)
- if (psiFile is PsiJavaFile) {
- result.add(psiFile)
- }
- }
- }
- }
- return result
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Generation/FileGenerator.kt b/core/src/main/kotlin/Generation/FileGenerator.kt
deleted file mode 100644
index ee2c068e..00000000
--- a/core/src/main/kotlin/Generation/FileGenerator.kt
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import java.io.File
-import java.io.IOException
-import java.io.PrintWriter
-import java.io.StringWriter
-
-class FileGenerator @Inject constructor(@Named("outputDir") override val root: File) : NodeLocationAwareGenerator {
-
- @set:Inject(optional = true) var outlineService: OutlineFormatService? = null
- @set:Inject(optional = true) lateinit var formatService: FormatService
- @set:Inject(optional = true) lateinit var dokkaConfiguration: DokkaConfiguration
- @set:Inject(optional = true) var packageListService: PackageListService? = null
-
- private val createdFiles = mutableMapOf<File, List<String>>()
-
- private fun File.writeFileAndAssert(context: String, action: (File) -> Unit) {
- //TODO: there is a possible refactoring to drop FileLocation
- //TODO: aad File from API, Location#path.
- //TODO: turn [Location] into a final class,
- //TODO: Use [Location] all over the place without full
- //TODO: reference to the real target path,
- //TODO: it opens the way to safely track all files created
- //TODO: to make sure no files were overwritten by mistake
- //TODO: also, the NodeLocationAwareGenerator should be removed
-
- val writes = createdFiles.getOrDefault(this, listOf()) + context
- createdFiles[this] = writes
- if (writes.size > 1) {
- println("ERROR. An attempt to write ${this.relativeTo(root)} several times!")
- return
- }
-
- try {
- parentFile?.mkdirsOrFail()
- action(this)
- } catch (e : Throwable) {
- println("Failed to write $this. ${e.message}")
- e.printStackTrace()
- }
- }
-
- private fun File.mkdirsOrFail() {
- if (!mkdirs() && !exists()) {
- throw IOException("Failed to create directory $this")
- }
- }
-
- override fun location(node: DocumentationNode): FileLocation {
- return FileLocation(fileForNode(node, formatService.linkExtension))
- }
-
- private fun fileForNode(node: DocumentationNode, extension: String = ""): File {
- return File(root, relativePathToNode(node)).appendExtension(extension)
- }
-
- private fun locationWithoutExtension(node: DocumentationNode): FileLocation {
- return FileLocation(fileForNode(node))
- }
-
- override fun buildPages(nodes: Iterable<DocumentationNode>) {
-
- for ((file, items) in nodes.groupBy { fileForNode(it, formatService.extension) }) {
- file.writeFileAndAssert("pages") { it ->
- it.writeText(formatService.format(location(items.first()), items))
- }
-
- buildPages(items.filterNot { it.kind == NodeKind.AllTypes }.flatMap { it.members })
- }
- }
-
- override fun buildOutlines(nodes: Iterable<DocumentationNode>) {
- val outlineService = this.outlineService ?: return
- for ((location, items) in nodes.groupBy { locationWithoutExtension(it) }) {
- outlineService.getOutlineFileName(location).writeFileAndAssert("outlines") { file ->
- file.writeText(outlineService.formatOutline(location, items))
- }
- }
- }
-
- override fun buildSupportFiles() {
- formatService.enumerateSupportFiles { resource, targetPath ->
- File(root, relativePathToNode(listOf(targetPath), false)).writeFileAndAssert("support files") { file ->
- file.outputStream().use {
- javaClass.getResourceAsStream(resource).copyTo(it)
- }
- }
- }
- }
-
- override fun buildPackageList(nodes: Iterable<DocumentationNode>) {
- if (packageListService == null) return
-
- for (module in nodes) {
-
- val moduleRoot = location(module).file.parentFile
- val packageListFile = File(moduleRoot, "package-list")
-
- val text = "\$dokka.format:${dokkaConfiguration.format}\n" + packageListService!!.formatPackageList(module as DocumentationModule)
-
- packageListFile.writeFileAndAssert("packages-list") { file ->
- file.writeText(text)
- }
- }
- }
-}
diff --git a/core/src/main/kotlin/Generation/Generator.kt b/core/src/main/kotlin/Generation/Generator.kt
deleted file mode 100644
index 23286e29..00000000
--- a/core/src/main/kotlin/Generation/Generator.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.jetbrains.dokka
-
-import java.io.File
-
-interface Generator {
- fun buildPages(nodes: Iterable<DocumentationNode>)
- fun buildOutlines(nodes: Iterable<DocumentationNode>)
- fun buildSupportFiles()
- fun buildPackageList(nodes: Iterable<DocumentationNode>)
-}
-
-fun Generator.buildAll(nodes: Iterable<DocumentationNode>) {
- buildPages(nodes)
- buildOutlines(nodes)
- buildSupportFiles()
- buildPackageList(nodes)
-}
-
-fun Generator.buildPage(node: DocumentationNode): Unit = buildPages(listOf(node))
-
-fun Generator.buildOutline(node: DocumentationNode): Unit = buildOutlines(listOf(node))
-
-fun Generator.buildAll(node: DocumentationNode): Unit = buildAll(listOf(node))
-
-
-interface NodeLocationAwareGenerator: Generator {
- fun location(node: DocumentationNode): Location
- val root: File
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
deleted file mode 100644
index d6743e60..00000000
--- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
+++ /dev/null
@@ -1,361 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.openapi.util.text.StringUtil
-import com.intellij.psi.*
-import com.intellij.psi.impl.JavaConstantExpressionEvaluator
-import com.intellij.psi.util.InheritanceUtil
-import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation
-import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
-import org.jetbrains.kotlin.asJava.elements.KtLightElement
-import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import org.jetbrains.kotlin.lexer.KtTokens
-import org.jetbrains.kotlin.psi.KtDeclaration
-import org.jetbrains.kotlin.psi.KtModifierListOwner
-
-fun getSignature(element: PsiElement?) = when(element) {
- is PsiPackage -> element.qualifiedName
- is PsiClass -> element.qualifiedName
- is PsiField -> element.containingClass!!.qualifiedName + "$" + element.name
- is PsiMethod ->
- methodSignature(element)
- is PsiParameter -> {
- val method = (element.parent.parent as PsiMethod)
- methodSignature(method)
- }
- else -> null
-}
-
-private fun methodSignature(method: PsiMethod): String {
- return method.containingClass?.qualifiedName + "$" + method.name + "(" +
- method.parameterList.parameters.map { it.type.typeSignature() }.joinToString(",") + ")"
-}
-
-private fun PsiType.typeSignature(): String = when(this) {
- is PsiArrayType -> "Array((${componentType.typeSignature()}))"
- is PsiPrimitiveType -> "kotlin." + canonicalText.capitalize()
- else -> mapTypeName(this)
-}
-
-private fun mapTypeName(psiType: PsiType): String = when (psiType) {
- is PsiPrimitiveType -> psiType.canonicalText
- is PsiClassType -> psiType.resolve()?.qualifiedName ?: psiType.className
- is PsiEllipsisType -> mapTypeName(psiType.componentType)
- is PsiArrayType -> "kotlin.Array"
- else -> psiType.canonicalText
-}
-
-interface JavaDocumentationBuilder {
- fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>)
-}
-
-class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
- private val passConfiguration: DokkaConfiguration.PassConfiguration
- private val refGraph: NodeReferenceGraph
- private val docParser: JavaDocumentationParser
-
- @Inject constructor(
- passConfiguration: DokkaConfiguration.PassConfiguration,
- refGraph: NodeReferenceGraph,
- logger: DokkaLogger,
- signatureProvider: ElementSignatureProvider,
- externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
- ) {
- this.passConfiguration = passConfiguration
- this.refGraph = refGraph
- this.docParser = JavadocParser(refGraph, logger, signatureProvider, externalDocumentationLinkResolver)
- }
-
- constructor(passConfiguration: DokkaConfiguration.PassConfiguration, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) {
- this.passConfiguration = passConfiguration
- this.refGraph = refGraph
- this.docParser = docParser
- }
-
- override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
- if (skipFile(file) || file.classes.all { skipElement(it) }) {
- return
- }
- val packageNode = findOrCreatePackageNode(module, file.packageName, emptyMap(), refGraph)
- appendClasses(packageNode, file.classes)
- }
-
- fun appendClasses(packageNode: DocumentationNode, classes: Array<PsiClass>) {
- packageNode.appendChildren(classes) { build() }
- }
-
- fun register(element: PsiElement, node: DocumentationNode) {
- val signature = getSignature(element)
- if (signature != null) {
- refGraph.register(signature, node)
- }
- }
-
- fun link(node: DocumentationNode, element: PsiElement?) {
- val qualifiedName = getSignature(element)
- if (qualifiedName != null) {
- refGraph.link(node, qualifiedName, RefKind.Link)
- }
- }
-
- fun link(element: PsiElement?, node: DocumentationNode, kind: RefKind) {
- val qualifiedName = getSignature(element)
- if (qualifiedName != null) {
- refGraph.link(qualifiedName, node, kind)
- }
- }
-
- fun nodeForElement(element: PsiNamedElement,
- kind: NodeKind,
- name: String = element.name ?: "<anonymous>",
- register: Boolean = false): DocumentationNode {
- val (docComment, deprecatedContent) = docParser.parseDocumentation(element)
- val node = DocumentationNode(name, docComment, kind)
- if (register) register(element, node)
- if (element is PsiModifierListOwner) {
- node.appendModifiers(element)
- val modifierList = element.modifierList
- if (modifierList != null) {
- modifierList.annotations.filter { !ignoreAnnotation(it) }.forEach {
- val annotation = it.build()
- node.append(annotation,
- if (it.qualifiedName == "java.lang.Deprecated") RefKind.Deprecation else RefKind.Annotation)
- }
- }
- }
- if (deprecatedContent != null) {
- val deprecationNode = DocumentationNode("", deprecatedContent, NodeKind.Modifier)
- node.append(deprecationNode, RefKind.Deprecation)
- }
- if (element is PsiDocCommentOwner && element.isDeprecated && node.deprecation == null) {
- val deprecationNode = DocumentationNode("", Content.of(ContentText("Deprecated")), NodeKind.Modifier)
- node.append(deprecationNode, RefKind.Deprecation)
- }
- return node
- }
-
- fun ignoreAnnotation(annotation: PsiAnnotation) = when(annotation.qualifiedName) {
- "java.lang.SuppressWarnings" -> true
- else -> false
- }
-
- fun <T : Any> DocumentationNode.appendChildren(elements: Array<T>,
- kind: RefKind = RefKind.Member,
- buildFn: T.() -> DocumentationNode) {
- elements.forEach {
- if (!skipElement(it)) {
- append(it.buildFn(), kind)
- }
- }
- }
-
- private fun skipFile(javaFile: PsiJavaFile): Boolean = passConfiguration.effectivePackageOptions(javaFile.packageName).suppress
-
- private fun skipElement(element: Any) =
- skipElementByVisibility(element) ||
- hasSuppressDocTag(element) ||
- skipElementBySuppressedFiles(element)
-
- private fun skipElementByVisibility(element: Any): Boolean =
- element is PsiModifierListOwner &&
- element !is PsiParameter &&
- !(passConfiguration.effectivePackageOptions((element.containingFile as? PsiJavaFile)?.packageName ?: "").includeNonPublic) &&
- (element.hasModifierProperty(PsiModifier.PRIVATE) ||
- element.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) ||
- element.isInternal())
-
- private fun skipElementBySuppressedFiles(element: Any): Boolean =
- element is PsiElement && element.containingFile.virtualFile?.path in passConfiguration.suppressedFiles
-
- private fun PsiElement.isInternal(): Boolean {
- val ktElement = (this as? KtLightElement<*, *>)?.kotlinOrigin ?: return false
- return (ktElement as? KtModifierListOwner)?.hasModifier(KtTokens.INTERNAL_KEYWORD) ?: false
- }
-
- fun <T : Any> DocumentationNode.appendMembers(elements: Array<T>, buildFn: T.() -> DocumentationNode) =
- appendChildren(elements, RefKind.Member, buildFn)
-
- fun <T : Any> DocumentationNode.appendDetails(elements: Array<T>, buildFn: T.() -> DocumentationNode) =
- appendChildren(elements, RefKind.Detail, buildFn)
-
- fun PsiClass.build(): DocumentationNode {
- val kind = when {
- isAnnotationType -> NodeKind.AnnotationClass
- isInterface -> NodeKind.Interface
- isEnum -> NodeKind.Enum
- isException() -> NodeKind.Exception
- else -> NodeKind.Class
- }
- val node = nodeForElement(this, kind, register = isAnnotationType)
- superTypes.filter { !ignoreSupertype(it) }.forEach {
- node.appendType(it, NodeKind.Supertype)
- val superClass = it.resolve()
- if (superClass != null) {
- link(superClass, node, RefKind.Inheritor)
- }
- }
-
- var methodsAndConstructors = methods
- if (constructors.isEmpty()) {
- // Having no constructor represents a class that only has an implicit/default constructor
- // so we create one synthetically for documentation
- val factory = JavaPsiFacade.getElementFactory(this.project)
- methodsAndConstructors += factory.createMethodFromText("public $name() {}", this)
- }
- node.appendDetails(typeParameters) { build() }
- node.appendMembers(methodsAndConstructors) { build() }
- node.appendMembers(fields) { build() }
- node.appendMembers(innerClasses) { build() }
- register(this, node)
- return node
- }
-
- fun PsiClass.isException() = InheritanceUtil.isInheritor(this, "java.lang.Throwable")
-
- fun ignoreSupertype(psiType: PsiClassType): Boolean =
- psiType.isClass("java.lang.Enum") || psiType.isClass("java.lang.Object")
-
- fun PsiClassType.isClass(qName: String): Boolean {
- val shortName = qName.substringAfterLast('.')
- if (className == shortName) {
- val psiClass = resolve()
- return psiClass?.qualifiedName == qName
- }
- return false
- }
-
- fun PsiField.build(): DocumentationNode {
- val node = nodeForElement(this, nodeKind())
- node.appendType(type)
-
- node.appendConstantValueIfAny(this)
- register(this, node)
- return node
- }
-
- private fun DocumentationNode.appendConstantValueIfAny(field: PsiField) {
- val modifierList = field.modifierList ?: return
- val initializer = field.initializer ?: return
- if (modifierList.hasExplicitModifier(PsiModifier.FINAL) &&
- modifierList.hasExplicitModifier(PsiModifier.STATIC)) {
- val value = JavaConstantExpressionEvaluator.computeConstantExpression(initializer, false)
- val text = when(value) {
- null -> return // No value found
- is String ->
- "\"" + StringUtil.escapeStringCharacters(value) + "\""
- else -> value.toString()
- }
- append(DocumentationNode(text, Content.Empty, NodeKind.Value), RefKind.Detail)
- }
- }
-
- private fun PsiField.nodeKind(): NodeKind = when {
- this is PsiEnumConstant -> NodeKind.EnumItem
- else -> NodeKind.Field
- }
-
- fun PsiMethod.build(): DocumentationNode {
- val node = nodeForElement(this, nodeKind(),
- if (isConstructor) "<init>" else name)
-
- if (!isConstructor) {
- node.appendType(returnType)
- }
- node.appendDetails(parameterList.parameters) { build() }
- node.appendDetails(typeParameters) { build() }
- register(this, node)
- return node
- }
-
- private fun PsiMethod.nodeKind(): NodeKind = when {
- isConstructor -> NodeKind.Constructor
- else -> NodeKind.Function
- }
-
- fun PsiParameter.build(): DocumentationNode {
- val node = nodeForElement(this, NodeKind.Parameter)
- node.appendType(type)
- if (type is PsiEllipsisType) {
- node.appendTextNode("vararg", NodeKind.Modifier, RefKind.Detail)
- }
- return node
- }
-
- fun PsiTypeParameter.build(): DocumentationNode {
- val node = nodeForElement(this, NodeKind.TypeParameter)
- extendsListTypes.forEach { node.appendType(it, NodeKind.UpperBound) }
- implementsListTypes.forEach { node.appendType(it, NodeKind.UpperBound) }
- return node
- }
-
- fun DocumentationNode.appendModifiers(element: PsiModifierListOwner) {
- val modifierList = element.modifierList ?: return
-
- PsiModifier.MODIFIERS.forEach {
- if (modifierList.hasExplicitModifier(it)) {
- appendTextNode(it, NodeKind.Modifier)
- }
- }
- }
-
- fun DocumentationNode.appendType(psiType: PsiType?, kind: NodeKind = NodeKind.Type) {
- if (psiType == null) {
- return
- }
- append(psiType.build(kind), RefKind.Detail)
- }
-
- fun PsiType.build(kind: NodeKind = NodeKind.Type): DocumentationNode {
- val name = mapTypeName(this)
- val node = DocumentationNode(name, Content.Empty, kind)
- if (this is PsiClassType) {
- node.appendDetails(parameters) { build(NodeKind.Type) }
- link(node, resolve())
- }
- if (this is PsiArrayType && this !is PsiEllipsisType) {
- node.append(componentType.build(NodeKind.Type), RefKind.Detail)
- }
- return node
- }
-
- private fun lookupOrBuildClass(psiClass: PsiClass): DocumentationNode {
- val existing = refGraph.lookup(getSignature(psiClass)!!)
- if (existing != null) return existing
- val new = psiClass.build()
- val packageNode = findOrCreatePackageNode(null, (psiClass.containingFile as PsiJavaFile).packageName, emptyMap(), refGraph)
- packageNode.append(new, RefKind.Member)
- return new
- }
-
- fun PsiAnnotation.build(): DocumentationNode {
-
- val original = when (this) {
- is KtLightAbstractAnnotation -> clsDelegate
- else -> this
- }
- val node = DocumentationNode(qualifiedName?.substringAfterLast(".") ?: "<?>", Content.Empty, NodeKind.Annotation)
- val psiClass = original.nameReferenceElement?.resolve() as? PsiClass
- if (psiClass != null && psiClass.isAnnotationType) {
- node.append(lookupOrBuildClass(psiClass), RefKind.Link)
- }
- parameterList.attributes.forEach {
- val parameter = DocumentationNode(it.name ?: "value", Content.Empty, NodeKind.Parameter)
- val value = it.value
- if (value != null) {
- val valueText = (value as? PsiLiteralExpression)?.value as? String ?: value.text
- val valueNode = DocumentationNode(valueText, Content.Empty, NodeKind.Value)
- parameter.append(valueNode, RefKind.Detail)
- }
- node.append(parameter, RefKind.Detail)
- }
- return node
- }
-}
-
-fun hasSuppressDocTag(element: Any?): Boolean {
- val declaration = (element as? KtLightDeclaration<*, *>)?.kotlinOrigin ?: return false
- return PsiTreeUtil.findChildrenOfType(declaration.docComment, KDocTag::class.java).any { it.knownTag == KDocKnownTag.SUPPRESS }
-}
-
diff --git a/core/src/main/kotlin/Java/JavadocParser.kt b/core/src/main/kotlin/Java/JavadocParser.kt
deleted file mode 100644
index 318bad28..00000000
--- a/core/src/main/kotlin/Java/JavadocParser.kt
+++ /dev/null
@@ -1,401 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.*
-import com.intellij.psi.impl.source.tree.JavaDocElementType
-import com.intellij.psi.javadoc.*
-import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.kotlin.utils.keysToMap
-import org.jsoup.Jsoup
-import org.jsoup.nodes.Element
-import org.jsoup.nodes.Node
-import org.jsoup.nodes.TextNode
-import java.net.URI
-
-data class JavadocParseResult(val content: Content, val deprecatedContent: Content?) {
- companion object {
- val Empty = JavadocParseResult(Content.Empty, null)
- }
-}
-
-interface JavaDocumentationParser {
- fun parseDocumentation(element: PsiNamedElement): JavadocParseResult
-}
-
-class JavadocParser(
- private val refGraph: NodeReferenceGraph,
- private val logger: DokkaLogger,
- private val signatureProvider: ElementSignatureProvider,
- private val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
-) : JavaDocumentationParser {
-
- private fun ContentSection.appendTypeElement(signature: String, selector: (DocumentationNode) -> DocumentationNode?) {
- append(LazyContentBlock {
- val node = refGraph.lookupOrWarn(signature, logger)?.let(selector) ?: return@LazyContentBlock emptyList()
- listOf(ContentBlock().apply {
- append(NodeRenderContent(node, LanguageService.RenderMode.SUMMARY))
- symbol(":")
- text(" ")
- })
- })
- }
-
- override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
- val docComment = (element as? PsiDocCommentOwner)?.docComment ?: return JavadocParseResult.Empty
- val result = MutableContent()
- var deprecatedContent: Content? = null
-
- val nodes = convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() }, element)
- val firstParagraphContents = nodes.takeWhile { it !is ContentParagraph }
- val firstParagraph = ContentParagraph()
- if (firstParagraphContents.isNotEmpty()) {
- firstParagraphContents.forEach { firstParagraph.append(it) }
- result.append(firstParagraph)
- }
-
- result.appendAll(nodes.drop(firstParagraphContents.size))
-
- if (element is PsiMethod) {
- val tagsByName = element.searchInheritedTags()
- for ((tagName, tags) in tagsByName) {
- for ((tag, context) in tags) {
- val section = result.addSection(javadocSectionDisplayName(tagName), tag.getSubjectName())
- val signature = signatureProvider.signature(element)
- when (tagName) {
- "param" -> {
- section.appendTypeElement(signature) {
- it.details
- .find { node -> node.kind == NodeKind.Parameter && node.name == tag.getSubjectName() }
- ?.detailOrNull(NodeKind.Type)
- }
- }
- "return" -> {
- section.appendTypeElement(signature) { it.detailOrNull(NodeKind.Type) }
- }
- }
- section.appendAll(convertJavadocElements(tag.contentElements(), context))
- }
- }
- }
-
- docComment.tags.forEach { tag ->
- when (tag.name) {
- "see" -> result.convertSeeTag(tag)
- "deprecated" -> {
- deprecatedContent = Content().apply {
- appendAll(convertJavadocElements(tag.contentElements(), element))
- }
- }
- in tagsToInherit -> {}
- else -> {
- val subjectName = tag.getSubjectName()
- val section = result.addSection(javadocSectionDisplayName(tag.name), subjectName)
-
- section.appendAll(convertJavadocElements(tag.contentElements(), element))
- }
- }
- }
- return JavadocParseResult(result, deprecatedContent)
- }
-
- private val tagsToInherit = setOf("param", "return", "throws")
-
- private data class TagWithContext(val tag: PsiDocTag, val context: PsiNamedElement)
-
- private fun PsiMethod.searchInheritedTags(): Map<String, Collection<TagWithContext>> {
-
- val output = tagsToInherit.keysToMap { mutableMapOf<String?, TagWithContext>() }
-
- fun recursiveSearch(methods: Array<PsiMethod>) {
- for (method in methods) {
- recursiveSearch(method.findSuperMethods())
- }
- for (method in methods) {
- for (tag in method.docComment?.tags.orEmpty()) {
- if (tag.name in tagsToInherit) {
- output[tag.name]!![tag.getSubjectName()] = TagWithContext(tag, method)
- }
- }
- }
- }
-
- recursiveSearch(arrayOf(this))
- return output.mapValues { it.value.values }
- }
-
-
- private fun PsiDocTag.contentElements(): Iterable<PsiElement> {
- val tagValueElements = children
- .dropWhile { it.node?.elementType == JavaDocTokenType.DOC_TAG_NAME }
- .dropWhile { it is PsiWhiteSpace }
- .filterNot { it.node?.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS }
- return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements
- }
-
- private fun convertJavadocElements(elements: Iterable<PsiElement>, element: PsiNamedElement): List<ContentNode> {
- val doc = Jsoup.parse(expandAllForElements(elements, element))
- return doc.body().childNodes().mapNotNull {
- convertHtmlNode(it)
- }
- }
-
- private fun ContentBlock.appendAll(nodes: List<ContentNode>) {
- nodes.forEach { append(it) }
- }
-
- private fun expandAllForElements(elements: Iterable<PsiElement>, element: PsiNamedElement): String {
- val htmlBuilder = StringBuilder()
- elements.forEach {
- if (it is PsiInlineDocTag) {
- htmlBuilder.append(convertInlineDocTag(it, element))
- } else {
- htmlBuilder.append(it.text)
- }
- }
- return htmlBuilder.toString().trim()
- }
-
- private fun convertHtmlNode(node: Node, insidePre: Boolean = false): ContentNode? {
- if (node is TextNode) {
- val text = if (insidePre) node.wholeText else node.text()
- return ContentText(text)
- } else if (node is Element) {
- val childBlock = createBlock(node, insidePre)
-
- node.childNodes().forEach {
- val child = convertHtmlNode(it, insidePre || childBlock is ContentBlockCode)
- if (child != null) {
- childBlock.append(child)
- }
- }
- return childBlock
- }
- return null
- }
-
- private fun createBlock(element: Element, insidePre: Boolean): ContentBlock = when (element.tagName()) {
- "p" -> ContentParagraph()
- "b", "strong" -> ContentStrong()
- "i", "em" -> ContentEmphasis()
- "s", "del" -> ContentStrikethrough()
- "code" -> if (insidePre) ContentBlock() else ContentCode()
- "pre" -> ContentBlockCode()
- "ul" -> ContentUnorderedList()
- "ol" -> ContentOrderedList()
- "li" -> ContentListItem()
- "a" -> createLink(element)
- "br" -> ContentBlock().apply { hardLineBreak() }
- else -> ContentBlock()
- }
-
- private fun createLink(element: Element): ContentBlock {
- return when {
- element.hasAttr("docref") -> {
- val docref = element.attr("docref")
- ContentNodeLazyLink(docref) { refGraph.lookupOrWarn(docref, logger)}
- }
- element.hasAttr("href") -> {
- val href = element.attr("href")
-
- val uri = try {
- URI(href)
- } catch (_: Exception) {
- null
- }
-
- if (uri?.isAbsolute == false) {
- ContentLocalLink(href)
- } else {
- ContentExternalLink(href)
- }
- }
- element.hasAttr("name") -> {
- ContentBookmark(element.attr("name"))
- }
- else -> ContentBlock()
- }
- }
-
- private fun MutableContent.convertSeeTag(tag: PsiDocTag) {
- val linkElement = tag.linkElement() ?: return
- val seeSection = findSectionByTag(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null)
-
- val valueElement = tag.referenceElement()
- val externalLink = resolveExternalLink(valueElement)
- val text = ContentText(linkElement.text)
-
- val linkSignature by lazy { resolveInternalLink(valueElement) }
- val node = when {
- externalLink != null -> {
- val linkNode = ContentExternalLink(externalLink)
- linkNode.append(text)
- linkNode
- }
- linkSignature != null -> {
- val linkNode =
- ContentNodeLazyLink(
- (tag.valueElement ?: linkElement).text
- ) { refGraph.lookupOrWarn(linkSignature!!, logger) }
- linkNode.append(text)
- linkNode
- }
- else -> text
- }
- seeSection.append(node)
- }
-
- private fun convertInlineDocTag(tag: PsiInlineDocTag, element: PsiNamedElement) = when (tag.name) {
- "link", "linkplain" -> {
- val valueElement = tag.referenceElement()
- val externalLink = resolveExternalLink(valueElement)
- val linkSignature by lazy { resolveInternalLink(valueElement) }
- if (externalLink != null || linkSignature != null) {
- val labelText = tag.dataElements.firstOrNull { it is PsiDocToken }?.text ?: valueElement!!.text
- val linkTarget = if (externalLink != null) "href=\"$externalLink\"" else "docref=\"$linkSignature\""
- val link = "<a $linkTarget>${labelText.htmlEscape()}</a>"
- if (tag.name == "link") "<code>$link</code>" else link
- } else if (valueElement != null) {
- valueElement.text
- } else {
- ""
- }
- }
- "code", "literal" -> {
- val text = StringBuilder()
- tag.dataElements.forEach { text.append(it.text) }
- val escaped = text.toString().trimStart().htmlEscape()
- if (tag.name == "code") "<code>$escaped</code>" else escaped
- }
- "inheritDoc" -> {
- val result = (element as? PsiMethod)?.let {
- // @{inheritDoc} is only allowed on functions
- val parent = tag.parent
- when (parent) {
- is PsiDocComment -> element.findSuperDocCommentOrWarn()
- is PsiDocTag -> element.findSuperDocTagOrWarn(parent)
- else -> null
- }
- }
- result ?: tag.text
- }
- else -> tag.text
- }
-
- private fun PsiDocTag.referenceElement(): PsiElement? =
- linkElement()?.let {
- if (it.node.elementType == JavaDocElementType.DOC_REFERENCE_HOLDER) {
- PsiTreeUtil.findChildOfType(it, PsiJavaCodeReferenceElement::class.java)
- } else {
- it
- }
- }
-
- private fun PsiDocTag.linkElement(): PsiElement? =
- valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
-
- private fun resolveExternalLink(valueElement: PsiElement?): String? {
- val target = valueElement?.reference?.resolve()
- if (target != null) {
- return externalDocumentationLinkResolver.buildExternalDocumentationLink(target)
- }
- return null
- }
-
- private fun resolveInternalLink(valueElement: PsiElement?): String? {
- val target = valueElement?.reference?.resolve()
- if (target != null) {
- return signatureProvider.signature(target)
- }
- return null
- }
-
- fun PsiDocTag.getSubjectName(): String? {
- if (name == "param" || name == "throws" || name == "exception") {
- return valueElement?.text
- }
- return null
- }
-
- private fun PsiMethod.findSuperDocCommentOrWarn(): String {
- val method = findFirstSuperMethodWithDocumentation(this)
- if (method != null) {
- val descriptionElements = method.docComment?.descriptionElements?.dropWhile {
- it.text.trim().isEmpty()
- } ?: return ""
-
- return expandAllForElements(descriptionElements, method)
- }
- logger.warn("No docs found on supertype with {@inheritDoc} method ${this.name} in ${this.containingFile.name}:${this.lineNumber()}")
- return ""
- }
-
-
- private fun PsiMethod.findSuperDocTagOrWarn(elementToExpand: PsiDocTag): String {
- val result = findFirstSuperMethodWithDocumentationforTag(elementToExpand, this)
-
- if (result != null) {
- val (method, tag) = result
-
- val contentElements = tag.contentElements().dropWhile { it.text.trim().isEmpty() }
-
- val expandedString = expandAllForElements(contentElements, method)
-
- return expandedString
- }
- logger.warn("No docs found on supertype for @${elementToExpand.name} ${elementToExpand.getSubjectName()} with {@inheritDoc} method ${this.name} in ${this.containingFile.name}:${this.lineNumber()}")
- return ""
- }
-
- private fun findFirstSuperMethodWithDocumentation(current: PsiMethod): PsiMethod? {
- val superMethods = current.findSuperMethods()
- for (method in superMethods) {
- val docs = method.docComment?.descriptionElements?.dropWhile { it.text.trim().isEmpty() }
- if (!docs.isNullOrEmpty()) {
- return method
- }
- }
- for (method in superMethods) {
- val result = findFirstSuperMethodWithDocumentation(method)
- if (result != null) {
- return result
- }
- }
-
- return null
- }
-
- private fun findFirstSuperMethodWithDocumentationforTag(elementToExpand: PsiDocTag, current: PsiMethod): Pair<PsiMethod, PsiDocTag>? {
- val superMethods = current.findSuperMethods()
- val mappedFilteredTags = superMethods.map {
- it to it.docComment?.tags?.filter { it.name == elementToExpand.name }
- }
-
- for ((method, tags) in mappedFilteredTags) {
- tags ?: continue
- for (tag in tags) {
- val (tagSubject, elementSubject) = when (tag.name) {
- "throws" -> {
- // match class names only for throws, ignore possibly fully qualified path
- // TODO: Always match exactly here
- tag.getSubjectName()?.split(".")?.last() to elementToExpand.getSubjectName()?.split(".")?.last()
- }
- else -> {
- tag.getSubjectName() to elementToExpand.getSubjectName()
- }
- }
-
- if (tagSubject == elementSubject) {
- return method to tag
- }
- }
- }
-
- for (method in superMethods) {
- val result = findFirstSuperMethodWithDocumentationforTag(elementToExpand, method)
- if (result != null) {
- return result
- }
- }
- return null
- }
-
-}
diff --git a/core/src/main/kotlin/Kotlin/ContentBuilder.kt b/core/src/main/kotlin/Kotlin/ContentBuilder.kt
deleted file mode 100644
index 573b41b6..00000000
--- a/core/src/main/kotlin/Kotlin/ContentBuilder.kt
+++ /dev/null
@@ -1,188 +0,0 @@
-package org.jetbrains.dokka
-
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.intellij.markdown.html.entities.EntityConverter
-import org.intellij.markdown.parser.LinkMap
-import java.util.*
-
-class LinkResolver(private val linkMap: LinkMap, private val contentFactory: (String) -> ContentBlock) {
- fun getLinkInfo(refLabel: String) = linkMap.getLinkInfo(refLabel)
- fun resolve(href: String): ContentBlock = contentFactory(href)
-}
-
-fun buildContent(tree: MarkdownNode, linkResolver: LinkResolver, inline: Boolean = false): MutableContent {
- val result = MutableContent()
- if (inline) {
- buildInlineContentTo(tree, result, linkResolver)
- } else {
- buildContentTo(tree, result, linkResolver)
- }
- return result
-}
-
-fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: LinkResolver) {
-// println(tree.toTestString())
- val nodeStack = ArrayDeque<ContentBlock>()
- nodeStack.push(target)
-
- tree.visit { node, processChildren ->
- val parent = nodeStack.peek()
-
- fun appendNodeWithChildren(content: ContentBlock) {
- nodeStack.push(content)
- processChildren()
- parent.append(nodeStack.pop())
- }
-
- when (node.type) {
- MarkdownElementTypes.ATX_1 -> appendNodeWithChildren(ContentHeading(1))
- MarkdownElementTypes.ATX_2 -> appendNodeWithChildren(ContentHeading(2))
- MarkdownElementTypes.ATX_3 -> appendNodeWithChildren(ContentHeading(3))
- MarkdownElementTypes.ATX_4 -> appendNodeWithChildren(ContentHeading(4))
- MarkdownElementTypes.ATX_5 -> appendNodeWithChildren(ContentHeading(5))
- MarkdownElementTypes.ATX_6 -> appendNodeWithChildren(ContentHeading(6))
- MarkdownElementTypes.UNORDERED_LIST -> appendNodeWithChildren(ContentUnorderedList())
- MarkdownElementTypes.ORDERED_LIST -> appendNodeWithChildren(ContentOrderedList())
- MarkdownElementTypes.LIST_ITEM -> appendNodeWithChildren(ContentListItem())
- MarkdownElementTypes.EMPH -> appendNodeWithChildren(ContentEmphasis())
- MarkdownElementTypes.STRONG -> appendNodeWithChildren(ContentStrong())
- MarkdownElementTypes.CODE_SPAN -> {
- val startDelimiter = node.child(MarkdownTokenTypes.BACKTICK)?.text
- if (startDelimiter != null) {
- val text = node.text.substring(startDelimiter.length).removeSuffix(startDelimiter)
- val codeSpan = ContentCode().apply { append(ContentText(text)) }
- parent.append(codeSpan)
- }
- }
- MarkdownElementTypes.CODE_BLOCK,
- MarkdownElementTypes.CODE_FENCE -> {
- val language = node.child(MarkdownTokenTypes.FENCE_LANG)?.text?.trim() ?: ""
- appendNodeWithChildren(ContentBlockCode(language))
- }
- MarkdownElementTypes.PARAGRAPH -> appendNodeWithChildren(ContentParagraph())
-
- MarkdownElementTypes.INLINE_LINK -> {
- val linkTextNode = node.child(MarkdownElementTypes.LINK_TEXT)
- val destination = node.child(MarkdownElementTypes.LINK_DESTINATION)
- if (linkTextNode != null) {
- if (destination != null) {
- val link = ContentExternalLink(destination.text)
- renderLinkTextTo(linkTextNode, link, linkResolver)
- parent.append(link)
- } else {
- val link = ContentExternalLink(linkTextNode.getLabelText())
- renderLinkTextTo(linkTextNode, link, linkResolver)
- parent.append(link)
- }
- }
- }
- MarkdownElementTypes.SHORT_REFERENCE_LINK,
- MarkdownElementTypes.FULL_REFERENCE_LINK -> {
- val labelElement = node.child(MarkdownElementTypes.LINK_LABEL)
- if (labelElement != null) {
- val linkInfo = linkResolver.getLinkInfo(labelElement.text)
- val labelText = labelElement.getLabelText()
- val link = linkInfo?.let { linkResolver.resolve(it.destination.toString()) } ?: linkResolver.resolve(labelText)
- val linkText = node.child(MarkdownElementTypes.LINK_TEXT)
- if (linkText != null) {
- renderLinkTextTo(linkText, link, linkResolver)
- } else {
- link.append(ContentText(labelText))
- }
- parent.append(link)
- }
- }
- MarkdownTokenTypes.WHITE_SPACE -> {
- // Don't append first space if start of header (it is added during formatting later)
- // v
- // #### Some Heading
- if (nodeStack.peek() !is ContentHeading || node.parent?.children?.first() != node) {
- parent.append(ContentText(node.text))
- }
- }
- MarkdownTokenTypes.EOL -> {
- if ((keepEol(nodeStack.peek()) && node.parent?.children?.last() != node) ||
- // Keep extra blank lines when processing lists (affects Markdown formatting)
- (processingList(nodeStack.peek()) && node.previous?.type == MarkdownTokenTypes.EOL)) {
- parent.append(ContentText(node.text))
- }
- }
-
- MarkdownTokenTypes.CODE_LINE -> {
- val content = ContentText(node.text)
- if (parent is ContentBlockCode) {
- parent.append(content)
- } else {
- parent.append(ContentBlockCode().apply { append(content) })
- }
- }
-
- MarkdownTokenTypes.TEXT -> {
- fun createEntityOrText(text: String): ContentNode {
- if (text == "&amp;" || text == "&quot;" || text == "&lt;" || text == "&gt;") {
- return ContentEntity(text)
- }
- if (text == "&") {
- return ContentEntity("&amp;")
- }
- val decodedText = EntityConverter.replaceEntities(text, true, true)
- if (decodedText != text) {
- return ContentEntity(text)
- }
- return ContentText(text)
- }
-
- parent.append(createEntityOrText(node.text))
- }
-
- MarkdownTokenTypes.EMPH -> {
- val parentNodeType = node.parent?.type
- if (parentNodeType != MarkdownElementTypes.EMPH && parentNodeType != MarkdownElementTypes.STRONG) {
- parent.append(ContentText(node.text))
- }
- }
-
- MarkdownTokenTypes.COLON,
- MarkdownTokenTypes.SINGLE_QUOTE,
- MarkdownTokenTypes.DOUBLE_QUOTE,
- MarkdownTokenTypes.LT,
- MarkdownTokenTypes.GT,
- MarkdownTokenTypes.LPAREN,
- MarkdownTokenTypes.RPAREN,
- MarkdownTokenTypes.LBRACKET,
- MarkdownTokenTypes.RBRACKET,
- MarkdownTokenTypes.EXCLAMATION_MARK,
- MarkdownTokenTypes.BACKTICK,
- MarkdownTokenTypes.CODE_FENCE_CONTENT -> {
- parent.append(ContentText(node.text))
- }
-
- MarkdownElementTypes.LINK_DEFINITION -> {
- }
-
- else -> {
- processChildren()
- }
- }
- }
-}
-
-private fun MarkdownNode.getLabelText() = children.filter { it.type == MarkdownTokenTypes.TEXT || it.type == MarkdownTokenTypes.EMPH || it.type == MarkdownTokenTypes.COLON }.joinToString("") { it.text }
-
-private fun keepEol(node: ContentNode) = node is ContentParagraph || node is ContentSection || node is ContentBlockCode
-private fun processingList(node: ContentNode) = node is ContentOrderedList || node is ContentUnorderedList
-
-fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: LinkResolver) {
- val inlineContent = tree.children.singleOrNull { it.type == MarkdownElementTypes.PARAGRAPH }?.children ?: listOf(tree)
- inlineContent.forEach {
- buildContentTo(it, target, linkResolver)
- }
-}
-
-fun renderLinkTextTo(tree: MarkdownNode, target: ContentBlock, linkResolver: LinkResolver) {
- val linkTextNodes = tree.children.drop(1).dropLast(1)
- linkTextNodes.forEach {
- buildContentTo(it, target, linkResolver)
- }
-}
diff --git a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
deleted file mode 100644
index 88494581..00000000
--- a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
-
-class DeclarationLinkResolver
- @Inject constructor(val resolutionFacade: DokkaResolutionFacade,
- val refGraph: NodeReferenceGraph,
- val logger: DokkaLogger,
- val passConfiguration: DokkaConfiguration.PassConfiguration,
- val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver,
- val elementSignatureProvider: ElementSignatureProvider) {
-
-
- fun tryResolveContentLink(fromDescriptor: DeclarationDescriptor, href: String): ContentBlock? {
- val symbol = try {
- val symbols = resolveKDocLink(resolutionFacade.resolveSession.bindingContext,
- resolutionFacade, fromDescriptor, null, href.split('.').toList())
- findTargetSymbol(symbols)
- } catch(e: Exception) {
- null
- }
-
- // don't include unresolved links in generated doc
- // assume that if an href doesn't contain '/', it's not an attempt to reference an external file
- if (symbol != null) {
- val externalHref = externalDocumentationLinkResolver.buildExternalDocumentationLink(symbol)
- if (externalHref != null) {
- return ContentExternalLink(externalHref)
- }
- val signature = elementSignatureProvider.signature(symbol)
- val referencedAt = fromDescriptor.signatureWithSourceLocation()
-
- return ContentNodeLazyLink(href) {
- val target = refGraph.lookup(signature)
-
- if (target == null) {
- logger.warn("Can't find node by signature `$signature`, referenced at $referencedAt. " +
- "This is probably caused by invalid configuration of cross-module dependencies")
- }
- target
- }
- }
- if ("/" in href) {
- return ContentExternalLink(href)
- }
- return null
- }
-
- fun resolveContentLink(fromDescriptor: DeclarationDescriptor, href: String) =
- tryResolveContentLink(fromDescriptor, href) ?: run {
- logger.warn("Unresolved link to $href in doc comment of ${fromDescriptor.signatureWithSourceLocation()}")
- ContentExternalLink("#")
- }
-
- fun findTargetSymbol(symbols: Collection<DeclarationDescriptor>): DeclarationDescriptor? {
- if (symbols.isEmpty()) {
- return null
- }
- val symbol = symbols.first()
- if (symbol is CallableMemberDescriptor && symbol.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
- return symbol.overriddenDescriptors.firstOrNull()
- }
- if (symbol is TypeAliasDescriptor && !symbol.isDocumented(passConfiguration)) {
- return symbol.classDescriptor
- }
- return symbol
- }
-
-}
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
deleted file mode 100644
index ce20aeec..00000000
--- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
+++ /dev/null
@@ -1,177 +0,0 @@
-package org.jetbrains.dokka.Kotlin
-
-import com.google.inject.Inject
-import com.intellij.psi.PsiDocCommentOwner
-import com.intellij.psi.PsiNamedElement
-import com.intellij.psi.util.PsiTreeUtil
-import org.intellij.markdown.parser.LinkMap
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Samples.SampleProcessingService
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
-import org.jetbrains.kotlin.idea.kdoc.findKDoc
-import org.jetbrains.kotlin.incremental.components.NoLookupLocation
-import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
-import org.jetbrains.kotlin.kdoc.psi.api.KDoc
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.KtDeclaration
-import org.jetbrains.kotlin.psi.KtElement
-import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
-import org.jetbrains.kotlin.resolve.DescriptorUtils
-import org.jetbrains.kotlin.resolve.annotations.argumentValue
-import org.jetbrains.kotlin.resolve.constants.StringValue
-import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
-import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
-import org.jetbrains.kotlin.resolve.source.PsiSourceElement
-
-class DescriptorDocumentationParser
- @Inject constructor(val options: DokkaConfiguration.PassConfiguration,
- val logger: DokkaLogger,
- val linkResolver: DeclarationLinkResolver,
- val resolutionFacade: DokkaResolutionFacade,
- val refGraph: NodeReferenceGraph,
- val sampleService: SampleProcessingService,
- val signatureProvider: KotlinElementSignatureProvider,
- val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
-)
-{
- fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Content =
- parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first
-
- fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> {
- if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) {
- return parseJavadoc(descriptor)
- }
-
- val kdoc = descriptor.findKDoc() ?: findStdlibKDoc(descriptor)
- if (kdoc == null) {
- if (options.effectivePackageOptions(descriptor.fqNameSafe).reportUndocumented && !descriptor.isDeprecated() &&
- descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor &&
- descriptor !is PropertyAccessorDescriptor && !descriptor.isSuppressWarning()) {
- logger.warn("No documentation for ${descriptor.signatureWithSourceLocation()}")
- }
- return Content.Empty to { node -> }
- }
-
- val contextDescriptor =
- (PsiTreeUtil.getParentOfType(kdoc, KDoc::class.java)?.context as? KtDeclaration)
- ?.takeIf { it != descriptor.original.sourcePsi() }
- ?.resolveToDescriptorIfAny()
- ?: descriptor
-
- var kdocText = if (isDefaultNoArgConstructor) {
- getConstructorTagContent(descriptor) ?: kdoc.getContent()
- } else kdoc.getContent()
-
- // workaround for code fence parsing problem in IJ markdown parser
- if (kdocText.endsWith("```") || kdocText.endsWith("~~~")) {
- kdocText += "\n"
- }
- val tree = parseMarkdown(kdocText)
- val linkMap = LinkMap.buildLinkMap(tree.node, kdocText)
- val content = buildContent(tree, LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }, inline)
- if (kdoc is KDocSection) {
- val tags = kdoc.getTags()
- tags.forEach {
- when (it.knownTag) {
- KDocKnownTag.SAMPLE ->
- content.append(sampleService.resolveSample(contextDescriptor, it.getSubjectName(), it))
- KDocKnownTag.SEE ->
- content.addTagToSeeAlso(contextDescriptor, it)
- else -> {
- val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName())
- val sectionContent = it.getContent()
- val markdownNode = parseMarkdown(sectionContent)
- buildInlineContentTo(markdownNode, section, LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) })
- }
- }
- }
- }
- return content to { node -> }
- }
-
- private fun getConstructorTagContent(descriptor: DeclarationDescriptor): String? {
- return ((DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.navigationElement as? KtElement) as KtDeclaration).docComment?.findSectionByTag(
- KDocKnownTag.CONSTRUCTOR
- )?.getContent()
- }
-
-
- private fun DeclarationDescriptor.isSuppressWarning() : Boolean {
- val suppressAnnotation = annotations.findAnnotation(FqName(Suppress::class.qualifiedName!!))
- return if (suppressAnnotation != null) {
- @Suppress("UNCHECKED_CAST")
- (suppressAnnotation.argumentValue("names")?.value as List<StringValue>).any { it.value == "NOT_DOCUMENTED" }
- } else containingDeclaration?.isSuppressWarning() ?: false
- }
-
- /**
- * Special case for generating stdlib documentation (the Any class to which the override chain will resolve
- * is not the same one as the Any class included in the source scope).
- */
- fun findStdlibKDoc(descriptor: DeclarationDescriptor): KDocTag? {
- if (descriptor !is CallableMemberDescriptor) {
- return null
- }
- val name = descriptor.name.asString()
- if (name == "equals" || name == "hashCode" || name == "toString") {
- var deepestDescriptor: CallableMemberDescriptor = descriptor
- while (!deepestDescriptor.overriddenDescriptors.isEmpty()) {
- deepestDescriptor = deepestDescriptor.overriddenDescriptors.first()
- }
- if (DescriptorUtils.getFqName(deepestDescriptor.containingDeclaration).asString() == "kotlin.Any") {
- val anyClassDescriptors = resolutionFacade.resolveSession.getTopLevelClassifierDescriptors(
- FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE)
- anyClassDescriptors.forEach {
- val anyMethod = (it as ClassDescriptor).getMemberScope(listOf())
- .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS) { it == descriptor.name }
- .single()
- val kdoc = anyMethod.findKDoc()
- if (kdoc != null) {
- return kdoc
- }
- }
- }
- }
- return null
- }
-
- fun parseJavadoc(descriptor: DeclarationDescriptor): Pair<Content, (DocumentationNode) -> Unit> {
- val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi
- if (psi is PsiDocCommentOwner) {
- val parseResult = JavadocParser(
- refGraph,
- logger,
- signatureProvider,
- externalDocumentationLinkResolver
- ).parseDocumentation(psi as PsiNamedElement)
- return parseResult.content to { node ->
- parseResult.deprecatedContent?.let {
- val deprecationNode = DocumentationNode("", it, NodeKind.Modifier)
- node.append(deprecationNode, RefKind.Deprecation)
- }
- }
- }
- return Content.Empty to { node -> }
- }
-
- fun KDocSection.getTags(): Array<KDocTag> = PsiTreeUtil.getChildrenOfType(this, KDocTag::class.java) ?: arrayOf()
-
- private fun MutableContent.addTagToSeeAlso(descriptor: DeclarationDescriptor, seeTag: KDocTag) {
- val subjectName = seeTag.getSubjectName()
- if (subjectName != null) {
- val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null)
- val link = linkResolver.resolveContentLink(descriptor, subjectName)
- link.append(ContentText(subjectName))
- val para = ContentParagraph()
- para.append(link)
- seeSection.append(para)
- }
- }
-
-}
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
deleted file mode 100644
index 13bbbb11..00000000
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ /dev/null
@@ -1,1166 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.openapi.util.text.StringUtil
-import com.intellij.psi.PsiJavaFile
-import org.jetbrains.dokka.DokkaConfiguration.PassConfiguration
-import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser
-import org.jetbrains.kotlin.builtins.KotlinBuiltIns
-import org.jetbrains.kotlin.coroutines.hasFunctionOrSuspendFunctionType
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.descriptors.annotations.Annotated
-import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
-import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
-import org.jetbrains.kotlin.idea.kdoc.findKDoc
-import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType
-import org.jetbrains.kotlin.idea.util.makeNotNullable
-import org.jetbrains.kotlin.idea.util.toFuzzyType
-import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
-import org.jetbrains.kotlin.lexer.KtTokens
-import org.jetbrains.kotlin.name.ClassId
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.psi.KtModifierListOwner
-import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.psi.addRemoveModifier.MODIFIERS_ORDER
-import org.jetbrains.kotlin.resolve.DescriptorUtils
-import org.jetbrains.kotlin.resolve.constants.ConstantValue
-import org.jetbrains.kotlin.resolve.descriptorUtil.*
-import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
-import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
-import org.jetbrains.kotlin.resolve.source.PsiSourceElement
-import org.jetbrains.kotlin.resolve.source.getPsi
-import org.jetbrains.kotlin.types.*
-import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
-import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
-import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
-import org.jetbrains.kotlin.types.typeUtil.supertypes
-import org.jetbrains.kotlin.util.supertypesWithAny
-import com.google.inject.name.Named as GuiceNamed
-
-private fun isExtensionForExternalClass(extensionFunctionDescriptor: DeclarationDescriptor,
- extensionReceiverDescriptor: DeclarationDescriptor,
- allFqNames: Collection<FqName>): Boolean {
- val extensionFunctionPackage = DescriptorUtils.getParentOfType(extensionFunctionDescriptor, PackageFragmentDescriptor::class.java)
- val extensionReceiverPackage = DescriptorUtils.getParentOfType(extensionReceiverDescriptor, PackageFragmentDescriptor::class.java)
- return extensionFunctionPackage != null && extensionReceiverPackage != null &&
- extensionFunctionPackage.fqName != extensionReceiverPackage.fqName &&
- extensionReceiverPackage.fqName !in allFqNames
-}
-
-interface PackageDocumentationBuilder {
- fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>,
- allFqNames: Collection<FqName>)
-}
-
-interface DefaultPlatformsProvider {
- fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String>
-}
-
-val ignoredSupertypes = setOf(
- "kotlin.Annotation", "kotlin.Enum", "kotlin.Any"
-)
-
-class DocumentationBuilder
-@Inject constructor(val resolutionFacade: DokkaResolutionFacade,
- val descriptorDocumentationParser: DescriptorDocumentationParser,
- val passConfiguration: DokkaConfiguration.PassConfiguration,
- val refGraph: NodeReferenceGraph,
- val platformNodeRegistry: PlatformNodeRegistry,
- val logger: DokkaLogger,
- val linkResolver: DeclarationLinkResolver,
- val defaultPlatformsProvider: DefaultPlatformsProvider) {
- val boringBuiltinClasses = setOf(
- "kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean",
- "kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any")
- val knownModifiers = setOf(
- KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.INTERNAL_KEYWORD, KtTokens.PRIVATE_KEYWORD,
- KtTokens.OPEN_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.ABSTRACT_KEYWORD, KtTokens.SEALED_KEYWORD,
- KtTokens.OVERRIDE_KEYWORD, KtTokens.INLINE_KEYWORD)
-
- fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: RefKind) {
- refGraph.link(node, descriptor.signature(), kind)
- }
-
- fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: RefKind) {
- if (fromDescriptor != null && toDescriptor != null) {
- refGraph.link(fromDescriptor.signature(), toDescriptor.signature(), kind)
- }
- }
-
- fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) {
- refGraph.register(descriptor.signature(), node)
- }
-
- fun <T> nodeForDescriptor(
- descriptor: T,
- kind: NodeKind,
- external: Boolean = false
- ): DocumentationNode where T : DeclarationDescriptor, T : Named {
- val (doc, callback) =
- if (external) {
- Content.Empty to { node -> }
- } else {
- descriptorDocumentationParser.parseDocumentationAndDetails(
- descriptor,
- kind == NodeKind.Parameter
- )
- }
- val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(descriptor)
- node.appendSignature(descriptor)
- callback(node)
- return node
- }
-
- private fun DocumentationNode.withModifiers(descriptor: DeclarationDescriptor): DocumentationNode {
- if (descriptor is MemberDescriptor) {
- appendVisibility(descriptor)
- if (descriptor !is ConstructorDescriptor) {
- appendModality(descriptor)
- }
- }
- return this
- }
-
- fun DocumentationNode.appendModality(descriptor: MemberDescriptor) {
- var modality = descriptor.modality
- if (modality == Modality.OPEN) {
- val containingClass = descriptor.containingDeclaration as? ClassDescriptor
- if (containingClass?.modality == Modality.FINAL) {
- modality = Modality.FINAL
- }
- }
- val modifier = modality.name.toLowerCase()
- appendTextNode(modifier, NodeKind.Modifier)
- }
-
- fun DocumentationNode.appendInline(descriptor: DeclarationDescriptor, psi: KtModifierListOwner) {
- if (!psi.hasModifier(KtTokens.INLINE_KEYWORD)) return
- if (descriptor is FunctionDescriptor
- && descriptor.valueParameters.none { it.hasFunctionOrSuspendFunctionType }) return
- appendTextNode(KtTokens.INLINE_KEYWORD.value, NodeKind.Modifier)
- }
-
- fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) {
- val modifier = descriptor.visibility.normalize().displayName
- appendTextNode(modifier, NodeKind.Modifier)
- }
-
- fun DocumentationNode.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) {
- val unwrappedType = superType.unwrap()
- if (unwrappedType is AbbreviatedType) {
- appendSupertype(descriptor, unwrappedType.abbreviation, backref)
- } else {
- appendType(unwrappedType, NodeKind.Supertype)
- val superclass = unwrappedType.constructor.declarationDescriptor
- if (backref) {
- link(superclass, descriptor, RefKind.Inheritor)
- }
- link(descriptor, superclass, RefKind.Superclass)
- }
- }
-
- fun DocumentationNode.appendProjection(projection: TypeProjection, kind: NodeKind = NodeKind.Type) {
- if (projection.isStarProjection) {
- appendTextNode("*", NodeKind.Type)
- } else {
- appendType(projection.type, kind, projection.projectionKind.label)
- }
- }
-
- fun DocumentationNode.appendType(kotlinType: KotlinType?, kind: NodeKind = NodeKind.Type, prefix: String = "") {
- if (kotlinType == null)
- return
- (kotlinType.unwrap() as? AbbreviatedType)?.let {
- return appendType(it.abbreviation)
- }
-
- if (kotlinType.isDynamic()) {
- append(DocumentationNode("dynamic", Content.Empty, kind), RefKind.Detail)
- return
- }
-
- val classifierDescriptor = kotlinType.constructor.declarationDescriptor
- val name = when (classifierDescriptor) {
- is ClassDescriptor -> {
- if (classifierDescriptor.isCompanionObject) {
- classifierDescriptor.containingDeclaration.name.asString() +
- "." + classifierDescriptor.name.asString()
- } else {
- classifierDescriptor.name.asString()
- }
- }
- is Named -> classifierDescriptor.name.asString()
- else -> "<anonymous>"
- }
- val node = DocumentationNode(name, Content.Empty, kind)
- if (prefix != "") {
- node.appendTextNode(prefix, NodeKind.Modifier)
- }
- if (kotlinType.isNullabilityFlexible()) {
- node.appendTextNode("!", NodeKind.NullabilityModifier)
- } else if (kotlinType.isMarkedNullable) {
- node.appendTextNode("?", NodeKind.NullabilityModifier)
- }
- if (classifierDescriptor != null) {
- val externalLink =
- linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(classifierDescriptor)
- if (externalLink != null) {
- if (classifierDescriptor !is TypeParameterDescriptor) {
- val targetNode =
- refGraph.lookup(classifierDescriptor.signature()) ?: classifierDescriptor.build(true)
- node.append(targetNode, RefKind.ExternalType)
- node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
- }
- } else {
- link(
- node, classifierDescriptor,
- if (classifierDescriptor.isBoringBuiltinClass()) RefKind.HiddenLink else RefKind.Link
- )
- }
- if (classifierDescriptor !is TypeParameterDescriptor) {
- node.append(
- DocumentationNode(
- classifierDescriptor.fqNameUnsafe.asString(),
- Content.Empty,
- NodeKind.QualifiedName
- ), RefKind.Detail
- )
- }
- }
-
-
- append(node, RefKind.Detail)
- node.appendAnnotations(kotlinType)
- for (typeArgument in kotlinType.arguments) {
- node.appendProjection(typeArgument)
- }
- }
-
- fun ClassifierDescriptor.isBoringBuiltinClass(): Boolean =
- DescriptorUtils.getFqName(this).asString() in boringBuiltinClasses
-
- fun DocumentationNode.appendAnnotations(annotated: Annotated) {
- annotated.annotations.forEach {
- it.build()?.let { annotationNode ->
- if (annotationNode.isSinceKotlin()) {
- appendSinceKotlin(annotationNode)
- }
- else {
- val refKind = when {
- it.isDocumented() ->
- when {
- annotationNode.isDeprecation() -> RefKind.Deprecation
- else -> RefKind.Annotation
- }
- it.isHiddenInDocumentation() -> RefKind.HiddenAnnotation
- else -> return@forEach
- }
- append(annotationNode, refKind)
- }
-
- }
- }
- }
-
- fun DocumentationNode.appendExternalLink(externalLink: String) {
- append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
- }
-
- fun DocumentationNode.appendExternalLink(descriptor: DeclarationDescriptor) {
- val target = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(descriptor)
- if (target != null) {
- appendExternalLink(target)
- }
- }
-
- fun DocumentationNode.appendSinceKotlin(annotation: DocumentationNode) {
- val kotlinVersion = annotation
- .detail(NodeKind.Parameter)
- .detail(NodeKind.Value)
- .name.removeSurrounding("\"")
-
- sinceKotlin = kotlinVersion
- }
-
- fun DocumentationNode.appendDefaultSinceKotlin() {
- if (sinceKotlin == null) {
- sinceKotlin = passConfiguration.sinceKotlin
- }
- }
-
- fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) {
- val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return
- KtTokens.MODIFIER_KEYWORDS_ARRAY.filter {
- it !in knownModifiers
- }.sortedBy {
- MODIFIERS_ORDER.indexOf(it)
- }.forEach {
- if (psi.hasModifier(it)) {
- appendTextNode(it.value, NodeKind.Modifier)
- }
- }
- appendInline(descriptor, psi)
- }
-
- fun DocumentationNode.appendDefaultPlatforms(descriptor: DeclarationDescriptor) {
- for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor)) {
- append(platformNodeRegistry[platform], RefKind.Platform)
- }
- }
-
- fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated"
-
- fun DocumentationNode.isSinceKotlin() = name == "SinceKotlin" && kind == NodeKind.Annotation
-
- fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
- appendSourceLink(sourceElement.getPsi(), passConfiguration.sourceLinks)
- }
-
- fun DocumentationNode.appendSignature(descriptor: DeclarationDescriptor) {
- appendTextNode(descriptor.signature(), NodeKind.Signature, RefKind.Detail)
- }
-
- fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? {
- if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) {
- val node = descriptor.build()
- append(node, kind)
- return node
- }
- return null
- }
-
- fun createGroupNode(signature: String, nodes: List<DocumentationNode>) = (nodes.find { it.kind == NodeKind.GroupNode } ?:
- DocumentationNode(nodes.first().name, Content.Empty, NodeKind.GroupNode).apply {
- appendTextNode(signature, NodeKind.Signature, RefKind.Detail)
- })
- .also { groupNode ->
- nodes.forEach { node ->
- if (node != groupNode) {
- node.owner?.let { owner ->
- node.dropReferences { it.to == owner && it.kind == RefKind.Owner }
- owner.dropReferences { it.to == node && it.kind == RefKind.Member }
- owner.append(groupNode, RefKind.Member)
- }
- groupNode.append(node, RefKind.Member)
- }
- }
- }
-
-
- fun DocumentationNode.appendOrUpdateMember(descriptor: DeclarationDescriptor) {
- if (descriptor.isGenerated() || !descriptor.isDocumented(passConfiguration)) return
-
- val existingNode = refGraph.lookup(descriptor.signature())
- if (existingNode != null) {
- if (existingNode.kind == NodeKind.TypeAlias && descriptor is ClassDescriptor
- || existingNode.kind == NodeKind.Class && descriptor is TypeAliasDescriptor) {
- val node = createGroupNode(descriptor.signature(), listOf(existingNode, descriptor.build()))
- register(descriptor, node)
- return
- }
-
- existingNode.updatePlatforms(descriptor)
-
- if (descriptor is ClassDescriptor) {
- val membersToDocument = descriptor.collectMembersToDocument()
- for ((memberDescriptor, inheritedLinkKind, extraModifier) in membersToDocument) {
- if (memberDescriptor is ClassDescriptor) {
- existingNode.appendOrUpdateMember(memberDescriptor) // recurse into nested classes
- }
- else {
- val existingMemberNode = refGraph.lookup(memberDescriptor.signature())
- if (existingMemberNode != null) {
- existingMemberNode.updatePlatforms(memberDescriptor)
- }
- else {
- existingNode.appendClassMember(memberDescriptor, inheritedLinkKind, extraModifier)
- }
- }
- }
- }
- }
- else {
- appendChild(descriptor, RefKind.Member)
- }
- }
-
- private fun DocumentationNode.updatePlatforms(descriptor: DeclarationDescriptor) {
- for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor) - platforms) {
- append(platformNodeRegistry[platform], RefKind.Platform)
- }
- }
-
- fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor,
- inheritedLinkKind: RefKind = RefKind.InheritedMember,
- extraModifier: String?) {
- if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
- val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull()
- if (baseDescriptor != null) {
- link(this, baseDescriptor, inheritedLinkKind)
- }
- } else {
- val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original
- val child = appendChild(descriptorToUse, RefKind.Member)
- if (extraModifier != null) {
- child?.appendTextNode("static", NodeKind.Modifier)
- }
- }
- }
-
- fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: RefKind) {
- descriptors.forEach { descriptor ->
- val node = appendChild(descriptor, kind)
- node?.addReferenceTo(this, RefKind.TopLevelPage)
- }
- }
-
- fun DocumentationModule.appendFragments(fragments: Collection<PackageFragmentDescriptor>,
- packageContent: Map<String, Content>,
- packageDocumentationBuilder: PackageDocumentationBuilder) {
- val allFqNames = fragments.filter { it.isDocumented(passConfiguration) }.map { it.fqName }.distinct()
-
- for (packageName in allFqNames) {
- if (packageName.isRoot && !passConfiguration.includeRootPackage) continue
- val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() }
-
- if (passConfiguration.skipEmptyPackages && declarations.none { it.isDocumented(passConfiguration) }) continue
- logger.info(" package $packageName: ${declarations.count()} declarations")
- val packageNode = findOrCreatePackageNode(this, packageName.asString(), packageContent, this@DocumentationBuilder.refGraph)
- packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode,
- declarations, allFqNames)
- }
-
- }
-
- fun propagateExtensionFunctionsToSubclasses(
- fragments: Collection<PackageFragmentDescriptor>,
- resolutionFacade: DokkaResolutionFacade
- ) {
-
- val moduleDescriptor = resolutionFacade.moduleDescriptor
-
- // Wide-collect all view descriptors
- val allPackageViewDescriptors = generateSequence(listOf(moduleDescriptor.getPackage(FqName.ROOT))) { packages ->
- packages
- .flatMap { pkg ->
- moduleDescriptor.getSubPackagesOf(pkg.fqName) { true }
- }.map { fqName ->
- moduleDescriptor.getPackage(fqName)
- }.takeUnless { it.isEmpty() }
- }.flatten()
-
- val allDescriptors =
- if (passConfiguration.collectInheritedExtensionsFromLibraries) {
- allPackageViewDescriptors.map { it.memberScope }
- } else {
- fragments.asSequence().map { it.getMemberScope() }
- }.flatMap {
- it.getDescriptorsFiltered(
- DescriptorKindFilter.CALLABLES
- ).asSequence()
- }
-
-
- val documentingDescriptors = fragments.flatMap { it.getMemberScope().getContributedDescriptors() }
- val documentingClasses = documentingDescriptors.filterIsInstance<ClassDescriptor>()
-
- val classHierarchy = buildClassHierarchy(documentingClasses)
-
- val allExtensionFunctions =
- allDescriptors
- .filterIsInstance<CallableMemberDescriptor>()
- .filter { it.extensionReceiverParameter != null }
- val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name }
-
- fun isIgnoredReceiverType(type: KotlinType) =
- type.isDynamic() ||
- type.isAnyOrNullableAny() ||
- (type.isTypeParameter() && type.immediateSupertypes().all { it.isAnyOrNullableAny() })
-
-
- for (extensionFunction in allExtensionFunctions) {
- val extensionReceiverParameter = extensionFunction.extensionReceiverParameter!!
- if (extensionFunction.dispatchReceiverParameter != null) continue
- val possiblyShadowingFunctions = extensionFunctionsByName[extensionFunction.name]
- ?.filter { fn -> fn.canShadow(extensionFunction) }
- ?: emptyList()
-
- if (isIgnoredReceiverType(extensionReceiverParameter.type)) continue
- val subclasses =
- classHierarchy.filter { (key) -> key.isExtensionApplicable(extensionFunction) }
- if (subclasses.isEmpty()) continue
- subclasses.values.flatten().forEach { subclass ->
- if (subclass.isExtensionApplicable(extensionFunction) &&
- possiblyShadowingFunctions.none { subclass.isExtensionApplicable(it) }) {
-
- val hasExternalLink =
- linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(
- extensionFunction
- ) != null
- if (hasExternalLink) {
- val containerDesc =
- extensionFunction.containingDeclaration as? PackageFragmentDescriptor
- if (containerDesc != null) {
- val container = refGraph.lookup(containerDesc.signature())
- ?: containerDesc.buildExternal()
- container.append(extensionFunction.buildExternal(), RefKind.Member)
- }
- }
-
- refGraph.link(subclass.signature(), extensionFunction.signature(), RefKind.Extension)
- }
- }
- }
- }
-
- private fun ClassDescriptor.isExtensionApplicable(extensionFunction: CallableMemberDescriptor): Boolean {
- val receiverType = extensionFunction.fuzzyExtensionReceiverType()?.makeNotNullable()
- val classType = defaultType.toFuzzyType(declaredTypeParameters)
- return receiverType != null && classType.checkIsSubtypeOf(receiverType) != null
- }
-
- private fun buildClassHierarchy(classes: List<ClassDescriptor>): Map<ClassDescriptor, List<ClassDescriptor>> {
- val result = hashMapOf<ClassDescriptor, MutableList<ClassDescriptor>>()
- classes.forEach { cls ->
- TypeUtils.getAllSupertypes(cls.defaultType).forEach { supertype ->
- val classDescriptor = supertype.constructor.declarationDescriptor as? ClassDescriptor
- if (classDescriptor != null) {
- val subtypesList = result.getOrPut(classDescriptor) { arrayListOf() }
- subtypesList.add(cls)
- }
- }
- }
- return result
- }
-
- private fun CallableMemberDescriptor.canShadow(other: CallableMemberDescriptor): Boolean {
- if (this == other) return false
- if (this is PropertyDescriptor && other is PropertyDescriptor) {
- return true
- }
- if (this is FunctionDescriptor && other is FunctionDescriptor) {
- val parameters1 = valueParameters
- val parameters2 = other.valueParameters
- if (parameters1.size != parameters2.size) {
- return false
- }
- for ((p1, p2) in parameters1 zip parameters2) {
- if (p1.type != p2.type) {
- return false
- }
- }
- return true
- }
- return false
- }
-
- fun DeclarationDescriptor.build(): DocumentationNode = when (this) {
- is ClassifierDescriptor -> build()
- is ConstructorDescriptor -> build()
- is PropertyDescriptor -> build()
- is FunctionDescriptor -> build()
- is ValueParameterDescriptor -> build()
- is ReceiverParameterDescriptor -> build()
- else -> throw IllegalStateException("Descriptor $this is not known")
- }
-
- fun PackageFragmentDescriptor.buildExternal(): DocumentationNode {
- val node = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.Package)
-
- val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(this)
- if (externalLink != null) {
- node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
- }
- register(this, node)
- return node
- }
-
- fun CallableDescriptor.buildExternal(): DocumentationNode = when(this) {
- is FunctionDescriptor -> build(true)
- is PropertyDescriptor -> build(true)
- else -> throw IllegalStateException("Descriptor $this is not known")
- }
-
-
- fun ClassifierDescriptor.build(external: Boolean = false): DocumentationNode = when (this) {
- is ClassDescriptor -> build(external)
- is TypeAliasDescriptor -> build(external)
- is TypeParameterDescriptor -> build()
- else -> throw IllegalStateException("Descriptor $this is not known")
- }
-
- fun TypeAliasDescriptor.build(external: Boolean = false): DocumentationNode {
- val node = nodeForDescriptor(this, NodeKind.TypeAlias)
-
- if (!external) {
- node.appendDefaultSinceKotlin()
- node.appendAnnotations(this)
- }
- node.appendModifiers(this)
- node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail)
-
- node.appendType(underlyingType, NodeKind.TypeAliasUnderlyingType)
-
- if (!external) {
- node.appendSourceLink(source)
- node.appendDefaultPlatforms(this)
- }
- register(this, node)
- return node
- }
-
- fun ClassDescriptor.build(external: Boolean = false): DocumentationNode {
- val kind = when {
- kind == ClassKind.OBJECT -> NodeKind.Object
- kind == ClassKind.INTERFACE -> NodeKind.Interface
- kind == ClassKind.ENUM_CLASS -> NodeKind.Enum
- kind == ClassKind.ANNOTATION_CLASS -> NodeKind.AnnotationClass
- kind == ClassKind.ENUM_ENTRY -> NodeKind.EnumItem
- isSubclassOfThrowable() -> NodeKind.Exception
- else -> NodeKind.Class
- }
- val node = nodeForDescriptor(this, kind, external)
- register(this, node)
- supertypesWithAnyPrecise().forEach {
- node.appendSupertype(this, it, !external)
- }
- if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
- node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail)
- }
- if (!external) {
- for ((descriptor, inheritedLinkKind, extraModifier) in collectMembersToDocument()) {
- node.appendClassMember(descriptor, inheritedLinkKind, extraModifier)
- }
- node.appendDefaultSinceKotlin()
- node.appendAnnotations(this)
- }
- node.appendModifiers(this)
- if (!external) {
- node.appendSourceLink(source)
- node.appendDefaultPlatforms(this)
- }
- return node
- }
-
- data class ClassMember(val descriptor: DeclarationDescriptor,
- val inheritedLinkKind: RefKind = RefKind.InheritedMember,
- val extraModifier: String? = null)
-
- fun ClassDescriptor.collectMembersToDocument(): List<ClassMember> {
- val result = arrayListOf<ClassMember>()
- if (kind != ClassKind.OBJECT && kind != ClassKind.ENUM_ENTRY) {
- val constructorsToDocument = if (kind == ClassKind.ENUM_CLASS)
- constructors.filter { it.valueParameters.size > 0 }
- else
- constructors
- constructorsToDocument.mapTo(result) { ClassMember(it) }
- }
-
- defaultType.memberScope.getContributedDescriptors()
- .filter { it != companionObjectDescriptor }
- .mapTo(result) { ClassMember(it) }
-
- staticScope.getContributedDescriptors()
- .mapTo(result) { ClassMember(it, extraModifier = "static") }
-
- val companionObjectDescriptor = companionObjectDescriptor
- if (companionObjectDescriptor != null && companionObjectDescriptor.isDocumented(passConfiguration)) {
- val descriptors = companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors()
- val descriptorsToDocument = descriptors.filter { it !is CallableDescriptor || !it.isInheritedFromAny() }
- descriptorsToDocument.mapTo(result) {
- ClassMember(it, inheritedLinkKind = RefKind.InheritedCompanionObjectMember)
- }
-
- if (companionObjectDescriptor.getAllSuperclassesWithoutAny().isNotEmpty()
- || companionObjectDescriptor.getSuperInterfaces().isNotEmpty()) {
- result += ClassMember(companionObjectDescriptor)
- }
- }
- return result
- }
-
- fun CallableDescriptor.isInheritedFromAny(): Boolean {
- return findTopMostOverriddenDescriptors().any {
- DescriptorUtils.getFqNameSafe(it.containingDeclaration).asString() == "kotlin.Any"
- }
- }
-
- fun ClassDescriptor.isSubclassOfThrowable(): Boolean =
- defaultType.supertypes().any { it.constructor.declarationDescriptor == builtIns.throwable }
-
- fun ConstructorDescriptor.build(): DocumentationNode {
- val node = nodeForDescriptor(this, NodeKind.Constructor)
- node.appendInPageChildren(valueParameters, RefKind.Detail)
- node.appendDefaultPlatforms(this)
- node.appendDefaultSinceKotlin()
- register(this, node)
- return node
- }
-
- private fun CallableMemberDescriptor.inCompanionObject(): Boolean {
- val containingDeclaration = containingDeclaration
- if ((containingDeclaration as? ClassDescriptor)?.isCompanionObject ?: false) {
- return true
- }
- val receiver = extensionReceiverParameter
- return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false
- }
-
- fun FunctionDescriptor.build(external: Boolean = false): DocumentationNode {
- if (ErrorUtils.containsErrorTypeInParameters(this) || ErrorUtils.containsErrorType(this.returnType)) {
- logger.warn("Found an unresolved type in ${signatureWithSourceLocation()}")
- }
-
- val node = nodeForDescriptor(this, if (inCompanionObject()) NodeKind.CompanionObjectFunction else NodeKind.Function, external)
-
- node.appendInPageChildren(typeParameters, RefKind.Detail)
- extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) }
- node.appendInPageChildren(valueParameters, RefKind.Detail)
- node.appendType(returnType)
- if (!external) {
- node.appendDefaultSinceKotlin()
- }
- node.appendAnnotations(this)
- node.appendModifiers(this)
- if (!external) {
- node.appendSourceLink(source)
- node.appendDefaultPlatforms(this)
- } else {
- node.appendExternalLink(this)
- }
-
- overriddenDescriptors.forEach {
- addOverrideLink(it, this)
- }
-
- register(this, node)
- return node
- }
-
- fun addOverrideLink(baseClassFunction: CallableMemberDescriptor, overridingFunction: CallableMemberDescriptor) {
- val source = baseClassFunction.original.source.getPsi()
- if (source != null) {
- link(overridingFunction, baseClassFunction, RefKind.Override)
- } else {
- baseClassFunction.overriddenDescriptors.forEach {
- addOverrideLink(it, overridingFunction)
- }
- }
- }
-
- fun PropertyDescriptor.build(external: Boolean = false): DocumentationNode {
- val node = nodeForDescriptor(
- this,
- if (inCompanionObject()) NodeKind.CompanionObjectProperty else NodeKind.Property,
- external
- )
- node.appendInPageChildren(typeParameters, RefKind.Detail)
- extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) }
- node.appendType(returnType)
- if (!external) {
- node.appendDefaultSinceKotlin()
- }
- node.appendAnnotations(this)
- node.appendModifiers(this)
- if (!external) {
- node.appendSourceLink(source)
- if (isVar) {
- node.appendTextNode("var", NodeKind.Modifier)
- }
-
- if (isConst) {
- this.compileTimeInitializer?.toDocumentationNode()?.let { node.append(it, RefKind.Detail) }
- }
-
-
- getter?.let {
- if (!it.isDefault) {
- node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Getter")
- }
- }
- setter?.let {
- if (!it.isDefault) {
- node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Setter")
- }
- }
- node.appendDefaultPlatforms(this)
- }
- if (external) {
- node.appendExternalLink(this)
- }
-
- overriddenDescriptors.forEach {
- addOverrideLink(it, this)
- }
-
- register(this, node)
- return node
- }
-
- fun DocumentationNode.addAccessorDocumentation(documentation: Content, prefix: String) {
- if (documentation == Content.Empty) return
- updateContent {
- if (!documentation.children.isEmpty()) {
- val section = addSection(prefix, null)
- documentation.children.forEach { section.append(it) }
- }
- documentation.sections.forEach {
- val section = addSection("$prefix ${it.tag}", it.subjectName)
- it.children.forEach { section.append(it) }
- }
- }
- }
-
- fun ValueParameterDescriptor.build(): DocumentationNode {
- val node = nodeForDescriptor(this, NodeKind.Parameter)
- node.appendType(varargElementType ?: type)
- if (declaresDefaultValue()) {
- val psi = source.getPsi() as? KtParameter
- if (psi != null) {
- val defaultValueText = psi.defaultValue?.text
- if (defaultValueText != null) {
- node.appendTextNode(defaultValueText, NodeKind.Value)
- }
- }
- }
- node.appendDefaultSinceKotlin()
- node.appendAnnotations(this)
- node.appendModifiers(this)
- if (varargElementType != null && node.details(NodeKind.Modifier).none { it.name == "vararg" }) {
- node.appendTextNode("vararg", NodeKind.Modifier)
- }
- register(this, node)
- return node
- }
-
- fun TypeParameterDescriptor.build(): DocumentationNode {
- val doc = descriptorDocumentationParser.parseDocumentation(this)
- val name = name.asString()
- val prefix = variance.label
-
- val node = DocumentationNode(name, doc, NodeKind.TypeParameter)
- if (prefix != "") {
- node.appendTextNode(prefix, NodeKind.Modifier)
- }
- if (isReified) {
- node.appendTextNode("reified", NodeKind.Modifier)
- }
-
- for (constraint in upperBounds) {
- if (KotlinBuiltIns.isDefaultBound(constraint)) {
- continue
- }
- node.appendType(constraint, NodeKind.UpperBound)
- }
- register(this, node)
- return node
- }
-
- fun ReceiverParameterDescriptor.build(): DocumentationNode {
- var receiverClass: DeclarationDescriptor = type.constructor.declarationDescriptor!!
- if ((receiverClass as? ClassDescriptor)?.isCompanionObject ?: false) {
- receiverClass = receiverClass.containingDeclaration!!
- } else if (receiverClass is TypeParameterDescriptor) {
- val upperBoundClass = receiverClass.upperBounds.singleOrNull()?.constructor?.declarationDescriptor
- if (upperBoundClass != null) {
- receiverClass = upperBoundClass
- }
- }
-
- if ((containingDeclaration as? FunctionDescriptor)?.dispatchReceiverParameter == null) {
- link(receiverClass, containingDeclaration, RefKind.Extension)
- }
-
- val node = DocumentationNode(name.asString(), Content.Empty, NodeKind.Receiver)
- node.appendType(type)
- register(this, node)
- return node
- }
-
- fun AnnotationDescriptor.build(): DocumentationNode? {
- val annotationClass = type.constructor.declarationDescriptor
- if (annotationClass == null || ErrorUtils.isError(annotationClass)) {
- return null
- }
- val node = DocumentationNode(annotationClass.name.asString(), Content.Empty, NodeKind.Annotation)
- allValueArguments.forEach { (name, value) ->
- val valueNode = value.toDocumentationNode()
- if (valueNode != null) {
- val paramNode = DocumentationNode(name.asString(), Content.Empty, NodeKind.Parameter)
- paramNode.append(valueNode, RefKind.Detail)
- node.append(paramNode, RefKind.Detail)
- }
- }
- return node
- }
-
- fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value.let { value ->
- val text = when (value) {
- is String ->
- "\"" + StringUtil.escapeStringCharacters(value) + "\""
- is EnumEntrySyntheticClassDescriptor ->
- value.containingDeclaration.name.asString() + "." + value.name.asString()
- is Pair<*, *> -> {
- val (classId, name) = value
- if (classId is ClassId && name is Name) {
- classId.shortClassName.asString() + "." + name.asString()
- } else {
- value.toString()
- }
- }
- else -> "$value"
- }
- DocumentationNode(text, Content.Empty, NodeKind.Value)
- }
-
-
- fun DocumentationNode.getParentForPackageMember(
- descriptor: DeclarationDescriptor,
- externalClassNodes: MutableMap<FqName, DocumentationNode>,
- allFqNames: Collection<FqName>,
- packageName: FqName
- ): DocumentationNode {
- if (descriptor is CallableMemberDescriptor) {
- val extensionClassDescriptor = descriptor.getExtensionClassDescriptor()
- if (extensionClassDescriptor != null && isExtensionForExternalClass(descriptor, extensionClassDescriptor, allFqNames) &&
- !ErrorUtils.isError(extensionClassDescriptor)) {
- val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor)
- return externalClassNodes.getOrPut(fqName) {
- val newNode = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.ExternalClass)
- val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(extensionClassDescriptor)
- if (externalLink != null) {
- newNode.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
- }
- append(newNode, RefKind.Member)
- refGraph.register("${packageName.asString()}:${extensionClassDescriptor.signature()}", newNode)
- newNode
- }
- }
- }
- return this
- }
-
-}
-
-fun DeclarationDescriptor.isDocumented(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean {
- return (passConfiguration.effectivePackageOptions(fqNameSafe).includeNonPublic
- || this !is MemberDescriptor
- || this.visibility.isPublicAPI)
- && !isDocumentationSuppressed(passConfiguration)
- && (!passConfiguration.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated())
-}
-
-private fun DeclarationDescriptor.isGenerated() = this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION
-
-class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
- override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>,
- allFqNames: Collection<FqName>) {
- val externalClassNodes = hashMapOf<FqName, DocumentationNode>()
- declarations.forEach { descriptor ->
- with(documentationBuilder) {
- if (descriptor.isDocumented(passConfiguration)) {
- val parent = packageNode.getParentForPackageMember(
- descriptor,
- externalClassNodes,
- allFqNames,
- packageName
- )
- parent.appendOrUpdateMember(descriptor)
- }
- }
- }
- }
-}
-
-class KotlinJavaDocumentationBuilder
-@Inject constructor(val resolutionFacade: DokkaResolutionFacade,
- val documentationBuilder: DocumentationBuilder,
- val passConfiguration: DokkaConfiguration.PassConfiguration,
- val logger: DokkaLogger) : JavaDocumentationBuilder {
- override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
- val classDescriptors = file.classes.map {
- it.getJavaClassDescriptor(resolutionFacade)
- }
-
- if (classDescriptors.any { it != null && it.isDocumented(passConfiguration) }) {
- val packageNode = findOrCreatePackageNode(module, file.packageName, packageContent, documentationBuilder.refGraph)
-
- for (descriptor in classDescriptors.filterNotNull()) {
- with(documentationBuilder) {
- packageNode.appendChild(descriptor, RefKind.Member)
- }
- }
- }
- }
-}
-
-private val hiddenAnnotations = setOf(
- KotlinBuiltIns.FQ_NAMES.parameterName.asString()
-)
-
-private fun AnnotationDescriptor.isHiddenInDocumentation() =
- type.constructor.declarationDescriptor?.fqNameSafe?.asString() in hiddenAnnotations
-
-private fun AnnotationDescriptor.isDocumented(): Boolean {
- if (source.getPsi() != null && mustBeDocumented()) return true
- val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString()
- return annotationClassName == KotlinBuiltIns.FQ_NAMES.extensionFunctionType.asString()
-}
-
-fun AnnotationDescriptor.mustBeDocumented(): Boolean {
- val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false
- return annotationClass.isDocumentedAnnotation()
-}
-
-fun DeclarationDescriptor.isDocumentationSuppressed(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean {
-
- if (passConfiguration.effectivePackageOptions(fqNameSafe).suppress) return true
-
- val path = this.findPsi()?.containingFile?.virtualFile?.path
- if (path != null) {
- if (path in passConfiguration.suppressedFiles) return true
- }
-
- val doc = findKDoc()
- if (doc is KDocSection && doc.findTagByName("suppress") != null) return true
-
- return hasSuppressDocTag(sourcePsi())
-}
-
-fun DeclarationDescriptor.sourcePsi() =
- ((original as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi
-
-fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any {
- DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated"
-} || (this is ConstructorDescriptor && containingDeclaration.isDeprecated())
-
-fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor? {
- val extensionReceiver = extensionReceiverParameter
- if (extensionReceiver != null) {
- val type = extensionReceiver.type
- val receiverClass = type.constructor.declarationDescriptor as? ClassDescriptor
- if (receiverClass?.isCompanionObject ?: false) {
- return receiverClass?.containingDeclaration as? ClassifierDescriptor
- }
- return receiverClass
- }
- return null
-}
-
-fun DeclarationDescriptor.signature(): String {
- if (this != original) return original.signature()
- return when (this) {
- is ClassDescriptor,
- is PackageFragmentDescriptor,
- is PackageViewDescriptor,
- is TypeAliasDescriptor -> DescriptorUtils.getFqName(this).asString()
-
- is PropertyDescriptor -> containingDeclaration.signature() + "$" + name + receiverSignature()
- is FunctionDescriptor -> containingDeclaration.signature() + "$" + name + parameterSignature()
- is ValueParameterDescriptor -> containingDeclaration.signature() + "/" + name
- is TypeParameterDescriptor -> containingDeclaration.signature() + "*" + name
- is ReceiverParameterDescriptor -> containingDeclaration.signature() + "/" + name
- else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
- }
-}
-
-fun PropertyDescriptor.receiverSignature(): String {
- val receiver = extensionReceiverParameter
- if (receiver != null) {
- return "#" + receiver.type.signature()
- }
- return ""
-}
-
-fun CallableMemberDescriptor.parameterSignature(): String {
- val params = valueParameters.map { it.type }.toMutableList()
- val extensionReceiver = extensionReceiverParameter
- if (extensionReceiver != null) {
- params.add(0, extensionReceiver.type)
- }
- return params.joinToString(prefix = "(", postfix = ")") { it.signature() }
-}
-
-fun KotlinType.signature(): String {
- val visited = hashSetOf<KotlinType>()
-
- fun KotlinType.signatureRecursive(): String {
- if (this in visited) {
- return ""
- }
- visited.add(this)
-
- val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>"
- val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString()
- if (arguments.isEmpty()) {
- return typeName
- }
- return typeName + arguments.joinToString(prefix = "((", postfix = "))") { it.type.signatureRecursive() }
- }
-
- return signatureRecursive()
-}
-
-fun DeclarationDescriptor.signatureWithSourceLocation(): String {
- val signature = signature()
- val sourceLocation = sourceLocation()
- return if (sourceLocation != null) "$signature ($sourceLocation)" else signature
-}
-
-fun DeclarationDescriptor.sourceLocation(): String? {
- val psi = sourcePsi()
- if (psi != null) {
- val fileName = psi.containingFile.name
- val lineNumber = psi.lineNumber()
- return if (lineNumber != null) "$fileName:$lineNumber" else fileName
- }
- return null
-}
-
-fun DocumentationModule.prepareForGeneration(configuration: DokkaConfiguration) {
- if (configuration.generateIndexPages) {
- generateAllTypesNode()
- }
- nodeRefGraph.resolveReferences()
-}
-
-fun DocumentationNode.generateAllTypesNode() {
- val allTypes = members(NodeKind.Package)
- .flatMap { it.members.filter {
- it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass
- || (it.kind == NodeKind.GroupNode && it.origins.all { it.kind in NodeKind.classLike }) } }
- .sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.').toLowerCase() else it.name.toLowerCase() }
-
- val allTypesNode = DocumentationNode("alltypes", Content.Empty, NodeKind.AllTypes)
- for (typeNode in allTypes) {
- allTypesNode.addReferenceTo(typeNode, RefKind.Member)
- }
-
- append(allTypesNode, RefKind.Member)
-}
-
-fun ClassDescriptor.supertypesWithAnyPrecise(): Collection<KotlinType> {
- if (KotlinBuiltIns.isAny(this)) {
- return emptyList()
- }
- return typeConstructor.supertypesWithAny()
-}
-
-fun PassConfiguration.effectivePackageOptions(pack: String): DokkaConfiguration.PackageOptions {
- val rootPackageOptions = PackageOptionsImpl("", includeNonPublic, reportUndocumented, skipDeprecated, false)
- return perPackageOptions.firstOrNull { pack == it.prefix }
- ?: perPackageOptions.firstOrNull { pack.startsWith(it.prefix + ".") }
- ?: rootPackageOptions
-}
-
-fun PassConfiguration.effectivePackageOptions(pack: FqName): DokkaConfiguration.PackageOptions = effectivePackageOptions(pack.asString())
-
diff --git a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
deleted file mode 100644
index bd8b9cf5..00000000
--- a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
+++ /dev/null
@@ -1,305 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.Singleton
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiMethod
-import com.intellij.util.io.*
-import org.jetbrains.dokka.Formats.FileGeneratorBasedFormatDescriptor
-import org.jetbrains.dokka.Formats.FormatDescriptor
-import org.jetbrains.dokka.Utilities.ServiceLocator
-import org.jetbrains.dokka.Utilities.lookup
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.*
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.resolve.DescriptorUtils
-import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
-import org.jetbrains.kotlin.resolve.descriptorUtil.parents
-import java.io.ByteArrayOutputStream
-import java.io.PrintWriter
-import java.net.HttpURLConnection
-import java.net.URL
-import java.net.URLConnection
-import java.nio.file.Path
-import java.nio.file.Paths
-import java.security.MessageDigest
-import javax.inject.Named
-import kotlin.reflect.full.findAnnotation
-
-fun ByteArray.toHexString() = this.joinToString(separator = "") { "%02x".format(it) }
-
-typealias PackageFqNameToLocation = MutableMap<FqName, PackageListProvider.ExternalDocumentationRoot>
-
-@Singleton
-class PackageListProvider @Inject constructor(
- val configuration: DokkaConfiguration,
- val logger: DokkaLogger
-) {
- val storage = mutableMapOf<DokkaConfiguration.ExternalDocumentationLink, PackageFqNameToLocation>()
-
- val cacheDir: Path? = when {
- configuration.cacheRoot == "default" -> Paths.get(System.getProperty("user.home"), ".cache", "dokka")
- configuration.cacheRoot != null -> Paths.get(configuration.cacheRoot)
- else -> null
- }?.resolve("packageListCache")?.apply { toFile().mkdirs() }
-
- val cachedProtocols = setOf("http", "https", "ftp")
-
- init {
- for (conf in configuration.passesConfigurations) {
- for (link in conf.externalDocumentationLinks) {
- if (link in storage) {
- continue
- }
-
- try {
- loadPackageList(link)
- } catch (e: Exception) {
- throw RuntimeException("Exception while loading package-list from $link", e)
- }
- }
-
- }
- }
-
-
-
- fun URL.doOpenConnectionToReadContent(timeout: Int = 10000, redirectsAllowed: Int = 16): URLConnection {
- val connection = this.openConnection()
- connection.connectTimeout = timeout
- connection.readTimeout = timeout
-
- when (connection) {
- is HttpURLConnection -> {
- return when (connection.responseCode) {
- in 200..299 -> {
- connection
- }
- HttpURLConnection.HTTP_MOVED_PERM,
- HttpURLConnection.HTTP_MOVED_TEMP,
- HttpURLConnection.HTTP_SEE_OTHER -> {
- if (redirectsAllowed > 0) {
- val newUrl = connection.getHeaderField("Location")
- URL(newUrl).doOpenConnectionToReadContent(timeout, redirectsAllowed - 1)
- } else {
- throw RuntimeException("Too many redirects")
- }
- }
- else -> {
- throw RuntimeException("Unhandled http code: ${connection.responseCode}")
- }
- }
- }
- else -> return connection
- }
- }
-
- fun loadPackageList(link: DokkaConfiguration.ExternalDocumentationLink) {
-
- val packageListUrl = link.packageListUrl
- val needsCache = packageListUrl.protocol in cachedProtocols
-
- val packageListStream = if (cacheDir != null && needsCache) {
- val packageListLink = packageListUrl.toExternalForm()
-
- val digest = MessageDigest.getInstance("SHA-256")
- val hash = digest.digest(packageListLink.toByteArray(Charsets.UTF_8)).toHexString()
- val cacheEntry = cacheDir.resolve(hash).toFile()
-
- if (cacheEntry.exists()) {
- try {
- val connection = packageListUrl.doOpenConnectionToReadContent()
- val originModifiedDate = connection.date
- val cacheDate = cacheEntry.lastModified()
- if (originModifiedDate > cacheDate || originModifiedDate == 0L) {
- if (originModifiedDate == 0L)
- logger.warn("No date header for $packageListUrl, downloading anyway")
- else
- logger.info("Renewing package-list from $packageListUrl")
- connection.getInputStream().copyTo(cacheEntry.outputStream())
- }
- } catch (e: Exception) {
- logger.error("Failed to update package-list cache for $link")
- val baos = ByteArrayOutputStream()
- PrintWriter(baos).use {
- e.printStackTrace(it)
- }
- baos.flush()
- logger.error(baos.toString())
- }
- } else {
- logger.info("Downloading package-list from $packageListUrl")
- packageListUrl.openStream().copyTo(cacheEntry.outputStream())
- }
- cacheEntry.inputStream()
- } else {
- packageListUrl.doOpenConnectionToReadContent().getInputStream()
- }
-
- val (params, packages) =
- packageListStream
- .bufferedReader()
- .useLines { lines -> lines.partition { it.startsWith(ExternalDocumentationLinkResolver.DOKKA_PARAM_PREFIX) } }
-
- val paramsMap = params.asSequence()
- .map { it.removePrefix(ExternalDocumentationLinkResolver.DOKKA_PARAM_PREFIX).split(":", limit = 2) }
- .groupBy({ (key, _) -> key }, { (_, value) -> value })
-
- val format = paramsMap["format"]?.singleOrNull() ?: "javadoc"
-
- val locations = paramsMap["location"].orEmpty()
- .map { it.split("\u001f", limit = 2) }
- .map { (key, value) -> key to value }
- .toMap()
-
-
- val defaultResolverDesc = ExternalDocumentationLinkResolver.services.getValue("dokka-default")
- val resolverDesc = ExternalDocumentationLinkResolver.services[format]
- ?: defaultResolverDesc.takeIf { format in formatsWithDefaultResolver }
- ?: defaultResolverDesc.also {
- logger.warn("Couldn't find InboundExternalLinkResolutionService(format = `$format`) for $link, using Dokka default")
- }
-
-
- val resolverClass = javaClass.classLoader.loadClass(resolverDesc.className).kotlin
-
- val constructors = resolverClass.constructors
-
- val constructor = constructors.singleOrNull()
- ?: constructors.first { it.findAnnotation<Inject>() != null }
- val resolver = constructor.call(paramsMap) as InboundExternalLinkResolutionService
-
- val rootInfo = ExternalDocumentationRoot(link.url, resolver, locations)
-
- val packageFqNameToLocation = mutableMapOf<FqName, ExternalDocumentationRoot>()
- storage[link] = packageFqNameToLocation
-
- val fqNames = packages.map { FqName(it) }
- for(name in fqNames) {
- packageFqNameToLocation[name] = rootInfo
- }
- }
-
-
-
- class ExternalDocumentationRoot(val rootUrl: URL, val resolver: InboundExternalLinkResolutionService, val locations: Map<String, String>) {
- override fun toString(): String = rootUrl.toString()
- }
-
- companion object {
- private val formatsWithDefaultResolver =
- ServiceLocator
- .allServices("format")
- .filter {
- val desc = ServiceLocator.lookup<FormatDescriptor>(it) as? FileGeneratorBasedFormatDescriptor
- desc?.generatorServiceClass == FileGenerator::class
- }.map { it.name }
- .toSet()
-
- }
-
-}
-
-class ExternalDocumentationLinkResolver @Inject constructor(
- val configuration: DokkaConfiguration,
- val passConfiguration: DokkaConfiguration.PassConfiguration,
- @Named("libraryResolutionFacade") val libraryResolutionFacade: DokkaResolutionFacade,
- val logger: DokkaLogger,
- val packageListProvider: PackageListProvider
-) {
-
- val formats = mutableMapOf<String, InboundExternalLinkResolutionService>()
- val packageFqNameToLocation = mutableMapOf<FqName, PackageListProvider.ExternalDocumentationRoot>()
-
- init {
- val fqNameToLocationMaps = passConfiguration.externalDocumentationLinks
- .mapNotNull { packageListProvider.storage[it] }
-
- for(map in fqNameToLocationMaps) {
- packageFqNameToLocation.putAll(map)
- }
- }
-
- fun buildExternalDocumentationLink(element: PsiElement): String? {
- return element.extractDescriptor(libraryResolutionFacade)?.let {
- buildExternalDocumentationLink(it)
- }
- }
-
- fun buildExternalDocumentationLink(symbol: DeclarationDescriptor): String? {
- val packageFqName: FqName =
- when (symbol) {
- is PackageFragmentDescriptor -> symbol.fqName
- is DeclarationDescriptorNonRoot -> symbol.parents.firstOrNull { it is PackageFragmentDescriptor }?.fqNameSafe ?: return null
- else -> return null
- }
-
- val externalLocation = packageFqNameToLocation[packageFqName] ?: return null
-
- val path = externalLocation.locations[symbol.signature()] ?:
- externalLocation.resolver.getPath(symbol) ?: return null
-
- return URL(externalLocation.rootUrl, path).toExternalForm()
- }
-
- companion object {
- const val DOKKA_PARAM_PREFIX = "\$dokka."
- val services = ServiceLocator.allServices("inbound-link-resolver").associateBy { it.name }
- }
-}
-
-
-interface InboundExternalLinkResolutionService {
- fun getPath(symbol: DeclarationDescriptor): String?
-
- class Javadoc(paramsMap: Map<String, List<String>>) : InboundExternalLinkResolutionService {
- override fun getPath(symbol: DeclarationDescriptor): String? {
- if (symbol is EnumEntrySyntheticClassDescriptor) {
- return getPath(symbol.containingDeclaration)?.let { it + "#" + symbol.name.asString() }
- } else if (symbol is JavaClassDescriptor) {
- return DescriptorUtils.getFqName(symbol).asString().replace(".", "/") + ".html"
- } else if (symbol is JavaCallableMemberDescriptor) {
- val containingClass = symbol.containingDeclaration as? JavaClassDescriptor ?: return null
- val containingClassLink = getPath(containingClass)
- if (containingClassLink != null) {
- if (symbol is JavaMethodDescriptor || symbol is JavaClassConstructorDescriptor) {
- val psi = symbol.sourcePsi() as? PsiMethod
- if (psi != null) {
- val params = psi.parameterList.parameters.joinToString { it.type.canonicalText }
- return containingClassLink + "#" + symbol.name + "(" + params + ")"
- }
- } else if (symbol is JavaPropertyDescriptor) {
- return "$containingClassLink#${symbol.name}"
- }
- }
- }
- // TODO Kotlin javadoc
- return null
- }
- }
-
- class Dokka(val paramsMap: Map<String, List<String>>) : InboundExternalLinkResolutionService {
- val extension = paramsMap["linkExtension"]?.singleOrNull() ?: error("linkExtension not provided for Dokka resolver")
-
- override fun getPath(symbol: DeclarationDescriptor): String? {
- val leafElement = when (symbol) {
- is CallableDescriptor, is TypeAliasDescriptor -> true
- else -> false
- }
- val path = getPathWithoutExtension(symbol)
- if (leafElement) return "$path.$extension"
- else return "$path/index.$extension"
- }
-
- private fun getPathWithoutExtension(symbol: DeclarationDescriptor): String {
- return when {
- symbol.containingDeclaration == null -> identifierToFilename(symbol.name.asString())
- symbol is PackageFragmentDescriptor -> identifierToFilename(symbol.fqName.asString())
- else -> getPathWithoutExtension(symbol.containingDeclaration!!) + '/' + identifierToFilename(symbol.name.asString())
- }
- }
-
- }
-}
-
diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt
deleted file mode 100644
index ee9d8c51..00000000
--- a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.psi.JavaPsiFacade
-import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiNamedElement
-import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser
-import org.jetbrains.kotlin.asJava.elements.KtLightElement
-import org.jetbrains.kotlin.asJava.elements.KtLightMethod
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.lexer.KtTokens
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.KtClass
-import org.jetbrains.kotlin.psi.KtDeclaration
-import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.psi.KtPropertyAccessor
-
-class KotlinAsJavaDocumentationBuilder
- @Inject constructor(val kotlinAsJavaDocumentationParser: KotlinAsJavaDocumentationParser) : PackageDocumentationBuilder
-{
- override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>,
- allFqNames: Collection<FqName>) {
- val project = documentationBuilder.resolutionFacade.project
- val psiPackage = JavaPsiFacade.getInstance(project).findPackage(packageName.asString())
- if (psiPackage == null) {
- documentationBuilder.logger.error("Cannot find Java package by qualified name: ${packageName.asString()}")
- return
- }
-
- val javaDocumentationBuilder = JavaPsiDocumentationBuilder(documentationBuilder.passConfiguration,
- documentationBuilder.refGraph,
- kotlinAsJavaDocumentationParser)
-
- psiPackage.classes.filter { it is KtLightElement<*, *> }.filter { it.isVisibleInDocumentation() }.forEach {
- javaDocumentationBuilder.appendClasses(packageNode, arrayOf(it))
- }
- }
-
- fun PsiClass.isVisibleInDocumentation(): Boolean {
- val origin: KtDeclaration = (this as KtLightElement<*, *>).kotlinOrigin as? KtDeclaration ?: return true
-
- return !origin.hasModifier(KtTokens.INTERNAL_KEYWORD) && !origin.hasModifier(KtTokens.PRIVATE_KEYWORD)
- }
-}
-
-class KotlinAsJavaDocumentationParser
- @Inject constructor(val resolutionFacade: DokkaResolutionFacade,
- val descriptorDocumentationParser: DescriptorDocumentationParser) : JavaDocumentationParser
-{
- override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
- val kotlinLightElement = element as? KtLightElement<*, *> ?: return JavadocParseResult.Empty
- val origin = kotlinLightElement.kotlinOrigin as? KtDeclaration ?: return JavadocParseResult.Empty
- if (origin is KtParameter) {
- // LazyDeclarationResolver does not support setter parameters
- val grandFather = origin.parent?.parent
- if (grandFather is KtPropertyAccessor) {
- return JavadocParseResult.Empty
- }
- }
- val isDefaultNoArgConstructor = kotlinLightElement is KtLightMethod && origin is KtClass
- val descriptor = resolutionFacade.resolveToDescriptor(origin)
- val content = descriptorDocumentationParser.parseDocumentation(descriptor, origin is KtParameter, isDefaultNoArgConstructor)
- return JavadocParseResult(content, null)
- }
-}
diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaElementSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaElementSignatureProvider.kt
deleted file mode 100644
index 20ea179e..00000000
--- a/core/src/main/kotlin/Kotlin/KotlinAsJavaElementSignatureProvider.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.PsiElement
-import org.jetbrains.kotlin.asJava.toLightElements
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.psi.KtElement
-
-class KotlinAsJavaElementSignatureProvider : ElementSignatureProvider {
-
- private fun PsiElement.javaLikePsi() = when {
- this is KtElement -> toLightElements().firstOrNull()
- else -> this
- }
-
- override fun signature(forPsi: PsiElement): String {
- return getSignature(forPsi.javaLikePsi()) ?:
- "not implemented for $forPsi"
- }
-
- override fun signature(forDesc: DeclarationDescriptor): String {
- val sourcePsi = forDesc.sourcePsi()
- return getSignature(sourcePsi?.javaLikePsi()) ?:
- "not implemented for $forDesc with psi: $sourcePsi"
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
deleted file mode 100644
index c7187b23..00000000
--- a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiMember
-import com.intellij.psi.PsiPackage
-import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
-import org.jetbrains.kotlin.asJava.elements.KtLightElement
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.resolve.BindingContext
-import javax.inject.Inject
-
-class KotlinElementSignatureProvider @Inject constructor(
- val resolutionFacade: DokkaResolutionFacade
-) : ElementSignatureProvider {
- override fun signature(forPsi: PsiElement): String {
- return forPsi.extractDescriptor(resolutionFacade)
- ?.let { signature(it) }
- ?: run { "no desc for $forPsi in ${(forPsi as? PsiMember)?.containingClass}" }
- }
-
- override fun signature(forDesc: DeclarationDescriptor): String = forDesc.signature()
-}
-
-
-fun PsiElement.extractDescriptor(resolutionFacade: DokkaResolutionFacade): DeclarationDescriptor? =
- when (val forPsi = this) {
- is KtLightClassForFacade -> resolutionFacade.moduleDescriptor.getPackage(forPsi.fqName)
- is KtLightElement<*, *> -> (forPsi.kotlinOrigin!!).extractDescriptor(resolutionFacade)
- is PsiPackage -> resolutionFacade.moduleDescriptor.getPackage(FqName(forPsi.qualifiedName))
- is PsiMember -> forPsi.getJavaOrKotlinMemberDescriptor(resolutionFacade)
- else -> resolutionFacade.resolveSession.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, forPsi]
- }
diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
deleted file mode 100644
index 7310610f..00000000
--- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
+++ /dev/null
@@ -1,473 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.LanguageService.RenderMode
-
-/**
- * Implements [LanguageService] and provides rendering of symbols in Kotlin language
- */
-class KotlinLanguageService : CommonLanguageService() {
- override fun showModifierInSummary(node: DocumentationNode): Boolean {
- return node.name !in fullOnlyModifiers
- }
-
- private val fullOnlyModifiers =
- setOf("public", "protected", "private", "internal", "inline", "noinline", "crossinline", "reified")
-
- override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
- return content {
- when (node.kind) {
- NodeKind.Package -> if (renderMode == RenderMode.FULL) renderPackage(node)
- in NodeKind.classLike -> renderClass(node, renderMode)
-
- NodeKind.EnumItem,
- NodeKind.ExternalClass -> if (renderMode == RenderMode.FULL) identifier(node.name)
-
- NodeKind.Parameter -> renderParameter(node, renderMode)
- NodeKind.TypeParameter -> renderTypeParameter(node, renderMode)
- NodeKind.Type,
- NodeKind.UpperBound -> renderType(node, renderMode)
-
- NodeKind.Modifier -> renderModifier(this, node, renderMode)
- NodeKind.Constructor,
- NodeKind.Function,
- NodeKind.CompanionObjectFunction -> renderFunction(node, renderMode)
- NodeKind.Property,
- NodeKind.CompanionObjectProperty -> renderProperty(node, renderMode)
- else -> identifier(node.name)
- }
- }
- }
-
-
- override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? {
- if (nodes.size < 2) return null
- val receiverKind = nodes.getReceiverKind() ?: return null
- val functionWithTypeParameter = nodes.firstOrNull { it.details(NodeKind.TypeParameter).any() } ?: return null
- return content {
- val typeParameter = functionWithTypeParameter.details(NodeKind.TypeParameter).first()
- if (functionWithTypeParameter.kind == NodeKind.Function) {
- renderFunction(
- functionWithTypeParameter,
- RenderMode.SUMMARY,
- SummarizingMapper(receiverKind, typeParameter.name)
- )
- } else {
- renderProperty(
- functionWithTypeParameter,
- RenderMode.SUMMARY,
- SummarizingMapper(receiverKind, typeParameter.name)
- )
- }
- }
- }
-
- private fun List<DocumentationNode>.getReceiverKind(): ReceiverKind? {
- val qNames = mapNotNull { it.getReceiverQName() }
- if (qNames.size != size)
- return null
-
- return ReceiverKind.values().firstOrNull { kind -> qNames.all { it in kind.classes } }
- }
-
- private fun DocumentationNode.getReceiverQName(): String? {
- if (kind != NodeKind.Function && kind != NodeKind.Property) return null
- val receiver = details(NodeKind.Receiver).singleOrNull() ?: return null
- return receiver.detail(NodeKind.Type).qualifiedNameFromType()
- }
-
- companion object {
- private val arrayClasses = setOf(
- "kotlin.Array",
- "kotlin.BooleanArray",
- "kotlin.ByteArray",
- "kotlin.CharArray",
- "kotlin.ShortArray",
- "kotlin.IntArray",
- "kotlin.LongArray",
- "kotlin.FloatArray",
- "kotlin.DoubleArray"
- )
-
- private val arrayOrListClasses = setOf("kotlin.List") + arrayClasses
-
- private val iterableClasses = setOf(
- "kotlin.Collection",
- "kotlin.Sequence",
- "kotlin.Iterable",
- "kotlin.Map",
- "kotlin.String",
- "kotlin.CharSequence"
- ) + arrayOrListClasses
- }
-
- private enum class ReceiverKind(val receiverName: String, val classes: Collection<String>) {
- ARRAY("any_array", arrayClasses),
- ARRAY_OR_LIST("any_array_or_list", arrayOrListClasses),
- ITERABLE("any_iterable", iterableClasses),
- }
-
- interface SignatureMapper {
- fun renderReceiver(receiver: DocumentationNode, to: ContentBlock)
- }
-
- private class SummarizingMapper(val kind: ReceiverKind, val typeParameterName: String) : SignatureMapper {
- override fun renderReceiver(receiver: DocumentationNode, to: ContentBlock) {
- to.append(ContentIdentifier(kind.receiverName, IdentifierKind.SummarizedTypeName))
- to.text("<$typeParameterName>")
- }
- }
-
- private fun ContentBlock.renderFunctionalTypeParameterName(node: DocumentationNode, renderMode: RenderMode) {
- node.references(RefKind.HiddenAnnotation).map { it.to }
- .find { it.name == "ParameterName" }?.let {
- val parameterNameValue = it.detail(NodeKind.Parameter).detail(NodeKind.Value)
- identifier(parameterNameValue.name.removeSurrounding("\""), IdentifierKind.ParameterName)
- symbol(":")
- nbsp()
- }
- }
-
- private fun ContentBlock.renderFunctionalType(node: DocumentationNode, renderMode: RenderMode) {
- var typeArguments = node.details(NodeKind.Type)
-
- if (node.name.startsWith("Suspend")) {
- keyword("suspend ")
- }
-
- // lambda
- val isExtension = node.annotations.any { it.name == "ExtensionFunctionType" }
- if (isExtension) {
- renderType(typeArguments.first(), renderMode)
- symbol(".")
- typeArguments = typeArguments.drop(1)
- }
- symbol("(")
- renderList(typeArguments.take(typeArguments.size - 1), noWrap = true) {
- renderFunctionalTypeParameterName(it, renderMode)
- renderType(it, renderMode)
- }
- symbol(")")
- nbsp()
- symbol("->")
- nbsp()
- renderType(typeArguments.last(), renderMode)
-
- }
-
- private fun DocumentationNode.isFunctionalType(): Boolean {
- val typeArguments = details(NodeKind.Type)
- val functionalTypeName = "Function${typeArguments.count() - 1}"
- val suspendFunctionalTypeName = "Suspend$functionalTypeName"
- return name == functionalTypeName || name == suspendFunctionalTypeName
- }
-
- private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) {
- if (node.name == "dynamic") {
- keyword("dynamic")
- return
- }
-
- val nullabilityModifier = node.detailOrNull(NodeKind.NullabilityModifier)
-
- if (node.isFunctionalType()) {
- if (nullabilityModifier != null) {
- symbol("(")
- renderFunctionalType(node, renderMode)
- symbol(")")
- symbol(nullabilityModifier.name)
- } else {
- renderFunctionalType(node, renderMode)
- }
- return
- }
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode, true)
- renderLinked(this, node) {
- identifier(it.typeDeclarationClass?.classNodeNameWithOuterClass() ?: it.name, IdentifierKind.TypeName)
- }
- val typeArguments = node.details(NodeKind.Type)
- if (typeArguments.isNotEmpty()) {
- symbol("<")
- renderList(typeArguments, noWrap = true) {
- renderType(it, renderMode)
- }
- symbol(">")
- }
-
- nullabilityModifier ?.apply {
- symbol(nullabilityModifier.name)
- }
- }
-
- override fun renderModifier(
- block: ContentBlock,
- node: DocumentationNode,
- renderMode: RenderMode,
- nowrap: Boolean
- ) {
- when (node.name) {
- "final", "public", "var", "expect", "actual", "external" -> {
- }
- else -> {
- if (showModifierInSummary(node) || renderMode == RenderMode.FULL) {
- super.renderModifier(block, node, renderMode, nowrap)
- }
- }
- }
- }
-
- private fun ContentBlock.renderTypeParameter(node: DocumentationNode, renderMode: RenderMode) {
- renderModifiersForNode(node, renderMode, true)
-
- identifier(node.name)
-
- val constraints = node.details(NodeKind.UpperBound)
- if (constraints.size == 1) {
- nbsp()
- symbol(":")
- nbsp()
- renderList(constraints, noWrap = true) {
- renderType(it, renderMode)
- }
- }
- }
-
- private fun ContentBlock.renderParameter(node: DocumentationNode, renderMode: RenderMode) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- identifier(node.name, IdentifierKind.ParameterName, node.detailOrNull(NodeKind.Signature)?.name)
- symbol(":")
- nbsp()
- val parameterType = node.detail(NodeKind.Type)
- renderType(parameterType, renderMode)
- val valueNode = node.details(NodeKind.Value).firstOrNull()
- if (valueNode != null) {
- nbsp()
- symbol("=")
- nbsp()
- text(valueNode.name)
- }
- }
-
- private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode, renderMode: RenderMode) {
- val typeParameters = node.details(NodeKind.TypeParameter)
- if (typeParameters.any()) {
- symbol("<")
- renderList(typeParameters) {
- renderTypeParameter(it, renderMode)
- }
- symbol(">")
- }
- }
-
- private fun ContentBlock.renderExtraTypeParameterConstraints(node: DocumentationNode, renderMode: RenderMode) {
- val parametersWithMultipleConstraints =
- node.details(NodeKind.TypeParameter).filter { it.details(NodeKind.UpperBound).size > 1 }
- val parametersWithConstraints = parametersWithMultipleConstraints
- .flatMap { parameter ->
- parameter.details(NodeKind.UpperBound).map { constraint -> parameter to constraint }
- }
- if (parametersWithMultipleConstraints.isNotEmpty()) {
- keyword(" where ")
- renderList(parametersWithConstraints) {
- identifier(it.first.name)
- nbsp()
- symbol(":")
- nbsp()
- renderType(it.second, renderMode)
- }
- }
- }
-
- private fun ContentBlock.renderSupertypesForNode(node: DocumentationNode, renderMode: RenderMode) {
- val supertypes = node.details(NodeKind.Supertype).filterNot { it.qualifiedNameFromType() in ignoredSupertypes }
- if (supertypes.any()) {
- nbsp()
- symbol(":")
- nbsp()
- renderList(supertypes) {
- indentedSoftLineBreak()
- renderType(it, renderMode)
- }
- }
- }
-
- private fun ContentBlock.renderAnnotationsForNode(node: DocumentationNode) {
- node.annotations.forEach {
- renderAnnotation(it)
- }
- }
-
- private fun ContentBlock.renderAnnotation(node: DocumentationNode) {
- identifier("@" + node.name, IdentifierKind.AnnotationName)
- val parameters = node.details(NodeKind.Parameter)
- if (!parameters.isEmpty()) {
- symbol("(")
- renderList(parameters) {
- text(it.detail(NodeKind.Value).name)
- }
- symbol(")")
- }
- text(" ")
- }
-
- private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- NodeKind.Class,
- NodeKind.AnnotationClass,
- NodeKind.Exception,
- NodeKind.Enum -> keyword("class ")
- NodeKind.Interface -> keyword("interface ")
- NodeKind.EnumItem -> keyword("enum val ")
- NodeKind.Object -> keyword("object ")
- NodeKind.TypeAlias -> keyword("typealias ")
- else -> throw IllegalArgumentException("Node $node is not a class-like object")
- }
-
- identifierOrDeprecated(node)
- renderTypeParametersForNode(node, renderMode)
- renderSupertypesForNode(node, renderMode)
- renderExtraTypeParameterConstraints(node, renderMode)
-
- if (node.kind == NodeKind.TypeAlias) {
- nbsp()
- symbol("=")
- nbsp()
- renderType(node.detail(NodeKind.TypeAliasUnderlyingType), renderMode)
- }
- }
-
- private fun ContentBlock.renderFunction(
- node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null
- ) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- NodeKind.Constructor -> identifier(node.owner!!.name)
- NodeKind.Function,
- NodeKind.CompanionObjectFunction -> keyword("fun ")
- else -> throw IllegalArgumentException("Node $node is not a function-like object")
- }
- renderTypeParametersForNode(node, renderMode)
- if (node.details(NodeKind.TypeParameter).any()) {
- text(" ")
- }
-
- renderReceiver(node, renderMode, signatureMapper)
-
- if (node.kind != NodeKind.Constructor)
- identifierOrDeprecated(node)
-
- symbol("(")
- val parameters = node.details(NodeKind.Parameter)
- renderList(parameters) {
- indentedSoftLineBreak()
- renderParameter(it, renderMode)
- }
- if (needReturnType(node)) {
- if (parameters.isNotEmpty()) {
- softLineBreak()
- }
- symbol(")")
- symbol(": ")
- renderType(node.detail(NodeKind.Type), renderMode)
- } else {
- symbol(")")
- }
- renderExtraTypeParameterConstraints(node, renderMode)
- }
-
- private fun ContentBlock.renderReceiver(
- node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper?
- ) {
- val receiver = node.details(NodeKind.Receiver).singleOrNull()
- if (receiver != null) {
- if (signatureMapper != null) {
- signatureMapper.renderReceiver(receiver, this)
- } else {
- val type = receiver.detail(NodeKind.Type)
-
- if (type.isFunctionalType()) {
- symbol("(")
- renderFunctionalType(type, renderMode)
- symbol(")")
- } else {
- renderType(type, renderMode)
- }
- }
- symbol(".")
- }
- }
-
- private fun needReturnType(node: DocumentationNode) = when (node.kind) {
- NodeKind.Constructor -> false
- else -> !node.isUnitReturnType()
- }
-
- fun DocumentationNode.isUnitReturnType(): Boolean =
- detail(NodeKind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit"
-
- private fun ContentBlock.renderProperty(
- node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null
- ) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- NodeKind.Property,
- NodeKind.CompanionObjectProperty -> keyword("${node.getPropertyKeyword()} ")
- else -> throw IllegalArgumentException("Node $node is not a property")
- }
- renderTypeParametersForNode(node, renderMode)
- if (node.details(NodeKind.TypeParameter).any()) {
- text(" ")
- }
-
- renderReceiver(node, renderMode, signatureMapper)
-
- identifierOrDeprecated(node)
- symbol(": ")
- renderType(node.detail(NodeKind.Type), renderMode)
- renderExtraTypeParameterConstraints(node, renderMode)
- }
-
- fun DocumentationNode.getPropertyKeyword() =
- if (details(NodeKind.Modifier).any { it.name == "var" }) "var" else "val"
-
- fun ContentBlock.identifierOrDeprecated(node: DocumentationNode) {
- if (node.deprecation != null) {
- val strike = ContentStrikethrough()
- strike.identifier(node.name)
- append(strike)
- } else {
- identifier(node.name)
- }
- }
-}
-
-fun DocumentationNode.qualifiedNameFromType(): String {
- return details.firstOrNull { it.kind == NodeKind.QualifiedName }?.name
- ?: (links.firstOrNull() ?: hiddenLinks.firstOrNull())?.qualifiedName()
- ?: name
-}
-
-
-val DocumentationNode.typeDeclarationClass
- get() = (links.firstOrNull { it.kind in NodeKind.classLike } ?: externalType)
diff --git a/core/src/main/kotlin/Languages/CommonLanguageService.kt b/core/src/main/kotlin/Languages/CommonLanguageService.kt
deleted file mode 100644
index ddc95d32..00000000
--- a/core/src/main/kotlin/Languages/CommonLanguageService.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.jetbrains.dokka
-
-
-abstract class CommonLanguageService : LanguageService {
-
- protected fun ContentBlock.renderPackage(node: DocumentationNode) {
- keyword("package")
- nbsp()
- identifier(node.name)
- }
-
- override fun renderName(node: DocumentationNode): String {
- return when (node.kind) {
- NodeKind.Constructor -> node.owner!!.name
- else -> node.name
- }
- }
-
- open fun renderModifier(
- block: ContentBlock,
- node: DocumentationNode,
- renderMode: LanguageService.RenderMode,
- nowrap: Boolean = false
- ) = with(block) {
- keyword(node.name)
- if (nowrap) {
- nbsp()
- } else {
- text(" ")
- }
- }
-
- protected fun renderLinked(
- block: ContentBlock,
- node: DocumentationNode,
- body: ContentBlock.(DocumentationNode) -> Unit
- ) = with(block) {
- val to = node.links.firstOrNull()
- if (to == null)
- body(node)
- else
- link(to) {
- this.body(node)
- }
- }
-
- protected fun <T> ContentBlock.renderList(
- nodes: List<T>, separator: String = ", ",
- noWrap: Boolean = false, renderItem: (T) -> Unit
- ) {
- if (nodes.none())
- return
- renderItem(nodes.first())
- nodes.drop(1).forEach {
- if (noWrap) {
- symbol(separator.removeSuffix(" "))
- nbsp()
- } else {
- symbol(separator)
- }
- renderItem(it)
- }
- }
-
- abstract fun showModifierInSummary(node: DocumentationNode): Boolean
-
- protected fun ContentBlock.renderModifiersForNode(
- node: DocumentationNode,
- renderMode: LanguageService.RenderMode,
- nowrap: Boolean = false
- ) {
- val modifiers = node.details(NodeKind.Modifier)
- for (it in modifiers) {
- if (node.kind == NodeKind.Interface && it.name == "abstract")
- continue
- if (renderMode == LanguageService.RenderMode.SUMMARY && !showModifierInSummary(it)) {
- continue
- }
- renderModifier(this, it, renderMode, nowrap)
- }
- }
-
-
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Languages/JavaLanguageService.kt b/core/src/main/kotlin/Languages/JavaLanguageService.kt
deleted file mode 100644
index ad66123b..00000000
--- a/core/src/main/kotlin/Languages/JavaLanguageService.kt
+++ /dev/null
@@ -1,171 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.LanguageService.RenderMode
-
-/**
- * Implements [LanguageService] and provides rendering of symbols in Java language
- */
-class JavaLanguageService : LanguageService {
- override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
- return ContentText(when (node.kind) {
- NodeKind.Package -> renderPackage(node)
- in NodeKind.classLike -> renderClass(node)
-
- NodeKind.TypeParameter -> renderTypeParameter(node)
- NodeKind.Type,
- NodeKind.UpperBound -> renderType(node)
-
- NodeKind.Constructor,
- NodeKind.Function -> renderFunction(node)
- NodeKind.Property -> renderProperty(node)
- else -> "${node.kind}: ${node.name}"
- })
- }
-
- override fun renderName(node: DocumentationNode): String {
- return when (node.kind) {
- NodeKind.Constructor -> node.owner!!.name
- else -> node.name
- }
- }
-
- override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? = null
-
- private fun renderPackage(node: DocumentationNode): String {
- return "package ${node.name}"
- }
-
- private fun renderModifier(node: DocumentationNode): String {
- return when (node.name) {
- "open" -> ""
- "internal" -> ""
- else -> node.name
- }
- }
-
- fun getArrayElementType(node: DocumentationNode): DocumentationNode? = when (node.qualifiedName()) {
- "kotlin.Array" ->
- node.details(NodeKind.Type).singleOrNull()?.let { et -> getArrayElementType(et) ?: et } ?:
- DocumentationNode("Object", node.content, NodeKind.ExternalClass)
-
- "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
- "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
- DocumentationNode(node.name.removeSuffix("Array").toLowerCase(), node.content, NodeKind.Type)
-
- else -> null
- }
-
- fun getArrayDimension(node: DocumentationNode): Int = when (node.qualifiedName()) {
- "kotlin.Array" ->
- 1 + (node.details(NodeKind.Type).singleOrNull()?.let { getArrayDimension(it) } ?: 0)
-
- "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
- "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
- 1
- else -> 0
- }
-
- fun renderType(node: DocumentationNode): String {
- return when (node.name) {
- "Unit" -> "void"
- "Int" -> "int"
- "Long" -> "long"
- "Double" -> "double"
- "Float" -> "float"
- "Char" -> "char"
- "Boolean" -> "bool"
- // TODO: render arrays
- else -> node.name
- }
- }
-
- private fun renderTypeParameter(node: DocumentationNode): String {
- val constraints = node.details(NodeKind.UpperBound)
- return if (constraints.none())
- node.name
- else {
- node.name + " extends " + constraints.joinToString { renderType(node) }
- }
- }
-
- private fun renderParameter(node: DocumentationNode): String {
- return "${renderType(node.detail(NodeKind.Type))} ${node.name}"
- }
-
- private fun renderTypeParametersForNode(node: DocumentationNode): String {
- return StringBuilder().apply {
- val typeParameters = node.details(NodeKind.TypeParameter)
- if (typeParameters.any()) {
- append("<")
- append(typeParameters.joinToString { renderTypeParameter(it) })
- append("> ")
- }
- }.toString()
- }
-
- private fun renderModifiersForNode(node: DocumentationNode): String {
- val modifiers = node.details(NodeKind.Modifier).map { renderModifier(it) }.filter { it != "" }
- if (modifiers.none())
- return ""
- return modifiers.joinToString(" ", postfix = " ")
- }
-
- private fun renderClass(node: DocumentationNode): String {
- return StringBuilder().apply {
- when (node.kind) {
- NodeKind.Class -> append("class ")
- NodeKind.Interface -> append("interface ")
- NodeKind.Enum -> append("enum ")
- NodeKind.EnumItem -> append("enum value ")
- NodeKind.Object -> append("class ")
- else -> throw IllegalArgumentException("Node $node is not a class-like object")
- }
-
- append(node.name)
- append(renderTypeParametersForNode(node))
- }.toString()
- }
-
- private fun renderFunction(node: DocumentationNode): String {
- return StringBuilder().apply {
- when (node.kind) {
- NodeKind.Constructor -> append(node.owner?.name)
- NodeKind.Function -> {
- append(renderTypeParametersForNode(node))
- append(renderType(node.detail(NodeKind.Type)))
- append(" ")
- append(node.name)
- }
- else -> throw IllegalArgumentException("Node $node is not a function-like object")
- }
-
- val receiver = node.details(NodeKind.Receiver).singleOrNull()
- append("(")
- if (receiver != null)
- (listOf(receiver) + node.details(NodeKind.Parameter)).joinTo(this) { renderParameter(it) }
- else
- node.details(NodeKind.Parameter).joinTo(this) { renderParameter(it) }
-
- append(")")
- }.toString()
- }
-
- private fun renderProperty(node: DocumentationNode): String {
- return StringBuilder().apply {
- when (node.kind) {
- NodeKind.Property -> append("val ")
- else -> throw IllegalArgumentException("Node $node is not a property")
- }
- append(renderTypeParametersForNode(node))
- val receiver = node.details(NodeKind.Receiver).singleOrNull()
- if (receiver != null) {
- append(renderType(receiver.detail(NodeKind.Type)))
- append(".")
- }
-
- append(node.name)
- append(": ")
- append(renderType(node.detail(NodeKind.Type)))
- }.toString()
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Languages/LanguageService.kt b/core/src/main/kotlin/Languages/LanguageService.kt
deleted file mode 100644
index b0f4bbc9..00000000
--- a/core/src/main/kotlin/Languages/LanguageService.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.jetbrains.dokka
-
-/**
- * Provides facility for rendering [DocumentationNode] as a language-dependent declaration
- */
-interface LanguageService {
- enum class RenderMode {
- /** Brief signature (used in a list of all members of the class). */
- SUMMARY,
- /** Full signature (used in the page describing the member itself */
- FULL
- }
-
- /**
- * Renders a [node] as a class, function, property or other signature in a target language.
- * @param node A [DocumentationNode] to render
- * @return [ContentNode] which is a root for a rich content tree suitable for formatting with [FormatService]
- */
- fun render(node: DocumentationNode, renderMode: RenderMode = RenderMode.FULL): ContentNode
-
- /**
- * Tries to summarize the signatures of the specified documentation nodes in a compact representation.
- * Returns the representation if successful, or null if the signatures could not be summarized.
- */
- fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode?
-
- /**
- * Renders [node] as a named representation in the target language
- *
- * For example:
- * ${code org.jetbrains.dokka.example}
- *
- * $node: A [DocumentationNode] to render
- * $returns: [String] which is a string representation of the node's name
- */
- fun renderName(node: DocumentationNode): String
-}
-
-fun example(service: LanguageService, node: DocumentationNode) {
- println("Node name: ${service.renderName(node)}")
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Languages/NewJavaLanguageService.kt b/core/src/main/kotlin/Languages/NewJavaLanguageService.kt
deleted file mode 100644
index 992cd090..00000000
--- a/core/src/main/kotlin/Languages/NewJavaLanguageService.kt
+++ /dev/null
@@ -1,197 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.LanguageService.RenderMode
-
-/**
- * Implements [LanguageService] and provides rendering of symbols in Java language
- */
-class NewJavaLanguageService : CommonLanguageService() {
- override fun showModifierInSummary(node: DocumentationNode): Boolean {
- return true
- }
-
- override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
- return content {
- (when (node.kind) {
- NodeKind.Package -> renderPackage(node)
- in NodeKind.classLike -> renderClass(node, renderMode)
-
- NodeKind.Modifier -> renderModifier(this, node, renderMode)
- NodeKind.TypeParameter -> renderTypeParameter(node)
- NodeKind.Type,
- NodeKind.UpperBound -> renderType(node)
- NodeKind.Parameter -> renderParameter(node)
- NodeKind.Constructor,
- NodeKind.Function -> renderFunction(node)
- NodeKind.Property -> renderProperty(node)
- else -> "${node.kind}: ${node.name}"
- })
- }
- }
-
- override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? = null
-
-
- override fun renderModifier(block: ContentBlock, node: DocumentationNode, renderMode: RenderMode, nowrap: Boolean) {
- when (node.name) {
- "open", "internal" -> {
- }
- else -> super.renderModifier(block, node, renderMode, nowrap)
- }
- }
-
- fun getArrayElementType(node: DocumentationNode): DocumentationNode? = when (node.qualifiedName()) {
- "kotlin.Array" ->
- node.details(NodeKind.Type).singleOrNull()?.let { et -> getArrayElementType(et) ?: et }
- ?: DocumentationNode("Object", node.content, NodeKind.ExternalClass)
-
- "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
- "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
- DocumentationNode(node.name.removeSuffix("Array").toLowerCase(), node.content, NodeKind.Type)
-
- else -> null
- }
-
- fun getArrayDimension(node: DocumentationNode): Int = when (node.qualifiedName()) {
- "kotlin.Array" ->
- 1 + (node.details(NodeKind.Type).singleOrNull()?.let { getArrayDimension(it) } ?: 0)
-
- "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
- "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
- 1
- else -> 0
- }
-
- fun ContentBlock.renderType(node: DocumentationNode) {
- when (node.name) {
- "Unit" -> identifier("void")
- "Int" -> identifier("int")
- "Long" -> identifier("long")
- "Double" -> identifier("double")
- "Float" -> identifier("float")
- "Char" -> identifier("char")
- "Boolean" -> identifier("bool")
- // TODO: render arrays
- else -> renderLinked(this, node) {
- identifier(node.name)
- }
- }
- }
-
- private fun ContentBlock.renderTypeParameter(node: DocumentationNode) {
- val constraints = node.details(NodeKind.UpperBound)
- if (constraints.none())
- identifier(node.name)
- else {
- identifier(node.name)
- text(" ")
- keyword("extends")
- text(" ")
- constraints.forEach { renderType(node) }
- }
- }
-
- private fun ContentBlock.renderParameter(node: DocumentationNode) {
- renderType(node.detail(NodeKind.Type))
- text(" ")
- identifier(node.name)
- }
-
- private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode) {
- val typeParameters = node.details(NodeKind.TypeParameter)
- if (typeParameters.any()) {
- symbol("<")
- renderList(typeParameters, noWrap = true) {
- renderTypeParameter(it)
- }
- symbol(">")
- text(" ")
- }
- }
-
-// private fun renderModifiersForNode(node: DocumentationNode): String {
-// val modifiers = node.details(NodeKind.Modifier).map { renderModifier(it) }.filter { it != "" }
-// if (modifiers.none())
-// return ""
-// return modifiers.joinToString(" ", postfix = " ")
-// }
-
- private fun ContentBlock.renderClassKind(node: DocumentationNode) {
- when (node.kind) {
- NodeKind.Interface -> {
- keyword("interface")
- }
- NodeKind.EnumItem -> {
- keyword("enum value")
- }
- NodeKind.Enum -> {
- keyword("enum")
- }
- NodeKind.Class, NodeKind.Exception, NodeKind.Object -> {
- keyword("class")
- }
- else -> throw IllegalArgumentException("Node $node is not a class-like object")
- }
- text(" ")
- }
-
- private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) {
- renderModifiersForNode(node, renderMode)
- renderClassKind(node)
-
- identifier(node.name)
- renderTypeParametersForNode(node)
- }
-
- private fun ContentBlock.renderParameters(nodes: List<DocumentationNode>) {
- renderList(nodes) {
- renderParameter(it)
- }
- }
-
- private fun ContentBlock.renderFunction(node: DocumentationNode) {
- when (node.kind) {
- NodeKind.Constructor -> identifier(node.owner?.name ?: "")
- NodeKind.Function -> {
- renderTypeParametersForNode(node)
- renderType(node.detail(NodeKind.Type))
- text(" ")
- identifier(node.name)
-
- }
- else -> throw IllegalArgumentException("Node $node is not a function-like object")
- }
-
- val receiver = node.details(NodeKind.Receiver).singleOrNull()
- symbol("(")
- if (receiver != null)
- renderParameters(listOf(receiver) + node.details(NodeKind.Parameter))
- else
- renderParameters(node.details(NodeKind.Parameter))
-
- symbol(")")
- }
-
- private fun ContentBlock.renderProperty(node: DocumentationNode) {
-
- when (node.kind) {
- NodeKind.Property -> {
- keyword("val")
- text(" ")
- }
- else -> throw IllegalArgumentException("Node $node is not a property")
- }
- renderTypeParametersForNode(node)
- val receiver = node.details(NodeKind.Receiver).singleOrNull()
- if (receiver != null) {
- renderType(receiver.detail(NodeKind.Type))
- symbol(".")
- }
-
- identifier(node.name)
- symbol(":")
- text(" ")
- renderType(node.detail(NodeKind.Type))
-
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Locations/Location.kt b/core/src/main/kotlin/Locations/Location.kt
deleted file mode 100644
index 63c9b913..00000000
--- a/core/src/main/kotlin/Locations/Location.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-package org.jetbrains.dokka
-
-import java.io.File
-
-interface Location {
- val path: String get
- fun relativePathTo(other: Location, anchor: String? = null): String
-}
-
-/**
- * Represents locations in the documentation in the form of [path](File).
- *
- * $file: [File] for this location
- * $path: [String] representing path of this location
- */
-data class FileLocation(val file: File) : Location {
- override val path: String
- get() = file.path
-
- override fun relativePathTo(other: Location, anchor: String?): String {
- if (other !is FileLocation) {
- throw IllegalArgumentException("$other is not a FileLocation")
- }
- if (file.path.substringBeforeLast(".") == other.file.path.substringBeforeLast(".") && anchor == null) {
- return "./${file.name}"
- }
- val ownerFolder = file.parentFile!!
- val relativePath = ownerFolder.toPath().relativize(other.file.toPath()).toString().replace(File.separatorChar, '/')
- return if (anchor == null) relativePath else "$relativePath#$anchor"
- }
-}
-
-fun relativePathToNode(qualifiedName: List<String>, hasMembers: Boolean): String {
- val parts = qualifiedName.map { identifierToFilename(it) }.filterNot { it.isEmpty() }
- return if (!hasMembers) {
- // leaf node, use file in owner's folder
- parts.joinToString("/")
- } else {
- parts.joinToString("/") + (if (parts.none()) "" else "/") + "index"
- }
-}
-
-fun nodeActualQualifier(node: DocumentationNode): List<DocumentationNode> {
- val topLevelPage = node.references(RefKind.TopLevelPage).singleOrNull()?.to
- if (topLevelPage != null) {
- return nodeActualQualifier(topLevelPage)
- }
- return node.owner?.let { nodeActualQualifier(it) }.orEmpty() + node
-}
-
-fun relativePathToNode(node: DocumentationNode): String {
- val qualifier = nodeActualQualifier(node)
- return relativePathToNode(
- qualifier.map { it.name },
- qualifier.last().members.any()
- )
-}
-
-
-fun identifierToFilename(path: String): String {
- if (path.isEmpty()) return "--root--"
- val escaped = path.replace('<', '-').replace('>', '-')
- val lowercase = escaped.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() }
- return if (lowercase == "index") "--index--" else lowercase
-}
-
-fun NodeLocationAwareGenerator.relativePathToLocation(owner: DocumentationNode, node: DocumentationNode): String {
- return location(owner).relativePathTo(location(node), null)
-}
-
-fun NodeLocationAwareGenerator.relativePathToRoot(from: Location): File {
- val file = File(from.path).parentFile
- return root.relativeTo(file)
-}
-
-fun File.toUnixString() = toString().replace(File.separatorChar, '/')
diff --git a/core/src/main/kotlin/Markdown/MarkdownProcessor.kt b/core/src/main/kotlin/Markdown/MarkdownProcessor.kt
deleted file mode 100644
index 2c8f7a73..00000000
--- a/core/src/main/kotlin/Markdown/MarkdownProcessor.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.jetbrains.dokka
-
-import org.intellij.markdown.IElementType
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.ast.ASTNode
-import org.intellij.markdown.ast.LeafASTNode
-import org.intellij.markdown.ast.getTextInNode
-import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
-import org.intellij.markdown.parser.MarkdownParser
-
-class MarkdownNode(val node: ASTNode, val parent: MarkdownNode?, val markdown: String) {
- val children: List<MarkdownNode> = node.children.map { MarkdownNode(it, this, markdown) }
- val type: IElementType get() = node.type
- val text: String get() = node.getTextInNode(markdown).toString()
- fun child(type: IElementType): MarkdownNode? = children.firstOrNull { it.type == type }
-
- val previous get() = parent?.children?.getOrNull(parent.children.indexOf(this) - 1)
-
- override fun toString(): String = StringBuilder().apply { presentTo(this) }.toString()
-}
-
-fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) {
- action(this) {
- for (child in children) {
- child.visit(action)
- }
- }
-}
-
-fun MarkdownNode.toTestString(): String {
- val sb = StringBuilder()
- var level = 0
- visit { node, visitChildren ->
- sb.append(" ".repeat(level * 2))
- node.presentTo(sb)
- sb.appendln()
- level++
- visitChildren()
- level--
- }
- return sb.toString()
-}
-
-private fun MarkdownNode.presentTo(sb: StringBuilder) {
- sb.append(type.toString())
- sb.append(":" + text.replace("\n", "\u23CE"))
-}
-
-fun parseMarkdown(markdown: String): MarkdownNode {
- if (markdown.isEmpty())
- return MarkdownNode(LeafASTNode(MarkdownElementTypes.MARKDOWN_FILE, 0, 0), null, markdown)
- return MarkdownNode(MarkdownParser(CommonMarkFlavourDescriptor()).buildMarkdownTreeFromString(markdown), null, markdown)
-}
diff --git a/core/src/main/kotlin/Model/Content.kt b/core/src/main/kotlin/Model/Content.kt
deleted file mode 100644
index 5530e1b4..00000000
--- a/core/src/main/kotlin/Model/Content.kt
+++ /dev/null
@@ -1,290 +0,0 @@
-package org.jetbrains.dokka
-
-interface ContentNode {
- val textLength: Int
-}
-
-object ContentEmpty : ContentNode {
- override val textLength: Int get() = 0
-}
-
-open class ContentBlock() : ContentNode {
- open val children = arrayListOf<ContentNode>()
-
- fun append(node: ContentNode) {
- children.add(node)
- }
-
- fun isEmpty() = children.isEmpty()
-
- override fun equals(other: Any?): Boolean =
- other is ContentBlock && javaClass == other.javaClass && children == other.children
-
- override fun hashCode(): Int =
- children.hashCode()
-
- override val textLength: Int
- get() = children.sumBy { it.textLength }
-}
-
-class NodeRenderContent(
- val node: DocumentationNode,
- val mode: LanguageService.RenderMode
-): ContentNode {
- override val textLength: Int
- get() = 0 //TODO: Clarify?
-}
-
-class LazyContentBlock(private val fillChildren: () -> List<ContentNode>) : ContentBlock() {
- private var computed = false
- override val children: ArrayList<ContentNode>
- get() {
- if (!computed) {
- computed = true
- children.addAll(fillChildren())
- }
- return super.children
- }
-
- override fun equals(other: Any?): Boolean {
- return other is LazyContentBlock && other.fillChildren == fillChildren && super.equals(other)
- }
-
- override fun hashCode(): Int {
- return super.hashCode() + 31 * fillChildren.hashCode()
- }
-}
-
-enum class IdentifierKind {
- TypeName,
- ParameterName,
- AnnotationName,
- SummarizedTypeName,
- Other
-}
-
-data class ContentText(val text: String) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-data class ContentKeyword(val text: String) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-data class ContentIdentifier(val text: String,
- val kind: IdentifierKind = IdentifierKind.Other,
- val signature: String? = null) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-data class ContentSymbol(val text: String) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-data class ContentEntity(val text: String) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-object ContentNonBreakingSpace: ContentNode {
- override val textLength: Int
- get() = 1
-}
-
-object ContentSoftLineBreak: ContentNode {
- override val textLength: Int
- get() = 0
-}
-
-object ContentIndentedSoftLineBreak: ContentNode {
- override val textLength: Int
- get() = 0
-}
-
-class ContentParagraph() : ContentBlock()
-class ContentEmphasis() : ContentBlock()
-class ContentStrong() : ContentBlock()
-class ContentStrikethrough() : ContentBlock()
-class ContentCode() : ContentBlock()
-open class ContentBlockCode(val language: String = "") : ContentBlock()
-class ContentBlockSampleCode(language: String = "kotlin", val importsBlock: ContentBlockCode = ContentBlockCode(language)) : ContentBlockCode(language)
-
-abstract class ContentNodeLink() : ContentBlock() {
- abstract val node: DocumentationNode?
- abstract val text: String?
-}
-
-object ContentHardLineBreak : ContentNode {
- override val textLength: Int
- get() = 0
-}
-
-class ContentNodeDirectLink(override val node: DocumentationNode): ContentNodeLink() {
- override fun equals(other: Any?): Boolean =
- super.equals(other) && other is ContentNodeDirectLink && node.name == other.node.name
-
- override fun hashCode(): Int =
- children.hashCode() * 31 + node.name.hashCode()
-
- override val text: String? = null
-}
-
-class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> DocumentationNode?): ContentNodeLink() {
- override val node: DocumentationNode? get() = lazyNode()
-
- override fun equals(other: Any?): Boolean =
- super.equals(other) && other is ContentNodeLazyLink && linkText == other.linkText
-
- override fun hashCode(): Int =
- children.hashCode() * 31 + linkText.hashCode()
-
- override val text: String? = linkText
-}
-
-class ContentExternalLink(val href : String) : ContentBlock() {
- override fun equals(other: Any?): Boolean =
- super.equals(other) && other is ContentExternalLink && href == other.href
-
- override fun hashCode(): Int =
- children.hashCode() * 31 + href.hashCode()
-}
-
-data class ContentBookmark(val name: String): ContentBlock()
-data class ContentLocalLink(val href: String) : ContentBlock()
-
-class ContentUnorderedList() : ContentBlock()
-class ContentOrderedList() : ContentBlock()
-class ContentListItem() : ContentBlock()
-
-class ContentHeading(val level: Int) : ContentBlock()
-
-class ContentSection(val tag: String, val subjectName: String?) : ContentBlock() {
- override fun equals(other: Any?): Boolean =
- super.equals(other) && other is ContentSection && tag == other.tag && subjectName == other.subjectName
-
- override fun hashCode(): Int =
- children.hashCode() * 31 * 31 + tag.hashCode() * 31 + (subjectName?.hashCode() ?: 0)
-}
-
-object ContentTags {
- const val Description = "Description"
- const val SeeAlso = "See Also"
- const val Return = "Return"
- const val Exceptions = "Exceptions"
-}
-
-fun content(body: ContentBlock.() -> Unit): ContentBlock {
- val block = ContentBlock()
- block.body()
- return block
-}
-
-fun ContentBlock.text(value: String) = append(ContentText(value))
-fun ContentBlock.keyword(value: String) = append(ContentKeyword(value))
-fun ContentBlock.symbol(value: String) = append(ContentSymbol(value))
-
-fun ContentBlock.identifier(value: String, kind: IdentifierKind = IdentifierKind.Other, signature: String? = null) {
- append(ContentIdentifier(value, kind, signature))
-}
-
-fun ContentBlock.nbsp() = append(ContentNonBreakingSpace)
-fun ContentBlock.softLineBreak() = append(ContentSoftLineBreak)
-fun ContentBlock.indentedSoftLineBreak() = append(ContentIndentedSoftLineBreak)
-fun ContentBlock.hardLineBreak() = append(ContentHardLineBreak)
-
-fun ContentBlock.strong(body: ContentBlock.() -> Unit) {
- val strong = ContentStrong()
- strong.body()
- append(strong)
-}
-
-fun ContentBlock.code(body: ContentBlock.() -> Unit) {
- val code = ContentCode()
- code.body()
- append(code)
-}
-
-fun ContentBlock.link(to: DocumentationNode, body: ContentBlock.() -> Unit) {
- val block = if (to.kind == NodeKind.ExternalLink)
- ContentExternalLink(to.name)
- else
- ContentNodeDirectLink(to)
-
- block.body()
- append(block)
-}
-
-open class Content(): ContentBlock() {
- open val sections: List<ContentSection> get() = emptyList()
- open val summary: ContentNode get() = ContentEmpty
- open val description: ContentNode get() = ContentEmpty
-
- fun findSectionByTag(tag: String): ContentSection? =
- sections.firstOrNull { tag.equals(it.tag, ignoreCase = true) }
-
- companion object {
- val Empty = object: Content() {
- override fun toString(): String {
- return "EMPTY_CONTENT"
- }
- }
-
- fun of(vararg child: ContentNode): Content {
- val result = MutableContent()
- child.forEach { result.append(it) }
- return result
- }
- }
-}
-
-open class MutableContent() : Content() {
- private val sectionList = arrayListOf<ContentSection>()
- override val sections: List<ContentSection>
- get() = sectionList
-
- fun addSection(tag: String?, subjectName: String?): ContentSection {
- val section = ContentSection(tag ?: "", subjectName)
- sectionList.add(section)
- return section
- }
-
- override val summary: ContentNode get() = children.firstOrNull() ?: ContentEmpty
-
- override val description: ContentNode by lazy {
- val descriptionNodes = children.drop(1)
- if (descriptionNodes.isEmpty()) {
- ContentEmpty
- } else {
- val result = ContentSection(ContentTags.Description, null)
- result.children.addAll(descriptionNodes)
- result
- }
- }
-
- override fun equals(other: Any?): Boolean {
- if (other !is Content)
- return false
- return sections == other.sections && children == other.children
- }
-
- override fun hashCode(): Int {
- return sections.map { it.hashCode() }.sum()
- }
-
- override fun toString(): String {
- if (sections.isEmpty())
- return "<empty>"
- return (listOf(summary, description) + sections).joinToString()
- }
-}
-
-fun javadocSectionDisplayName(sectionName: String?): String? =
- when(sectionName) {
- "param" -> "Parameters"
- "throws", "exception" -> ContentTags.Exceptions
- else -> sectionName?.capitalize()
- }
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
deleted file mode 100644
index 311b46e4..00000000
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ /dev/null
@@ -1,276 +0,0 @@
-package org.jetbrains.dokka
-
-import java.util.*
-
-enum class NodeKind {
- Unknown,
-
- Package,
- Class,
- Interface,
- Enum,
- AnnotationClass,
- Exception,
- EnumItem,
- Object,
- TypeAlias,
-
- Constructor,
- Function,
- Property,
- Field,
-
- CompanionObjectProperty,
- CompanionObjectFunction,
-
- Parameter,
- Receiver,
- TypeParameter,
- Type,
- Supertype,
- UpperBound,
- LowerBound,
-
- TypeAliasUnderlyingType,
-
- Modifier,
- NullabilityModifier,
-
- Module,
-
- ExternalClass,
- Annotation,
-
- Value,
-
- SourceUrl,
- SourcePosition,
- Signature,
-
- ExternalLink,
- QualifiedName,
- Platform,
-
- AllTypes,
-
- /**
- * A note which is rendered once on a page documenting a group of overloaded functions.
- * Needs to be generated equally on all overloads.
- */
- OverloadGroupNote,
-
- GroupNode;
-
- companion object {
- val classLike = setOf(Class, Interface, Enum, AnnotationClass, Exception, Object, TypeAlias)
- val memberLike = setOf(Function, Property, Field, Constructor, CompanionObjectFunction, CompanionObjectProperty, EnumItem)
- }
-}
-
-open class DocumentationNode(val name: String,
- content: Content,
- val kind: NodeKind) {
-
- private val references = LinkedHashSet<DocumentationReference>()
-
- var content: Content = content
- private set
-
- val summary: ContentNode get() = when (kind) {
- NodeKind.GroupNode -> this.origins
- .map { it.content }
- .firstOrNull { !it.isEmpty() }
- ?.summary ?: ContentEmpty
- else -> content.summary
- }
-
-
- val owner: DocumentationNode?
- get() = references(RefKind.Owner).singleOrNull()?.to
- val details: List<DocumentationNode>
- get() = references(RefKind.Detail).map { it.to }
- val members: List<DocumentationNode>
- get() = references(RefKind.Member).map { it.to }
- val origins: List<DocumentationNode>
- get() = references(RefKind.Origin).map { it.to }
-
- val inheritedMembers: List<DocumentationNode>
- get() = references(RefKind.InheritedMember).map { it.to }
- val allInheritedMembers: List<DocumentationNode>
- get() = recursiveInheritedMembers()
- val inheritedCompanionObjectMembers: List<DocumentationNode>
- get() = references(RefKind.InheritedCompanionObjectMember).map { it.to }
- val extensions: List<DocumentationNode>
- get() = references(RefKind.Extension).map { it.to }
- val inheritors: List<DocumentationNode>
- get() = references(RefKind.Inheritor).map { it.to }
- val overrides: List<DocumentationNode>
- get() = references(RefKind.Override).map { it.to }
- val links: List<DocumentationNode>
- get() = references(RefKind.Link).map { it.to }
- val hiddenLinks: List<DocumentationNode>
- get() = references(RefKind.HiddenLink).map { it.to }
- val annotations: List<DocumentationNode>
- get() = references(RefKind.Annotation).map { it.to }
- val deprecation: DocumentationNode?
- get() = references(RefKind.Deprecation).singleOrNull()?.to
- val platforms: List<String>
- get() = references(RefKind.Platform).map { it.to.name }
- val externalType: DocumentationNode?
- get() = references(RefKind.ExternalType).map { it.to }.firstOrNull()
-
- var sinceKotlin: String?
- get() = references(RefKind.SinceKotlin).singleOrNull()?.to?.name
- set(value) {
- dropReferences { it.kind == RefKind.SinceKotlin }
- if (value != null) {
- append(DocumentationNode(value, Content.Empty, NodeKind.Value), RefKind.SinceKotlin)
- }
- }
-
- val supertypes: List<DocumentationNode>
- get() = details(NodeKind.Supertype)
-
- val superclassType: DocumentationNode?
- get() = when (kind) {
- NodeKind.Supertype -> {
- (links + listOfNotNull(externalType)).firstOrNull { it.kind in NodeKind.classLike }?.superclassType
- }
- NodeKind.Interface -> null
- in NodeKind.classLike -> supertypes.firstOrNull {
- (it.links + listOfNotNull(it.externalType)).any { it.isSuperclassFor(this) }
- }
- else -> null
- }
-
- val superclassTypeSequence: Sequence<DocumentationNode>
- get() = generateSequence(superclassType) {
- it.superclassType
- }
-
- // TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice
- fun addReferenceTo(to: DocumentationNode, kind: RefKind) {
- references.add(DocumentationReference(this, to, kind))
- }
-
- fun addReference(reference: DocumentationReference) {
- references.add(reference)
- }
-
- fun dropReferences(predicate: (DocumentationReference) -> Boolean) {
- references.removeAll(predicate)
- }
-
- fun addAllReferencesFrom(other: DocumentationNode) {
- references.addAll(other.references)
- }
-
- fun updateContent(body: MutableContent.() -> Unit) {
- if (content !is MutableContent) {
- content = MutableContent()
- }
- (content as MutableContent).body()
- }
- fun details(kind: NodeKind): List<DocumentationNode> = details.filter { it.kind == kind }
- fun members(kind: NodeKind): List<DocumentationNode> = members.filter { it.kind == kind }
- fun inheritedMembers(kind: NodeKind): List<DocumentationNode> = inheritedMembers.filter { it.kind == kind }
- fun inheritedCompanionObjectMembers(kind: NodeKind): List<DocumentationNode> = inheritedCompanionObjectMembers.filter { it.kind == kind }
- fun links(kind: NodeKind): List<DocumentationNode> = links.filter { it.kind == kind }
-
- fun detail(kind: NodeKind): DocumentationNode = details.single { it.kind == kind }
- fun detailOrNull(kind: NodeKind): DocumentationNode? = details.singleOrNull { it.kind == kind }
- fun member(kind: NodeKind): DocumentationNode = members.single { it.kind == kind }
- fun link(kind: NodeKind): DocumentationNode = links.single { it.kind == kind }
-
-
- fun references(kind: RefKind): List<DocumentationReference> = references.filter { it.kind == kind }
- fun allReferences(): Set<DocumentationReference> = references
-
- override fun toString(): String {
- return "$kind:$name"
- }
-}
-
-class DocumentationModule(name: String, content: Content = Content.Empty, val nodeRefGraph: NodeReferenceGraph = NodeReferenceGraph())
- : DocumentationNode(name, content, NodeKind.Module) {
-
-}
-
-val DocumentationNode.path: List<DocumentationNode>
- get() {
- val parent = owner ?: return listOf(this)
- return parent.path + this
- }
-
-fun findOrCreatePackageNode(module: DocumentationNode?, packageName: String, packageContent: Map<String, Content>, refGraph: NodeReferenceGraph): DocumentationNode {
- val node = refGraph.lookup(packageName) ?: run {
- val newNode = DocumentationNode(
- packageName,
- packageContent.getOrElse(packageName) { Content.Empty },
- NodeKind.Package
- )
-
- refGraph.register(packageName, newNode)
- newNode
- }
- if (module != null && node !in module.members) {
- module.append(node, RefKind.Member)
- }
- return node
-}
-
-fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) {
- addReferenceTo(child, kind)
- when (kind) {
- RefKind.Detail -> child.addReferenceTo(this, RefKind.Owner)
- RefKind.Member -> child.addReferenceTo(this, RefKind.Owner)
- RefKind.Owner -> child.addReferenceTo(this, RefKind.Member)
- RefKind.Origin -> child.addReferenceTo(this, RefKind.Owner)
- else -> { /* Do not add any links back for other types */
- }
- }
-}
-
-fun DocumentationNode.appendTextNode(text: String,
- kind: NodeKind,
- refKind: RefKind = RefKind.Detail) {
- append(DocumentationNode(text, Content.Empty, kind), refKind)
-}
-
-fun DocumentationNode.qualifiedName(): String {
- if (kind == NodeKind.Type) {
- return qualifiedNameFromType()
- } else if (kind == NodeKind.Package) {
- return name
- }
- return path.dropWhile { it.kind == NodeKind.Module }.map { it.name }.filter { it.isNotEmpty() }.joinToString(".")
-}
-
-fun DocumentationNode.simpleName() = name.substringAfterLast('.')
-
-private fun DocumentationNode.recursiveInheritedMembers(): List<DocumentationNode> {
- val allInheritedMembers = mutableListOf<DocumentationNode>()
- recursiveInheritedMembers(allInheritedMembers)
- return allInheritedMembers
-}
-
-private fun DocumentationNode.recursiveInheritedMembers(allInheritedMembers: MutableList<DocumentationNode>) {
- allInheritedMembers.addAll(inheritedMembers)
- System.out.println(allInheritedMembers.size)
- inheritedMembers.groupBy { it.owner!! } .forEach { (node, _) ->
- node.recursiveInheritedMembers(allInheritedMembers)
- }
-}
-
-private fun DocumentationNode.isSuperclassFor(node: DocumentationNode): Boolean {
- return when(node.kind) {
- NodeKind.Object, NodeKind.Class, NodeKind.Enum -> kind == NodeKind.Class
- NodeKind.Exception -> kind == NodeKind.Class || kind == NodeKind.Exception
- else -> false
- }
-}
-
-fun DocumentationNode.classNodeNameWithOuterClass(): String {
- assert(kind in NodeKind.classLike)
- return path.dropWhile { it.kind == NodeKind.Package || it.kind == NodeKind.Module }.joinToString(separator = ".") { it.name }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt
deleted file mode 100644
index 0b890a78..00000000
--- a/core/src/main/kotlin/Model/DocumentationReference.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Singleton
-
-enum class RefKind {
- Owner,
- Member,
- InheritedMember,
- InheritedCompanionObjectMember,
- Detail,
- Link,
- HiddenLink,
- Extension,
- Inheritor,
- Superclass,
- Override,
- Annotation,
- HiddenAnnotation,
- Deprecation,
- TopLevelPage,
- Platform,
- ExternalType,
- Origin,
- SinceKotlin
-}
-
-data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: RefKind) {
-}
-
-sealed class NodeResolver {
- abstract fun resolve(nodeRephGraph: NodeReferenceGraph): DocumentationNode?
- class BySignature(var signature: String) : NodeResolver() {
- override fun resolve(nodeRephGraph: NodeReferenceGraph): DocumentationNode? {
- return nodeRephGraph.lookup(signature)
- }
- }
-
- class Exact(var exactNode: DocumentationNode) : NodeResolver() {
- override fun resolve(nodeRephGraph: NodeReferenceGraph): DocumentationNode? {
- return exactNode
- }
- }
-}
-
-class PendingDocumentationReference(val lazyNodeFrom: NodeResolver,
- val lazyNodeTo: NodeResolver,
- val kind: RefKind) {
- fun resolve(nodeRephGraph: NodeReferenceGraph) {
- val fromNode = lazyNodeFrom.resolve(nodeRephGraph)
- val toNode = lazyNodeTo.resolve(nodeRephGraph)
- if (fromNode != null && toNode != null) {
- fromNode.addReferenceTo(toNode, kind)
- }
- }
-}
-
-class NodeReferenceGraph {
- private val nodeMap = hashMapOf<String, DocumentationNode>()
- val nodeMapView: Map<String, DocumentationNode>
- get() = HashMap(nodeMap)
-
- val references = arrayListOf<PendingDocumentationReference>()
-
- fun register(signature: String, node: DocumentationNode) {
- nodeMap[signature] = node
- }
-
- fun link(fromNode: DocumentationNode, toSignature: String, kind: RefKind) {
- references.add(
- PendingDocumentationReference(
- NodeResolver.Exact(fromNode),
- NodeResolver.BySignature(toSignature),
- kind
- ))
- }
-
- fun link(fromSignature: String, toNode: DocumentationNode, kind: RefKind) {
- references.add(
- PendingDocumentationReference(
- NodeResolver.BySignature(fromSignature),
- NodeResolver.Exact(toNode),
- kind
- )
- )
- }
-
- fun link(fromSignature: String, toSignature: String, kind: RefKind) {
- references.add(
- PendingDocumentationReference(
- NodeResolver.BySignature(fromSignature),
- NodeResolver.BySignature(toSignature),
- kind
- )
- )
- }
-
- fun addReference(reference: PendingDocumentationReference) {
- references.add(reference)
- }
-
- fun lookup(signature: String) = nodeMap[signature]
-
- fun lookupOrWarn(signature: String, logger: DokkaLogger): DocumentationNode? {
- val result = nodeMap[signature]
- if (result == null) {
- logger.warn("Can't find node by signature `$signature`." +
- "This is probably caused by invalid configuration of cross-module dependencies")
- }
- return result
- }
-
- fun resolveReferences() {
- references.forEach { it.resolve(this) }
- }
-}
-
-@Singleton
-class PlatformNodeRegistry {
- private val platformNodes = hashMapOf<String, DocumentationNode>()
-
- operator fun get(platform: String): DocumentationNode {
- return platformNodes.getOrPut(platform) {
- DocumentationNode(platform, Content.Empty, NodeKind.Platform)
- }
- }
-}
diff --git a/core/src/main/kotlin/Model/ElementSignatureProvider.kt b/core/src/main/kotlin/Model/ElementSignatureProvider.kt
deleted file mode 100644
index e8fdde6e..00000000
--- a/core/src/main/kotlin/Model/ElementSignatureProvider.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.PsiElement
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-
-interface ElementSignatureProvider {
- fun signature(forDesc: DeclarationDescriptor): String
- fun signature(forPsi: PsiElement): String
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Model/PackageDocs.kt b/core/src/main/kotlin/Model/PackageDocs.kt
deleted file mode 100644
index b24efc5d..00000000
--- a/core/src/main/kotlin/Model/PackageDocs.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.Singleton
-import com.intellij.ide.highlighter.JavaFileType
-import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiFileFactory
-import com.intellij.psi.util.PsiTreeUtil
-import com.intellij.util.LocalTimeCounter
-import com.intellij.openapi.util.text.StringUtil
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.intellij.markdown.parser.LinkMap
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
-import java.io.File
-
-@Singleton
-class PackageDocs
- @Inject constructor(val linkResolver: DeclarationLinkResolver?,
- val logger: DokkaLogger,
- val environment: KotlinCoreEnvironment,
- val refGraph: NodeReferenceGraph,
- val elementSignatureProvider: ElementSignatureProvider)
-{
- val moduleContent: MutableContent = MutableContent()
- private val _packageContent: MutableMap<String, MutableContent> = hashMapOf()
- val packageContent: Map<String, Content>
- get() = _packageContent
-
- fun parse(fileName: String, linkResolveContext: List<PackageFragmentDescriptor>) {
- val file = File(fileName)
- if (file.exists()) {
- val text = StringUtil.convertLineSeparators(file.readText())
- val tree = parseMarkdown(text)
- val linkMap = LinkMap.buildLinkMap(tree.node, text)
- var targetContent: MutableContent = moduleContent
- tree.children.forEach {
- if (it.type == MarkdownElementTypes.ATX_1) {
- val headingText = it.child(MarkdownTokenTypes.ATX_CONTENT)?.text
- if (headingText != null) {
- targetContent = findTargetContent(headingText.trimStart())
- }
- } else {
- buildContentTo(it, targetContent, LinkResolver(linkMap) { resolveContentLink(fileName, it, linkResolveContext) })
- }
- }
- } else {
- logger.warn("Include file $file was not found.")
- }
- }
-
- private fun parseHtmlAsJavadoc(text: String, packageName: String, file: File) {
- val javadocText = text
- .replace("*/", "*&#47;")
- .removeSurrounding("<html>", "</html>", true).trim()
- .removeSurrounding("<body>", "</body>", true)
- .lineSequence()
- .map { "* $it" }
- .joinToString (separator = "\n", prefix = "/**\n", postfix = "\n*/")
- parseJavadoc(javadocText, packageName, file)
- }
-
- private fun CharSequence.removeSurrounding(prefix: CharSequence, suffix: CharSequence, ignoringCase: Boolean = false): CharSequence {
- if ((length >= prefix.length + suffix.length) && startsWith(prefix, ignoringCase) && endsWith(suffix, ignoringCase)) {
- return subSequence(prefix.length, length - suffix.length)
- }
- return subSequence(0, length)
- }
-
-
- private fun parseJavadoc(text: String, packageName: String, file: File) {
-
- val psiFileFactory = PsiFileFactory.getInstance(environment.project)
- val psiFile = psiFileFactory.createFileFromText(
- file.nameWithoutExtension + ".java",
- JavaFileType.INSTANCE,
- "package $packageName; $text\npublic class C {}",
- LocalTimeCounter.currentTime(),
- false,
- true
- )
-
- val psiClass = PsiTreeUtil.getChildOfType(psiFile, PsiClass::class.java)!!
- val parser = JavadocParser(refGraph, logger, elementSignatureProvider, linkResolver?.externalDocumentationLinkResolver!!)
- findOrCreatePackageContent(packageName).apply {
- val content = parser.parseDocumentation(psiClass).content
- children.addAll(content.children)
- content.sections.forEach {
- addSection(it.tag, it.subjectName).children.addAll(it.children)
- }
- }
- }
-
-
- fun parseJava(fileName: String, packageName: String) {
- val file = File(fileName)
- if (file.exists()) {
- val text = file.readText()
-
- val trimmedText = text.trim()
-
- if (trimmedText.startsWith("/**")) {
- parseJavadoc(text, packageName, file)
- } else if (trimmedText.toLowerCase().startsWith("<html>")) {
- parseHtmlAsJavadoc(trimmedText, packageName, file)
- }
- }
- }
-
- private fun findTargetContent(heading: String): MutableContent {
- if (heading.startsWith("Module") || heading.startsWith("module")) {
- return moduleContent
- }
- if (heading.startsWith("Package") || heading.startsWith("package")) {
- return findOrCreatePackageContent(heading.substring("package".length).trim())
- }
- return findOrCreatePackageContent(heading)
- }
-
- private fun findOrCreatePackageContent(packageName: String) =
- _packageContent.getOrPut(packageName) { MutableContent() }
-
- private fun resolveContentLink(fileName: String, href: String, linkResolveContext: List<PackageFragmentDescriptor>): ContentBlock {
- if (linkResolver != null) {
- linkResolveContext
- .asSequence()
- .map { p -> linkResolver.tryResolveContentLink(p, href) }
- .filterNotNull()
- .firstOrNull()
- ?.let { return it }
- }
- logger.warn("Unresolved link to `$href` in include ($fileName)")
- return ContentExternalLink("#")
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Model/SourceLinks.kt b/core/src/main/kotlin/Model/SourceLinks.kt
deleted file mode 100644
index 99ee362e..00000000
--- a/core/src/main/kotlin/Model/SourceLinks.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.PsiDocumentManager
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiNameIdentifierOwner
-import org.jetbrains.dokka.DokkaConfiguration.SourceLinkDefinition
-import org.jetbrains.kotlin.psi.psiUtil.startOffset
-import java.io.File
-
-
-fun DocumentationNode.appendSourceLink(psi: PsiElement?, sourceLinks: List<SourceLinkDefinition>) {
- val path = psi?.containingFile?.virtualFile?.path ?: return
- val canonicalPath = File(path).canonicalPath
-
- val target = if (psi is PsiNameIdentifierOwner) psi.nameIdentifier else psi
- val pair = determineSourceLinkDefinition(canonicalPath, sourceLinks)
- if (pair != null) {
- val (sourceLinkDefinition, sourceLinkCanonicalPath) = pair
- var url = determineUrl(canonicalPath, sourceLinkDefinition, sourceLinkCanonicalPath)
- if (sourceLinkDefinition.lineSuffix != null) {
- val line = target?.lineNumber()
- if (line != null) {
- url += sourceLinkDefinition.lineSuffix + line.toString()
- }
- }
- append(DocumentationNode(url, Content.Empty, NodeKind.SourceUrl), RefKind.Detail)
- }
-
- if (target != null) {
- append(DocumentationNode(target.sourcePosition(), Content.Empty, NodeKind.SourcePosition), RefKind.Detail)
- }
-}
-
-private fun determineSourceLinkDefinition(
- canonicalPath: String,
- sourceLinks: List<SourceLinkDefinition>
-): Pair<SourceLinkDefinition, String>? {
- return sourceLinks
- .asSequence()
- .map { it to File(it.path).canonicalPath }
- .firstOrNull { (_, sourceLinkCanonicalPath) ->
- canonicalPath.startsWith(sourceLinkCanonicalPath)
- }
-}
-
-private fun determineUrl(
- canonicalPath: String,
- sourceLinkDefinition: SourceLinkDefinition,
- sourceLinkCanonicalPath: String
-): String {
- val relativePath = canonicalPath.substring(sourceLinkCanonicalPath.length)
- val relativeUrl = relativePath.replace('\\', '/').removePrefix("/")
- return "${sourceLinkDefinition.url.removeSuffix("/")}/$relativeUrl"
-}
-
-private fun PsiElement.sourcePosition(): String {
- val path = containingFile.virtualFile.path
- val lineNumber = lineNumber()
- val columnNumber = columnNumber()
-
- return when {
- lineNumber == null -> path
- columnNumber == null -> "$path:$lineNumber"
- else -> "$path:$lineNumber:$columnNumber"
- }
-}
-
-fun PsiElement.lineNumber(): Int? {
- val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile)
- // IJ uses 0-based line-numbers; external source browsers use 1-based
- return doc?.getLineNumber(textRange.startOffset)?.plus(1)
-}
-
-fun PsiElement.columnNumber(): Int? {
- val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile) ?: return null
- val lineNumber = doc.getLineNumber(textRange.startOffset)
- return startOffset - doc.getLineStartOffset(lineNumber)
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt b/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt
deleted file mode 100644
index da74495f..00000000
--- a/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-package org.jetbrains.dokka.Samples
-
-import com.google.inject.Inject
-import com.intellij.psi.PsiElement
-import org.jetbrains.dokka.*
-import org.jetbrains.kotlin.descriptors.ClassDescriptor
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
-import org.jetbrains.kotlin.idea.kdoc.getKDocLinkResolutionScope
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.psi.KtBlockExpression
-import org.jetbrains.kotlin.psi.KtDeclarationWithBody
-import org.jetbrains.kotlin.psi.KtFile
-import org.jetbrains.kotlin.resolve.BindingContext
-import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
-import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.ResolutionScope
-
-
-open class DefaultSampleProcessingService
-@Inject constructor(val configuration: DokkaConfiguration,
- val logger: DokkaLogger,
- val resolutionFacade: DokkaResolutionFacade)
- : SampleProcessingService {
-
- override fun resolveSample(descriptor: DeclarationDescriptor, functionName: String?, kdocTag: KDocTag): ContentNode {
- if (functionName == null) {
- logger.warn("Missing function name in @sample in ${descriptor.signature()}")
- return ContentBlockSampleCode().apply { append(ContentText("//Missing function name in @sample")) }
- }
- val bindingContext = BindingContext.EMPTY
- val symbol = resolveKDocLink(bindingContext, resolutionFacade, descriptor, kdocTag, functionName.split(".")).firstOrNull()
- if (symbol == null) {
- logger.warn("Unresolved function $functionName in @sample in ${descriptor.signature()}")
- return ContentBlockSampleCode().apply { append(ContentText("//Unresolved: $functionName")) }
- }
- val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(symbol)
- if (psiElement == null) {
- logger.warn("Can't find source for function $functionName in @sample in ${descriptor.signature()}")
- return ContentBlockSampleCode().apply { append(ContentText("//Source not found: $functionName")) }
- }
-
- val text = processSampleBody(psiElement).trim { it == '\n' || it == '\r' }.trimEnd()
- val lines = text.split("\n")
- val indent = lines.filter(String::isNotBlank).map { it.takeWhile(Char::isWhitespace).count() }.min() ?: 0
- val finalText = lines.joinToString("\n") { it.drop(indent) }
-
- return ContentBlockSampleCode(importsBlock = processImports(psiElement)).apply { append(ContentText(finalText)) }
- }
-
- protected open fun processSampleBody(psiElement: PsiElement): String = when (psiElement) {
- is KtDeclarationWithBody -> {
- val bodyExpression = psiElement.bodyExpression
- when (bodyExpression) {
- is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}")
- else -> bodyExpression!!.text
- }
- }
- else -> psiElement.text
- }
-
- protected open fun processImports(psiElement: PsiElement): ContentBlockCode {
- val psiFile = psiElement.containingFile
- if (psiFile is KtFile) {
- return ContentBlockCode("kotlin").apply {
- append(ContentText(psiFile.importList?.text ?: ""))
- }
- } else {
- return ContentBlockCode("")
- }
- }
-
- private fun resolveInScope(functionName: String, scope: ResolutionScope): DeclarationDescriptor? {
- var currentScope = scope
- val parts = functionName.split('.')
-
- var symbol: DeclarationDescriptor? = null
-
- for (part in parts) {
- // short name
- val symbolName = Name.identifier(part)
- val partSymbol = currentScope.getContributedDescriptors(DescriptorKindFilter.ALL) { it == symbolName }.firstOrNull { it.name == symbolName }
-
- if (partSymbol == null) {
- symbol = null
- break
- }
- @Suppress("IfThenToElvis")
- currentScope = if (partSymbol is ClassDescriptor)
- partSymbol.defaultType.memberScope
- else if (partSymbol is PackageViewDescriptor)
- partSymbol.memberScope
- else
- getKDocLinkResolutionScope(resolutionFacade, partSymbol)
- symbol = partSymbol
- }
-
- return symbol
- }
-}
-
diff --git a/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt b/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt
deleted file mode 100644
index a67306f4..00000000
--- a/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt
+++ /dev/null
@@ -1,197 +0,0 @@
-package org.jetbrains.dokka.Samples
-
-import com.google.inject.Inject
-import com.intellij.psi.PsiDocumentManager
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiElementVisitor
-import com.intellij.psi.PsiWhiteSpace
-import com.intellij.psi.impl.source.tree.LeafPsiElement
-import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.dokka.*
-import org.jetbrains.kotlin.psi.*
-import org.jetbrains.kotlin.psi.psiUtil.allChildren
-import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
-import org.jetbrains.kotlin.psi.psiUtil.startOffset
-import org.jetbrains.kotlin.resolve.ImportPath
-import java.io.PrintWriter
-import java.io.StringWriter
-
-
-open class KotlinWebsiteSampleProcessingService
-@Inject constructor(dokkaConfiguration: DokkaConfiguration,
- logger: DokkaLogger,
- resolutionFacade: DokkaResolutionFacade)
- : DefaultSampleProcessingService(dokkaConfiguration, logger, resolutionFacade) {
-
- private class SampleBuilder : KtTreeVisitorVoid() {
- val builder = StringBuilder()
- val text: String
- get() = builder.toString()
-
- val errors = mutableListOf<ConvertError>()
-
- data class ConvertError(val e: Exception, val text: String, val loc: String)
-
- fun KtValueArgument.extractStringArgumentValue() =
- (getArgumentExpression() as KtStringTemplateExpression)
- .entries.joinToString("") { it.text }
-
-
- fun convertAssertPrints(expression: KtCallExpression) {
- val (argument, commentArgument) = expression.valueArguments
- builder.apply {
- append("println(")
- append(argument.text)
- append(") // ")
- append(commentArgument.extractStringArgumentValue())
- }
- }
-
- fun convertAssertTrueFalse(expression: KtCallExpression, expectedResult: Boolean) {
- val (argument) = expression.valueArguments
- builder.apply {
- expression.valueArguments.getOrNull(1)?.let {
- append("// ${it.extractStringArgumentValue()}")
- val ws = expression.prevLeaf { it is PsiWhiteSpace }
- append(ws?.text ?: "\n")
- }
- append("println(\"")
- append(argument.text)
- append(" is \${")
- append(argument.text)
- append("}\") // $expectedResult")
- }
- }
-
- fun convertAssertFails(expression: KtCallExpression) {
- val valueArguments = expression.valueArguments
-
- val funcArgument: KtValueArgument
- val message: KtValueArgument?
-
- if (valueArguments.size == 1) {
- message = null
- funcArgument = valueArguments.first()
- } else {
- message = valueArguments.first()
- funcArgument = valueArguments.last()
- }
-
- builder.apply {
- val argument = funcArgument.extractFunctionalArgumentText()
- append(argument.lines().joinToString(separator = "\n") { "// $it" })
- append(" // ")
- if (message != null) {
- append(message.extractStringArgumentValue())
- }
- append(" will fail")
- }
- }
-
- private fun KtValueArgument.extractFunctionalArgumentText(): String {
- return if (getArgumentExpression() is KtLambdaExpression)
- PsiTreeUtil.findChildOfType(this, KtBlockExpression::class.java)?.text ?: ""
- else
- text
- }
-
- fun convertAssertFailsWith(expression: KtCallExpression) {
- val (funcArgument) = expression.valueArguments
- val (exceptionType) = expression.typeArguments
- builder.apply {
- val argument = funcArgument.extractFunctionalArgumentText()
- append(argument.lines().joinToString(separator = "\n") { "// $it" })
- append(" // will fail with ")
- append(exceptionType.text)
- }
- }
-
- override fun visitCallExpression(expression: KtCallExpression) {
- when (expression.calleeExpression?.text) {
- "assertPrints" -> convertAssertPrints(expression)
- "assertTrue" -> convertAssertTrueFalse(expression, expectedResult = true)
- "assertFalse" -> convertAssertTrueFalse(expression, expectedResult = false)
- "assertFails" -> convertAssertFails(expression)
- "assertFailsWith" -> convertAssertFailsWith(expression)
- else -> super.visitCallExpression(expression)
- }
- }
-
- private fun reportProblemConvertingElement(element: PsiElement, e: Exception) {
- val text = element.text
- val document = PsiDocumentManager.getInstance(element.project).getDocument(element.containingFile)
-
- val lineInfo = if (document != null) {
- val lineNumber = document.getLineNumber(element.startOffset)
- "$lineNumber, ${element.startOffset - document.getLineStartOffset(lineNumber)}"
- } else {
- "offset: ${element.startOffset}"
- }
- errors += ConvertError(e, text, lineInfo)
- }
-
- override fun visitElement(element: PsiElement) {
- if (element is LeafPsiElement)
- builder.append(element.text)
-
- element.acceptChildren(object : PsiElementVisitor() {
- override fun visitElement(element: PsiElement) {
- try {
- element.accept(this@SampleBuilder)
- } catch (e: Exception) {
- try {
- reportProblemConvertingElement(element, e)
- } finally {
- builder.append(element.text) //recover
- }
- }
- }
- })
- }
-
- }
-
- private fun PsiElement.buildSampleText(): String {
- val sampleBuilder = SampleBuilder()
- this.accept(sampleBuilder)
-
- sampleBuilder.errors.forEach {
- val sw = StringWriter()
- val pw = PrintWriter(sw)
- it.e.printStackTrace(pw)
-
- logger.error("${containingFile.name}: (${it.loc}): Exception thrown while converting \n```\n${it.text}\n```\n$sw")
- }
- return sampleBuilder.text
- }
-
- val importsToIgnore = arrayOf("samples.*", "samples.Sample").map { ImportPath.fromString(it) }
-
- override fun processImports(psiElement: PsiElement): ContentBlockCode {
- val psiFile = psiElement.containingFile
- if (psiFile is KtFile) {
- return ContentBlockCode("kotlin").apply {
- append(ContentText("\n"))
- psiFile.importList?.let {
- it.allChildren.filter {
- it !is KtImportDirective || it.importPath !in importsToIgnore
- }.forEach { append(ContentText(it.text)) }
- }
- }
- }
- return super.processImports(psiElement)
- }
-
- override fun processSampleBody(psiElement: PsiElement) = when (psiElement) {
- is KtDeclarationWithBody -> {
- val bodyExpression = psiElement.bodyExpression
- val bodyExpressionText = bodyExpression!!.buildSampleText()
- when (bodyExpression) {
- is KtBlockExpression -> bodyExpressionText.removeSurrounding("{", "}")
- else -> bodyExpressionText
- }
- }
- else -> psiElement.buildSampleText()
- }
-}
-
diff --git a/core/src/main/kotlin/Samples/SampleProcessingService.kt b/core/src/main/kotlin/Samples/SampleProcessingService.kt
deleted file mode 100644
index 86c917cf..00000000
--- a/core/src/main/kotlin/Samples/SampleProcessingService.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.jetbrains.dokka.Samples
-
-import org.jetbrains.dokka.ContentNode
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-
-interface SampleProcessingService {
- fun resolveSample(descriptor: DeclarationDescriptor, functionName: String?, kdocTag: KDocTag): ContentNode
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Utilities/DokkaLogging.kt b/core/src/main/kotlin/Utilities/DokkaLogging.kt
deleted file mode 100644
index 1ef52837..00000000
--- a/core/src/main/kotlin/Utilities/DokkaLogging.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.jetbrains.dokka
-
-interface DokkaLogger {
- fun info(message: String)
- fun warn(message: String)
- fun error(message: String)
-}
-
-object DokkaConsoleLogger : DokkaLogger {
- var warningCount: Int = 0
-
- override fun info(message: String) = println(message)
- override fun warn(message: String) {
- println("WARN: $message")
- warningCount++
- }
-
- override fun error(message: String) = println("ERROR: $message")
-
- fun report() {
- if (warningCount > 0) {
- println("generation completed with $warningCount warnings")
- } else {
- println("generation completed successfully")
- }
- }
-}
diff --git a/core/src/main/kotlin/Utilities/DokkaModules.kt b/core/src/main/kotlin/Utilities/DokkaModules.kt
deleted file mode 100644
index 919ec30f..00000000
--- a/core/src/main/kotlin/Utilities/DokkaModules.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.jetbrains.dokka.Utilities
-
-import com.google.inject.Binder
-import com.google.inject.Module
-import com.google.inject.TypeLiteral
-import com.google.inject.binder.AnnotatedBindingBuilder
-import com.google.inject.name.Names
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Formats.FormatDescriptor
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import java.io.File
-import kotlin.reflect.KClass
-
-const val impliedPlatformsName = "impliedPlatforms"
-
-class DokkaRunModule(val configuration: DokkaConfiguration) : Module {
- override fun configure(binder: Binder) {
- binder.bind<DokkaConfiguration>().toInstance(configuration)
- binder.bind(StringListType).annotatedWith(Names.named(impliedPlatformsName)).toInstance(configuration.impliedPlatforms)
-
- binder.bind(File::class.java).annotatedWith(Names.named("outputDir")).toInstance(File(configuration.outputDir))
- }
-
-}
-
-class DokkaAnalysisModule(val environment: AnalysisEnvironment,
- val configuration: DokkaConfiguration,
- val defaultPlatformsProvider: DefaultPlatformsProvider,
- val nodeReferenceGraph: NodeReferenceGraph,
- val passConfiguration: DokkaConfiguration.PassConfiguration,
- val logger: DokkaLogger) : Module {
- override fun configure(binder: Binder) {
- binder.bind<DokkaLogger>().toInstance(logger)
-
- val coreEnvironment = environment.createCoreEnvironment()
- binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
-
- val (dokkaResolutionFacade, libraryResolutionFacade) = environment.createResolutionFacade(coreEnvironment)
- binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
- binder.bind<DokkaResolutionFacade>().annotatedWith(Names.named("libraryResolutionFacade")).toInstance(libraryResolutionFacade)
-
- binder.bind<DokkaConfiguration.PassConfiguration>().toInstance(passConfiguration)
-
- binder.bind<DefaultPlatformsProvider>().toInstance(defaultPlatformsProvider)
-
- binder.bind<NodeReferenceGraph>().toInstance(nodeReferenceGraph)
-
- val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", configuration.format)
- descriptor.configureAnalysis(binder)
- }
-}
-
-object StringListType : TypeLiteral<@JvmSuppressWildcards List<String>>()
-
-class DokkaOutputModule(val configuration: DokkaConfiguration,
- val logger: DokkaLogger) : Module {
- override fun configure(binder: Binder) {
- binder.bind<DokkaLogger>().toInstance(logger)
-
- val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", configuration.format)
-
- descriptor.configureOutput(binder)
- }
-}
-
-private inline fun <reified T: Any> Binder.registerCategory(category: String) {
- ServiceLocator.allServices(category).forEach {
- @Suppress("UNCHECKED_CAST")
- bind(T::class.java).annotatedWith(Names.named(it.name)).to(T::class.java.classLoader.loadClass(it.className) as Class<T>)
- }
-}
-
-private inline fun <reified Base : Any, reified T : Base> Binder.bindNameAnnotated(name: String) {
- bind(Base::class.java).annotatedWith(Names.named(name)).to(T::class.java)
-}
-
-
-inline fun <reified T: Any> Binder.bind(): AnnotatedBindingBuilder<T> = bind(T::class.java)
-
-inline fun <reified T: Any> Binder.lazyBind(): Lazy<AnnotatedBindingBuilder<T>> = lazy { bind(T::class.java) }
-
-inline infix fun <reified T: Any, TKClass: KClass<out T>> Lazy<AnnotatedBindingBuilder<T>>.toOptional(kClass: TKClass?) =
- kClass?.let { value toType it }
-
-inline infix fun <reified T: Any, TKClass: KClass<out T>> AnnotatedBindingBuilder<T>.toType(kClass: TKClass) = to(kClass.java)
diff --git a/core/src/main/kotlin/Utilities/Links.kt b/core/src/main/kotlin/Utilities/Links.kt
deleted file mode 100644
index 34423e4e..00000000
--- a/core/src/main/kotlin/Utilities/Links.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.jetbrains.dokka.Utilities
-
-import org.jetbrains.dokka.DokkaConfiguration
-import org.jetbrains.dokka.ExternalDocumentationLinkImpl
-
-fun DokkaConfiguration.PassConfiguration.defaultLinks(): List<ExternalDocumentationLinkImpl> {
- val links = mutableListOf<ExternalDocumentationLinkImpl>()
- if (!noJdkLink)
- links += DokkaConfiguration.ExternalDocumentationLink
- .Builder("https://docs.oracle.com/javase/${jdkVersion}/docs/api/")
- .build() as ExternalDocumentationLinkImpl
-
- if (!noStdlibLink)
- links += DokkaConfiguration.ExternalDocumentationLink
- .Builder("https://kotlinlang.org/api/latest/jvm/stdlib/")
- .build() as ExternalDocumentationLinkImpl
- return links
-}
diff --git a/core/src/main/kotlin/Utilities/Path.kt b/core/src/main/kotlin/Utilities/Path.kt
deleted file mode 100644
index 05838499..00000000
--- a/core/src/main/kotlin/Utilities/Path.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.jetbrains.dokka
-
-import java.io.File
-
-fun File.appendExtension(extension: String) = if (extension.isEmpty()) this else File(path + "." + extension)
diff --git a/core/src/main/kotlin/configuration.kt b/core/src/main/kotlin/configuration.kt
new file mode 100644
index 00000000..eaee351b
--- /dev/null
+++ b/core/src/main/kotlin/configuration.kt
@@ -0,0 +1,149 @@
+@file:Suppress("FunctionName")
+
+package org.jetbrains.dokka
+
+import com.google.gson.Gson
+import java.io.File
+import java.io.Serializable
+import java.net.URL
+
+object DokkaDefaults {
+ const val outputDir = "./dokka"
+ const val format: String = "html"
+ val cacheRoot: String? = null
+ const val offlineMode: Boolean = false
+ const val failOnWarning: Boolean = false
+
+ const val includeNonPublic: Boolean = false
+ const val includeRootPackage: Boolean = false
+ const val reportUndocumented: Boolean = false
+ const val skipEmptyPackages: Boolean = false
+ const val skipDeprecated: Boolean = false
+ const val jdkVersion: Int = 8
+ const val noStdlibLink: Boolean = false
+ const val noJdkLink: Boolean = false
+ val analysisPlatform: Platform = Platform.DEFAULT
+ const val suppress: Boolean = false
+}
+
+enum class Platform(val key: String) {
+ jvm("jvm"),
+ js("js"),
+ native("native"),
+ common("common");
+
+ companion object {
+ val DEFAULT = jvm
+
+ fun fromString(key: String): Platform {
+ return when (key.toLowerCase()) {
+ jvm.key -> jvm
+ js.key -> js
+ native.key -> native
+ common.key -> common
+ else -> throw IllegalArgumentException("Unrecognized platform: $key")
+ }
+ }
+ }
+}
+
+data class DokkaSourceSetID(
+ val moduleName: String,
+ val sourceSetName: String
+) : Serializable {
+ override fun toString(): String {
+ return "$moduleName/$sourceSetName"
+ }
+}
+
+fun DokkaConfigurationImpl(json: String): DokkaConfigurationImpl {
+ return Gson().fromJson(json, DokkaConfigurationImpl::class.java)
+}
+
+fun DokkaConfiguration.toJson(): String {
+ return Gson().toJson(this)
+}
+
+interface DokkaConfiguration {
+ val outputDir: String
+ val cacheRoot: String?
+ val offlineMode: Boolean
+ val failOnWarning: Boolean
+ val sourceSets: List<DokkaSourceSet>
+ val modules: List<DokkaModuleDescription>
+ val pluginsClasspath: List<File>
+ val pluginsConfiguration: Map<String, String>
+
+ interface DokkaSourceSet {
+ val sourceSetID: DokkaSourceSetID
+ val displayName: String
+ val moduleDisplayName: String
+ val classpath: List<String>
+ val sourceRoots: List<SourceRoot>
+ val dependentSourceSets: Set<DokkaSourceSetID>
+ val samples: List<String>
+ val includes: List<String>
+ val includeNonPublic: Boolean
+ val includeRootPackage: Boolean
+ val reportUndocumented: Boolean
+ val skipEmptyPackages: Boolean
+ val skipDeprecated: Boolean
+ val jdkVersion: Int
+ val sourceLinks: List<SourceLinkDefinition>
+ val perPackageOptions: List<PackageOptions>
+ val externalDocumentationLinks: List<ExternalDocumentationLink>
+ val languageVersion: String?
+ val apiVersion: String?
+ val noStdlibLink: Boolean
+ val noJdkLink: Boolean
+ val suppressedFiles: List<String>
+ val analysisPlatform: Platform
+ }
+
+ interface SourceRoot {
+ val path: String
+ }
+
+ interface SourceLinkDefinition {
+ val path: String
+ val url: String
+ val lineSuffix: String?
+ }
+
+ interface DokkaModuleDescription {
+ val name: String
+ val path: String
+ val docFile: String
+ }
+
+ interface PackageOptions {
+ val prefix: String
+ val includeNonPublic: Boolean
+ val reportUndocumented: Boolean?
+ val skipDeprecated: Boolean
+ val suppress: Boolean
+ }
+
+ interface ExternalDocumentationLink {
+ val url: URL
+ val packageListUrl: URL
+
+ open class Builder(
+ open var url: URL? = null,
+ open var packageListUrl: URL? = null
+ ) {
+
+ constructor(root: String, packageList: String? = null) : this(URL(root), packageList?.let { URL(it) })
+
+ fun build(): ExternalDocumentationLink =
+ if (packageListUrl != null && url != null)
+ ExternalDocumentationLinkImpl(url!!, packageListUrl!!)
+ else if (url != null)
+ ExternalDocumentationLinkImpl(url!!, URL(url!!, "package-list"))
+ else
+ throw IllegalArgumentException("url or url && packageListUrl must not be null for external documentation link")
+ }
+ }
+}
+
+
diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt
new file mode 100644
index 00000000..02274e5d
--- /dev/null
+++ b/core/src/main/kotlin/defaultConfiguration.kt
@@ -0,0 +1,83 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import java.io.File
+import java.net.URL
+import java.io.Serializable
+
+data class DokkaConfigurationImpl(
+ override val outputDir: String,
+ override val cacheRoot: String?,
+ override val offlineMode: Boolean,
+ override val sourceSets: List<DokkaSourceSetImpl>,
+ override val pluginsClasspath: List<File>,
+ override val pluginsConfiguration: Map<String, String>,
+ override val modules: List<DokkaModuleDescriptionImpl>,
+ override val failOnWarning: Boolean
+) : DokkaConfiguration
+
+data class DokkaSourceSetImpl(
+ override val moduleDisplayName: String,
+ override val displayName: String,
+ override val sourceSetID: DokkaSourceSetID,
+ override val classpath: List<String>,
+ override val sourceRoots: List<SourceRootImpl>,
+ override val dependentSourceSets: Set<DokkaSourceSetID>,
+ override val samples: List<String>,
+ override val includes: List<String>,
+ override val includeNonPublic: Boolean,
+ override val includeRootPackage: Boolean,
+ override val reportUndocumented: Boolean,
+ override val skipEmptyPackages: Boolean,
+ override val skipDeprecated: Boolean,
+ override val jdkVersion: Int,
+ override val sourceLinks: List<SourceLinkDefinitionImpl>,
+ override val perPackageOptions: List<PackageOptionsImpl>,
+ override var externalDocumentationLinks: List<ExternalDocumentationLinkImpl>,
+ override val languageVersion: String?,
+ override val apiVersion: String?,
+ override val noStdlibLink: Boolean,
+ override val noJdkLink: Boolean,
+ override val suppressedFiles: List<String>,
+ override val analysisPlatform: Platform
+) : DokkaSourceSet
+
+data class DokkaModuleDescriptionImpl(
+ override val name: String,
+ override val path: String,
+ override val docFile: String
+) : DokkaConfiguration.DokkaModuleDescription
+
+data class SourceRootImpl(
+ override val path: String
+) : DokkaConfiguration.SourceRoot
+
+data class SourceLinkDefinitionImpl(
+ override val path: String,
+ override val url: String,
+ override val lineSuffix: String?
+) : DokkaConfiguration.SourceLinkDefinition {
+ companion object {
+ fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinitionImpl {
+ val (path, urlAndLine) = srcLink.split('=')
+ return SourceLinkDefinitionImpl(
+ File(path).canonicalPath,
+ urlAndLine.substringBefore("#"),
+ urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#$it" })
+ }
+ }
+}
+
+data class PackageOptionsImpl(
+ override val prefix: String,
+ override val includeNonPublic: Boolean,
+ override val reportUndocumented: Boolean?,
+ override val skipDeprecated: Boolean,
+ override val suppress: Boolean
+) : DokkaConfiguration.PackageOptions
+
+
+data class ExternalDocumentationLinkImpl(
+ override val url: URL,
+ override val packageListUrl: URL
+) : DokkaConfiguration.ExternalDocumentationLink, Serializable
diff --git a/core/src/main/kotlin/javadoc/docbase.kt b/core/src/main/kotlin/javadoc/docbase.kt
deleted file mode 100644
index 0bf72ccf..00000000
--- a/core/src/main/kotlin/javadoc/docbase.kt
+++ /dev/null
@@ -1,539 +0,0 @@
-package org.jetbrains.dokka.javadoc
-
-import com.sun.javadoc.*
-import org.jetbrains.dokka.*
-import java.lang.reflect.Modifier.*
-import java.util.*
-import kotlin.reflect.KClass
-
-private interface HasModule {
- val module: ModuleNodeAdapter
-}
-
-private interface HasDocumentationNode {
- val node: DocumentationNode
-}
-
-open class DocumentationNodeBareAdapter(override val node: DocumentationNode) : Doc, HasDocumentationNode {
- private var rawCommentText_: String? = null
-
- override fun name(): String = node.name
- override fun position(): SourcePosition? = SourcePositionAdapter(node)
-
- override fun inlineTags(): Array<out Tag>? = emptyArray()
- override fun firstSentenceTags(): Array<out Tag>? = emptyArray()
- override fun tags(): Array<out Tag> = emptyArray()
- override fun tags(tagname: String?): Array<out Tag>? = tags().filter { it.kind() == tagname || it.kind() == "@$tagname" }.toTypedArray()
- override fun seeTags(): Array<out SeeTag>? = tags().filterIsInstance<SeeTag>().toTypedArray()
- override fun commentText(): String = ""
-
- override fun setRawCommentText(rawDocumentation: String?) {
- rawCommentText_ = rawDocumentation ?: ""
- }
-
- override fun getRawCommentText(): String = rawCommentText_ ?: ""
-
- override fun isError(): Boolean = false
- override fun isException(): Boolean = node.kind == NodeKind.Exception
- override fun isEnumConstant(): Boolean = node.kind == NodeKind.EnumItem
- override fun isEnum(): Boolean = node.kind == NodeKind.Enum
- override fun isMethod(): Boolean = node.kind == NodeKind.Function
- override fun isInterface(): Boolean = node.kind == NodeKind.Interface
- override fun isField(): Boolean = node.kind == NodeKind.Field
- override fun isClass(): Boolean = node.kind == NodeKind.Class
- override fun isAnnotationType(): Boolean = node.kind == NodeKind.AnnotationClass
- override fun isConstructor(): Boolean = node.kind == NodeKind.Constructor
- override fun isOrdinaryClass(): Boolean = node.kind == NodeKind.Class
- override fun isAnnotationTypeElement(): Boolean = node.kind == NodeKind.Annotation
-
- override fun compareTo(other: Any?): Int = when (other) {
- !is DocumentationNodeAdapter -> 1
- else -> node.name.compareTo(other.node.name)
- }
-
- override fun equals(other: Any?): Boolean = node.qualifiedName() == (other as? DocumentationNodeAdapter)?.node?.qualifiedName()
- override fun hashCode(): Int = node.name.hashCode()
-
- override fun isIncluded(): Boolean = node.kind != NodeKind.ExternalClass
-}
-
-
-// TODO think of source position instead of null
-// TODO tags
-open class DocumentationNodeAdapter(override val module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeBareAdapter(node), HasModule {
- override fun inlineTags(): Array<out Tag> = buildInlineTags(module, this, node.content).toTypedArray()
- override fun firstSentenceTags(): Array<out Tag> = buildInlineTags(module, this, node.summary).toTypedArray()
-
- override fun tags(): Array<out Tag> {
- val result = ArrayList<Tag>(buildInlineTags(module, this, node.content))
- node.content.sections.flatMapTo(result) {
- when (it.tag) {
- ContentTags.SeeAlso -> buildInlineTags(module, this, it)
- else -> emptyList<Tag>()
- }
- }
-
- node.deprecation?.let {
- val content = it.content.asText()
- result.add(TagImpl(this, "deprecated", content ?: ""))
- }
-
- return result.toTypedArray()
- }
-}
-
-// should be extension property but can't because of KT-8745
-private fun <T> nodeAnnotations(self: T): List<AnnotationDescAdapter> where T : HasModule, T : HasDocumentationNode
- = self.node.annotations.map { AnnotationDescAdapter(self.module, it) }
-
-private fun DocumentationNode.hasAnnotation(klass: KClass<*>) = klass.qualifiedName in annotations.map { it.qualifiedName() }
-private fun DocumentationNode.hasModifier(name: String) = details(NodeKind.Modifier).any { it.name == name }
-
-
-class PackageAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), PackageDoc {
- private val allClasses = listOf(node).collectAllTypesRecursively()
-
- override fun findClass(className: String?): ClassDoc? =
- allClasses.get(className)?.let { ClassDocumentationNodeAdapter(module, it) }
-
- override fun annotationTypes(): Array<out AnnotationTypeDoc> = emptyArray()
- override fun annotations(): Array<out AnnotationDesc> = node.members(NodeKind.AnnotationClass).map { AnnotationDescAdapter(module, it) }.toTypedArray()
- override fun exceptions(): Array<out ClassDoc> = node.members(NodeKind.Exception).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
- override fun ordinaryClasses(): Array<out ClassDoc> = node.members(NodeKind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
- override fun interfaces(): Array<out ClassDoc> = node.members(NodeKind.Interface).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
- override fun errors(): Array<out ClassDoc> = emptyArray()
- override fun enums(): Array<out ClassDoc> = node.members(NodeKind.Enum).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
- override fun allClasses(filter: Boolean): Array<out ClassDoc> = allClasses.values.map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
- override fun allClasses(): Array<out ClassDoc> = allClasses(true)
-
- override fun isIncluded(): Boolean = node.name in module.allPackages
-}
-
-class AnnotationTypeDocAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : ClassDocumentationNodeAdapter(module, node), AnnotationTypeDoc {
- override fun elements(): Array<out AnnotationTypeElementDoc>? = emptyArray() // TODO
-}
-
-class AnnotationDescAdapter(val module: ModuleNodeAdapter, val node: DocumentationNode) : AnnotationDesc {
- override fun annotationType(): AnnotationTypeDoc? = AnnotationTypeDocAdapter(module, node.links.find { it.kind == NodeKind.AnnotationClass } ?: node) // TODO ?????
- override fun isSynthesized(): Boolean = false
- override fun elementValues(): Array<out AnnotationDesc.ElementValuePair>? = emptyArray() // TODO
-}
-
-open class ProgramElementAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), ProgramElementDoc {
- override fun isPublic(): Boolean = node.hasModifier("public") || node.hasModifier("internal")
- override fun isPackagePrivate(): Boolean = false
- override fun isStatic(): Boolean = node.hasModifier("static")
- override fun modifierSpecifier(): Int = visibilityModifier or (if (isStatic) STATIC else 0)
- private val visibilityModifier
- get() = when {
- isPublic -> PUBLIC
- isPrivate -> PRIVATE
- isProtected -> PROTECTED
- else -> 0
- }
- override fun qualifiedName(): String? = node.qualifiedName()
- override fun annotations(): Array<out AnnotationDesc>? = nodeAnnotations(this).toTypedArray()
- override fun modifiers(): String? = "public ${if (isStatic) "static" else ""}".trim()
- override fun isProtected(): Boolean = node.hasModifier("protected")
-
- override fun isFinal(): Boolean = node.hasModifier("final")
-
- override fun containingPackage(): PackageDoc? {
- if (node.kind == NodeKind.Type) {
- return null
- }
-
- var owner: DocumentationNode? = node
- while (owner != null) {
- if (owner.kind == NodeKind.Package) {
- return PackageAdapter(module, owner)
- }
- owner = owner.owner
- }
-
- return null
- }
-
- override fun containingClass(): ClassDoc? {
- if (node.kind == NodeKind.Type) {
- return null
- }
-
- var owner = node.owner
- while (owner != null) {
- if (owner.kind in NodeKind.classLike) {
- return ClassDocumentationNodeAdapter(module, owner)
- }
- owner = owner.owner
- }
-
- return null
- }
-
- override fun isPrivate(): Boolean = node.hasModifier("private")
- override fun isIncluded(): Boolean = containingPackage()?.isIncluded ?: false && containingClass()?.let { it.isIncluded } ?: true
-}
-
-open class TypeAdapter(override val module: ModuleNodeAdapter, override val node: DocumentationNode) : Type, HasDocumentationNode, HasModule {
- private val javaLanguageService = JavaLanguageService()
-
- override fun qualifiedTypeName(): String = javaLanguageService.getArrayElementType(node)?.qualifiedNameFromType() ?: node.qualifiedNameFromType()
- override fun typeName(): String = (javaLanguageService.getArrayElementType(node)?.simpleName() ?: node.simpleName()) + dimension()
- override fun simpleTypeName(): String = typeName() // TODO difference typeName() vs simpleTypeName()
-
- override fun dimension(): String = Collections.nCopies(javaLanguageService.getArrayDimension(node), "[]").joinToString("")
- override fun isPrimitive(): Boolean = simpleTypeName() in setOf("int", "long", "short", "byte", "char", "double", "float", "boolean", "void")
-
- override fun asClassDoc(): ClassDoc? = if (isPrimitive) null else
- elementType?.asClassDoc() ?:
- when (node.kind) {
- in NodeKind.classLike,
- NodeKind.ExternalClass,
- NodeKind.Exception -> module.classNamed(qualifiedTypeName()) ?: ClassDocumentationNodeAdapter(module, node)
-
- else -> when {
- node.links.isNotEmpty() -> TypeAdapter(module, node.links.first()).asClassDoc()
- else -> ClassDocumentationNodeAdapter(module, node) // TODO ?
- }
- }
-
- override fun asTypeVariable(): TypeVariable? = if (node.kind == NodeKind.TypeParameter) TypeVariableAdapter(module, node) else null
- override fun asParameterizedType(): ParameterizedType? =
- if (node.details(NodeKind.Type).isNotEmpty() && javaLanguageService.getArrayElementType(node) == null)
- ParameterizedTypeAdapter(module, node)
- else
- null
-
- override fun asAnnotationTypeDoc(): AnnotationTypeDoc? = if (node.kind == NodeKind.AnnotationClass) AnnotationTypeDocAdapter(module, node) else null
- override fun asAnnotatedType(): AnnotatedType? = if (node.annotations.isNotEmpty()) AnnotatedTypeAdapter(module, node) else null
- override fun getElementType(): Type? = javaLanguageService.getArrayElementType(node)?.let { et -> TypeAdapter(module, et) }
- override fun asWildcardType(): WildcardType? = null
-
- override fun toString(): String = qualifiedTypeName() + dimension()
- override fun hashCode(): Int = node.name.hashCode()
- override fun equals(other: Any?): Boolean = other is TypeAdapter && toString() == other.toString()
-}
-
-class NotAnnotatedTypeAdapter(typeAdapter: AnnotatedTypeAdapter) : Type by typeAdapter {
- override fun asAnnotatedType() = null
-}
-
-class AnnotatedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), AnnotatedType {
- override fun underlyingType(): Type? = NotAnnotatedTypeAdapter(this)
- override fun annotations(): Array<out AnnotationDesc> = nodeAnnotations(this).toTypedArray()
-}
-
-class WildcardTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), WildcardType {
- override fun extendsBounds(): Array<out Type> = node.details(NodeKind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray()
- override fun superBounds(): Array<out Type> = node.details(NodeKind.LowerBound).map { TypeAdapter(module, it) }.toTypedArray()
-}
-
-class TypeVariableAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), TypeVariable {
- override fun owner(): ProgramElementDoc = node.owner!!.let<DocumentationNode, ProgramElementDoc> { owner ->
- when (owner.kind) {
- NodeKind.Function,
- NodeKind.Constructor -> ExecutableMemberAdapter(module, owner)
-
- NodeKind.Class,
- NodeKind.Interface,
- NodeKind.Enum -> ClassDocumentationNodeAdapter(module, owner)
-
- else -> ProgramElementAdapter(module, node.owner!!)
- }
- }
-
- override fun bounds(): Array<out Type>? = node.details(NodeKind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray()
- override fun annotations(): Array<out AnnotationDesc>? = node.members(NodeKind.Annotation).map { AnnotationDescAdapter(module, it) }.toTypedArray()
-
- override fun qualifiedTypeName(): String = node.name
- override fun simpleTypeName(): String = node.name
- override fun typeName(): String = node.name
-
- override fun hashCode(): Int = node.name.hashCode()
- override fun equals(other: Any?): Boolean = other is Type && other.typeName() == typeName() && other.asTypeVariable()?.owner() == owner()
-
- override fun asTypeVariable(): TypeVariableAdapter = this
-}
-
-class ParameterizedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), ParameterizedType {
- override fun typeArguments(): Array<out Type> = node.details(NodeKind.Type).map { TypeVariableAdapter(module, it) }.toTypedArray()
- override fun superclassType(): Type? =
- node.lookupSuperClasses(module)
- .firstOrNull { it.kind == NodeKind.Class || it.kind == NodeKind.ExternalClass }
- ?.let { ClassDocumentationNodeAdapter(module, it) }
-
- override fun interfaceTypes(): Array<out Type> =
- node.lookupSuperClasses(module)
- .filter { it.kind == NodeKind.Interface }
- .map { ClassDocumentationNodeAdapter(module, it) }
- .toTypedArray()
-
- override fun containingType(): Type? = when (node.owner?.kind) {
- NodeKind.Package -> null
- NodeKind.Class,
- NodeKind.Interface,
- NodeKind.Object,
- NodeKind.Enum -> ClassDocumentationNodeAdapter(module, node.owner!!)
-
- else -> null
- }
-}
-
-class ParameterAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), Parameter {
- override fun typeName(): String? = type()?.typeName()
- override fun type(): Type? = TypeAdapter(module, node.detail(NodeKind.Type))
- override fun annotations(): Array<out AnnotationDesc> = nodeAnnotations(this).toTypedArray()
-}
-
-class ReceiverParameterAdapter(module: ModuleNodeAdapter, val receiverType: DocumentationNode, val parent: ExecutableMemberAdapter) : DocumentationNodeAdapter(module, receiverType), Parameter {
- override fun typeName(): String? = receiverType.name
- override fun type(): Type? = TypeAdapter(module, receiverType)
- override fun annotations(): Array<out AnnotationDesc> = nodeAnnotations(this).toTypedArray()
- override fun name(): String = tryName("receiver")
-
- private tailrec fun tryName(name: String): String = when (name) {
- in parent.parameters().drop(1).map { it.name() } -> tryName("$$name")
- else -> name
- }
-}
-
-fun classOf(fqName: String, kind: NodeKind = NodeKind.Class) = DocumentationNode(fqName.substringAfterLast(".", fqName), Content.Empty, kind).let { node ->
- val pkg = fqName.substringBeforeLast(".", "")
- if (pkg.isNotEmpty()) {
- node.append(DocumentationNode(pkg, Content.Empty, NodeKind.Package), RefKind.Owner)
- }
-
- node
-}
-
-private fun DocumentationNode.hasNonEmptyContent() =
- this.content.summary !is ContentEmpty || this.content.description !is ContentEmpty || this.content.sections.isNotEmpty()
-
-
-open class ExecutableMemberAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : ProgramElementAdapter(module, node), ExecutableMemberDoc {
-
- override fun isSynthetic(): Boolean = false
- override fun isNative(): Boolean = node.annotations.any { it.name == "native" }
-
- override fun thrownExceptions(): Array<out ClassDoc> = emptyArray() // TODO
- override fun throwsTags(): Array<out ThrowsTag> =
- node.content.sections
- .filter { it.tag == ContentTags.Exceptions && it.subjectName != null }
- .map { ThrowsTagAdapter(this, ClassDocumentationNodeAdapter(module, classOf(it.subjectName!!, NodeKind.Exception)), it.children) }
- .toTypedArray()
-
- override fun isVarArgs(): Boolean = node.details(NodeKind.Parameter).last().hasModifier("vararg")
-
- override fun isSynchronized(): Boolean = node.annotations.any { it.name == "synchronized" }
-
- override fun paramTags(): Array<out ParamTag> =
- collectParamTags(NodeKind.Parameter, sectionFilter = { it.subjectName in parameters().map { it.name() } })
-
- override fun thrownExceptionTypes(): Array<out Type> = emptyArray()
- override fun receiverType(): Type? = receiverNode()?.let { receiver -> TypeAdapter(module, receiver) }
- override fun flatSignature(): String = node.details(NodeKind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")")
- override fun signature(): String = node.details(NodeKind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")") // TODO it should be FQ types
-
- override fun parameters(): Array<out Parameter> =
- ((receiverNode()?.let { receiver -> listOf<Parameter>(ReceiverParameterAdapter(module, receiver, this)) } ?: emptyList())
- + node.details(NodeKind.Parameter).map { ParameterAdapter(module, it) }
- ).toTypedArray()
-
- override fun typeParameters(): Array<out TypeVariable> = node.details(NodeKind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray()
-
- override fun typeParamTags(): Array<out ParamTag> =
- collectParamTags(NodeKind.TypeParameter, sectionFilter = { it.subjectName in typeParameters().map { it.simpleTypeName() } })
-
- private fun receiverNode() = node.details(NodeKind.Receiver).let { receivers ->
- when {
- receivers.isNotEmpty() -> receivers.single().detail(NodeKind.Type)
- else -> null
- }
- }
-}
-
-class ConstructorAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : ExecutableMemberAdapter(module, node), ConstructorDoc {
- override fun name(): String = node.owner?.name ?: throw IllegalStateException("No owner for $node")
-
- override fun containingClass(): ClassDoc? {
- return super.containingClass()
- }
-}
-
-class MethodAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : ExecutableMemberAdapter(module, node), MethodDoc {
- override fun overrides(meth: MethodDoc?): Boolean = false // TODO
-
- override fun overriddenType(): Type? = node.overrides.firstOrNull()?.owner?.let { owner -> TypeAdapter(module, owner) }
-
- override fun overriddenMethod(): MethodDoc? = node.overrides.map { MethodAdapter(module, it) }.firstOrNull()
- override fun overriddenClass(): ClassDoc? = overriddenMethod()?.containingClass()
-
- override fun isAbstract(): Boolean = false // TODO
-
- override fun isDefault(): Boolean = false
-
- override fun returnType(): Type = TypeAdapter(module, node.detail(NodeKind.Type))
-
- override fun tags(tagname: String?) = super.tags(tagname)
-
- override fun tags(): Array<out Tag> {
- val tags = super.tags().toMutableList()
- node.content.findSectionByTag(ContentTags.Return)?.let {
- tags += ReturnTagAdapter(module, this, it.children)
- }
-
- return tags.toTypedArray()
- }
-}
-
-class FieldAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : ProgramElementAdapter(module, node), FieldDoc {
- override fun isSynthetic(): Boolean = false
-
- override fun constantValueExpression(): String? = node.detailOrNull(NodeKind.Value)?.let { it.name }
- override fun constantValue(): Any? = constantValueExpression()
-
- override fun type(): Type = TypeAdapter(module, node.detail(NodeKind.Type))
- override fun isTransient(): Boolean = node.hasAnnotation(Transient::class)
- override fun serialFieldTags(): Array<out SerialFieldTag> = emptyArray()
-
- override fun isVolatile(): Boolean = node.hasAnnotation(Volatile::class)
-}
-open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNode: DocumentationNode)
- : ProgramElementAdapter(module, classNode),
- Type by TypeAdapter(module, classNode),
- ClassDoc,
- AnnotationTypeDoc {
-
- override fun elements(): Array<out AnnotationTypeElementDoc>? = emptyArray() // TODO
-
- override fun name(): String {
- val parent = classNode.owner
- if (parent?.kind in NodeKind.classLike) {
- return parent!!.name + "." + classNode.name
- }
- return classNode.simpleName()
- }
-
- override fun qualifiedName(): String? {
- return super.qualifiedName()
- }
- override fun constructors(filter: Boolean): Array<out ConstructorDoc> = classNode.members(NodeKind.Constructor).map { ConstructorAdapter(module, it) }.toTypedArray()
- override fun constructors(): Array<out ConstructorDoc> = constructors(true)
- override fun importedPackages(): Array<out PackageDoc> = emptyArray()
- override fun importedClasses(): Array<out ClassDoc>? = emptyArray()
- override fun typeParameters(): Array<out TypeVariable> = classNode.details(NodeKind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray()
- override fun asTypeVariable(): TypeVariable? = if (classNode.kind == NodeKind.Class) TypeVariableAdapter(module, classNode) else null
- override fun isExternalizable(): Boolean = interfaces().any { it.qualifiedName() == "java.io.Externalizable" }
- override fun definesSerializableFields(): Boolean = false
- override fun methods(filter: Boolean): Array<out MethodDoc> = classNode.members(NodeKind.Function).map { MethodAdapter(module, it) }.toTypedArray() // TODO include get/set methods
- override fun methods(): Array<out MethodDoc> = methods(true)
- override fun enumConstants(): Array<out FieldDoc>? = classNode.members(NodeKind.EnumItem).map { FieldAdapter(module, it) }.toTypedArray()
- override fun isAbstract(): Boolean = classNode.details(NodeKind.Modifier).any { it.name == "abstract" }
- override fun interfaceTypes(): Array<out Type> = classNode.lookupSuperClasses(module)
- .filter { it.kind == NodeKind.Interface }
- .map { ClassDocumentationNodeAdapter(module, it) }
- .toTypedArray()
-
- override fun interfaces(): Array<out ClassDoc> = classNode.lookupSuperClasses(module)
- .filter { it.kind == NodeKind.Interface }
- .map { ClassDocumentationNodeAdapter(module, it) }
- .toTypedArray()
-
- override fun typeParamTags(): Array<out ParamTag> =
- collectParamTags(NodeKind.TypeParameter, sectionFilter = { it.subjectName in typeParameters().map { it.simpleTypeName() } })
-
- override fun fields(): Array<out FieldDoc> = fields(true)
- override fun fields(filter: Boolean): Array<out FieldDoc> = classNode.members(NodeKind.Field).map { FieldAdapter(module, it) }.toTypedArray()
-
- override fun findClass(className: String?): ClassDoc? = null // TODO !!!
- override fun serializableFields(): Array<out FieldDoc> = emptyArray()
- override fun superclassType(): Type? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == NodeKind.Class }?.let { ClassDocumentationNodeAdapter(module, it) }
- override fun serializationMethods(): Array<out MethodDoc> = emptyArray() // TODO
- override fun superclass(): ClassDoc? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == NodeKind.Class }?.let { ClassDocumentationNodeAdapter(module, it) }
- override fun isSerializable(): Boolean = false // TODO
- override fun subclassOf(cd: ClassDoc?): Boolean {
- if (cd == null) {
- return false
- }
-
- val expectedFQName = cd.qualifiedName()
- val types = arrayListOf(classNode)
- val visitedTypes = HashSet<String>()
-
- while (types.isNotEmpty()) {
- val type = types.removeAt(types.lastIndex)
- val fqName = type.qualifiedName()
-
- if (expectedFQName == fqName) {
- return true
- }
-
- visitedTypes.add(fqName)
- types.addAll(type.details(NodeKind.Supertype).filter { it.qualifiedName() !in visitedTypes })
- }
-
- return false
- }
-
- override fun innerClasses(): Array<out ClassDoc> = classNode.members(NodeKind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray()
- override fun innerClasses(filter: Boolean): Array<out ClassDoc> = innerClasses()
-}
-
-fun DocumentationNode.lookupSuperClasses(module: ModuleNodeAdapter) =
- details(NodeKind.Supertype)
- .map { it.links.firstOrNull() }.mapNotNull { module.allTypes[it?.qualifiedName()] }
-
-fun List<DocumentationNode>.collectAllTypesRecursively(): Map<String, DocumentationNode> {
- val result = hashMapOf<String, DocumentationNode>()
-
- fun DocumentationNode.collectTypesRecursively() {
- val classLikeMembers = NodeKind.classLike.flatMap { members(it) }
- classLikeMembers.forEach {
- result.put(it.qualifiedName(), it)
- it.collectTypesRecursively()
- }
- }
-
- forEach { it.collectTypesRecursively() }
- return result
-}
-
-class ModuleNodeAdapter(val module: DocumentationModule, val reporter: DocErrorReporter, val outputPath: String) : DocumentationNodeBareAdapter(module), DocErrorReporter by reporter, RootDoc {
- val allPackages = module.members(NodeKind.Package).associateBy { it.name }
- val allTypes = module.members(NodeKind.Package).collectAllTypesRecursively()
-
- override fun packageNamed(name: String?): PackageDoc? = allPackages[name]?.let { PackageAdapter(this, it) }
-
- override fun classes(): Array<out ClassDoc> =
- allTypes.values.map { ClassDocumentationNodeAdapter(this, it) }.toTypedArray()
-
- override fun options(): Array<out Array<String>> = arrayOf(
- arrayOf("-d", outputPath),
- arrayOf("-docencoding", "UTF-8"),
- arrayOf("-charset", "UTF-8"),
- arrayOf("-keywords")
- )
-
- override fun specifiedPackages(): Array<out PackageDoc>? = module.members(NodeKind.Package).map { PackageAdapter(this, it) }.toTypedArray()
-
- override fun classNamed(qualifiedName: String?): ClassDoc? =
- allTypes[qualifiedName]?.let { ClassDocumentationNodeAdapter(this, it) }
-
- override fun specifiedClasses(): Array<out ClassDoc> = classes()
-}
-
-private fun DocumentationNodeAdapter.collectParamTags(kind: NodeKind, sectionFilter: (ContentSection) -> Boolean) =
- (node.details(kind)
- .filter(DocumentationNode::hasNonEmptyContent)
- .map { ParamTagAdapter(module, this, it.name, true, it.content.children) }
-
- + node.content.sections
- .filter(sectionFilter)
- .map {
- ParamTagAdapter(module, this, it.subjectName ?: "?", true,
- it.children.filterNot { contentNode -> contentNode is LazyContentBlock }
- )
- }
- )
- .distinctBy { it.parameterName }
- .toTypedArray() \ No newline at end of file
diff --git a/core/src/main/kotlin/javadoc/dokka-adapters.kt b/core/src/main/kotlin/javadoc/dokka-adapters.kt
deleted file mode 100644
index 1329876a..00000000
--- a/core/src/main/kotlin/javadoc/dokka-adapters.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.jetbrains.dokka.javadoc
-
-import com.google.inject.Binder
-import com.google.inject.Inject
-import com.sun.tools.doclets.formats.html.HtmlDoclet
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Formats.DefaultAnalysisComponent
-import org.jetbrains.dokka.Formats.DefaultAnalysisComponentServices
-import org.jetbrains.dokka.Formats.FormatDescriptor
-import org.jetbrains.dokka.Formats.KotlinAsJava
-import org.jetbrains.dokka.Utilities.bind
-import org.jetbrains.dokka.Utilities.toType
-
-class JavadocGenerator @Inject constructor(val configuration: DokkaConfiguration, val logger: DokkaLogger) : Generator {
-
- override fun buildPages(nodes: Iterable<DocumentationNode>) {
- val module = nodes.single() as DocumentationModule
-
- HtmlDoclet.start(ModuleNodeAdapter(module, StandardReporter(logger), configuration.outputDir))
- }
-
- override fun buildOutlines(nodes: Iterable<DocumentationNode>) {
- // no outline could be generated separately
- }
-
- override fun buildSupportFiles() {
- }
-
- override fun buildPackageList(nodes: Iterable<DocumentationNode>) {
- // handled by javadoc itself
- }
-}
-
-class JavadocFormatDescriptor :
- FormatDescriptor,
- DefaultAnalysisComponent,
- DefaultAnalysisComponentServices by KotlinAsJava {
-
- override fun configureOutput(binder: Binder): Unit = with(binder) {
- bind<Generator>() toType JavadocGenerator::class
- }
-}
diff --git a/core/src/main/kotlin/javadoc/reporter.kt b/core/src/main/kotlin/javadoc/reporter.kt
deleted file mode 100644
index fc38368c..00000000
--- a/core/src/main/kotlin/javadoc/reporter.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.jetbrains.dokka.javadoc
-
-import com.sun.javadoc.DocErrorReporter
-import com.sun.javadoc.SourcePosition
-import org.jetbrains.dokka.DokkaLogger
-
-class StandardReporter(val logger: DokkaLogger) : DocErrorReporter {
- override fun printWarning(msg: String?) {
- logger.warn(msg.toString())
- }
-
- override fun printWarning(pos: SourcePosition?, msg: String?) {
- logger.warn(format(pos, msg))
- }
-
- override fun printError(msg: String?) {
- logger.error(msg.toString())
- }
-
- override fun printError(pos: SourcePosition?, msg: String?) {
- logger.error(format(pos, msg))
- }
-
- override fun printNotice(msg: String?) {
- logger.info(msg.toString())
- }
-
- override fun printNotice(pos: SourcePosition?, msg: String?) {
- logger.info(format(pos, msg))
- }
-
- private fun format(pos: SourcePosition?, msg: String?) =
- if (pos == null) msg.toString() else "${pos.file()}:${pos.line()}:${pos.column()}: $msg"
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/javadoc/source-position.kt b/core/src/main/kotlin/javadoc/source-position.kt
deleted file mode 100644
index 6125f968..00000000
--- a/core/src/main/kotlin/javadoc/source-position.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.jetbrains.dokka.javadoc
-
-import com.sun.javadoc.SourcePosition
-import org.jetbrains.dokka.DocumentationNode
-import org.jetbrains.dokka.NodeKind
-import java.io.File
-
-class SourcePositionAdapter(val docNode: DocumentationNode) : SourcePosition {
-
- private val sourcePositionParts: List<String> by lazy {
- docNode.details(NodeKind.SourcePosition).firstOrNull()?.name?.split(":") ?: emptyList()
- }
-
- override fun file(): File? = if (sourcePositionParts.isEmpty()) null else File(sourcePositionParts[0])
-
- override fun line(): Int = sourcePositionParts.getOrNull(1)?.toInt() ?: -1
-
- override fun column(): Int = sourcePositionParts.getOrNull(2)?.toInt() ?: -1
-}
diff --git a/core/src/main/kotlin/javadoc/tags.kt b/core/src/main/kotlin/javadoc/tags.kt
deleted file mode 100644
index 99c9bfff..00000000
--- a/core/src/main/kotlin/javadoc/tags.kt
+++ /dev/null
@@ -1,228 +0,0 @@
-package org.jetbrains.dokka.javadoc
-
-import com.sun.javadoc.*
-import org.jetbrains.dokka.*
-import java.util.*
-
-class TagImpl(val holder: Doc, val name: String, val text: String): Tag {
- override fun text(): String? = text
-
- override fun holder(): Doc = holder
- override fun firstSentenceTags(): Array<out Tag>? = arrayOf()
- override fun inlineTags(): Array<out Tag>? = arrayOf()
-
- override fun name(): String = name
- override fun kind(): String = name
-
- override fun position(): SourcePosition = holder.position()
-}
-
-class TextTag(val holder: Doc, val content: ContentText) : Tag {
- val plainText: String
- get() = content.text
-
- override fun name(): String = "Text"
- override fun kind(): String = name()
- override fun text(): String? = plainText
- override fun inlineTags(): Array<out Tag> = arrayOf(this)
- override fun holder(): Doc = holder
- override fun firstSentenceTags(): Array<out Tag> = arrayOf(this)
- override fun position(): SourcePosition = holder.position()
-}
-
-abstract class SeeTagAdapter(val holder: Doc, val content: ContentNodeLink) : SeeTag {
- override fun position(): SourcePosition? = holder.position()
- override fun name(): String = "@see"
- override fun kind(): String = "@see"
- override fun holder(): Doc = holder
-
- override fun text(): String? = content.node?.name ?: "(?)"
-}
-
-class SeeExternalLinkTagAdapter(val holder: Doc, val link: ContentExternalLink) : SeeTag {
- override fun position(): SourcePosition = holder.position()
- override fun text(): String = label()
- override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
-
- override fun label(): String {
- val label = link.asText() ?: link.href
- return "<a href=\"${link.href}\">$label</a>"
- }
-
- override fun referencedPackage(): PackageDoc? = null
- override fun referencedClass(): ClassDoc? = null
- override fun referencedMemberName(): String? = null
- override fun referencedClassName(): String? = null
- override fun referencedMember(): MemberDoc? = null
- override fun holder(): Doc = holder
- override fun firstSentenceTags(): Array<out Tag> = inlineTags()
- override fun name(): String = "@link"
- override fun kind(): String = "@see"
-}
-
-fun ContentBlock.asText(): String? {
- val contentText = children.singleOrNull() as? ContentText
- return contentText?.text
-}
-
-class SeeMethodTagAdapter(holder: Doc, val method: MethodAdapter, content: ContentNodeLink) : SeeTagAdapter(holder, content) {
- override fun referencedMember(): MemberDoc = method
- override fun referencedMemberName(): String = method.name()
- override fun referencedPackage(): PackageDoc? = null
- override fun referencedClass(): ClassDoc? = method.containingClass()
- override fun referencedClassName(): String = method.containingClass()?.name() ?: ""
- override fun label(): String = content.text ?: "${method.containingClass()?.name()}.${method.name()}"
-
- override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
- override fun firstSentenceTags(): Array<out Tag> = inlineTags() // TODO
-}
-
-class SeeClassTagAdapter(holder: Doc, val clazz: ClassDocumentationNodeAdapter, content: ContentNodeLink) : SeeTagAdapter(holder, content) {
- override fun referencedMember(): MemberDoc? = null
- override fun referencedMemberName(): String? = null
- override fun referencedPackage(): PackageDoc? = null
- override fun referencedClass(): ClassDoc = clazz
- override fun referencedClassName(): String = clazz.name()
- override fun label(): String = "${clazz.classNode.kind.name.toLowerCase()} ${clazz.name()}"
-
- override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
- override fun firstSentenceTags(): Array<out Tag> = inlineTags() // TODO
-}
-
-class ParamTagAdapter(val module: ModuleNodeAdapter,
- val holder: Doc,
- val parameterName: String,
- val typeParameter: Boolean,
- val content: List<ContentNode>) : ParamTag {
-
- constructor(module: ModuleNodeAdapter, holder: Doc, parameterName: String, isTypeParameter: Boolean, content: ContentNode)
- : this(module, holder, parameterName, isTypeParameter, listOf(content)) {
- }
-
- override fun name(): String = "@param"
- override fun kind(): String = name()
- override fun holder(): Doc = holder
- override fun position(): SourcePosition? = holder.position()
-
- override fun text(): String = "@param $parameterName ${parameterComment()}" // Seems has no effect, so used for debug
- override fun inlineTags(): Array<out Tag> = buildInlineTags(module, holder, content).toTypedArray()
- override fun firstSentenceTags(): Array<out Tag> = arrayOf(TextTag(holder, ContentText(text())))
-
- override fun isTypeParameter(): Boolean = typeParameter
- override fun parameterComment(): String = content.toString() // TODO
- override fun parameterName(): String = parameterName
-}
-
-
-class ThrowsTagAdapter(val holder: Doc, val type: ClassDocumentationNodeAdapter, val content: List<ContentNode>) : ThrowsTag {
- override fun name(): String = "@throws"
- override fun kind(): String = name()
- override fun holder(): Doc = holder
- override fun position(): SourcePosition? = holder.position()
-
- override fun text(): String = "${name()} ${exceptionName()} ${exceptionComment()}"
- override fun inlineTags(): Array<out Tag> = buildInlineTags(type.module, holder, content).toTypedArray()
- override fun firstSentenceTags(): Array<out Tag> = emptyArray()
-
- override fun exceptionComment(): String = content.toString()
- override fun exceptionType(): Type = type
- override fun exception(): ClassDoc = type
- override fun exceptionName(): String = type.qualifiedTypeName()
-}
-
-class ReturnTagAdapter(val module: ModuleNodeAdapter, val holder: Doc, val content: List<ContentNode>) : Tag {
- override fun name(): String = "@return"
- override fun kind() = name()
- override fun holder() = holder
- override fun position(): SourcePosition? = holder.position()
-
- override fun text(): String = "@return $content" // Seems has no effect, so used for debug
- override fun inlineTags(): Array<Tag> = buildInlineTags(module, holder, content).toTypedArray()
- override fun firstSentenceTags(): Array<Tag> = inlineTags()
-}
-
-fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, tags: List<ContentNode>): List<Tag> = ArrayList<Tag>().apply { tags.forEach { buildInlineTags(module, holder, it, this) } }
-
-fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, root: ContentNode): List<Tag> = ArrayList<Tag>().apply { buildInlineTags(module, holder, root, this) }
-
-private fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, nodes: List<ContentNode>, result: MutableList<Tag>) {
- nodes.forEach {
- buildInlineTags(module, holder, it, result)
- }
-}
-
-
-private fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, node: ContentNode, result: MutableList<Tag>) {
- fun surroundWith(module: ModuleNodeAdapter, holder: Doc, prefix: String, postfix: String, node: ContentBlock, result: MutableList<Tag>) {
- if (node.children.isNotEmpty()) {
- val open = TextTag(holder, ContentText(prefix))
- val close = TextTag(holder, ContentText(postfix))
-
- result.add(open)
- buildInlineTags(module, holder, node.children, result)
-
- if (result.last() === open) {
- result.removeAt(result.lastIndex)
- } else {
- result.add(close)
- }
- }
- }
-
- fun surroundWith(module: ModuleNodeAdapter, holder: Doc, prefix: String, postfix: String, node: ContentNode, result: MutableList<Tag>) {
- if (node !is ContentEmpty) {
- val open = TextTag(holder, ContentText(prefix))
- val close = TextTag(holder, ContentText(postfix))
-
- result.add(open)
- buildInlineTags(module, holder, node, result)
- if (result.last() === open) {
- result.removeAt(result.lastIndex)
- } else {
- result.add(close)
- }
- }
- }
-
- when (node) {
- is ContentText -> result.add(TextTag(holder, node))
- is ContentNodeLink -> {
- val target = node.node
- when (target?.kind) {
- NodeKind.Function -> result.add(SeeMethodTagAdapter(holder, MethodAdapter(module, node.node!!), node))
-
- in NodeKind.classLike -> result.add(SeeClassTagAdapter(holder, ClassDocumentationNodeAdapter(module, node.node!!), node))
-
- else -> buildInlineTags(module, holder, node.children, result)
- }
- }
- is ContentExternalLink -> result.add(SeeExternalLinkTagAdapter(holder, node))
- is ContentCode -> surroundWith(module, holder, "<code>", "</code>", node, result)
- is ContentBlockCode -> surroundWith(module, holder, "<code><pre>", "</pre></code>", node, result)
- is ContentEmpty -> {}
- is ContentEmphasis -> surroundWith(module, holder, "<em>", "</em>", node, result)
- is ContentHeading -> surroundWith(module, holder, "<h${node.level}>", "</h${node.level}>", node, result)
- is ContentEntity -> result.add(TextTag(holder, ContentText(node.text))) // TODO ??
- is ContentIdentifier -> result.add(TextTag(holder, ContentText(node.text))) // TODO
- is ContentKeyword -> result.add(TextTag(holder, ContentText(node.text))) // TODO
- is ContentListItem -> surroundWith(module, holder, "<li>", "</li>", node, result)
- is ContentOrderedList -> surroundWith(module, holder, "<ol>", "</ol>", node, result)
- is ContentUnorderedList -> surroundWith(module, holder, "<ul>", "</ul>", node, result)
- is ContentParagraph -> surroundWith(module, holder, "<p>", "</p>", node, result)
- is ContentSection -> surroundWith(module, holder, "<p>", "</p>", node, result) // TODO how section should be represented?
- is ContentNonBreakingSpace -> result.add(TextTag(holder, ContentText("&nbsp;")))
- is ContentStrikethrough -> surroundWith(module, holder, "<strike>", "</strike>", node, result)
- is ContentStrong -> surroundWith(module, holder, "<strong>", "</strong>", node, result)
- is ContentSymbol -> result.add(TextTag(holder, ContentText(node.text))) // TODO?
- is Content -> {
- surroundWith(module, holder, "<p>", "</p>", node.summary, result)
- surroundWith(module, holder, "<p>", "</p>", node.description, result)
- }
- is ContentBlock -> {
- surroundWith(module, holder, "", "", node, result)
- }
- is ContentHardLineBreak -> result.add(TextTag(holder, ContentText("<br/>")))
-
- else -> result.add(TextTag(holder, ContentText("$node")))
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt
new file mode 100644
index 00000000..4a555e71
--- /dev/null
+++ b/core/src/main/kotlin/links/DRI.kt
@@ -0,0 +1,105 @@
+package org.jetbrains.dokka.links
+
+import org.jetbrains.dokka.model.ClassKind
+
+/**
+ * [DRI] stands for DokkaResourceIdentifier
+ */
+data class DRI(
+ val packageName: String? = null,
+ val classNames: String? = null,
+ val callable: Callable? = null,
+ val target: DriTarget = PointingToDeclaration,
+ val extra: String? = null
+) {
+ override fun toString(): String =
+ "${packageName.orEmpty()}/${classNames.orEmpty()}/${callable?.name.orEmpty()}/${callable?.signature()
+ .orEmpty()}/$target/${extra.orEmpty()}"
+
+ companion object {
+ val topLevel = DRI()
+ }
+}
+
+val DriOfUnit = DRI("kotlin", "Unit")
+val DriOfAny = DRI("kotlin", "Any")
+
+fun DRI.withClass(name: String) = copy(classNames = if (classNames.isNullOrBlank()) name else "$classNames.$name")
+
+fun DRI.withTargetToDeclaration() = copy(target = PointingToDeclaration)
+
+val DRI.parent: DRI
+ get() = when {
+ extra != null -> copy(extra = null)
+ target != PointingToDeclaration -> copy(target = PointingToDeclaration)
+ callable != null -> copy(callable = null)
+ classNames != null -> copy(classNames = classNames.substringBeforeLast(".", "").takeIf { it.isNotBlank() })
+ else -> DRI.topLevel
+ }
+
+val DRI.sureClassNames
+ get() = classNames ?: throw IllegalStateException("Malformed DRI. It requires classNames in this context.")
+
+data class Callable(
+ val name: String,
+ val receiver: TypeReference? = null,
+ val params: List<TypeReference>
+) {
+ fun signature() = "${receiver?.toString().orEmpty()}#${params.joinToString("#")}"
+
+ companion object
+}
+
+sealed class TypeReference {
+ companion object
+}
+
+data class JavaClassReference(val name: String) : TypeReference() {
+ override fun toString(): String = name
+}
+
+data class TypeParam(val bounds: List<TypeReference>) : TypeReference()
+
+data class TypeConstructor(
+ val fullyQualifiedName: String,
+ val params: List<TypeReference>
+) : TypeReference() {
+ override fun toString() = fullyQualifiedName +
+ (if (params.isNotEmpty()) "[${params.joinToString(",")}]" else "")
+}
+
+object SelfType : TypeReference() {
+ override fun toString() = "^"
+}
+
+data class Nullable(val wrapped: TypeReference) : TypeReference() {
+ override fun toString() = "$wrapped?"
+}
+
+object StarProjection : TypeReference() {
+ override fun toString() = "*"
+}
+
+sealed class DriTarget {
+ override fun toString(): String = this.javaClass.simpleName
+
+ companion object
+}
+
+data class PointingToGenericParameters(val parameterIndex: Int) : DriTarget() {
+ override fun toString(): String = "PointingToGenericParameters($parameterIndex)"
+}
+
+object PointingToDeclaration : DriTarget()
+
+data class PointingToCallableParameters(val parameterIndex: Int) : DriTarget() {
+ override fun toString(): String = "PointingToCallableParameters($parameterIndex)"
+}
+
+fun DriTarget.nextTarget(): DriTarget = when (this) {
+ is PointingToGenericParameters -> PointingToGenericParameters(this.parameterIndex + 1)
+ is PointingToCallableParameters -> PointingToCallableParameters(this.parameterIndex + 1)
+ else -> this
+}
+
+data class DriWithKind(val dri: DRI, val kind: ClassKind)
diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt
new file mode 100644
index 00000000..2c3e1323
--- /dev/null
+++ b/core/src/main/kotlin/model/Documentable.kt
@@ -0,0 +1,398 @@
+package org.jetbrains.dokka.model
+
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.links.DriWithKind
+import org.jetbrains.dokka.model.doc.DocumentationNode
+import org.jetbrains.dokka.model.properties.PropertyContainer
+import org.jetbrains.dokka.model.properties.WithExtraProperties
+
+
+abstract class Documentable : WithChildren<Documentable> {
+ abstract val name: String?
+ abstract val dri: DRI
+ abstract val documentation: SourceSetDependent<DocumentationNode>
+ abstract val sourceSets: Set<DokkaSourceSet>
+ abstract val expectPresentInSet: DokkaSourceSet?
+
+ override fun toString(): String =
+ "${javaClass.simpleName}($dri)"
+
+ override fun equals(other: Any?) =
+ other is Documentable && this.dri == other.dri // TODO: https://github.com/Kotlin/dokka/pull/667#discussion_r382555806
+
+ override fun hashCode() = dri.hashCode()
+}
+
+typealias SourceSetDependent<T> = Map<DokkaSourceSet, T>
+
+interface WithExpectActual {
+ val sources: SourceSetDependent<DocumentableSource>
+}
+
+interface WithScope {
+ val functions: List<DFunction>
+ val properties: List<DProperty>
+ val classlikes: List<DClasslike>
+}
+
+interface WithVisibility {
+ val visibility: SourceSetDependent<Visibility>
+}
+
+interface WithType {
+ val type: Bound
+}
+
+interface WithAbstraction {
+ val modifier: SourceSetDependent<Modifier>
+}
+
+sealed class Modifier(val name: String)
+sealed class KotlinModifier(name: String) : Modifier(name) {
+ object Abstract : KotlinModifier("abstract")
+ object Open : KotlinModifier("open")
+ object Final : KotlinModifier("final")
+ object Sealed : KotlinModifier("sealed")
+ object Empty : KotlinModifier("")
+}
+
+sealed class JavaModifier(name: String) : Modifier(name) {
+ object Abstract : JavaModifier("abstract")
+ object Final : JavaModifier("final")
+ object Empty : JavaModifier("")
+}
+
+interface WithCompanion {
+ val companion: DObject?
+}
+
+interface WithConstructors {
+ val constructors: List<DFunction>
+}
+
+interface WithGenerics {
+ val generics: List<DTypeParameter>
+}
+
+interface WithSupertypes {
+ val supertypes: SourceSetDependent<List<DriWithKind>>
+}
+
+interface Callable : WithVisibility, WithType, WithAbstraction, WithExpectActual {
+ val receiver: DParameter?
+}
+
+sealed class DClasslike : Documentable(), WithScope, WithVisibility, WithExpectActual
+
+data class DModule(
+ override val name: String,
+ val packages: List<DPackage>,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet? = null,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DModule> = PropertyContainer.empty()
+) : Documentable(), WithExtraProperties<DModule> {
+ override val dri: DRI = DRI.topLevel
+ override val children: List<Documentable>
+ get() = packages
+
+ override fun withNewExtras(newExtras: PropertyContainer<DModule>) = copy(extra = newExtras)
+}
+
+data class DPackage(
+ override val dri: DRI,
+ override val functions: List<DFunction>,
+ override val properties: List<DProperty>,
+ override val classlikes: List<DClasslike>,
+ val typealiases: List<DTypeAlias>,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet? = null,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DPackage> = PropertyContainer.empty()
+) : Documentable(), WithScope, WithExtraProperties<DPackage> {
+ override val name = dri.packageName.orEmpty()
+ override val children: List<Documentable>
+ get() = (properties + functions + classlikes)
+
+ override fun withNewExtras(newExtras: PropertyContainer<DPackage>) = copy(extra = newExtras)
+}
+
+data class DClass(
+ override val dri: DRI,
+ override val name: String,
+ override val constructors: List<DFunction>,
+ override val functions: List<DFunction>,
+ override val properties: List<DProperty>,
+ override val classlikes: List<DClasslike>,
+ override val sources: SourceSetDependent<DocumentableSource>,
+ override val visibility: SourceSetDependent<Visibility>,
+ override val companion: DObject?,
+ override val generics: List<DTypeParameter>,
+ override val supertypes: SourceSetDependent<List<DriWithKind>>,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val modifier: SourceSetDependent<Modifier>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DClass> = PropertyContainer.empty()
+) : DClasslike(), WithAbstraction, WithCompanion, WithConstructors, WithGenerics, WithSupertypes,
+ WithExtraProperties<DClass> {
+
+ override val children: List<Documentable>
+ get() = (functions + properties + classlikes + constructors)
+
+ override fun withNewExtras(newExtras: PropertyContainer<DClass>) = copy(extra = newExtras)
+}
+
+data class DEnum(
+ override val dri: DRI,
+ override val name: String,
+ val entries: List<DEnumEntry>,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val sources: SourceSetDependent<DocumentableSource>,
+ override val functions: List<DFunction>,
+ override val properties: List<DProperty>,
+ override val classlikes: List<DClasslike>,
+ override val visibility: SourceSetDependent<Visibility>,
+ override val companion: DObject?,
+ override val constructors: List<DFunction>,
+ override val supertypes: SourceSetDependent<List<DriWithKind>>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DEnum> = PropertyContainer.empty()
+) : DClasslike(), WithCompanion, WithConstructors, WithSupertypes, WithExtraProperties<DEnum> {
+ override val children: List<Documentable>
+ get() = (entries + functions + properties + classlikes + constructors)
+
+ override fun withNewExtras(newExtras: PropertyContainer<DEnum>) = copy(extra = newExtras)
+}
+
+data class DEnumEntry(
+ override val dri: DRI,
+ override val name: String,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val functions: List<DFunction>,
+ override val properties: List<DProperty>,
+ override val classlikes: List<DClasslike>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DEnumEntry> = PropertyContainer.empty()
+) : Documentable(), WithScope, WithExtraProperties<DEnumEntry> {
+ override val children: List<Documentable>
+ get() = (functions + properties + classlikes)
+
+ override fun withNewExtras(newExtras: PropertyContainer<DEnumEntry>) = copy(extra = newExtras)
+}
+
+data class DFunction(
+ override val dri: DRI,
+ override val name: String,
+ val isConstructor: Boolean,
+ val parameters: List<DParameter>,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val sources: SourceSetDependent<DocumentableSource>,
+ override val visibility: SourceSetDependent<Visibility>,
+ override val type: Bound,
+ override val generics: List<DTypeParameter>,
+ override val receiver: DParameter?,
+ override val modifier: SourceSetDependent<Modifier>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DFunction> = PropertyContainer.empty()
+) : Documentable(), Callable, WithGenerics, WithExtraProperties<DFunction> {
+ override val children: List<Documentable>
+ get() = parameters
+
+ override fun withNewExtras(newExtras: PropertyContainer<DFunction>) = copy(extra = newExtras)
+}
+
+data class DInterface(
+ override val dri: DRI,
+ override val name: String,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val sources: SourceSetDependent<DocumentableSource>,
+ override val functions: List<DFunction>,
+ override val properties: List<DProperty>,
+ override val classlikes: List<DClasslike>,
+ override val visibility: SourceSetDependent<Visibility>,
+ override val companion: DObject?,
+ override val generics: List<DTypeParameter>,
+ override val supertypes: SourceSetDependent<List<DriWithKind>>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DInterface> = PropertyContainer.empty()
+) : DClasslike(), WithCompanion, WithGenerics, WithSupertypes, WithExtraProperties<DInterface> {
+ override val children: List<Documentable>
+ get() = (functions + properties + classlikes)
+
+ override fun withNewExtras(newExtras: PropertyContainer<DInterface>) = copy(extra = newExtras)
+}
+
+data class DObject(
+ override val name: String?,
+ override val dri: DRI,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val sources: SourceSetDependent<DocumentableSource>,
+ override val functions: List<DFunction>,
+ override val properties: List<DProperty>,
+ override val classlikes: List<DClasslike>,
+ override val visibility: SourceSetDependent<Visibility>,
+ override val supertypes: SourceSetDependent<List<DriWithKind>>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DObject> = PropertyContainer.empty()
+) : DClasslike(), WithSupertypes, WithExtraProperties<DObject> {
+ override val children: List<Documentable>
+ get() = (functions + properties + classlikes) as List<Documentable>
+
+ override fun withNewExtras(newExtras: PropertyContainer<DObject>) = copy(extra = newExtras)
+}
+
+data class DAnnotation(
+ override val name: String,
+ override val dri: DRI,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val sources: SourceSetDependent<DocumentableSource>,
+ override val functions: List<DFunction>,
+ override val properties: List<DProperty>,
+ override val classlikes: List<DClasslike>,
+ override val visibility: SourceSetDependent<Visibility>,
+ override val companion: DObject?,
+ override val constructors: List<DFunction>,
+ override val generics: List<DTypeParameter>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DAnnotation> = PropertyContainer.empty()
+) : DClasslike(), WithCompanion, WithConstructors, WithExtraProperties<DAnnotation>, WithGenerics {
+ override val children: List<Documentable>
+ get() = (functions + properties + classlikes + constructors)
+
+ override fun withNewExtras(newExtras: PropertyContainer<DAnnotation>) = copy(extra = newExtras)
+}
+
+data class DProperty(
+ override val dri: DRI,
+ override val name: String,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val sources: SourceSetDependent<DocumentableSource>,
+ override val visibility: SourceSetDependent<Visibility>,
+ override val type: Bound,
+ override val receiver: DParameter?,
+ val setter: DFunction?,
+ val getter: DFunction?,
+ override val modifier: SourceSetDependent<Modifier>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val generics: List<DTypeParameter>,
+ override val extra: PropertyContainer<DProperty> = PropertyContainer.empty()
+) : Documentable(), Callable, WithExtraProperties<DProperty>, WithGenerics {
+ override val children: List<Nothing>
+ get() = emptyList()
+
+ override fun withNewExtras(newExtras: PropertyContainer<DProperty>) = copy(extra = newExtras)
+}
+
+// TODO: treat named Parameters and receivers differently
+data class DParameter(
+ override val dri: DRI,
+ override val name: String?,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ val type: Bound,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DParameter> = PropertyContainer.empty()
+) : Documentable(), WithExtraProperties<DParameter> {
+ override val children: List<Nothing>
+ get() = emptyList()
+
+ override fun withNewExtras(newExtras: PropertyContainer<DParameter>) = copy(extra = newExtras)
+}
+
+data class DTypeParameter(
+ override val dri: DRI,
+ override val name: String,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ val bounds: List<Bound>,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DTypeParameter> = PropertyContainer.empty()
+) : Documentable(), WithExtraProperties<DTypeParameter> {
+ override val children: List<Nothing>
+ get() = emptyList()
+
+ override fun withNewExtras(newExtras: PropertyContainer<DTypeParameter>) = copy(extra = newExtras)
+}
+
+data class DTypeAlias(
+ override val dri: DRI,
+ override val name: String,
+ override val type: Bound,
+ val underlyingType: SourceSetDependent<Bound>,
+ override val visibility: SourceSetDependent<Visibility>,
+ override val documentation: SourceSetDependent<DocumentationNode>,
+ override val expectPresentInSet: DokkaSourceSet?,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val extra: PropertyContainer<DTypeAlias> = PropertyContainer.empty()
+) : Documentable(), WithType, WithVisibility, WithExtraProperties<DTypeAlias> {
+ override val children: List<Nothing>
+ get() = emptyList()
+
+ override fun withNewExtras(newExtras: PropertyContainer<DTypeAlias>) = copy(extra = newExtras)
+}
+
+sealed class Projection
+sealed class Bound : Projection()
+data class OtherParameter(val declarationDRI: DRI, val name: String) : Bound()
+object Star : Projection()
+data class TypeConstructor(
+ val dri: DRI,
+ val projections: List<Projection>,
+ val modifier: FunctionModifiers = FunctionModifiers.NONE
+) : Bound()
+
+data class Nullable(val inner: Bound) : Bound()
+data class Variance(val kind: Kind, val inner: Bound) : Projection() {
+ enum class Kind { In, Out }
+}
+
+data class PrimitiveJavaType(val name: String) : Bound()
+object Void : Bound()
+object JavaObject : Bound()
+object Dynamic : Bound()
+data class UnresolvedBound(val name: String) : Bound()
+
+enum class FunctionModifiers {
+ NONE, FUNCTION, EXTENSION
+}
+
+private fun String.shorten(maxLength: Int) = lineSequence().first().let {
+ if (it.length != length || it.length > maxLength) it.take(maxLength - 3) + "..." else it
+}
+
+fun Documentable.dfs(predicate: (Documentable) -> Boolean): Documentable? =
+ if (predicate(this)) {
+ this
+ } else {
+ this.children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull()
+ }
+
+sealed class Visibility(val name: String)
+sealed class KotlinVisibility(name: String) : Visibility(name) {
+ object Public : KotlinVisibility("public")
+ object Private : KotlinVisibility("private")
+ object Protected : KotlinVisibility("protected")
+ object Internal : KotlinVisibility("internal")
+}
+
+sealed class JavaVisibility(name: String) : Visibility(name) {
+ object Public : JavaVisibility("public")
+ object Private : JavaVisibility("private")
+ object Protected : JavaVisibility("protected")
+ object Default : JavaVisibility("")
+}
+
+fun <T> SourceSetDependent<T>?.orEmpty(): SourceSetDependent<T> = this ?: emptyMap()
+
+interface DocumentableSource {
+ val path: String
+}
diff --git a/core/src/main/kotlin/model/WithChildren.kt b/core/src/main/kotlin/model/WithChildren.kt
new file mode 100644
index 00000000..589bcd2a
--- /dev/null
+++ b/core/src/main/kotlin/model/WithChildren.kt
@@ -0,0 +1,64 @@
+package org.jetbrains.dokka.model
+
+interface WithChildren<out T> {
+ val children: List<T>
+}
+
+inline fun <reified T> WithChildren<*>.firstChildOfTypeOrNull(): T? =
+ children.filterIsInstance<T>().firstOrNull()
+
+inline fun <reified T> WithChildren<*>.firstChildOfTypeOrNull(predicate: (T) -> Boolean): T? =
+ children.filterIsInstance<T>().firstOrNull(predicate)
+
+inline fun <reified T> WithChildren<*>.firstChildOfType(): T =
+ children.filterIsInstance<T>().first()
+
+inline fun <reified T> WithChildren<*>.firstChildOfType(predicate: (T) -> Boolean): T =
+ children.filterIsInstance<T>().first(predicate)
+
+inline fun <reified T> WithChildren<WithChildren<*>>.firstMemberOfType(): T where T : WithChildren<*> {
+ return withDescendants().filterIsInstance<T>().first()
+}
+
+inline fun <reified T> WithChildren<WithChildren<*>>.firstMemberOfTypeOrNull(): T? where T : WithChildren<*> {
+ return withDescendants().filterIsInstance<T>().firstOrNull()
+}
+
+fun <T> T.withDescendants(): Sequence<T> where T : WithChildren<T> {
+ return sequence {
+ yield(this@withDescendants)
+ children.forEach { child ->
+ yieldAll(child.withDescendants())
+ }
+ }
+}
+
+@JvmName("withDescendantsProjection")
+fun WithChildren<*>.withDescendants(): Sequence<Any?> {
+ return sequence {
+ yield(this@withDescendants)
+ children.forEach { child ->
+ if (child is WithChildren<*>) {
+ yieldAll(child.withDescendants())
+ }
+ }
+ }
+}
+
+@JvmName("withDescendantsAny")
+fun WithChildren<Any>.withDescendants(): Sequence<Any> {
+ return sequence {
+ yield(this@withDescendants)
+ children.forEach { child ->
+ if (child is WithChildren<*>) {
+ yieldAll(child.withDescendants().filterNotNull())
+ }
+ }
+ }
+}
+
+fun <T> T.dfs(predicate: (T) -> Boolean): T? where T : WithChildren<T> = if (predicate(this)) {
+ this
+} else {
+ children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull()
+}
diff --git a/core/src/main/kotlin/model/additionalExtras.kt b/core/src/main/kotlin/model/additionalExtras.kt
new file mode 100644
index 00000000..94d0e751
--- /dev/null
+++ b/core/src/main/kotlin/model/additionalExtras.kt
@@ -0,0 +1,75 @@
+package org.jetbrains.dokka.model
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.properties.ExtraProperty
+import org.jetbrains.dokka.model.properties.MergeStrategy
+
+class AdditionalModifiers(val content: SourceSetDependent<Set<ExtraModifiers>>) : ExtraProperty<Documentable> {
+ companion object : ExtraProperty.Key<Documentable, AdditionalModifiers> {
+ override fun mergeStrategyFor(
+ left: AdditionalModifiers,
+ right: AdditionalModifiers
+ ): MergeStrategy<Documentable> = MergeStrategy.Replace(AdditionalModifiers(left.content + right.content))
+ }
+
+ override fun equals(other: Any?): Boolean =
+ if (other is AdditionalModifiers) other.content == content else false
+
+ override fun hashCode() = content.hashCode()
+ override val key: ExtraProperty.Key<Documentable, *> = AdditionalModifiers
+}
+
+fun SourceSetDependent<Set<ExtraModifiers>>.toAdditionalModifiers() = AdditionalModifiers(this)
+
+class Annotations(val content: SourceSetDependent<List<Annotation>>) : ExtraProperty<Documentable> {
+ companion object : ExtraProperty.Key<Documentable, Annotations> {
+ override fun mergeStrategyFor(left: Annotations, right: Annotations): MergeStrategy<Documentable> =
+ MergeStrategy.Replace(Annotations(left.content + right.content))
+ }
+
+ override val key: ExtraProperty.Key<Documentable, *> = Annotations
+
+ data class Annotation(val dri: DRI, val params: Map<String, AnnotationParameterValue>, val mustBeDocumented: Boolean = false) {
+ override fun equals(other: Any?): Boolean = when (other) {
+ is Annotation -> dri == other.dri
+ else -> false
+ }
+
+ override fun hashCode(): Int = dri.hashCode()
+ }
+}
+
+fun SourceSetDependent<List<Annotations.Annotation>>.toAnnotations() = Annotations(this)
+
+sealed class AnnotationParameterValue
+data class AnnotationValue(val annotation: Annotations.Annotation) : AnnotationParameterValue()
+data class ArrayValue(val value: List<AnnotationParameterValue>) : AnnotationParameterValue()
+data class EnumValue(val enumName: String, val enumDri: DRI) : AnnotationParameterValue()
+data class ClassValue(val className: String, val classDRI: DRI) : AnnotationParameterValue()
+data class StringValue(val value: String) : AnnotationParameterValue()
+
+
+object PrimaryConstructorExtra : ExtraProperty<DFunction>, ExtraProperty.Key<DFunction, PrimaryConstructorExtra> {
+ override val key: ExtraProperty.Key<DFunction, *> = this
+}
+
+data class ActualTypealias(val underlyingType: SourceSetDependent<Bound>) : ExtraProperty<DClasslike> {
+ companion object : ExtraProperty.Key<DClasslike, ActualTypealias> {
+ override fun mergeStrategyFor(
+ left: ActualTypealias,
+ right: ActualTypealias
+ ) =
+ MergeStrategy.Replace(ActualTypealias(left.underlyingType + right.underlyingType))
+ }
+
+ override val key: ExtraProperty.Key<DClasslike, ActualTypealias> = ActualTypealias
+}
+
+data class ConstructorValues(val values: SourceSetDependent<List<String>>) : ExtraProperty<DEnumEntry>{
+ companion object : ExtraProperty.Key<DEnumEntry, ConstructorValues> {
+ override fun mergeStrategyFor(left: ConstructorValues, right: ConstructorValues) =
+ MergeStrategy.Replace(ConstructorValues(left.values + right.values))
+ }
+
+ override val key: ExtraProperty.Key<DEnumEntry, ConstructorValues> = ConstructorValues
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/model/classKinds.kt b/core/src/main/kotlin/model/classKinds.kt
new file mode 100644
index 00000000..be8c47b0
--- /dev/null
+++ b/core/src/main/kotlin/model/classKinds.kt
@@ -0,0 +1,20 @@
+package org.jetbrains.dokka.model
+
+interface ClassKind
+
+enum class KotlinClassKindTypes : ClassKind {
+ CLASS,
+ INTERFACE,
+ ENUM_CLASS,
+ ENUM_ENTRY,
+ ANNOTATION_CLASS,
+ OBJECT;
+}
+
+enum class JavaClassKindTypes : ClassKind {
+ CLASS,
+ INTERFACE,
+ ENUM_CLASS,
+ ENUM_ENTRY,
+ ANNOTATION_CLASS;
+}
diff --git a/core/src/main/kotlin/model/defaultValues.kt b/core/src/main/kotlin/model/defaultValues.kt
new file mode 100644
index 00000000..ab6cd376
--- /dev/null
+++ b/core/src/main/kotlin/model/defaultValues.kt
@@ -0,0 +1,13 @@
+package org.jetbrains.dokka.model
+
+import org.jetbrains.dokka.model.properties.ExtraProperty
+import org.jetbrains.dokka.model.properties.MergeStrategy
+
+class DefaultValue(val value: String): ExtraProperty<DParameter> {
+ companion object : ExtraProperty.Key<DParameter, DefaultValue> {
+ override fun mergeStrategyFor(left: DefaultValue, right: DefaultValue): MergeStrategy<DParameter> = MergeStrategy.Remove // TODO pass a logger somehow and log this
+ }
+
+ override val key: ExtraProperty.Key<DParameter, *>
+ get() = Companion
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/model/doc/DocTag.kt b/core/src/main/kotlin/model/doc/DocTag.kt
new file mode 100644
index 00000000..dc2cd2be
--- /dev/null
+++ b/core/src/main/kotlin/model/doc/DocTag.kt
@@ -0,0 +1,96 @@
+package org.jetbrains.dokka.model.doc
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.WithChildren
+
+sealed class DocTag(
+ override val children: List<DocTag>,
+ val params: Map<String, String>
+) : WithChildren<DocTag> {
+ override fun equals(other: Any?): Boolean =
+ (
+ other != null &&
+ other::class == this::class &&
+ this.children == (other as DocTag).children &&
+ this.params == other.params
+ )
+
+ override fun hashCode(): Int = children.hashCode() + params.hashCode()
+}
+
+class A(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Big(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class B(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class BlockQuote(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+object Br : DocTag(emptyList(), emptyMap())
+class Cite(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+sealed class Code(children: List<DocTag>, params: Map<String, String>) : DocTag(children, params)
+class CodeInline(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : Code(children, params)
+class CodeBlock(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : Code(children, params)
+class Dd(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Dfn(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Dir(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Div(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Dl(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Dt(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Em(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Font(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Footer(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Frame(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class FrameSet(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class H1(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class H2(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class H3(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class H4(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class H5(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class H6(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Head(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Header(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Html(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class I(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class IFrame(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Img(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Input(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Li(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Link(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Listing(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Main(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Menu(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Meta(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Nav(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class NoFrames(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class NoScript(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Ol(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class P(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Pre(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Script(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Section(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Small(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Span(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Strikethrough(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Strong(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Sub(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Sup(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Table(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Text(val body: String = "", children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) {
+ override fun equals(other: Any?): Boolean = super.equals(other) && this.body == (other as Text).body
+ override fun hashCode(): Int = super.hashCode() + body.hashCode()
+}
+class TBody(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Td(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class TFoot(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Th(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class THead(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Title(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Tr(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Tt(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class U(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Ul(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class Var(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class DocumentationLink(val dri: DRI, children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) {
+ override fun equals(other: Any?): Boolean = super.equals(other) && this.dri == (other as DocumentationLink).dri
+ override fun hashCode(): Int = super.hashCode() + dri.hashCode()
+}
+object HorizontalRule : DocTag(emptyList(), emptyMap())
+class Index(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
+class CustomDocTag(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params)
diff --git a/core/src/main/kotlin/model/doc/DocumentationNode.kt b/core/src/main/kotlin/model/doc/DocumentationNode.kt
new file mode 100644
index 00000000..6eb26a6a
--- /dev/null
+++ b/core/src/main/kotlin/model/doc/DocumentationNode.kt
@@ -0,0 +1,5 @@
+package org.jetbrains.dokka.model.doc
+
+import org.jetbrains.dokka.model.WithChildren
+
+data class DocumentationNode(override val children: List<TagWrapper>): WithChildren<TagWrapper>
diff --git a/core/src/main/kotlin/model/doc/TagWrapper.kt b/core/src/main/kotlin/model/doc/TagWrapper.kt
new file mode 100644
index 00000000..095f3eaf
--- /dev/null
+++ b/core/src/main/kotlin/model/doc/TagWrapper.kt
@@ -0,0 +1,39 @@
+package org.jetbrains.dokka.model.doc
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.WithChildren
+
+sealed class TagWrapper(val root: DocTag) : WithChildren<DocTag> {
+
+ override val children: List<DocTag>
+ get() = root.children
+
+ override fun equals(other: Any?): Boolean =
+ (
+ other != null &&
+ this::class == other::class &&
+ this.root == (other as TagWrapper).root
+ )
+
+ override fun hashCode(): Int = root.hashCode()
+}
+sealed class NamedTagWrapper(root: DocTag, val name: String) : TagWrapper(root) {
+ override fun equals(other: Any?): Boolean = super.equals(other) && this.name == (other as NamedTagWrapper).name
+ override fun hashCode(): Int = super.hashCode() + name.hashCode()
+}
+
+class Description(root: DocTag) : TagWrapper(root)
+class Author(root: DocTag) : TagWrapper(root)
+class Version(root: DocTag) : TagWrapper(root)
+class Since(root: DocTag) : TagWrapper(root)
+class See(root: DocTag, name: String, val address: DRI?) : NamedTagWrapper(root, name)
+class Param(root: DocTag, name: String) : NamedTagWrapper(root, name)
+class Return(root: DocTag) : TagWrapper(root)
+class Receiver(root: DocTag) : TagWrapper(root)
+class Constructor(root: DocTag) : TagWrapper(root)
+class Throws(root: DocTag, name: String) : NamedTagWrapper(root, name)
+class Sample(root: DocTag, name: String) : NamedTagWrapper(root, name)
+class Deprecated(root: DocTag) : TagWrapper(root)
+class Property(root: DocTag, name: String) : NamedTagWrapper(root, name)
+class Suppress(root: DocTag) : TagWrapper(root)
+class CustomTagWrapper(root: DocTag, name: String) : NamedTagWrapper(root, name)
diff --git a/core/src/main/kotlin/model/documentableProperties.kt b/core/src/main/kotlin/model/documentableProperties.kt
new file mode 100644
index 00000000..cd6a9335
--- /dev/null
+++ b/core/src/main/kotlin/model/documentableProperties.kt
@@ -0,0 +1,27 @@
+package org.jetbrains.dokka.model
+
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.properties.ExtraProperty
+import org.jetbrains.dokka.model.properties.MergeStrategy
+
+data class InheritedFunction(val inheritedFrom: SourceSetDependent<DRI?>) : ExtraProperty<DFunction> {
+ companion object : ExtraProperty.Key<DFunction, InheritedFunction> {
+ override fun mergeStrategyFor(left: InheritedFunction, right: InheritedFunction) = MergeStrategy.Replace(
+ InheritedFunction(left.inheritedFrom + right.inheritedFrom)
+ )
+ }
+
+ fun isInherited(sourceSetDependent: DokkaSourceSet): Boolean = inheritedFrom[sourceSetDependent] != null
+
+ override val key: ExtraProperty.Key<DFunction, *> = InheritedFunction
+}
+
+data class ImplementedInterfaces(val interfaces: SourceSetDependent<List<DRI>>) : ExtraProperty<Documentable> {
+ companion object : ExtraProperty.Key<Documentable, ImplementedInterfaces> {
+ override fun mergeStrategyFor(left: ImplementedInterfaces, right: ImplementedInterfaces) =
+ MergeStrategy.Replace(ImplementedInterfaces(left.interfaces + right.interfaces))
+ }
+
+ override val key: ExtraProperty.Key<Documentable, *> = ImplementedInterfaces
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/model/documentableUtils.kt b/core/src/main/kotlin/model/documentableUtils.kt
new file mode 100644
index 00000000..287cf313
--- /dev/null
+++ b/core/src/main/kotlin/model/documentableUtils.kt
@@ -0,0 +1,22 @@
+package org.jetbrains.dokka.model
+
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+
+fun <T> SourceSetDependent<T>.filtered(sourceSets: Set<DokkaSourceSet>) = filter { it.key in sourceSets }
+fun DokkaSourceSet?.filtered(sourceSets: Set<DokkaSourceSet>) = takeIf { this in sourceSets }
+
+fun DTypeParameter.filter(filteredSet: Set<DokkaSourceSet>) =
+ if (filteredSet.containsAll(sourceSets)) this
+ else {
+ val intersection = filteredSet.intersect(sourceSets)
+ if (intersection.isEmpty()) null
+ else DTypeParameter(
+ dri,
+ name,
+ documentation.filtered(intersection),
+ expectPresentInSet?.takeIf { intersection.contains(expectPresentInSet) },
+ bounds,
+ intersection,
+ extra
+ )
+ }
diff --git a/core/src/main/kotlin/model/extraModifiers.kt b/core/src/main/kotlin/model/extraModifiers.kt
new file mode 100644
index 00000000..efaa3d60
--- /dev/null
+++ b/core/src/main/kotlin/model/extraModifiers.kt
@@ -0,0 +1,62 @@
+package org.jetbrains.dokka.model
+
+sealed class ExtraModifiers(val name: String) {
+
+ sealed class KotlinOnlyModifiers(name: String) : ExtraModifiers(name) {
+ object Inline : KotlinOnlyModifiers("inline")
+ object Infix : KotlinOnlyModifiers("infix")
+ object External : KotlinOnlyModifiers("external")
+ object Suspend : KotlinOnlyModifiers("suspend")
+ object Reified : KotlinOnlyModifiers("reified")
+ object CrossInline : KotlinOnlyModifiers("crossinline")
+ object NoInline : KotlinOnlyModifiers("noinline")
+ object Override : KotlinOnlyModifiers("override")
+ object Data : KotlinOnlyModifiers("data")
+ object Const : KotlinOnlyModifiers("const")
+ object Inner : KotlinOnlyModifiers("inner")
+ object LateInit : KotlinOnlyModifiers("lateinit")
+ object Operator : KotlinOnlyModifiers("operator")
+ object TailRec : KotlinOnlyModifiers("tailrec")
+ object VarArg : KotlinOnlyModifiers("vararg")
+ object Fun : KotlinOnlyModifiers("fun")
+ }
+
+ sealed class JavaOnlyModifiers(name: String) : ExtraModifiers(name) {
+ object Static : JavaOnlyModifiers("static")
+ object Native : JavaOnlyModifiers("native")
+ object Synchronized : JavaOnlyModifiers("synchronized")
+ object StrictFP : JavaOnlyModifiers("strictfp")
+ object Transient : JavaOnlyModifiers("transient")
+ object Volatile : JavaOnlyModifiers("volatile")
+ object Transitive : JavaOnlyModifiers("transitive")
+ }
+
+ companion object {
+ fun valueOf(str: String) = when (str) {
+ "inline" -> KotlinOnlyModifiers.Inline
+ "infix" -> KotlinOnlyModifiers.Infix
+ "external" -> KotlinOnlyModifiers.External
+ "suspend" -> KotlinOnlyModifiers.Suspend
+ "reified" -> KotlinOnlyModifiers.Reified
+ "crossinline" -> KotlinOnlyModifiers.CrossInline
+ "noinline" -> KotlinOnlyModifiers.NoInline
+ "override" -> KotlinOnlyModifiers.Override
+ "data" -> KotlinOnlyModifiers.Data
+ "const" -> KotlinOnlyModifiers.Const
+ "inner" -> KotlinOnlyModifiers.Inner
+ "lateinit" -> KotlinOnlyModifiers.LateInit
+ "operator" -> KotlinOnlyModifiers.Operator
+ "tailrec" -> KotlinOnlyModifiers.TailRec
+ "vararg" -> KotlinOnlyModifiers.VarArg
+ "static" -> JavaOnlyModifiers.Static
+ "native" -> JavaOnlyModifiers.Native
+ "synchronized" -> JavaOnlyModifiers.Synchronized
+ "strictfp" -> JavaOnlyModifiers.StrictFP
+ "transient" -> JavaOnlyModifiers.Transient
+ "volatile" -> JavaOnlyModifiers.Volatile
+ "transitive" -> JavaOnlyModifiers.Transitive
+ "fun" -> KotlinOnlyModifiers.Fun
+ else -> throw IllegalArgumentException("There is no Extra Modifier for given name $str")
+ }
+ }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/model/properties/PropertyContainer.kt b/core/src/main/kotlin/model/properties/PropertyContainer.kt
new file mode 100644
index 00000000..6009bfe0
--- /dev/null
+++ b/core/src/main/kotlin/model/properties/PropertyContainer.kt
@@ -0,0 +1,60 @@
+package org.jetbrains.dokka.model.properties
+
+class PropertyContainer<C : Any> internal constructor(
+ @PublishedApi internal val map: Map<ExtraProperty.Key<C, *>, ExtraProperty<C>>
+) {
+ operator fun <D : C> plus(prop: ExtraProperty<D>): PropertyContainer<D> =
+ PropertyContainer(map + (prop.key to prop))
+
+ // TODO: Add logic for caching calculated properties
+ inline operator fun <reified T : Any> get(key: ExtraProperty.Key<C, T>): T? = when (val prop = map[key]) {
+ is T? -> prop
+ else -> throw ClassCastException("Property for $key stored under not matching key type.")
+ }
+
+ inline fun <reified T : Any> allOfType(): List<T> = map.values.filterIsInstance<T>()
+ fun <D : C> addAll(extras: Collection<ExtraProperty<D>>): PropertyContainer<D> =
+ PropertyContainer(map + extras.map { p -> p.key to p })
+
+ companion object {
+ fun <T : Any> empty(): PropertyContainer<T> = PropertyContainer(emptyMap())
+ fun <T : Any> withAll(vararg extras: ExtraProperty<T>) = empty<T>().addAll(extras.toList())
+ fun <T : Any> withAll(extras: Collection<ExtraProperty<T>>) = empty<T>().addAll(extras)
+ }
+}
+
+operator fun <D: Any> PropertyContainer<D>.plus(prop: ExtraProperty<D>?): PropertyContainer<D> =
+ if (prop == null) this else PropertyContainer(map + (prop.key to prop))
+
+interface WithExtraProperties<C : Any> {
+ val extra: PropertyContainer<C>
+
+ fun withNewExtras(newExtras: PropertyContainer<C>): C
+}
+
+fun <C> C.mergeExtras(left: C, right: C): C where C : Any, C : WithExtraProperties<C> {
+ val aggregatedExtras: List<List<ExtraProperty<C>>> =
+ (left.extra.map.values + right.extra.map.values)
+ .groupBy { it.key }
+ .values
+ .map { it.distinct() }
+
+ val (unambiguous, toMerge) = aggregatedExtras.partition { it.size == 1 }
+
+ @Suppress("UNCHECKED_CAST")
+ val strategies: List<MergeStrategy<C>> = toMerge.map { (l, r) ->
+ (l.key as ExtraProperty.Key<C, ExtraProperty<C>>).mergeStrategyFor(l, r)
+ }
+
+ strategies.filterIsInstance<MergeStrategy.Fail>().firstOrNull()?.error?.invoke()
+
+ val replaces: List<ExtraProperty<C>> =
+ strategies.filterIsInstance<MergeStrategy.Replace<C>>().map { it.newProperty }
+
+ val needingFullMerge: List<(preMerged: C, left: C, right: C) -> C> =
+ strategies.filterIsInstance<MergeStrategy.Full<C>>().map { it.merger }
+
+ val newExtras = PropertyContainer((unambiguous.flatten() + replaces).associateBy { it.key })
+
+ return needingFullMerge.fold(withNewExtras(newExtras)) { acc, merger -> merger(acc, left, right) }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/model/properties/properties.kt b/core/src/main/kotlin/model/properties/properties.kt
new file mode 100644
index 00000000..7010d0df
--- /dev/null
+++ b/core/src/main/kotlin/model/properties/properties.kt
@@ -0,0 +1,22 @@
+package org.jetbrains.dokka.model.properties
+
+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, *>
+}
+
+interface CalculatedProperty<in C : Any, T : Any> : ExtraProperty.Key<C, T> {
+ fun calculate(subject: C): T
+}
+
+sealed class MergeStrategy<in C> {
+ class Replace<in C : Any>(val newProperty: ExtraProperty<C>) : MergeStrategy<C>()
+ object Remove : MergeStrategy<Any>()
+ class Full<C : Any>(val merger: (preMerged: C, left: C, right: C) -> C) : MergeStrategy<C>()
+ class Fail(val error: () -> Nothing) : MergeStrategy<Any>()
+}
diff --git a/core/src/main/kotlin/pages/ContentNodes.kt b/core/src/main/kotlin/pages/ContentNodes.kt
new file mode 100644
index 00000000..5129dfcf
--- /dev/null
+++ b/core/src/main/kotlin/pages/ContentNodes.kt
@@ -0,0 +1,266 @@
+package org.jetbrains.dokka.pages
+
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.WithChildren
+import org.jetbrains.dokka.model.properties.PropertyContainer
+import org.jetbrains.dokka.model.properties.WithExtraProperties
+
+data class DCI(val dri: Set<DRI>, val kind: Kind) {
+ override fun toString() = "$dri[$kind]"
+}
+
+interface ContentNode : WithExtraProperties<ContentNode>, WithChildren<ContentNode> {
+ val dci: DCI
+ val sourceSets: Set<DokkaSourceSet>
+ val style: Set<Style>
+
+ fun hasAnyContent(): Boolean
+
+ override val children: List<ContentNode>
+ get() = emptyList()
+}
+
+/** Simple text */
+data class ContentText(
+ val text: String,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style> = emptySet(),
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentNode {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentNode = copy(extra = newExtras)
+
+ override fun hasAnyContent(): Boolean = !text.isBlank()
+}
+
+// TODO: Remove
+data class ContentBreakLine(
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val dci: DCI = DCI(emptySet(), ContentKind.Empty),
+ override val style: Set<Style> = emptySet(),
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentNode {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentNode = copy(extra = newExtras)
+
+ override fun hasAnyContent(): Boolean = true
+}
+
+/** Headers */
+data class ContentHeader(
+ override val children: List<ContentNode>,
+ val level: Int,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style>,
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentComposite {
+ constructor(level: Int, c: ContentComposite) : this(c.children, level, c.dci, c.sourceSets, c.style, c.extra)
+
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentHeader = copy(extra = newExtras)
+}
+
+interface ContentCode : ContentComposite
+
+/** Code blocks */
+data class ContentCodeBlock(
+ override val children: List<ContentNode>,
+ val language: String,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style>,
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentCode {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentCodeBlock = copy(extra = newExtras)
+}
+
+data class ContentCodeInline(
+ override val children: List<ContentNode>,
+ val language: String,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style>,
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentCode {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentCodeInline = copy(extra = newExtras)
+}
+
+/** Union type replacement */
+interface ContentLink : ContentComposite
+
+/** All links to classes, packages, etc. that have te be resolved */
+data class ContentDRILink(
+ override val children: List<ContentNode>,
+ val address: DRI,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style> = emptySet(),
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentLink {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentDRILink = copy(extra = newExtras)
+}
+
+/** All links that do not need to be resolved */
+data class ContentResolvedLink(
+ override val children: List<ContentNode>,
+ val address: String,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style> = emptySet(),
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentLink {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentResolvedLink =
+ copy(extra = newExtras)
+}
+
+/** Embedded resources like images */
+data class ContentEmbeddedResource(
+ override val children: List<ContentNode> = emptyList(),
+ val address: String,
+ val altText: String?,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style> = emptySet(),
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentLink {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentEmbeddedResource =
+ copy(extra = newExtras)
+}
+
+/** Logical grouping of [ContentNode]s */
+interface ContentComposite : ContentNode {
+ override val children: List<ContentNode> // overwrite to make it abstract once again
+
+ override fun hasAnyContent(): Boolean = children.any { it.hasAnyContent() }
+}
+
+/** Tables */
+data class ContentTable(
+ val header: List<ContentGroup>,
+ override val children: List<ContentGroup>,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style>,
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentComposite {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentTable = copy(extra = newExtras)
+}
+
+/** Lists */
+data class ContentList(
+ override val children: List<ContentNode>,
+ val ordered: Boolean,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style>,
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentComposite {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentList = copy(extra = newExtras)
+}
+
+/** Default group, eg. for blocks of Functions, Properties, etc. **/
+data class ContentGroup(
+ override val children: List<ContentNode>,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style>,
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentComposite {
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentGroup = copy(extra = newExtras)
+}
+
+/**
+ * @property groupID is used for finding and copying [ContentDivergentInstance]s when merging [ContentPage]s
+ */
+data class ContentDivergentGroup(
+ override val children: List<ContentDivergentInstance>,
+ override val dci: DCI,
+ override val style: Set<Style>,
+ override val extra: PropertyContainer<ContentNode>,
+ val groupID: GroupID,
+ val implicitlySourceSetHinted: Boolean = true
+) : ContentComposite {
+ data class GroupID(val name: String)
+
+ override val sourceSets: Set<DokkaSourceSet>
+ get() = children.flatMap { it.sourceSets }.distinct().toSet()
+
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentDivergentGroup =
+ copy(extra = newExtras)
+}
+
+/** Instance of a divergent content */
+data class ContentDivergentInstance(
+ val before: ContentNode?,
+ val divergent: ContentNode,
+ val after: ContentNode?,
+ override val dci: DCI,
+ override val sourceSets: Set<DokkaSourceSet>,
+ override val style: Set<Style>,
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentComposite {
+ override val children: List<ContentNode>
+ get() = listOfNotNull(before, divergent, after)
+
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentDivergentInstance =
+ copy(extra = newExtras)
+}
+
+data class PlatformHintedContent(
+ val inner: ContentNode,
+ override val sourceSets: Set<DokkaSourceSet>
+) : ContentComposite {
+ override val children = listOf(inner)
+
+ override val dci: DCI
+ get() = inner.dci
+
+ override val extra: PropertyContainer<ContentNode>
+ get() = inner.extra
+
+ override val style: Set<Style>
+ get() = inner.style
+
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>) =
+ throw UnsupportedOperationException("This method should not be called on this PlatformHintedContent")
+}
+
+interface Style
+interface Kind
+
+enum class ContentKind : Kind {
+
+ Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, Symbol, Sample, Main, BriefComment,
+ Empty, Source, TypeAliases, Cover, Inheritors, SourceSetDependentHint, Extensions, Annotations;
+
+ companion object {
+ private val platformTagged =
+ setOf(Constructors, Functions, Properties, Classlikes, Packages, Source, TypeAliases, Inheritors, Extensions)
+
+ fun shouldBePlatformTagged(kind: Kind): Boolean = kind in platformTagged
+ }
+}
+
+enum class TextStyle : Style {
+ Bold, Italic, Strong, Strikethrough, Paragraph, Block, Span, Monospace, Indented, Cover, UnderCoverText, BreakableAfter, Breakable
+}
+
+enum class ContentStyle : Style {
+ RowTitle, TabbedContent, WithExtraAttributes, RunnableSample, InDocumentationAnchor
+}
+
+object CommentTable : Style
+
+object MultimoduleTable : Style
+
+fun ContentNode.dfs(predicate: (ContentNode) -> Boolean): ContentNode? = if (predicate(this)) {
+ this
+} else {
+ if (this is ContentComposite) {
+ this.children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull()
+ } else {
+ null
+ }
+}
+
+fun ContentNode.hasStyle(style: Style) = this.style.contains(style)
diff --git a/core/src/main/kotlin/pages/PageNodes.kt b/core/src/main/kotlin/pages/PageNodes.kt
new file mode 100644
index 00000000..71ec8597
--- /dev/null
+++ b/core/src/main/kotlin/pages/PageNodes.kt
@@ -0,0 +1,181 @@
+package org.jetbrains.dokka.pages
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.Documentable
+import org.jetbrains.dokka.model.WithChildren
+import java.util.*
+
+interface PageNode: WithChildren<PageNode> {
+ val name: String
+
+ fun modified(
+ name: String = this.name,
+ children: List<PageNode> = this.children
+ ): PageNode
+}
+
+interface ContentPage: PageNode {
+ val content: ContentNode
+ val dri: Set<DRI>
+ val documentable: Documentable?
+ val embeddedResources: List<String>
+
+ fun modified(
+ name: String = this.name,
+ content: ContentNode = this.content,
+ dri: Set<DRI> = this.dri,
+ embeddedResources: List<String> = this.embeddedResources,
+ children: List<PageNode> = this.children
+ ): ContentPage
+}
+
+abstract class RootPageNode: PageNode {
+ val parentMap: Map<PageNode, PageNode> by lazy {
+ IdentityHashMap<PageNode, PageNode>().apply {
+ fun process(parent: PageNode) {
+ parent.children.forEach { child ->
+ put(child, parent)
+ process(child)
+ }
+ }
+ process(this@RootPageNode)
+ }
+ }
+
+ fun transformPageNodeTree(operation: (PageNode) -> PageNode) =
+ this.transformNode(operation) as RootPageNode
+
+ fun transformContentPagesTree(operation: (ContentPage) -> ContentPage) = transformPageNodeTree {
+ if (it is ContentPage) operation(it) else it
+ }
+
+ private fun PageNode.transformNode(operation: (PageNode) -> PageNode): PageNode =
+ operation(this).let { newNode ->
+ newNode.modified(children = newNode.children.map { it.transformNode(operation) })
+ }
+
+ abstract override fun modified(
+ name: String,
+ children: List<PageNode>
+ ): RootPageNode
+}
+
+class ModulePageNode(
+ override val name: String,
+ override val content: ContentNode,
+ override val documentable: Documentable?,
+ override val children: List<PageNode>,
+ override val embeddedResources: List<String> = listOf()
+) : RootPageNode(), ContentPage {
+ override val dri: Set<DRI> = setOf(DRI.topLevel)
+
+ override fun modified(name: String, children: List<PageNode>): ModulePageNode =
+ modified(name = name, content = this.content, dri = dri, children = children)
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ): ModulePageNode =
+ if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
+ else ModulePageNode(name, content, documentable, children, embeddedResources)
+}
+
+class PackagePageNode(
+ override val name: String,
+ override val content: ContentNode,
+ override val dri: Set<DRI>,
+ override val documentable: Documentable?,
+ override val children: List<PageNode>,
+ override val embeddedResources: List<String> = listOf()
+) : ContentPage {
+ override fun modified(name: String, children: List<PageNode>): PackagePageNode =
+ modified(name = name, content = this.content, children = children)
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ): PackagePageNode =
+ if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
+ else PackagePageNode(name, content, dri, documentable, children, embeddedResources)
+}
+
+class ClasslikePageNode(
+ override val name: String,
+ override val content: ContentNode,
+ override val dri: Set<DRI>,
+ override val documentable: Documentable?,
+ override val children: List<PageNode>,
+ override val embeddedResources: List<String> = listOf()
+) : ContentPage {
+ override fun modified(name: String, children: List<PageNode>): ClasslikePageNode =
+ modified(name = name, content = this.content, children = children)
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ): ClasslikePageNode =
+ if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
+ else ClasslikePageNode(name, content, dri, documentable, children, embeddedResources)
+}
+
+class MemberPageNode(
+ override val name: String,
+ override val content: ContentNode,
+ override val dri: Set<DRI>,
+ override val documentable: Documentable?,
+ override val children: List<PageNode> = emptyList(),
+ override val embeddedResources: List<String> = listOf()
+) : ContentPage {
+ override fun modified(name: String, children: List<PageNode>): MemberPageNode =
+ modified(name = name, content = this.content, children = children) as MemberPageNode
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ): MemberPageNode =
+ if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
+ else MemberPageNode(name, content, dri, documentable, children, embeddedResources)
+}
+
+
+class MultimoduleRootPageNode(
+ override val name: String,
+ override val dri: Set<DRI>,
+ override val content: ContentNode,
+ override val embeddedResources: List<String> = emptyList()
+) : RootPageNode(), ContentPage {
+
+ override val children: List<PageNode> = emptyList()
+
+ override val documentable: Documentable? = null
+
+ override fun modified(name: String, children: List<PageNode>): RootPageNode =
+ MultimoduleRootPageNode(name, dri, content, embeddedResources)
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ) =
+ if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
+ else MultimoduleRootPageNode(name, dri, content, embeddedResources)
+}
+
+inline fun <reified T: PageNode> PageNode.children() = children.filterIsInstance<T>()
+
+private infix fun <T> List<T>.shallowEq(other: List<T>) =
+ this === other || (this.size == other.size && (this zip other).all { (a, b) -> a === b })
diff --git a/core/src/main/kotlin/pages/RendererSpecificPage.kt b/core/src/main/kotlin/pages/RendererSpecificPage.kt
new file mode 100644
index 00000000..85e6d530
--- /dev/null
+++ b/core/src/main/kotlin/pages/RendererSpecificPage.kt
@@ -0,0 +1,40 @@
+package org.jetbrains.dokka.pages
+
+import org.jetbrains.dokka.renderers.Renderer
+import kotlin.reflect.KClass
+
+interface RendererSpecificPage : PageNode {
+ val strategy: RenderingStrategy
+}
+
+class RendererSpecificRootPage(
+ override val name: String,
+ override val children: List<PageNode>,
+ override val strategy: RenderingStrategy
+) : RootPageNode(), RendererSpecificPage {
+ override fun modified(name: String, children: List<PageNode>): RendererSpecificRootPage =
+ RendererSpecificRootPage(name, children, strategy)
+}
+
+class RendererSpecificResourcePage(
+ override val name: String,
+ override val children: List<PageNode>,
+ override val strategy: RenderingStrategy
+): RendererSpecificPage {
+ override fun modified(name: String, children: List<PageNode>): RendererSpecificResourcePage =
+ RendererSpecificResourcePage(name, children, strategy)
+}
+
+sealed class RenderingStrategy {
+ class Callback(val instructions: Renderer.(PageNode) -> String): RenderingStrategy()
+ data class Copy(val from: String) : RenderingStrategy()
+ data class Write(val text: String) : RenderingStrategy()
+ object DoNothing : RenderingStrategy()
+
+ companion object {
+ inline operator fun <reified T: Renderer> invoke(crossinline instructions: T.(PageNode) -> String) =
+ Callback { if (this is T) instructions(it) else throw WrongRendererTypeException(T::class) }
+ }
+}
+
+data class WrongRendererTypeException(val expectedType: KClass<*>): Exception() \ No newline at end of file
diff --git a/core/src/main/kotlin/pages/contentNodeProperties.kt b/core/src/main/kotlin/pages/contentNodeProperties.kt
new file mode 100644
index 00000000..67acef6d
--- /dev/null
+++ b/core/src/main/kotlin/pages/contentNodeProperties.kt
@@ -0,0 +1,12 @@
+package org.jetbrains.dokka.pages
+
+import org.jetbrains.dokka.model.properties.ExtraProperty
+
+class SimpleAttr(val extraKey: String, val extraValue: String) : ExtraProperty<ContentNode> {
+ data class SimpleAttrKey(val key: String) : ExtraProperty.Key<ContentNode, SimpleAttr>
+ override val key: ExtraProperty.Key<ContentNode, SimpleAttr> = SimpleAttrKey(extraKey)
+
+ companion object {
+ fun header(value: String) = SimpleAttr("data-togglable", value)
+ }
+}
diff --git a/core/src/main/kotlin/pages/utils.kt b/core/src/main/kotlin/pages/utils.kt
new file mode 100644
index 00000000..c9039416
--- /dev/null
+++ b/core/src/main/kotlin/pages/utils.kt
@@ -0,0 +1,31 @@
+package org.jetbrains.dokka.pages
+
+import kotlin.reflect.KClass
+
+inline fun <reified T : ContentNode, R : ContentNode> R.mapTransform(noinline operation: (T) -> T): R =
+ mapTransform(T::class, operation)
+
+@PublishedApi
+@Suppress("UNCHECKED_CAST")
+internal fun <T : ContentNode, R : ContentNode> R.mapTransform(type: KClass<T>, operation: (T) -> T): R {
+ if (this::class == type) {
+ return operation(this as T) as R
+ }
+ val new = when (this) {
+ is ContentGroup -> this.copy(children.map { it.mapTransform(type, operation) })
+ is ContentHeader -> this.copy(children.map { it.mapTransform(type, operation) })
+ is ContentCodeBlock -> this.copy(children.map { it.mapTransform(type, operation) })
+ is ContentCodeInline -> this.copy(children.map { it.mapTransform(type, operation) })
+ is ContentTable -> this.copy(children.map { it.mapTransform(type, operation) })
+ is ContentList -> this.copy(children.map { it.mapTransform(type, operation) })
+ is ContentDivergentGroup -> this.copy(children.map { it.mapTransform(type, operation) })
+ is ContentDivergentInstance -> this.copy(
+ before = before?.mapTransform(type, operation),
+ divergent = divergent.mapTransform(type, operation),
+ after = after?.mapTransform(type, operation)
+ )
+ is PlatformHintedContent -> this.copy(inner.mapTransform(type, operation))
+ else -> this
+ }
+ return new as R
+}
diff --git a/core/src/main/kotlin/plugability/DefaultExtensions.kt b/core/src/main/kotlin/plugability/DefaultExtensions.kt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/core/src/main/kotlin/plugability/DefaultExtensions.kt
diff --git a/core/src/main/kotlin/plugability/DokkaContext.kt b/core/src/main/kotlin/plugability/DokkaContext.kt
new file mode 100644
index 00000000..323039e9
--- /dev/null
+++ b/core/src/main/kotlin/plugability/DokkaContext.kt
@@ -0,0 +1,223 @@
+package org.jetbrains.dokka.plugability
+
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.utilities.DokkaLogger
+import java.io.File
+import java.net.URLClassLoader
+import java.util.*
+import kotlin.reflect.KClass
+import kotlin.reflect.full.createInstance
+
+
+interface DokkaContext {
+ fun <T : DokkaPlugin> plugin(kclass: KClass<T>): T?
+
+ operator fun <T, E> get(point: E): List<T>
+ where T : Any, E : ExtensionPoint<T>
+
+ fun <T, E> single(point: E): T where T : Any, E : ExtensionPoint<T>
+
+ val logger: DokkaLogger
+ val configuration: DokkaConfiguration
+ val unusedPoints: Collection<ExtensionPoint<*>>
+
+
+ companion object {
+ fun create(
+ configuration: DokkaConfiguration,
+ logger: DokkaLogger,
+ pluginOverrides: List<DokkaPlugin>
+ ): DokkaContext =
+ DokkaContextConfigurationImpl(logger, configuration).apply {
+ // File(it.path) is a workaround for an incorrect filesystem in a File instance returned by Gradle.
+ configuration.pluginsClasspath.map { File(it.path).toURI().toURL() }
+ .toTypedArray()
+ .let { URLClassLoader(it, this.javaClass.classLoader) }
+ .also { checkClasspath(it) }
+ .let { ServiceLoader.load(DokkaPlugin::class.java, it) }
+ .let { it + pluginOverrides }
+ .forEach { install(it) }
+ topologicallySortAndPrune()
+ }.also { it.logInitialisationInfo() }
+ }
+}
+
+inline fun <reified T : DokkaPlugin> DokkaContext.plugin(): T = plugin(T::class)
+ ?: throw java.lang.IllegalStateException("Plugin ${T::class.qualifiedName} is not present in context.")
+
+interface DokkaContextConfiguration {
+ fun installExtension(extension: Extension<*, *, *>)
+}
+
+private class DokkaContextConfigurationImpl(
+ override val logger: DokkaLogger,
+ override val configuration: DokkaConfiguration
+) : DokkaContext, DokkaContextConfiguration {
+ private val plugins = mutableMapOf<KClass<*>, DokkaPlugin>()
+ private val pluginStubs = mutableMapOf<KClass<*>, DokkaPlugin>()
+ val extensions = mutableMapOf<ExtensionPoint<*>, MutableList<Extension<*, *, *>>>()
+ val pointsUsed: MutableSet<ExtensionPoint<*>> = mutableSetOf()
+ val pointsPopulated: MutableSet<ExtensionPoint<*>> = mutableSetOf()
+ override val unusedPoints: Set<ExtensionPoint<*>>
+ get() = pointsPopulated - pointsUsed
+
+ private enum class State {
+ UNVISITED,
+ VISITING,
+ VISITED;
+ }
+
+ private sealed class Suppression {
+ data class ByExtension(val extension: Extension<*, *, *>) : Suppression() {
+ override fun toString() = extension.toString()
+ }
+
+ data class ByPlugin(val plugin: DokkaPlugin) : Suppression() {
+ override fun toString() = "Plugin ${plugin::class.qualifiedName}"
+ }
+ }
+
+ private val rawExtensions = mutableListOf<Extension<*, *, *>>()
+ private val rawAdjacencyList = mutableMapOf<Extension<*, *, *>, MutableList<Extension<*, *, *>>>()
+ private val suppressedExtensions = mutableMapOf<Extension<*, *, *>, MutableList<Suppression>>()
+
+ fun topologicallySortAndPrune() {
+ pointsPopulated.clear()
+ extensions.clear()
+
+ val overridesInfo = processOverrides()
+ val extensionsToSort = overridesInfo.keys
+ val adjacencyList = translateAdjacencyList(overridesInfo)
+
+ val verticesWithState = extensionsToSort.associateWithTo(mutableMapOf()) { State.UNVISITED }
+ val result: MutableList<Extension<*, *, *>> = mutableListOf()
+
+ fun visit(n: Extension<*, *, *>) {
+ val state = verticesWithState[n]
+ if (state == State.VISITED)
+ return
+ if (state == State.VISITING)
+ throw Error("Detected cycle in plugins graph")
+ verticesWithState[n] = State.VISITING
+ adjacencyList[n]?.forEach { visit(it) }
+ verticesWithState[n] = State.VISITED
+ result += n
+ }
+
+ extensionsToSort.forEach(::visit)
+
+ val filteredResult = result.asReversed().filterNot { it in suppressedExtensions }
+
+ filteredResult.mapTo(pointsPopulated) { it.extensionPoint }
+ filteredResult.groupByTo(extensions) { it.extensionPoint }
+ }
+
+ private fun processOverrides(): Map<Extension<*, *, *>, Set<Extension<*, *, *>>> {
+ val buckets = rawExtensions.associateWithTo(mutableMapOf()) { setOf(it) }
+ suppressedExtensions.forEach { (extension, suppressions) ->
+ val mergedBucket = suppressions.filterIsInstance<Suppression.ByExtension>()
+ .map { it.extension }
+ .plus(extension)
+ .flatMap { buckets[it].orEmpty() }
+ .toSet()
+ mergedBucket.forEach { buckets[it] = mergedBucket }
+ }
+ return buckets.values.distinct().associateBy(::findNotOverridden)
+ }
+
+ private fun findNotOverridden(bucket: Set<Extension<*, *, *>>): Extension<*, *, *> {
+ val filtered = bucket.filter { it !in suppressedExtensions }
+ return filtered.singleOrNull() ?: throw IllegalStateException("Conflicting overrides: $filtered")
+ }
+
+ private fun translateAdjacencyList(
+ overridesInfo: Map<Extension<*, *, *>, Set<Extension<*, *, *>>>
+ ): Map<Extension<*, *, *>, List<Extension<*, *, *>>> {
+ val reverseOverrideInfo = overridesInfo.flatMap { (ext, set) -> set.map { it to ext } }.toMap()
+ return rawAdjacencyList.mapNotNull { (ext, list) ->
+ reverseOverrideInfo[ext]?.to(list.mapNotNull { reverseOverrideInfo[it] })
+ }.toMap()
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override operator fun <T, E> get(point: E) where T : Any, E : ExtensionPoint<T> =
+ actions(point).also { pointsUsed += point }.orEmpty() as List<T>
+
+ @Suppress("UNCHECKED_CAST")
+ override fun <T, E> single(point: E): T where T : Any, E : ExtensionPoint<T> {
+ fun throwBadArity(substitution: String): Nothing = throw IllegalStateException(
+ "$point was expected to have exactly one extension registered, but $substitution found."
+ )
+ pointsUsed += point
+
+ val extensions = extensions[point].orEmpty() as List<Extension<T, *, *>>
+ return when (extensions.size) {
+ 0 -> throwBadArity("none was")
+ 1 -> extensions.single().action.get(this)
+ else -> throwBadArity("many were")
+ }
+ }
+
+ private fun <E : ExtensionPoint<*>> actions(point: E) = extensions[point]?.map { it.action.get(this) }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : DokkaPlugin> plugin(kclass: KClass<T>) = (plugins[kclass] ?: pluginStubFor(kclass)) as T
+
+ private fun <T : DokkaPlugin> pluginStubFor(kclass: KClass<T>): DokkaPlugin =
+ pluginStubs.getOrPut(kclass) { kclass.createInstance().also { it.context = this } }
+
+ fun install(plugin: DokkaPlugin) {
+ plugins[plugin::class] = plugin
+ plugin.context = this
+ plugin.internalInstall(this, this.configuration)
+
+ if (plugin is WithUnsafeExtensionSuppression) {
+ plugin.extensionsSuppressed.forEach {
+ suppressedExtensions.listFor(it) += Suppression.ByPlugin(plugin)
+ }
+ }
+ }
+
+ override fun installExtension(extension: Extension<*, *, *>) {
+ rawExtensions += extension
+
+ if (extension.ordering is OrderingKind.ByDsl) {
+ val orderDsl = OrderDsl()
+ orderDsl.(extension.ordering.block)()
+
+ rawAdjacencyList.listFor(extension) += orderDsl.following.toList()
+ orderDsl.previous.forEach { rawAdjacencyList.listFor(it) += extension }
+ }
+
+ if (extension.override is OverrideKind.Present) {
+ suppressedExtensions.listFor(extension.override.overriden) += Suppression.ByExtension(extension)
+ }
+ }
+
+ fun logInitialisationInfo() {
+ val pluginNames = plugins.values.map { it::class.qualifiedName.toString() }
+
+ val loadedListForDebug = extensions.run { keys + values.flatten() }.toList()
+ .joinToString(prefix = "[\n", separator = ",\n", postfix = "\n]") { "\t$it" }
+
+ val suppressedList = suppressedExtensions.asSequence()
+ .joinToString(prefix = "[\n", separator = ",\n", postfix = "\n]") {
+ "\t${it.key} by " + (it.value.singleOrNull() ?: it.value)
+ }
+
+ logger.info("Loaded plugins: $pluginNames")
+ logger.info("Loaded: $loadedListForDebug")
+ logger.info("Suppressed: $suppressedList")
+ }
+}
+
+private fun checkClasspath(classLoader: URLClassLoader) {
+ classLoader.findResource(DokkaContext::class.java.name.replace('.', '/') + ".class")?.also {
+ throw AssertionError(
+ "Dokka API found on plugins classpath. This will lead to subtle bugs. " +
+ "Please fix your plugins dependencies or exclude dokka api artifact from plugin classpath"
+ )
+ }
+}
+
+private fun <K, V> MutableMap<K, MutableList<V>>.listFor(key: K) = getOrPut(key, ::mutableListOf)
diff --git a/core/src/main/kotlin/plugability/DokkaPlugin.kt b/core/src/main/kotlin/plugability/DokkaPlugin.kt
new file mode 100644
index 00000000..2c755a49
--- /dev/null
+++ b/core/src/main/kotlin/plugability/DokkaPlugin.kt
@@ -0,0 +1,82 @@
+package org.jetbrains.dokka.plugability
+
+import com.google.gson.Gson
+import org.jetbrains.dokka.DokkaConfiguration
+import kotlin.properties.ReadOnlyProperty
+import kotlin.reflect.KProperty
+import kotlin.reflect.KProperty1
+import kotlin.reflect.full.createInstance
+
+abstract class DokkaPlugin {
+ private val extensionDelegates = mutableListOf<KProperty<*>>()
+
+ @PublishedApi
+ internal var context: DokkaContext? = null
+
+ protected inline fun <reified T : DokkaPlugin> plugin(): T = context?.plugin(T::class) ?: throwIllegalQuery()
+
+ protected fun <T : Any> extensionPoint() =
+ object : ReadOnlyProperty<DokkaPlugin, ExtensionPoint<T>> {
+ override fun getValue(thisRef: DokkaPlugin, property: KProperty<*>) = ExtensionPoint<T>(
+ thisRef::class.qualifiedName ?: throw AssertionError("Plugin must be named class"),
+ property.name
+ )
+ }
+
+ protected fun <T : Any> extending(definition: ExtendingDSL.() -> Extension<T, *, *>) = ExtensionProvider(definition)
+
+ protected class ExtensionProvider<T : Any> internal constructor(
+ private val definition: ExtendingDSL.() -> Extension<T, *, *>
+ ) {
+ operator fun provideDelegate(thisRef: DokkaPlugin, property: KProperty<*>) = lazy {
+ ExtendingDSL(
+ thisRef::class.qualifiedName ?: throw AssertionError("Plugin must be named class"),
+ property.name
+ ).definition()
+ }.also { thisRef.extensionDelegates += property }
+ }
+
+ internal fun internalInstall(ctx: DokkaContextConfiguration, configuration: DokkaConfiguration) {
+ extensionDelegates.asSequence()
+ .filterIsInstance<KProperty1<DokkaPlugin, Extension<*, *, *>>>() // should be always true
+ .map { it.get(this) }
+ .forEach { if (configuration.(it.condition)()) ctx.installExtension(it) }
+ }
+}
+
+interface WithUnsafeExtensionSuppression {
+ val extensionsSuppressed: List<Extension<*, *, *>>
+}
+
+interface Configurable {
+ val pluginsConfiguration: Map<String, String>
+}
+
+interface ConfigurableBlock
+
+inline fun <reified P : DokkaPlugin, reified T : ConfigurableBlock> Configurable.pluginConfiguration(block: T.() -> Unit) {
+ val instance = T::class.createInstance().apply(block)
+
+ val mutablePluginsConfiguration = pluginsConfiguration as MutableMap<String, String>
+ mutablePluginsConfiguration[P::class.qualifiedName!!] = Gson().toJson(instance, T::class.java)
+}
+
+inline fun <reified P : DokkaPlugin, reified E : Any> P.query(extension: P.() -> ExtensionPoint<E>): List<E> =
+ context?.let { it[extension()] } ?: throwIllegalQuery()
+
+inline fun <reified P : DokkaPlugin, reified E : Any> P.querySingle(extension: P.() -> ExtensionPoint<E>): E =
+ context?.single(extension()) ?: throwIllegalQuery()
+
+fun throwIllegalQuery(): Nothing =
+ throw IllegalStateException("Querying about plugins is only possible with dokka context initialised")
+
+inline fun <reified T : DokkaPlugin, reified R : ConfigurableBlock> configuration(context: DokkaContext): ReadOnlyProperty<Any?, R> {
+ return object : ReadOnlyProperty<Any?, R> {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): R {
+ return context.configuration.pluginsConfiguration[T::class.qualifiedName
+ ?: throw AssertionError("Plugin must be named class")].let {
+ Gson().fromJson(it, R::class.java)
+ }
+ }
+ }
+}
diff --git a/core/src/main/kotlin/plugability/LazyEvaluated.kt b/core/src/main/kotlin/plugability/LazyEvaluated.kt
new file mode 100644
index 00000000..c0c271f4
--- /dev/null
+++ b/core/src/main/kotlin/plugability/LazyEvaluated.kt
@@ -0,0 +1,16 @@
+package org.jetbrains.dokka.plugability
+
+internal class LazyEvaluated<T : Any> private constructor(private val recipe: ((DokkaContext) -> T)? = null, private var value: T? = null) {
+
+ internal fun get(context: DokkaContext): T {
+ if(value == null) {
+ value = recipe?.invoke(context)
+ }
+ return value ?: throw AssertionError("Incorrect initialized LazyEvaluated instance")
+ }
+
+ companion object {
+ fun <T : Any> fromInstance(value: T) = LazyEvaluated(value = value)
+ fun <T : Any> fromRecipe(recipe: (DokkaContext) -> T) = LazyEvaluated(recipe = recipe)
+ }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/plugability/extensions.kt b/core/src/main/kotlin/plugability/extensions.kt
new file mode 100644
index 00000000..c6dd0b85
--- /dev/null
+++ b/core/src/main/kotlin/plugability/extensions.kt
@@ -0,0 +1,87 @@
+package org.jetbrains.dokka.plugability
+
+import org.jetbrains.dokka.DokkaConfiguration
+
+data class ExtensionPoint<T : Any> internal constructor(
+ internal val pluginClass: String,
+ internal val pointName: String
+) {
+ override fun toString() = "ExtensionPoint: $pluginClass/$pointName"
+}
+
+sealed class OrderingKind {
+ object None : OrderingKind()
+ class ByDsl(val block: (OrderDsl.() -> Unit)) : OrderingKind()
+}
+
+sealed class OverrideKind {
+ object None : OverrideKind()
+ class Present(val overriden: Extension<*, *, *>) : OverrideKind()
+}
+
+class Extension<T : Any, Ordering : OrderingKind, Override : OverrideKind> internal constructor(
+ internal val extensionPoint: ExtensionPoint<T>,
+ internal val pluginClass: String,
+ internal val extensionName: String,
+ internal val action: LazyEvaluated<T>,
+ internal val ordering: Ordering,
+ internal val override: Override,
+ internal val conditions: List<DokkaConfiguration.() -> Boolean>
+) {
+ override fun toString() = "Extension: $pluginClass/$extensionName"
+
+ override fun equals(other: Any?) =
+ if (other is Extension<*, *, *>) this.pluginClass == other.pluginClass && this.extensionName == other.extensionName
+ else false
+
+ override fun hashCode() = listOf(pluginClass, extensionName).hashCode()
+
+ val condition: DokkaConfiguration.() -> Boolean
+ get() = { conditions.all { it(this) } }
+}
+
+private fun <T : Any> Extension(
+ extensionPoint: ExtensionPoint<T>,
+ pluginClass: String,
+ extensionName: String,
+ action: LazyEvaluated<T>
+) = Extension(extensionPoint, pluginClass, extensionName, action, OrderingKind.None, OverrideKind.None, emptyList())
+
+@DslMarker
+annotation class ExtensionsDsl
+
+@ExtensionsDsl
+class ExtendingDSL(private val pluginClass: String, private val extensionName: String) {
+
+ infix fun <T : Any> ExtensionPoint<T>.with(action: T) =
+ Extension(this, this@ExtendingDSL.pluginClass, extensionName, LazyEvaluated.fromInstance(action))
+
+ infix fun <T : Any> ExtensionPoint<T>.providing(action: (DokkaContext) -> T) =
+ Extension(this, this@ExtendingDSL.pluginClass, extensionName, LazyEvaluated.fromRecipe(action))
+
+ infix fun <T : Any, Override : OverrideKind> Extension<T, OrderingKind.None, Override>.order(
+ block: OrderDsl.() -> Unit
+ ) = Extension(extensionPoint, pluginClass, extensionName, action, OrderingKind.ByDsl(block), override, conditions)
+
+ infix fun <T : Any, Override : OverrideKind, Ordering: OrderingKind> Extension<T, Ordering, Override>.applyIf(
+ condition: DokkaConfiguration.() -> Boolean
+ ) = Extension(extensionPoint, pluginClass, extensionName, action, ordering, override, conditions + condition)
+
+ infix fun <T : Any, Override : OverrideKind, Ordering: OrderingKind> Extension<T, Ordering, Override>.override(
+ overriden: Extension<T, *, *>
+ ) = Extension(extensionPoint, pluginClass, extensionName, action, ordering, OverrideKind.Present(overriden), conditions)
+}
+
+@ExtensionsDsl
+class OrderDsl {
+ internal val previous = mutableSetOf<Extension<*, *, *>>()
+ internal val following = mutableSetOf<Extension<*, *, *>>()
+
+ fun after(vararg extensions: Extension<*, *, *>) {
+ previous += extensions
+ }
+
+ fun before(vararg extensions: Extension<*, *, *>) {
+ following += extensions
+ }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/renderers/Renderer.kt b/core/src/main/kotlin/renderers/Renderer.kt
new file mode 100644
index 00000000..10235f21
--- /dev/null
+++ b/core/src/main/kotlin/renderers/Renderer.kt
@@ -0,0 +1,7 @@
+package org.jetbrains.dokka.renderers
+
+import org.jetbrains.dokka.pages.RootPageNode
+
+interface Renderer {
+ fun render(root: RootPageNode)
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt b/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt
new file mode 100644
index 00000000..c8ae9c02
--- /dev/null
+++ b/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt
@@ -0,0 +1,8 @@
+package org.jetbrains.dokka.transformers.documentation
+
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.plugability.DokkaContext
+
+interface DocumentableMerger {
+ operator fun invoke(modules: Collection<DModule>, context: DokkaContext): DModule
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt b/core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt
new file mode 100644
index 00000000..a4daba63
--- /dev/null
+++ b/core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt
@@ -0,0 +1,9 @@
+package org.jetbrains.dokka.transformers.documentation
+
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.pages.ModulePageNode
+import org.jetbrains.dokka.pages.RootPageNode
+
+interface DocumentableToPageTranslator {
+ operator fun invoke(module: DModule): RootPageNode
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt b/core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt
new file mode 100644
index 00000000..3eb4704e
--- /dev/null
+++ b/core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt
@@ -0,0 +1,8 @@
+package org.jetbrains.dokka.transformers.documentation
+
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.plugability.DokkaContext
+
+interface DocumentableTransformer {
+ operator fun invoke(original: DModule, context: DokkaContext): DModule
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/documentation/PreMergeDocumentableTransformer.kt b/core/src/main/kotlin/transformers/documentation/PreMergeDocumentableTransformer.kt
new file mode 100644
index 00000000..b67a1d57
--- /dev/null
+++ b/core/src/main/kotlin/transformers/documentation/PreMergeDocumentableTransformer.kt
@@ -0,0 +1,8 @@
+package org.jetbrains.dokka.transformers.documentation
+
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.plugability.DokkaContext
+
+interface PreMergeDocumentableTransformer {
+ operator fun invoke(modules: List<DModule>): List<DModule>
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/pages/PageCreator.kt b/core/src/main/kotlin/transformers/pages/PageCreator.kt
new file mode 100644
index 00000000..f74b5efa
--- /dev/null
+++ b/core/src/main/kotlin/transformers/pages/PageCreator.kt
@@ -0,0 +1,8 @@
+package org.jetbrains.dokka.transformers.pages
+
+import org.jetbrains.dokka.pages.RootPageNode
+import org.jetbrains.dokka.plugability.DokkaContext
+
+interface PageCreator {
+ operator fun invoke(): RootPageNode
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/pages/PageTransformer.kt b/core/src/main/kotlin/transformers/pages/PageTransformer.kt
new file mode 100644
index 00000000..218d9821
--- /dev/null
+++ b/core/src/main/kotlin/transformers/pages/PageTransformer.kt
@@ -0,0 +1,7 @@
+package org.jetbrains.dokka.transformers.pages
+
+import org.jetbrains.dokka.pages.RootPageNode
+
+interface PageTransformer {
+ operator fun invoke(input: RootPageNode): RootPageNode
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/pages/PageTransformerBuilders.kt b/core/src/main/kotlin/transformers/pages/PageTransformerBuilders.kt
new file mode 100644
index 00000000..291b72ef
--- /dev/null
+++ b/core/src/main/kotlin/transformers/pages/PageTransformerBuilders.kt
@@ -0,0 +1,22 @@
+package org.jetbrains.dokka.transformers.pages
+
+import org.jetbrains.dokka.pages.PageNode
+import org.jetbrains.dokka.pages.RootPageNode
+
+fun pageScanner(block: PageNode.() -> Unit) = object : PageTransformer {
+ override fun invoke(input: RootPageNode): RootPageNode = input.invokeOnAll(block) as RootPageNode
+}
+
+fun pageMapper(block: PageNode.() -> PageNode) = object : PageTransformer {
+ override fun invoke(input: RootPageNode): RootPageNode = input.alterChildren(block) as RootPageNode
+}
+
+fun pageStructureTransformer(block: RootPageNode.() -> RootPageNode) = object : PageTransformer {
+ override fun invoke(input: RootPageNode): RootPageNode = block(input)
+}
+
+fun PageNode.invokeOnAll(block: PageNode.() -> Unit): PageNode =
+ this.also(block).also { it.children.forEach { it.invokeOnAll(block) } }
+
+fun PageNode.alterChildren(block: PageNode.() -> PageNode): PageNode =
+ block(this).modified(children = this.children.map { it.alterChildren(block) }) \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/sources/SourceToDocumentableTranslator.kt b/core/src/main/kotlin/transformers/sources/SourceToDocumentableTranslator.kt
new file mode 100644
index 00000000..6bc8fb14
--- /dev/null
+++ b/core/src/main/kotlin/transformers/sources/SourceToDocumentableTranslator.kt
@@ -0,0 +1,9 @@
+package org.jetbrains.dokka.transformers.sources
+
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.plugability.DokkaContext
+
+interface SourceToDocumentableTranslator {
+ fun invoke(sourceSet: DokkaSourceSet, context: DokkaContext): DModule
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/utilities/DokkaLogging.kt b/core/src/main/kotlin/utilities/DokkaLogging.kt
new file mode 100644
index 00000000..6b8ed5d2
--- /dev/null
+++ b/core/src/main/kotlin/utilities/DokkaLogging.kt
@@ -0,0 +1,38 @@
+package org.jetbrains.dokka.utilities
+
+interface DokkaLogger {
+ var warningsCount: Int
+ var errorsCount: Int
+ fun debug(message: String)
+ fun info(message: String)
+ fun progress(message: String)
+ fun warn(message: String)
+ fun error(message: String)
+}
+
+fun DokkaLogger.report() {
+ if (DokkaConsoleLogger.warningsCount > 0 || DokkaConsoleLogger.errorsCount > 0) {
+ info("Generation completed with ${DokkaConsoleLogger.warningsCount} warning" +
+ (if(DokkaConsoleLogger.warningsCount == 1) "" else "s") +
+ " and ${DokkaConsoleLogger.errorsCount} error" +
+ if(DokkaConsoleLogger.errorsCount == 1) "" else "s"
+ )
+ } else {
+ info("generation completed successfully")
+ }
+}
+
+object DokkaConsoleLogger : DokkaLogger {
+ override var warningsCount: Int = 0
+ override var errorsCount: Int = 0
+
+ override fun debug(message: String)= println(message)
+
+ override fun progress(message: String) = println("PROGRESS: $message")
+
+ override fun info(message: String) = println(message)
+
+ override fun warn(message: String) = println("WARN: $message").also { warningsCount++ }
+
+ override fun error(message: String) = println("ERROR: $message").also { errorsCount++ }
+}
diff --git a/core/src/main/kotlin/Utilities/Html.kt b/core/src/main/kotlin/utilities/Html.kt
index de1ce1a5..3226ca9d 100644
--- a/core/src/main/kotlin/Utilities/Html.kt
+++ b/core/src/main/kotlin/utilities/Html.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka
+package org.jetbrains.dokka.utilities
import java.net.URLEncoder
@@ -9,4 +9,7 @@ import java.net.URLEncoder
*/
fun String.htmlEscape(): String = replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
-fun String.urlEncoded(): String = URLEncoder.encode(this, "UTF-8") \ No newline at end of file
+fun String.urlEncoded(): String = URLEncoder.encode(this, "UTF-8")
+
+fun String.formatToEndWithHtml() =
+ if (endsWith(".html") || contains(Regex("\\.html#"))) this else "$this.html" \ No newline at end of file
diff --git a/core/src/main/kotlin/Utilities/ServiceLocator.kt b/core/src/main/kotlin/utilities/ServiceLocator.kt
index eda83422..00c9ae9f 100644
--- a/core/src/main/kotlin/Utilities/ServiceLocator.kt
+++ b/core/src/main/kotlin/utilities/ServiceLocator.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.Utilities
+package org.jetbrains.dokka.utilities
import java.io.File
import java.net.URISyntaxException
diff --git a/core/src/main/kotlin/Utilities/Uri.kt b/core/src/main/kotlin/utilities/Uri.kt
index 9827c624..089b3cff 100644
--- a/core/src/main/kotlin/Utilities/Uri.kt
+++ b/core/src/main/kotlin/utilities/Uri.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka
+package org.jetbrains.dokka.utilities
import java.net.URI
diff --git a/core/src/main/kotlin/utilities/cast.kt b/core/src/main/kotlin/utilities/cast.kt
new file mode 100644
index 00000000..d4a8d73d
--- /dev/null
+++ b/core/src/main/kotlin/utilities/cast.kt
@@ -0,0 +1,5 @@
+package org.jetbrains.dokka.utilities
+
+inline fun <reified T> Any.cast(): T {
+ return this as T
+}
diff --git a/core/src/main/kotlin/utilities/nodeDebug.kt b/core/src/main/kotlin/utilities/nodeDebug.kt
new file mode 100644
index 00000000..0e8c61f7
--- /dev/null
+++ b/core/src/main/kotlin/utilities/nodeDebug.kt
@@ -0,0 +1,50 @@
+package org.jetbrains.dokka.utilities
+
+import org.jetbrains.dokka.model.Documentable
+import org.jetbrains.dokka.pages.*
+
+const val DOWN = '\u2503'
+const val BRANCH = '\u2523'
+const val LAST = '\u2517'
+
+fun Documentable.pretty(prefix: String = "", isLast: Boolean = true): String {
+ val nextPrefix = prefix + (if (isLast) ' ' else DOWN) + ' '
+
+ return prefix + (if (isLast) LAST else BRANCH) + this.toString() +
+ children.dropLast(1)
+ .map { it.pretty(nextPrefix, false) }
+ .plus(children.lastOrNull()?.pretty(nextPrefix))
+ .filterNotNull()
+ .takeIf { it.isNotEmpty() }
+ ?.joinToString(prefix = "\n", separator = "")
+ .orEmpty() + if (children.isEmpty()) "\n" else ""
+}
+
+//fun Any.genericPretty(prefix: String = "", isLast: Boolean = true): String {
+// val nextPrefix = prefix + (if (isLast) ' ' else DOWN) + ' '
+//
+// return prefix + (if (isLast) LAST else BRANCH) + this.stringify() +
+// allChildren().dropLast(1)
+// .map { it.genericPretty(nextPrefix, false) }
+// .plus(allChildren().lastOrNull()?.genericPretty(nextPrefix))
+// .filterNotNull()
+// .takeIf { it.isNotEmpty() }
+// ?.joinToString(prefix = "\n", separator = "")
+// .orEmpty() + if (allChildren().isEmpty()) "\n" else ""
+//}
+private fun Any.stringify() = when(this) {
+ is ContentNode -> toString() + this.dci
+ is ContentPage -> this.name + this::class.simpleName
+ else -> toString()
+}
+//private fun Any.allChildren() = when(this){
+// is PageNode -> children + content
+// is ContentBlock -> this.children
+// is ContentHeader -> this.items
+// is ContentStyle -> this.items
+// is ContentSymbol -> this.parts
+// is ContentComment -> this.parts
+// is ContentGroup -> this.children
+// is ContentList -> this.items
+// else -> emptyList()
+//}
diff --git a/core/src/main/resources/META-INF/MANIFEST.MF b/core/src/main/resources/META-INF/MANIFEST.MF
index 78fabddc..9d885be5 100644
--- a/core/src/main/resources/META-INF/MANIFEST.MF
+++ b/core/src/main/resources/META-INF/MANIFEST.MF
@@ -1,4 +1 @@
Manifest-Version: 1.0
-Class-Path: kotlin-plugin.jar
-Main-Class: org.jetbrains.dokka.DokkaPackage
-
diff --git a/core/src/main/resources/META-INF/dokka/dokka-version.properties b/core/src/main/resources/META-INF/dokka/dokka-version.properties
new file mode 100644
index 00000000..6b2e2bcd
--- /dev/null
+++ b/core/src/main/resources/META-INF/dokka/dokka-version.properties
@@ -0,0 +1 @@
+dokka-version=<dokka-version>
diff --git a/core/src/main/resources/dokka/format/gfm.properties b/core/src/main/resources/dokka/format/gfm.properties
deleted file mode 100644
index 5e8f7aa8..00000000
--- a/core/src/main/resources/dokka/format/gfm.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.Formats.GFMFormatDescriptor
-description=Produces documentation in GitHub-flavored markdown format
diff --git a/core/src/main/resources/dokka/format/html-as-java.properties b/core/src/main/resources/dokka/format/html-as-java.properties
deleted file mode 100644
index f598f377..00000000
--- a/core/src/main/resources/dokka/format/html-as-java.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.Formats.HtmlAsJavaFormatDescriptor
-description=Produces output in HTML format using Java syntax \ No newline at end of file
diff --git a/core/src/main/resources/dokka/format/html.properties b/core/src/main/resources/dokka/format/html.properties
deleted file mode 100644
index 7881dfae..00000000
--- a/core/src/main/resources/dokka/format/html.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.Formats.HtmlFormatDescriptor
-description=Produces output in HTML format \ No newline at end of file
diff --git a/core/src/main/resources/dokka/format/java-layout-html.properties b/core/src/main/resources/dokka/format/java-layout-html.properties
deleted file mode 100644
index fbb2bbed..00000000
--- a/core/src/main/resources/dokka/format/java-layout-html.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.Formats.JavaLayoutHtmlFormatDescriptor
-description=Produces Kotlin Style Docs with Javadoc like layout \ No newline at end of file
diff --git a/core/src/main/resources/dokka/format/javadoc.properties b/core/src/main/resources/dokka/format/javadoc.properties
deleted file mode 100644
index a0d8a945..00000000
--- a/core/src/main/resources/dokka/format/javadoc.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.javadoc.JavadocFormatDescriptor
-description=Produces Javadoc, with Kotlin declarations as Java view \ No newline at end of file
diff --git a/core/src/main/resources/dokka/format/jekyll.properties b/core/src/main/resources/dokka/format/jekyll.properties
deleted file mode 100644
index b11401a4..00000000
--- a/core/src/main/resources/dokka/format/jekyll.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.Formats.JekyllFormatDescriptor
-description=Produces documentation in Jekyll format \ No newline at end of file
diff --git a/core/src/main/resources/dokka/format/kotlin-website-html.properties b/core/src/main/resources/dokka/format/kotlin-website-html.properties
deleted file mode 100644
index f4c320b9..00000000
--- a/core/src/main/resources/dokka/format/kotlin-website-html.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.Formats.KotlinWebsiteHtmlFormatDescriptor
-description=Generates Kotlin website documentation \ No newline at end of file
diff --git a/core/src/main/resources/dokka/format/markdown.properties b/core/src/main/resources/dokka/format/markdown.properties
deleted file mode 100644
index 6217a6df..00000000
--- a/core/src/main/resources/dokka/format/markdown.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.Formats.MarkdownFormatDescriptor
-description=Produces documentation in markdown format \ No newline at end of file
diff --git a/core/src/main/resources/dokka/inbound-link-resolver/dokka-default.properties b/core/src/main/resources/dokka/inbound-link-resolver/dokka-default.properties
deleted file mode 100644
index c484a920..00000000
--- a/core/src/main/resources/dokka/inbound-link-resolver/dokka-default.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.InboundExternalLinkResolutionService$Dokka
-description=Uses Dokka Default resolver \ No newline at end of file
diff --git a/core/src/main/resources/dokka/inbound-link-resolver/java-layout-html.properties b/core/src/main/resources/dokka/inbound-link-resolver/java-layout-html.properties
deleted file mode 100644
index 3b61eabe..00000000
--- a/core/src/main/resources/dokka/inbound-link-resolver/java-layout-html.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.Formats.JavaLayoutHtmlInboundLinkResolutionService
-description=Resolver for JavaLayoutHtml \ No newline at end of file
diff --git a/core/src/main/resources/dokka/inbound-link-resolver/javadoc.properties b/core/src/main/resources/dokka/inbound-link-resolver/javadoc.properties
deleted file mode 100644
index 0d5d7d17..00000000
--- a/core/src/main/resources/dokka/inbound-link-resolver/javadoc.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-class=org.jetbrains.dokka.InboundExternalLinkResolutionService$Javadoc
-description=Uses Javadoc Default resolver \ No newline at end of file
diff --git a/core/src/main/resources/dokka/styles/style.css b/core/src/main/resources/dokka/styles/style.css
deleted file mode 100644
index 914be69d..00000000
--- a/core/src/main/resources/dokka/styles/style.css
+++ /dev/null
@@ -1,283 +0,0 @@
-@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700);
-
-body, table {
- padding:50px;
- font:14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif;
- color:#555;
- font-weight:300;
- margin-left: auto;
- margin-right: auto;
- max-width: 1440px;
-}
-
-.keyword {
- color:black;
- font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal;
- font-size:12px;
-}
-
-.symbol {
- font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal;
- font-size:12px;
-}
-
-.identifier {
- color: darkblue;
- font-size:12px;
- font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal;
-}
-
-h1, h2, h3, h4, h5, h6 {
- color:#222;
- margin:0 0 20px;
-}
-
-p, ul, ol, table, pre, dl {
- margin:0 0 20px;
-}
-
-h1, h2, h3 {
- line-height:1.1;
-}
-
-h1 {
- font-size:28px;
-}
-
-h2 {
- color:#393939;
-}
-
-h3, h4, h5, h6 {
- color:#494949;
-}
-
-a {
- color:#258aaf;
- font-weight:400;
- text-decoration:none;
-}
-
-a:hover {
- color: inherit;
- text-decoration:underline;
-}
-
-a small {
- font-size:11px;
- color:#555;
- margin-top:-0.6em;
- display:block;
-}
-
-.wrapper {
- width:860px;
- margin:0 auto;
-}
-
-blockquote {
- border-left:1px solid #e5e5e5;
- margin:0;
- padding:0 0 0 20px;
- font-style:italic;
-}
-
-code, pre {
- font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal;
- color:#333;
- font-size:12px;
-}
-
-pre {
- display: block;
-/*
- padding:8px 8px;
- background: #f8f8f8;
- border-radius:5px;
- border:1px solid #e5e5e5;
-*/
- overflow-x: auto;
-}
-
-table {
- width:100%;
- border-collapse:collapse;
-}
-
-th, td {
- text-align:left;
- vertical-align: top;
- padding:5px 10px;
-}
-
-dt {
- color:#444;
- font-weight:700;
-}
-
-th {
- color:#444;
-}
-
-img {
- max-width:100%;
-}
-
-header {
- width:270px;
- float:left;
- position:fixed;
-}
-
-header ul {
- list-style:none;
- height:40px;
-
- padding:0;
-
- background: #eee;
- background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd));
- background: -webkit-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);
- background: -o-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);
- background: -ms-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);
- background: linear-gradient(top, #f8f8f8 0%,#dddddd 100%);
-
- border-radius:5px;
- border:1px solid #d2d2d2;
- box-shadow:inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0;
- width:270px;
-}
-
-header li {
- width:89px;
- float:left;
- border-right:1px solid #d2d2d2;
- height:40px;
-}
-
-header ul a {
- line-height:1;
- font-size:11px;
- color:#999;
- display:block;
- text-align:center;
- padding-top:6px;
- height:40px;
-}
-
-strong {
- color:#222;
- font-weight:700;
-}
-
-header ul li + li {
- width:88px;
- border-left:1px solid #fff;
-}
-
-header ul li + li + li {
- border-right:none;
- width:89px;
-}
-
-header ul a strong {
- font-size:14px;
- display:block;
- color:#222;
-}
-
-section {
- width:500px;
- float:right;
- padding-bottom:50px;
-}
-
-small {
- font-size:11px;
-}
-
-hr {
- border:0;
- background:#e5e5e5;
- height:1px;
- margin:0 0 20px;
-}
-
-footer {
- width:270px;
- float:left;
- position:fixed;
- bottom:50px;
-}
-
-@media print, screen and (max-width: 960px) {
-
- div.wrapper {
- width:auto;
- margin:0;
- }
-
- header, section, footer {
- float:none;
- position:static;
- width:auto;
- }
-
- header {
- padding-right:320px;
- }
-
- section {
- border:1px solid #e5e5e5;
- border-width:1px 0;
- padding:20px 0;
- margin:0 0 20px;
- }
-
- header a small {
- display:inline;
- }
-
- header ul {
- position:absolute;
- right:50px;
- top:52px;
- }
-}
-
-@media print, screen and (max-width: 720px) {
- body {
- word-wrap:break-word;
- }
-
- header {
- padding:0;
- }
-
- header ul, header p.view {
- position:static;
- }
-
- pre, code {
- word-wrap:normal;
- }
-}
-
-@media print, screen and (max-width: 480px) {
- body {
- padding:15px;
- }
-
- header ul {
- display:none;
- }
-}
-
-@media print {
- body {
- padding:0.4in;
- font-size:12pt;
- color:#444;
- }
-}
diff --git a/core/src/test/kotlin/DokkaConfigurationTestImplementations.kt b/core/src/test/kotlin/DokkaConfigurationTestImplementations.kt
deleted file mode 100644
index a6f427b1..00000000
--- a/core/src/test/kotlin/DokkaConfigurationTestImplementations.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.DokkaConfiguration
-import org.jetbrains.dokka.Platform
-import java.io.File
-
-
-data class SourceLinkDefinitionImpl(override val path: String,
- override val url: String,
- override val lineSuffix: String?) : DokkaConfiguration.SourceLinkDefinition {
- companion object {
- fun parseSourceLinkDefinition(srcLink: String): DokkaConfiguration.SourceLinkDefinition {
- val (path, urlAndLine) = srcLink.split('=')
- return SourceLinkDefinitionImpl(
- File(path).canonicalPath,
- urlAndLine.substringBefore("#"),
- urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#$it" })
- }
- }
-}
-
-class SourceRootImpl(path: String) : DokkaConfiguration.SourceRoot {
- override val path: String = File(path).absolutePath
-
- companion object {
- fun parseSourceRoot(sourceRoot: String): DokkaConfiguration.SourceRoot = SourceRootImpl(sourceRoot)
- }
-}
-
-data class PackageOptionsImpl(override val prefix: String,
- override val includeNonPublic: Boolean = false,
- override val reportUndocumented: Boolean = true,
- override val skipDeprecated: Boolean = false,
- override val suppress: Boolean = false) : DokkaConfiguration.PackageOptions
-
- class DokkaConfigurationImpl(
- override val outputDir: String = "",
- override val format: String = "html",
- override val generateIndexPages: Boolean = false,
- override val cacheRoot: String? = null,
- override val impliedPlatforms: List<String> = emptyList(),
- override val passesConfigurations: List<DokkaConfiguration.PassConfiguration> = emptyList()
-) : DokkaConfiguration
-
-class PassConfigurationImpl (
- override val classpath: List<String> = emptyList(),
- override val moduleName: String = "",
- override val sourceRoots: List<DokkaConfiguration.SourceRoot> = emptyList(),
- override val samples: List<String> = emptyList(),
- override val includes: List<String> = emptyList(),
- override val includeNonPublic: Boolean = false,
- override val includeRootPackage: Boolean = false,
- override val reportUndocumented: Boolean = false,
- override val skipEmptyPackages: Boolean = false,
- override val skipDeprecated: Boolean = false,
- override val jdkVersion: Int = 6,
- override val sourceLinks: List<DokkaConfiguration.SourceLinkDefinition> = emptyList(),
- override val perPackageOptions: List<DokkaConfiguration.PackageOptions> = emptyList(),
- externalDocumentationLinks: List<DokkaConfiguration.ExternalDocumentationLink> = emptyList(),
- override val languageVersion: String? = null,
- override val apiVersion: String? = null,
- override val noStdlibLink: Boolean = false,
- override val noJdkLink: Boolean = false,
- override val suppressedFiles: List<String> = emptyList(),
- override val collectInheritedExtensionsFromLibraries: Boolean = false,
- override val analysisPlatform: Platform = Platform.DEFAULT,
- override val targets: List<String> = emptyList(),
- override val sinceKotlin: String? = null
-): DokkaConfiguration.PassConfiguration {
- private val defaultLinks = run {
- val links = mutableListOf<DokkaConfiguration.ExternalDocumentationLink>()
- if (!noJdkLink)
- links += DokkaConfiguration.ExternalDocumentationLink.Builder("https://docs.oracle.com/javase/$jdkVersion/docs/api/").build()
-
- if (!noStdlibLink)
- links += DokkaConfiguration.ExternalDocumentationLink.Builder("https://kotlinlang.org/api/latest/jvm/stdlib/").build()
- links
- }
- override val externalDocumentationLinks = defaultLinks + externalDocumentationLinks
-}
-
diff --git a/core/src/test/kotlin/NodeSelect.kt b/core/src/test/kotlin/NodeSelect.kt
deleted file mode 100644
index fe0394f9..00000000
--- a/core/src/test/kotlin/NodeSelect.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.DocumentationNode
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.RefKind
-
-class SelectBuilder {
- private val root = ChainFilterNode(SubgraphTraverseFilter(), null)
- private var activeNode = root
- private val chainEnds = mutableListOf<SelectFilter>()
-
- fun withName(name: String) = matching { it.name == name }
-
- fun withKind(kind: NodeKind) = matching{ it.kind == kind }
-
- fun matching(block: (DocumentationNode) -> Boolean) {
- attachFilterAndMakeActive(PredicateFilter(block))
- }
-
- fun subgraph() {
- attachFilterAndMakeActive(SubgraphTraverseFilter())
- }
-
- fun subgraphOf(kind: RefKind) {
- attachFilterAndMakeActive(DirectEdgeFilter(kind))
- }
-
- private fun attachFilterAndMakeActive(next: SelectFilter) {
- activeNode = ChainFilterNode(next, activeNode)
- }
-
- private fun endChain() {
- chainEnds += activeNode
- }
-
- fun build(): SelectFilter {
- endChain()
- return CombineFilterNode(chainEnds)
- }
-}
-
-private class ChainFilterNode(val filter: SelectFilter, val previous: SelectFilter?): SelectFilter() {
- override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
- return filter.select(previous?.select(roots) ?: roots)
- }
-}
-
-private class CombineFilterNode(val previous: List<SelectFilter>): SelectFilter() {
- override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
- return previous.asSequence().flatMap { it.select(roots) }
- }
-}
-
-abstract class SelectFilter {
- abstract fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode>
-}
-
-private class SubgraphTraverseFilter: SelectFilter() {
- override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
- val visited = mutableSetOf<DocumentationNode>()
- return roots.flatMap {
- generateSequence(listOf(it)) { nodes ->
- nodes.flatMap { it.allReferences() }
- .map { it.to }
- .filter { visited.add(it) }
- .takeUnless { it.isEmpty() }
- }
- }.flatten()
- }
-
-}
-
-private class PredicateFilter(val condition: (DocumentationNode) -> Boolean): SelectFilter() {
- override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
- return roots.filter(condition)
- }
-}
-
-private class DirectEdgeFilter(val kind: RefKind): SelectFilter() {
- override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
- return roots.flatMap { it.references(kind).asSequence() }.map { it.to }
- }
-}
-
-
-fun selectNodes(root: DocumentationNode, block: SelectBuilder.() -> Unit): List<DocumentationNode> {
- val builder = SelectBuilder()
- builder.apply(block)
- return builder.build().select(sequenceOf(root)).toMutableSet().toList()
-} \ No newline at end of file
diff --git a/core/src/test/kotlin/TestAPI.kt b/core/src/test/kotlin/TestAPI.kt
deleted file mode 100644
index 4f9af761..00000000
--- a/core/src/test/kotlin/TestAPI.kt
+++ /dev/null
@@ -1,353 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import com.google.inject.Guice
-import com.intellij.openapi.application.PathManager
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.util.io.FileUtil
-import com.intellij.rt.execution.junit.FileComparisonFailure
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Utilities.DokkaAnalysisModule
-import org.jetbrains.dokka.Utilities.DokkaRunModule
-import org.jetbrains.kotlin.cli.common.config.ContentRoot
-import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
-import org.jetbrains.kotlin.cli.common.messages.MessageCollector
-import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.utils.PathUtil
-import org.junit.Assert
-import org.junit.Assert.fail
-import java.io.File
-
-data class ModelConfig(
- val roots: Array<ContentRoot> = arrayOf(),
- val withJdk: Boolean = false,
- val withKotlinRuntime: Boolean = false,
- val format: String = "html",
- val includeNonPublic: Boolean = true,
- val perPackageOptions: List<DokkaConfiguration.PackageOptions> = emptyList(),
- val analysisPlatform: Platform = Platform.DEFAULT,
- val defaultPlatforms: List<String> = emptyList(),
- val noStdlibLink: Boolean = true,
- val collectInheritedExtensionsFromLibraries: Boolean = false,
- val sourceLinks: List<DokkaConfiguration.SourceLinkDefinition> = emptyList()
-)
-
-fun verifyModel(
- modelConfig: ModelConfig,
- verifier: (DocumentationModule) -> Unit
-) {
- val documentation = DocumentationModule("test")
-
- val passConfiguration = PassConfigurationImpl(
- includeNonPublic = modelConfig.includeNonPublic,
- skipEmptyPackages = false,
- includeRootPackage = true,
- sourceLinks = modelConfig.sourceLinks,
- perPackageOptions = modelConfig.perPackageOptions,
- noStdlibLink = modelConfig.noStdlibLink,
- noJdkLink = false,
- languageVersion = null,
- apiVersion = null,
- collectInheritedExtensionsFromLibraries = modelConfig.collectInheritedExtensionsFromLibraries
- )
- val configuration = DokkaConfigurationImpl(
- outputDir = "",
- format = modelConfig.format,
- generateIndexPages = false,
- cacheRoot = "default",
- passesConfigurations = listOf(passConfiguration)
- )
-
- appendDocumentation(documentation, configuration, passConfiguration, modelConfig)
- documentation.prepareForGeneration(configuration)
-
- verifier(documentation)
-}
-
-fun appendDocumentation(
- documentation: DocumentationModule,
- dokkaConfiguration: DokkaConfiguration,
- passConfiguration: DokkaConfiguration.PassConfiguration,
- modelConfig: ModelConfig
-) {
- val messageCollector = object : MessageCollector {
- override fun clear() {
-
- }
-
- override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
- when (severity) {
- CompilerMessageSeverity.STRONG_WARNING,
- CompilerMessageSeverity.WARNING,
- CompilerMessageSeverity.LOGGING,
- CompilerMessageSeverity.OUTPUT,
- CompilerMessageSeverity.INFO,
- CompilerMessageSeverity.ERROR -> {
- println("$severity: $message at $location")
- }
- CompilerMessageSeverity.EXCEPTION -> {
- fail("$severity: $message at $location")
- }
- }
- }
-
- override fun hasErrors() = false
- }
-
- val environment = AnalysisEnvironment(messageCollector, modelConfig.analysisPlatform)
- environment.apply {
- if (modelConfig.withJdk || modelConfig.withKotlinRuntime) {
- addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
- }
- if (modelConfig.withKotlinRuntime) {
- if (analysisPlatform == Platform.jvm) {
- val kotlinStrictfpRoot = PathManager.getResourceRoot(Strictfp::class.java, "/kotlin/jvm/Strictfp.class")
- addClasspath(File(kotlinStrictfpRoot))
- }
- if (analysisPlatform == Platform.js) {
- val kotlinStdlibJsRoot = PathManager.getResourceRoot(Any::class.java, "/kotlin/jquery")
- addClasspath(File(kotlinStdlibJsRoot))
- }
-
- if (analysisPlatform == Platform.common) {
- // TODO: Feels hacky
- val kotlinStdlibCommonRoot = ClassLoader.getSystemResource("kotlin/UInt.kotlin_metadata")
- addClasspath(File(kotlinStdlibCommonRoot.file.replace("file:", "").replaceAfter(".jar", "")))
- }
- }
- addRoots(modelConfig.roots.toList())
-
- loadLanguageVersionSettings(passConfiguration.languageVersion, passConfiguration.apiVersion)
- }
- val defaultPlatformsProvider = object : DefaultPlatformsProvider {
- override fun getDefaultPlatforms(descriptor: DeclarationDescriptor) = modelConfig.defaultPlatforms
- }
-
- val globalInjector = Guice.createInjector(
- DokkaRunModule(dokkaConfiguration)
- )
-
- val injector = globalInjector.createChildInjector(
- DokkaAnalysisModule(
- environment,
- dokkaConfiguration,
- defaultPlatformsProvider,
- documentation.nodeRefGraph,
- passConfiguration,
- DokkaConsoleLogger
- )
- )
-
- buildDocumentationModule(injector, documentation)
- Disposer.dispose(environment)
-}
-
-fun checkSourceExistsAndVerifyModel(
- source: String,
- modelConfig: ModelConfig = ModelConfig(),
- verifier: (DocumentationModule) -> Unit
-) {
- require(File(source).exists()) {
- "Cannot find test data file $source"
- }
- verifyModel(
- ModelConfig(
- roots = arrayOf(contentRootFromPath(source)),
- withJdk = modelConfig.withJdk,
- withKotlinRuntime = modelConfig.withKotlinRuntime,
- format = modelConfig.format,
- includeNonPublic = modelConfig.includeNonPublic,
- sourceLinks = modelConfig.sourceLinks,
- analysisPlatform = modelConfig.analysisPlatform
- ),
-
- verifier = verifier
- )
-}
-
-fun verifyPackageMember(
- source: String,
- modelConfig: ModelConfig = ModelConfig(),
- verifier: (DocumentationNode) -> Unit
-) {
- checkSourceExistsAndVerifyModel(
- source,
- modelConfig = ModelConfig(
- withJdk = modelConfig.withJdk,
- withKotlinRuntime = modelConfig.withKotlinRuntime,
- analysisPlatform = modelConfig.analysisPlatform
- )
- ) { model ->
- val pkg = model.members.single()
- verifier(pkg.members.single())
- }
-}
-
-fun verifyJavaModel(
- source: String,
- modelConfig: ModelConfig = ModelConfig(),
- verifier: (DocumentationModule) -> Unit
-) {
- val tempDir = FileUtil.createTempDirectory("dokka", "")
- try {
- val sourceFile = File(source)
- FileUtil.copy(sourceFile, File(tempDir, sourceFile.name))
- verifyModel(
- ModelConfig(
- roots = arrayOf(JavaSourceRoot(tempDir, null)),
- withJdk = true,
- withKotlinRuntime = modelConfig.withKotlinRuntime,
- analysisPlatform = modelConfig.analysisPlatform
- ),
- verifier = verifier
- )
- } finally {
- FileUtil.delete(tempDir)
- }
-}
-
-fun verifyJavaPackageMember(
- source: String,
- modelConfig: ModelConfig = ModelConfig(),
- verifier: (DocumentationNode) -> Unit
-) {
- verifyJavaModel(source, modelConfig) { model ->
- val pkg = model.members.single()
- verifier(pkg.members.single())
- }
-}
-
-fun verifyOutput(
- modelConfig: ModelConfig = ModelConfig(),
- outputExtension: String,
- outputGenerator: (DocumentationModule, StringBuilder) -> Unit
-) {
- verifyModel(modelConfig) {
- verifyModelOutput(it, outputExtension, modelConfig.roots.first().path, outputGenerator)
- }
-}
-
-fun verifyOutput(
- path: String,
- outputExtension: String,
- modelConfig: ModelConfig = ModelConfig(),
- outputGenerator: (DocumentationModule, StringBuilder) -> Unit
-) {
- verifyOutput(
- ModelConfig(
- roots = arrayOf(contentRootFromPath(path)) + modelConfig.roots,
- withJdk = modelConfig.withJdk,
- withKotlinRuntime = modelConfig.withKotlinRuntime,
- format = modelConfig.format,
- includeNonPublic = modelConfig.includeNonPublic,
- analysisPlatform = modelConfig.analysisPlatform,
- noStdlibLink = modelConfig.noStdlibLink,
- collectInheritedExtensionsFromLibraries = modelConfig.collectInheritedExtensionsFromLibraries
- ),
- outputExtension,
- outputGenerator
- )
-}
-
-fun verifyModelOutput(
- it: DocumentationModule,
- outputExtension: String,
- sourcePath: String,
- outputGenerator: (DocumentationModule, StringBuilder) -> Unit
-) {
- val output = StringBuilder()
- outputGenerator(it, output)
- val ext = outputExtension.removePrefix(".")
- val expectedFile = File(sourcePath.replaceAfterLast(".", ext, sourcePath + "." + ext))
- assertEqualsIgnoringSeparators(expectedFile, output.toString())
-}
-
-fun verifyJavaOutput(
- path: String,
- outputExtension: String,
- modelConfig: ModelConfig = ModelConfig(),
- outputGenerator: (DocumentationModule, StringBuilder) -> Unit
-) {
- verifyJavaModel(path, modelConfig) { model ->
- verifyModelOutput(model, outputExtension, path, outputGenerator)
- }
-}
-
-fun assertEqualsIgnoringSeparators(expectedFile: File, output: String) {
- if (!expectedFile.exists()) expectedFile.createNewFile()
- val expectedText = expectedFile.readText().replace("\r\n", "\n")
- val actualText = output.replace("\r\n", "\n")
-
- if (expectedText != actualText)
- throw FileComparisonFailure("", expectedText, actualText, expectedFile.canonicalPath)
-}
-
-fun assertEqualsIgnoringSeparators(expectedOutput: String, output: String) {
- Assert.assertEquals(expectedOutput.replace("\r\n", "\n"), output.replace("\r\n", "\n"))
-}
-
-fun StringBuilder.appendChildren(node: ContentBlock): StringBuilder {
- for (child in node.children) {
- val childText = child.toTestString()
- append(childText)
- }
- return this
-}
-
-fun StringBuilder.appendNode(node: ContentNode): StringBuilder {
- when (node) {
- is ContentText -> {
- append(node.text)
- }
- is ContentEmphasis -> append("*").appendChildren(node).append("*")
- is ContentBlockCode -> {
- if (node.language.isNotBlank())
- appendln("[code lang=${node.language}]")
- else
- appendln("[code]")
- appendChildren(node)
- appendln()
- appendln("[/code]")
- }
- is ContentNodeLink -> {
- append("[")
- appendChildren(node)
- append(" -> ")
- append(node.node.toString())
- append("]")
- }
- is ContentBlock -> {
- appendChildren(node)
- }
- is NodeRenderContent -> {
- append("render(")
- append(node.node)
- append(",")
- append(node.mode)
- append(")")
- }
- is ContentSymbol -> {
- append(node.text)
- }
- is ContentEmpty -> { /* nothing */
- }
- else -> throw IllegalStateException("Don't know how to format node $node")
- }
- return this
-}
-
-fun ContentNode.toTestString(): String {
- val node = this
- return StringBuilder().apply {
- appendNode(node)
- }.toString()
-}
-
-val ContentRoot.path: String
- get() = when (this) {
- is KotlinSourceRoot -> path
- is JavaSourceRoot -> file.path
- else -> throw UnsupportedOperationException()
- }
diff --git a/core/src/test/kotlin/format/FileGeneratorTestCase.kt b/core/src/test/kotlin/format/FileGeneratorTestCase.kt
deleted file mode 100644
index ef9e815d..00000000
--- a/core/src/test/kotlin/format/FileGeneratorTestCase.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.*
-import org.junit.Before
-import org.junit.Rule
-import org.junit.rules.TemporaryFolder
-
-
-abstract class FileGeneratorTestCase {
- abstract val formatService: FormatService
-
- @get:Rule
- var folder = TemporaryFolder()
-
- val fileGenerator = FileGenerator(folder.apply { create() }.root)
-
- @Before
- fun bindGenerator() {
- fileGenerator.formatService = formatService
- }
-
- fun buildPagesAndReadInto(nodes: List<DocumentationNode>, sb: StringBuilder) = with(fileGenerator) {
- buildPages(nodes)
- val byLocations = nodes.groupBy { location(it) }
- byLocations.forEach { (loc, _) ->
- if (byLocations.size > 1) {
- if (sb.isNotBlank() && !sb.endsWith('\n')) {
- sb.appendln()
- }
- sb.appendln("<!-- File: ${loc.file.relativeTo(root).toUnixString()} -->")
- }
- sb.append(loc.file.readText())
- }
- }
-} \ No newline at end of file
diff --git a/core/src/test/kotlin/format/GFMFormatTest.kt b/core/src/test/kotlin/format/GFMFormatTest.kt
deleted file mode 100644
index 60de7d29..00000000
--- a/core/src/test/kotlin/format/GFMFormatTest.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.GFMFormatService
-import org.jetbrains.dokka.KotlinLanguageService
-import org.jetbrains.dokka.Platform
-import org.junit.Test
-
-abstract class BaseGFMFormatTest(val analysisPlatform: Platform) : FileGeneratorTestCase() {
- override val formatService = GFMFormatService(fileGenerator, KotlinLanguageService(), listOf())
- private val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
-
-
- @Test
- fun sample() {
- verifyGFMNodeByName("sample", "Foo", defaultModelConfig)
- }
-
- @Test
- fun listInTableCell() {
- verifyGFMNodeByName("listInTableCell", "Foo", defaultModelConfig)
- }
-
- private fun verifyGFMNodeByName(fileName: String, name: String, modelConfig: ModelConfig) {
- verifyOutput("testdata/format/gfm/$fileName.kt", ".md", modelConfig) { model, output ->
- buildPagesAndReadInto(
- model.members.single().members.filter { it.name == name },
- output
- )
- }
- }
-}
-
-
-class JsGFMFormatTest : BaseGFMFormatTest(Platform.js)
-class JvmGFMFormatTest : BaseGFMFormatTest(Platform.jvm)
-class CommonGFMFormatTest : BaseGFMFormatTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/format/HtmlFormatTest.kt b/core/src/test/kotlin/format/HtmlFormatTest.kt
deleted file mode 100644
index 60e29006..00000000
--- a/core/src/test/kotlin/format/HtmlFormatTest.kt
+++ /dev/null
@@ -1,192 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.*
-import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
-import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
-import org.junit.Test
-import java.io.File
-
-abstract class BaseHtmlFormatTest(val analysisPlatform: Platform): FileGeneratorTestCase() {
- protected val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
- override val formatService = HtmlFormatService(fileGenerator, KotlinLanguageService(), HtmlTemplateService.default(), listOf())
-
- @Test fun classWithCompanionObject() {
- verifyHtmlNode("classWithCompanionObject", defaultModelConfig)
- }
-
- @Test fun htmlEscaping() {
- verifyHtmlNode("htmlEscaping", defaultModelConfig)
- }
-
- @Test fun overloads() {
- verifyHtmlNodes("overloads", defaultModelConfig) { model -> model.members }
- }
-
- @Test fun overloadsWithDescription() {
- verifyHtmlNode("overloadsWithDescription", defaultModelConfig)
- }
-
- @Test fun overloadsWithDifferentDescriptions() {
- verifyHtmlNode("overloadsWithDifferentDescriptions", defaultModelConfig)
- }
-
- @Test fun deprecated() {
- verifyOutput("testdata/format/deprecated.kt", ".package.html", defaultModelConfig) { model, output ->
- buildPagesAndReadInto(model.members, output)
- }
- verifyOutput("testdata/format/deprecated.kt", ".class.html", defaultModelConfig) { model, output ->
- buildPagesAndReadInto(model.members.single().members, output)
- }
- }
-
- @Test fun brokenLink() {
- verifyHtmlNode("brokenLink", defaultModelConfig)
- }
-
- @Test fun codeSpan() {
- verifyHtmlNode("codeSpan", defaultModelConfig)
- }
-
- @Test fun parenthesis() {
- verifyHtmlNode("parenthesis", defaultModelConfig)
- }
-
- @Test fun bracket() {
- verifyHtmlNode("bracket", defaultModelConfig)
- }
-
- @Test fun see() {
- verifyHtmlNode("see", defaultModelConfig)
- }
-
- @Test fun tripleBackticks() {
- verifyHtmlNode("tripleBackticks", defaultModelConfig)
- }
-
- @Test fun typeLink() {
- verifyHtmlNodes("typeLink", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Bar" } }
- }
-
- @Test fun parameterAnchor() {
- verifyHtmlNode("parameterAnchor", defaultModelConfig)
- }
-
- @Test fun codeBlock() {
- verifyHtmlNode("codeBlock", defaultModelConfig)
- }
- @Test fun orderedList() {
- verifyHtmlNodes("orderedList", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Bar" } }
- }
-
- @Test fun linkWithLabel() {
- verifyHtmlNodes("linkWithLabel", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Bar" } }
- }
-
- @Test fun entity() {
- verifyHtmlNodes("entity", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Bar" } }
- }
-
- @Test fun uninterpretedEmphasisCharacters() {
- verifyHtmlNode("uninterpretedEmphasisCharacters", defaultModelConfig)
- }
-
- @Test fun markdownInLinks() {
- verifyHtmlNode("markdownInLinks", defaultModelConfig)
- }
-
- @Test fun returnWithLink() {
- verifyHtmlNode("returnWithLink", defaultModelConfig)
- }
-
- @Test fun linkWithStarProjection() {
- verifyHtmlNode("linkWithStarProjection", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun functionalTypeWithNamedParameters() {
- verifyHtmlNode("functionalTypeWithNamedParameters", defaultModelConfig)
- }
-
- @Test fun sinceKotlin() {
- verifyHtmlNode("sinceKotlin", defaultModelConfig)
- }
-
- @Test fun blankLineInsideCodeBlock() {
- verifyHtmlNode("blankLineInsideCodeBlock", defaultModelConfig)
- }
-
- @Test fun indentedCodeBlock() {
- verifyHtmlNode("indentedCodeBlock", defaultModelConfig)
- }
-
- private fun verifyHtmlNode(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
- verifyHtmlNodes(fileName, modelConfig) { model -> model.members.single().members }
- }
-
- private fun verifyHtmlNodes(fileName: String,
- modelConfig: ModelConfig = ModelConfig(),
- nodeFilter: (DocumentationModule) -> List<DocumentationNode>) {
- verifyOutput("testdata/format/$fileName.kt", ".html", modelConfig) { model, output ->
- buildPagesAndReadInto(nodeFilter(model), output)
- }
- }
-
- protected fun verifyJavaHtmlNode(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
- verifyJavaHtmlNodes(fileName, modelConfig) { model -> model.members.single().members }
- }
-
- protected fun verifyJavaHtmlNodes(fileName: String,
- modelConfig: ModelConfig = ModelConfig(),
- nodeFilter: (DocumentationModule) -> List<DocumentationNode>) {
- verifyJavaOutput("testdata/format/$fileName.java", ".html", modelConfig) { model, output ->
- buildPagesAndReadInto(nodeFilter(model), output)
- }
- }
-}
-
-class JSHtmlFormatTest: BaseHtmlFormatTest(Platform.js)
-
-class JVMHtmlFormatTest: BaseHtmlFormatTest(Platform.jvm) {
- @Test
- fun javaSeeTag() {
- verifyJavaHtmlNode("javaSeeTag", defaultModelConfig)
- }
-
- @Test fun javaDeprecated() {
- verifyJavaHtmlNodes("javaDeprecated", defaultModelConfig) { model ->
- model.members.single().members.single { it.name == "Foo" }.members.filter { it.name == "foo" }
- }
- }
-
- @Test fun crossLanguageKotlinExtendsJava() {
- verifyOutput(
- ModelConfig(
- roots = arrayOf(
- KotlinSourceRoot("testdata/format/crossLanguage/kotlinExtendsJava/Bar.kt", false),
- JavaSourceRoot(File("testdata/format/crossLanguage/kotlinExtendsJava"), null)
- ),
- analysisPlatform = analysisPlatform
- ), ".html") { model, output ->
- buildPagesAndReadInto(
- model.members.single().members.filter { it.name == "Bar" },
- output
- )
- }
- }
-
- @Test fun javaLinkTag() {
- verifyJavaHtmlNode("javaLinkTag", defaultModelConfig)
- }
-
- @Test fun javaLinkTagWithLabel() {
- verifyJavaHtmlNode("javaLinkTagWithLabel", defaultModelConfig)
- }
-
- @Test fun javaSupertypeLink() {
- verifyJavaHtmlNodes("JavaSupertype", defaultModelConfig) { model ->
- model.members.single().members.single { it.name == "JavaSupertype" }.members.filter { it.name == "Bar" }
- }
- }
-
-}
-
-class CommonHtmlFormatTest: BaseHtmlFormatTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt b/core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt
deleted file mode 100644
index ebab5f36..00000000
--- a/core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt
+++ /dev/null
@@ -1,123 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Generation.DocumentationMerger
-import org.junit.Test
-
-abstract class BaseKotlinWebSiteHtmlFormatTest(val analysisPlatform: Platform): FileGeneratorTestCase() {
- val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
- override val formatService = KotlinWebsiteHtmlFormatService(fileGenerator, KotlinLanguageService(), listOf(), EmptyHtmlTemplateService)
-
- @Test fun dropImport() {
- verifyKWSNodeByName("dropImport", "foo", defaultModelConfig)
- }
-
- @Test fun sample() {
- verifyKWSNodeByName("sample", "foo", defaultModelConfig)
- }
-
- @Test fun sampleWithAsserts() {
- verifyKWSNodeByName("sampleWithAsserts", "a", defaultModelConfig)
- }
-
- @Test fun newLinesInSamples() {
- verifyKWSNodeByName("newLinesInSamples", "foo", defaultModelConfig)
- }
-
- @Test fun newLinesInImportList() {
- verifyKWSNodeByName("newLinesInImportList", "foo", defaultModelConfig)
- }
-
- @Test fun returnTag() {
- verifyKWSNodeByName("returnTag", "indexOf", defaultModelConfig)
- }
-
- @Test fun overloadGroup() {
- verifyKWSNodeByName("overloadGroup", "magic", defaultModelConfig)
- }
-
- @Test fun dataTags() {
- val module = buildMultiplePlatforms("dataTags")
- verifyMultiplatformPackage(module, "dataTags")
- }
-
- @Test fun dataTagsInGroupNode() {
- val path = "dataTagsInGroupNode"
- val module = buildMultiplePlatforms(path)
- verifyModelOutput(module, ".html", "testdata/format/website-html/$path/multiplatform.kt") { model, output ->
- buildPagesAndReadInto(
- listOfNotNull(model.members.single().members.find { it.kind == NodeKind.GroupNode }),
- output
- )
- }
- verifyMultiplatformPackage(module, path)
- }
-
- private fun verifyKWSNodeByName(fileName: String, name: String, modelConfig: ModelConfig) {
- verifyOutput(
- "testdata/format/website-html/$fileName.kt",
- ".html",
- ModelConfig(analysisPlatform = modelConfig.analysisPlatform, format = "kotlin-website-html")
- ) { model, output ->
- buildPagesAndReadInto(model.members.single().members.filter { it.name == name }, output)
- }
- }
-
- private fun buildMultiplePlatforms(path: String): DocumentationModule {
- val moduleName = "test"
- val passConfiguration = PassConfigurationImpl(
- noStdlibLink = true,
- noJdkLink = true,
- languageVersion = null,
- apiVersion = null
- )
-
- val dokkaConfiguration = DokkaConfigurationImpl(
- outputDir = "",
- format = "kotlin-website-html",
- generateIndexPages = false,
- passesConfigurations = listOf(
- passConfiguration
- )
-
- )
-
- val module1 = DocumentationModule(moduleName)
- appendDocumentation(
- module1, dokkaConfiguration, passConfiguration, ModelConfig(
- roots = arrayOf(contentRootFromPath("testdata/format/website-html/$path/jvm.kt")),
- defaultPlatforms = listOf("JVM")
- )
- )
-
- val module2 = DocumentationModule(moduleName)
- appendDocumentation(
- module2, dokkaConfiguration, passConfiguration, ModelConfig(
- roots = arrayOf(contentRootFromPath("testdata/format/website-html/$path/jre7.kt")),
- defaultPlatforms = listOf("JVM", "JRE7")
- )
- )
-
- val module3 = DocumentationModule(moduleName)
- appendDocumentation(
- module3, dokkaConfiguration, passConfiguration, ModelConfig(
- roots = arrayOf(contentRootFromPath("testdata/format/website-html/$path/js.kt")),
- defaultPlatforms = listOf("JS")
- )
- )
-
- return DocumentationMerger(listOf(module1, module2, module3), DokkaConsoleLogger).merge()
- }
-
- private fun verifyMultiplatformPackage(module: DocumentationModule, path: String) {
- verifyModelOutput(module, ".package.html", "testdata/format/website-html/$path/multiplatform.kt") { model, output ->
- buildPagesAndReadInto(model.members, output)
- }
- }
-
-}
-class JsKotlinWebSiteHtmlFormatTest: BaseKotlinWebSiteHtmlFormatTest(Platform.js)
-
-class JvmKotlinWebSiteHtmlFormatTest: BaseKotlinWebSiteHtmlFormatTest(Platform.jvm)
-
-class CommonKotlinWebSiteHtmlFormatTest: BaseKotlinWebSiteHtmlFormatTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/format/MarkdownFormatTest.kt b/core/src/test/kotlin/format/MarkdownFormatTest.kt
deleted file mode 100644
index 4984e1d5..00000000
--- a/core/src/test/kotlin/format/MarkdownFormatTest.kt
+++ /dev/null
@@ -1,615 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Generation.DocumentationMerger
-import org.junit.Test
-
-abstract class BaseMarkdownFormatTest(val analysisPlatform: Platform): FileGeneratorTestCase() {
- override val formatService = MarkdownFormatService(fileGenerator, KotlinLanguageService(), listOf())
-
- protected val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
-
- @Test fun emptyDescription() {
- verifyMarkdownNode("emptyDescription", defaultModelConfig)
- }
-
- @Test fun classWithCompanionObject() {
- verifyMarkdownNode("classWithCompanionObject", defaultModelConfig)
- }
-
- @Test fun annotations() {
- verifyMarkdownNode("annotations", defaultModelConfig)
- }
-
- @Test fun annotationClass() {
- verifyMarkdownNode("annotationClass", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- verifyMarkdownPackage("annotationClass", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun enumClass() {
- verifyOutput("testdata/format/enumClass.kt", ".md", defaultModelConfig) { model, output ->
- buildPagesAndReadInto(model.members.single().members, output)
- }
- verifyOutput("testdata/format/enumClass.kt", ".value.md", defaultModelConfig) { model, output ->
- val enumClassNode = model.members.single().members[0]
- buildPagesAndReadInto(
- enumClassNode.members.filter { it.name == "LOCAL_CONTINUE_AND_BREAK" },
- output
- )
- }
- }
-
- @Test fun varargsFunction() {
- verifyMarkdownNode("varargsFunction", defaultModelConfig)
- }
-
- @Test fun overridingFunction() {
- verifyMarkdownNodes("overridingFunction", defaultModelConfig) { model->
- val classMembers = model.members.single().members.first { it.name == "D" }.members
- classMembers.filter { it.name == "f" }
- }
- }
-
- @Test fun propertyVar() {
- verifyMarkdownNode("propertyVar", defaultModelConfig)
- }
-
- @Test fun functionWithDefaultParameter() {
- verifyMarkdownNode("functionWithDefaultParameter", defaultModelConfig)
- }
-
- @Test fun accessor() {
- verifyMarkdownNodes("accessor", defaultModelConfig) { model ->
- model.members.single().members.first { it.name == "C" }.members.filter { it.name == "x" }
- }
- }
-
- @Test fun paramTag() {
- verifyMarkdownNode("paramTag", defaultModelConfig)
- }
-
- @Test fun throwsTag() {
- verifyMarkdownNode("throwsTag", defaultModelConfig)
- }
-
- @Test fun typeParameterBounds() {
- verifyMarkdownNode("typeParameterBounds", defaultModelConfig)
- }
-
- @Test fun typeParameterVariance() {
- verifyMarkdownNode("typeParameterVariance", defaultModelConfig)
- }
-
- @Test fun typeProjectionVariance() {
- verifyMarkdownNode("typeProjectionVariance", defaultModelConfig)
- }
-
- @Test fun codeBlockNoHtmlEscape() {
- verifyMarkdownNodeByName("codeBlockNoHtmlEscape", "hackTheArithmetic", defaultModelConfig)
- }
-
- @Test fun companionObjectExtension() {
- verifyMarkdownNodeByName("companionObjectExtension", "Foo", defaultModelConfig)
- }
-
- @Test fun starProjection() {
- verifyMarkdownNode("starProjection", defaultModelConfig)
- }
-
- @Test fun extensionFunctionParameter() {
- verifyMarkdownNode("extensionFunctionParameter", defaultModelConfig)
- }
-
- @Test fun summarizeSignatures() {
- verifyMarkdownNodes("summarizeSignatures", defaultModelConfig) { model -> model.members }
- }
-
- @Test fun reifiedTypeParameter() {
- verifyMarkdownNode("reifiedTypeParameter", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun suspendInlineFunctionOrder() {
- verifyMarkdownNode("suspendInlineFunction", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun inlineSuspendFunctionOrderChanged() {
- verifyMarkdownNode("inlineSuspendFunction", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun annotatedTypeParameter() {
- verifyMarkdownNode("annotatedTypeParameter", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun inheritedMembers() {
- verifyMarkdownNodeByName("inheritedMembers", "Bar", defaultModelConfig)
- }
-
- @Test fun inheritedExtensions() {
- verifyMarkdownNodeByName("inheritedExtensions", "Bar", defaultModelConfig)
- }
-
- @Test fun genericInheritedExtensions() {
- verifyMarkdownNodeByName("genericInheritedExtensions", "Bar", defaultModelConfig)
- }
-
- @Test fun arrayAverage() {
- verifyMarkdownNodeByName("arrayAverage", "XArray", defaultModelConfig)
- }
-
- @Test fun multipleTypeParameterConstraints() {
- verifyMarkdownNode("multipleTypeParameterConstraints", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun inheritedCompanionObjectProperties() {
- verifyMarkdownNodeByName("inheritedCompanionObjectProperties", "C", defaultModelConfig)
- }
-
- @Test fun shadowedExtensionFunctions() {
- verifyMarkdownNodeByName("shadowedExtensionFunctions", "Bar", defaultModelConfig)
- }
-
- @Test fun inapplicableExtensionFunctions() {
- verifyMarkdownNodeByName("inapplicableExtensionFunctions", "Bar", defaultModelConfig)
- }
-
- @Test fun receiverParameterTypeBound() {
- verifyMarkdownNodeByName("receiverParameterTypeBound", "Foo", defaultModelConfig)
- }
-
- @Test fun extensionWithDocumentedReceiver() {
- verifyMarkdownNodes("extensionWithDocumentedReceiver", defaultModelConfig) { model ->
- model.members.single().members.single().members.filter { it.name == "fn" }
- }
- }
-
- @Test fun codeBlock() {
- verifyMarkdownNode("codeBlock", defaultModelConfig)
- }
-
- @Test fun exclInCodeBlock() {
- verifyMarkdownNodeByName("exclInCodeBlock", "foo", defaultModelConfig)
- }
-
- @Test fun backtickInCodeBlock() {
- verifyMarkdownNodeByName("backtickInCodeBlock", "foo", defaultModelConfig)
- }
-
- @Test fun qualifiedNameLink() {
- verifyMarkdownNodeByName("qualifiedNameLink", "foo",
- ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun functionalTypeWithNamedParameters() {
- verifyMarkdownNode("functionalTypeWithNamedParameters", defaultModelConfig)
- }
-
- @Test fun typeAliases() {
- verifyMarkdownNode("typeAliases", defaultModelConfig)
- verifyMarkdownPackage("typeAliases", defaultModelConfig)
- }
-
- @Test fun sampleByShortName() {
- verifyMarkdownNode("sampleByShortName", defaultModelConfig)
- }
-
-
- @Test fun suspendParam() {
- verifyMarkdownNode("suspendParam", defaultModelConfig)
- verifyMarkdownPackage("suspendParam", defaultModelConfig)
- }
-
- @Test fun sinceKotlin() {
- verifyMarkdownNode("sinceKotlin", defaultModelConfig)
- verifyMarkdownPackage("sinceKotlin", defaultModelConfig)
- }
-
- @Test fun sinceKotlinWide() {
- verifyMarkdownPackage("sinceKotlinWide", defaultModelConfig)
- }
-
- @Test fun dynamicType() {
- verifyMarkdownNode("dynamicType", defaultModelConfig)
- }
-
- @Test fun dynamicExtension() {
- verifyMarkdownNodes("dynamicExtension", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Foo" } }
- }
-
- @Test fun memberExtension() {
- verifyMarkdownNodes("memberExtension", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Foo" } }
- }
-
- @Test fun renderFunctionalTypeInParenthesisWhenItIsReceiver() {
- verifyMarkdownNode("renderFunctionalTypeInParenthesisWhenItIsReceiver", defaultModelConfig)
- }
-
- @Test fun multiplePlatforms() {
- verifyMultiplatformPackage(buildMultiplePlatforms("multiplatform/simple"), "multiplatform/simple")
- }
-
- @Test fun multiplePlatformsMerge() {
- verifyMultiplatformPackage(buildMultiplePlatforms("multiplatform/merge"), "multiplatform/merge")
- }
-
- @Test fun multiplePlatformsMergeMembers() {
- val module = buildMultiplePlatforms("multiplatform/mergeMembers")
- verifyModelOutput(module, ".md", "testdata/format/multiplatform/mergeMembers/foo.kt") { model, output ->
- buildPagesAndReadInto(model.members.single().members, output)
- }
- }
-
- @Test fun multiplePlatformsOmitRedundant() {
- val module = buildMultiplePlatforms("multiplatform/omitRedundant")
- verifyModelOutput(module, ".md", "testdata/format/multiplatform/omitRedundant/foo.kt") { model, output ->
- buildPagesAndReadInto(model.members.single().members, output)
- }
- }
-
- @Test fun multiplePlatformsImplied() {
- val module = buildMultiplePlatforms("multiplatform/implied")
- verifyModelOutput(module, ".md", "testdata/format/multiplatform/implied/foo.kt") { model, output ->
- val service = MarkdownFormatService(fileGenerator, KotlinLanguageService(), listOf("JVM", "JS"))
- fileGenerator.formatService = service
- buildPagesAndReadInto(model.members.single().members, output)
- }
- }
-
- @Test fun packagePlatformsWithExtExtensions() {
- val path = "multiplatform/packagePlatformsWithExtExtensions"
- val module = DocumentationModule("test")
- val passConfiguration = PassConfigurationImpl(
- noStdlibLink = true,
- noJdkLink = true,
- languageVersion = null,
- apiVersion = null
- )
-
- val dokkaConfiguration = DokkaConfigurationImpl(
- outputDir = "",
- format = "html",
- generateIndexPages = false,
- passesConfigurations = listOf(
- passConfiguration
- )
- )
-
- appendDocumentation(module, dokkaConfiguration, passConfiguration, ModelConfig(
- roots = arrayOf(contentRootFromPath("testdata/format/$path/jvm.kt")),
- defaultPlatforms = listOf("JVM"),
- withKotlinRuntime = true,
- analysisPlatform = analysisPlatform
- )
- )
- verifyMultiplatformIndex(module, path)
- verifyMultiplatformPackage(module, path)
- }
-
- @Test fun multiplePlatformsPackagePlatformFromMembers() {
- val path = "multiplatform/packagePlatformsFromMembers"
- val module = buildMultiplePlatforms(path)
- verifyMultiplatformIndex(module, path)
- verifyMultiplatformPackage(module, path)
- }
-
- @Test fun multiplePlatformsGroupNode() {
- val path = "multiplatform/groupNode"
- val module = buildMultiplePlatforms(path)
- verifyModelOutput(module, ".md", "testdata/format/$path/multiplatform.kt") { model, output ->
- buildPagesAndReadInto(
- listOfNotNull(model.members.single().members.find { it.kind == NodeKind.GroupNode }),
- output
- )
- }
- verifyMultiplatformPackage(module, path)
- }
-
- @Test fun multiplePlatformsBreadcrumbsInMemberOfMemberOfGroupNode() {
- val path = "multiplatform/breadcrumbsInMemberOfMemberOfGroupNode"
- val module = buildMultiplePlatforms(path)
- verifyModelOutput(module, ".md", "testdata/format/$path/multiplatform.kt") { model, output ->
- buildPagesAndReadInto(
- listOfNotNull(model.members.single().members.find { it.kind == NodeKind.GroupNode }?.member(NodeKind.Function)),
- output
- )
- }
- }
-
- @Test fun linksInEmphasis() {
- verifyMarkdownNode("linksInEmphasis", defaultModelConfig)
- }
-
- @Test fun linksInStrong() {
- verifyMarkdownNode("linksInStrong", defaultModelConfig)
- }
-
- @Test fun linksInHeaders() {
- verifyMarkdownNode("linksInHeaders", defaultModelConfig)
- }
-
- @Test fun tokensInEmphasis() {
- verifyMarkdownNode("tokensInEmphasis", defaultModelConfig)
- }
-
- @Test fun tokensInStrong() {
- verifyMarkdownNode("tokensInStrong", defaultModelConfig)
- }
-
- @Test fun tokensInHeaders() {
- verifyMarkdownNode("tokensInHeaders", defaultModelConfig)
- }
-
- @Test fun unorderedLists() {
- verifyMarkdownNode("unorderedLists", defaultModelConfig)
- }
-
- @Test fun nestedLists() {
- verifyMarkdownNode("nestedLists", defaultModelConfig)
- }
-
- @Test fun referenceLink() {
- verifyMarkdownNode("referenceLink", defaultModelConfig)
- }
-
- @Test fun externalReferenceLink() {
- verifyMarkdownNode("externalReferenceLink", defaultModelConfig)
- }
-
- @Test fun newlineInTableCell() {
- verifyMarkdownPackage("newlineInTableCell", defaultModelConfig)
- }
-
- @Test fun indentedCodeBlock() {
- verifyMarkdownNode("indentedCodeBlock", defaultModelConfig)
- }
-
- @Test fun receiverReference() {
- verifyMarkdownNode("receiverReference", defaultModelConfig)
- }
-
- @Test fun extensionScope() {
- verifyMarkdownNodeByName("extensionScope", "test", defaultModelConfig)
- }
-
- @Test fun typeParameterReference() {
- verifyMarkdownNode("typeParameterReference", defaultModelConfig)
- }
-
- @Test fun notPublishedTypeAliasAutoExpansion() {
- verifyMarkdownNodeByName("notPublishedTypeAliasAutoExpansion", "foo", ModelConfig(
- analysisPlatform = analysisPlatform,
- includeNonPublic = false
- ))
- }
-
- @Test fun companionImplements() {
- verifyMarkdownNodeByName("companionImplements", "Foo", defaultModelConfig)
- }
-
-
- private fun buildMultiplePlatforms(path: String): DocumentationModule {
- val moduleName = "test"
- val passConfiguration = PassConfigurationImpl(
- noStdlibLink = true,
- noJdkLink = true,
- languageVersion = null,
- apiVersion = null
- )
- val dokkaConfiguration = DokkaConfigurationImpl(
- outputDir = "",
- format = "html",
- generateIndexPages = false,
- passesConfigurations = listOf(
- passConfiguration
- )
-
- )
- val module1 = DocumentationModule(moduleName)
- appendDocumentation(
- module1, dokkaConfiguration, passConfiguration, ModelConfig(
- roots = arrayOf(contentRootFromPath("testdata/format/$path/jvm.kt")),
- defaultPlatforms = listOf("JVM"),
- analysisPlatform = Platform.jvm
- )
- )
-
- val module2 = DocumentationModule(moduleName)
- appendDocumentation(
- module2, dokkaConfiguration, passConfiguration, ModelConfig(
- roots = arrayOf(contentRootFromPath("testdata/format/$path/js.kt")),
- defaultPlatforms = listOf("JS"),
- analysisPlatform = Platform.js
- )
- )
-
- return DocumentationMerger(listOf(module1, module2), DokkaConsoleLogger).merge()
- }
-
- private fun verifyMultiplatformPackage(module: DocumentationModule, path: String) {
- verifyModelOutput(module, ".package.md", "testdata/format/$path/multiplatform.kt") { model, output ->
- buildPagesAndReadInto(model.members, output)
- }
- }
-
- private fun verifyMultiplatformIndex(module: DocumentationModule, path: String) {
- verifyModelOutput(module, ".md", "testdata/format/$path/multiplatform.index.kt") {
- model, output ->
- val service = MarkdownFormatService(fileGenerator, KotlinLanguageService(), listOf())
- fileGenerator.formatService = service
- buildPagesAndReadInto(listOf(model), output)
- }
- }
-
- @Test fun blankLineInsideCodeBlock() {
- verifyMarkdownNode("blankLineInsideCodeBlock", defaultModelConfig)
- }
-
- protected fun verifyMarkdownPackage(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
- verifyOutput("testdata/format/$fileName.kt", ".package.md", modelConfig) { model, output ->
- buildPagesAndReadInto(model.members, output)
- }
- }
-
- protected fun verifyMarkdownNode(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
- verifyMarkdownNodes(fileName, modelConfig) { model -> model.members.single().members }
- }
-
- protected fun verifyMarkdownNodes(
- fileName: String,
- modelConfig: ModelConfig = ModelConfig(),
- nodeFilter: (DocumentationModule) -> List<DocumentationNode>
- ) {
- verifyOutput(
- "testdata/format/$fileName.kt",
- ".md",
- modelConfig
- ) { model, output ->
- buildPagesAndReadInto(nodeFilter(model), output)
- }
- }
-
- protected fun verifyJavaMarkdownNode(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
- verifyJavaMarkdownNodes(fileName, modelConfig) { model -> model.members.single().members }
- }
-
- protected fun verifyJavaMarkdownNodes(fileName: String, modelConfig: ModelConfig = ModelConfig(), nodeFilter: (DocumentationModule) -> List<DocumentationNode>) {
- verifyJavaOutput("testdata/format/$fileName.java", ".md", modelConfig) { model, output ->
- buildPagesAndReadInto(nodeFilter(model), output)
- }
- }
-
- protected fun verifyMarkdownNodeByName(
- fileName: String,
- name: String,
- modelConfig: ModelConfig = ModelConfig()
- ) {
- verifyMarkdownNodes(fileName, modelConfig) { model->
- val nodesWithName = model.members.single().members.filter { it.name == name }
- if (nodesWithName.isEmpty()) {
- throw IllegalArgumentException("Found no nodes named $name")
- }
- nodesWithName
- }
- }
-
- @Test fun nullableTypeParameterFunction() {
- verifyMarkdownNode("nullableTypeParameterFunction", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-}
-
-class JSMarkdownFormatTest: BaseMarkdownFormatTest(Platform.js)
-
-class JVMMarkdownFormatTest: BaseMarkdownFormatTest(Platform.jvm) {
-
- @Test
- fun enumRef() {
- verifyMarkdownNode("enumRef", defaultModelConfig)
- }
-
- @Test
- fun javaCodeLiteralTags() {
- verifyJavaMarkdownNode("javaCodeLiteralTags", defaultModelConfig)
- }
-
- @Test
- fun nullability() {
- verifyMarkdownNode("nullability", defaultModelConfig)
- }
-
- @Test
- fun exceptionClass() {
- verifyMarkdownNode(
- "exceptionClass", ModelConfig(
- analysisPlatform = analysisPlatform,
- withKotlinRuntime = true
- )
- )
- verifyMarkdownPackage(
- "exceptionClass", ModelConfig(
- analysisPlatform = analysisPlatform,
- withKotlinRuntime = true
- )
- )
- }
-
- @Test
- fun operatorOverloading() {
- verifyMarkdownNodes("operatorOverloading", defaultModelConfig) { model->
- model.members.single().members.single { it.name == "C" }.members.filter { it.name == "plus" }
- }
- }
-
- @Test
- fun extensions() {
- verifyOutput("testdata/format/extensions.kt", ".package.md", defaultModelConfig) { model, output ->
- buildPagesAndReadInto(model.members, output)
- }
- verifyOutput("testdata/format/extensions.kt", ".class.md", defaultModelConfig) { model, output ->
- buildPagesAndReadInto(model.members.single().members, output)
- }
- }
-
- @Test
- fun summarizeSignaturesProperty() {
- verifyMarkdownNodes("summarizeSignaturesProperty", defaultModelConfig) { model -> model.members }
- }
-
- @Test
- fun javaSpaceInAuthor() {
- verifyJavaMarkdownNode("javaSpaceInAuthor", defaultModelConfig)
- }
-
- @Test
- fun javaCodeInParam() {
- verifyJavaMarkdownNodes("javaCodeInParam", defaultModelConfig) {
- selectNodes(it) {
- subgraphOf(RefKind.Member)
- withKind(NodeKind.Function)
- }
- }
- }
-
- @Test
- fun annotationParams() {
- verifyMarkdownNode("annotationParams", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
- }
-
- @Test fun inheritedLink() {
- val filePath = "testdata/format/inheritedLink"
- verifyOutput(
- filePath,
- ".md",
- ModelConfig(
- roots = arrayOf(
- contentRootFromPath("$filePath.kt"),
- contentRootFromPath("$filePath.1.kt")
- ),
- withJdk = true,
- withKotlinRuntime = true,
- includeNonPublic = false,
- analysisPlatform = analysisPlatform
-
- )
- ) { model, output ->
- buildPagesAndReadInto(model.members.single { it.name == "p2" }.members.single().members, output)
- }
- }
-
- @Test
- fun javadocOrderedList() {
- verifyJavaMarkdownNodes("javadocOrderedList", defaultModelConfig) { model ->
- model.members.single().members.filter { it.name == "Bar" }
- }
- }
-
- @Test
- fun jdkLinks() {
- verifyMarkdownNode("jdkLinks", ModelConfig(withKotlinRuntime = true, analysisPlatform = analysisPlatform))
- }
-
- @Test
- fun javadocHtml() {
- verifyJavaMarkdownNode("javadocHtml", defaultModelConfig)
- }
-}
-
-class CommonMarkdownFormatTest: BaseMarkdownFormatTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/format/PackageDocsTest.kt b/core/src/test/kotlin/format/PackageDocsTest.kt
deleted file mode 100644
index 3ff5f123..00000000
--- a/core/src/test/kotlin/format/PackageDocsTest.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.jetbrains.dokka.tests.format
-
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.util.Disposer
-import com.nhaarman.mockito_kotlin.any
-import com.nhaarman.mockito_kotlin.doAnswer
-import com.nhaarman.mockito_kotlin.eq
-import com.nhaarman.mockito_kotlin.mock
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.tests.assertEqualsIgnoringSeparators
-import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment
-import org.jetbrains.kotlin.config.CompilerConfiguration
-import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
-import org.junit.After
-import org.junit.Assert.assertEquals
-import org.junit.Before
-import org.junit.Test
-import java.io.File
-
-class PackageDocsTest {
-
- private lateinit var testDisposable: Disposable
-
- @Before
- fun setup() {
- testDisposable = Disposer.newDisposable()
- }
-
- @After
- fun cleanup() {
- Disposer.dispose(testDisposable)
- }
-
- fun createPackageDocs(linkResolver: DeclarationLinkResolver?): PackageDocs {
- val environment = KotlinCoreEnvironment.createForTests(testDisposable, CompilerConfiguration.EMPTY, EnvironmentConfigFiles.JVM_CONFIG_FILES)
- return PackageDocs(linkResolver, DokkaConsoleLogger, environment, mock(), mock())
- }
-
- @Test fun verifyParse() {
-
- val docs = createPackageDocs(null)
- docs.parse("testdata/packagedocs/stdlib.md", emptyList())
- val packageContent = docs.packageContent["kotlin"]!!
- val block = (packageContent.children.single() as ContentBlock).children.first() as ContentText
- assertEquals("Core functions and types", block.text)
- }
-
- @Test fun testReferenceLinksInPackageDocs() {
- val mockLinkResolver = mock<DeclarationLinkResolver> {
- val exampleCom = "https://example.com"
- on { tryResolveContentLink(any(), eq(exampleCom)) } doAnswer { ContentExternalLink(exampleCom) }
- }
-
- val mockPackageDescriptor = mock<PackageFragmentDescriptor> {}
-
- val docs = createPackageDocs(mockLinkResolver)
- docs.parse("testdata/packagedocs/referenceLinks.md", listOf(mockPackageDescriptor))
-
- checkMarkdownOutput(docs, "testdata/packagedocs/referenceLinks")
- }
-
- fun checkMarkdownOutput(docs: PackageDocs, expectedFilePrefix: String) {
-
- val generator = FileGenerator(File(""))
-
- val out = StringBuilder()
- val outputBuilder = MarkdownOutputBuilder(
- out,
- FileLocation(generator.root),
- generator,
- KotlinLanguageService(),
- ".md",
- emptyList()
- )
- fun checkOutput(content: Content, filePostfix: String) {
- outputBuilder.appendContent(content)
- val expectedFile = File(expectedFilePrefix + filePostfix)
- assertEqualsIgnoringSeparators(expectedFile, out.toString())
- out.setLength(0)
- }
-
- checkOutput(docs.moduleContent, ".module.md")
-
- docs.packageContent.forEach {
- (name, content) ->
- checkOutput(content, ".$name.md")
- }
-
- }
-}
diff --git a/core/src/test/kotlin/issues/IssuesTest.kt b/core/src/test/kotlin/issues/IssuesTest.kt
deleted file mode 100644
index da5acd6e..00000000
--- a/core/src/test/kotlin/issues/IssuesTest.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package issues
-
-import org.jetbrains.dokka.DocumentationNode
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.Platform
-import org.jetbrains.dokka.tests.ModelConfig
-import org.jetbrains.dokka.tests.checkSourceExistsAndVerifyModel
-import org.junit.Test
-import kotlin.test.assertEquals
-
-abstract class BaseIssuesTest(val analysisPlatform: Platform) {
- val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
-
- @Test
- fun errorClasses() {
- checkSourceExistsAndVerifyModel("testdata/issues/errorClasses.kt",
- modelConfig = ModelConfig(analysisPlatform = analysisPlatform, withJdk = true, withKotlinRuntime = true)) { model ->
- val cls = model.members.single().members.single()
-
- fun DocumentationNode.returnType() = this.details.find { it.kind == NodeKind.Type }?.name
- assertEquals("Test", cls.members[1].returnType())
- assertEquals("Test", cls.members[2].returnType())
- assertEquals("Test", cls.members[3].returnType())
- assertEquals("List", cls.members[4].returnType())
- assertEquals("String", cls.members[5].returnType())
- assertEquals("String", cls.members[6].returnType())
- assertEquals("String", cls.members[7].returnType())
- }
- }
-}
-
-class JSIssuesTest: BaseIssuesTest(Platform.js)
-class JVMIssuesTest: BaseIssuesTest(Platform.jvm)
-class CommonIssuesTest: BaseIssuesTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/javadoc/JavadocTest.kt b/core/src/test/kotlin/javadoc/JavadocTest.kt
deleted file mode 100644
index 1c4dd258..00000000
--- a/core/src/test/kotlin/javadoc/JavadocTest.kt
+++ /dev/null
@@ -1,333 +0,0 @@
-package org.jetbrains.dokka.javadoc
-
-import com.sun.javadoc.Tag
-import com.sun.javadoc.Type
-import org.jetbrains.dokka.DokkaConsoleLogger
-import org.jetbrains.dokka.Platform
-import org.jetbrains.dokka.tests.ModelConfig
-import org.jetbrains.dokka.tests.assertEqualsIgnoringSeparators
-import org.jetbrains.dokka.tests.checkSourceExistsAndVerifyModel
-import org.junit.Assert.*
-import org.junit.Test
-import java.lang.reflect.Modifier.*
-
-class JavadocTest {
- val defaultModelConfig = ModelConfig(analysisPlatform = Platform.jvm)
-
- @Test fun testTypes() {
- verifyJavadoc("testdata/javadoc/types.kt", ModelConfig(analysisPlatform = Platform.jvm, withJdk = true)) { doc ->
- val classDoc = doc.classNamed("foo.TypesKt")!!
- val method = classDoc.methods().find { it.name() == "foo" }!!
-
- val type = method.returnType()
- assertFalse(type.asClassDoc().isIncluded)
- assertEquals("java.lang.String", type.qualifiedTypeName())
- assertEquals("java.lang.String", type.asClassDoc().qualifiedName())
-
- val params = method.parameters()
- assertTrue(params[0].type().isPrimitive)
- assertFalse(params[1].type().asClassDoc().isIncluded)
- }
- }
-
- @Test fun testObject() {
- verifyJavadoc("testdata/javadoc/obj.kt", defaultModelConfig) { doc ->
- val classDoc = doc.classNamed("foo.O")
- assertNotNull(classDoc)
-
- val companionDoc = doc.classNamed("foo.O.Companion")
- assertNotNull(companionDoc)
-
- val pkgDoc = doc.packageNamed("foo")!!
- assertEquals(2, pkgDoc.allClasses().size)
- }
- }
-
- @Test fun testException() {
- verifyJavadoc(
- "testdata/javadoc/exception.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- val classDoc = doc.classNamed("foo.MyException")!!
- val member = classDoc.methods().find { it.name() == "foo" }
- assertEquals(classDoc, member!!.containingClass())
- }
- }
-
- @Test fun testByteArray() {
- verifyJavadoc(
- "testdata/javadoc/bytearr.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- val classDoc = doc.classNamed("foo.ByteArray")!!
- assertNotNull(classDoc.asClassDoc())
-
- val member = classDoc.methods().find { it.name() == "foo" }!!
- assertEquals("[]", member.returnType().dimension())
- }
- }
-
- @Test fun testStringArray() {
- verifyJavadoc(
- "testdata/javadoc/stringarr.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- val classDoc = doc.classNamed("foo.Foo")!!
- assertNotNull(classDoc.asClassDoc())
-
- val member = classDoc.methods().find { it.name() == "main" }!!
- val paramType = member.parameters()[0].type()
- assertNull(paramType.asParameterizedType())
- assertEquals("String[]", paramType.typeName())
- assertEquals("String", paramType.asClassDoc().name())
- }
- }
-
- @Test fun testJvmName() {
- verifyJavadoc(
- "testdata/javadoc/jvmname.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- val classDoc = doc.classNamed("foo.Apple")!!
- assertNotNull(classDoc.asClassDoc())
-
- val member = classDoc.methods().find { it.name() == "_tree" }
- assertNotNull(member)
- }
- }
-
- @Test fun testLinkWithParam() {
- verifyJavadoc(
- "testdata/javadoc/paramlink.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- val classDoc = doc.classNamed("demo.Apple")!!
- assertNotNull(classDoc.asClassDoc())
- val tags = classDoc.inlineTags().filterIsInstance<SeeTagAdapter>()
- assertEquals(2, tags.size)
- val linkTag = tags[1] as SeeMethodTagAdapter
- assertEquals("cutIntoPieces", linkTag.method.name())
- }
- }
-
- @Test fun testInternalVisibility() {
- verifyJavadoc(
- "testdata/javadoc/internal.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true, includeNonPublic = false)
- ) { doc ->
- val classDoc = doc.classNamed("foo.Person")!!
- val constructors = classDoc.constructors()
- assertEquals(1, constructors.size)
- assertEquals(1, constructors.single().parameters().size)
- }
- }
-
- @Test fun testSuppress() {
- verifyJavadoc(
- "testdata/javadoc/suppress.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- assertNull(doc.classNamed("Some"))
- assertNull(doc.classNamed("SomeAgain"))
- assertNull(doc.classNamed("Interface"))
- val classSame = doc.classNamed("Same")!!
- assertTrue(classSame.fields().isEmpty())
- assertTrue(classSame.methods().isEmpty())
- }
- }
-
- @Test fun testTypeAliases() {
- verifyJavadoc(
- "testdata/javadoc/typealiases.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- assertNull(doc.classNamed("B"))
- assertNull(doc.classNamed("D"))
-
- assertEquals("A", doc.classNamed("C")!!.superclass().name())
- val methodParamType = doc.classNamed("TypealiasesKt")!!.methods()
- .find { it.name() == "some" }!!.parameters().first()
- .type()
- assertEquals("kotlin.jvm.functions.Function1", methodParamType.qualifiedTypeName())
- assertEquals("? super A, C",
- methodParamType.asParameterizedType().typeArguments().joinToString(transform = Type::qualifiedTypeName)
- )
- }
- }
-
- @Test fun testKDocKeywordsOnMethod() {
- verifyJavadoc(
- "testdata/javadoc/kdocKeywordsOnMethod.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- val method = doc.classNamed("KdocKeywordsOnMethodKt")!!.methods()[0]
- assertEquals("@return [ContentText(text=value of a)]", method.tags("return").first().text())
- assertEquals("@param a [ContentText(text=Some string)]", method.paramTags().first().text())
- assertEquals("@throws FireException [ContentText(text=in case of fire)]", method.throwsTags().first().text())
- }
- }
-
- @Test
- fun testBlankLineInsideCodeBlock() {
- verifyJavadoc(
- "testdata/javadoc/blankLineInsideCodeBlock.kt",
- ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
- ) { doc ->
- val method = doc.classNamed("BlankLineInsideCodeBlockKt")!!.methods()[0]
- val text = method.inlineTags().joinToString(separator = "", transform = Tag::text)
- assertEqualsIgnoringSeparators("""
- <p><code><pre>
- This is a test
- of Dokka's code blocks.
- Here is a blank line.
-
- The previous line was blank.
- </pre></code></p>
- """.trimIndent(), text)
- }
- }
-
- @Test
- fun testCompanionMethodReference() {
- verifyJavadoc("testdata/javadoc/companionMethodReference.kt", defaultModelConfig) { doc ->
- val classDoc = doc.classNamed("foo.TestClass")!!
- val tag = classDoc.inlineTags().filterIsInstance<SeeMethodTagAdapter>().first()
- assertEquals("TestClass.Companion", tag.referencedClassName())
- assertEquals("test", tag.referencedMemberName())
- }
- }
-
- @Test
- fun testVararg() {
- verifyJavadoc("testdata/javadoc/vararg.kt") { doc ->
- val classDoc = doc.classNamed("VarargKt")!!
- val methods = classDoc.methods()
- methods.single { it.name() == "vararg" }.let { method ->
- assertTrue(method.isVarArgs)
- assertEquals("int", method.parameters().last().typeName())
- }
- methods.single { it.name() == "varargInMiddle" }.let { method ->
- assertFalse(method.isVarArgs)
- assertEquals("int[]", method.parameters()[1].typeName())
- }
- }
- }
-
- @Test
- fun shouldHaveValidVisibilityModifiers() {
- verifyJavadoc("testdata/javadoc/visibilityModifiers.kt", ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)) { doc ->
- val classDoc = doc.classNamed("foo.Apple")!!
- val methods = classDoc.methods()
-
- val getName = methods[0]
- val setName = methods[1]
- val getWeight = methods[2]
- val setWeight = methods[3]
- val getRating = methods[4]
- val setRating = methods[5]
- val getCode = methods[6]
- val color = classDoc.fields()[3]
- val code = classDoc.fields()[4]
-
- assertTrue(getName.isProtected)
- assertEquals(PROTECTED, getName.modifierSpecifier())
- assertTrue(setName.isProtected)
- assertEquals(PROTECTED, setName.modifierSpecifier())
-
- assertTrue(getWeight.isPublic)
- assertEquals(PUBLIC, getWeight.modifierSpecifier())
- assertTrue(setWeight.isPublic)
- assertEquals(PUBLIC, setWeight.modifierSpecifier())
-
- assertTrue(getRating.isPublic)
- assertEquals(PUBLIC, getRating.modifierSpecifier())
- assertTrue(setRating.isPublic)
- assertEquals(PUBLIC, setRating.modifierSpecifier())
-
- assertTrue(getCode.isPublic)
- assertEquals(PUBLIC or STATIC, getCode.modifierSpecifier())
-
- assertEquals(methods.size, 7)
-
- assertTrue(color.isPrivate)
- assertEquals(PRIVATE, color.modifierSpecifier())
-
- assertTrue(code.isPrivate)
- assertTrue(code.isStatic)
- assertEquals(PRIVATE or STATIC, code.modifierSpecifier())
- }
- }
-
- @Test
- fun shouldNotHaveDuplicatedConstructorParameters() {
- verifyJavadoc("testdata/javadoc/constructorParameters.kt") { doc ->
- val classDoc = doc.classNamed("bar.Banana")!!
- val paramTags = classDoc.constructors()[0].paramTags()
-
- assertEquals(3, paramTags.size)
- }
- }
-
- @Test fun shouldHaveAllFunctionMarkedAsDeprecated() {
- verifyJavadoc("testdata/javadoc/deprecated.java") { doc ->
- val classDoc = doc.classNamed("bar.Banana")!!
-
- classDoc.methods().forEach { method ->
- assertTrue(method.tags().any { it.kind() == "deprecated" })
- }
- }
- }
-
- @Test
- fun testDefaultNoArgConstructor() {
- verifyJavadoc("testdata/javadoc/defaultNoArgConstructor.kt") { doc ->
- val classDoc = doc.classNamed("foo.Peach")!!
- assertTrue(classDoc.constructors()[0].tags()[2].text() == "print peach")
- }
- }
-
- @Test
- fun testNoArgConstructor() {
- verifyJavadoc("testdata/javadoc/noArgConstructor.kt") { doc ->
- val classDoc = doc.classNamed("foo.Plum")!!
- assertTrue(classDoc.constructors()[0].tags()[2].text() == "print plum")
- }
- }
-
- @Test
- fun testArgumentReference() {
- verifyJavadoc("testdata/javadoc/argumentReference.kt") { doc ->
- val classDoc = doc.classNamed("ArgumentReferenceKt")!!
- val method = classDoc.methods().first()
- val tag = method.seeTags().first()
- assertEquals("argNamedError", tag.referencedMemberName())
- assertEquals("error", tag.label())
- }
- }
-
- @Test
- fun functionParameters() {
- verifyJavadoc("testdata/javadoc/functionParameters.java") { doc ->
- val tags = doc.classNamed("bar.Foo")!!.methods().first().paramTags()
- assertEquals((tags.first() as ParamTagAdapter).content.size, 1)
- assertEquals((tags[1] as ParamTagAdapter).content.size, 1)
- }
- }
-
- private fun verifyJavadoc(name: String,
- modelConfig: ModelConfig = ModelConfig(),
- callback: (ModuleNodeAdapter) -> Unit) {
-
- checkSourceExistsAndVerifyModel(name,
- ModelConfig(
- analysisPlatform = Platform.jvm,
- format = "javadoc",
- withJdk = modelConfig.withJdk,
- withKotlinRuntime = modelConfig.withKotlinRuntime,
- includeNonPublic = modelConfig.includeNonPublic
- )) { model ->
- val doc = ModuleNodeAdapter(model, StandardReporter(DokkaConsoleLogger), "")
- callback(doc)
- }
- }
-}
diff --git a/core/src/test/kotlin/markdown/ParserTest.kt b/core/src/test/kotlin/markdown/ParserTest.kt
deleted file mode 100644
index b0ec68ff..00000000
--- a/core/src/test/kotlin/markdown/ParserTest.kt
+++ /dev/null
@@ -1,154 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.junit.Test
-import org.jetbrains.dokka.toTestString
-import org.jetbrains.dokka.parseMarkdown
-import org.junit.Ignore
-
-@Ignore public class ParserTest {
- fun runTestFor(text : String) {
- println("MD: ---")
- println(text)
- val markdownTree = parseMarkdown(text)
- println("AST: ---")
- println(markdownTree.toTestString())
- println()
- }
-
- @Test fun text() {
- runTestFor("text")
- }
-
- @Test fun textWithSpaces() {
- runTestFor("text and string")
- }
-
- @Test fun textWithColon() {
- runTestFor("text and string: cool!")
- }
-
- @Test fun link() {
- runTestFor("text [links]")
- }
-
- @Test fun linkWithHref() {
- runTestFor("text [links](http://google.com)")
- }
-
- @Test fun multiline() {
- runTestFor(
- """
-text
-and
-string
-""")
- }
-
- @Test fun para() {
- runTestFor(
- """
-paragraph number
-one
-
-paragraph
-number two
-""")
- }
-
- @Test fun bulletList() {
- runTestFor(
- """* list item 1
-* list item 2
-""")
- }
-
- @Test fun bulletListWithLines() {
- runTestFor(
- """
-* list item 1
- continue 1
-* list item 2
- continue 2
- """)
- }
-
- @Test fun bulletListStrong() {
- runTestFor(
- """
-* list *item* 1
- continue 1
-* list *item* 2
- continue 2
- """)
- }
-
- @Test fun emph() {
- runTestFor("*text*")
- }
-
- @Test fun underscoresNoEmph() {
- runTestFor("text_with_underscores")
- }
-
- @Test fun emphUnderscores() {
- runTestFor("_text_")
- }
-
- @Test fun singleStar() {
- runTestFor("Embedded*Star")
- }
-
- @Test fun directive() {
- runTestFor("A text \${code with.another.value} with directive")
- }
-
- @Test fun emphAndEmptySection() {
- runTestFor("*text*\n\$sec:\n")
- }
-
- @Test fun emphAndSection() {
- runTestFor("*text*\n\$sec: some text\n")
- }
-
- @Test fun emphAndBracedSection() {
- runTestFor("Text *bold* text \n\${sec}: some text")
- }
-
- @Test fun section() {
- runTestFor(
- "Plain text \n\$one: Summary \n\${two}: Description with *emphasis* \n\${An example of a section}: Example")
- }
-
- @Test fun anonymousSection() {
- runTestFor("Summary\n\nDescription\n")
- }
-
- @Test fun specialSection() {
- runTestFor(
- "Plain text \n\$\$summary: Summary \n\${\$description}: Description \n\${\$An example of a section}: Example")
- }
-
- @Test fun emptySection() {
- runTestFor(
- "Plain text \n\$summary:")
- }
-
- val b = "$"
- @Test fun pair() {
- runTestFor(
- """Represents a generic pair of two values.
-
-There is no meaning attached to values in this class, it can be used for any purpose.
-Pair exhibits value semantics, i.e. two pairs are equal if both components are equal.
-
-An example of decomposing it into values:
-${b}{code test.tuples.PairTest.pairMultiAssignment}
-
-${b}constructor: Creates new instance of [Pair]
-${b}first: First value
-${b}second: Second value""""
- )
- }
-
-}
-
diff --git a/core/src/test/kotlin/model/ClassTest.kt b/core/src/test/kotlin/model/ClassTest.kt
deleted file mode 100644
index 35ec1d09..00000000
--- a/core/src/test/kotlin/model/ClassTest.kt
+++ /dev/null
@@ -1,318 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.Content
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.Platform
-import org.jetbrains.dokka.RefKind
-import org.junit.Assert
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Test
-
-abstract class BaseClassTest(val analysisPlatform: Platform) {
- protected val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
- @Test fun emptyClass() {
- checkSourceExistsAndVerifyModel("testdata/classes/emptyClass.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals(NodeKind.Class, kind)
- assertEquals("Klass", name)
- assertEquals(Content.Empty, content)
- assertEquals("<init>", members.single().name)
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun emptyObject() {
- checkSourceExistsAndVerifyModel("testdata/classes/emptyObject.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals(NodeKind.Object, kind)
- assertEquals("Obj", name)
- assertEquals(Content.Empty, content)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun classWithConstructor() {
- checkSourceExistsAndVerifyModel("testdata/classes/classWithConstructor.kt", defaultModelConfig) { model ->
- with (model.members.single().members.single()) {
- assertEquals(NodeKind.Class, kind)
- assertEquals("Klass", name)
- assertEquals(Content.Empty, content)
- assertTrue(links.none())
-
- assertEquals(1, members.count())
- with(members.elementAt(0)) {
- assertEquals("<init>", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Constructor, kind)
- assertEquals(3, details.count())
- assertEquals("public", details.elementAt(0).name)
- with(details.elementAt(2)) {
- assertEquals("name", name)
- assertEquals(NodeKind.Parameter, kind)
- assertEquals(Content.Empty, content)
- assertEquals("String", detail(NodeKind.Type).name)
- assertTrue(links.none())
- assertTrue(members.none())
- }
- assertTrue(links.none())
- assertTrue(members.none())
- }
- }
- }
- }
-
- @Test fun classWithFunction() {
- checkSourceExistsAndVerifyModel("testdata/classes/classWithFunction.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals(NodeKind.Class, kind)
- assertEquals("Klass", name)
- assertEquals(Content.Empty, content)
- assertTrue(links.none())
-
- assertEquals(2, members.count())
- with(members.elementAt(0)) {
- assertEquals("<init>", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Constructor, kind)
- assertEquals(2, details.count())
- assertEquals("public", details.elementAt(0).name)
- assertTrue(links.none())
- assertTrue(members.none())
- }
- with(members.elementAt(1)) {
- assertEquals("fn", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Function, kind)
- assertEquals("Unit", detail(NodeKind.Type).name)
- assertTrue(links.none())
- assertTrue(members.none())
- }
- }
- }
- }
-
- @Test fun classWithProperty() {
- checkSourceExistsAndVerifyModel("testdata/classes/classWithProperty.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals(NodeKind.Class, kind)
- assertEquals("Klass", name)
- assertEquals(Content.Empty, content)
- assertTrue(links.none())
-
- assertEquals(2, members.count())
- with(members.elementAt(0)) {
- assertEquals("<init>", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Constructor, kind)
- assertEquals(2, details.count())
- assertEquals("public", details.elementAt(0).name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- with(members.elementAt(1)) {
- assertEquals("name", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Property, kind)
- assertEquals("String", detail(NodeKind.Type).name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
- }
-
- @Test fun classWithCompanionObject() {
- checkSourceExistsAndVerifyModel("testdata/classes/classWithCompanionObject.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals(NodeKind.Class, kind)
- assertEquals("Klass", name)
- assertEquals(Content.Empty, content)
- assertTrue(links.none())
-
- assertEquals(3, members.count())
- with(members.elementAt(0)) {
- assertEquals("<init>", name)
- assertEquals(Content.Empty, content)
- }
- with(members.elementAt(1)) {
- assertEquals("x", name)
- assertEquals(NodeKind.CompanionObjectProperty, kind)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- with(members.elementAt(2)) {
- assertEquals("foo", name)
- assertEquals(NodeKind.CompanionObjectFunction, kind)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
- }
-
- @Test fun dataClass() {
- verifyPackageMember("testdata/classes/dataClass.kt", defaultModelConfig) { cls ->
- val modifiers = cls.details(NodeKind.Modifier).map { it.name }
- assertTrue("data" in modifiers)
- }
- }
-
- @Test fun sealedClass() {
- verifyPackageMember("testdata/classes/sealedClass.kt", defaultModelConfig) { cls ->
- val modifiers = cls.details(NodeKind.Modifier).map { it.name }
- assertEquals(1, modifiers.count { it == "sealed" })
- }
- }
-
- @Test fun annotatedClassWithAnnotationParameters() {
- checkSourceExistsAndVerifyModel(
- "testdata/classes/annotatedClassWithAnnotationParameters.kt",
- defaultModelConfig
- ) { model ->
- with(model.members.single().members.single()) {
- with(deprecation!!) {
- assertEquals("Deprecated", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Annotation, kind)
- assertEquals(1, details.count())
- with(details[0]) {
- assertEquals(NodeKind.Parameter, kind)
- assertEquals(1, details.count())
- with(details[0]) {
- assertEquals(NodeKind.Value, kind)
- assertEquals("\"should no longer be used\"", name)
- }
- }
- }
- }
- }
- }
-
- @Test fun notOpenClass() {
- checkSourceExistsAndVerifyModel("testdata/classes/notOpenClass.kt", defaultModelConfig) { model ->
- with(model.members.single().members.first { it.name == "D"}.members.first { it.name == "f" }) {
- val modifiers = details(NodeKind.Modifier)
- assertEquals(2, modifiers.size)
- assertEquals("final", modifiers[1].name)
-
- val overrideReferences = references(RefKind.Override)
- assertEquals(1, overrideReferences.size)
- }
- }
- }
-
- @Test fun indirectOverride() {
- checkSourceExistsAndVerifyModel("testdata/classes/indirectOverride.kt", defaultModelConfig) { model ->
- with(model.members.single().members.first { it.name == "E"}.members.first { it.name == "foo" }) {
- val modifiers = details(NodeKind.Modifier)
- assertEquals(2, modifiers.size)
- assertEquals("final", modifiers[1].name)
-
- val overrideReferences = references(RefKind.Override)
- assertEquals(1, overrideReferences.size)
- }
- }
- }
-
- @Test fun innerClass() {
- verifyPackageMember("testdata/classes/innerClass.kt", defaultModelConfig) { cls ->
- val innerClass = cls.members.single { it.name == "D" }
- val modifiers = innerClass.details(NodeKind.Modifier)
- assertEquals(3, modifiers.size)
- assertEquals("inner", modifiers[2].name)
- }
- }
-
- @Test fun companionObjectExtension() {
- checkSourceExistsAndVerifyModel("testdata/classes/companionObjectExtension.kt", defaultModelConfig) { model ->
- val pkg = model.members.single()
- val cls = pkg.members.single { it.name == "Foo" }
- val extensions = cls.extensions.filter { it.kind == NodeKind.CompanionObjectProperty }
- assertEquals(1, extensions.size)
- }
- }
-
- @Test fun secondaryConstructor() {
- verifyPackageMember("testdata/classes/secondaryConstructor.kt", defaultModelConfig) { cls ->
- val constructors = cls.members(NodeKind.Constructor)
- assertEquals(2, constructors.size)
- with (constructors.first { it.details(NodeKind.Parameter).size == 1}) {
- assertEquals("<init>", name)
- assertEquals("This is a secondary constructor.", summary.toTestString())
- }
- }
- }
-
- @Test fun sinceKotlin() {
- checkSourceExistsAndVerifyModel("testdata/classes/sinceKotlin.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("1.1", sinceKotlin)
- }
- }
- }
-
- @Test fun privateCompanionObject() {
- checkSourceExistsAndVerifyModel(
- "testdata/classes/privateCompanionObject.kt",
- modelConfig = ModelConfig(analysisPlatform = analysisPlatform, includeNonPublic = false)
- ) { model ->
- with(model.members.single().members.single()) {
- assertEquals(0, members(NodeKind.CompanionObjectFunction).size)
- assertEquals(0, members(NodeKind.CompanionObjectProperty).size)
- }
- }
- }
-
-}
-
-class JSClassTest: BaseClassTest(Platform.js) {}
-
-class JVMClassTest: BaseClassTest(Platform.jvm) {
- @Test
- fun annotatedClass() {
- verifyPackageMember("testdata/classes/annotatedClass.kt", ModelConfig(
- analysisPlatform = analysisPlatform,
- withKotlinRuntime = true
- )
- ) { cls ->
- Assert.assertEquals(1, cls.annotations.count())
- with(cls.annotations[0]) {
- Assert.assertEquals("Strictfp", name)
- Assert.assertEquals(Content.Empty, content)
- Assert.assertEquals(NodeKind.Annotation, kind)
- }
- }
- }
-
-
- @Test fun javaAnnotationClass() {
- checkSourceExistsAndVerifyModel(
- "testdata/classes/javaAnnotationClass.kt",
- modelConfig = ModelConfig(analysisPlatform = analysisPlatform, withJdk = true)
- ) { model ->
- with(model.members.single().members.single()) {
- Assert.assertEquals(1, annotations.count())
- with(annotations[0]) {
- Assert.assertEquals("Retention", name)
- Assert.assertEquals(Content.Empty, content)
- Assert.assertEquals(NodeKind.Annotation, kind)
- with(details[0]) {
- Assert.assertEquals(NodeKind.Parameter, kind)
- Assert.assertEquals(1, details.count())
- with(details[0]) {
- Assert.assertEquals(NodeKind.Value, kind)
- Assert.assertEquals("RetentionPolicy.SOURCE", name)
- }
- }
- }
- }
- }
- }
-
-}
-
-class CommonClassTest: BaseClassTest(Platform.common) {} \ No newline at end of file
diff --git a/core/src/test/kotlin/model/CommentTest.kt b/core/src/test/kotlin/model/CommentTest.kt
deleted file mode 100644
index 08aa3572..00000000
--- a/core/src/test/kotlin/model/CommentTest.kt
+++ /dev/null
@@ -1,190 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.junit.Test
-import org.junit.Assert.*
-import org.jetbrains.dokka.*
-
-abstract class BaseCommentTest(val analysisPlatform: Platform) {
- val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
- @Test fun codeBlockComment() {
- checkSourceExistsAndVerifyModel("testdata/comments/codeBlockComment.kt", defaultModelConfig) { model ->
- with(model.members.single().members.first()) {
- assertEqualsIgnoringSeparators("""[code lang=brainfuck]
- |
- |++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
- |
- |[/code]
- |""".trimMargin(),
- content.toTestString())
- }
- with(model.members.single().members.last()) {
- assertEqualsIgnoringSeparators("""[code]
- |
- |a + b - c
- |
- |[/code]
- |""".trimMargin(),
- content.toTestString())
- }
- }
- }
-
- @Test fun emptyDoc() {
- checkSourceExistsAndVerifyModel("testdata/comments/emptyDoc.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals(Content.Empty, content)
- }
- }
- }
-
- @Test fun emptyDocButComment() {
- checkSourceExistsAndVerifyModel("testdata/comments/emptyDocButComment.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals(Content.Empty, content)
- }
- }
- }
-
- @Test fun multilineDoc() {
- checkSourceExistsAndVerifyModel("testdata/comments/multilineDoc.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("doc1", content.summary.toTestString())
- assertEquals("doc2\ndoc3", content.description.toTestString())
- }
- }
- }
-
- @Test fun multilineDocWithComment() {
- checkSourceExistsAndVerifyModel("testdata/comments/multilineDocWithComment.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("doc1", content.summary.toTestString())
- assertEquals("doc2\ndoc3", content.description.toTestString())
- }
- }
- }
-
- @Test fun oneLineDoc() {
- checkSourceExistsAndVerifyModel("testdata/comments/oneLineDoc.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("doc", content.summary.toTestString())
- }
- }
- }
-
- @Test fun oneLineDocWithComment() {
- checkSourceExistsAndVerifyModel("testdata/comments/oneLineDocWithComment.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("doc", content.summary.toTestString())
- }
- }
- }
-
- @Test fun oneLineDocWithEmptyLine() {
- checkSourceExistsAndVerifyModel("testdata/comments/oneLineDocWithEmptyLine.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("doc", content.summary.toTestString())
- }
- }
- }
-
- @Test fun emptySection() {
- checkSourceExistsAndVerifyModel("testdata/comments/emptySection.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Summary", content.summary.toTestString())
- assertEquals(1, content.sections.count())
- with (content.findSectionByTag("one")!!) {
- assertEquals("One", tag)
- assertEquals("", toTestString())
- }
- }
- }
- }
-
- @Test fun quotes() {
- checkSourceExistsAndVerifyModel("testdata/comments/quotes.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("it's \"useful\"", content.summary.toTestString())
- }
- }
- }
-
- @Test fun section1() {
- checkSourceExistsAndVerifyModel("testdata/comments/section1.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Summary", content.summary.toTestString())
- assertEquals(1, content.sections.count())
- with (content.findSectionByTag("one")!!) {
- assertEquals("One", tag)
- assertEquals("section one", toTestString())
- }
- }
- }
- }
-
- @Test fun section2() {
- checkSourceExistsAndVerifyModel("testdata/comments/section2.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Summary", content.summary.toTestString())
- assertEquals(2, content.sections.count())
- with (content.findSectionByTag("one")!!) {
- assertEquals("One", tag)
- assertEquals("section one", toTestString())
- }
- with (content.findSectionByTag("two")!!) {
- assertEquals("Two", tag)
- assertEquals("section two", toTestString())
- }
- }
- }
- }
-
- @Test fun multilineSection() {
- checkSourceExistsAndVerifyModel("testdata/comments/multilineSection.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Summary", content.summary.toTestString())
- assertEquals(1, content.sections.count())
- with (content.findSectionByTag("one")!!) {
- assertEquals("One", tag)
- assertEquals("""line one
-line two""", toTestString())
- }
- }
- }
- }
-
- @Test fun directive() {
- checkSourceExistsAndVerifyModel("testdata/comments/directive.kt", defaultModelConfig) { model ->
- with(model.members.single().members.first()) {
- assertEquals("Summary", content.summary.toTestString())
- with (content.description) {
- assertEqualsIgnoringSeparators("""
- |[code lang=kotlin]
- |if (true) {
- | println(property)
- |}
- |[/code]
- |[code lang=kotlin]
- |if (true) {
- | println(property)
- |}
- |[/code]
- |[code lang=kotlin]
- |if (true) {
- | println(property)
- |}
- |[/code]
- |[code lang=kotlin]
- |if (true) {
- | println(property)
- |}
- |[/code]
- |""".trimMargin(), toTestString())
- }
- }
- }
- }
-}
-
-class JSCommentTest: BaseCommentTest(Platform.js)
-class JVMCommentTest: BaseCommentTest(Platform.jvm)
-class CommonCommentTest: BaseCommentTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/model/DocumentableTest.kt b/core/src/test/kotlin/model/DocumentableTest.kt
new file mode 100644
index 00000000..a801d549
--- /dev/null
+++ b/core/src/test/kotlin/model/DocumentableTest.kt
@@ -0,0 +1,108 @@
+package model
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.properties.PropertyContainer
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class DocumentableTest {
+
+ @Test
+ fun withDescendents() {
+ val dClass = DClass(
+ dri = DRI(),
+ name = "TestClass",
+ constructors = emptyList(),
+ classlikes = emptyList(),
+ companion = null,
+ documentation = emptyMap(),
+ expectPresentInSet = null,
+ extra = PropertyContainer.empty(),
+ visibility = emptyMap(),
+ generics = emptyList(),
+ modifier = emptyMap(),
+ properties = emptyList(),
+ sources = emptyMap(),
+ sourceSets = emptySet(),
+ supertypes = emptyMap(),
+ functions = listOf(
+ DFunction(
+ dri = DRI(),
+ name = "function0",
+ documentation = emptyMap(),
+ expectPresentInSet = null,
+ extra = PropertyContainer.empty(),
+ visibility = emptyMap(),
+ generics = emptyList(),
+ modifier = emptyMap(),
+ sources = emptyMap(),
+ sourceSets = emptySet(),
+ type = Void,
+ receiver = null,
+ isConstructor = false,
+ parameters = listOf(
+ DParameter(
+ dri = DRI(),
+ name = "f0p0",
+ documentation = emptyMap(),
+ expectPresentInSet = null,
+ extra = PropertyContainer.empty(),
+ sourceSets = emptySet(),
+ type = Void
+ ),
+ DParameter(
+ dri = DRI(),
+ name = "f0p1",
+ documentation = emptyMap(),
+ expectPresentInSet = null,
+ extra = PropertyContainer.empty(),
+ sourceSets = emptySet(),
+ type = Void
+ )
+ )
+ ),
+ DFunction(
+ dri = DRI(),
+ name = "function1",
+ documentation = emptyMap(),
+ expectPresentInSet = null,
+ extra = PropertyContainer.empty(),
+ visibility = emptyMap(),
+ generics = emptyList(),
+ modifier = emptyMap(),
+ sources = emptyMap(),
+ sourceSets = emptySet(),
+ type = Void,
+ receiver = null,
+ isConstructor = false,
+ parameters = listOf(
+ DParameter(
+ dri = DRI(),
+ name = "f1p0",
+ documentation = emptyMap(),
+ expectPresentInSet = null,
+ extra = PropertyContainer.empty(),
+ sourceSets = emptySet(),
+ type = Void
+ ),
+ DParameter(
+ dri = DRI(),
+ name = "f1p1",
+ documentation = emptyMap(),
+ expectPresentInSet = null,
+ extra = PropertyContainer.empty(),
+ sourceSets = emptySet(),
+ type = Void
+ )
+ )
+ )
+ )
+ )
+
+ assertEquals(
+ listOf("TestClass", "function0", "f0p0", "f0p1", "function1", "f1p0", "f1p1"),
+ dClass.withDescendants().map { it.name }.toList()
+ )
+ }
+} \ No newline at end of file
diff --git a/core/src/test/kotlin/model/FunctionTest.kt b/core/src/test/kotlin/model/FunctionTest.kt
deleted file mode 100644
index 4c6bfb74..00000000
--- a/core/src/test/kotlin/model/FunctionTest.kt
+++ /dev/null
@@ -1,281 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.Content
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.Platform
-import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
-import org.junit.Assert
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Test
-
-abstract class BaseFunctionTest(val analysisPlatform: Platform) {
- protected val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
- @Test fun function() {
- checkSourceExistsAndVerifyModel("testdata/functions/function.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("fn", name)
- assertEquals(NodeKind.Function, kind)
- assertEquals("Function fn", content.summary.toTestString())
- assertEquals("Unit", detail(NodeKind.Type).name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun functionWithReceiver() {
- checkSourceExistsAndVerifyModel("testdata/functions/functionWithReceiver.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("kotlin.String", name)
- assertEquals(NodeKind.ExternalClass, kind)
- assertEquals(2, members.count())
- with(members[0]) {
- assertEquals("fn", name)
- assertEquals(NodeKind.Function, kind)
- assertEquals("Function with receiver", content.summary.toTestString())
- assertEquals("public", details.elementAt(0).name)
- assertEquals("final", details.elementAt(1).name)
- with(details.elementAt(3)) {
- assertEquals("<this>", name)
- assertEquals(NodeKind.Receiver, kind)
- assertEquals(Content.Empty, content)
- assertEquals("String", details.single().name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- assertEquals("Unit", details.elementAt(4).name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- with(members[1]) {
- assertEquals("fn", name)
- assertEquals(NodeKind.Function, kind)
- }
- }
- }
- }
-
- @Test fun genericFunction() {
- checkSourceExistsAndVerifyModel("testdata/functions/genericFunction.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("generic", name)
- assertEquals(NodeKind.Function, kind)
- assertEquals("generic function", content.summary.toTestString())
-
- assertEquals("private", details.elementAt(0).name)
- assertEquals("final", details.elementAt(1).name)
- with(details.elementAt(3)) {
- assertEquals("T", name)
- assertEquals(NodeKind.TypeParameter, kind)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertTrue(members.none())
- assertTrue(links.none())
- }
- assertEquals("Unit", details.elementAt(4).name)
-
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
- @Test fun genericFunctionWithConstraints() {
- checkSourceExistsAndVerifyModel("testdata/functions/genericFunctionWithConstraints.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("generic", name)
- assertEquals(NodeKind.Function, kind)
- assertEquals("generic function", content.summary.toTestString())
-
- val functionDetails = details
- assertEquals("public", functionDetails.elementAt(0).name)
- assertEquals("final", functionDetails.elementAt(1).name)
- with(functionDetails.elementAt(3)) {
- assertEquals("T", name)
- assertEquals(NodeKind.TypeParameter, kind)
- assertEquals(Content.Empty, content)
- with(details.single()) {
- assertEquals("R", name)
- assertEquals(NodeKind.UpperBound, kind)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertTrue(members.none())
- assertTrue(links.singleOrNull() == functionDetails.elementAt(4))
- }
- assertTrue(members.none())
- assertTrue(links.none())
- }
- with(functionDetails.elementAt(4)) {
- assertEquals("R", name)
- assertEquals(NodeKind.TypeParameter, kind)
- assertEquals(Content.Empty, content)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- assertEquals("Unit", functionDetails.elementAt(5).name)
-
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun functionWithParams() {
- checkSourceExistsAndVerifyModel("testdata/functions/functionWithParams.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("function", name)
- assertEquals(NodeKind.Function, kind)
- assertEquals("Multiline", content.summary.toTestString())
- assertEquals("""Function
-Documentation""", content.description.toTestString())
-
- assertEquals("public", details.elementAt(0).name)
- assertEquals("final", details.elementAt(1).name)
- with(details.elementAt(3)) {
- assertEquals("x", name)
- assertEquals(NodeKind.Parameter, kind)
- assertEquals("parameter", content.summary.toTestString())
- assertEquals("Int", detail(NodeKind.Type).name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- assertEquals("Unit", details.elementAt(4).name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun functionWithNotDocumentedAnnotation() {
- verifyPackageMember("testdata/functions/functionWithNotDocumentedAnnotation.kt", defaultModelConfig) { func ->
- assertEquals(0, func.annotations.count())
- }
- }
-
- @Test fun inlineFunction() {
- verifyPackageMember("testdata/functions/inlineFunction.kt", defaultModelConfig) { func ->
- val modifiers = func.details(NodeKind.Modifier).map { it.name }
- assertTrue("inline" in modifiers)
- }
- }
-
- @Test fun suspendFunction() {
- verifyPackageMember("testdata/functions/suspendFunction.kt") { func ->
- val modifiers = func.details(NodeKind.Modifier).map { it.name }
- assertTrue("suspend" in modifiers)
- }
- }
-
- @Test fun suspendInlineFunctionOrder() {
- verifyPackageMember("testdata/functions/suspendInlineFunction.kt") { func ->
- val modifiers = func.details(NodeKind.Modifier).map { it.name }.filter {
- it == "suspend" || it == "inline"
- }
-
- assertEquals(listOf("suspend", "inline"), modifiers)
- }
- }
-
- @Test fun inlineSuspendFunctionOrderChanged() {
- verifyPackageMember("testdata/functions/inlineSuspendFunction.kt") { func ->
- val modifiers = func.details(NodeKind.Modifier).map { it.name }.filter {
- it == "suspend" || it == "inline"
- }
-
- assertEquals(listOf("suspend", "inline"), modifiers)
- }
- }
-
- @Test fun functionWithAnnotatedParam() {
- checkSourceExistsAndVerifyModel("testdata/functions/functionWithAnnotatedParam.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single { it.name == "function" }) {
- with(details(NodeKind.Parameter).first()) {
- assertEquals(1, annotations.count())
- with(annotations[0]) {
- assertEquals("Fancy", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Annotation, kind)
- }
- }
- }
- }
- }
-
- @Test fun functionWithNoinlineParam() {
- verifyPackageMember("testdata/functions/functionWithNoinlineParam.kt", defaultModelConfig) { func ->
- with(func.details(NodeKind.Parameter).first()) {
- val modifiers = details(NodeKind.Modifier).map { it.name }
- assertTrue("noinline" in modifiers)
- }
- }
- }
-
- @Test fun annotatedFunctionWithAnnotationParameters() {
- checkSourceExistsAndVerifyModel(
- "testdata/functions/annotatedFunctionWithAnnotationParameters.kt",
- defaultModelConfig
- ) { model ->
- with(model.members.single().members.single { it.name == "f" }) {
- assertEquals(1, annotations.count())
- with(annotations[0]) {
- assertEquals("Fancy", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Annotation, kind)
- assertEquals(1, details.count())
- with(details[0]) {
- assertEquals(NodeKind.Parameter, kind)
- assertEquals(1, details.count())
- with(details[0]) {
- assertEquals(NodeKind.Value, kind)
- assertEquals("1", name)
- }
- }
- }
- }
- }
- }
-
- @Test fun functionWithDefaultParameter() {
- checkSourceExistsAndVerifyModel("testdata/functions/functionWithDefaultParameter.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- with(details.elementAt(3)) {
- val value = details(NodeKind.Value)
- assertEquals(1, value.count())
- with(value[0]) {
- assertEquals("\"\"", name)
- }
- }
- }
- }
- }
-
- @Test fun sinceKotlin() {
- checkSourceExistsAndVerifyModel("testdata/functions/sinceKotlin.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("1.1", sinceKotlin)
- }
- }
- }
-}
-
-class JSFunctionTest: BaseFunctionTest(Platform.js)
-
-class JVMFunctionTest: BaseFunctionTest(Platform.jvm) {
- @Test
- fun annotatedFunction() {
- verifyPackageMember("testdata/functions/annotatedFunction.kt", ModelConfig(
- analysisPlatform = Platform.jvm,
- withKotlinRuntime = true
- )) { func ->
- Assert.assertEquals(1, func.annotations.count())
- with(func.annotations[0]) {
- Assert.assertEquals("Strictfp", name)
- Assert.assertEquals(Content.Empty, content)
- Assert.assertEquals(NodeKind.Annotation, kind)
- }
- }
- }
-
-}
-
-class CommonFunctionTest: BaseFunctionTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/model/JavaTest.kt b/core/src/test/kotlin/model/JavaTest.kt
deleted file mode 100644
index da9da624..00000000
--- a/core/src/test/kotlin/model/JavaTest.kt
+++ /dev/null
@@ -1,210 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.Platform
-import org.jetbrains.dokka.RefKind
-import org.junit.Assert.*
-import org.junit.Ignore
-import org.junit.Test
-
-public class JavaTest {
- private val defaultModelConfig = ModelConfig(analysisPlatform = Platform.jvm)
- @Test fun function() {
- verifyJavaPackageMember("testdata/java/member.java", defaultModelConfig) { cls ->
- assertEquals("Test", cls.name)
- assertEquals(NodeKind.Class, cls.kind)
- with(cls.members(NodeKind.Function).single()) {
- assertEquals("fn", name)
- assertEquals("Summary for Function", content.summary.toTestString().trimEnd())
- assertEquals(3, content.sections.size)
- with(content.sections[0]) {
- assertEquals("Parameters", tag)
- assertEquals("name", subjectName)
- assertEquals("render(Type:String,SUMMARY): is String parameter", toTestString())
- }
- with(content.sections[1]) {
- assertEquals("Parameters", tag)
- assertEquals("value", subjectName)
- assertEquals("render(Type:Int,SUMMARY): is int parameter", toTestString())
- }
- with(content.sections[2]) {
- assertEquals("Author", tag)
- assertEquals("yole", toTestString())
- }
- assertEquals("Unit", detail(NodeKind.Type).name)
- assertTrue(members.none())
- assertTrue(links.none())
- with(details.first { it.name == "name" }) {
- assertEquals(NodeKind.Parameter, kind)
- assertEquals("String", detail(NodeKind.Type).name)
- }
- with(details.first { it.name == "value" }) {
- assertEquals(NodeKind.Parameter, kind)
- assertEquals("Int", detail(NodeKind.Type).name)
- }
- }
- }
- }
-
- @Test fun memberWithModifiers() {
- verifyJavaPackageMember("testdata/java/memberWithModifiers.java", defaultModelConfig) { cls ->
- val modifiers = cls.details(NodeKind.Modifier).map { it.name }
- assertTrue("abstract" in modifiers)
- with(cls.members.single { it.name == "fn" }) {
- assertEquals("protected", details[0].name)
- }
- with(cls.members.single { it.name == "openFn" }) {
- assertEquals("open", details[1].name)
- }
- }
- }
-
- @Test fun superClass() {
- verifyJavaPackageMember("testdata/java/superClass.java", defaultModelConfig) { cls ->
- val superTypes = cls.details(NodeKind.Supertype)
- assertEquals(2, superTypes.size)
- assertEquals("Exception", superTypes[0].name)
- assertEquals("Cloneable", superTypes[1].name)
- }
- }
-
- @Test fun arrayType() {
- verifyJavaPackageMember("testdata/java/arrayType.java", defaultModelConfig) { cls ->
- with(cls.members(NodeKind.Function).single()) {
- val type = detail(NodeKind.Type)
- assertEquals("Array", type.name)
- assertEquals("String", type.detail(NodeKind.Type).name)
- with(details(NodeKind.Parameter).single()) {
- val parameterType = detail(NodeKind.Type)
- assertEquals("IntArray", parameterType.name)
- }
- }
- }
- }
-
- @Test fun typeParameter() {
- verifyJavaPackageMember("testdata/java/typeParameter.java", defaultModelConfig) { cls ->
- val typeParameters = cls.details(NodeKind.TypeParameter)
- with(typeParameters.single()) {
- assertEquals("T", name)
- with(detail(NodeKind.UpperBound)) {
- assertEquals("Comparable", name)
- assertEquals("T", detail(NodeKind.Type).name)
- }
- }
- with(cls.members(NodeKind.Function).single()) {
- val methodTypeParameters = details(NodeKind.TypeParameter)
- with(methodTypeParameters.single()) {
- assertEquals("E", name)
- }
- }
- }
- }
-
- @Test fun constructors() {
- verifyJavaPackageMember("testdata/java/constructors.java", defaultModelConfig) { cls ->
- val constructors = cls.members(NodeKind.Constructor)
- assertEquals(2, constructors.size)
- with(constructors[0]) {
- assertEquals("<init>", name)
- }
- }
- }
-
- @Test fun innerClass() {
- verifyJavaPackageMember("testdata/java/InnerClass.java", defaultModelConfig) { cls ->
- val innerClass = cls.members(NodeKind.Class).single()
- assertEquals("D", innerClass.name)
- }
- }
-
- @Test fun varargs() {
- verifyJavaPackageMember("testdata/java/varargs.java", defaultModelConfig) { cls ->
- val fn = cls.members(NodeKind.Function).single()
- val param = fn.detail(NodeKind.Parameter)
- assertEquals("vararg", param.details(NodeKind.Modifier).first().name)
- val psiType = param.detail(NodeKind.Type)
- assertEquals("String", psiType.name)
- assertTrue(psiType.details(NodeKind.Type).isEmpty())
- }
- }
-
- @Test fun fields() {
- verifyJavaPackageMember("testdata/java/field.java", defaultModelConfig) { cls ->
- val i = cls.members(NodeKind.Property).single { it.name == "i" }
- assertEquals("Int", i.detail(NodeKind.Type).name)
- assertTrue("var" in i.details(NodeKind.Modifier).map { it.name })
-
- val s = cls.members(NodeKind.Property).single { it.name == "s" }
- assertEquals("String", s.detail(NodeKind.Type).name)
- assertFalse("var" in s.details(NodeKind.Modifier).map { it.name })
- assertTrue("static" in s.details(NodeKind.Modifier).map { it.name })
- }
- }
-
- @Test fun staticMethod() {
- verifyJavaPackageMember("testdata/java/staticMethod.java", defaultModelConfig) { cls ->
- val m = cls.members(NodeKind.Function).single { it.name == "foo" }
- assertTrue("static" in m.details(NodeKind.Modifier).map { it.name })
- }
- }
-
- /**
- * `@suppress` not supported in Java!
- *
- * [Proposed tags](https://www.oracle.com/technetwork/java/javase/documentation/proposed-tags-142378.html)
- * Proposed tag `@exclude` for it, but not supported yet
- */
- @Ignore("@suppress not supported in Java!") @Test fun suppressTag() {
- verifyJavaPackageMember("testdata/java/suppressTag.java", defaultModelConfig) { cls ->
- assertEquals(1, cls.members(NodeKind.Function).size)
- }
- }
-
- @Test fun annotatedAnnotation() {
- verifyJavaPackageMember("testdata/java/annotatedAnnotation.java", defaultModelConfig) { cls ->
- assertEquals(1, cls.annotations.size)
- with(cls.annotations[0]) {
- assertEquals(1, details.count())
- with(details[0]) {
- assertEquals(NodeKind.Parameter, kind)
- assertEquals(1, details.count())
- with(details[0]) {
- assertEquals(NodeKind.Value, kind)
- assertEquals("[AnnotationTarget.FIELD, AnnotationTarget.CLASS, AnnotationTarget.FILE, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER]", name)
- }
- }
- }
- }
- }
-
- @Test fun deprecation() {
- verifyJavaPackageMember("testdata/java/deprecation.java", defaultModelConfig) { cls ->
- val fn = cls.members(NodeKind.Function).single()
- assertEquals("This should no longer be used", fn.deprecation!!.content.toTestString())
- }
- }
-
- @Test fun javaLangObject() {
- verifyJavaPackageMember("testdata/java/javaLangObject.java", defaultModelConfig) { cls ->
- val fn = cls.members(NodeKind.Function).single()
- assertEquals("Any", fn.detail(NodeKind.Type).name)
- }
- }
-
- @Test fun enumValues() {
- verifyJavaPackageMember("testdata/java/enumValues.java", defaultModelConfig) { cls ->
- val superTypes = cls.details(NodeKind.Supertype)
- assertEquals(1, superTypes.size)
- assertEquals(1, cls.members(NodeKind.EnumItem).size)
- }
- }
-
- @Test fun inheritorLinks() {
- verifyJavaPackageMember("testdata/java/InheritorLinks.java", defaultModelConfig) { cls ->
- val fooClass = cls.members.single { it.name == "Foo" }
- val inheritors = fooClass.references(RefKind.Inheritor)
- assertEquals(1, inheritors.size)
- }
- }
-}
diff --git a/core/src/test/kotlin/model/KotlinAsJavaTest.kt b/core/src/test/kotlin/model/KotlinAsJavaTest.kt
deleted file mode 100644
index c29776be..00000000
--- a/core/src/test/kotlin/model/KotlinAsJavaTest.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.DocumentationModule
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.Platform
-import org.jetbrains.dokka.RefKind
-import org.junit.Assert
-import org.junit.Assert.assertEquals
-import org.junit.Test
-
-class KotlinAsJavaTest {
- @Test fun function() {
- verifyModelAsJava("testdata/functions/function.kt") { model ->
- val pkg = model.members.single()
-
- val facadeClass = pkg.members.single { it.name == "FunctionKt" }
- assertEquals(NodeKind.Class, facadeClass.kind)
-
- val fn = facadeClass.members.single { it.kind == NodeKind.Function}
- assertEquals("fn", fn.name)
- }
- }
-
- @Test fun propertyWithComment() {
- verifyModelAsJava("testdata/comments/oneLineDoc.kt") { model ->
- val facadeClass = model.members.single().members.single { it.name == "OneLineDocKt" }
- val getter = facadeClass.members.single { it.name == "getProperty" }
- assertEquals(NodeKind.Function, getter.kind)
- assertEquals("doc", getter.content.summary.toTestString())
- }
- }
-
-
- @Test fun constants() {
- verifyModelAsJava("testdata/java/constants.java") { cls ->
- selectNodes(cls) {
- subgraphOf(RefKind.Member)
- matching { it.name == "constStr" || it.name == "refConst" }
- }.forEach {
- assertEquals("In $it", "\"some value\"", it.detailOrNull(NodeKind.Value)?.name)
- }
- val nullConstNode = selectNodes(cls) {
- subgraphOf(RefKind.Member)
- withName("nullConst")
- }.single()
-
- Assert.assertNull(nullConstNode.detailOrNull(NodeKind.Value))
- }
- }
-}
-
-fun verifyModelAsJava(source: String,
- modelConfig: ModelConfig = ModelConfig(),
- verifier: (DocumentationModule) -> Unit) {
- checkSourceExistsAndVerifyModel(
- source,
- modelConfig = ModelConfig(
- withJdk = modelConfig.withJdk,
- withKotlinRuntime = modelConfig.withKotlinRuntime,
- format = "html-as-java",
- analysisPlatform = Platform.jvm),
- verifier = verifier
- )
-}
diff --git a/core/src/test/kotlin/model/LinkTest.kt b/core/src/test/kotlin/model/LinkTest.kt
deleted file mode 100644
index 6526a4db..00000000
--- a/core/src/test/kotlin/model/LinkTest.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.ContentBlock
-import org.jetbrains.dokka.ContentNodeLazyLink
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.Platform
-import org.junit.Assert.assertEquals
-import org.junit.Test
-
-abstract class BaseLinkTest(val analysisPlatform: Platform) {
- private val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
- @Test fun linkToSelf() {
- checkSourceExistsAndVerifyModel("testdata/links/linkToSelf.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Foo", name)
- assertEquals(NodeKind.Class, kind)
- assertEquals("This is link to [Foo -> Class:Foo]", content.summary.toTestString())
- }
- }
- }
-
- @Test fun linkToExternalSite() {
- checkSourceExistsAndVerifyModel("testdata/links/linkToExternalSite.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Foo", name)
- assertEquals(NodeKind.Class, kind)
- assertEquals("This is link to http://example.com/#example", content.summary.toTestString())
- }
- }
- }
-
- @Test fun linkToMember() {
- checkSourceExistsAndVerifyModel("testdata/links/linkToMember.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Foo", name)
- assertEquals(NodeKind.Class, kind)
- assertEquals("This is link to [member -> Function:member]", content.summary.toTestString())
- }
- }
- }
-
- @Test fun linkToConstantWithUnderscores() {
- checkSourceExistsAndVerifyModel("testdata/links/linkToConstantWithUnderscores.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Foo", name)
- assertEquals(NodeKind.Class, kind)
- assertEquals("This is link to [MY_CONSTANT_VALUE -> CompanionObjectProperty:MY_CONSTANT_VALUE]", content.summary.toTestString())
- }
- }
- }
-
- @Test fun linkToQualifiedMember() {
- checkSourceExistsAndVerifyModel("testdata/links/linkToQualifiedMember.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Foo", name)
- assertEquals(NodeKind.Class, kind)
- assertEquals("This is link to [Foo.member -> Function:member]", content.summary.toTestString())
- }
- }
- }
-
- @Test fun linkToParam() {
- checkSourceExistsAndVerifyModel("testdata/links/linkToParam.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("Foo", name)
- assertEquals(NodeKind.Function, kind)
- assertEquals("This is link to [param -> Parameter:param]", content.summary.toTestString())
- }
- }
- }
-
- @Test fun linkToPackage() {
- checkSourceExistsAndVerifyModel("testdata/links/linkToPackage.kt", defaultModelConfig) { model ->
- val packageNode = model.members.single()
- with(packageNode) {
- assertEquals(this.name, "test.magic")
- }
- with(packageNode.members.single()) {
- assertEquals("Magic", name)
- assertEquals(NodeKind.Class, kind)
- assertEquals("Basic implementations of [Magic -> Class:Magic] are located in [test.magic -> Package:test.magic] package", content.summary.toTestString())
- assertEquals(packageNode, ((this.content.summary as ContentBlock).children.filterIsInstance<ContentNodeLazyLink>().last()).lazyNode.invoke())
- }
- }
- }
-
-}
-
-class JSLinkTest: BaseLinkTest(Platform.js)
-class JVMLinkTest: BaseLinkTest(Platform.jvm)
-class CommonLinkTest: BaseLinkTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/model/PackageTest.kt b/core/src/test/kotlin/model/PackageTest.kt
deleted file mode 100644
index 47c88385..00000000
--- a/core/src/test/kotlin/model/PackageTest.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.*
-import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
-import org.junit.Assert.*
-import org.junit.Test
-
-abstract class BasePackageTest(val analysisPlatform: Platform) {
- val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
- @Test fun rootPackage() {
- checkSourceExistsAndVerifyModel("testdata/packages/rootPackage.kt", defaultModelConfig) { model ->
- with(model.members.single()) {
- assertEquals(NodeKind.Package, kind)
- assertEquals("", name)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun simpleNamePackage() {
- checkSourceExistsAndVerifyModel("testdata/packages/simpleNamePackage.kt", defaultModelConfig) { model ->
- with(model.members.single()) {
- assertEquals(NodeKind.Package, kind)
- assertEquals("simple", name)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun dottedNamePackage() {
- checkSourceExistsAndVerifyModel("testdata/packages/dottedNamePackage.kt", defaultModelConfig) { model ->
- with(model.members.single()) {
- assertEquals(NodeKind.Package, kind)
- assertEquals("dot.name", name)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun multipleFiles() {
- verifyModel(
- ModelConfig(
- roots = arrayOf(
- KotlinSourceRoot("testdata/packages/dottedNamePackage.kt", false),
- KotlinSourceRoot("testdata/packages/simpleNamePackage.kt", false)
- ),
- analysisPlatform = analysisPlatform
- )
- ) { model ->
- assertEquals(2, model.members.count())
- with(model.members.single { it.name == "simple" }) {
- assertEquals(NodeKind.Package, kind)
- assertEquals("simple", name)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertTrue(members.none())
- assertTrue(links.none())
- }
- with(model.members.single { it.name == "dot.name" }) {
- assertEquals(NodeKind.Package, kind)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun multipleFilesSamePackage() {
- verifyModel(
- ModelConfig(
- roots = arrayOf(
- KotlinSourceRoot("testdata/packages/simpleNamePackage.kt", false),
- KotlinSourceRoot("testdata/packages/simpleNamePackage2.kt", false)
- ),
- analysisPlatform = analysisPlatform
- )
- ) { model ->
- assertEquals(1, model.members.count())
- with(model.members.elementAt(0)) {
- assertEquals(NodeKind.Package, kind)
- assertEquals("simple", name)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun classAtPackageLevel() {
- verifyModel(
- ModelConfig(
- roots = arrayOf(KotlinSourceRoot("testdata/packages/classInPackage.kt", false)),
- analysisPlatform = analysisPlatform
- )
- ) { model ->
- assertEquals(1, model.members.count())
- with(model.members.elementAt(0)) {
- assertEquals(NodeKind.Package, kind)
- assertEquals("simple.name", name)
- assertEquals(Content.Empty, content)
- assertTrue(details.none())
- assertEquals(1, members.size)
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun suppressAtPackageLevel() {
- verifyModel(
- ModelConfig(
- roots = arrayOf(KotlinSourceRoot("testdata/packages/classInPackage.kt", false)),
- perPackageOptions = listOf(
- PackageOptionsImpl(prefix = "simple.name", suppress = true)
- ),
- analysisPlatform = analysisPlatform
- )
- ) { model ->
- assertEquals(0, model.members.count())
- }
- }
-}
-
-class JSPackageTest : BasePackageTest(Platform.js)
-class JVMPackageTest : BasePackageTest(Platform.jvm)
-class CommonPackageTest : BasePackageTest(Platform.common) \ No newline at end of file
diff --git a/core/src/test/kotlin/model/PropertyTest.kt b/core/src/test/kotlin/model/PropertyTest.kt
deleted file mode 100644
index 9f070862..00000000
--- a/core/src/test/kotlin/model/PropertyTest.kt
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import org.jetbrains.dokka.*
-import org.junit.Assert
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Test
-
-abstract class BasePropertyTest(val analysisPlatform: Platform) {
-
- protected val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
- @Test fun valueProperty() {
- checkSourceExistsAndVerifyModel("testdata/properties/valueProperty.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("property", name)
- assertEquals(NodeKind.Property, kind)
- assertEquals(Content.Empty, content)
- assertEquals("String", detail(NodeKind.Type).name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun variableProperty() {
- checkSourceExistsAndVerifyModel("testdata/properties/variableProperty.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("property", name)
- assertEquals(NodeKind.Property, kind)
- assertEquals(Content.Empty, content)
- assertEquals("String", detail(NodeKind.Type).name)
- assertTrue(members.none())
- assertTrue(links.none())
- }
- }
- }
-
- @Test fun valuePropertyWithGetter() {
- checkSourceExistsAndVerifyModel("testdata/properties/valuePropertyWithGetter.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("property", name)
- assertEquals(NodeKind.Property, kind)
- assertEquals(Content.Empty, content)
- assertEquals("String", detail(NodeKind.Type).name)
- assertTrue(links.none())
- assertTrue(members.none())
- }
- }
- }
-
- @Test fun variablePropertyWithAccessors() {
- checkSourceExistsAndVerifyModel("testdata/properties/variablePropertyWithAccessors.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("property", name)
- assertEquals(NodeKind.Property, kind)
- assertEquals(Content.Empty, content)
- assertEquals("String", detail(NodeKind.Type).name)
- val modifiers = details(NodeKind.Modifier).map { it.name }
- assertTrue("final" in modifiers)
- assertTrue("public" in modifiers)
- assertTrue("var" in modifiers)
- assertTrue(links.none())
- assertTrue(members.none())
- }
- }
- }
-
- @Test fun propertyWithReceiver() {
- checkSourceExistsAndVerifyModel(
- "testdata/properties/propertyWithReceiver.kt",
- defaultModelConfig
- ) { model ->
- with(model.members.single().members.single()) {
- assertEquals("kotlin.String", name)
- assertEquals(NodeKind.ExternalClass, kind)
- with(members.single()) {
- assertEquals("foobar", name)
- assertEquals(NodeKind.Property, kind)
- }
- }
- }
- }
-
- @Test fun propertyOverride() {
- checkSourceExistsAndVerifyModel("testdata/properties/propertyOverride.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single { it.name == "Bar" }.members.single { it.name == "xyzzy"}) {
- assertEquals("xyzzy", name)
- val override = references(RefKind.Override).single().to
- assertEquals("xyzzy", override.name)
- assertEquals("Foo", override.owner!!.name)
- }
- }
- }
-
- @Test fun sinceKotlin() {
- checkSourceExistsAndVerifyModel("testdata/properties/sinceKotlin.kt", defaultModelConfig) { model ->
- with(model.members.single().members.single()) {
- assertEquals("1.1", sinceKotlin)
- }
- }
- }
-}
-
-class JSPropertyTest: BasePropertyTest(Platform.js) {}
-
-class JVMPropertyTest : BasePropertyTest(Platform.jvm) {
- @Test
- fun annotatedProperty() {
- checkSourceExistsAndVerifyModel(
- "testdata/properties/annotatedProperty.kt",
- modelConfig = ModelConfig(
- analysisPlatform = analysisPlatform,
- withKotlinRuntime = true
- )
- ) { model ->
- with(model.members.single().members.single()) {
- Assert.assertEquals(1, annotations.count())
- with(annotations[0]) {
- Assert.assertEquals("Strictfp", name)
- Assert.assertEquals(Content.Empty, content)
- Assert.assertEquals(NodeKind.Annotation, kind)
- }
- }
- }
- }
-
-}
-
-class CommonPropertyTest: BasePropertyTest(Platform.common) {} \ No newline at end of file
diff --git a/core/src/test/kotlin/model/SourceLinksErrorTest.kt b/core/src/test/kotlin/model/SourceLinksErrorTest.kt
deleted file mode 100644
index 9812569d..00000000
--- a/core/src/test/kotlin/model/SourceLinksErrorTest.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.jetbrains.dokka.tests.model
-
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.SourceLinkDefinitionImpl
-import org.jetbrains.dokka.tests.ModelConfig
-import org.jetbrains.dokka.tests.checkSourceExistsAndVerifyModel
-import org.junit.Assert
-import org.junit.Test
-import java.io.File
-
-class SourceLinksErrorTest {
-
- @Test
- fun absolutePath_notMatching() {
- val sourceLink = SourceLinkDefinitionImpl(File("testdata/nonExisting").absolutePath, "http://...", null)
- verifyNoSourceUrl(sourceLink)
- }
-
- @Test
- fun relativePath_notMatching() {
- val sourceLink = SourceLinkDefinitionImpl("testdata/nonExisting", "http://...", null)
- verifyNoSourceUrl(sourceLink)
- }
-
- private fun verifyNoSourceUrl(sourceLink: SourceLinkDefinitionImpl) {
- checkSourceExistsAndVerifyModel("testdata/sourceLinks/dummy.kt", ModelConfig(sourceLinks = listOf(sourceLink))) { model ->
- with(model.members.single().members.single()) {
- Assert.assertEquals("foo", name)
- Assert.assertEquals(NodeKind.Function, kind)
- Assert.assertTrue("should not have source urls", details(NodeKind.SourceUrl).isEmpty())
- }
- }
- }
-}
-
diff --git a/core/src/test/kotlin/model/SourceLinksTest.kt b/core/src/test/kotlin/model/SourceLinksTest.kt
deleted file mode 100644
index a4ba870c..00000000
--- a/core/src/test/kotlin/model/SourceLinksTest.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.jetbrains.dokka.tests.model
-
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.SourceLinkDefinitionImpl
-import org.jetbrains.dokka.tests.ModelConfig
-import org.jetbrains.dokka.tests.checkSourceExistsAndVerifyModel
-import org.junit.Assert
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import java.io.File
-
-@RunWith(Parameterized::class)
-class SourceLinksTest(
- private val srcLink: String,
- private val url: String,
- private val lineSuffix: String?,
- private val expectedUrl: String
-) {
-
- @Test
- fun test() {
- val link = if(srcLink.contains(sourceLinks)){
- srcLink.substringBeforeLast(sourceLinks) + sourceLinks
- } else {
- srcLink.substringBeforeLast(testdata) + testdata
- }
- val sourceLink = SourceLinkDefinitionImpl(link, url, lineSuffix)
-
- checkSourceExistsAndVerifyModel(filePath, ModelConfig(sourceLinks = listOf(sourceLink))) { model ->
- with(model.members.single().members.single()) {
- Assert.assertEquals("foo", name)
- Assert.assertEquals(NodeKind.Function, kind)
- Assert.assertEquals(expectedUrl, details(NodeKind.SourceUrl).single().name)
- }
- }
- }
-
- companion object {
- private const val testdata = "testdata"
- private const val sourceLinks = "sourceLinks"
- private const val dummy = "dummy.kt"
- private const val pathSuffix = "$sourceLinks/$dummy"
- private const val filePath = "$testdata/$pathSuffix"
- private const val url = "https://example.com"
-
- @Parameterized.Parameters(name = "{index}: {0}, {1}, {2} = {3}")
- @JvmStatic
- fun data(): Collection<Array<String?>> {
- val longestPath = File(testdata).absolutePath.removeSuffix("/") + "/../$testdata/"
- val maxLength = longestPath.length
- val list = listOf(
- arrayOf(File(testdata).absolutePath.removeSuffix("/"), "$url/$pathSuffix"),
- arrayOf(File("$testdata/$sourceLinks").absolutePath.removeSuffix("/") + "/", "$url/$dummy"),
- arrayOf(longestPath, "$url/$pathSuffix"),
-
- arrayOf(testdata, "$url/$pathSuffix"),
- arrayOf("./$testdata", "$url/$pathSuffix"),
- arrayOf("../core/$testdata", "$url/$pathSuffix"),
- arrayOf("$testdata/$sourceLinks", "$url/$dummy"),
- arrayOf("./$testdata/../$testdata/$sourceLinks", "$url/$dummy")
- )
-
- return list.map { arrayOf(it[0].padEnd(maxLength, '_'), url, null, it[1]) } +
- listOf(
- // check that it also works if url ends with /
- arrayOf((File(testdata).absolutePath.removeSuffix("/") + "/").padEnd(maxLength, '_'), "$url/", null, "$url/$pathSuffix"),
- // check if line suffix work
- arrayOf<String?>("../core/../core/./$testdata/$sourceLinks/".padEnd(maxLength, '_'), "$url/", "#L", "$url/$dummy#L4")
- )
- }
- }
-
-}
-
diff --git a/core/src/test/kotlin/model/TypeAliasTest.kt b/core/src/test/kotlin/model/TypeAliasTest.kt
deleted file mode 100644
index 71976dc3..00000000
--- a/core/src/test/kotlin/model/TypeAliasTest.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.jetbrains.dokka.tests
-
-import junit.framework.TestCase.assertEquals
-import org.jetbrains.dokka.Content
-import org.jetbrains.dokka.NodeKind
-import org.junit.Test
-
-class TypeAliasTest {
- @Test
- fun testSimple() {
- checkSourceExistsAndVerifyModel("testdata/typealias/simple.kt") {
- val pkg = it.members.single()
- with(pkg.member(NodeKind.TypeAlias)) {
- assertEquals(Content.Empty, content)
- assertEquals("B", name)
- assertEquals("A", detail(NodeKind.TypeAliasUnderlyingType).name)
- }
- }
- }
-
- @Test
- fun testInheritanceFromTypeAlias() {
- checkSourceExistsAndVerifyModel("testdata/typealias/inheritanceFromTypeAlias.kt") {
- val pkg = it.members.single()
- with(pkg.member(NodeKind.TypeAlias)) {
- assertEquals(Content.Empty, content)
- assertEquals("Same", name)
- assertEquals("Some", detail(NodeKind.TypeAliasUnderlyingType).name)
- assertEquals("My", inheritors.single().name)
- }
- with(pkg.members(NodeKind.Class).find { it.name == "My" }!!) {
- assertEquals("Same", detail(NodeKind.Supertype).name)
- }
- }
- }
-
- @Test
- fun testChain() {
- checkSourceExistsAndVerifyModel("testdata/typealias/chain.kt") {
- val pkg = it.members.single()
- with(pkg.members(NodeKind.TypeAlias).find { it.name == "B" }!!) {
- assertEquals(Content.Empty, content)
- assertEquals("A", detail(NodeKind.TypeAliasUnderlyingType).name)
- }
- with(pkg.members(NodeKind.TypeAlias).find { it.name == "C" }!!) {
- assertEquals(Content.Empty, content)
- assertEquals("B", detail(NodeKind.TypeAliasUnderlyingType).name)
- }
- }
- }
-
- @Test
- fun testDocumented() {
- checkSourceExistsAndVerifyModel("testdata/typealias/documented.kt") {
- val pkg = it.members.single()
- with(pkg.member(NodeKind.TypeAlias)) {
- assertEquals("Just typealias", content.summary.toTestString())
- }
- }
- }
-
- @Test
- fun testDeprecated() {
- checkSourceExistsAndVerifyModel("testdata/typealias/deprecated.kt") {
- val pkg = it.members.single()
- with(pkg.member(NodeKind.TypeAlias)) {
- assertEquals(Content.Empty, content)
- assertEquals("Deprecated", deprecation!!.name)
- assertEquals("\"Not mainstream now\"", deprecation!!.detail(NodeKind.Parameter).detail(NodeKind.Value).name)
- }
- }
- }
-
- @Test
- fun testGeneric() {
- checkSourceExistsAndVerifyModel("testdata/typealias/generic.kt") {
- val pkg = it.members.single()
- with(pkg.members(NodeKind.TypeAlias).find { it.name == "B" }!!) {
- assertEquals("Any", detail(NodeKind.TypeAliasUnderlyingType).detail(NodeKind.Type).name)
- }
-
- with(pkg.members(NodeKind.TypeAlias).find { it.name == "C" }!!) {
- assertEquals("T", detail(NodeKind.TypeAliasUnderlyingType).detail(NodeKind.Type).name)
- assertEquals("T", detail(NodeKind.TypeParameter).name)
- }
- }
- }
-
- @Test
- fun testFunctional() {
- checkSourceExistsAndVerifyModel("testdata/typealias/functional.kt") {
- val pkg = it.members.single()
- with(pkg.member(NodeKind.TypeAlias)) {
- assertEquals("Function1", detail(NodeKind.TypeAliasUnderlyingType).name)
- val typeParams = detail(NodeKind.TypeAliasUnderlyingType).details(NodeKind.Type)
- assertEquals("A", typeParams.first().name)
- assertEquals("B", typeParams.last().name)
- }
-
- with(pkg.member(NodeKind.Function)) {
- assertEquals("Spell", detail(NodeKind.Parameter).detail(NodeKind.Type).name)
- }
- }
- }
-
- @Test
- fun testAsTypeBoundWithVariance() {
- checkSourceExistsAndVerifyModel("testdata/typealias/asTypeBoundWithVariance.kt") {
- val pkg = it.members.single()
- with(pkg.members(NodeKind.Class).find { it.name == "C" }!!) {
- val tParam = detail(NodeKind.TypeParameter)
- assertEquals("out", tParam.detail(NodeKind.Modifier).name)
- assertEquals("B", tParam.detail(NodeKind.Type).link(NodeKind.TypeAlias).name)
- }
-
- with(pkg.members(NodeKind.Class).find { it.name == "D" }!!) {
- val tParam = detail(NodeKind.TypeParameter)
- assertEquals("in", tParam.detail(NodeKind.Modifier).name)
- assertEquals("B", tParam.detail(NodeKind.Type).link(NodeKind.TypeAlias).name)
- }
- }
- }
-
- @Test
- fun sinceKotlin() {
- checkSourceExistsAndVerifyModel("testdata/typealias/sinceKotlin.kt") { model ->
- with(model.members.single().members.single()) {
- assertEquals("1.1", sinceKotlin)
- }
- }
- }
-} \ No newline at end of file
diff --git a/core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
deleted file mode 100644
index ca6ee9ce..00000000
--- a/core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
+++ /dev/null
@@ -1 +0,0 @@
-mock-maker-inline \ No newline at end of file