aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorKrystianUjma <kujma@virtuslab.com>2019-03-19 11:34:38 +0100
committerKrystianUjma <kujma@virtuslab.com>2019-03-19 15:56:01 +0100
commit2e94ac4098d9e2582223485b981114fa462e5757 (patch)
treeed1b772bce9d790c473b346bcce435e893b29be7 /core
parentb566f8852e94f9a17be86bf845aeff6c36bd8378 (diff)
parenta9c91cb7dc54c1554be5cf8de90516c929c0c1cb (diff)
downloaddokka-2e94ac4098d9e2582223485b981114fa462e5757.tar.gz
dokka-2e94ac4098d9e2582223485b981114fa462e5757.tar.bz2
dokka-2e94ac4098d9e2582223485b981114fa462e5757.zip
Merge branch 'kotlin-website-jonnyzzz' into multiplatform-support
Diffstat (limited to 'core')
-rw-r--r--core/build.gradle2
-rw-r--r--core/src/main/kotlin/Analysis/AnalysisEnvironment.kt223
-rw-r--r--core/src/main/kotlin/Analysis/DokkaAnalyzerFacades.kt163
-rw-r--r--core/src/main/kotlin/DokkaBootstrapImpl.kt32
-rw-r--r--core/src/main/kotlin/Formats/FormatDescriptor.kt1
-rw-r--r--core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt10
-rw-r--r--core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt130
-rw-r--r--core/src/main/kotlin/Formats/PackageListService.kt11
-rw-r--r--core/src/main/kotlin/Formats/StructuredFormatService.kt691
-rw-r--r--core/src/main/kotlin/Formats/YamlOutlineService.kt2
-rw-r--r--core/src/main/kotlin/Generation/DocumentationMerger.kt217
-rw-r--r--core/src/main/kotlin/Generation/DokkaGenerator.kt93
-rw-r--r--core/src/main/kotlin/Generation/FileGenerator.kt87
-rw-r--r--core/src/main/kotlin/Generation/configurationImpl.kt78
-rw-r--r--core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt25
-rw-r--r--core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt4
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt2
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt172
-rw-r--r--core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt115
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt2
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinLanguageService.kt2
-rw-r--r--core/src/main/kotlin/Locations/Location.kt19
-rw-r--r--core/src/main/kotlin/Model/Content.kt6
-rw-r--r--core/src/main/kotlin/Model/DocumentationNode.kt31
-rw-r--r--core/src/main/kotlin/Model/DocumentationReference.kt65
-rw-r--r--core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt2
-rw-r--r--core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt86
-rw-r--r--core/src/main/kotlin/Utilities/DokkaModules.kt29
-rw-r--r--core/src/main/kotlin/Utilities/ServiceLocator.kt2
-rw-r--r--core/src/main/kotlin/javadoc/dokka-adapters.kt9
-rw-r--r--core/src/test/kotlin/TestAPI.kt238
-rw-r--r--core/src/test/kotlin/format/GFMFormatTest.kt18
-rw-r--r--core/src/test/kotlin/format/HtmlFormatTest.kt161
-rw-r--r--core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt40
-rw-r--r--core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt68
-rw-r--r--core/src/test/kotlin/format/MarkdownFormatTest.kt443
-rw-r--r--core/src/test/kotlin/issues/IssuesTest.kt16
-rw-r--r--core/src/test/kotlin/javadoc/JavadocTest.kt77
-rw-r--r--core/src/test/kotlin/model/ClassTest.kt123
-rw-r--r--core/src/test/kotlin/model/CommentTest.kt36
-rw-r--r--core/src/test/kotlin/model/FunctionTest.kt67
-rw-r--r--core/src/test/kotlin/model/JavaTest.kt34
-rw-r--r--core/src/test/kotlin/model/KotlinAsJavaTest.kt15
-rw-r--r--core/src/test/kotlin/model/LinkTest.kt22
-rw-r--r--core/src/test/kotlin/model/PackageTest.kt57
-rw-r--r--core/src/test/kotlin/model/PropertyTest.kt66
-rw-r--r--core/src/test/kotlin/model/SourceLinksErrorTest.kt5
-rw-r--r--core/src/test/kotlin/model/SourceLinksTest.kt5
-rw-r--r--core/src/test/kotlin/model/TypeAliasTest.kt18
-rw-r--r--core/testdata/format/website-html/sampleWithAsserts.html2
-rw-r--r--core/testdata/format/website-html/sampleWithAsserts.kt2
51 files changed, 2632 insertions, 1192 deletions
diff --git a/core/build.gradle b/core/build.gradle
index a4538471..c90a7789 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -32,6 +32,8 @@ dependencies {
compile "org.jetbrains:markdown:$markdownVersion"
compile intellijCoreAnalysis()
+
+ compile kotlinPluginDependency()
compile 'org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.8'
diff --git a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
index 8ad7b8bb..603fd0e4 100644
--- a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
+++ b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
@@ -17,8 +17,15 @@ import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.io.URLUtil
+import org.jetbrains.dokka.Analysis.DokkaJsAnalyzerFacade
+import org.jetbrains.dokka.Analysis.DokkaNativeAnalyzerFacade
import org.jetbrains.kotlin.analyzer.*
+import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
+import org.jetbrains.kotlin.analyzer.common.CommonAnalyzerFacade
+import org.jetbrains.kotlin.builtins.DefaultBuiltIns
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
+import org.jetbrains.kotlin.caches.project.LibraryModuleInfo
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.ContentRoot
@@ -38,16 +45,17 @@ import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+import org.jetbrains.kotlin.js.config.JSConfigurationKeys
+import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
import org.jetbrains.kotlin.name.Name
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.*
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.jvm.JvmAnalyzerFacade
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
+import org.jetbrains.kotlin.resolve.konan.platform.KonanPlatform
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.types.KotlinType
@@ -63,7 +71,7 @@ import java.io.File
* $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) : Disposable {
+class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPlatform: Platform) : Disposable {
val configuration = CompilerConfiguration()
init {
@@ -72,12 +80,19 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
fun createCoreEnvironment(): KotlinCoreEnvironment {
System.setProperty("idea.io.use.fallback", "true")
- val environment = KotlinCoreEnvironment.createForProduction(this, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
+
+ 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)
}
@@ -96,10 +111,11 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
return environment
}
- fun createSourceModuleSearchScope(project: Project, sourceFiles: List<KtFile>): GlobalSearchScope {
- // TODO: Fix when going to implement dokka for JS
- return TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, sourceFiles)
- }
+ 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> {
@@ -108,7 +124,21 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
val sourceFiles = environment.getSourceFiles()
- val library = object : ModuleInfo {
+ val targetPlatform = when (analysisPlatform) {
+ Platform.js -> JsPlatform
+ Platform.common -> TargetPlatform.Common
+ Platform.native -> KonanPlatform
+ Platform.jvm -> JvmPlatform
+ }
+
+ val library = object : LibraryModuleInfo {
+ override val platform: TargetPlatform
+ get() = targetPlatform
+
+ override fun getLibraryRoots(): Collection<String> {
+ return classpath.map { it.absolutePath }
+ }
+
override val name: Name = Name.special("<library>")
override fun dependencies(): List<ModuleInfo> = listOf(this)
}
@@ -118,43 +148,146 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
}
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))
+ else -> throw IllegalArgumentException("Unexpected module info")
+ }
+ }
- val builtIns = JvmBuiltIns(projectContext.storageManager)
+ var builtIns: JvmBuiltIns? = null
+ val resolverForProject = when (analysisPlatform) {
+ Platform.jvm -> {
+ builtIns = JvmBuiltIns(projectContext.storageManager)
+ 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 javaRoots = classpath
- .mapNotNull {
- val rootFile = when {
- it.extension == "jar" ->
- StandardFileSystems.jar().findFileByPath("${it.absolutePath}${URLUtil.JAR_SEPARATOR}")
- else ->
- StandardFileSystems.local().findFileByPath(it.absolutePath)
- }
+ }
+ val resolverForLibrary = resolverForProject.resolverForModule(library) // Required before module to initialize library properly
+ val resolverForModule = resolverForProject.resolverForModule(module)
+ val libraryModuleDescriptor = resolverForProject.descriptorForModule(library)
+ val moduleDescriptor = resolverForProject.descriptorForModule(module)
+ builtIns?.initialize(moduleDescriptor, true)
+ 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))
- rootFile?.let { JavaRoot(it, JavaRoot.RootType.BINARY) }
+ return created to libraryResolutionFacade
+ }
+
+ private fun createCommonResolverForProject(
+ projectContext: ProjectContext,
+ module: ModuleInfo,
+ library: LibraryModuleInfo,
+ modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>,
+ environment: KotlinCoreEnvironment
+ ): ResolverForProjectImpl<ModuleInfo> {
+ return ResolverForProjectImpl(
+ debugName = "Dokka",
+ projectContext = projectContext,
+ modules = listOf(module, library),
+ modulesContent = modulesContent,
+ modulePlatforms = { MultiTargetPlatform.Common },
+ moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */,
+ resolverForModuleFactoryByPlatform = { CommonAnalyzerFacade },
+ platformParameters = { _ ->
+ CommonAnalysisParameters { content ->
+ environment.createPackagePartProvider(content.moduleContentScope)
+ }
+ },
+ targetEnvironment = CompilerEnvironment,
+ builtIns = DefaultBuiltIns.Instance
+ )
+ }
+
+ private fun createJsResolverForProject(
+ projectContext: ProjectContext,
+ module: ModuleInfo,
+ library: LibraryModuleInfo,
+ modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>
+ ): ResolverForProjectImpl<ModuleInfo> {
+ return ResolverForProjectImpl(
+ debugName = "Dokka",
+ projectContext = projectContext,
+ modules = listOf(module, library),
+ modulesContent = modulesContent,
+ modulePlatforms = { JsPlatform.multiTargetPlatform },
+ moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */,
+ resolverForModuleFactoryByPlatform = { DokkaJsAnalyzerFacade },
+ platformParameters = { _ -> PlatformAnalysisParameters.Empty },
+ targetEnvironment = CompilerEnvironment,
+ builtIns = JsPlatform.builtIns
+ )
+ }
+
+ private fun createNativeResolverForProject(
+ projectContext: ProjectContext,
+ module: ModuleInfo,
+ library: LibraryModuleInfo,
+ modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>
+ ): ResolverForProjectImpl<ModuleInfo> {
+ return ResolverForProjectImpl(
+ debugName = "Dokka",
+ projectContext = projectContext,
+ modules = listOf(module, library),
+ modulesContent = modulesContent,
+ modulePlatforms = { KonanPlatform.multiTargetPlatform },
+ moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */,
+ resolverForModuleFactoryByPlatform = { DokkaNativeAnalyzerFacade },
+ platformParameters = { _ -> PlatformAnalysisParameters.Empty },
+ targetEnvironment = CompilerEnvironment
+ )
+
+ }
+
+ private fun createJvmResolverForProject(
+ projectContext: ProjectContext,
+ module: ModuleInfo,
+ library: LibraryModuleInfo,
+ modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>,
+ sourcesScope: GlobalSearchScope,
+ builtIns: KotlinBuiltIns
+ ): ResolverForProjectImpl<ModuleInfo> {
+ val javaRoots = classpath
+ .mapNotNull {
+ val rootFile = when {
+ it.extension == "jar" ->
+ StandardFileSystems.jar().findFileByPath("${it.absolutePath}${URLUtil.JAR_SEPARATOR}")
+ else ->
+ StandardFileSystems.local().findFileByPath(it.absolutePath)
}
- val resolverForProject = ResolverForProjectImpl(
- "Dokka",
- projectContext,
- listOf(library, module),
- {
+ rootFile?.let { JavaRoot(it, JavaRoot.RootType.BINARY) }
+ }
+
+ return ResolverForProjectImpl(
+ debugName = "Dokka",
+ projectContext = projectContext,
+ modules = listOf(library, module),
+ modulesContent = {
when (it) {
library -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope))
module -> ModuleContent(it, emptyList(), sourcesScope)
else -> throw IllegalArgumentException("Unexpected module info")
}
},
- {
- JvmPlatform.multiTargetPlatform
- },
- LanguageSettingsProvider.Default /* TODO: Fix this */,
- { JvmAnalyzerFacade },
- {
+ modulePlatforms = { JvmPlatform.multiTargetPlatform },
+ moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */,
+ resolverForModuleFactoryByPlatform = { JvmAnalyzerFacade },
+ platformParameters = {
JvmPlatformParameters ({ content ->
- JvmPackagePartProvider(configuration.languageVersionSettings, content.moduleContentScope).apply {
- addRoots(javaRoots, messageCollector)
- }
+ JvmPackagePartProvider(
+ configuration.languageVersionSettings,
+ content.moduleContentScope)
+ .apply {
+ addRoots(javaRoots, messageCollector)
+ }
}, {
val file = (it as JavaClassImpl).psi.containingFile.virtualFile
if (file in sourcesScope)
@@ -163,21 +296,9 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
library
})
},
- CompilerEnvironment,
+ targetEnvironment = CompilerEnvironment,
builtIns = builtIns
)
-
- val resolverForLibrary = resolverForProject.resolverForModule(library) // Required before module to initialize library properly
- val resolverForModule = resolverForProject.resolverForModule(module)
- val libraryModuleDescriptor = resolverForProject.descriptorForModule(library)
- val moduleDescriptor = resolverForProject.descriptorForModule(module)
- builtIns.initialize(moduleDescriptor, true)
- 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
}
fun loadLanguageVersionSettings(languageVersionString: String?, apiVersionString: String?) {
@@ -197,6 +318,10 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
* $paths: collection of files to add
*/
fun addClasspath(paths: List<File>) {
+ if (analysisPlatform == Platform.js) {
+ configuration.addAll(JSConfigurationKeys.LIBRARIES, paths.map { it.absolutePath })
+ }
+ configuration.addAll(JSConfigurationKeys.LIBRARIES, paths.map { it.absolutePath })
configuration.addJvmClasspathRoots(paths)
}
@@ -205,6 +330,10 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
* $path: path to add
*/
fun addClasspath(path: File) {
+ if (analysisPlatform == Platform.js) {
+ configuration.add(JSConfigurationKeys.LIBRARIES, path.absolutePath)
+ }
+ configuration.add(JSConfigurationKeys.LIBRARIES, path.absolutePath)
configuration.addJvmClasspathRoot(path)
}
diff --git a/core/src/main/kotlin/Analysis/DokkaAnalyzerFacades.kt b/core/src/main/kotlin/Analysis/DokkaAnalyzerFacades.kt
new file mode 100644
index 00000000..082d3968
--- /dev/null
+++ b/core/src/main/kotlin/Analysis/DokkaAnalyzerFacades.kt
@@ -0,0 +1,163 @@
+package org.jetbrains.dokka.Analysis
+
+import org.jetbrains.kotlin.analyzer.*
+import org.jetbrains.kotlin.caches.project.LibraryModuleInfo
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.config.TargetPlatformVersion
+import org.jetbrains.kotlin.container.StorageComponentContainer
+import org.jetbrains.kotlin.container.get
+import org.jetbrains.kotlin.container.useImpl
+import org.jetbrains.kotlin.container.useInstance
+import org.jetbrains.kotlin.context.ModuleContext
+import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
+import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
+import org.jetbrains.kotlin.frontend.di.configureModule
+import org.jetbrains.kotlin.ide.konan.KOTLIN_NATIVE_CURRENT_ABI_VERSION
+import org.jetbrains.kotlin.ide.konan.createPackageFragmentProvider
+import org.jetbrains.kotlin.incremental.components.LookupTracker
+import org.jetbrains.kotlin.js.resolve.JsPlatform
+import org.jetbrains.kotlin.konan.file.File
+import org.jetbrains.kotlin.konan.library.createKonanLibrary
+import org.jetbrains.kotlin.resolve.*
+import org.jetbrains.kotlin.resolve.konan.platform.KonanPlatform
+import org.jetbrains.kotlin.resolve.lazy.ResolveSession
+import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
+import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
+import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
+import org.jetbrains.kotlin.serialization.js.createKotlinJavascriptPackageFragmentProvider
+import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
+
+fun createContainerForLazyResolve(
+ moduleContext: ModuleContext,
+ declarationProviderFactory: DeclarationProviderFactory,
+ bindingTrace: BindingTrace,
+ platform: TargetPlatform,
+ targetPlatformVersion: TargetPlatformVersion,
+ targetEnvironment: TargetEnvironment,
+ languageVersionSettings: LanguageVersionSettings
+): StorageComponentContainer = createContainer("LazyResolve", platform) {
+ configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
+
+ useInstance(declarationProviderFactory)
+ useInstance(languageVersionSettings)
+
+ useImpl<AnnotationResolverImpl>()
+ useImpl<CompilerDeserializationConfiguration>()
+ targetEnvironment.configure(this)
+
+ useImpl<ResolveSession>()
+ useImpl<LazyTopDownAnalyzer>()
+}
+
+
+object DokkaJsAnalyzerFacade : ResolverForModuleFactory() {
+ override fun <M : ModuleInfo> createResolverForModule(
+ moduleDescriptor: ModuleDescriptorImpl,
+ moduleContext: ModuleContext,
+ moduleContent: ModuleContent<M>,
+ platformParameters: PlatformAnalysisParameters,
+ targetEnvironment: TargetEnvironment,
+ resolverForProject: ResolverForProject<M>,
+ languageVersionSettings: LanguageVersionSettings,
+ targetPlatformVersion: TargetPlatformVersion
+ ): ResolverForModule {
+ val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent
+ val project = moduleContext.project
+ val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
+ project,
+ moduleContext.storageManager,
+ syntheticFiles,
+ moduleContentScope,
+ moduleInfo
+ )
+
+ val container = createContainerForLazyResolve(
+ moduleContext,
+ declarationProviderFactory,
+ BindingTraceContext(),
+ JsPlatform,
+ TargetPlatformVersion.NoVersion,
+ targetEnvironment,
+ languageVersionSettings
+ )
+ var packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider
+
+ if (moduleInfo is LibraryModuleInfo && moduleInfo.platform == JsPlatform) {
+ val providers = moduleInfo.getLibraryRoots()
+ .flatMap { KotlinJavascriptMetadataUtils.loadMetadata(it) }
+ .filter { it.version.isCompatible() }
+ .map { metadata ->
+ val (header, packageFragmentProtos) =
+ KotlinJavascriptSerializationUtil.readModuleAsProto(metadata.body, metadata.version)
+ createKotlinJavascriptPackageFragmentProvider(
+ moduleContext.storageManager, moduleDescriptor, header, packageFragmentProtos, metadata.version,
+ container.get(), LookupTracker.DO_NOTHING
+ )
+ }
+
+ if (providers.isNotEmpty()) {
+ packageFragmentProvider = CompositePackageFragmentProvider(listOf(packageFragmentProvider) + providers)
+ }
+ }
+
+ return ResolverForModule(packageFragmentProvider, container)
+ }
+
+ override val targetPlatform: TargetPlatform
+ get() = JsPlatform
+}
+
+object DokkaNativeAnalyzerFacade : ResolverForModuleFactory() {
+ override val targetPlatform: TargetPlatform
+ get() = KonanPlatform
+
+ override fun <M : ModuleInfo> createResolverForModule(
+ moduleDescriptor: ModuleDescriptorImpl,
+ moduleContext: ModuleContext,
+ moduleContent: ModuleContent<M>,
+ platformParameters: PlatformAnalysisParameters,
+ targetEnvironment: TargetEnvironment,
+ resolverForProject: ResolverForProject<M>,
+ languageVersionSettings: LanguageVersionSettings,
+ targetPlatformVersion: TargetPlatformVersion
+ ): ResolverForModule {
+
+ val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
+ moduleContext.project,
+ moduleContext.storageManager,
+ moduleContent.syntheticFiles,
+ moduleContent.moduleContentScope,
+ moduleContent.moduleInfo
+ )
+
+ val container = createContainerForLazyResolve(
+ moduleContext,
+ declarationProviderFactory,
+ BindingTraceContext(),
+ targetPlatform,
+ TargetPlatformVersion.NoVersion,
+ targetEnvironment,
+ languageVersionSettings
+ )
+
+ val packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider
+ val fragmentProviders = mutableListOf(packageFragmentProvider)
+
+ val moduleInfo = moduleContent.moduleInfo
+
+ if (moduleInfo is LibraryModuleInfo) {
+ moduleInfo.getLibraryRoots()
+ .map { createKonanLibrary(File(it), KOTLIN_NATIVE_CURRENT_ABI_VERSION) }
+ .mapTo(fragmentProviders) {
+ it.createPackageFragmentProvider(
+ moduleContext.storageManager,
+ languageVersionSettings,
+ moduleDescriptor
+ )
+ }
+
+ }
+
+ return ResolverForModule(CompositePackageFragmentProvider(fragmentProviders), container)
+ }
+}
diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt
index e18ab6cf..ccafcd12 100644
--- a/core/src/main/kotlin/DokkaBootstrapImpl.kt
+++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt
@@ -2,7 +2,6 @@ package org.jetbrains.dokka
import org.jetbrains.dokka.DokkaConfiguration.PackageOptions
import ru.yole.jkid.deserialization.deserialize
-import java.io.File
import java.util.function.BiConsumer
@@ -44,36 +43,7 @@ class DokkaBootstrapImpl : DokkaBootstrap {
= configure(DokkaProxyLogger(logger), deserialize<DokkaConfigurationImpl>(serializedConfigurationJSON))
fun configure(logger: DokkaLogger, configuration: DokkaConfiguration) = with(configuration) {
- generator = DokkaGenerator(
- logger,
- classpath,
- sourceRoots,
- samples,
- includes,
- moduleName,
- DocumentationOptions(
- outputDir = outputDir,
- outputFormat = format,
- includeNonPublic = includeNonPublic,
- includeRootPackage = includeRootPackage,
- reportUndocumented = reportUndocumented,
- skipEmptyPackages = skipEmptyPackages,
- skipDeprecated = skipDeprecated,
- jdkVersion = jdkVersion,
- generateIndexPages = generateIndexPages,
- sourceLinks = sourceLinks,
- impliedPlatforms = impliedPlatforms,
- perPackageOptions = perPackageOptions,
- externalDocumentationLinks = externalDocumentationLinks,
- noStdlibLink = noStdlibLink,
- noJdkLink = noJdkLink,
- languageVersion = languageVersion,
- apiVersion = apiVersion,
- cacheRoot = cacheRoot,
- suppressedFiles = suppressedFiles.map { File(it) }.toSet(),
- collectInheritedExtensionsFromLibraries = collectInheritedExtensionsFromLibraries
- )
- )
+ generator = DokkaGenerator(configuration, logger)
}
override fun generate() = generator.generate()
diff --git a/core/src/main/kotlin/Formats/FormatDescriptor.kt b/core/src/main/kotlin/Formats/FormatDescriptor.kt
index b497fb0f..4bac8aa0 100644
--- a/core/src/main/kotlin/Formats/FormatDescriptor.kt
+++ b/core/src/main/kotlin/Formats/FormatDescriptor.kt
@@ -25,6 +25,7 @@ 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
diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
index a98002d4..51ceb47e 100644
--- a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
+++ b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
@@ -57,8 +57,8 @@ open class KotlinWebsiteOutputBuilder(
}
}
- override fun appendAsOverloadGroup(to: StringBuilder, platforms: Set<String>, block: () -> Unit) {
- div(to, "overload-group", calculateDataAttributes(platforms), true) {
+ override fun appendAsOverloadGroup(to: StringBuilder, platforms: PlatformsData, block: () -> Unit) {
+ div(to, "overload-group", calculateDataAttributes(platforms.keys), true) {
ensureParagraph()
block()
ensureParagraph()
@@ -159,14 +159,14 @@ open class KotlinWebsiteOutputBuilder(
return "$platformsAttr$kotlinVersionAttr$jreVersionAttr"
}
- override fun appendIndexRow(platforms: Set<String>, block: () -> Unit) {
+ override fun appendIndexRow(platforms: PlatformsData, block: () -> Unit) {
if (platforms.isNotEmpty())
- wrap("<tr${calculateDataAttributes(platforms)}>", "</tr>", block)
+ wrap("<tr${calculateDataAttributes(platforms.keys)}>", "</tr>", block)
else
appendTableRow(block)
}
- override fun appendPlatforms(platforms: Set<String>) {
+ override fun appendPlatforms(platforms: PlatformsData) {
}
}
diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt
index 6ced75b5..86bc9df9 100644
--- a/core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt
+++ b/core/src/main/kotlin/Formats/KotlinWebsiteHtmlFormatService.kt
@@ -3,7 +3,6 @@ package org.jetbrains.dokka
import com.google.inject.Inject
import com.google.inject.name.Named
import org.jetbrains.dokka.Utilities.impliedPlatformsName
-import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import java.io.File
@@ -20,7 +19,7 @@ open class KotlinWebsiteHtmlOutputBuilder(
generator: NodeLocationAwareGenerator,
languageService: LanguageService,
extension: String,
- impliedPlatforms: List<String>,
+ val impliedPlatforms: List<String>,
templateService: HtmlTemplateService
) : HtmlOutputBuilder(to, location, generator, languageService, extension, impliedPlatforms, templateService) {
private var needHardLineBreaks = false
@@ -60,7 +59,7 @@ open class KotlinWebsiteHtmlOutputBuilder(
}
}
- override fun appendAsOverloadGroup(to: StringBuilder, platforms: Set<String>, block: () -> Unit) {
+ override fun appendAsOverloadGroup(to: StringBuilder, platforms: PlatformsData, block: () -> Unit) {
div(to, "overload-group", calculateDataAttributes(platforms)) {
block()
}
@@ -69,27 +68,29 @@ open class KotlinWebsiteHtmlOutputBuilder(
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\">")
- body()
- to.appendln("</table>")
+ //to.appendln("<table class=\"api-docs-table\">")
+ div(to, "api-declarations-list") {
+ body()
+ }
+ //to.appendln("</table>")
}
override fun appendTableBody(body: () -> Unit) {
- to.appendln("<tbody>")
+ //to.appendln("<tbody>")
body()
- to.appendln("</tbody>")
+ //to.appendln("</tbody>")
}
override fun appendTableRow(body: () -> Unit) {
- to.appendln("<tr>")
+ //to.appendln("<tr>")
body()
- to.appendln("</tr>")
+ //to.appendln("</tr>")
}
override fun appendTableCell(body: () -> Unit) {
- to.appendln("<td>")
+// to.appendln("<td>")
body()
- to.appendln("\n</td>")
+// to.appendln("\n</td>")
}
override fun appendSymbol(text: String) {
@@ -122,34 +123,79 @@ open class KotlinWebsiteHtmlOutputBuilder(
else -> "identifier"
}
- fun calculateDataAttributes(platforms: Set<String>): String {
- fun String.isKotlinVersion() = this.startsWith("Kotlin")
- fun String.isJREVersion() = this.startsWith("JRE")
- val kotlinVersion = platforms.singleOrNull(String::isKotlinVersion)
- val jreVersion = platforms.singleOrNull(String::isJREVersion)
- val targetPlatforms = platforms.filterNot { it.isKotlinVersion() || it.isJREVersion() }
+ 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) }
+ )
+ }
- val kotlinVersionAttr = kotlinVersion?.let { " data-kotlin-version=\"$it\"" } ?: ""
- val jreVersionAttr = jreVersion?.let { " data-jre-version=\"$it\"" } ?: ""
- val platformsAttr = targetPlatforms.ifNotEmpty { " data-platform=\"${targetPlatforms.joinToString()}\"" } ?: ""
- return "$platformsAttr$kotlinVersionAttr$jreVersionAttr"
+ 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: Set<String>, block: () -> Unit) {
- if (platforms.isNotEmpty())
- wrap("<tr${calculateDataAttributes(platforms)}>", "</tr>", block)
- else
- appendTableRow(block)
+ 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: Set<String>) {}
+ 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") {
+ div(to, "sample", otherAttributes = " data-min-compiler-version=\"1.3\"") {
appendBlockCode(language) {
imports()
wrap("\n\nfun main(args: Array<String>) {".htmlEscape(), "}") {
@@ -169,6 +215,29 @@ open class KotlinWebsiteHtmlOutputBuilder(
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(
@@ -184,3 +253,6 @@ class KotlinWebsiteHtmlFormatService @Inject constructor(
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/PackageListService.kt b/core/src/main/kotlin/Formats/PackageListService.kt
index 7b68098e..e675d927 100644
--- a/core/src/main/kotlin/Formats/PackageListService.kt
+++ b/core/src/main/kotlin/Formats/PackageListService.kt
@@ -32,10 +32,13 @@ class DefaultPackageListService @Inject constructor(
node.members.forEach { visit(it, relocated = true) }
}
NodeKind.GroupNode -> {
- //only children of top-level GN records interesting for us, since link to top-level ones should point to GN
- node.members.forEach { it.members.forEach { visit(it, relocated = true) } }
- //record signature of GN as signature of type alias and class merged to GN, so link to it should point to GN
- node.detailOrNull(NodeKind.Signature)?.let { visit(it, relocated = true) }
+ 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) {
diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt
index 410de281..04810498 100644
--- a/core/src/main/kotlin/Formats/StructuredFormatService.kt
+++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt
@@ -1,18 +1,59 @@
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,
- val impliedPlatforms: List<String>) : FormattedOutputBuilder {
-
- protected fun DocumentationNode.location() = generator.location(this)
+ impliedPlatforms: List<String>) : FormattedOutputBuilder {
protected fun wrap(prefix: String, suffix: String, body: () -> Unit) {
to.append(prefix)
@@ -83,6 +124,14 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
+ 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)
}
@@ -95,6 +144,10 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
appendText(text)
}
+ open fun appendAsNodeDescription(platforms: PlatformsData, block: () -> Unit) {
+ block()
+ }
+
fun appendEntity(text: String) {
to.append(text)
}
@@ -158,7 +211,7 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
is ContentNodeLink -> {
val node = content.node
- val linkTo = if (node != null) locationHref(location, node) else "#"
+ val linkTo = if (node != null) locationHref(location, node, generator) else "#"
appendLinkIfNotThisPage(linkTo, content)
}
is ContentExternalLink -> appendLinkIfNotThisPage(content.href, content)
@@ -196,31 +249,19 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
- 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 {
- if (to.owner?.kind == NodeKind.GroupNode)
- return link(from, to.owner!!, extension, name)
-
- if (from.owner?.kind == NodeKind.GroupNode)
- return link(from.owner!!, to, extension, name)
+ open fun link(
+ from: DocumentationNode,
+ to: DocumentationNode,
+ name: (DocumentationNode) -> String = DocumentationNode::name
+ ): FormatLink = link(from, to, extension, name)
- return FormatLink(name(to), from.location().relativePathTo(to.location()))
- }
-
- fun locationHref(from: Location, to: DocumentationNode): String {
- val topLevelPage = to.references(RefKind.TopLevelPage).singleOrNull()?.to
- if (topLevelPage != null) {
- val signature = to.detailOrNull(NodeKind.Signature)
- return from.relativePathTo(topLevelPage.location(), signature?.name ?: to.name)
- }
- return from.relativePathTo(to.location())
- }
+ 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
@@ -229,18 +270,25 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
block()
}
- protected open fun appendAsOverloadGroup(to: StringBuilder, platforms: Set<String>, block: () -> Unit) {
+ protected open fun appendAsOverloadGroup(to: StringBuilder, platforms: PlatformsData, block: () -> Unit) {
block()
}
- protected open fun appendIndexRow(platforms: Set<String>, block: () -> Unit) {
+ protected open fun appendIndexRow(platforms: PlatformsData, block: () -> Unit) {
appendTableRow(block)
}
- protected open fun appendPlatforms(platforms: Set<String>) {
+ protected open fun appendPlatformsAsText(platforms: PlatformsData) {
+ if (platforms.isNotEmpty()) {
+ appendLine()
+ appendText(platforms.keys.joinToString(prefix = "(", postfix = ")"))
+ }
+ }
+
+ protected open fun appendPlatforms(platforms: PlatformsData) {
if (platforms.isNotEmpty()) {
appendLine()
- appendText(platforms.joinToString(prefix = "(", postfix = ")"))
+ appendText(platforms.keys.joinToString(prefix = "(", postfix = ")"))
}
}
@@ -289,7 +337,6 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
val packageName = if (singleNode.name.isEmpty()) "<root>" else singleNode.name
appendHeader(2) { appendText("Package $packageName") }
}
- singleNode.appendPlatforms()
appendContent(singleNode.content)
} else {
val breakdownByName = nodes.groupBy { node -> node.name }
@@ -302,45 +349,136 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
private fun appendDocumentation(overloads: Iterable<DocumentationNode>, isSingleNode: Boolean) {
- val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node -> node.content }
+ val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node ->
+ when (node.kind) {
+ NodeKind.GroupNode -> node.origins.map { it.content }
+ else -> node.content
+ }
+ }
if (breakdownBySummary.size == 1) {
- formatOverloadGroup(breakdownBySummary.values.single(), isSingleNode)
+ val node = breakdownBySummary.values.single()
+ appendAsNodeDescription(effectivePlatformsForMembers(node)) {
+ formatOverloadGroup(node, isSingleNode)
+ }
} else {
for ((_, items) in breakdownBySummary) {
-
- appendAsOverloadGroup(to, platformsOfItems(items)) {
+ 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 {
+ if (!item.content.isEmpty()) {
+ 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()
- item.appendPlatforms()
}
- // All items have exactly the same documentation, so we can use any item to render it
- val item = items.first()
- item.details(NodeKind.OverloadGroupNote).forEach {
- appendContent(it.content)
+ }
+
+ fun renderGroupNode(item: DocumentationNode, isSingleNode: Boolean, withPlatforms: Boolean = true) {
+ // TODO: use summarizesignatures
+ val groupBySignature = item.origins.groupBy {
+ languageService.render(it)
}
- appendContent(item.content.summary)
- item.appendDescription()
+ 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() {
@@ -355,7 +493,7 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
overrides.forEach {
appendParagraph {
to.append("Overrides ")
- val location = location().relativePathTo(it.location())
+ val location = generator.relativePathToLocation(this, it)
appendLink(FormatLink(it.owner!!.name + "." + it.name, location))
}
@@ -367,82 +505,95 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
val deprecationParameter = deprecation!!.details(NodeKind.Parameter).firstOrNull()
val deprecationValue = deprecationParameter?.details(NodeKind.Value)?.firstOrNull()
appendLine()
- if (deprecationValue != null) {
- appendStrong { to.append("Deprecated:") }
- appendText(" " + deprecationValue.name.removeSurrounding("\""))
- appendLine()
- appendLine()
- } else if (deprecation?.content != Content.Empty) {
- appendStrong { to.append("Deprecated:") }
- to.append(" ")
- appendContent(deprecation!!.content)
- } else {
- appendStrong { to.append("Deprecated") }
- appendLine()
- appendLine()
- }
- }
- }
-
- private fun DocumentationNode.appendPlatforms() {
- val platforms = if (isModuleOrPackage())
- platformsToShow.toSet() + platformsOfItems(members)
- else
- platformsToShow
-
- if (platforms.isEmpty()) return
-
- appendParagraph {
- appendStrong { to.append("Platform and version requirements:") }
- to.append(" " + platforms.joinToString())
- }
- }
-
- protected fun platformsOfItems(items: List<DocumentationNode>): Set<String> {
- val platforms = items.asSequence().map {
- when (it.kind) {
- NodeKind.ExternalClass, NodeKind.Package, NodeKind.Module, NodeKind.GroupNode -> platformsOfItems(it.members)
- else -> it.platformsToShow.toSet()
- }
- }
-
- fun String.isKotlinVersion() = this.startsWith("Kotlin")
-
- // 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()) {
- val allKotlinVersions = (kotlinVersions + otherKotlinVersion).distinct()
-
- val minVersion = allKotlinVersions.min()!!
- val resultVersion = when {
- allKotlinVersions.size == 1 -> allKotlinVersions.single()
- minVersion.endsWith("+") -> minVersion
- else -> minVersion + "+"
+ 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()
}
-
- result.intersect(otherPlatforms) + resultVersion
- } else {
- result.intersect(platformsOfItem)
}
}
}
- val DocumentationNode.platformsToShow: List<String>
- get() = platforms.let { if (it.containsAll(impliedPlatforms)) it - impliedPlatforms else it }
- private fun DocumentationNode.appendDescription() {
- if (content.description != ContentEmpty) {
- appendContent(content.description)
- }
- content.getSectionsWithSubjects().forEach {
+// 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 content.sections.filter { it.subjectName == null }) {
+ for (section in sections.filter { it.subjectName == null }) {
appendSectionWithTag(section)
}
}
@@ -461,6 +612,38 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
}
+
+ 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)) {
@@ -473,39 +656,37 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
appendLine()
appendHeader { appendText(node.name) }
- fun DocumentationNode.priority(): Int = when (kind) {
- NodeKind.TypeAlias -> 1
- NodeKind.Class -> 2
- else -> 3
- }
-
- for (member in node.members.sortedBy(DocumentationNode::priority)) {
-
- appendAsOverloadGroup(to, platformsOfItems(listOf(member))) {
- formatSubNodeOfGroup(member)
- }
+ appendAsNodeDescription(effectivePlatformsForNode(node)) {
+ renderGroupNode(node, true)
+ appendOriginsGroupByContent(node)
}
- }
- fun formatSubNodeOfGroup(member: DocumentationNode) {
- SingleNodePageBuilder(member, true).build()
+ SectionsBuilder(node).build()
}
}
-
- inner class SingleNodePageBuilder(val node: DocumentationNode, noHeader: Boolean = false)
- : PageBuilder(listOf(node), noHeader) {
-
+//
+// 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() {
- super.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).flatMap { it.members.filter(predicate) }
+ return members.filter(predicate) + members(NodeKind.GroupNode).filter{ it.origins.isNotEmpty() && predicate(it.origins.first()) }
}
fun DocumentationNode.membersOrGroupMembers(kind: NodeKind): List<DocumentationNode> {
@@ -513,20 +694,19 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
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("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("Type Aliases", node.membersOrGroupMembers(NodeKind.TypeAlias))
appendSection("Extensions for External Classes", node.members(NodeKind.ExternalClass))
- appendSection("Enum Values", node.members(NodeKind.EnumItem), sortMembers = false, omitSamePlatforms = true)
- appendSection("Constructors", node.members(NodeKind.Constructor), omitSamePlatforms = true)
- appendSection("Properties", node.members(NodeKind.Property), omitSamePlatforms = true)
+ 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.members(NodeKind.Function), omitSamePlatforms = true)
+ appendSection("Functions", node.membersOrGroupMembers(NodeKind.Function), omitSamePlatforms = true)
appendSection("Inherited Functions", node.inheritedMembers(NodeKind.Function))
- appendSection("Companion Object Properties", node.members(NodeKind.CompanionObjectProperty), omitSamePlatforms = true)
+ appendSection("Companion Object Properties", node.membersOrGroupMembers(NodeKind.CompanionObjectProperty), omitSamePlatforms = true)
appendSection("Inherited Companion Object Properties", node.inheritedCompanionObjectMembers(NodeKind.Property))
- appendSection("Companion Object Functions", node.members(NodeKind.CompanionObjectFunction), omitSamePlatforms = true)
+ 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(
@@ -561,7 +741,7 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
if (node.kind == NodeKind.Module) {
appendHeader(3) { to.append("Index") }
node.members(NodeKind.AllTypes).singleOrNull()?.let { allTypes ->
- appendLink(link(node, allTypes, { "All Types" }))
+ appendLink(link(node, allTypes) { "All Types" })
}
}
}
@@ -582,26 +762,27 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
appendTable("Name", "Summary") {
appendTableBody {
for ((memberLocation, members) in membersMap) {
- val elementPlatforms = platformsOfItems(members, omitSamePlatforms)
- val platforms = if (platformsBasedOnMembers)
- members.flatMapTo(mutableSetOf()) { platformsOfItems(it.members) } + elementPlatforms
- else
- elementPlatforms
+ val platforms = effectivePlatformsForMembers(members)
+// val platforms = if (platformsBasedOnMembers)
+// members.flatMapTo(mutableSetOf()) { platformsOfItems(it.members) } + elementPlatforms
+// else
+// elementPlatforms
+
+ val summarized = computeSummarySignatures(members)
+
+
appendIndexRow(platforms) {
appendTableCell {
- appendParagraph {
- appendLink(memberLocation)
- if (members.singleOrNull()?.kind != NodeKind.ExternalClass) {
- appendPlatforms(platforms)
- }
+ if (summarized.platformPlacement == Summarized.PlatformPlacement.Row) {
+ appendPlatforms(platforms)
}
- }
- appendTableCell {
- val breakdownBySummary = members.groupBy { it.summary }
- for ((summary, items) in breakdownBySummary) {
- appendSummarySignatures(items)
- appendContent(summary)
+ appendHeader(level = 4) {
+ appendLink(memberLocation)
+// if (members.singleOrNull()?.kind != NodeKind.ExternalClass) {
+// appendPlatforms(platforms)
+// }
}
+ appendSummarySignatures(summarized)
}
}
}
@@ -609,35 +790,90 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
- private fun platformsOfItems(items: List<DocumentationNode>, omitSamePlatforms: Boolean = true): Set<String> {
- val platforms = platformsOfItems(items)
- if (platforms.isNotEmpty() && (platforms != node.platformsToShow.toSet() || !omitSamePlatforms)) {
- return platforms
+//
+// 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)
+ appendSoftLineBreak()
+ for (signature in summary.signatures) {
+ appendSignatures(
+ signature,
+ summarized.platformPlacement == Summarized.PlatformPlacement.Signature
+ )
+ }
+ }
+
}
- return emptySet()
}
- private fun appendSummarySignatures(items: List<DocumentationNode>) {
- val summarySignature = languageService.summarizeSignatures(items)
- if (summarySignature != null) {
- appendAsSignature(summarySignature) {
- summarySignature.appendSignature()
+ 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)
}
- return
- }
- val renderedSignatures = items.map { languageService.render(it, RenderMode.SUMMARY) }
- renderedSignatures.subList(0, renderedSignatures.size - 1).forEach {
- appendAsSignature(it) {
- it.appendSignature()
+ appendAsSignature(signature.content) {
+ signature.content.appendSignature()
}
- appendLine()
- }
- appendAsSignature(renderedSignatures.last()) {
- renderedSignatures.last().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)) {
@@ -648,21 +884,23 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
appendTable("Name", "Summary") {
appendTableBody {
for (type in node.members) {
- appendTableRow {
- appendTableCell {
+ val platforms = effectivePlatformsForNode(type)
+ appendIndexRow(platforms) {
+ appendPlatforms(platforms)
+ appendHeader(level = 5) {
appendLink(link(node, type) {
if (it.kind == NodeKind.ExternalClass) it.name else it.qualifiedName()
})
- if (type.kind == NodeKind.ExternalClass) {
- val packageName = type.owner?.name
- if (packageName != null) {
- appendText(" (extensions in package $packageName)")
- }
- }
}
- appendTableCell {
- appendContent(type.summary)
+
+ if (type.kind == NodeKind.ExternalClass) {
+ val packageName = type.owner?.name
+ if (packageName != null) {
+ appendText(" (extensions in package $packageName)")
+ }
}
+
+ appendContent(type.summary)
}
}
}
@@ -687,3 +925,78 @@ abstract class StructuredFormatService(val generator: NodeLocationAwareGenerator
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()!!
+}
+
+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
index c36f98eb..3c92d8ff 100644
--- a/core/src/main/kotlin/Formats/YamlOutlineService.kt
+++ b/core/src/main/kotlin/Formats/YamlOutlineService.kt
@@ -13,7 +13,7 @@ class YamlOutlineService @Inject constructor(
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.location(node).path}")
+ to.appendln("$indent url: ${generator.relativePathToLocation(node.path.first(), node)}")
}
override fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) {
diff --git a/core/src/main/kotlin/Generation/DocumentationMerger.kt b/core/src/main/kotlin/Generation/DocumentationMerger.kt
new file mode 100644
index 00000000..f58d2f8e
--- /dev/null
+++ b/core/src/main/kotlin/Generation/DocumentationMerger.kt
@@ -0,0 +1,217 @@
+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 }
+ }
+ }
+
+ val groupNode = 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 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
index a5279772..90d7cfcc 100644
--- a/core/src/main/kotlin/Generation/DokkaGenerator.kt
+++ b/core/src/main/kotlin/Generation/DokkaGenerator.kt
@@ -7,9 +7,10 @@ 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.DokkaConfiguration.SourceRoot
+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
@@ -18,63 +19,74 @@ 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 logger: DokkaLogger,
- val classpath: List<String>,
- val sources: List<SourceRoot>,
- val samples: List<String>,
- val includes: List<String>,
- val moduleName: String,
- val options: DocumentationOptions) {
+class DokkaGenerator(val dokkaConfiguration: DokkaConfiguration,
+ val logger: DokkaLogger) {
- private val documentationModule = DocumentationModule(moduleName)
+ private val documentationModules: MutableList<DocumentationModule> = mutableListOf()
+ private val globalInjector = Guice.createInjector(DokkaRunModule(dokkaConfiguration))
- fun generate() {
- val sourcesGroupedByPlatform = sources.groupBy { it.platforms.firstOrNull() }
- for ((platform, roots) in sourcesGroupedByPlatform) {
- appendSourceModule(platform, roots)
+
+ fun generate() = with(dokkaConfiguration) {
+
+
+ for (pass in passesConfigurations) {
+ val documentationModule = DocumentationModule(pass.moduleName)
+ appendSourceModule(pass, documentationModule)
+ documentationModules.add(documentationModule)
}
- documentationModule.prepareForGeneration(options)
+
+ val totalDocumentationModule = DocumentationMerger(documentationModules, logger).merge()
+ totalDocumentationModule.prepareForGeneration(dokkaConfiguration)
val timeBuild = measureTimeMillis {
logger.info("Generating pages... ")
- val outputInjector = Guice.createInjector(DokkaOutputModule(options, logger))
- outputInjector.getInstance(Generator::class.java).buildAll(documentationModule)
+ 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(defaultPlatform: String?, sourceRoots: List<SourceRoot>) {
- val sourcePaths = sourceRoots.map { it.path }
- val environment = createAnalysisEnvironment(sourcePaths)
+ 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(options.outputDir)}")
+ 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 = defaultPlatform?.let { listOf(it) }.orEmpty()
+ 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) } }
- return sourceRoot?.platforms ?: defaultPlatformAsList
+// 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 = Guice.createInjector(
- DokkaAnalysisModule(environment, options, defaultPlatformsProvider, documentationModule.nodeRefGraph, logger))
+ val injector = globalInjector.createChildInjector(
+ DokkaAnalysisModule(environment, dokkaConfiguration, defaultPlatformsProvider, documentationModule.nodeRefGraph, passConfiguration, logger))
- buildDocumentationModule(injector, documentationModule, { isNotSample(it) }, includes)
+ buildDocumentationModule(injector, documentationModule, { isNotSample(it, passConfiguration.samples) }, includes)
val timeAnalyse = System.currentTimeMillis() - startAnalyse
logger.info("done in ${timeAnalyse / 1000} secs")
@@ -82,26 +94,31 @@ class DokkaGenerator(val logger: DokkaLogger,
Disposer.dispose(environment)
}
- fun createAnalysisEnvironment(sourcePaths: List<String>): AnalysisEnvironment {
- val environment = AnalysisEnvironment(DokkaMessageCollector(logger))
+ fun createAnalysisEnvironment(
+ sourcePaths: List<String>,
+ passConfiguration: DokkaConfiguration.PassConfiguration
+ ): AnalysisEnvironment {
+ val environment = AnalysisEnvironment(DokkaMessageCollector(logger), passConfiguration.analysisPlatform)
environment.apply {
- addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
+ if (analysisPlatform == Platform.jvm) {
+ addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
+ }
// addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath())
- for (element in this@DokkaGenerator.classpath) {
+ for (element in passConfiguration.classpath) {
addClasspath(File(element))
}
addSources(sourcePaths)
- addSources(this@DokkaGenerator.samples)
+ addSources(passConfiguration.samples)
- loadLanguageVersionSettings(options.languageVersion, options.apiVersion)
+ loadLanguageVersionSettings(passConfiguration.languageVersion, passConfiguration.apiVersion)
}
return environment
}
- fun isNotSample(file: PsiFile): Boolean {
+ private fun isNotSample(file: PsiFile, samples: List<String>): Boolean {
val sourceFile = File(file.virtualFile!!.path)
return samples.none { sample ->
val canonicalSample = File(sample).canonicalPath
@@ -140,9 +157,7 @@ fun buildDocumentationModule(injector: Injector,
val analyzer = resolutionFacade.getFrontendService(LazyTopDownAnalyzer::class.java)
analyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, fragmentFiles)
- val fragments = fragmentFiles
- .map { resolutionFacade.resolveSession.getPackageFragment(it.packageFqName) }
- .filterNotNull()
+ val fragments = fragmentFiles.mapNotNull { resolutionFacade.resolveSession.getPackageFragment(it.packageFqName) }
.distinct()
val packageDocs = injector.getInstance(PackageDocs::class.java)
@@ -205,4 +220,4 @@ fun KotlinCoreEnvironment.getJavaSourceFiles(): List<PsiJavaFile> {
}
}
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
index b7c6cf63..ee2c068e 100644
--- a/core/src/main/kotlin/Generation/FileGenerator.kt
+++ b/core/src/main/kotlin/Generation/FileGenerator.kt
@@ -2,19 +2,52 @@ package org.jetbrains.dokka
import com.google.inject.Inject
import com.google.inject.name.Named
-import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
import java.io.File
-import java.io.FileOutputStream
import java.io.IOException
-import java.io.OutputStreamWriter
+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 options: DocumentationOptions
+ @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))
}
@@ -23,45 +56,36 @@ class FileGenerator @Inject constructor(@Named("outputDir") override val root: F
return File(root, relativePathToNode(node)).appendExtension(extension)
}
- fun locationWithoutExtension(node: DocumentationNode): FileLocation {
+ 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.parentFile?.mkdirsOrFail()
- try {
- FileOutputStream(file).use {
- OutputStreamWriter(it, Charsets.UTF_8).use {
- it.write(formatService.format(location(items.first()), items))
- }
- }
- } catch (e: Throwable) {
- println(e)
+ file.writeFileAndAssert("pages") { it ->
+ it.writeText(formatService.format(location(items.first()), items))
}
- buildPages(items.flatMap { it.members })
+
+ 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) }) {
- val file = outlineService.getOutlineFileName(location)
- file.parentFile?.mkdirsOrFail()
- FileOutputStream(file).use {
- OutputStreamWriter(it, Charsets.UTF_8).use {
- it.write(outlineService.formatOutline(location, items))
- }
+ outlineService.getOutlineFileName(location).writeFileAndAssert("outlines") { file ->
+ file.writeText(outlineService.formatOutline(location, items))
}
}
}
override fun buildSupportFiles() {
formatService.enumerateSupportFiles { resource, targetPath ->
- FileOutputStream(File(root, relativePathToNode(listOf(targetPath), false))).use {
- javaClass.getResourceAsStream(resource).copyTo(it)
+ File(root, relativePathToNode(listOf(targetPath), false)).writeFileAndAssert("support files") { file ->
+ file.outputStream().use {
+ javaClass.getResourceAsStream(resource).copyTo(it)
+ }
}
}
}
@@ -74,16 +98,11 @@ class FileGenerator @Inject constructor(@Named("outputDir") override val root: F
val moduleRoot = location(module).file.parentFile
val packageListFile = File(moduleRoot, "package-list")
- packageListFile.writeText("\$dokka.format:${options.outputFormat}\n" +
- packageListService!!.formatPackageList(module as DocumentationModule))
- }
+ val text = "\$dokka.format:${dokkaConfiguration.format}\n" + packageListService!!.formatPackageList(module as DocumentationModule)
+ packageListFile.writeFileAndAssert("packages-list") { file ->
+ file.writeText(text)
+ }
+ }
}
-
}
-
-private fun File.mkdirsOrFail() {
- if (!mkdirs() && !exists()) {
- throw IOException("Failed to create directory $this")
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Generation/configurationImpl.kt b/core/src/main/kotlin/Generation/configurationImpl.kt
index eecf122e..46174198 100644
--- a/core/src/main/kotlin/Generation/configurationImpl.kt
+++ b/core/src/main/kotlin/Generation/configurationImpl.kt
@@ -18,14 +18,11 @@ data class SourceLinkDefinitionImpl(override val path: String,
}
}
-class SourceRootImpl(path: String, override val platforms: List<String> = emptyList()) : SourceRoot {
+class SourceRootImpl(path: String) : SourceRoot {
override val path: String = File(path).absolutePath
companion object {
- fun parseSourceRoot(sourceRoot: String): SourceRoot {
- val components = sourceRoot.split("::", limit = 2)
- return SourceRootImpl(components.last(), if (components.size == 1) listOf() else components[0].split(','))
- }
+ fun parseSourceRoot(sourceRoot: String): SourceRoot = SourceRootImpl(sourceRoot)
}
}
@@ -36,29 +33,48 @@ data class PackageOptionsImpl(override val prefix: String,
override val suppress: Boolean = false) : DokkaConfiguration.PackageOptions
data class DokkaConfigurationImpl(
- override val moduleName: String,
- override val classpath: List<String>,
- override val sourceRoots: List<SourceRootImpl>,
- override val samples: List<String>,
- override val includes: List<String>,
- override val outputDir: String,
- override val format: 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 generateIndexPages: Boolean,
- override val sourceLinks: List<SourceLinkDefinitionImpl>,
- override val impliedPlatforms: List<String>,
- override val perPackageOptions: List<PackageOptionsImpl>,
- override val externalDocumentationLinks: List<ExternalDocumentationLinkImpl>,
- override val noStdlibLink: Boolean,
- override val noJdkLink: Boolean,
- override val cacheRoot: String?,
- override val suppressedFiles: List<String>,
- override val languageVersion: String?,
- override val apiVersion: String?,
- override val collectInheritedExtensionsFromLibraries: Boolean
-) : DokkaConfiguration \ No newline at end of file
+ override val outputDir: String = "",
+ override val format: String = "html",
+ override val generateIndexPages: Boolean = false,
+ override val cacheRoot: String? = null,
+ override val impliedPlatforms: List<String> = listOf(),
+ override val passesConfigurations: List<DokkaConfiguration.PassConfiguration> = listOf()
+) : DokkaConfiguration
+
+class PassConfigurationImpl (
+ override val classpath: List<String> = listOf(),
+ override val moduleName: String = "",
+ override val sourceRoots: List<SourceRoot> = listOf(),
+ override val samples: List<String> = listOf(),
+ override val includes: List<String> = listOf(),
+ 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<SourceLinkDefinition> = listOf(),
+ override val perPackageOptions: List<DokkaConfiguration.PackageOptions> = listOf(),
+ externalDocumentationLinks: List<DokkaConfiguration.ExternalDocumentationLink> = listOf(),
+ 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> = listOf(),
+ override val collectInheritedExtensionsFromLibraries: Boolean = false,
+ override val analysisPlatform: Platform = Platform.DEFAULT,
+ override val targets: List<String> = listOf(),
+ override val sinceKotlin: String = "1.0"
+): 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/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
index f1f170d7..98d56856 100644
--- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
+++ b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
@@ -14,7 +14,6 @@ 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
-import java.io.File
fun getSignature(element: PsiElement?) = when(element) {
is PsiPackage -> element.qualifiedName
@@ -53,24 +52,24 @@ interface JavaDocumentationBuilder {
}
class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
- private val options: DocumentationOptions
+ private val passConfiguration: DokkaConfiguration.PassConfiguration
private val refGraph: NodeReferenceGraph
private val docParser: JavaDocumentationParser
@Inject constructor(
- options: DocumentationOptions,
- refGraph: NodeReferenceGraph,
- logger: DokkaLogger,
- signatureProvider: ElementSignatureProvider,
- externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
+ passConfiguration: DokkaConfiguration.PassConfiguration,
+ refGraph: NodeReferenceGraph,
+ logger: DokkaLogger,
+ signatureProvider: ElementSignatureProvider,
+ externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
) {
- this.options = options
+ this.passConfiguration = passConfiguration
this.refGraph = refGraph
this.docParser = JavadocParser(refGraph, logger, signatureProvider, externalDocumentationLinkResolver)
}
- constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) {
- this.options = options
+ constructor(passConfiguration: DokkaConfiguration.PassConfiguration, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) {
+ this.passConfiguration = passConfiguration
this.refGraph = refGraph
this.docParser = docParser
}
@@ -152,7 +151,7 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
}
}
- private fun skipFile(javaFile: PsiJavaFile): Boolean = options.effectivePackageOptions(javaFile.packageName).suppress
+ private fun skipFile(javaFile: PsiJavaFile): Boolean = passConfiguration.effectivePackageOptions(javaFile.packageName).suppress
private fun skipElement(element: Any) =
skipElementByVisibility(element) ||
@@ -162,13 +161,13 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
private fun skipElementByVisibility(element: Any): Boolean =
element is PsiModifierListOwner &&
element !is PsiParameter &&
- !(options.effectivePackageOptions((element.containingFile as? PsiJavaFile)?.packageName ?: "").includeNonPublic) &&
+ !(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 && File(element.containingFile.virtualFile.path).absoluteFile in options.suppressedFiles
+ element is PsiElement && element.containingFile.virtualFile.path in passConfiguration.suppressedFiles
private fun PsiElement.isInternal(): Boolean {
val ktElement = (this as? KtLightElement<*, *>)?.kotlinOrigin ?: return false
diff --git a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
index d73bef4a..c3a84e57 100644
--- a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
@@ -10,7 +10,7 @@ class DeclarationLinkResolver
@Inject constructor(val resolutionFacade: DokkaResolutionFacade,
val refGraph: NodeReferenceGraph,
val logger: DokkaLogger,
- val options: DocumentationOptions,
+ val passConfiguration: DokkaConfiguration.PassConfiguration,
val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver,
val elementSignatureProvider: ElementSignatureProvider) {
@@ -63,7 +63,7 @@ class DeclarationLinkResolver
if (symbol is CallableMemberDescriptor && symbol.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
return symbol.overriddenDescriptors.firstOrNull()
}
- if (symbol is TypeAliasDescriptor && !symbol.isDocumented(options)) {
+ 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
index d1f98184..ddd8a32a 100644
--- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
+++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
class DescriptorDocumentationParser
- @Inject constructor(val options: DocumentationOptions,
+ @Inject constructor(val options: DokkaConfiguration.PassConfiguration,
val logger: DokkaLogger,
val linkResolver: DeclarationLinkResolver,
val resolutionFacade: DokkaResolutionFacade,
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index 38804e39..e3f7c35b 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -3,9 +3,10 @@ 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.*
+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
@@ -32,64 +33,13 @@ 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 java.io.File
-import java.nio.file.Path
-import java.nio.file.Paths
import com.google.inject.name.Named as GuiceNamed
-class DocumentationOptions(val outputDir: String,
- val outputFormat: String,
- includeNonPublic: Boolean = false,
- val includeRootPackage: Boolean = false,
- reportUndocumented: Boolean = true,
- val skipEmptyPackages: Boolean = true,
- skipDeprecated: Boolean = false,
- jdkVersion: Int = 6,
- val generateIndexPages: Boolean = true,
- val sourceLinks: List<SourceLinkDefinition> = emptyList(),
- val impliedPlatforms: List<String> = emptyList(),
- // Sorted by pattern length
- perPackageOptions: List<PackageOptions> = emptyList(),
- externalDocumentationLinks: List<ExternalDocumentationLink> = emptyList(),
- noStdlibLink: Boolean,
- noJdkLink: Boolean = false,
- val languageVersion: String?,
- val apiVersion: String?,
- cacheRoot: String? = null,
- val suppressedFiles: Set<File> = emptySet(),
- val collectInheritedExtensionsFromLibraries: Boolean = false) {
- init {
- if (perPackageOptions.any { it.prefix == "" })
- throw IllegalArgumentException("Please do not register packageOptions with all match pattern, use global settings instead")
- }
-
- val perPackageOptions = perPackageOptions.sortedByDescending { it.prefix.length }
- val rootPackageOptions = PackageOptionsImpl("", includeNonPublic, reportUndocumented, skipDeprecated)
-
- fun effectivePackageOptions(pack: String): PackageOptions = perPackageOptions.firstOrNull { pack == it.prefix || pack.startsWith(it.prefix + ".") } ?: rootPackageOptions
- fun effectivePackageOptions(pack: FqName): PackageOptions = effectivePackageOptions(pack.asString())
-
- val defaultLinks = run {
- val links = mutableListOf<ExternalDocumentationLink>()
- if (!noJdkLink)
- links += ExternalDocumentationLink.Builder("https://docs.oracle.com/javase/$jdkVersion/docs/api/").build()
-
- if (!noStdlibLink)
- links += ExternalDocumentationLink.Builder("https://kotlinlang.org/api/latest/jvm/stdlib/").build()
- links
- }
-
- val externalDocumentationLinks = defaultLinks + externalDocumentationLinks
-
- val cacheRoot: Path? = when {
- cacheRoot == "default" -> Paths.get(System.getProperty("user.home"), ".cache", "dokka")
- cacheRoot != null -> Paths.get(cacheRoot)
- else -> null
- }
-}
-
private fun isExtensionForExternalClass(extensionFunctionDescriptor: DeclarationDescriptor,
extensionReceiverDescriptor: DeclarationDescriptor,
allFqNames: Collection<FqName>): Boolean {
@@ -119,7 +69,7 @@ val ignoredSupertypes = setOf(
class DocumentationBuilder
@Inject constructor(val resolutionFacade: DokkaResolutionFacade,
val descriptorDocumentationParser: DescriptorDocumentationParser,
- val options: DocumentationOptions,
+ val passConfiguration: DokkaConfiguration.PassConfiguration,
val refGraph: NodeReferenceGraph,
val platformNodeRegistry: PlatformNodeRegistry,
val logger: DokkaLogger,
@@ -131,7 +81,7 @@ class DocumentationBuilder
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.OVERRIDE_KEYWORD, KtTokens.INLINE_KEYWORD)
fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: RefKind) {
refGraph.link(node, descriptor.signature(), kind)
@@ -189,6 +139,13 @@ class DocumentationBuilder
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)
@@ -328,11 +285,18 @@ class DocumentationBuilder
.detail(NodeKind.Value)
.name.removeSurrounding("\"")
- append(platformNodeRegistry["Kotlin " + kotlinVersion], RefKind.Platform)
+ 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
+ appendInline(descriptor, psi)
KtTokens.MODIFIER_KEYWORDS_ARRAY.filter {
it !in knownModifiers
}.sortedBy {
@@ -355,7 +319,7 @@ class DocumentationBuilder
fun DocumentationNode.isSinceKotlin() = name == "SinceKotlin" && kind == NodeKind.Annotation
fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
- appendSourceLink(sourceElement.getPsi(), options.sourceLinks)
+ appendSourceLink(sourceElement.getPsi(), passConfiguration.sourceLinks)
}
fun DocumentationNode.appendSignature(descriptor: DeclarationDescriptor) {
@@ -363,7 +327,7 @@ class DocumentationBuilder
}
fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? {
- if (!descriptor.isGenerated() && descriptor.isDocumented(options)) {
+ if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) {
val node = descriptor.build()
append(node, kind)
return node
@@ -390,7 +354,7 @@ class DocumentationBuilder
fun DocumentationNode.appendOrUpdateMember(descriptor: DeclarationDescriptor) {
- if (descriptor.isGenerated() || !descriptor.isDocumented(options)) return
+ if (descriptor.isGenerated() || !descriptor.isDocumented(passConfiguration)) return
val existingNode = refGraph.lookup(descriptor.signature())
if (existingNode != null) {
@@ -462,10 +426,10 @@ class DocumentationBuilder
val allFqNames = fragments.map { it.fqName }.distinct()
for (packageName in allFqNames) {
- if (packageName.isRoot && !options.includeRootPackage) continue
+ if (packageName.isRoot && !passConfiguration.includeRootPackage) continue
val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() }
- if (options.skipEmptyPackages && declarations.none { it.isDocumented(options) }) continue
+ 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,
@@ -492,7 +456,7 @@ class DocumentationBuilder
}.flatten()
val allDescriptors =
- if (options.collectInheritedExtensionsFromLibraries) {
+ if (passConfiguration.collectInheritedExtensionsFromLibraries) {
allPackageViewDescriptors.map { it.memberScope }
} else {
fragments.asSequence().map { it.getMemberScope() }
@@ -514,13 +478,20 @@ class DocumentationBuilder
.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 (extensionFunction.extensionReceiverParameter?.type?.isDynamic() == true) continue
+ if (isIgnoredReceiverType(extensionReceiverParameter.type)) continue
val subclasses =
classHierarchy.filter { (key) -> key.isExtensionApplicable(extensionFunction) }
if (subclasses.isEmpty()) continue
@@ -628,6 +599,7 @@ class DocumentationBuilder
val node = nodeForDescriptor(this, NodeKind.TypeAlias)
if (!external) {
+ node.appendDefaultSinceKotlin()
node.appendAnnotations(this)
}
node.appendModifiers(this)
@@ -665,6 +637,7 @@ class DocumentationBuilder
for ((descriptor, inheritedLinkKind, extraModifier) in collectMembersToDocument()) {
node.appendClassMember(descriptor, inheritedLinkKind, extraModifier)
}
+ node.appendDefaultSinceKotlin()
node.appendAnnotations(this)
}
node.appendModifiers(this)
@@ -697,7 +670,7 @@ class DocumentationBuilder
.mapTo(result) { ClassMember(it, extraModifier = "static") }
val companionObjectDescriptor = companionObjectDescriptor
- if (companionObjectDescriptor != null && companionObjectDescriptor.isDocumented(options)) {
+ if (companionObjectDescriptor != null && companionObjectDescriptor.isDocumented(passConfiguration)) {
val descriptors = companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors()
val descriptorsToDocument = descriptors.filter { it !is CallableDescriptor || !it.isInheritedFromAny() }
descriptorsToDocument.mapTo(result) {
@@ -725,6 +698,7 @@ class DocumentationBuilder
val node = nodeForDescriptor(this, NodeKind.Constructor)
node.appendInPageChildren(valueParameters, RefKind.Detail)
node.appendDefaultPlatforms(this)
+ node.appendDefaultSinceKotlin()
register(this, node)
return node
}
@@ -749,6 +723,9 @@ class DocumentationBuilder
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) {
@@ -786,6 +763,9 @@ class DocumentationBuilder
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) {
@@ -849,6 +829,7 @@ class DocumentationBuilder
}
}
}
+ node.appendDefaultSinceKotlin()
node.appendAnnotations(this)
node.appendModifiers(this)
if (varargElementType != null && node.details(NodeKind.Modifier).none { it.name == "vararg" }) {
@@ -939,23 +920,27 @@ class DocumentationBuilder
}
- fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor,
- externalClassNodes: MutableMap<FqName, DocumentationNode>,
- allFqNames: Collection<FqName>): DocumentationNode {
+ 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, {
+ 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
@@ -963,12 +948,12 @@ class DocumentationBuilder
}
-fun DeclarationDescriptor.isDocumented(options: DocumentationOptions): Boolean {
- return (options.effectivePackageOptions(fqNameSafe).includeNonPublic
+fun DeclarationDescriptor.isDocumented(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean {
+ return (passConfiguration.effectivePackageOptions(fqNameSafe).includeNonPublic
|| this !is MemberDescriptor
|| this.visibility.isPublicAPI)
- && !isDocumentationSuppressed(options)
- && (!options.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated())
+ && !isDocumentationSuppressed(passConfiguration)
+ && (!passConfiguration.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated())
}
private fun DeclarationDescriptor.isGenerated() = this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION
@@ -982,8 +967,13 @@ class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
val externalClassNodes = hashMapOf<FqName, DocumentationNode>()
declarations.forEach { descriptor ->
with(documentationBuilder) {
- if (descriptor.isDocumented(options)) {
- val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes, allFqNames)
+ if (descriptor.isDocumented(passConfiguration)) {
+ val parent = packageNode.getParentForPackageMember(
+ descriptor,
+ externalClassNodes,
+ allFqNames,
+ packageName
+ )
parent.appendOrUpdateMember(descriptor)
}
}
@@ -994,14 +984,14 @@ class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
class KotlinJavaDocumentationBuilder
@Inject constructor(val resolutionFacade: DokkaResolutionFacade,
val documentationBuilder: DocumentationBuilder,
- val options: DocumentationOptions,
+ 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(options) }) {
+ if (classDescriptors.any { it != null && it.isDocumented(passConfiguration) }) {
val packageNode = findOrCreatePackageNode(module, file.packageName, packageContent, documentationBuilder.refGraph)
for (descriptor in classDescriptors.filterNotNull()) {
@@ -1031,13 +1021,13 @@ fun AnnotationDescriptor.mustBeDocumented(): Boolean {
return annotationClass.isDocumentedAnnotation()
}
-fun DeclarationDescriptor.isDocumentationSuppressed(options: DocumentationOptions): Boolean {
+fun DeclarationDescriptor.isDocumentationSuppressed(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean {
- if (options.effectivePackageOptions(fqNameSafe).suppress) return true
+ if (passConfiguration.effectivePackageOptions(fqNameSafe).suppress) return true
val path = this.findPsi()?.containingFile?.virtualFile?.path
if (path != null) {
- if (File(path).absoluteFile in options.suppressedFiles) return true
+ if (path in passConfiguration.suppressedFiles) return true
}
val doc = findKDoc()
@@ -1136,8 +1126,8 @@ fun DeclarationDescriptor.sourceLocation(): String? {
return null
}
-fun DocumentationModule.prepareForGeneration(options: DocumentationOptions) {
- if (options.generateIndexPages) {
+fun DocumentationModule.prepareForGeneration(configuration: DokkaConfiguration) {
+ if (configuration.generateIndexPages) {
generateAllTypesNode()
}
nodeRefGraph.resolveReferences()
@@ -1145,7 +1135,9 @@ fun DocumentationModule.prepareForGeneration(options: DocumentationOptions) {
fun DocumentationNode.generateAllTypesNode() {
val allTypes = members(NodeKind.Package)
- .flatMap { it.members.filter { it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass } }
+ .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)
@@ -1161,4 +1153,12 @@ fun ClassDescriptor.supertypesWithAnyPrecise(): Collection<KotlinType> {
return emptyList()
}
return typeConstructor.supertypesWithAny()
-} \ No newline at end of file
+}
+
+fun PassConfiguration.effectivePackageOptions(pack: String): DokkaConfiguration.PackageOptions {
+ val rootPackageOptions = PackageOptionsImpl("", includeNonPublic, reportUndocumented, skipDeprecated)
+ return perPackageOptions.firstOrNull { pack == it.prefix || 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
index a8129793..9d986aee 100644
--- a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
@@ -22,29 +22,48 @@ 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 ExternalDocumentationLinkResolver @Inject constructor(
- val options: DocumentationOptions,
- @Named("libraryResolutionFacade") val libraryResolutionFacade: DokkaResolutionFacade,
- val logger: DokkaLogger
+class PackageListProvider @Inject constructor(
+ val configuration: DokkaConfiguration,
+ val logger: DokkaLogger
) {
+ val storage = mutableMapOf<DokkaConfiguration.ExternalDocumentationLink, PackageFqNameToLocation>()
- val packageFqNameToLocation = mutableMapOf<FqName, ExternalDocumentationRoot>()
- val formats = mutableMapOf<String, InboundExternalLinkResolutionService>()
+ 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 { createDirectories() }
- class ExternalDocumentationRoot(val rootUrl: URL, val resolver: InboundExternalLinkResolutionService, val locations: Map<String, String>) {
- override fun toString(): String = rootUrl.toString()
+ 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)
+ }
+ }
+
+ }
}
- val cacheDir: Path? = options.cacheRoot?.resolve("packageListCache")?.apply { createDirectories() }
- val cachedProtocols = setOf("http", "https", "ftp")
fun URL.doOpenConnectionToReadContent(timeout: Int = 10000, redirectsAllowed: Int = 16): URLConnection {
val connection = this.openConnection()
@@ -120,23 +139,23 @@ class ExternalDocumentationLinkResolver @Inject constructor(
val (params, packages) =
packageListStream
- .bufferedReader()
- .useLines { lines -> lines.partition { it.startsWith(DOKKA_PARAM_PREFIX) } }
+ .bufferedReader()
+ .useLines { lines -> lines.partition { it.startsWith(ExternalDocumentationLinkResolver.DOKKA_PARAM_PREFIX) } }
val paramsMap = params.asSequence()
- .map { it.removePrefix(DOKKA_PARAM_PREFIX).split(":", limit = 2) }
- .groupBy({ (key, _) -> key }, { (_, value) -> value })
+ .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()
+ .map { it.split("\u001f", limit = 2) }
+ .map { (key, value) -> key to value }
+ .toMap()
- val defaultResolverDesc = services["dokka-default"]!!
- val resolverDesc = services[format]
+ val defaultResolverDesc = ExternalDocumentationLinkResolver.services["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")
@@ -153,16 +172,52 @@ class ExternalDocumentationLinkResolver @Inject constructor(
val rootInfo = ExternalDocumentationRoot(link.url, resolver, locations)
- packages.map { FqName(it) }.forEach { packageFqNameToLocation[it] = rootInfo }
+ 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 {
- options.externalDocumentationLinks.forEach {
- try {
- loadPackageList(it)
- } catch (e: Exception) {
- throw RuntimeException("Exception while loading package-list from $it", e)
- }
+ val fqNameToLocationMaps = passConfiguration.externalDocumentationLinks
+ .mapNotNull { packageListProvider.storage[it] }
+
+ for(map in fqNameToLocationMaps) {
+ packageFqNameToLocation.putAll(map)
}
}
@@ -191,14 +246,6 @@ class ExternalDocumentationLinkResolver @Inject constructor(
companion object {
const val DOKKA_PARAM_PREFIX = "\$dokka."
val services = ServiceLocator.allServices("inbound-link-resolver").associateBy { it.name }
- private val formatsWithDefaultResolver =
- ServiceLocator
- .allServices("format")
- .filter {
- val desc = ServiceLocator.lookup<FormatDescriptor>(it) as? FileGeneratorBasedFormatDescriptor
- desc?.generatorServiceClass == FileGenerator::class
- }.map { it.name }
- .toSet()
}
}
diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt
index 00a795d0..6e58f766 100644
--- a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt
@@ -30,7 +30,7 @@ class KotlinAsJavaDocumentationBuilder
return
}
- val javaDocumentationBuilder = JavaPsiDocumentationBuilder(documentationBuilder.options,
+ val javaDocumentationBuilder = JavaPsiDocumentationBuilder(documentationBuilder.passConfiguration,
documentationBuilder.refGraph,
kotlinAsJavaDocumentationParser)
diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
index 5f43c22e..daa09cbf 100644
--- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
+++ b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
@@ -208,7 +208,7 @@ class KotlinLanguageService : CommonLanguageService() {
nowrap: Boolean
) {
when (node.name) {
- "final", "public", "var" -> {
+ "final", "public", "var", "expect", "actual", "external" -> {
}
else -> {
if (showModifierInSummary(node) || renderMode == RenderMode.FULL) {
diff --git a/core/src/main/kotlin/Locations/Location.kt b/core/src/main/kotlin/Locations/Location.kt
index 4cb0ac39..ccefa6e3 100644
--- a/core/src/main/kotlin/Locations/Location.kt
+++ b/core/src/main/kotlin/Locations/Location.kt
@@ -26,7 +26,7 @@ data class FileLocation(val file: File) : Location {
}
val ownerFolder = file.parentFile!!
val relativePath = ownerFolder.toPath().relativize(other.file.toPath()).toString().replace(File.separatorChar, '/')
- return if (anchor == null) relativePath else relativePath + "#" + anchor
+ return if (anchor == null) relativePath else relativePath + "#" + anchor.urlEncoded()
}
}
@@ -40,10 +40,25 @@ fun relativePathToNode(qualifiedName: List<String>, hasMembers: Boolean): String
}
}
+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 relativePathToNode(node: DocumentationNode) = relativePathToNode(node.path.map { it.name }, node.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
diff --git a/core/src/main/kotlin/Model/Content.kt b/core/src/main/kotlin/Model/Content.kt
index c142f4a4..8312b2e2 100644
--- a/core/src/main/kotlin/Model/Content.kt
+++ b/core/src/main/kotlin/Model/Content.kt
@@ -227,7 +227,11 @@ open class Content(): ContentBlock() {
sections.firstOrNull { tag.equals(it.tag, ignoreCase = true) }
companion object {
- val Empty = Content()
+ val Empty = object: Content() {
+ override fun toString(): String {
+ return "EMPTY_CONTENT"
+ }
+ }
fun of(vararg child: ContentNode): Content {
val result = MutableContent()
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
index ad7801f2..1ff14ff1 100644
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ b/core/src/main/kotlin/Model/DocumentationNode.kt
@@ -76,7 +76,14 @@ open class DocumentationNode(val name: String,
var content: Content = content
private set
- val summary: ContentNode get() = content.summary
+ 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
@@ -84,6 +91,9 @@ open class DocumentationNode(val name: String,
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>
@@ -109,6 +119,15 @@ open class DocumentationNode(val name: String,
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)
@@ -134,6 +153,10 @@ open class DocumentationNode(val name: String,
references.add(DocumentationReference(this, to, kind))
}
+ fun addReference(reference: DocumentationReference) {
+ references.add(reference)
+ }
+
fun dropReferences(predicate: (DocumentationReference) -> Boolean) {
references.removeAll(predicate)
}
@@ -159,6 +182,7 @@ open class DocumentationNode(val name: String,
fun member(kind: NodeKind): DocumentationNode = members.filter { it.kind == kind }.single()
fun link(kind: NodeKind): DocumentationNode = links.filter { it.kind == kind }.single()
+
fun references(kind: RefKind): List<DocumentationReference> = references.filter { it.kind == kind }
fun allReferences(): Set<DocumentationReference> = references
@@ -167,9 +191,9 @@ open class DocumentationNode(val name: String,
}
}
-class DocumentationModule(name: String, content: Content = Content.Empty)
+class DocumentationModule(name: String, content: Content = Content.Empty, val nodeRefGraph: NodeReferenceGraph = NodeReferenceGraph())
: DocumentationNode(name, content, NodeKind.Module) {
- val nodeRefGraph = NodeReferenceGraph()
+
}
val DocumentationNode.path: List<DocumentationNode>
@@ -201,6 +225,7 @@ fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) {
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 */
}
}
diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt
index 89ec1b3e..1f2fc0c9 100644
--- a/core/src/main/kotlin/Model/DocumentationReference.kt
+++ b/core/src/main/kotlin/Model/DocumentationReference.kt
@@ -19,42 +19,83 @@ enum class RefKind {
Deprecation,
TopLevelPage,
Platform,
- ExternalType
+ ExternalType,
+ Origin,
+ SinceKotlin
}
data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: RefKind) {
}
-class PendingDocumentationReference(val lazyNodeFrom: () -> DocumentationNode?,
- val lazyNodeTo: () -> DocumentationNode?,
+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() {
- val fromNode = lazyNodeFrom()
- val toNode = lazyNodeTo()
+ 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() {
+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.put(signature, node)
+ nodeMap[signature] = node
}
fun link(fromNode: DocumentationNode, toSignature: String, kind: RefKind) {
- references.add(PendingDocumentationReference({ -> fromNode}, { -> nodeMap[toSignature]}, kind))
+ references.add(
+ PendingDocumentationReference(
+ NodeResolver.Exact(fromNode),
+ NodeResolver.BySignature(toSignature),
+ kind
+ ))
}
fun link(fromSignature: String, toNode: DocumentationNode, kind: RefKind) {
- references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> toNode}, kind))
+ references.add(
+ PendingDocumentationReference(
+ NodeResolver.BySignature(fromSignature),
+ NodeResolver.Exact(toNode),
+ kind
+ )
+ )
}
fun link(fromSignature: String, toSignature: String, kind: RefKind) {
- references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> nodeMap[toSignature]}, kind))
+ references.add(
+ PendingDocumentationReference(
+ NodeResolver.BySignature(fromSignature),
+ NodeResolver.BySignature(toSignature),
+ kind
+ )
+ )
+ }
+
+ fun addReference(reference: PendingDocumentationReference) {
+ references.add(reference)
}
fun lookup(signature: String) = nodeMap[signature]
@@ -68,7 +109,7 @@ class NodeReferenceGraph() {
}
fun resolveReferences() {
- references.forEach { it.resolve() }
+ references.forEach { it.resolve(this) }
}
}
diff --git a/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt b/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt
index 116a5c02..f3f45c3f 100644
--- a/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt
+++ b/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.resolve.scopes.ResolutionScope
open class DefaultSampleProcessingService
-@Inject constructor(val options: DocumentationOptions,
+@Inject constructor(val configuration: DokkaConfiguration,
val logger: DokkaLogger,
val resolutionFacade: DokkaResolutionFacade)
: SampleProcessingService {
diff --git a/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt b/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt
index b0988c35..4525e9d9 100644
--- a/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt
+++ b/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt
@@ -1,7 +1,9 @@
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
@@ -9,19 +11,27 @@ 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(options: DocumentationOptions,
+@Inject constructor(dokkaConfiguration: DokkaConfiguration,
logger: DokkaLogger,
resolutionFacade: DokkaResolutionFacade)
- : DefaultSampleProcessingService(options, logger, resolutionFacade) {
+ : 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 }
@@ -54,27 +64,42 @@ open class KotlinWebsiteSampleProcessingService
}
fun convertAssertFails(expression: KtCallExpression) {
- val (message, funcArgument) = expression.valueArguments
+ 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 = if (funcArgument.getArgumentExpression() is KtLambdaExpression)
- PsiTreeUtil.findChildOfType(funcArgument, KtBlockExpression::class.java)?.text ?: ""
- else
- funcArgument.text
+ val argument = funcArgument.extractFunctionalArgumentText()
append(argument.lines().joinToString(separator = "\n") { "// $it" })
append(" // ")
- append(message.extractStringArgumentValue())
+ 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 = if (funcArgument.firstChild is KtLambdaExpression)
- PsiTreeUtil.findChildOfType(funcArgument, KtBlockExpression::class.java)?.text ?: ""
- else
- funcArgument.text
+ val argument = funcArgument.extractFunctionalArgumentText()
append(argument.lines().joinToString(separator = "\n") { "// $it" })
append(" // will fail with ")
append(exceptionType.text)
@@ -92,16 +117,51 @@ open class KotlinWebsiteSampleProcessingService
}
}
+ 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)
- super.visitElement(element)
+
+ 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
}
diff --git a/core/src/main/kotlin/Utilities/DokkaModules.kt b/core/src/main/kotlin/Utilities/DokkaModules.kt
index 732cbc48..c2e652b6 100644
--- a/core/src/main/kotlin/Utilities/DokkaModules.kt
+++ b/core/src/main/kotlin/Utilities/DokkaModules.kt
@@ -1,8 +1,6 @@
package org.jetbrains.dokka.Utilities
-import com.google.inject.Binder
-import com.google.inject.Module
-import com.google.inject.TypeLiteral
+import com.google.inject.*
import com.google.inject.binder.AnnotatedBindingBuilder
import com.google.inject.name.Names
import org.jetbrains.dokka.*
@@ -13,10 +11,21 @@ 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 options: DocumentationOptions,
+ 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)
@@ -28,29 +37,25 @@ class DokkaAnalysisModule(val environment: AnalysisEnvironment,
binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
binder.bind<DokkaResolutionFacade>().annotatedWith(Names.named("libraryResolutionFacade")).toInstance(libraryResolutionFacade)
- binder.bind<DocumentationOptions>().toInstance(options)
+ binder.bind<DokkaConfiguration.PassConfiguration>().toInstance(passConfiguration)
binder.bind<DefaultPlatformsProvider>().toInstance(defaultPlatformsProvider)
binder.bind<NodeReferenceGraph>().toInstance(nodeReferenceGraph)
- val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", options.outputFormat)
+ val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", configuration.format)
descriptor.configureAnalysis(binder)
}
}
object StringListType : TypeLiteral<@JvmSuppressWildcards List<String>>()
-class DokkaOutputModule(val options: DocumentationOptions,
+class DokkaOutputModule(val configuration: DokkaConfiguration,
val logger: DokkaLogger) : Module {
override fun configure(binder: Binder) {
- binder.bind(File::class.java).annotatedWith(Names.named("outputDir")).toInstance(File(options.outputDir))
-
- binder.bind<DocumentationOptions>().toInstance(options)
binder.bind<DokkaLogger>().toInstance(logger)
- binder.bind(StringListType).annotatedWith(Names.named(impliedPlatformsName)).toInstance(options.impliedPlatforms)
- val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", options.outputFormat)
+ val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", configuration.format)
descriptor.configureOutput(binder)
}
diff --git a/core/src/main/kotlin/Utilities/ServiceLocator.kt b/core/src/main/kotlin/Utilities/ServiceLocator.kt
index 83c4c65c..fca08f38 100644
--- a/core/src/main/kotlin/Utilities/ServiceLocator.kt
+++ b/core/src/main/kotlin/Utilities/ServiceLocator.kt
@@ -70,7 +70,7 @@ object ServiceLocator {
"jar" -> {
val file = JarFile(URL(it.file.substringBefore("!")).toFile())
try {
- val jarPath = it.file.substringAfterLast("!").removePrefix("/")
+ val jarPath = it.file.substringAfterLast("!").removeSurrounding("/")
file.entries()
.asSequence()
.filter { entry -> !entry.isDirectory && entry.path == jarPath && entry.extension == "properties" }
diff --git a/core/src/main/kotlin/javadoc/dokka-adapters.kt b/core/src/main/kotlin/javadoc/dokka-adapters.kt
index 483fb3cd..1329876a 100644
--- a/core/src/main/kotlin/javadoc/dokka-adapters.kt
+++ b/core/src/main/kotlin/javadoc/dokka-adapters.kt
@@ -4,16 +4,19 @@ 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.*
+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 options: DocumentationOptions, val logger: DokkaLogger) : Generator {
+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), options.outputDir))
+ HtmlDoclet.start(ModuleNodeAdapter(module, StandardReporter(logger), configuration.outputDir))
}
override fun buildOutlines(nodes: Iterable<DocumentationNode>) {
diff --git a/core/src/test/kotlin/TestAPI.kt b/core/src/test/kotlin/TestAPI.kt
index 4f77a2f6..6ee610cd 100644
--- a/core/src/test/kotlin/TestAPI.kt
+++ b/core/src/test/kotlin/TestAPI.kt
@@ -8,6 +8,7 @@ import com.intellij.rt.execution.junit.FileComparisonFailure
import org.jetbrains.dokka.*
import org.jetbrains.dokka.DokkaConfiguration.SourceLinkDefinition
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
@@ -15,54 +16,59 @@ 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<SourceLinkDefinition> = emptyList()
+)
-fun verifyModel(vararg roots: ContentRoot,
- withJdk: Boolean = false,
- withKotlinRuntime: Boolean = false,
- format: String = "html",
- includeNonPublic: Boolean = true,
- perPackageOptions: List<DokkaConfiguration.PackageOptions> = emptyList(),
- noStdlibLink: Boolean = true,
- collectInheritedExtensionsFromLibraries: Boolean = false,
- sourceLinks: List<SourceLinkDefinition> = emptyList(),
+fun verifyModel(modelConfig: ModelConfig,
verifier: (DocumentationModule) -> Unit) {
val documentation = DocumentationModule("test")
- val options = DocumentationOptions(
- "",
- format,
- includeNonPublic = includeNonPublic,
+ val passConfiguration = PassConfigurationImpl (
+ includeNonPublic = modelConfig.includeNonPublic,
skipEmptyPackages = false,
includeRootPackage = true,
- sourceLinks = sourceLinks,
- perPackageOptions = perPackageOptions,
- generateIndexPages = false,
- noStdlibLink = noStdlibLink,
+ sourceLinks = modelConfig.sourceLinks,
+ perPackageOptions = modelConfig.perPackageOptions,
+ noStdlibLink = modelConfig.noStdlibLink,
noJdkLink = false,
- cacheRoot = "default",
languageVersion = null,
apiVersion = null,
- collectInheritedExtensionsFromLibraries = collectInheritedExtensionsFromLibraries
+ collectInheritedExtensionsFromLibraries = modelConfig.collectInheritedExtensionsFromLibraries
+ )
+ val configuration = DokkaConfigurationImpl(
+ outputDir = "",
+ format = modelConfig.format,
+ generateIndexPages = false,
+ cacheRoot = "default",
+ passesConfigurations = listOf(passConfiguration)
)
- appendDocumentation(documentation, *roots,
- withJdk = withJdk,
- withKotlinRuntime = withKotlinRuntime,
- options = options)
- documentation.prepareForGeneration(options)
+ appendDocumentation(documentation, configuration, passConfiguration, modelConfig)
+ documentation.prepareForGeneration(configuration)
verifier(documentation)
}
fun appendDocumentation(documentation: DocumentationModule,
- vararg roots: ContentRoot,
- withJdk: Boolean = false,
- withKotlinRuntime: Boolean = false,
- options: DocumentationOptions,
- defaultPlatforms: List<String> = emptyList()) {
+ dokkaConfiguration: DokkaConfiguration,
+ passConfiguration: DokkaConfiguration.PassConfiguration,
+ modelConfig: ModelConfig
+) {
val messageCollector = object : MessageCollector {
override fun clear() {
@@ -87,66 +93,106 @@ fun appendDocumentation(documentation: DocumentationModule,
override fun hasErrors() = false
}
- val environment = AnalysisEnvironment(messageCollector)
+ val environment = AnalysisEnvironment(messageCollector, modelConfig.analysisPlatform)
environment.apply {
- if (withJdk || withKotlinRuntime) {
- val stringRoot = PathManager.getResourceRoot(String::class.java, "/java/lang/String.class")
- addClasspath(File(stringRoot))
+ if (modelConfig.withJdk || modelConfig.withKotlinRuntime) {
+ addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
}
- if (withKotlinRuntime) {
- val kotlinStrictfpRoot = PathManager.getResourceRoot(Strictfp::class.java, "/kotlin/jvm/Strictfp.class")
- addClasspath(File(kotlinStrictfpRoot))
+ if (modelConfig.withKotlinRuntime) {
+ if (analysisPlatform == Platform.jvm) {
+ val kotlinStrictfpRoot = PathManager.getResourceRoot(Strictfp::class.java, "/kotlin/jvm/Strictfp.class")
+ addClasspath(File(kotlinStrictfpRoot))
+ }
+ // TODO: Fix concrete path to correct gradle path providing
+ if (analysisPlatform == Platform.js) {
+ addClasspath(File("/home/jetbrains/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/181.5281.24/plugins/Kotlin/kotlinc/lib/kotlin-jslib.jar"))
+ addClasspath(File("/home/jetbrains/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/181.5281.24/plugins/Kotlin/kotlinc/lib/kotlin-stdlib-js.jar"))
+ addClasspath(File("/home/jetbrains/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/181.5281.24/plugins/Kotlin/kotlinc/lib/kotlin-stdlib-js-sources.jar"))
+ }
+ if (analysisPlatform == Platform.common) {
+ addClasspath(File("/home/jetbrains/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.2.51/e4a9d4b13ab19ed1e6531fce6df98e8cfa7f7301/kotlin-stdlib-common-1.2.51.jar"))
+ }
}
- addRoots(roots.toList())
+ addRoots(modelConfig.roots.toList())
- loadLanguageVersionSettings(options.languageVersion, options.apiVersion)
+ loadLanguageVersionSettings(passConfiguration.languageVersion, passConfiguration.apiVersion)
}
val defaultPlatformsProvider = object : DefaultPlatformsProvider {
- override fun getDefaultPlatforms(descriptor: DeclarationDescriptor) = defaultPlatforms
+ override fun getDefaultPlatforms(descriptor: DeclarationDescriptor) = modelConfig.defaultPlatforms
}
- val injector = Guice.createInjector(
- DokkaAnalysisModule(environment, options, defaultPlatformsProvider, documentation.nodeRefGraph, DokkaConsoleLogger))
+
+ 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 verifyModel(source: String,
- withJdk: Boolean = false,
- withKotlinRuntime: Boolean = false,
- format: String = "html",
- includeNonPublic: Boolean = true,
- sourceLinks: List<SourceLinkDefinition> = emptyList(),
- verifier: (DocumentationModule) -> Unit) {
+fun checkSourceExistsAndVerifyModel(source: String,
+ modelConfig: ModelConfig = ModelConfig(),
+ verifier: (DocumentationModule) -> Unit) {
require (File(source).exists()) {
"Cannot find test data file $source"
}
- verifyModel(contentRootFromPath(source),
- withJdk = withJdk,
- withKotlinRuntime = withKotlinRuntime,
- format = format,
- includeNonPublic = includeNonPublic,
- sourceLinks = sourceLinks,
- verifier = verifier)
+ 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,
- withJdk: Boolean = false,
- withKotlinRuntime: Boolean = false,
+ modelConfig: ModelConfig = ModelConfig(),
verifier: (DocumentationNode) -> Unit) {
- verifyModel(source, withJdk = withJdk, withKotlinRuntime = withKotlinRuntime) { model ->
+ 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,
- withKotlinRuntime: Boolean = false,
+ modelConfig: ModelConfig = ModelConfig(),
verifier: (DocumentationModule) -> Unit) {
val tempDir = FileUtil.createTempDirectory("dokka", "")
try {
val sourceFile = File(source)
FileUtil.copy(sourceFile, File(tempDir, sourceFile.name))
- verifyModel(JavaSourceRoot(tempDir, null), withJdk = true, withKotlinRuntime = withKotlinRuntime, verifier = verifier)
+ verifyModel(
+ ModelConfig(
+ roots = arrayOf(JavaSourceRoot(tempDir, null)),
+ withJdk = true,
+ withKotlinRuntime = modelConfig.withKotlinRuntime,
+ analysisPlatform = modelConfig.analysisPlatform
+ ),
+ verifier = verifier
+ )
}
finally {
FileUtil.delete(tempDir)
@@ -154,36 +200,42 @@ fun verifyJavaModel(source: String,
}
fun verifyJavaPackageMember(source: String,
- withKotlinRuntime: Boolean = false,
+ modelConfig: ModelConfig = ModelConfig(),
verifier: (DocumentationNode) -> Unit) {
- verifyJavaModel(source, withKotlinRuntime) { model ->
+ verifyJavaModel(source, modelConfig) { model ->
val pkg = model.members.single()
verifier(pkg.members.single())
}
}
-fun verifyOutput(roots: Array<ContentRoot>,
+fun verifyOutput(modelConfig: ModelConfig = ModelConfig(),
outputExtension: String,
- withJdk: Boolean = false,
- withKotlinRuntime: Boolean = false,
- format: String = "html",
- includeNonPublic: Boolean = true,
- noStdlibLink: Boolean = true,
- collectInheritedExtensionsFromLibraries: Boolean = false,
outputGenerator: (DocumentationModule, StringBuilder) -> Unit) {
- verifyModel(
- *roots,
- withJdk = withJdk,
- withKotlinRuntime = withKotlinRuntime,
- format = format,
- includeNonPublic = includeNonPublic,
- noStdlibLink = noStdlibLink,
- collectInheritedExtensionsFromLibraries = collectInheritedExtensionsFromLibraries
- ) {
- verifyModelOutput(it, outputExtension, roots.first().path, outputGenerator)
+ 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,
@@ -195,35 +247,11 @@ fun verifyModelOutput(it: DocumentationModule,
assertEqualsIgnoringSeparators(expectedFile, output.toString())
}
-fun verifyOutput(
- path: String,
- outputExtension: String,
- withJdk: Boolean = false,
- withKotlinRuntime: Boolean = false,
- format: String = "html",
- includeNonPublic: Boolean = true,
- noStdlibLink: Boolean = true,
- collectInheritedExtensionsFromLibraries: Boolean = false,
- outputGenerator: (DocumentationModule, StringBuilder) -> Unit
-) {
- verifyOutput(
- arrayOf(contentRootFromPath(path)),
- outputExtension,
- withJdk,
- withKotlinRuntime,
- format,
- includeNonPublic,
- noStdlibLink,
- collectInheritedExtensionsFromLibraries,
- outputGenerator
- )
-}
-
fun verifyJavaOutput(path: String,
outputExtension: String,
- withKotlinRuntime: Boolean = false,
+ modelConfig: ModelConfig = ModelConfig(),
outputGenerator: (DocumentationModule, StringBuilder) -> Unit) {
- verifyJavaModel(path, withKotlinRuntime) { model ->
+ verifyJavaModel(path, modelConfig) { model ->
verifyModelOutput(model, outputExtension, path, outputGenerator)
}
}
diff --git a/core/src/test/kotlin/format/GFMFormatTest.kt b/core/src/test/kotlin/format/GFMFormatTest.kt
index b90ab2bf..60de7d29 100644
--- a/core/src/test/kotlin/format/GFMFormatTest.kt
+++ b/core/src/test/kotlin/format/GFMFormatTest.kt
@@ -2,23 +2,26 @@ package org.jetbrains.dokka.tests
import org.jetbrains.dokka.GFMFormatService
import org.jetbrains.dokka.KotlinLanguageService
+import org.jetbrains.dokka.Platform
import org.junit.Test
-class GFMFormatTest : FileGeneratorTestCase() {
+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")
+ verifyGFMNodeByName("sample", "Foo", defaultModelConfig)
}
@Test
fun listInTableCell() {
- verifyGFMNodeByName("listInTableCell", "Foo")
+ verifyGFMNodeByName("listInTableCell", "Foo", defaultModelConfig)
}
- private fun verifyGFMNodeByName(fileName: String, name: String) {
- verifyOutput("testdata/format/gfm/$fileName.kt", ".md") { model, output ->
+ 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
@@ -26,3 +29,8 @@ class GFMFormatTest : FileGeneratorTestCase() {
}
}
}
+
+
+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
index 807118c5..60e29006 100644
--- a/core/src/test/kotlin/format/HtmlFormatTest.kt
+++ b/core/src/test/kotlin/format/HtmlFormatTest.kt
@@ -6,176 +6,187 @@ import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.junit.Test
import java.io.File
-class HtmlFormatTest: FileGeneratorTestCase() {
+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")
+ verifyHtmlNode("classWithCompanionObject", defaultModelConfig)
}
@Test fun htmlEscaping() {
- verifyHtmlNode("htmlEscaping")
+ verifyHtmlNode("htmlEscaping", defaultModelConfig)
}
@Test fun overloads() {
- verifyHtmlNodes("overloads") { model -> model.members }
+ verifyHtmlNodes("overloads", defaultModelConfig) { model -> model.members }
}
@Test fun overloadsWithDescription() {
- verifyHtmlNode("overloadsWithDescription")
+ verifyHtmlNode("overloadsWithDescription", defaultModelConfig)
}
@Test fun overloadsWithDifferentDescriptions() {
- verifyHtmlNode("overloadsWithDifferentDescriptions")
+ verifyHtmlNode("overloadsWithDifferentDescriptions", defaultModelConfig)
}
@Test fun deprecated() {
- verifyOutput("testdata/format/deprecated.kt", ".package.html") { model, output ->
+ verifyOutput("testdata/format/deprecated.kt", ".package.html", defaultModelConfig) { model, output ->
buildPagesAndReadInto(model.members, output)
}
- verifyOutput("testdata/format/deprecated.kt", ".class.html") { model, output ->
+ verifyOutput("testdata/format/deprecated.kt", ".class.html", defaultModelConfig) { model, output ->
buildPagesAndReadInto(model.members.single().members, output)
}
}
@Test fun brokenLink() {
- verifyHtmlNode("brokenLink")
+ verifyHtmlNode("brokenLink", defaultModelConfig)
}
@Test fun codeSpan() {
- verifyHtmlNode("codeSpan")
+ verifyHtmlNode("codeSpan", defaultModelConfig)
}
@Test fun parenthesis() {
- verifyHtmlNode("parenthesis")
+ verifyHtmlNode("parenthesis", defaultModelConfig)
}
@Test fun bracket() {
- verifyHtmlNode("bracket")
+ verifyHtmlNode("bracket", defaultModelConfig)
}
@Test fun see() {
- verifyHtmlNode("see")
+ verifyHtmlNode("see", defaultModelConfig)
}
@Test fun tripleBackticks() {
- verifyHtmlNode("tripleBackticks")
+ verifyHtmlNode("tripleBackticks", defaultModelConfig)
}
@Test fun typeLink() {
- verifyHtmlNodes("typeLink") { model -> model.members.single().members.filter { it.name == "Bar" } }
+ verifyHtmlNodes("typeLink", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Bar" } }
}
@Test fun parameterAnchor() {
- verifyHtmlNode("parameterAnchor")
- }
-
- @Test fun javaSupertypeLink() {
- verifyJavaHtmlNodes("JavaSupertype") { model ->
- model.members.single().members.single { it.name == "JavaSupertype" }.members.filter { it.name == "Bar" }
- }
+ verifyHtmlNode("parameterAnchor", defaultModelConfig)
}
@Test fun codeBlock() {
- verifyHtmlNode("codeBlock")
- }
-
- @Test fun javaLinkTag() {
- verifyJavaHtmlNode("javaLinkTag")
- }
-
- @Test fun javaLinkTagWithLabel() {
- verifyJavaHtmlNode("javaLinkTagWithLabel")
- }
-
- @Test fun javaSeeTag() {
- verifyJavaHtmlNode("javaSeeTag")
+ verifyHtmlNode("codeBlock", defaultModelConfig)
}
-
- @Test fun javaDeprecated() {
- verifyJavaHtmlNodes("javaDeprecated") { model ->
- model.members.single().members.single { it.name == "Foo" }.members.filter { it.name == "foo" }
- }
- }
-
- @Test fun crossLanguageKotlinExtendsJava() {
- verifyOutput(arrayOf(
- KotlinSourceRoot("testdata/format/crossLanguage/kotlinExtendsJava/Bar.kt", false),
- JavaSourceRoot(File("testdata/format/crossLanguage/kotlinExtendsJava"), null)),
- ".html") { model, output ->
- buildPagesAndReadInto(
- model.members.single().members.filter { it.name == "Bar" },
- output
- )
- }
- }
-
@Test fun orderedList() {
- verifyHtmlNodes("orderedList") { model -> model.members.single().members.filter { it.name == "Bar" } }
+ verifyHtmlNodes("orderedList", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Bar" } }
}
@Test fun linkWithLabel() {
- verifyHtmlNodes("linkWithLabel") { model -> model.members.single().members.filter { it.name == "Bar" } }
+ verifyHtmlNodes("linkWithLabel", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Bar" } }
}
@Test fun entity() {
- verifyHtmlNodes("entity") { model -> model.members.single().members.filter { it.name == "Bar" } }
+ verifyHtmlNodes("entity", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Bar" } }
}
@Test fun uninterpretedEmphasisCharacters() {
- verifyHtmlNode("uninterpretedEmphasisCharacters")
+ verifyHtmlNode("uninterpretedEmphasisCharacters", defaultModelConfig)
}
@Test fun markdownInLinks() {
- verifyHtmlNode("markdownInLinks")
+ verifyHtmlNode("markdownInLinks", defaultModelConfig)
}
@Test fun returnWithLink() {
- verifyHtmlNode("returnWithLink")
+ verifyHtmlNode("returnWithLink", defaultModelConfig)
}
@Test fun linkWithStarProjection() {
- verifyHtmlNode("linkWithStarProjection", withKotlinRuntime = true)
+ verifyHtmlNode("linkWithStarProjection", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
}
@Test fun functionalTypeWithNamedParameters() {
- verifyHtmlNode("functionalTypeWithNamedParameters")
+ verifyHtmlNode("functionalTypeWithNamedParameters", defaultModelConfig)
}
@Test fun sinceKotlin() {
- verifyHtmlNode("sinceKotlin")
+ verifyHtmlNode("sinceKotlin", defaultModelConfig)
}
@Test fun blankLineInsideCodeBlock() {
- verifyHtmlNode("blankLineInsideCodeBlock")
+ verifyHtmlNode("blankLineInsideCodeBlock", defaultModelConfig)
}
@Test fun indentedCodeBlock() {
- verifyHtmlNode("indentedCodeBlock")
+ verifyHtmlNode("indentedCodeBlock", defaultModelConfig)
}
- private fun verifyHtmlNode(fileName: String, withKotlinRuntime: Boolean = false) {
- verifyHtmlNodes(fileName, withKotlinRuntime) { model -> model.members.single().members }
+ private fun verifyHtmlNode(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
+ verifyHtmlNodes(fileName, modelConfig) { model -> model.members.single().members }
}
private fun verifyHtmlNodes(fileName: String,
- withKotlinRuntime: Boolean = false,
+ modelConfig: ModelConfig = ModelConfig(),
nodeFilter: (DocumentationModule) -> List<DocumentationNode>) {
- verifyOutput("testdata/format/$fileName.kt", ".html", withKotlinRuntime = withKotlinRuntime) { model, output ->
+ verifyOutput("testdata/format/$fileName.kt", ".html", modelConfig) { model, output ->
buildPagesAndReadInto(nodeFilter(model), output)
}
}
- private fun verifyJavaHtmlNode(fileName: String, withKotlinRuntime: Boolean = false) {
- verifyJavaHtmlNodes(fileName, withKotlinRuntime) { model -> model.members.single().members }
+ protected fun verifyJavaHtmlNode(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
+ verifyJavaHtmlNodes(fileName, modelConfig) { model -> model.members.single().members }
}
- private fun verifyJavaHtmlNodes(fileName: String,
- withKotlinRuntime: Boolean = false,
- nodeFilter: (DocumentationModule) -> List<DocumentationNode>) {
- verifyJavaOutput("testdata/format/$fileName.java", ".html", withKotlinRuntime = withKotlinRuntime) { model, output ->
+ 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/KotlinWebSiteFormatTest.kt b/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
index 062cf0b5..4f292e37 100644
--- a/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
+++ b/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
@@ -1,7 +1,6 @@
package org.jetbrains.dokka.tests
import org.jetbrains.dokka.*
-import org.junit.Before
import org.junit.Ignore
import org.junit.Test
@@ -39,7 +38,7 @@ class KotlinWebSiteFormatTest: FileGeneratorTestCase() {
}
private fun verifyKWSNodeByName(fileName: String, name: String) {
- verifyOutput("testdata/format/website/$fileName.kt", ".md", format = "kotlin-website") { model, output ->
+ verifyOutput("testdata/format/website/$fileName.kt", ".md", ModelConfig(format = "kotlin-website")) { model, output ->
buildPagesAndReadInto(
model.members.single().members.filter { it.name == name },
output
@@ -49,18 +48,39 @@ class KotlinWebSiteFormatTest: FileGeneratorTestCase() {
private fun buildMultiplePlatforms(path: String): DocumentationModule {
val module = DocumentationModule("test")
- val options = DocumentationOptions(
- outputDir = "",
- outputFormat = "html",
- generateIndexPages = false,
- noStdlibLink = true,
+ val passConfiguration = PassConfigurationImpl(noStdlibLink = true,
noJdkLink = true,
languageVersion = null,
apiVersion = null
)
- appendDocumentation(module, contentRootFromPath("testdata/format/website/$path/jvm.kt"), defaultPlatforms = listOf("JVM"), options = options)
- appendDocumentation(module, contentRootFromPath("testdata/format/website/$path/jre7.kt"), defaultPlatforms = listOf("JVM", "JRE7"), options = options)
- appendDocumentation(module, contentRootFromPath("testdata/format/website/$path/js.kt"), defaultPlatforms = listOf("JS"), options = options)
+ val configuration = DokkaConfigurationImpl(
+ outputDir = "",
+ format = "html",
+ generateIndexPages = false,
+ passesConfigurations = listOf(passConfiguration)
+ )
+
+ appendDocumentation(
+ module, configuration, passConfiguration, ModelConfig(
+ roots = arrayOf(contentRootFromPath("testdata/format/website/$path/jvm.kt")),
+ defaultPlatforms = listOf("JVM")
+ )
+
+ )
+
+
+ appendDocumentation(
+ module, configuration, passConfiguration, ModelConfig(
+ roots = arrayOf(contentRootFromPath("testdata/format/website/$path/jre7.kt")),
+ defaultPlatforms = listOf("JVM", "JRE7")
+ )
+ )
+ appendDocumentation(
+ module, configuration, passConfiguration, ModelConfig(
+ roots = arrayOf(contentRootFromPath("testdata/format/website/$path/js.kt")),
+ defaultPlatforms = listOf("JS")
+ )
+ )
return module
}
diff --git a/core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt b/core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt
index 8076fb92..1901154f 100644
--- a/core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt
+++ b/core/src/test/kotlin/format/KotlinWebSiteHtmlFormatTest.kt
@@ -1,38 +1,38 @@
package org.jetbrains.dokka.tests
import org.jetbrains.dokka.*
-import org.junit.Before
import org.junit.Test
-class KotlinWebSiteHtmlFormatTest: FileGeneratorTestCase() {
+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")
+ verifyKWSNodeByName("dropImport", "foo", defaultModelConfig)
}
@Test fun sample() {
- verifyKWSNodeByName("sample", "foo")
+ verifyKWSNodeByName("sample", "foo", defaultModelConfig)
}
@Test fun sampleWithAsserts() {
- verifyKWSNodeByName("sampleWithAsserts", "a")
+ verifyKWSNodeByName("sampleWithAsserts", "a", defaultModelConfig)
}
@Test fun newLinesInSamples() {
- verifyKWSNodeByName("newLinesInSamples", "foo")
+ verifyKWSNodeByName("newLinesInSamples", "foo", defaultModelConfig)
}
@Test fun newLinesInImportList() {
- verifyKWSNodeByName("newLinesInImportList", "foo")
+ verifyKWSNodeByName("newLinesInImportList", "foo", defaultModelConfig)
}
@Test fun returnTag() {
- verifyKWSNodeByName("returnTag", "indexOf")
+ verifyKWSNodeByName("returnTag", "indexOf", defaultModelConfig)
}
@Test fun overloadGroup() {
- verifyKWSNodeByName("overloadGroup", "magic")
+ verifyKWSNodeByName("overloadGroup", "magic", defaultModelConfig)
}
@Test fun dataTags() {
@@ -52,26 +52,54 @@ class KotlinWebSiteHtmlFormatTest: FileGeneratorTestCase() {
verifyMultiplatformPackage(module, path)
}
- private fun verifyKWSNodeByName(fileName: String, name: String) {
- verifyOutput("testdata/format/website-html/$fileName.kt", ".html", format = "kotlin-website-html") { model, output ->
+ 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 module = DocumentationModule("test")
- val options = DocumentationOptions(
- outputDir = "",
- outputFormat = "kotlin-website-html",
- generateIndexPages = false,
+ val passConfiguration = PassConfigurationImpl(
noStdlibLink = true,
noJdkLink = true,
languageVersion = null,
apiVersion = null
)
- appendDocumentation(module, contentRootFromPath("testdata/format/website-html/$path/jvm.kt"), defaultPlatforms = listOf("JVM"), options = options)
- appendDocumentation(module, contentRootFromPath("testdata/format/website-html/$path/jre7.kt"), defaultPlatforms = listOf("JVM", "JRE7"), options = options)
- appendDocumentation(module, contentRootFromPath("testdata/format/website-html/$path/js.kt"), defaultPlatforms = listOf("JS"), options = options)
+
+ val dokkaConfiguration = DokkaConfigurationImpl(
+ outputDir = "",
+ format = "kotlin-website-html",
+ generateIndexPages = false,
+ passesConfigurations = listOf(
+ passConfiguration
+ )
+
+ )
+
+ appendDocumentation(
+ module, dokkaConfiguration, passConfiguration, ModelConfig(
+ roots = arrayOf(contentRootFromPath("testdata/format/website-html/$path/jvm.kt")),
+ defaultPlatforms = listOf("JVM")
+ )
+ )
+ appendDocumentation(
+ module, dokkaConfiguration, passConfiguration, ModelConfig(
+ roots = arrayOf(contentRootFromPath("testdata/format/website-html/$path/jre7.kt")),
+ defaultPlatforms = listOf("JVM", "JRE7")
+ )
+ )
+ appendDocumentation(
+ module, dokkaConfiguration, passConfiguration, ModelConfig(
+ roots = arrayOf(contentRootFromPath("testdata/format/website-html/$path/js.kt")),
+ defaultPlatforms = listOf("JS")
+ )
+ )
+
return module
}
@@ -82,3 +110,7 @@ class KotlinWebSiteHtmlFormatTest: FileGeneratorTestCase() {
}
}
+
+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
index b078292b..4796c17c 100644
--- a/core/src/test/kotlin/format/MarkdownFormatTest.kt
+++ b/core/src/test/kotlin/format/MarkdownFormatTest.kt
@@ -1,52 +1,35 @@
package org.jetbrains.dokka.tests
import org.jetbrains.dokka.*
-import org.junit.Before
import org.junit.Test
-class MarkdownFormatTest: FileGeneratorTestCase() {
+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")
+ verifyMarkdownNode("emptyDescription", defaultModelConfig)
}
@Test fun classWithCompanionObject() {
- verifyMarkdownNode("classWithCompanionObject")
+ verifyMarkdownNode("classWithCompanionObject", defaultModelConfig)
}
@Test fun annotations() {
- verifyMarkdownNode("annotations")
+ verifyMarkdownNode("annotations", defaultModelConfig)
}
@Test fun annotationClass() {
- verifyMarkdownNode("annotationClass", withKotlinRuntime = true)
- verifyMarkdownPackage("annotationClass", withKotlinRuntime = true)
- }
-
- @Test fun exceptionClass() {
- verifyMarkdownNode("exceptionClass", withKotlinRuntime = true)
- verifyMarkdownPackage("exceptionClass", withKotlinRuntime = true)
- }
-
- @Test fun annotationParams() {
- verifyMarkdownNode("annotationParams", withKotlinRuntime = true)
- }
-
- @Test fun extensions() {
- verifyOutput("testdata/format/extensions.kt", ".package.md") { model, output ->
- buildPagesAndReadInto(model.members, output)
- }
- verifyOutput("testdata/format/extensions.kt", ".class.md") { model, output ->
- buildPagesAndReadInto(model.members.single().members, output)
- }
+ verifyMarkdownNode("annotationClass", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
+ verifyMarkdownPackage("annotationClass", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
}
@Test fun enumClass() {
- verifyOutput("testdata/format/enumClass.kt", ".md") { model, output ->
+ verifyOutput("testdata/format/enumClass.kt", ".md", defaultModelConfig) { model, output ->
buildPagesAndReadInto(model.members.single().members, output)
}
- verifyOutput("testdata/format/enumClass.kt", ".value.md") { model, 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" },
@@ -56,235 +39,187 @@ class MarkdownFormatTest: FileGeneratorTestCase() {
}
@Test fun varargsFunction() {
- verifyMarkdownNode("varargsFunction")
+ verifyMarkdownNode("varargsFunction", defaultModelConfig)
}
@Test fun overridingFunction() {
- verifyMarkdownNodes("overridingFunction") { model->
+ 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")
+ verifyMarkdownNode("propertyVar", defaultModelConfig)
}
@Test fun functionWithDefaultParameter() {
- verifyMarkdownNode("functionWithDefaultParameter")
+ verifyMarkdownNode("functionWithDefaultParameter", defaultModelConfig)
}
@Test fun accessor() {
- verifyMarkdownNodes("accessor") { model ->
+ verifyMarkdownNodes("accessor", defaultModelConfig) { model ->
model.members.single().members.first { it.name == "C" }.members.filter { it.name == "x" }
}
}
@Test fun paramTag() {
- verifyMarkdownNode("paramTag")
+ verifyMarkdownNode("paramTag", defaultModelConfig)
}
@Test fun throwsTag() {
- verifyMarkdownNode("throwsTag")
+ verifyMarkdownNode("throwsTag", defaultModelConfig)
}
@Test fun typeParameterBounds() {
- verifyMarkdownNode("typeParameterBounds")
+ verifyMarkdownNode("typeParameterBounds", defaultModelConfig)
}
@Test fun typeParameterVariance() {
- verifyMarkdownNode("typeParameterVariance")
+ verifyMarkdownNode("typeParameterVariance", defaultModelConfig)
}
@Test fun typeProjectionVariance() {
- verifyMarkdownNode("typeProjectionVariance")
- }
-
- @Test fun javadocHtml() {
- verifyJavaMarkdownNode("javadocHtml")
- }
-
- @Test fun javaCodeLiteralTags() {
- verifyJavaMarkdownNode("javaCodeLiteralTags")
- }
-
- @Test fun javaCodeInParam() {
- verifyJavaMarkdownNodes("javaCodeInParam") {
- selectNodes(it) {
- subgraphOf(RefKind.Member)
- withKind(NodeKind.Function)
- }
- }
- }
-
- @Test fun javaSpaceInAuthor() {
- verifyJavaMarkdownNode("javaSpaceInAuthor")
- }
-
- @Test fun nullability() {
- verifyMarkdownNode("nullability")
- }
-
- @Test fun operatorOverloading() {
- verifyMarkdownNodes("operatorOverloading") { model->
- model.members.single().members.single { it.name == "C" }.members.filter { it.name == "plus" }
- }
- }
-
- @Test fun javadocOrderedList() {
- verifyJavaMarkdownNodes("javadocOrderedList") { model ->
- model.members.single().members.filter { it.name == "Bar" }
- }
+ verifyMarkdownNode("typeProjectionVariance", defaultModelConfig)
}
@Test fun codeBlockNoHtmlEscape() {
- verifyMarkdownNodeByName("codeBlockNoHtmlEscape", "hackTheArithmetic")
+ verifyMarkdownNodeByName("codeBlockNoHtmlEscape", "hackTheArithmetic", defaultModelConfig)
}
@Test fun companionObjectExtension() {
- verifyMarkdownNodeByName("companionObjectExtension", "Foo")
+ verifyMarkdownNodeByName("companionObjectExtension", "Foo", defaultModelConfig)
}
@Test fun starProjection() {
- verifyMarkdownNode("starProjection")
+ verifyMarkdownNode("starProjection", defaultModelConfig)
}
@Test fun extensionFunctionParameter() {
- verifyMarkdownNode("extensionFunctionParameter")
+ verifyMarkdownNode("extensionFunctionParameter", defaultModelConfig)
}
@Test fun summarizeSignatures() {
- verifyMarkdownNodes("summarizeSignatures") { model -> model.members }
- }
-
- @Test fun summarizeSignaturesProperty() {
- verifyMarkdownNodes("summarizeSignaturesProperty") { model -> model.members }
+ verifyMarkdownNodes("summarizeSignatures", defaultModelConfig) { model -> model.members }
}
@Test fun reifiedTypeParameter() {
- verifyMarkdownNode("reifiedTypeParameter", withKotlinRuntime = true)
+ verifyMarkdownNode("reifiedTypeParameter", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
}
@Test fun suspendInlineFunctionOrder() {
- verifyMarkdownNode("suspendInlineFunction", withKotlinRuntime = true)
+ verifyMarkdownNode("suspendInlineFunction", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
}
@Test fun inlineSuspendFunctionOrderChanged() {
- verifyMarkdownNode("inlineSuspendFunction", withKotlinRuntime = true)
+ verifyMarkdownNode("inlineSuspendFunction", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
}
@Test fun annotatedTypeParameter() {
- verifyMarkdownNode("annotatedTypeParameter", withKotlinRuntime = true)
+ verifyMarkdownNode("annotatedTypeParameter", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
}
@Test fun inheritedMembers() {
- verifyMarkdownNodeByName("inheritedMembers", "Bar")
+ verifyMarkdownNodeByName("inheritedMembers", "Bar", defaultModelConfig)
}
@Test fun inheritedExtensions() {
- verifyMarkdownNodeByName("inheritedExtensions", "Bar")
+ verifyMarkdownNodeByName("inheritedExtensions", "Bar", defaultModelConfig)
}
@Test fun genericInheritedExtensions() {
- verifyMarkdownNodeByName("genericInheritedExtensions", "Bar")
+ verifyMarkdownNodeByName("genericInheritedExtensions", "Bar", defaultModelConfig)
}
@Test fun arrayAverage() {
- verifyMarkdownNodeByName("arrayAverage", "XArray")
+ verifyMarkdownNodeByName("arrayAverage", "XArray", defaultModelConfig)
}
@Test fun multipleTypeParameterConstraints() {
- verifyMarkdownNode("multipleTypeParameterConstraints", withKotlinRuntime = true)
+ verifyMarkdownNode("multipleTypeParameterConstraints", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
}
@Test fun inheritedCompanionObjectProperties() {
- verifyMarkdownNodeByName("inheritedCompanionObjectProperties", "C")
+ verifyMarkdownNodeByName("inheritedCompanionObjectProperties", "C", defaultModelConfig)
}
@Test fun shadowedExtensionFunctions() {
- verifyMarkdownNodeByName("shadowedExtensionFunctions", "Bar")
+ verifyMarkdownNodeByName("shadowedExtensionFunctions", "Bar", defaultModelConfig)
}
@Test fun inapplicableExtensionFunctions() {
- verifyMarkdownNodeByName("inapplicableExtensionFunctions", "Bar")
+ verifyMarkdownNodeByName("inapplicableExtensionFunctions", "Bar", defaultModelConfig)
}
@Test fun receiverParameterTypeBound() {
- verifyMarkdownNodeByName("receiverParameterTypeBound", "Foo")
+ verifyMarkdownNodeByName("receiverParameterTypeBound", "Foo", defaultModelConfig)
}
@Test fun extensionWithDocumentedReceiver() {
- verifyMarkdownNodes("extensionWithDocumentedReceiver") { model ->
+ verifyMarkdownNodes("extensionWithDocumentedReceiver", defaultModelConfig) { model ->
model.members.single().members.single().members.filter { it.name == "fn" }
}
}
- @Test fun jdkLinks() {
- verifyMarkdownNode("jdkLinks", withKotlinRuntime = true)
- }
-
@Test fun codeBlock() {
- verifyMarkdownNode("codeBlock")
+ verifyMarkdownNode("codeBlock", defaultModelConfig)
}
@Test fun exclInCodeBlock() {
- verifyMarkdownNodeByName("exclInCodeBlock", "foo")
+ verifyMarkdownNodeByName("exclInCodeBlock", "foo", defaultModelConfig)
}
@Test fun backtickInCodeBlock() {
- verifyMarkdownNodeByName("backtickInCodeBlock", "foo")
+ verifyMarkdownNodeByName("backtickInCodeBlock", "foo", defaultModelConfig)
}
@Test fun qualifiedNameLink() {
- verifyMarkdownNodeByName("qualifiedNameLink", "foo", withKotlinRuntime = true)
+ verifyMarkdownNodeByName("qualifiedNameLink", "foo",
+ ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true))
}
@Test fun functionalTypeWithNamedParameters() {
- verifyMarkdownNode("functionalTypeWithNamedParameters")
+ verifyMarkdownNode("functionalTypeWithNamedParameters", defaultModelConfig)
}
@Test fun typeAliases() {
- verifyMarkdownNode("typeAliases")
- verifyMarkdownPackage("typeAliases")
- }
-
- @Test fun sampleByFQName() {
- verifyMarkdownNode("sampleByFQName")
+ verifyMarkdownNode("typeAliases", defaultModelConfig)
+ verifyMarkdownPackage("typeAliases", defaultModelConfig)
}
@Test fun sampleByShortName() {
- verifyMarkdownNode("sampleByShortName")
+ verifyMarkdownNode("sampleByShortName", defaultModelConfig)
}
@Test fun suspendParam() {
- verifyMarkdownNode("suspendParam")
- verifyMarkdownPackage("suspendParam")
+ verifyMarkdownNode("suspendParam", defaultModelConfig)
+ verifyMarkdownPackage("suspendParam", defaultModelConfig)
}
@Test fun sinceKotlin() {
- verifyMarkdownNode("sinceKotlin")
- verifyMarkdownPackage("sinceKotlin")
+ verifyMarkdownNode("sinceKotlin", defaultModelConfig)
+ verifyMarkdownPackage("sinceKotlin", defaultModelConfig)
}
@Test fun sinceKotlinWide() {
- verifyMarkdownPackage("sinceKotlinWide")
+ verifyMarkdownPackage("sinceKotlinWide", defaultModelConfig)
}
@Test fun dynamicType() {
- verifyMarkdownNode("dynamicType")
+ verifyMarkdownNode("dynamicType", defaultModelConfig)
}
@Test fun dynamicExtension() {
- verifyMarkdownNodes("dynamicExtension") { model -> model.members.single().members.filter { it.name == "Foo" } }
+ verifyMarkdownNodes("dynamicExtension", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Foo" } }
}
@Test fun memberExtension() {
- verifyMarkdownNodes("memberExtension") { model -> model.members.single().members.filter { it.name == "Foo" } }
+ verifyMarkdownNodes("memberExtension", defaultModelConfig) { model -> model.members.single().members.filter { it.name == "Foo" } }
}
@Test fun renderFunctionalTypeInParenthesisWhenItIsReceiver() {
- verifyMarkdownNode("renderFunctionalTypeInParenthesisWhenItIsReceiver")
+ verifyMarkdownNode("renderFunctionalTypeInParenthesisWhenItIsReceiver", defaultModelConfig)
}
@Test fun multiplePlatforms() {
@@ -321,16 +256,29 @@ class MarkdownFormatTest: FileGeneratorTestCase() {
@Test fun packagePlatformsWithExtExtensions() {
val path = "multiplatform/packagePlatformsWithExtExtensions"
val module = DocumentationModule("test")
- val options = DocumentationOptions(
- outputDir = "",
- outputFormat = "html",
- generateIndexPages = false,
+ val passConfiguration = PassConfigurationImpl(
noStdlibLink = true,
noJdkLink = true,
languageVersion = null,
apiVersion = null
)
- appendDocumentation(module, contentRootFromPath("testdata/format/$path/jvm.kt"), defaultPlatforms = listOf("JVM"), withKotlinRuntime = true, options = options)
+
+ 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)
}
@@ -366,107 +314,109 @@ class MarkdownFormatTest: FileGeneratorTestCase() {
}
@Test fun linksInEmphasis() {
- verifyMarkdownNode("linksInEmphasis")
+ verifyMarkdownNode("linksInEmphasis", defaultModelConfig)
}
@Test fun linksInStrong() {
- verifyMarkdownNode("linksInStrong")
+ verifyMarkdownNode("linksInStrong", defaultModelConfig)
}
@Test fun linksInHeaders() {
- verifyMarkdownNode("linksInHeaders")
+ verifyMarkdownNode("linksInHeaders", defaultModelConfig)
}
@Test fun tokensInEmphasis() {
- verifyMarkdownNode("tokensInEmphasis")
+ verifyMarkdownNode("tokensInEmphasis", defaultModelConfig)
}
@Test fun tokensInStrong() {
- verifyMarkdownNode("tokensInStrong")
+ verifyMarkdownNode("tokensInStrong", defaultModelConfig)
}
@Test fun tokensInHeaders() {
- verifyMarkdownNode("tokensInHeaders")
+ verifyMarkdownNode("tokensInHeaders", defaultModelConfig)
}
@Test fun unorderedLists() {
- verifyMarkdownNode("unorderedLists")
+ verifyMarkdownNode("unorderedLists", defaultModelConfig)
}
@Test fun nestedLists() {
- verifyMarkdownNode("nestedLists")
+ verifyMarkdownNode("nestedLists", defaultModelConfig)
}
@Test fun referenceLink() {
- verifyMarkdownNode("referenceLink")
+ verifyMarkdownNode("referenceLink", defaultModelConfig)
}
@Test fun externalReferenceLink() {
- verifyMarkdownNode("externalReferenceLink")
+ verifyMarkdownNode("externalReferenceLink", defaultModelConfig)
}
@Test fun newlineInTableCell() {
- verifyMarkdownPackage("newlineInTableCell")
+ verifyMarkdownPackage("newlineInTableCell", defaultModelConfig)
}
@Test fun indentedCodeBlock() {
- verifyMarkdownNode("indentedCodeBlock")
+ verifyMarkdownNode("indentedCodeBlock", defaultModelConfig)
}
@Test fun receiverReference() {
- verifyMarkdownNode("receiverReference")
+ verifyMarkdownNode("receiverReference", defaultModelConfig)
}
@Test fun extensionScope() {
- verifyMarkdownNodeByName("extensionScope", "test")
+ verifyMarkdownNodeByName("extensionScope", "test", defaultModelConfig)
}
@Test fun typeParameterReference() {
- verifyMarkdownNode("typeParameterReference")
+ verifyMarkdownNode("typeParameterReference", defaultModelConfig)
}
@Test fun notPublishedTypeAliasAutoExpansion() {
- verifyMarkdownNodeByName("notPublishedTypeAliasAutoExpansion", "foo", includeNonPublic = false)
+ verifyMarkdownNodeByName("notPublishedTypeAliasAutoExpansion", "foo", ModelConfig(
+ analysisPlatform = analysisPlatform,
+ includeNonPublic = false
+ ))
}
@Test fun companionImplements() {
- verifyMarkdownNodeByName("companionImplements", "Foo")
- }
-
- @Test fun enumRef() {
- verifyMarkdownNode("enumRef")
- }
-
- @Test fun inheritedLink() {
- val filePath = "testdata/format/inheritedLink"
- verifyOutput(
- arrayOf(
- contentRootFromPath("$filePath.kt"),
- contentRootFromPath("$filePath.1.kt")
- ),
- ".md",
- withJdk = true,
- withKotlinRuntime = true,
- includeNonPublic = false
- ) { model, output ->
- buildPagesAndReadInto(model.members.single { it.name == "p2" }.members.single().members, output)
- }
+ verifyMarkdownNodeByName("companionImplements", "Foo", defaultModelConfig)
}
private fun buildMultiplePlatforms(path: String): DocumentationModule {
val module = DocumentationModule("test")
- val options = DocumentationOptions(
- outputDir = "",
- outputFormat = "html",
- generateIndexPages = false,
+ val passConfiguration = PassConfigurationImpl(
noStdlibLink = true,
noJdkLink = true,
languageVersion = null,
apiVersion = null
)
- appendDocumentation(module, contentRootFromPath("testdata/format/$path/jvm.kt"), defaultPlatforms = listOf("JVM"), options = options)
- appendDocumentation(module, contentRootFromPath("testdata/format/$path/js.kt"), defaultPlatforms = listOf("JS"), options = options)
+ 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"),
+ analysisPlatform = Platform.jvm
+ )
+ )
+ appendDocumentation(
+ module, dokkaConfiguration, passConfiguration, ModelConfig(
+ roots = arrayOf(contentRootFromPath("testdata/format/$path/js.kt")),
+ defaultPlatforms = listOf("JS"),
+ analysisPlatform = Platform.js
+ )
+ )
+
return module
}
@@ -486,52 +436,49 @@ class MarkdownFormatTest: FileGeneratorTestCase() {
}
@Test fun blankLineInsideCodeBlock() {
- verifyMarkdownNode("blankLineInsideCodeBlock")
+ verifyMarkdownNode("blankLineInsideCodeBlock", defaultModelConfig)
}
- private fun verifyMarkdownPackage(fileName: String, withKotlinRuntime: Boolean = false) {
- verifyOutput("testdata/format/$fileName.kt", ".package.md", withKotlinRuntime = withKotlinRuntime) { model, output ->
+ protected fun verifyMarkdownPackage(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
+ verifyOutput("testdata/format/$fileName.kt", ".package.md", modelConfig) { model, output ->
buildPagesAndReadInto(model.members, output)
}
}
- private fun verifyMarkdownNode(fileName: String, withKotlinRuntime: Boolean = false) {
- verifyMarkdownNodes(fileName, withKotlinRuntime) { model -> model.members.single().members }
+ protected fun verifyMarkdownNode(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
+ verifyMarkdownNodes(fileName, modelConfig) { model -> model.members.single().members }
}
- private fun verifyMarkdownNodes(
+ protected fun verifyMarkdownNodes(
fileName: String,
- withKotlinRuntime: Boolean = false,
- includeNonPublic: Boolean = true,
+ modelConfig: ModelConfig = ModelConfig(),
nodeFilter: (DocumentationModule) -> List<DocumentationNode>
) {
verifyOutput(
"testdata/format/$fileName.kt",
".md",
- withKotlinRuntime = withKotlinRuntime,
- includeNonPublic = includeNonPublic
+ modelConfig
) { model, output ->
buildPagesAndReadInto(nodeFilter(model), output)
}
}
- private fun verifyJavaMarkdownNode(fileName: String, withKotlinRuntime: Boolean = false) {
- verifyJavaMarkdownNodes(fileName, withKotlinRuntime) { model -> model.members.single().members }
+ protected fun verifyJavaMarkdownNode(fileName: String, modelConfig: ModelConfig = ModelConfig()) {
+ verifyJavaMarkdownNodes(fileName, modelConfig) { model -> model.members.single().members }
}
- private fun verifyJavaMarkdownNodes(fileName: String, withKotlinRuntime: Boolean = false, nodeFilter: (DocumentationModule) -> List<DocumentationNode>) {
- verifyJavaOutput("testdata/format/$fileName.java", ".md", withKotlinRuntime = withKotlinRuntime) { model, output ->
+ 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)
}
}
- private fun verifyMarkdownNodeByName(
+ protected fun verifyMarkdownNodeByName(
fileName: String,
name: String,
- withKotlinRuntime: Boolean = false,
- includeNonPublic: Boolean = true
+ modelConfig: ModelConfig = ModelConfig()
) {
- verifyMarkdownNodes(fileName, withKotlinRuntime, includeNonPublic) { model->
+ verifyMarkdownNodes(fileName, modelConfig) { model->
val nodesWithName = model.members.single().members.filter { it.name == name }
if (nodesWithName.isEmpty()) {
throw IllegalArgumentException("Found no nodes named $name")
@@ -541,6 +488,124 @@ class MarkdownFormatTest: FileGeneratorTestCase() {
}
@Test fun nullableTypeParameterFunction() {
- verifyMarkdownNode("nullableTypeParameterFunction", withKotlinRuntime = true)
+ 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/issues/IssuesTest.kt b/core/src/test/kotlin/issues/IssuesTest.kt
index 625d7e46..da5acd6e 100644
--- a/core/src/test/kotlin/issues/IssuesTest.kt
+++ b/core/src/test/kotlin/issues/IssuesTest.kt
@@ -2,17 +2,19 @@ package issues
import org.jetbrains.dokka.DocumentationNode
import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.tests.toTestString
-import org.jetbrains.dokka.tests.verifyModel
+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
-
-class IssuesTest {
+abstract class BaseIssuesTest(val analysisPlatform: Platform) {
+ val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
@Test
fun errorClasses() {
- verifyModel("testdata/issues/errorClasses.kt", withJdk = true, withKotlinRuntime = true) { model ->
+ 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
@@ -26,3 +28,7 @@ class IssuesTest {
}
}
}
+
+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
index 6adbe7a0..d4f82571 100644
--- a/core/src/test/kotlin/javadoc/JavadocTest.kt
+++ b/core/src/test/kotlin/javadoc/JavadocTest.kt
@@ -3,15 +3,19 @@ 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.verifyModel
+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", withJdk = true) { doc ->
+ 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" }!!
@@ -27,7 +31,7 @@ class JavadocTest {
}
@Test fun testObject() {
- verifyJavadoc("testdata/javadoc/obj.kt") { doc ->
+ verifyJavadoc("testdata/javadoc/obj.kt", defaultModelConfig) { doc ->
val classDoc = doc.classNamed("foo.O")
assertNotNull(classDoc)
@@ -40,7 +44,10 @@ class JavadocTest {
}
@Test fun testException() {
- verifyJavadoc("testdata/javadoc/exception.kt", withKotlinRuntime = true) { doc ->
+ 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())
@@ -48,7 +55,10 @@ class JavadocTest {
}
@Test fun testByteArray() {
- verifyJavadoc("testdata/javadoc/bytearr.kt", withKotlinRuntime = true) { doc ->
+ verifyJavadoc(
+ "testdata/javadoc/bytearr.kt",
+ ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
+ ) { doc ->
val classDoc = doc.classNamed("foo.ByteArray")!!
assertNotNull(classDoc.asClassDoc())
@@ -58,7 +68,10 @@ class JavadocTest {
}
@Test fun testStringArray() {
- verifyJavadoc("testdata/javadoc/stringarr.kt", withKotlinRuntime = true) { doc ->
+ verifyJavadoc(
+ "testdata/javadoc/stringarr.kt",
+ ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
+ ) { doc ->
val classDoc = doc.classNamed("foo.Foo")!!
assertNotNull(classDoc.asClassDoc())
@@ -71,7 +84,10 @@ class JavadocTest {
}
@Test fun testJvmName() {
- verifyJavadoc("testdata/javadoc/jvmname.kt", withKotlinRuntime = true) { doc ->
+ verifyJavadoc(
+ "testdata/javadoc/jvmname.kt",
+ ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
+ ) { doc ->
val classDoc = doc.classNamed("foo.Apple")!!
assertNotNull(classDoc.asClassDoc())
@@ -81,7 +97,10 @@ class JavadocTest {
}
@Test fun testLinkWithParam() {
- verifyJavadoc("testdata/javadoc/paramlink.kt", withKotlinRuntime = true) { doc ->
+ 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>()
@@ -92,7 +111,10 @@ class JavadocTest {
}
@Test fun testInternalVisibility() {
- verifyJavadoc("testdata/javadoc/internal.kt", withKotlinRuntime = true, includeNonPublic = false) { doc ->
+ 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)
@@ -101,7 +123,10 @@ class JavadocTest {
}
@Test fun testSuppress() {
- verifyJavadoc("testdata/javadoc/suppress.kt", withKotlinRuntime = true) { doc ->
+ verifyJavadoc(
+ "testdata/javadoc/suppress.kt",
+ ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
+ ) { doc ->
assertNull(doc.classNamed("Some"))
assertNull(doc.classNamed("SomeAgain"))
assertNull(doc.classNamed("Interface"))
@@ -112,7 +137,10 @@ class JavadocTest {
}
@Test fun testTypeAliases() {
- verifyJavadoc("testdata/javadoc/typealiases.kt", withKotlinRuntime = true) { doc ->
+ verifyJavadoc(
+ "testdata/javadoc/typealiases.kt",
+ ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)
+ ) { doc ->
assertNull(doc.classNamed("B"))
assertNull(doc.classNamed("D"))
@@ -127,7 +155,10 @@ class JavadocTest {
}
@Test fun testKDocKeywordsOnMethod() {
- verifyJavadoc("testdata/javadoc/kdocKeywordsOnMethod.kt", withKotlinRuntime = true) { doc ->
+ 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())
@@ -137,7 +168,10 @@ class JavadocTest {
@Test
fun testBlankLineInsideCodeBlock() {
- verifyJavadoc("testdata/javadoc/blankLineInsideCodeBlock.kt", withKotlinRuntime = true) { doc ->
+ 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("""
@@ -154,7 +188,7 @@ class JavadocTest {
@Test
fun testCompanionMethodReference() {
- verifyJavadoc("testdata/javadoc/companionMethodReference.kt") { doc ->
+ 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())
@@ -180,7 +214,7 @@ class JavadocTest {
@Test
fun shouldHaveValidVisibilityModifiers() {
- verifyJavadoc("testdata/javadoc/visibilityModifiers.kt", withKotlinRuntime = true) { doc ->
+ verifyJavadoc("testdata/javadoc/visibilityModifiers.kt", ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)) { doc ->
val classDoc = doc.classNamed("foo.Apple")!!
val methods = classDoc.methods()
@@ -272,12 +306,17 @@ class JavadocTest {
private fun verifyJavadoc(name: String,
- withJdk: Boolean = false,
- withKotlinRuntime: Boolean = false,
- includeNonPublic: Boolean = true,
+ modelConfig: ModelConfig = ModelConfig(),
callback: (ModuleNodeAdapter) -> Unit) {
- verifyModel(name, format = "javadoc", withJdk = withJdk, withKotlinRuntime = withKotlinRuntime, includeNonPublic = includeNonPublic) { model ->
+ 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/model/ClassTest.kt b/core/src/test/kotlin/model/ClassTest.kt
index ea586041..b8e58a62 100644
--- a/core/src/test/kotlin/model/ClassTest.kt
+++ b/core/src/test/kotlin/model/ClassTest.kt
@@ -2,14 +2,17 @@ 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
-class ClassTest {
+abstract class BaseClassTest(val analysisPlatform: Platform) {
+ protected val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
@Test fun emptyClass() {
- verifyModel("testdata/classes/emptyClass.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/classes/emptyClass.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(NodeKind.Class, kind)
assertEquals("Klass", name)
@@ -21,7 +24,7 @@ class ClassTest {
}
@Test fun emptyObject() {
- verifyModel("testdata/classes/emptyObject.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/classes/emptyObject.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(NodeKind.Object, kind)
assertEquals("Obj", name)
@@ -33,7 +36,7 @@ class ClassTest {
}
@Test fun classWithConstructor() {
- verifyModel("testdata/classes/classWithConstructor.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/classes/classWithConstructor.kt", defaultModelConfig) { model ->
with (model.members.single().members.single()) {
assertEquals(NodeKind.Class, kind)
assertEquals("Klass", name)
@@ -63,7 +66,7 @@ class ClassTest {
}
@Test fun classWithFunction() {
- verifyModel("testdata/classes/classWithFunction.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/classes/classWithFunction.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(NodeKind.Class, kind)
assertEquals("Klass", name)
@@ -93,7 +96,7 @@ class ClassTest {
}
@Test fun classWithProperty() {
- verifyModel("testdata/classes/classWithProperty.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/classes/classWithProperty.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(NodeKind.Class, kind)
assertEquals("Klass", name)
@@ -123,7 +126,7 @@ class ClassTest {
}
@Test fun classWithCompanionObject() {
- verifyModel("testdata/classes/classWithCompanionObject.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/classes/classWithCompanionObject.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(NodeKind.Class, kind)
assertEquals("Klass", name)
@@ -151,33 +154,25 @@ class ClassTest {
}
}
- @Test fun annotatedClass() {
- verifyPackageMember("testdata/classes/annotatedClass.kt", withKotlinRuntime = true) { cls ->
- assertEquals(1, cls.annotations.count())
- with(cls.annotations[0]) {
- assertEquals("Strictfp", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Annotation, kind)
- }
- }
- }
-
@Test fun dataClass() {
- verifyPackageMember("testdata/classes/dataClass.kt") { cls ->
+ 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") { cls ->
+ 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() {
- verifyModel("testdata/classes/annotatedClassWithAnnotationParameters.kt") { model ->
+ checkSourceExistsAndVerifyModel(
+ "testdata/classes/annotatedClassWithAnnotationParameters.kt",
+ defaultModelConfig
+ ) { model ->
with(model.members.single().members.single()) {
with(deprecation!!) {
assertEquals("Deprecated", name)
@@ -197,29 +192,8 @@ class ClassTest {
}
}
- @Test fun javaAnnotationClass() {
- verifyModel("testdata/classes/javaAnnotationClass.kt", withJdk = true) { model ->
- with(model.members.single().members.single()) {
- assertEquals(1, annotations.count())
- with(annotations[0]) {
- assertEquals("Retention", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Annotation, kind)
- with(details[0]) {
- assertEquals(NodeKind.Parameter, kind)
- assertEquals(1, details.count())
- with(details[0]) {
- assertEquals(NodeKind.Value, kind)
- assertEquals("RetentionPolicy.SOURCE", name)
- }
- }
- }
- }
- }
- }
-
@Test fun notOpenClass() {
- verifyModel("testdata/classes/notOpenClass.kt") { model ->
+ 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)
@@ -232,7 +206,7 @@ class ClassTest {
}
@Test fun indirectOverride() {
- verifyModel("testdata/classes/indirectOverride.kt") { model ->
+ 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)
@@ -245,7 +219,7 @@ class ClassTest {
}
@Test fun innerClass() {
- verifyPackageMember("testdata/classes/innerClass.kt") { cls ->
+ 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)
@@ -254,7 +228,7 @@ class ClassTest {
}
@Test fun companionObjectExtension() {
- verifyModel("testdata/classes/companionObjectExtension.kt") { model ->
+ 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 }
@@ -263,7 +237,7 @@ class ClassTest {
}
@Test fun secondaryConstructor() {
- verifyPackageMember("testdata/classes/secondaryConstructor.kt") { cls ->
+ 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}) {
@@ -274,7 +248,7 @@ class ClassTest {
}
@Test fun sinceKotlin() {
- verifyModel("testdata/classes/sinceKotlin.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/classes/sinceKotlin.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(listOf("Kotlin 1.1"), platforms)
}
@@ -282,7 +256,10 @@ class ClassTest {
}
@Test fun privateCompanionObject() {
- verifyModel("testdata/classes/privateCompanionObject.kt", includeNonPublic = false) { model ->
+ 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)
@@ -291,3 +268,51 @@ class ClassTest {
}
}
+
+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
index 3752bb8c..08aa3572 100644
--- a/core/src/test/kotlin/model/CommentTest.kt
+++ b/core/src/test/kotlin/model/CommentTest.kt
@@ -4,10 +4,10 @@ import org.junit.Test
import org.junit.Assert.*
import org.jetbrains.dokka.*
-public class CommentTest {
-
+abstract class BaseCommentTest(val analysisPlatform: Platform) {
+ val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
@Test fun codeBlockComment() {
- verifyModel("testdata/comments/codeBlockComment.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/codeBlockComment.kt", defaultModelConfig) { model ->
with(model.members.single().members.first()) {
assertEqualsIgnoringSeparators("""[code lang=brainfuck]
|
@@ -30,7 +30,7 @@ public class CommentTest {
}
@Test fun emptyDoc() {
- verifyModel("testdata/comments/emptyDoc.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/emptyDoc.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(Content.Empty, content)
}
@@ -38,7 +38,7 @@ public class CommentTest {
}
@Test fun emptyDocButComment() {
- verifyModel("testdata/comments/emptyDocButComment.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/emptyDocButComment.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(Content.Empty, content)
}
@@ -46,7 +46,7 @@ public class CommentTest {
}
@Test fun multilineDoc() {
- verifyModel("testdata/comments/multilineDoc.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/multilineDoc.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("doc1", content.summary.toTestString())
assertEquals("doc2\ndoc3", content.description.toTestString())
@@ -55,7 +55,7 @@ public class CommentTest {
}
@Test fun multilineDocWithComment() {
- verifyModel("testdata/comments/multilineDocWithComment.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/multilineDocWithComment.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("doc1", content.summary.toTestString())
assertEquals("doc2\ndoc3", content.description.toTestString())
@@ -64,7 +64,7 @@ public class CommentTest {
}
@Test fun oneLineDoc() {
- verifyModel("testdata/comments/oneLineDoc.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/oneLineDoc.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("doc", content.summary.toTestString())
}
@@ -72,7 +72,7 @@ public class CommentTest {
}
@Test fun oneLineDocWithComment() {
- verifyModel("testdata/comments/oneLineDocWithComment.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/oneLineDocWithComment.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("doc", content.summary.toTestString())
}
@@ -80,7 +80,7 @@ public class CommentTest {
}
@Test fun oneLineDocWithEmptyLine() {
- verifyModel("testdata/comments/oneLineDocWithEmptyLine.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/oneLineDocWithEmptyLine.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("doc", content.summary.toTestString())
}
@@ -88,7 +88,7 @@ public class CommentTest {
}
@Test fun emptySection() {
- verifyModel("testdata/comments/emptySection.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/emptySection.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Summary", content.summary.toTestString())
assertEquals(1, content.sections.count())
@@ -101,7 +101,7 @@ public class CommentTest {
}
@Test fun quotes() {
- verifyModel("testdata/comments/quotes.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/quotes.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("it's \"useful\"", content.summary.toTestString())
}
@@ -109,7 +109,7 @@ public class CommentTest {
}
@Test fun section1() {
- verifyModel("testdata/comments/section1.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/section1.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Summary", content.summary.toTestString())
assertEquals(1, content.sections.count())
@@ -122,7 +122,7 @@ public class CommentTest {
}
@Test fun section2() {
- verifyModel("testdata/comments/section2.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/section2.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Summary", content.summary.toTestString())
assertEquals(2, content.sections.count())
@@ -139,7 +139,7 @@ public class CommentTest {
}
@Test fun multilineSection() {
- verifyModel("testdata/comments/multilineSection.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/multilineSection.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Summary", content.summary.toTestString())
assertEquals(1, content.sections.count())
@@ -153,7 +153,7 @@ line two""", toTestString())
}
@Test fun directive() {
- verifyModel("testdata/comments/directive.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/comments/directive.kt", defaultModelConfig) { model ->
with(model.members.single().members.first()) {
assertEquals("Summary", content.summary.toTestString())
with (content.description) {
@@ -184,3 +184,7 @@ line two""", 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/FunctionTest.kt b/core/src/test/kotlin/model/FunctionTest.kt
index fd7a16a4..2a60751d 100644
--- a/core/src/test/kotlin/model/FunctionTest.kt
+++ b/core/src/test/kotlin/model/FunctionTest.kt
@@ -2,14 +2,17 @@ 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
-import kotlin.test.assertNotNull
-class FunctionTest {
+abstract class BaseFunctionTest(val analysisPlatform: Platform) {
+ protected val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
@Test fun function() {
- verifyModel("testdata/functions/function.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/functions/function.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("fn", name)
assertEquals(NodeKind.Function, kind)
@@ -22,7 +25,7 @@ class FunctionTest {
}
@Test fun functionWithReceiver() {
- verifyModel("testdata/functions/functionWithReceiver.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/functions/functionWithReceiver.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("kotlin.String", name)
assertEquals(NodeKind.ExternalClass, kind)
@@ -54,7 +57,7 @@ class FunctionTest {
}
@Test fun genericFunction() {
- verifyModel("testdata/functions/genericFunction.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/functions/genericFunction.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("generic", name)
assertEquals(NodeKind.Function, kind)
@@ -78,7 +81,7 @@ class FunctionTest {
}
}
@Test fun genericFunctionWithConstraints() {
- verifyModel("testdata/functions/genericFunctionWithConstraints.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/functions/genericFunctionWithConstraints.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("generic", name)
assertEquals(NodeKind.Function, kind)
@@ -118,7 +121,7 @@ class FunctionTest {
}
@Test fun functionWithParams() {
- verifyModel("testdata/functions/functionWithParams.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/functions/functionWithParams.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("function", name)
assertEquals(NodeKind.Function, kind)
@@ -143,25 +146,14 @@ Documentation""", content.description.toTestString())
}
}
- @Test fun annotatedFunction() {
- verifyPackageMember("testdata/functions/annotatedFunction.kt", withKotlinRuntime = true) { func ->
- assertEquals(1, func.annotations.count())
- with(func.annotations[0]) {
- assertEquals("Strictfp", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Annotation, kind)
- }
- }
- }
-
@Test fun functionWithNotDocumentedAnnotation() {
- verifyPackageMember("testdata/functions/functionWithNotDocumentedAnnotation.kt") { func ->
+ verifyPackageMember("testdata/functions/functionWithNotDocumentedAnnotation.kt", defaultModelConfig) { func ->
assertEquals(0, func.annotations.count())
}
}
@Test fun inlineFunction() {
- verifyPackageMember("testdata/functions/inlineFunction.kt") { func ->
+ verifyPackageMember("testdata/functions/inlineFunction.kt", defaultModelConfig) { func ->
val modifiers = func.details(NodeKind.Modifier).map { it.name }
assertTrue("inline" in modifiers)
}
@@ -195,7 +187,7 @@ Documentation""", content.description.toTestString())
}
@Test fun functionWithAnnotatedParam() {
- verifyModel("testdata/functions/functionWithAnnotatedParam.kt") { model ->
+ 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())
@@ -210,7 +202,7 @@ Documentation""", content.description.toTestString())
}
@Test fun functionWithNoinlineParam() {
- verifyPackageMember("testdata/functions/functionWithNoinlineParam.kt") { func ->
+ 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)
@@ -219,7 +211,10 @@ Documentation""", content.description.toTestString())
}
@Test fun annotatedFunctionWithAnnotationParameters() {
- verifyModel("testdata/functions/annotatedFunctionWithAnnotationParameters.kt") { model ->
+ checkSourceExistsAndVerifyModel(
+ "testdata/functions/annotatedFunctionWithAnnotationParameters.kt",
+ defaultModelConfig
+ ) { model ->
with(model.members.single().members.single { it.name == "f" }) {
assertEquals(1, annotations.count())
with(annotations[0]) {
@@ -241,7 +236,7 @@ Documentation""", content.description.toTestString())
}
@Test fun functionWithDefaultParameter() {
- verifyModel("testdata/functions/functionWithDefaultParameter.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/functions/functionWithDefaultParameter.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
with(details.elementAt(3)) {
val value = details(NodeKind.Value)
@@ -255,10 +250,32 @@ Documentation""", content.description.toTestString())
}
@Test fun sinceKotlin() {
- verifyModel("testdata/functions/sinceKotlin.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/functions/sinceKotlin.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(listOf("Kotlin 1.1"), platforms)
}
}
}
}
+
+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
index 0bec6d01..da9da624 100644
--- a/core/src/test/kotlin/model/JavaTest.kt
+++ b/core/src/test/kotlin/model/JavaTest.kt
@@ -1,14 +1,16 @@
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") { cls ->
+ verifyJavaPackageMember("testdata/java/member.java", defaultModelConfig) { cls ->
assertEquals("Test", cls.name)
assertEquals(NodeKind.Class, cls.kind)
with(cls.members(NodeKind.Function).single()) {
@@ -45,7 +47,7 @@ public class JavaTest {
}
@Test fun memberWithModifiers() {
- verifyJavaPackageMember("testdata/java/memberWithModifiers.java") { cls ->
+ 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" }) {
@@ -58,7 +60,7 @@ public class JavaTest {
}
@Test fun superClass() {
- verifyJavaPackageMember("testdata/java/superClass.java") { cls ->
+ verifyJavaPackageMember("testdata/java/superClass.java", defaultModelConfig) { cls ->
val superTypes = cls.details(NodeKind.Supertype)
assertEquals(2, superTypes.size)
assertEquals("Exception", superTypes[0].name)
@@ -67,7 +69,7 @@ public class JavaTest {
}
@Test fun arrayType() {
- verifyJavaPackageMember("testdata/java/arrayType.java") { cls ->
+ verifyJavaPackageMember("testdata/java/arrayType.java", defaultModelConfig) { cls ->
with(cls.members(NodeKind.Function).single()) {
val type = detail(NodeKind.Type)
assertEquals("Array", type.name)
@@ -81,7 +83,7 @@ public class JavaTest {
}
@Test fun typeParameter() {
- verifyJavaPackageMember("testdata/java/typeParameter.java") { cls ->
+ verifyJavaPackageMember("testdata/java/typeParameter.java", defaultModelConfig) { cls ->
val typeParameters = cls.details(NodeKind.TypeParameter)
with(typeParameters.single()) {
assertEquals("T", name)
@@ -100,7 +102,7 @@ public class JavaTest {
}
@Test fun constructors() {
- verifyJavaPackageMember("testdata/java/constructors.java") { cls ->
+ verifyJavaPackageMember("testdata/java/constructors.java", defaultModelConfig) { cls ->
val constructors = cls.members(NodeKind.Constructor)
assertEquals(2, constructors.size)
with(constructors[0]) {
@@ -110,14 +112,14 @@ public class JavaTest {
}
@Test fun innerClass() {
- verifyJavaPackageMember("testdata/java/InnerClass.java") { cls ->
+ 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") { cls ->
+ 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)
@@ -128,7 +130,7 @@ public class JavaTest {
}
@Test fun fields() {
- verifyJavaPackageMember("testdata/java/field.java") { cls ->
+ 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 })
@@ -141,7 +143,7 @@ public class JavaTest {
}
@Test fun staticMethod() {
- verifyJavaPackageMember("testdata/java/staticMethod.java") { cls ->
+ 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 })
}
@@ -154,13 +156,13 @@ public class JavaTest {
* Proposed tag `@exclude` for it, but not supported yet
*/
@Ignore("@suppress not supported in Java!") @Test fun suppressTag() {
- verifyJavaPackageMember("testdata/java/suppressTag.java") { cls ->
+ verifyJavaPackageMember("testdata/java/suppressTag.java", defaultModelConfig) { cls ->
assertEquals(1, cls.members(NodeKind.Function).size)
}
}
@Test fun annotatedAnnotation() {
- verifyJavaPackageMember("testdata/java/annotatedAnnotation.java") { cls ->
+ verifyJavaPackageMember("testdata/java/annotatedAnnotation.java", defaultModelConfig) { cls ->
assertEquals(1, cls.annotations.size)
with(cls.annotations[0]) {
assertEquals(1, details.count())
@@ -177,21 +179,21 @@ public class JavaTest {
}
@Test fun deprecation() {
- verifyJavaPackageMember("testdata/java/deprecation.java") { cls ->
+ 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") { cls ->
+ 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") { cls ->
+ verifyJavaPackageMember("testdata/java/enumValues.java", defaultModelConfig) { cls ->
val superTypes = cls.details(NodeKind.Supertype)
assertEquals(1, superTypes.size)
assertEquals(1, cls.members(NodeKind.EnumItem).size)
@@ -199,7 +201,7 @@ public class JavaTest {
}
@Test fun inheritorLinks() {
- verifyJavaPackageMember("testdata/java/InheritorLinks.java") { cls ->
+ 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
index 22818038..b5c15618 100644
--- a/core/src/test/kotlin/model/KotlinAsJavaTest.kt
+++ b/core/src/test/kotlin/model/KotlinAsJavaTest.kt
@@ -2,6 +2,7 @@ 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.Test
@@ -50,11 +51,15 @@ class KotlinAsJavaTest {
}
fun verifyModelAsJava(source: String,
- withJdk: Boolean = false,
- withKotlinRuntime: Boolean = false,
+ modelConfig: ModelConfig = ModelConfig(),
verifier: (DocumentationModule) -> Unit) {
- verifyModel(source,
- withJdk = withJdk, withKotlinRuntime = withKotlinRuntime,
+ checkSourceExistsAndVerifyModel(
+ source,
+ modelConfig = ModelConfig(
+ withJdk = modelConfig.withJdk,
+ withKotlinRuntime = modelConfig.withKotlinRuntime,
format = "html-as-java",
- verifier = verifier)
+ analysisPlatform = Platform.jvm),
+ verifier = verifier
+ )
}
diff --git a/core/src/test/kotlin/model/LinkTest.kt b/core/src/test/kotlin/model/LinkTest.kt
index 6b72525f..9b2f9f0d 100644
--- a/core/src/test/kotlin/model/LinkTest.kt
+++ b/core/src/test/kotlin/model/LinkTest.kt
@@ -3,12 +3,14 @@ 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
-class LinkTest {
+abstract class BaseLinkTest(val analysisPlatform: Platform) {
+ private val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
@Test fun linkToSelf() {
- verifyModel("testdata/links/linkToSelf.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/links/linkToSelf.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Foo", name)
assertEquals(NodeKind.Class, kind)
@@ -18,7 +20,7 @@ class LinkTest {
}
@Test fun linkToMember() {
- verifyModel("testdata/links/linkToMember.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/links/linkToMember.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Foo", name)
assertEquals(NodeKind.Class, kind)
@@ -28,7 +30,7 @@ class LinkTest {
}
@Test fun linkToConstantWithUnderscores() {
- verifyModel("testdata/links/linkToConstantWithUnderscores.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/links/linkToConstantWithUnderscores.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Foo", name)
assertEquals(NodeKind.Class, kind)
@@ -38,7 +40,7 @@ class LinkTest {
}
@Test fun linkToQualifiedMember() {
- verifyModel("testdata/links/linkToQualifiedMember.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/links/linkToQualifiedMember.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Foo", name)
assertEquals(NodeKind.Class, kind)
@@ -48,7 +50,7 @@ class LinkTest {
}
@Test fun linkToParam() {
- verifyModel("testdata/links/linkToParam.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/links/linkToParam.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("Foo", name)
assertEquals(NodeKind.Function, kind)
@@ -58,7 +60,7 @@ class LinkTest {
}
@Test fun linkToPackage() {
- verifyModel("testdata/links/linkToPackage.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/links/linkToPackage.kt", defaultModelConfig) { model ->
val packageNode = model.members.single()
with(packageNode) {
assertEquals(this.name, "test.magic")
@@ -72,4 +74,8 @@ class LinkTest {
}
}
-} \ No newline at end of file
+}
+
+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
index 7a8f0d06..e20e6afa 100644
--- a/core/src/test/kotlin/model/PackageTest.kt
+++ b/core/src/test/kotlin/model/PackageTest.kt
@@ -1,15 +1,14 @@
package org.jetbrains.dokka.tests
-import org.jetbrains.dokka.Content
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.PackageOptionsImpl
+import org.jetbrains.dokka.*
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
import org.junit.Assert.*
import org.junit.Test
-public class PackageTest {
+abstract class BasePackageTest(val analysisPlatform: Platform) {
+ val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
@Test fun rootPackage() {
- verifyModel("testdata/packages/rootPackage.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/packages/rootPackage.kt", defaultModelConfig) { model ->
with(model.members.single()) {
assertEquals(NodeKind.Package, kind)
assertEquals("", name)
@@ -22,7 +21,7 @@ public class PackageTest {
}
@Test fun simpleNamePackage() {
- verifyModel("testdata/packages/simpleNamePackage.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/packages/simpleNamePackage.kt", defaultModelConfig) { model ->
with(model.members.single()) {
assertEquals(NodeKind.Package, kind)
assertEquals("simple", name)
@@ -35,7 +34,7 @@ public class PackageTest {
}
@Test fun dottedNamePackage() {
- verifyModel("testdata/packages/dottedNamePackage.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/packages/dottedNamePackage.kt", defaultModelConfig) { model ->
with(model.members.single()) {
assertEquals(NodeKind.Package, kind)
assertEquals("dot.name", name)
@@ -48,8 +47,15 @@ public class PackageTest {
}
@Test fun multipleFiles() {
- verifyModel(KotlinSourceRoot("testdata/packages/dottedNamePackage.kt", false),
- KotlinSourceRoot("testdata/packages/simpleNamePackage.kt", false)) { model ->
+ 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)
@@ -70,8 +76,15 @@ public class PackageTest {
}
@Test fun multipleFilesSamePackage() {
- verifyModel(KotlinSourceRoot("testdata/packages/simpleNamePackage.kt", false),
- KotlinSourceRoot("testdata/packages/simpleNamePackage2.kt", false)) { model ->
+ 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)
@@ -85,7 +98,12 @@ public class PackageTest {
}
@Test fun classAtPackageLevel() {
- verifyModel(KotlinSourceRoot("testdata/packages/classInPackage.kt", false)) { model ->
+ 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)
@@ -99,8 +117,15 @@ public class PackageTest {
}
@Test fun suppressAtPackageLevel() {
- verifyModel(KotlinSourceRoot("testdata/packages/classInPackage.kt", false),
- perPackageOptions = listOf(PackageOptionsImpl(prefix = "simple.name", suppress = true))) { model ->
+ verifyModel(
+ ModelConfig(
+ roots = arrayOf(KotlinSourceRoot("testdata/packages/classInPackage.kt", false)),
+ perPackageOptions = listOf(
+ PackageOptionsImpl(prefix = "simple.name", suppress = true)
+ ),
+ analysisPlatform = analysisPlatform
+ )
+ ) { model ->
assertEquals(1, model.members.count())
with(model.members.elementAt(0)) {
assertEquals(NodeKind.Package, kind)
@@ -113,3 +138,7 @@ public class PackageTest {
}
}
}
+
+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
index 296eaa4c..b3481265 100644
--- a/core/src/test/kotlin/model/PropertyTest.kt
+++ b/core/src/test/kotlin/model/PropertyTest.kt
@@ -1,15 +1,16 @@
package org.jetbrains.dokka.tests
-import org.jetbrains.dokka.Content
-import org.jetbrains.dokka.NodeKind
-import org.jetbrains.dokka.RefKind
+import org.jetbrains.dokka.*
+import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
-class PropertyTest {
+abstract class BasePropertyTest(val analysisPlatform: Platform) {
+
+ protected val defaultModelConfig = ModelConfig(analysisPlatform = analysisPlatform)
@Test fun valueProperty() {
- verifyModel("testdata/properties/valueProperty.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/properties/valueProperty.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("property", name)
assertEquals(NodeKind.Property, kind)
@@ -22,7 +23,7 @@ class PropertyTest {
}
@Test fun variableProperty() {
- verifyModel("testdata/properties/variableProperty.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/properties/variableProperty.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("property", name)
assertEquals(NodeKind.Property, kind)
@@ -35,7 +36,7 @@ class PropertyTest {
}
@Test fun valuePropertyWithGetter() {
- verifyModel("testdata/properties/valuePropertyWithGetter.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/properties/valuePropertyWithGetter.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("property", name)
assertEquals(NodeKind.Property, kind)
@@ -48,7 +49,7 @@ class PropertyTest {
}
@Test fun variablePropertyWithAccessors() {
- verifyModel("testdata/properties/variablePropertyWithAccessors.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/properties/variablePropertyWithAccessors.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals("property", name)
assertEquals(NodeKind.Property, kind)
@@ -64,21 +65,11 @@ class PropertyTest {
}
}
- @Test fun annotatedProperty() {
- verifyModel("testdata/properties/annotatedProperty.kt", withKotlinRuntime = true) { model ->
- with(model.members.single().members.single()) {
- assertEquals(1, annotations.count())
- with(annotations[0]) {
- assertEquals("Strictfp", name)
- assertEquals(Content.Empty, content)
- assertEquals(NodeKind.Annotation, kind)
- }
- }
- }
- }
-
@Test fun propertyWithReceiver() {
- verifyModel("testdata/properties/propertyWithReceiver.kt") { model ->
+ checkSourceExistsAndVerifyModel(
+ "testdata/properties/propertyWithReceiver.kt",
+ defaultModelConfig
+ ) { model ->
with(model.members.single().members.single()) {
assertEquals("kotlin.String", name)
assertEquals(NodeKind.ExternalClass, kind)
@@ -91,7 +82,7 @@ class PropertyTest {
}
@Test fun propertyOverride() {
- verifyModel("testdata/properties/propertyOverride.kt") { model ->
+ 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
@@ -102,10 +93,37 @@ class PropertyTest {
}
@Test fun sinceKotlin() {
- verifyModel("testdata/properties/sinceKotlin.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/properties/sinceKotlin.kt", defaultModelConfig) { model ->
with(model.members.single().members.single()) {
assertEquals(listOf("Kotlin 1.1"), platforms)
}
}
}
}
+
+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
index a72bd62a..9812569d 100644
--- a/core/src/test/kotlin/model/SourceLinksErrorTest.kt
+++ b/core/src/test/kotlin/model/SourceLinksErrorTest.kt
@@ -2,7 +2,8 @@ package org.jetbrains.dokka.tests.model
import org.jetbrains.dokka.NodeKind
import org.jetbrains.dokka.SourceLinkDefinitionImpl
-import org.jetbrains.dokka.tests.verifyModel
+import org.jetbrains.dokka.tests.ModelConfig
+import org.jetbrains.dokka.tests.checkSourceExistsAndVerifyModel
import org.junit.Assert
import org.junit.Test
import java.io.File
@@ -22,7 +23,7 @@ class SourceLinksErrorTest {
}
private fun verifyNoSourceUrl(sourceLink: SourceLinkDefinitionImpl) {
- verifyModel("testdata/sourceLinks/dummy.kt", sourceLinks = listOf(sourceLink)) { model ->
+ 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)
diff --git a/core/src/test/kotlin/model/SourceLinksTest.kt b/core/src/test/kotlin/model/SourceLinksTest.kt
index 0e9b666c..a4ba870c 100644
--- a/core/src/test/kotlin/model/SourceLinksTest.kt
+++ b/core/src/test/kotlin/model/SourceLinksTest.kt
@@ -2,7 +2,8 @@ package org.jetbrains.dokka.tests.model
import org.jetbrains.dokka.NodeKind
import org.jetbrains.dokka.SourceLinkDefinitionImpl
-import org.jetbrains.dokka.tests.verifyModel
+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
@@ -26,7 +27,7 @@ class SourceLinksTest(
}
val sourceLink = SourceLinkDefinitionImpl(link, url, lineSuffix)
- verifyModel(filePath, sourceLinks = listOf(sourceLink)) { model ->
+ checkSourceExistsAndVerifyModel(filePath, ModelConfig(sourceLinks = listOf(sourceLink))) { model ->
with(model.members.single().members.single()) {
Assert.assertEquals("foo", name)
Assert.assertEquals(NodeKind.Function, kind)
diff --git a/core/src/test/kotlin/model/TypeAliasTest.kt b/core/src/test/kotlin/model/TypeAliasTest.kt
index c653ac83..a011b44f 100644
--- a/core/src/test/kotlin/model/TypeAliasTest.kt
+++ b/core/src/test/kotlin/model/TypeAliasTest.kt
@@ -8,7 +8,7 @@ import org.junit.Test
class TypeAliasTest {
@Test
fun testSimple() {
- verifyModel("testdata/typealias/simple.kt") {
+ checkSourceExistsAndVerifyModel("testdata/typealias/simple.kt") {
val pkg = it.members.single()
with(pkg.member(NodeKind.TypeAlias)) {
assertEquals(Content.Empty, content)
@@ -20,7 +20,7 @@ class TypeAliasTest {
@Test
fun testInheritanceFromTypeAlias() {
- verifyModel("testdata/typealias/inheritanceFromTypeAlias.kt") {
+ checkSourceExistsAndVerifyModel("testdata/typealias/inheritanceFromTypeAlias.kt") {
val pkg = it.members.single()
with(pkg.member(NodeKind.TypeAlias)) {
assertEquals(Content.Empty, content)
@@ -36,7 +36,7 @@ class TypeAliasTest {
@Test
fun testChain() {
- verifyModel("testdata/typealias/chain.kt") {
+ checkSourceExistsAndVerifyModel("testdata/typealias/chain.kt") {
val pkg = it.members.single()
with(pkg.members(NodeKind.TypeAlias).find { it.name == "B" }!!) {
assertEquals(Content.Empty, content)
@@ -51,7 +51,7 @@ class TypeAliasTest {
@Test
fun testDocumented() {
- verifyModel("testdata/typealias/documented.kt") {
+ checkSourceExistsAndVerifyModel("testdata/typealias/documented.kt") {
val pkg = it.members.single()
with(pkg.member(NodeKind.TypeAlias)) {
assertEquals("Just typealias", content.summary.toTestString())
@@ -61,7 +61,7 @@ class TypeAliasTest {
@Test
fun testDeprecated() {
- verifyModel("testdata/typealias/deprecated.kt") {
+ checkSourceExistsAndVerifyModel("testdata/typealias/deprecated.kt") {
val pkg = it.members.single()
with(pkg.member(NodeKind.TypeAlias)) {
assertEquals(Content.Empty, content)
@@ -73,7 +73,7 @@ class TypeAliasTest {
@Test
fun testGeneric() {
- verifyModel("testdata/typealias/generic.kt") {
+ 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)
@@ -88,7 +88,7 @@ class TypeAliasTest {
@Test
fun testFunctional() {
- verifyModel("testdata/typealias/functional.kt") {
+ checkSourceExistsAndVerifyModel("testdata/typealias/functional.kt") {
val pkg = it.members.single()
with(pkg.member(NodeKind.TypeAlias)) {
assertEquals("Function1", detail(NodeKind.TypeAliasUnderlyingType).name)
@@ -105,7 +105,7 @@ class TypeAliasTest {
@Test
fun testAsTypeBoundWithVariance() {
- verifyModel("testdata/typealias/asTypeBoundWithVariance.kt") {
+ checkSourceExistsAndVerifyModel("testdata/typealias/asTypeBoundWithVariance.kt") {
val pkg = it.members.single()
with(pkg.members(NodeKind.Class).find { it.name == "C" }!!) {
val tParam = detail(NodeKind.TypeParameter)
@@ -123,7 +123,7 @@ class TypeAliasTest {
@Test
fun sinceKotlin() {
- verifyModel("testdata/typealias/sinceKotlin.kt") { model ->
+ checkSourceExistsAndVerifyModel("testdata/typealias/sinceKotlin.kt") { model ->
with(model.members.single().members.single()) {
assertEquals(listOf("Kotlin 1.1"), platforms)
}
diff --git a/core/testdata/format/website-html/sampleWithAsserts.html b/core/testdata/format/website-html/sampleWithAsserts.html
index e91232f5..2b2a9ac5 100644
--- a/core/testdata/format/website-html/sampleWithAsserts.html
+++ b/core/testdata/format/website-html/sampleWithAsserts.html
@@ -14,6 +14,8 @@ println("a() == b() is ${a() == b()}") // true
// readSomeFile(File("some.txt")) // reading file now will fail
// readSomeFile(File("some.txt")) // will fail with FileNotFoundException
+// readSomeFile(File("some.txt")) // will fail
+
fun indented() {
// A neq B
println("a() != b() is ${a() != b()}") // false
diff --git a/core/testdata/format/website-html/sampleWithAsserts.kt b/core/testdata/format/website-html/sampleWithAsserts.kt
index b3bce11d..bb5848e6 100644
--- a/core/testdata/format/website-html/sampleWithAsserts.kt
+++ b/core/testdata/format/website-html/sampleWithAsserts.kt
@@ -26,6 +26,8 @@ fun sample() {
assertFails("reading file now") { readSomeFile(File("some.txt")) }
assertFailsWith<FileNotFoundException> { readSomeFile(File("some.txt")) }
+ assertFails { readSomeFile(File("some.txt")) }
+
fun indented() {
assertFalse(a() != b(), "A neq B")
}