aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Analysis/AnalysisEnvironment.kt210
-rw-r--r--src/Analysis/CoreProjectFileIndex.kt550
-rw-r--r--src/Formats/FormatDescriptor.kt12
-rw-r--r--src/Formats/FormatService.kt20
-rw-r--r--src/Formats/HtmlFormatService.kt165
-rw-r--r--src/Formats/HtmlTemplateService.kt34
-rw-r--r--src/Formats/JekyllFormatService.kt22
-rw-r--r--src/Formats/KotlinWebsiteFormatService.kt121
-rw-r--r--src/Formats/MarkdownFormatService.kt117
-rw-r--r--src/Formats/OutlineService.kt29
-rw-r--r--src/Formats/StandardFormats.kt38
-rw-r--r--src/Formats/StructuredFormatService.kt367
-rw-r--r--src/Formats/YamlOutlineService.kt24
-rw-r--r--src/Generation/ConsoleGenerator.kt42
-rw-r--r--src/Generation/FileGenerator.kt57
-rw-r--r--src/Generation/Generator.kt19
-rw-r--r--src/Java/JavaPsiDocumentationBuilder.kt266
-rw-r--r--src/Java/JavadocParser.kt170
-rw-r--r--src/Kotlin/ContentBuilder.kt132
-rw-r--r--src/Kotlin/DeclarationLinkResolver.kt43
-rw-r--r--src/Kotlin/DescriptorDocumentationParser.kt199
-rw-r--r--src/Kotlin/DocumentationBuilder.kt653
-rw-r--r--src/Kotlin/KotlinAsJavaDocumentationBuilder.kt64
-rw-r--r--src/Kotlin/KotlinLanguageService.kt409
-rw-r--r--src/Languages/JavaLanguageService.kt162
-rw-r--r--src/Languages/LanguageService.kt41
-rw-r--r--src/Locations/FoldersLocationService.kt29
-rw-r--r--src/Locations/LocationService.kt78
-rw-r--r--src/Locations/SingleFolderLocationService.kt19
-rw-r--r--src/Markdown/MarkdownProcessor.kt50
-rw-r--r--src/Model/Content.kt231
-rw-r--r--src/Model/DocumentationNode.kt162
-rw-r--r--src/Model/DocumentationReference.kt61
-rw-r--r--src/Model/PackageDocs.kt60
-rw-r--r--src/Model/SourceLinks.kt56
-rw-r--r--src/Utilities/DokkaModule.kt73
-rw-r--r--src/Utilities/Html.kt8
-rw-r--r--src/Utilities/Path.kt5
-rw-r--r--src/Utilities/ServiceLocator.kt78
-rw-r--r--src/main.kt262
40 files changed, 0 insertions, 5138 deletions
diff --git a/src/Analysis/AnalysisEnvironment.kt b/src/Analysis/AnalysisEnvironment.kt
deleted file mode 100644
index a5e35a0e..00000000
--- a/src/Analysis/AnalysisEnvironment.kt
+++ /dev/null
@@ -1,210 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.core.CoreApplicationEnvironment
-import com.intellij.core.CoreModuleManager
-import com.intellij.mock.MockComponentManager
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.extensions.Extensions
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.module.ModuleManager
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.roots.OrderEnumerationHandler
-import com.intellij.openapi.roots.ProjectFileIndex
-import com.intellij.openapi.roots.ProjectRootManager
-import com.intellij.openapi.util.Disposer
-import com.intellij.psi.PsiElement
-import com.intellij.psi.search.GlobalSearchScope
-import org.jetbrains.kotlin.analyzer.AnalysisResult
-import org.jetbrains.kotlin.analyzer.ModuleContent
-import org.jetbrains.kotlin.analyzer.ModuleInfo
-import org.jetbrains.kotlin.analyzer.ResolverForModule
-import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
-import org.jetbrains.kotlin.cli.common.messages.MessageCollector
-import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
-import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot
-import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
-import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
-import org.jetbrains.kotlin.config.CommonConfigurationKeys
-import org.jetbrains.kotlin.config.CompilerConfiguration
-import org.jetbrains.kotlin.config.ContentRoot
-import org.jetbrains.kotlin.config.KotlinSourceRoot
-import org.jetbrains.kotlin.container.getService
-import org.jetbrains.kotlin.context.ProjectContext
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.descriptors.ModuleDescriptor
-import org.jetbrains.kotlin.idea.caches.resolve.KotlinCacheService
-import org.jetbrains.kotlin.idea.caches.resolve.KotlinOutOfBlockCompletionModificationTracker
-import org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker
-import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
-import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.psi.KtDeclaration
-import org.jetbrains.kotlin.psi.KtElement
-import org.jetbrains.kotlin.resolve.BindingContext
-import org.jetbrains.kotlin.resolve.CompilerEnvironment
-import org.jetbrains.kotlin.resolve.jvm.JvmAnalyzerFacade
-import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
-import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
-import org.jetbrains.kotlin.resolve.lazy.ResolveSession
-import java.io.File
-
-/**
- * Kotlin as a service entry point
- *
- * Configures environment, analyses files and provides facilities to perform code processing without emitting bytecode
- *
- * $messageCollector: required by compiler infrastructure and will receive all compiler messages
- * $body: optional and can be used to configure environment without creating local variable
- */
-public class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
- val configuration = CompilerConfiguration();
-
- init {
- configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
- }
-
- fun createCoreEnvironment(): KotlinCoreEnvironment {
- val environment = KotlinCoreEnvironment.createForProduction(this, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
- val projectComponentManager = environment.project as MockComponentManager
-
- val projectFileIndex = CoreProjectFileIndex(environment.project,
- environment.configuration.getList(CommonConfigurationKeys.CONTENT_ROOTS))
-
- val moduleManager = object : CoreModuleManager(environment.project, this) {
- override fun getModules(): Array<out Module> = arrayOf(projectFileIndex.module)
- }
-
- CoreApplicationEnvironment.registerComponentInstance(projectComponentManager.picoContainer,
- ModuleManager::class.java, moduleManager)
-
- Extensions.registerAreaClass("IDEA_MODULE", null)
- CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(),
- OrderEnumerationHandler.EP_NAME, OrderEnumerationHandler.Factory::class.java)
-
- projectComponentManager.registerService(ProjectFileIndex::class.java,
- projectFileIndex)
- projectComponentManager.registerService(ProjectRootManager::class.java,
- CoreProjectRootManager(projectFileIndex))
- projectComponentManager.registerService(LibraryModificationTracker::class.java,
- LibraryModificationTracker(environment.project))
- projectComponentManager.registerService(KotlinCacheService::class.java,
- KotlinCacheService(environment.project))
- projectComponentManager.registerService(KotlinOutOfBlockCompletionModificationTracker::class.java,
- KotlinOutOfBlockCompletionModificationTracker())
- return environment
- }
-
- fun createResolutionFacade(environment: KotlinCoreEnvironment): DokkaResolutionFacade {
- val projectContext = ProjectContext(environment.project)
- val sourceFiles = environment.getSourceFiles()
-
- val module = object : ModuleInfo {
- override val name: Name = Name.special("<module>")
- override fun dependencies(): List<ModuleInfo> = listOf(this)
- }
- val resolverForProject = JvmAnalyzerFacade.setupResolverForProject(
- "Dokka",
- projectContext,
- listOf(module),
- { ModuleContent(sourceFiles, GlobalSearchScope.allScope(environment.project)) },
- JvmPlatformParameters { module },
- CompilerEnvironment
- )
-
- val resolverForModule = resolverForProject.resolverForModule(module)
- return DokkaResolutionFacade(environment.project, resolverForProject.descriptorForModule(module), resolverForModule)
- }
-
- /**
- * Classpath for this environment.
- */
- public val classpath: List<File>
- get() = configuration.jvmClasspathRoots
-
- /**
- * Adds list of paths to classpath.
- * $paths: collection of files to add
- */
- public fun addClasspath(paths: List<File>) {
- configuration.addJvmClasspathRoots(paths)
- }
-
- /**
- * Adds path to classpath.
- * $path: path to add
- */
- public fun addClasspath(path: File) {
- configuration.addJvmClasspathRoot(path)
- }
-
- /**
- * List of source roots for this environment.
- */
- public val sources: List<String>
- get() = configuration.get(CommonConfigurationKeys.CONTENT_ROOTS)
- ?.filterIsInstance<KotlinSourceRoot>()
- ?.map { it.path } ?: emptyList()
-
- /**
- * Adds list of paths to source roots.
- * $list: collection of files to add
- */
- public fun addSources(list: List<String>) {
- list.forEach {
- configuration.add(CommonConfigurationKeys.CONTENT_ROOTS, contentRootFromPath(it))
- }
- }
-
- public fun addRoots(list: List<ContentRoot>) {
- configuration.addAll(CommonConfigurationKeys.CONTENT_ROOTS, list)
- }
-
- /**
- * Disposes the environment and frees all associated resources.
- */
- public override fun dispose() {
- Disposer.dispose(this)
- }
-}
-
-public fun contentRootFromPath(path: String): ContentRoot {
- val file = File(path)
- return if (file.extension == "java") JavaSourceRoot(file, null) else KotlinSourceRoot(path)
-}
-
-
-class DokkaResolutionFacade(override val project: Project,
- override val moduleDescriptor: ModuleDescriptor,
- val resolverForModule: ResolverForModule) : ResolutionFacade {
-
- val resolveSession: ResolveSession get() = getFrontendService(ResolveSession::class.java)
-
- override fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode): BindingContext {
- throw UnsupportedOperationException()
- }
-
- override fun analyzeFullyAndGetResult(elements: Collection<KtElement>): AnalysisResult {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any> getFrontendService(serviceClass: Class<T>): T {
- return resolverForModule.componentProvider.getService(serviceClass)
- }
-
- override fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any> getIdeService(serviceClass: Class<T>): T {
- throw UnsupportedOperationException()
- }
-
- override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor {
- return resolveSession.resolveToDescriptor(declaration)
- }
-}
diff --git a/src/Analysis/CoreProjectFileIndex.kt b/src/Analysis/CoreProjectFileIndex.kt
deleted file mode 100644
index a1362fde..00000000
--- a/src/Analysis/CoreProjectFileIndex.kt
+++ /dev/null
@@ -1,550 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.components.BaseComponent
-import com.intellij.openapi.extensions.ExtensionPointName
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.projectRoots.Sdk
-import com.intellij.openapi.projectRoots.SdkAdditionalData
-import com.intellij.openapi.projectRoots.SdkModificator
-import com.intellij.openapi.projectRoots.SdkTypeId
-import com.intellij.openapi.roots.*
-import com.intellij.openapi.roots.impl.ProjectOrderEnumerator
-import com.intellij.openapi.util.Condition
-import com.intellij.openapi.util.Key
-import com.intellij.openapi.util.UserDataHolderBase
-import com.intellij.openapi.vfs.StandardFileSystems
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.util.messages.MessageBus
-import org.jetbrains.jps.model.module.JpsModuleSourceRootType
-import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
-import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot
-import org.jetbrains.kotlin.config.ContentRoot
-import org.jetbrains.kotlin.config.KotlinSourceRoot
-import org.picocontainer.PicoContainer
-import java.io.File
-
-/**
- * Workaround for the lack of ability to create a ProjectFileIndex implementation using only
- * classes from projectModel-{api,impl}.
- */
-class CoreProjectFileIndex(val project: Project, contentRoots: List<ContentRoot>) : ProjectFileIndex, ModuleFileIndex {
- val sourceRoots = contentRoots.filter { it !is JvmClasspathRoot }
- val classpathRoots = contentRoots.filterIsInstance<JvmClasspathRoot>()
-
- val module: Module = object : UserDataHolderBase(), Module {
- override fun isDisposed(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getOptionValue(p0: String): String? {
- throw UnsupportedOperationException()
- }
-
- override fun clearOption(p0: String) {
- throw UnsupportedOperationException()
- }
-
- override fun getName(): String = "<Dokka module>"
-
- override fun getModuleWithLibrariesScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleWithDependentsScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleContentScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun isLoaded(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun setOption(p0: String, p1: String) {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleWithDependenciesScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleWithDependenciesAndLibrariesScope(p0: Boolean): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getProject(): Project = project
-
- override fun getModuleContentWithDependenciesScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleFilePath(): String {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleTestsWithDependentsScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleScope(): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleScope(p0: Boolean): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleRuntimeScope(p0: Boolean): GlobalSearchScope {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleFile(): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getExtensions(p0: ExtensionPointName<T>): Array<out T> {
- throw UnsupportedOperationException()
- }
-
- override fun getComponent(p0: String): BaseComponent? {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getComponent(p0: Class<T>, p1: T): T {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getComponent(interfaceClass: Class<T>): T? {
- if (interfaceClass == ModuleRootManager::class.java) {
- return moduleRootManager as T
- }
- throw UnsupportedOperationException()
- }
-
- override fun getDisposed(): Condition<*> {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getComponents(p0: Class<T>): Array<out T> {
- throw UnsupportedOperationException()
- }
-
- override fun getPicoContainer(): PicoContainer {
- throw UnsupportedOperationException()
- }
-
- override fun hasComponent(p0: Class<*>): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getMessageBus(): MessageBus {
- throw UnsupportedOperationException()
- }
-
- override fun dispose() {
- throw UnsupportedOperationException()
- }
- }
-
- private val sdk: Sdk = object : Sdk, RootProvider {
- override fun getFiles(rootType: OrderRootType): Array<out VirtualFile> = classpathRoots
- .map { StandardFileSystems.local().findFileByPath(it.file.path) }
- .filterNotNull()
- .toTypedArray()
-
- override fun addRootSetChangedListener(p0: RootProvider.RootSetChangedListener) {
- throw UnsupportedOperationException()
- }
-
- override fun addRootSetChangedListener(p0: RootProvider.RootSetChangedListener, p1: Disposable) {
- throw UnsupportedOperationException()
- }
-
- override fun getUrls(p0: OrderRootType): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun removeRootSetChangedListener(p0: RootProvider.RootSetChangedListener) {
- throw UnsupportedOperationException()
- }
-
- override fun getSdkModificator(): SdkModificator {
- throw UnsupportedOperationException()
- }
-
- override fun getName(): String = "<dokka SDK>"
-
- override fun getRootProvider(): RootProvider = this
-
- override fun getHomePath(): String? {
- throw UnsupportedOperationException()
- }
-
- override fun getVersionString(): String? {
- throw UnsupportedOperationException()
- }
-
- override fun getSdkAdditionalData(): SdkAdditionalData? {
- throw UnsupportedOperationException()
- }
-
- override fun clone(): Any {
- throw UnsupportedOperationException()
- }
-
- override fun getSdkType(): SdkTypeId {
- throw UnsupportedOperationException()
- }
-
- override fun getHomeDirectory(): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> getUserData(p0: Key<T>): T? {
- throw UnsupportedOperationException()
- }
-
- override fun <T : Any?> putUserData(p0: Key<T>, p1: T?) {
- throw UnsupportedOperationException()
- }
- }
-
- private val moduleSourceOrderEntry = object : ModuleSourceOrderEntry {
- override fun getFiles(p0: OrderRootType?): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getPresentableName(): String {
- throw UnsupportedOperationException()
- }
-
- override fun getUrls(p0: OrderRootType?): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getOwnerModule(): Module = module
-
- override fun <R : Any?> accept(p0: RootPolicy<R>?, p1: R?): R {
- throw UnsupportedOperationException()
- }
-
- override fun isValid(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun compareTo(other: OrderEntry?): Int {
- throw UnsupportedOperationException()
- }
-
- override fun getRootModel(): ModuleRootModel = moduleRootManager
-
- override fun isSynthetic(): Boolean {
- throw UnsupportedOperationException()
- }
- }
-
- private val sdkOrderEntry = object : JdkOrderEntry {
- override fun getJdkName(): String? {
- throw UnsupportedOperationException()
- }
-
- override fun getJdk(): Sdk = sdk
-
- override fun getFiles(p0: OrderRootType?): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getPresentableName(): String {
- throw UnsupportedOperationException()
- }
-
- override fun getUrls(p0: OrderRootType?): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getOwnerModule(): Module {
- throw UnsupportedOperationException()
- }
-
- override fun <R : Any?> accept(p0: RootPolicy<R>?, p1: R?): R {
- throw UnsupportedOperationException()
- }
-
- override fun isValid(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getRootFiles(p0: OrderRootType?): Array<out VirtualFile>? {
- throw UnsupportedOperationException()
- }
-
- override fun getRootUrls(p0: OrderRootType?): Array<out String>? {
- throw UnsupportedOperationException()
- }
-
- override fun compareTo(other: OrderEntry?): Int {
- throw UnsupportedOperationException()
- }
-
- override fun isSynthetic(): Boolean {
- throw UnsupportedOperationException()
- }
-
- }
-
- inner class MyModuleRootManager : ModuleRootManager() {
- override fun getExcludeRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getContentEntries(): Array<out ContentEntry> {
- throw UnsupportedOperationException()
- }
-
- override fun getExcludeRootUrls(): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun <R : Any?> processOrder(p0: RootPolicy<R>?, p1: R): R {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRoots(p0: Boolean): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRoots(p0: JpsModuleSourceRootType<*>): MutableList<VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRoots(p0: MutableSet<out JpsModuleSourceRootType<*>>): MutableList<VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun orderEntries(): OrderEnumerator =
- ProjectOrderEnumerator(project, null).using(object : RootModelProvider {
- override fun getModules(): Array<out Module> = arrayOf(module)
-
- override fun getRootModel(p0: Module): ModuleRootModel = this@MyModuleRootManager
- })
-
- override fun <T : Any?> getModuleExtension(p0: Class<T>?): T {
- throw UnsupportedOperationException()
- }
-
- override fun getDependencyModuleNames(): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getModule(): Module = module
-
- override fun isSdkInherited(): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getOrderEntries(): Array<out OrderEntry> = arrayOf(moduleSourceOrderEntry, sdkOrderEntry)
-
- override fun getSourceRootUrls(): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRootUrls(p0: Boolean): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getSdk(): Sdk? {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRootUrls(): Array<out String> {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleDependencies(): Array<out Module> {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleDependencies(p0: Boolean): Array<out Module> {
- throw UnsupportedOperationException()
- }
-
- override fun getModifiableModel(): ModifiableRootModel {
- throw UnsupportedOperationException()
- }
-
- override fun isDependsOn(p0: Module?): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getFileIndex(): ModuleFileIndex {
- return this@CoreProjectFileIndex
- }
-
- override fun getDependencies(): Array<out Module> {
- throw UnsupportedOperationException()
- }
-
- override fun getDependencies(p0: Boolean): Array<out Module> {
- throw UnsupportedOperationException()
- }
- }
-
- val moduleRootManager = MyModuleRootManager()
-
- override fun getContentRootForFile(p0: VirtualFile): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRootForFile(p0: VirtualFile, p1: Boolean): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun getPackageNameByDirectory(p0: VirtualFile): String? {
- throw UnsupportedOperationException()
- }
-
- override fun isInLibrarySource(file: VirtualFile): Boolean = false
-
- override fun getClassRootForFile(file: VirtualFile): VirtualFile? =
- classpathRoots.firstOrNull { it.contains(file) }?.let { StandardFileSystems.local().findFileByPath(it.file.path) }
-
- override fun getOrderEntriesForFile(file: VirtualFile): List<OrderEntry> =
- if (classpathRoots.contains(file)) listOf(sdkOrderEntry) else emptyList()
-
- override fun isInLibraryClasses(file: VirtualFile): Boolean = classpathRoots.contains(file)
-
- override fun isExcluded(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getSourceRootForFile(p0: VirtualFile): VirtualFile? {
- throw UnsupportedOperationException()
- }
-
- override fun isUnderIgnored(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isLibraryClassFile(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleForFile(file: VirtualFile): Module? =
- if (sourceRoots.contains(file)) module else null
-
- private fun List<ContentRoot>.contains(file: VirtualFile): Boolean = any { it.contains(file) }
-
- override fun getModuleForFile(p0: VirtualFile, p1: Boolean): Module? {
- throw UnsupportedOperationException()
- }
-
- override fun isInSource(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isIgnored(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isContentSourceFile(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isInSourceContent(file: VirtualFile): Boolean = sourceRoots.contains(file)
-
- override fun iterateContent(p0: ContentIterator): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isInContent(p0: VirtualFile): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun iterateContentUnderDirectory(p0: VirtualFile, p1: ContentIterator): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun isInTestSourceContent(file: VirtualFile): Boolean = false
-
- override fun isUnderSourceRootOfType(p0: VirtualFile, p1: MutableSet<out JpsModuleSourceRootType<*>>): Boolean {
- throw UnsupportedOperationException()
- }
-
- override fun getOrderEntryForFile(p0: VirtualFile): OrderEntry? {
- throw UnsupportedOperationException()
- }
-}
-
-class CoreProjectRootManager(val projectFileIndex: CoreProjectFileIndex) : ProjectRootManager() {
- override fun orderEntries(): OrderEnumerator {
- throw UnsupportedOperationException()
- }
-
- override fun orderEntries(p0: MutableCollection<out Module>): OrderEnumerator {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRootsFromAllModules(): Array<out VirtualFile>? {
- throw UnsupportedOperationException()
- }
-
- override fun setProjectSdk(p0: Sdk?) {
- throw UnsupportedOperationException()
- }
-
- override fun setProjectSdkName(p0: String?) {
- throw UnsupportedOperationException()
- }
-
- override fun getModuleSourceRoots(p0: MutableSet<out JpsModuleSourceRootType<*>>): MutableList<VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getContentSourceRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getFileIndex(): ProjectFileIndex = projectFileIndex
-
- override fun getProjectSdkName(): String? {
- throw UnsupportedOperationException()
- }
-
- override fun getProjectSdk(): Sdk? {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRoots(): Array<out VirtualFile> {
- throw UnsupportedOperationException()
- }
-
- override fun getContentRootUrls(): MutableList<String> {
- throw UnsupportedOperationException()
- }
-
-}
-
-fun ContentRoot.contains(file: VirtualFile) = when (this) {
- is JvmContentRoot -> {
- val path = if (file.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL)
- StandardFileSystems.getVirtualFileForJar(file)?.path ?: file.path
- else
- file.path
- File(path).startsWith(this.file.absoluteFile)
- }
- is KotlinSourceRoot -> File(file.path).startsWith(File(this.path).absoluteFile)
- else -> false
-}
diff --git a/src/Formats/FormatDescriptor.kt b/src/Formats/FormatDescriptor.kt
deleted file mode 100644
index 0c7ca794..00000000
--- a/src/Formats/FormatDescriptor.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import org.jetbrains.dokka.*
-import kotlin.reflect.KClass
-
-public interface FormatDescriptor {
- val formatServiceClass: KClass<out FormatService>?
- val outlineServiceClass: KClass<out OutlineFormatService>?
- val generatorServiceClass: KClass<out Generator>
- val packageDocumentationBuilderClass: KClass<out PackageDocumentationBuilder>
- val javaDocumentationBuilderClass: KClass<out JavaDocumentationBuilder>
-}
diff --git a/src/Formats/FormatService.kt b/src/Formats/FormatService.kt
deleted file mode 100644
index 7e66a6b7..00000000
--- a/src/Formats/FormatService.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.jetbrains.dokka
-
-/**
- * Abstract representation of a formatting service used to output documentation in desired format
- *
- * Bundled Formatters:
- * * [HtmlFormatService] – outputs documentation to HTML format
- * * [MarkdownFormatService] – outputs documentation in Markdown format
- * * [TextFormatService] – outputs documentation in Text format
- */
-public interface FormatService {
- /** Returns extension for output files */
- val extension: String
-
- /** Appends formatted content to [StringBuilder](to) using specified [location] */
- fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>)
-}
-
-/** Format content to [String] using specified [location] */
-fun FormatService.format(location: Location, nodes: Iterable<DocumentationNode>): String = StringBuilder().apply { appendNodes(location, this, nodes) }.toString()
diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt
deleted file mode 100644
index 2c461905..00000000
--- a/src/Formats/HtmlFormatService.kt
+++ /dev/null
@@ -1,165 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import java.io.File
-import java.nio.file.Paths
-
-public open class HtmlFormatService @Inject constructor(@Named("folders") locationService: LocationService,
- signatureGenerator: LanguageService,
- val templateService: HtmlTemplateService)
-: StructuredFormatService(locationService, signatureGenerator, "html"), OutlineFormatService {
- override public fun formatText(text: String): String {
- return text.htmlEscape()
- }
-
- override fun formatSymbol(text: String): String {
- return "<span class=\"symbol\">${formatText(text)}</span>"
- }
-
- override fun formatKeyword(text: String): String {
- return "<span class=\"keyword\">${formatText(text)}</span>"
- }
-
- override fun formatIdentifier(text: String, kind: IdentifierKind): String {
- return "<span class=\"identifier\">${formatText(text)}</span>"
- }
-
- override fun appendBlockCode(to: StringBuilder, line: String, language: String) {
- to.append("<pre><code>")
- to.append(line)
- to.append("</code></pre>")
- }
-
- override fun appendHeader(to: StringBuilder, text: String, level: Int) {
- to.appendln("<h$level>${text}</h$level>")
- }
-
- override fun appendParagraph(to: StringBuilder, text: String) {
- to.appendln("<p>${text}</p>")
- }
-
- override fun appendLine(to: StringBuilder, text: String) {
- to.appendln("${text}<br/>")
- }
-
- override fun appendLine(to: StringBuilder) {
- to.appendln("<br/>")
- }
-
- override fun appendAnchor(to: StringBuilder, anchor: String) {
- to.appendln("<a name=\"${anchor.htmlEscape()}\"></a>")
- }
-
- override fun appendTable(to: StringBuilder, body: () -> Unit) {
- to.appendln("<table>")
- body()
- to.appendln("</table>")
- }
-
- override fun appendTableHeader(to: StringBuilder, body: () -> Unit) {
- to.appendln("<thead>")
- body()
- to.appendln("</thead>")
- }
-
- override fun appendTableBody(to: StringBuilder, body: () -> Unit) {
- to.appendln("<tbody>")
- body()
- to.appendln("</tbody>")
- }
-
- override fun appendTableRow(to: StringBuilder, body: () -> Unit) {
- to.appendln("<tr>")
- body()
- to.appendln("</tr>")
- }
-
- override fun appendTableCell(to: StringBuilder, body: () -> Unit) {
- to.appendln("<td>")
- body()
- to.appendln("</td>")
- }
-
- override fun formatLink(text: String, href: String): String {
- return "<a href=\"${href}\">${text}</a>"
- }
-
- override fun formatStrong(text: String): String {
- return "<strong>${text}</strong>"
- }
-
- override fun formatEmphasis(text: String): String {
- return "<emph>${text}</emph>"
- }
-
- override fun formatStrikethrough(text: String): String {
- return "<s>${text}</s>"
- }
-
- override fun formatCode(code: String): String {
- return "<code>${code}</code>"
- }
-
- override fun formatUnorderedList(text: String): String = "<ul>${text}</ul>"
- override fun formatOrderedList(text: String): String = "<ol>${text}</ol>"
-
- override fun formatListItem(text: String, kind: ListKind): String {
- return "<li>${text}</li>"
- }
-
- override fun formatBreadcrumbs(items: Iterable<FormatLink>): String {
- return items.map { formatLink(it) }.joinToString("&nbsp;/&nbsp;")
- }
-
-
- override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- templateService.appendHeader(to, getPageTitle(nodes), calcPathToRoot(location))
- super.appendNodes(location, to, nodes)
- templateService.appendFooter(to)
- }
-
- override fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- templateService.appendHeader(to, "Module Contents", calcPathToRoot(location))
- super.appendOutline(location, to, nodes)
- templateService.appendFooter(to)
- }
-
- private fun calcPathToRoot(location: Location) = Paths.get(location.path).parent.relativize(Paths.get(locationService.root.path + '/'))
-
- override fun getOutlineFileName(location: Location): File {
- return File("${location.path}-outline.html")
- }
-
- override fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) {
- val link = ContentNodeDirectLink(node)
- link.append(languageService.render(node, LanguageService.RenderMode.FULL))
- val signature = formatText(location, link)
- to.appendln("<a href=\"${location.path}\">${signature}</a><br/>")
- }
-
- override fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) {
- to.appendln("<ul>")
- body()
- to.appendln("</ul>")
- }
-
- override fun formatNonBreakingSpace(): String = "&nbsp;"
-}
-
-fun getPageTitle(nodes: Iterable<DocumentationNode>): String? {
- val breakdownByLocation = nodes.groupBy { node -> formatPageTitle(node) }
- return breakdownByLocation.keys.singleOrNull()
-}
-
-fun formatPageTitle(node: DocumentationNode): String {
- val path = node.path
- if (path.size == 1) {
- return path.first().name
- }
- val qualifiedName = node.qualifiedName()
- if (qualifiedName.length == 0 && path.size == 2) {
- return path.first().name + " / root package"
- }
- return path.first().name + " / " + qualifiedName
-}
diff --git a/src/Formats/HtmlTemplateService.kt b/src/Formats/HtmlTemplateService.kt
deleted file mode 100644
index ae42a31b..00000000
--- a/src/Formats/HtmlTemplateService.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.jetbrains.dokka
-
-import java.nio.file.Path
-
-public interface HtmlTemplateService {
- fun appendHeader(to: StringBuilder, title: String?, basePath: Path)
- fun appendFooter(to: StringBuilder)
-
- companion object {
- public fun default(css: String? = null): HtmlTemplateService {
- return object : HtmlTemplateService {
- override fun appendFooter(to: StringBuilder) {
- to.appendln("</BODY>")
- to.appendln("</HTML>")
- }
- override fun appendHeader(to: StringBuilder, title: String?, basePath: Path) {
- to.appendln("<HTML>")
- to.appendln("<HEAD>")
- if (title != null) {
- to.appendln("<title>$title</title>")
- }
- if (css != null) {
- val cssPath = basePath.resolve(css)
- to.appendln("<link rel=\"stylesheet\" href=\"$cssPath\">")
- }
- to.appendln("</HEAD>")
- to.appendln("<BODY>")
- }
- }
- }
- }
-}
-
-
diff --git a/src/Formats/JekyllFormatService.kt b/src/Formats/JekyllFormatService.kt
deleted file mode 100644
index f81257d6..00000000
--- a/src/Formats/JekyllFormatService.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-
-open class JekyllFormatService
- @Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService,
- linkExtension: String = "md")
-: MarkdownFormatService(locationService, signatureGenerator, linkExtension) {
-
- override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- to.appendln("---")
- appendFrontMatter(nodes, to)
- to.appendln("---")
- to.appendln("")
- super.appendNodes(location, to, nodes)
- }
-
- protected open fun appendFrontMatter(nodes: Iterable<DocumentationNode>, to: StringBuilder) {
- to.appendln("title: ${getPageTitle(nodes)}")
- }
-} \ No newline at end of file
diff --git a/src/Formats/KotlinWebsiteFormatService.kt b/src/Formats/KotlinWebsiteFormatService.kt
deleted file mode 100644
index 4eda7910..00000000
--- a/src/Formats/KotlinWebsiteFormatService.kt
+++ /dev/null
@@ -1,121 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-
-public class KotlinWebsiteFormatService @Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService)
-: JekyllFormatService(locationService, signatureGenerator, "html") {
- private var needHardLineBreaks = false
-
- override fun appendFrontMatter(nodes: Iterable<DocumentationNode>, to: StringBuilder) {
- super.appendFrontMatter(nodes, to)
- to.appendln("layout: api")
- }
-
- override public fun formatBreadcrumbs(items: Iterable<FormatLink>): String {
- items.drop(1)
-
- if (items.count() > 1) {
- return "<div class='api-docs-breadcrumbs'>" +
- items.map { formatLink(it) }.joinToString(" / ") +
- "</div>"
- }
-
- return ""
- }
-
- override public fun formatCode(code: String): String = if (code.length > 0) "<code>$code</code>" else ""
-
- override fun formatStrikethrough(text: String): String = "<s>$text</s>"
-
- override fun appendAsSignature(to: StringBuilder, node: ContentNode, block: () -> Unit) {
- val contentLength = node.textLength
- if (contentLength == 0) return
- to.append("<div class=\"signature\">")
- needHardLineBreaks = contentLength >= 62
- try {
- block()
- } finally {
- needHardLineBreaks = false
- }
- to.append("</div>")
- }
-
- override fun appendAsOverloadGroup(to: StringBuilder, block: () -> Unit) {
- to.append("<div class=\"overload-group\">\n")
- block()
- to.append("</div>\n")
- }
-
- override fun formatLink(text: String, href: String): String {
- return "<a href=\"${href}\">${text}</a>"
- }
-
- override fun appendTable(to: StringBuilder, body: () -> Unit) {
- to.appendln("<table class=\"api-docs-table\">")
- body()
- to.appendln("</table>")
- }
-
- override fun appendTableHeader(to: StringBuilder, body: () -> Unit) {
- to.appendln("<thead>")
- body()
- to.appendln("</thead>")
- }
-
- override fun appendTableBody(to: StringBuilder, body: () -> Unit) {
- to.appendln("<tbody>")
- body()
- to.appendln("</tbody>")
- }
-
- override fun appendTableRow(to: StringBuilder, body: () -> Unit) {
- to.appendln("<tr>")
- body()
- to.appendln("</tr>")
- }
-
- override fun appendTableCell(to: StringBuilder, body: () -> Unit) {
- to.appendln("<td markdown=\"1\">")
- body()
- to.appendln("\n</td>")
- }
-
- override public fun appendBlockCode(to: StringBuilder, line: String, language: String) {
- if (language.isNotEmpty()) {
- super.appendBlockCode(to, line, language)
- } else {
- to.append("<pre markdown=\"1\">")
- to.append(line.trimStart())
- to.append("</pre>")
- }
- }
-
- override fun formatSymbol(text: String): String {
- return "<span class=\"symbol\">${formatText(text)}</span>"
- }
-
- override fun formatKeyword(text: String): String {
- return "<span class=\"keyword\">${formatText(text)}</span>"
- }
-
- override fun formatIdentifier(text: String, kind: IdentifierKind): String {
- return "<span class=\"${identifierClassName(kind)}\">${formatText(text)}</span>"
- }
-
- override fun formatSoftLineBreak(): String = if (needHardLineBreaks)
- "<br/>"
- else
- ""
-
- override fun formatIndentedSoftLineBreak(): String = if (needHardLineBreaks)
- "<br/>&nbsp;&nbsp;&nbsp;&nbsp;"
- else
- ""
-
- private fun identifierClassName(kind: IdentifierKind) = when(kind) {
- IdentifierKind.ParameterName -> "parameterName"
- IdentifierKind.SummarizedTypeName -> "summarizedTypeName"
- else -> "identifier"
- }
-}
diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt
deleted file mode 100644
index f694ae3e..00000000
--- a/src/Formats/MarkdownFormatService.kt
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-
-
-public open class MarkdownFormatService
- @Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService,
- linkExtension: String = "md")
-: StructuredFormatService(locationService, signatureGenerator, "md", linkExtension) {
- override public fun formatBreadcrumbs(items: Iterable<FormatLink>): String {
- return items.map { formatLink(it) }.joinToString(" / ")
- }
-
- override public fun formatText(text: String): String {
- return text.htmlEscape()
- }
-
- override fun formatSymbol(text: String): String {
- return text.htmlEscape()
- }
-
- override fun formatKeyword(text: String): String {
- return text.htmlEscape()
- }
- override fun formatIdentifier(text: String, kind: IdentifierKind): String {
- return text.htmlEscape()
- }
-
- override public fun formatCode(code: String): String {
- return "`$code`"
- }
-
- override public fun formatUnorderedList(text: String): String = text + "\n"
- override public fun formatOrderedList(text: String): String = text + "\n"
-
- override fun formatListItem(text: String, kind: ListKind): String {
- val itemText = if (text.endsWith("\n")) text else text + "\n"
- return if (kind == ListKind.Unordered) "* $itemText" else "1. $itemText"
- }
-
- override public fun formatStrong(text: String): String {
- return "**$text**"
- }
-
- override fun formatEmphasis(text: String): String {
- return "*$text*"
- }
-
- override fun formatStrikethrough(text: String): String {
- return "~~$text~~"
- }
-
- override fun formatLink(text: String, href: String): String {
- return "[$text]($href)"
- }
-
- override public fun appendLine(to: StringBuilder) {
- to.appendln()
- }
-
- override public fun appendLine(to: StringBuilder, text: String) {
- to.appendln(text)
- }
-
- override fun appendAnchor(to: StringBuilder, anchor: String) {
- // no anchors in Markdown
- }
-
- override public fun appendParagraph(to: StringBuilder, text: String) {
- to.appendln()
- to.appendln(text)
- to.appendln()
- }
-
- override public fun appendHeader(to: StringBuilder, text: String, level: Int) {
- appendLine(to)
- appendLine(to, "${"#".repeat(level)} $text")
- appendLine(to)
- }
-
- override public fun appendBlockCode(to: StringBuilder, line: String, language: String) {
- appendLine(to)
- to.appendln("``` ${language}")
- to.appendln(line)
- to.appendln("```")
- appendLine(to)
- }
-
- override fun appendTable(to: StringBuilder, body: () -> Unit) {
- to.appendln()
- body()
- to.appendln()
- }
-
- override fun appendTableHeader(to: StringBuilder, body: () -> Unit) {
- body()
- }
-
- override fun appendTableBody(to: StringBuilder, body: () -> Unit) {
- body()
- }
-
- override fun appendTableRow(to: StringBuilder, body: () -> Unit) {
- to.append("|")
- body()
- to.appendln()
- }
-
- override fun appendTableCell(to: StringBuilder, body: () -> Unit) {
- to.append(" ")
- body()
- to.append(" |")
- }
-
- override fun formatNonBreakingSpace(): String = "&nbsp;"
-}
diff --git a/src/Formats/OutlineService.kt b/src/Formats/OutlineService.kt
deleted file mode 100644
index 6626cf51..00000000
--- a/src/Formats/OutlineService.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.jetbrains.dokka
-
-import java.io.File
-
-/**
- * Service for building the outline of the package contents.
- */
-public interface OutlineFormatService {
- fun getOutlineFileName(location: Location): File
-
- public fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder)
- public fun appendOutlineLevel(to: StringBuilder, body: () -> Unit)
-
- /** Appends formatted outline to [StringBuilder](to) using specified [location] */
- public fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- for (node in nodes) {
- appendOutlineHeader(location, node, to)
- if (node.members.any()) {
- val sortedMembers = node.members.sortedBy { it.name }
- appendOutlineLevel(to) {
- appendOutline(location, to, sortedMembers)
- }
- }
- }
- }
-
- fun formatOutline(location: Location, nodes: Iterable<DocumentationNode>): String =
- StringBuilder().apply { appendOutline(location, this, nodes) }.toString()
-}
diff --git a/src/Formats/StandardFormats.kt b/src/Formats/StandardFormats.kt
deleted file mode 100644
index 94e1b115..00000000
--- a/src/Formats/StandardFormats.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import org.jetbrains.dokka.*
-
-abstract class KotlinFormatDescriptorBase : FormatDescriptor {
- override val packageDocumentationBuilderClass = KotlinPackageDocumentationBuilder::class
- override val javaDocumentationBuilderClass = KotlinJavaDocumentationBuilder::class
-
- override val generatorServiceClass = FileGenerator::class
-}
-
-class HtmlFormatDescriptor : KotlinFormatDescriptorBase() {
- override val formatServiceClass = HtmlFormatService::class
- override val outlineServiceClass = HtmlFormatService::class
-}
-
-class HtmlAsJavaFormatDescriptor : FormatDescriptor {
- override val formatServiceClass = HtmlFormatService::class
- override val outlineServiceClass = HtmlFormatService::class
- override val generatorServiceClass = FileGenerator::class
- override val packageDocumentationBuilderClass = KotlinAsJavaDocumentationBuilder::class
- override val javaDocumentationBuilderClass = JavaPsiDocumentationBuilder::class
-}
-
-class KotlinWebsiteFormatDescriptor : KotlinFormatDescriptorBase() {
- override val formatServiceClass = KotlinWebsiteFormatService::class
- override val outlineServiceClass = YamlOutlineService::class
-}
-
-class JekyllFormatDescriptor : KotlinFormatDescriptorBase() {
- override val formatServiceClass = JekyllFormatService::class
- override val outlineServiceClass = null
-}
-
-class MarkdownFormatDescriptor : KotlinFormatDescriptorBase() {
- override val formatServiceClass = MarkdownFormatService::class
- override val outlineServiceClass = null
-}
diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt
deleted file mode 100644
index 32a2b68a..00000000
--- a/src/Formats/StructuredFormatService.kt
+++ /dev/null
@@ -1,367 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.LanguageService.RenderMode
-import java.util.*
-
-data class FormatLink(val text: String, val href: String)
-
-enum class ListKind {
- Ordered,
- Unordered
-}
-
-abstract class StructuredFormatService(locationService: LocationService,
- val languageService: LanguageService,
- override val extension: String,
- val linkExtension: String = extension) : FormatService {
- val locationService: LocationService = locationService.withExtension(linkExtension)
-
- abstract fun appendBlockCode(to: StringBuilder, line: String, language: String)
- abstract fun appendHeader(to: StringBuilder, text: String, level: Int = 1)
- abstract fun appendParagraph(to: StringBuilder, text: String)
- abstract fun appendLine(to: StringBuilder, text: String)
- abstract fun appendLine(to: StringBuilder)
- abstract fun appendAnchor(to: StringBuilder, anchor: String)
-
- abstract fun appendTable(to: StringBuilder, body: () -> Unit)
- abstract fun appendTableHeader(to: StringBuilder, body: () -> Unit)
- abstract fun appendTableBody(to: StringBuilder, body: () -> Unit)
- abstract fun appendTableRow(to: StringBuilder, body: () -> Unit)
- abstract fun appendTableCell(to: StringBuilder, body: () -> Unit)
-
- abstract fun formatText(text: String): String
- abstract fun formatSymbol(text: String): String
- abstract fun formatKeyword(text: String): String
- abstract fun formatIdentifier(text: String, kind: IdentifierKind): String
- fun formatEntity(text: String): String = text
- abstract fun formatLink(text: String, href: String): String
- open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.href)
- abstract fun formatStrong(text: String): String
- abstract fun formatStrikethrough(text: String): String
- abstract fun formatEmphasis(text: String): String
- abstract fun formatCode(code: String): String
- abstract fun formatUnorderedList(text: String): String
- abstract fun formatOrderedList(text: String): String
- abstract fun formatListItem(text: String, kind: ListKind): String
- abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String
- abstract fun formatNonBreakingSpace(): String
- open fun formatSoftLineBreak(): String = ""
- open fun formatIndentedSoftLineBreak(): String = ""
-
- open fun formatText(location: Location, nodes: Iterable<ContentNode>, listKind: ListKind = ListKind.Unordered): String {
- return nodes.map { formatText(location, it, listKind) }.joinToString("")
- }
-
- open fun formatText(location: Location, content: ContentNode, listKind: ListKind = ListKind.Unordered): String {
- return StringBuilder().apply {
- when (content) {
- is ContentText -> append(formatText(content.text))
- is ContentSymbol -> append(formatSymbol(content.text))
- is ContentKeyword -> append(formatKeyword(content.text))
- is ContentIdentifier -> append(formatIdentifier(content.text, content.kind))
- is ContentNonBreakingSpace -> append(formatNonBreakingSpace())
- is ContentSoftLineBreak -> append(formatSoftLineBreak())
- is ContentIndentedSoftLineBreak -> append(formatIndentedSoftLineBreak())
- is ContentEntity -> append(formatEntity(content.text))
- is ContentStrong -> append(formatStrong(formatText(location, content.children)))
- is ContentStrikethrough -> append(formatStrikethrough(formatText(location, content.children)))
- is ContentCode -> append(formatCode(formatText(location, content.children)))
- is ContentEmphasis -> append(formatEmphasis(formatText(location, content.children)))
- is ContentUnorderedList -> append(formatUnorderedList(formatText(location, content.children, ListKind.Unordered)))
- is ContentOrderedList -> append(formatOrderedList(formatText(location, content.children, ListKind.Ordered)))
- is ContentListItem -> append(formatListItem(formatText(location, content.children), listKind))
-
- is ContentNodeLink -> {
- val node = content.node
- val linkTo = if (node != null) locationHref(location, node) else "#"
- val linkText = formatText(location, content.children)
- if (linkTo == ".") {
- append(linkText)
- } else {
- append(formatLink(linkText, linkTo))
- }
- }
- is ContentExternalLink -> {
- val linkText = formatText(location, content.children)
- if (content.href == ".") {
- append(linkText)
- } else {
- append(formatLink(linkText, content.href))
- }
- }
- is ContentParagraph -> appendParagraph(this, formatText(location, content.children))
- is ContentBlockCode -> appendBlockCode(this, formatText(location, content.children), content.language)
- is ContentHeading -> appendHeader(this, formatText(location, content.children), content.level)
- is ContentBlock -> append(formatText(location, content.children))
- }
- }.toString()
- }
-
- open fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension)
-
- open fun link(from: DocumentationNode, to: DocumentationNode, extension: String): FormatLink {
- return FormatLink(to.name, locationService.relativePathToLocation(from, to))
- }
-
- fun locationHref(from: Location, to: DocumentationNode): String {
- val topLevelPage = to.references(DocumentationReference.Kind.TopLevelPage).singleOrNull()?.to
- if (topLevelPage != null) {
- return from.relativePathTo(locationService.location(topLevelPage), to.name)
- }
- return from.relativePathTo(locationService.location(to))
- }
-
- fun appendDocumentation(location: Location, to: StringBuilder, overloads: Iterable<DocumentationNode>) {
- val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node -> node.content }
-
- for ((summary, items) in breakdownBySummary) {
- appendAsOverloadGroup(to) {
- items.forEach {
- val rendered = languageService.render(it)
- appendAsSignature(to, rendered) {
- to.append(formatCode(formatText(location, rendered)))
- it.appendSourceLink(to)
- }
- it.appendOverrides(to)
- it.appendDeprecation(location, to)
- }
- // All items have exactly the same documentation, so we can use any item to render it
- val item = items.first()
- item.details(DocumentationNode.Kind.OverloadGroupNote).forEach {
- to.append(formatText(location, it.content))
- }
- to.append(formatText(location, item.content.summary))
- appendDescription(location, to, item)
- appendLine(to)
- appendLine(to)
- }
- }
- }
-
- private fun DocumentationNode.isModuleOrPackage(): Boolean =
- kind == DocumentationNode.Kind.Module || kind == DocumentationNode.Kind.Package
-
- protected open fun appendAsSignature(to: StringBuilder, node: ContentNode, block: () -> Unit) {
- block()
- }
-
- protected open fun appendAsOverloadGroup(to: StringBuilder, block: () -> Unit) {
- block()
- }
-
- fun appendDescription(location: Location, to: StringBuilder, node: DocumentationNode) {
- if (node.content.description != ContentEmpty) {
- appendLine(to, formatText(location, node.content.description))
- appendLine(to)
- }
- node.content.getSectionsWithSubjects().forEach {
- appendSectionWithSubject(it.key, location, it.value, to)
- }
-
- for (section in node.content.sections.filter { it.subjectName == null }) {
- appendLine(to, formatStrong(formatText(section.tag)))
- appendLine(to, formatText(location, section))
- }
- }
-
- fun Content.getSectionsWithSubjects(): Map<String, List<ContentSection>> =
- sections.filter { it.subjectName != null }.groupBy { it.tag }
-
- fun appendSectionWithSubject(title: String, location: Location, subjectSections: List<ContentSection>, to: StringBuilder) {
- appendHeader(to, title, 3)
- subjectSections.forEach {
- val subjectName = it.subjectName
- if (subjectName != null) {
- appendAnchor(to, subjectName)
- to.append(formatCode(subjectName)).append(" - ")
- to.append(formatText(location, it))
- appendLine(to)
- }
- }
- }
-
- private fun DocumentationNode.appendOverrides(to: StringBuilder) {
- overrides.forEach {
- to.append("Overrides ")
- val location = locationService.relativePathToLocation(this, it)
- appendLine(to, formatLink(FormatLink(it.owner!!.name + "." + it.name, location)))
- }
- }
-
- private fun DocumentationNode.appendDeprecation(location: Location, to: StringBuilder) {
- if (deprecation != null) {
- val deprecationParameter = deprecation!!.details(DocumentationNode.Kind.Parameter).firstOrNull()
- val deprecationValue = deprecationParameter?.details(DocumentationNode.Kind.Value)?.firstOrNull()
- if (deprecationValue != null) {
- to.append(formatStrong("Deprecated:")).append(" ")
- appendLine(to, formatText(deprecationValue.name.removeSurrounding("\"")))
- appendLine(to)
- } else if (deprecation?.content != Content.Empty) {
- to.append(formatStrong("Deprecated:")).append(" ")
- to.append(formatText(location, deprecation!!.content))
- } else {
- appendLine(to, formatStrong("Deprecated"))
- appendLine(to)
- }
- }
- }
-
- private fun DocumentationNode.appendSourceLink(to: StringBuilder) {
- val sourceUrl = details(DocumentationNode.Kind.SourceUrl).firstOrNull()
- if (sourceUrl != null) {
- to.append(" ")
- appendLine(to, formatLink("(source)", sourceUrl.name))
- } else {
- appendLine(to)
- }
- }
-
- fun appendLocation(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- val singleNode = nodes.singleOrNull()
- if (singleNode != null && singleNode.isModuleOrPackage()) {
- if (singleNode.kind == DocumentationNode.Kind.Package) {
- appendHeader(to, "Package " + formatText(singleNode.name), 2)
- }
- to.append(formatText(location, singleNode.content))
- } else {
- val breakdownByName = nodes.groupBy { node -> node.name }
- for ((name, items) in breakdownByName) {
- appendHeader(to, formatText(name))
- appendDocumentation(location, to, items)
- }
- }
- }
-
- private fun appendSection(location: Location, caption: String, nodes: List<DocumentationNode>, node: DocumentationNode, to: StringBuilder) {
- if (nodes.any()) {
- appendHeader(to, caption, 3)
-
- val children = nodes.sortedBy { it.name }
- val membersMap = children.groupBy { link(node, it) }
-
- appendTable(to) {
- appendTableBody(to) {
- for ((memberLocation, members) in membersMap) {
- appendTableRow(to) {
- appendTableCell(to) {
- to.append(formatLink(memberLocation))
- }
- appendTableCell(to) {
- val breakdownBySummary = members.groupBy { formatText(location, it.summary) }
- for ((summary, items) in breakdownBySummary) {
- appendSummarySignatures(items, location, to)
- if (!summary.isEmpty()) {
- to.append(summary)
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- private fun appendSummarySignatures(items: List<DocumentationNode>, location: Location, to: StringBuilder) {
- val summarySignature = languageService.summarizeSignatures(items)
- if (summarySignature != null) {
- appendAsSignature(to, summarySignature) {
- appendLine(to, summarySignature.signatureToText(location))
- }
- return
- }
- val renderedSignatures = items.map { languageService.render(it, RenderMode.SUMMARY) }
- renderedSignatures.subList(0, renderedSignatures.size - 1).forEach {
- appendAsSignature(to, it) {
- appendLine(to, it.signatureToText(location))
- }
- }
- appendAsSignature(to, renderedSignatures.last()) {
- to.append(renderedSignatures.last().signatureToText(location))
- }
- }
-
- private fun ContentNode.signatureToText(location: Location): String {
- return if (this is ContentBlock && this.isEmpty()) {
- ""
- } else {
- val signatureAsCode = ContentCode()
- signatureAsCode.append(this)
- formatText(location, signatureAsCode)
- }
- }
-
- override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- val breakdownByLocation = nodes.groupBy { node ->
- formatBreadcrumbs(node.path.filterNot { it.name.isEmpty() }.map { link(node, it) })
- }
-
- for ((breadcrumbs, items) in breakdownByLocation) {
- appendLine(to, breadcrumbs)
- appendLine(to)
- appendLocation(location, to, items.filter { it.kind != DocumentationNode.Kind.ExternalClass })
- }
-
- for (node in nodes) {
- if (node.kind == DocumentationNode.Kind.ExternalClass) {
- appendSection(location, "Extensions for ${node.name}", node.members, node, to)
- continue
- }
-
- appendSection(location, "Packages", node.members(DocumentationNode.Kind.Package), node, to)
- appendSection(location, "Types", node.members.filter { it.kind in DocumentationNode.Kind.classLike }, node, to)
- appendSection(location, "Extensions for External Classes", node.members(DocumentationNode.Kind.ExternalClass), node, to)
- appendSection(location, "Enum Values", node.members(DocumentationNode.Kind.EnumItem), node, to)
- appendSection(location, "Constructors", node.members(DocumentationNode.Kind.Constructor), node, to)
- appendSection(location, "Properties", node.members(DocumentationNode.Kind.Property), node, to)
- appendSection(location, "Inherited Properties", node.inheritedMembers(DocumentationNode.Kind.Property), node, to)
- appendSection(location, "Functions", node.members(DocumentationNode.Kind.Function), node, to)
- appendSection(location, "Inherited Functions", node.inheritedMembers(DocumentationNode.Kind.Function), node, to)
- appendSection(location, "Companion Object Properties", node.members(DocumentationNode.Kind.CompanionObjectProperty), node, to)
- appendSection(location, "Companion Object Functions", node.members(DocumentationNode.Kind.CompanionObjectFunction), node, to)
- appendSection(location, "Other members", node.members.filter {
- it.kind !in setOf(
- DocumentationNode.Kind.Class,
- DocumentationNode.Kind.Interface,
- DocumentationNode.Kind.Enum,
- DocumentationNode.Kind.Object,
- DocumentationNode.Kind.AnnotationClass,
- DocumentationNode.Kind.Constructor,
- DocumentationNode.Kind.Property,
- DocumentationNode.Kind.Package,
- DocumentationNode.Kind.Function,
- DocumentationNode.Kind.CompanionObjectProperty,
- DocumentationNode.Kind.CompanionObjectFunction,
- DocumentationNode.Kind.ExternalClass,
- DocumentationNode.Kind.EnumItem
- )
- }, node, to)
-
- val allExtensions = collectAllExtensions(node)
- appendSection(location, "Extension Properties", allExtensions.filter { it.kind == DocumentationNode.Kind.Property }, node, to)
- appendSection(location, "Extension Functions", allExtensions.filter { it.kind == DocumentationNode.Kind.Function }, node, to)
- appendSection(location, "Companion Object Extension Properties", allExtensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectProperty }, node, to)
- appendSection(location, "Companion Object Extension Functions", allExtensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectFunction }, node, to)
- appendSection(location, "Inheritors",
- node.inheritors.filter { it.kind != DocumentationNode.Kind.EnumItem }, node, to)
- appendSection(location, "Links", node.links, node, to)
-
- }
- }
-
- private fun collectAllExtensions(node: DocumentationNode): Collection<DocumentationNode> {
- val result = LinkedHashSet<DocumentationNode>()
- val visited = hashSetOf<DocumentationNode>()
-
- fun collect(node: DocumentationNode) {
- if (!visited.add(node)) return
- result.addAll(node.extensions)
- node.references(DocumentationReference.Kind.Superclass).forEach { collect(it.to) }
- }
-
- collect(node)
-
- return result
-
- }
-} \ No newline at end of file
diff --git a/src/Formats/YamlOutlineService.kt b/src/Formats/YamlOutlineService.kt
deleted file mode 100644
index 7968824c..00000000
--- a/src/Formats/YamlOutlineService.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import java.io.File
-
-class YamlOutlineService @Inject constructor(val locationService: LocationService,
- val languageService: LanguageService) : OutlineFormatService {
- override fun getOutlineFileName(location: Location): File = File("${location.path}.yml")
-
- var outlineLevel = 0
- override fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) {
- val indent = " ".repeat(outlineLevel)
- to.appendln("$indent- title: ${languageService.renderName(node)}")
- to.appendln("$indent url: ${locationService.location(node).path}")
- }
-
- override fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) {
- val indent = " ".repeat(outlineLevel)
- to.appendln("$indent content:")
- outlineLevel++
- body()
- outlineLevel--
- }
-}
diff --git a/src/Generation/ConsoleGenerator.kt b/src/Generation/ConsoleGenerator.kt
deleted file mode 100644
index 803a16e4..00000000
--- a/src/Generation/ConsoleGenerator.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.jetbrains.dokka
-
-public class ConsoleGenerator(val signatureGenerator: LanguageService, val locationService: LocationService) {
- val IndentStep = " "
-
- public fun generate(node: DocumentationNode, indent: String = "") {
- println("@${locationService.location(node).path}")
- generateHeader(node, indent)
- //generateDetails(node, indent)
- generateMembers(node, indent)
- generateLinks(node, indent)
- }
-
- public fun generateHeader(node: DocumentationNode, indent: String = "") {
- println(indent + signatureGenerator.render(node))
- val docString = node.content.toString()
- if (!docString.isEmpty())
- println("$indent\"${docString.replace("\n", "\n$indent")}\"")
- println()
- }
-
- public fun generateMembers(node: DocumentationNode, indent: String = "") {
- val items = node.members.sortedBy { it.name }
- for (child in items)
- generate(child, indent + IndentStep)
- }
-
- public fun generateDetails(node: DocumentationNode, indent: String = "") {
- val items = node.details
- for (child in items)
- generate(child, indent + " ")
- }
-
- public fun generateLinks(node: DocumentationNode, indent: String = "") {
- val items = node.links
- if (items.isEmpty())
- return
- println("$indent Links")
- for (child in items)
- generate(child, indent + " ")
- }
-} \ No newline at end of file
diff --git a/src/Generation/FileGenerator.kt b/src/Generation/FileGenerator.kt
deleted file mode 100644
index a762bae3..00000000
--- a/src/Generation/FileGenerator.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import java.io.File
-import java.io.FileOutputStream
-import java.io.IOException
-import java.io.OutputStreamWriter
-
-public class FileGenerator @Inject constructor(val locationService: FileLocationService) : Generator {
-
- @set:Inject(optional = true) var outlineService: OutlineFormatService? = null
- @set:Inject(optional = true) lateinit var formatService: FormatService
-
- override fun buildPages(nodes: Iterable<DocumentationNode>) {
- val specificLocationService = locationService.withExtension(formatService.extension)
-
- for ((location, items) in nodes.groupBy { specificLocationService.location(it) }) {
- val file = location.file
- file.parentFile?.mkdirsOrFail()
- try {
- FileOutputStream(file).use {
- OutputStreamWriter(it, Charsets.UTF_8).use {
- it.write(formatService.format(location, items))
- }
- }
- } catch (e: Throwable) {
- println(e)
- }
- buildPages(items.flatMap { it.members })
- }
- }
-
- override fun buildOutlines(nodes: Iterable<DocumentationNode>) {
- val outlineService = this.outlineService ?: return
- for ((location, items) in nodes.groupBy { locationService.location(it) }) {
- val file = outlineService.getOutlineFileName(location)
- file.parentFile?.mkdirsOrFail()
- FileOutputStream(file).use {
- OutputStreamWriter(it, Charsets.UTF_8).use {
- it.write(outlineService.formatOutline(location, items))
- }
- }
- }
- }
-
- override fun buildSupportFiles() {
- FileOutputStream(locationService.location(listOf("style.css"), false).file).use {
- javaClass.getResourceAsStream("/dokka/styles/style.css").copyTo(it)
- }
- }
-}
-
-private fun File.mkdirsOrFail() {
- if (!mkdirs() && !exists()) {
- throw IOException("Failed to create directory $this")
- }
-} \ No newline at end of file
diff --git a/src/Generation/Generator.kt b/src/Generation/Generator.kt
deleted file mode 100644
index ac10a6a5..00000000
--- a/src/Generation/Generator.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.jetbrains.dokka
-
-public interface Generator {
- fun buildPages(nodes: Iterable<DocumentationNode>)
- fun buildOutlines(nodes: Iterable<DocumentationNode>)
- fun buildSupportFiles()
-}
-
-fun Generator.buildAll(nodes: Iterable<DocumentationNode>) {
- buildPages(nodes)
- buildOutlines(nodes)
- buildSupportFiles()
-}
-
-fun Generator.buildPage(node: DocumentationNode): Unit = buildPages(listOf(node))
-
-fun Generator.buildOutline(node: DocumentationNode): Unit = buildOutlines(listOf(node))
-
-fun Generator.buildAll(node: DocumentationNode): Unit = buildAll(listOf(node))
diff --git a/src/Java/JavaPsiDocumentationBuilder.kt b/src/Java/JavaPsiDocumentationBuilder.kt
deleted file mode 100644
index 3c9875cd..00000000
--- a/src/Java/JavaPsiDocumentationBuilder.kt
+++ /dev/null
@@ -1,266 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.psi.*
-import org.jetbrains.dokka.DocumentationNode.Kind
-
-fun getSignature(element: PsiElement?) = when(element) {
- is PsiClass -> element.qualifiedName
- is PsiField -> element.containingClass!!.qualifiedName + "#" + element.name
- is PsiMethod ->
- element.containingClass!!.qualifiedName + "#" + element.name + "(" +
- element.parameterList.parameters.map { it.type.typeSignature() }.joinToString(",") + ")"
- else -> null
-}
-
-private fun PsiType.typeSignature(): String = when(this) {
- is PsiArrayType -> "Array<${componentType.typeSignature()}>"
- else -> mapTypeName(this)
-}
-
-private fun mapTypeName(psiType: PsiType): String = when (psiType) {
- is PsiPrimitiveType -> psiType.canonicalText
- is PsiClassType -> psiType.resolve()?.qualifiedName ?: psiType.className
- is PsiEllipsisType -> mapTypeName(psiType.componentType)
- is PsiArrayType -> "Array"
- else -> psiType.canonicalText
-}
-
-interface JavaDocumentationBuilder {
- fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>)
-}
-
-class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
- private val options: DocumentationOptions
- private val refGraph: NodeReferenceGraph
- private val docParser: JavaDocumentationParser
-
- @Inject constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph) {
- this.options = options
- this.refGraph = refGraph
- this.docParser = JavadocParser(refGraph)
- }
-
- constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) {
- this.options = options
- this.refGraph = refGraph
- this.docParser = docParser
- }
-
- override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
- if (file.classes.all { skipElement(it) }) {
- return
- }
- val packageNode = module.findOrCreatePackageNode(file.packageName, emptyMap())
- appendClasses(packageNode, file.classes)
- }
-
- fun appendClasses(packageNode: DocumentationNode, classes: Array<PsiClass>) {
- packageNode.appendChildren(classes) { build() }
- }
-
- fun register(element: PsiElement, node: DocumentationNode) {
- val signature = getSignature(element)
- if (signature != null) {
- refGraph.register(signature, node)
- }
- }
-
- fun link(node: DocumentationNode, element: PsiElement?) {
- val qualifiedName = getSignature(element)
- if (qualifiedName != null) {
- refGraph.link(node, qualifiedName, DocumentationReference.Kind.Link)
- }
- }
-
- fun link(element: PsiElement?, node: DocumentationNode, kind: DocumentationReference.Kind) {
- val qualifiedName = getSignature(element)
- if (qualifiedName != null) {
- refGraph.link(qualifiedName, node, kind)
- }
- }
-
- fun nodeForElement(element: PsiNamedElement,
- kind: Kind,
- name: String = element.name ?: "<anonymous>"): DocumentationNode {
- val (docComment, deprecatedContent) = docParser.parseDocumentation(element)
- val node = DocumentationNode(name, docComment, kind)
- if (element is PsiModifierListOwner) {
- node.appendModifiers(element)
- val modifierList = element.modifierList
- if (modifierList != null) {
- modifierList.annotations.filter { !ignoreAnnotation(it) }.forEach {
- val annotation = it.build()
- node.append(annotation,
- if (it.qualifiedName == "java.lang.Deprecated") DocumentationReference.Kind.Deprecation else DocumentationReference.Kind.Annotation)
- }
- }
- }
- if (deprecatedContent != null) {
- val deprecationNode = DocumentationNode("", deprecatedContent, Kind.Modifier)
- node.append(deprecationNode, DocumentationReference.Kind.Deprecation)
- }
- if (element is PsiDocCommentOwner && element.isDeprecated && node.deprecation == null) {
- val deprecationNode = DocumentationNode("", Content.of(ContentText("Deprecated")), Kind.Modifier)
- node.append(deprecationNode, DocumentationReference.Kind.Deprecation)
- }
- return node
- }
-
- fun ignoreAnnotation(annotation: PsiAnnotation) = when(annotation.qualifiedName) {
- "java.lang.SuppressWarnings" -> true
- else -> false
- }
-
- fun <T : Any> DocumentationNode.appendChildren(elements: Array<T>,
- kind: DocumentationReference.Kind = DocumentationReference.Kind.Member,
- buildFn: T.() -> DocumentationNode) {
- elements.forEach {
- if (!skipElement(it)) {
- append(it.buildFn(), kind)
- }
- }
- }
-
- private fun skipElement(element: Any) = skipElementByVisibility(element) || hasSuppressTag(element)
-
- private fun skipElementByVisibility(element: Any): Boolean =
- !options.includeNonPublic && element is PsiModifierListOwner &&
- (element.hasModifierProperty(PsiModifier.PRIVATE) || element.hasModifierProperty(PsiModifier.PACKAGE_LOCAL))
-
- private fun hasSuppressTag(element: Any) =
- element is PsiDocCommentOwner && element.docComment?.let { it.findTagByName("suppress") != null } ?: false
-
- fun <T : Any> DocumentationNode.appendMembers(elements: Array<T>, buildFn: T.() -> DocumentationNode) =
- appendChildren(elements, DocumentationReference.Kind.Member, buildFn)
-
- fun <T : Any> DocumentationNode.appendDetails(elements: Array<T>, buildFn: T.() -> DocumentationNode) =
- appendChildren(elements, DocumentationReference.Kind.Detail, buildFn)
-
- fun PsiClass.build(): DocumentationNode {
- val kind = when {
- isInterface -> DocumentationNode.Kind.Interface
- isEnum -> DocumentationNode.Kind.Enum
- isAnnotationType -> DocumentationNode.Kind.AnnotationClass
- else -> DocumentationNode.Kind.Class
- }
- val node = nodeForElement(this, kind)
- superTypes.filter { !ignoreSupertype(it) }.forEach {
- node.appendType(it, Kind.Supertype)
- val superClass = it.resolve()
- if (superClass != null) {
- link(superClass, node, DocumentationReference.Kind.Inheritor)
- }
- }
- node.appendDetails(typeParameters) { build() }
- node.appendMembers(methods) { build() }
- node.appendMembers(fields) { build() }
- node.appendMembers(innerClasses) { build() }
- register(this, node)
- return node
- }
-
- fun ignoreSupertype(psiType: PsiClassType): Boolean =
- psiType.isClass("java.lang.Enum") || psiType.isClass("java.lang.Object")
-
- fun PsiClassType.isClass(qName: String): Boolean {
- val shortName = qName.substringAfterLast('.')
- if (className == shortName) {
- val psiClass = resolve()
- return psiClass?.qualifiedName == qName
- }
- return false
- }
-
- fun PsiField.build(): DocumentationNode {
- val node = nodeForElement(this, nodeKind())
- node.appendType(type)
- node.appendModifiers(this)
- register(this, node)
- return node
- }
-
- private fun PsiField.nodeKind(): Kind = when {
- this is PsiEnumConstant -> Kind.EnumItem
- else -> Kind.Field
- }
-
- fun PsiMethod.build(): DocumentationNode {
- val node = nodeForElement(this, nodeKind(),
- if (isConstructor) "<init>" else name)
-
- if (!isConstructor) {
- node.appendType(returnType)
- }
- node.appendDetails(parameterList.parameters) { build() }
- node.appendDetails(typeParameters) { build() }
- register(this, node)
- return node
- }
-
- private fun PsiMethod.nodeKind(): Kind = when {
- isConstructor -> Kind.Constructor
- else -> Kind.Function
- }
-
- fun PsiParameter.build(): DocumentationNode {
- val node = nodeForElement(this, Kind.Parameter)
- node.appendType(type)
- if (type is PsiEllipsisType) {
- node.appendTextNode("vararg", Kind.Modifier, DocumentationReference.Kind.Detail)
- }
- return node
- }
-
- fun PsiTypeParameter.build(): DocumentationNode {
- val node = nodeForElement(this, Kind.TypeParameter)
- extendsListTypes.forEach { node.appendType(it, Kind.UpperBound) }
- implementsListTypes.forEach { node.appendType(it, Kind.UpperBound) }
- return node
- }
-
- fun DocumentationNode.appendModifiers(element: PsiModifierListOwner) {
- val modifierList = element.modifierList ?: return
-
- PsiModifier.MODIFIERS.forEach {
- if (modifierList.hasExplicitModifier(it)) {
- appendTextNode(it, Kind.Modifier)
- }
- }
- }
-
- fun DocumentationNode.appendType(psiType: PsiType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) {
- if (psiType == null) {
- return
- }
- append(psiType.build(kind), DocumentationReference.Kind.Detail)
- }
-
- fun PsiType.build(kind: DocumentationNode.Kind = DocumentationNode.Kind.Type): DocumentationNode {
- val name = mapTypeName(this)
- val node = DocumentationNode(name, Content.Empty, kind)
- if (this is PsiClassType) {
- node.appendDetails(parameters) { build(Kind.Type) }
- link(node, resolve())
- }
- if (this is PsiArrayType && this !is PsiEllipsisType) {
- node.append(componentType.build(Kind.Type), DocumentationReference.Kind.Detail)
- }
- return node
- }
-
- fun PsiAnnotation.build(): DocumentationNode {
- val node = DocumentationNode(nameReferenceElement?.text ?: "<?>", Content.Empty, DocumentationNode.Kind.Annotation)
- parameterList.attributes.forEach {
- val parameter = DocumentationNode(it.name ?: "value", Content.Empty, DocumentationNode.Kind.Parameter)
- val value = it.value
- if (value != null) {
- val valueText = (value as? PsiLiteralExpression)?.value as? String ?: value.text
- val valueNode = DocumentationNode(valueText, Content.Empty, DocumentationNode.Kind.Value)
- parameter.append(valueNode, DocumentationReference.Kind.Detail)
- }
- node.append(parameter, DocumentationReference.Kind.Detail)
- }
- return node
- }
-}
diff --git a/src/Java/JavadocParser.kt b/src/Java/JavadocParser.kt
deleted file mode 100644
index 1378a5a7..00000000
--- a/src/Java/JavadocParser.kt
+++ /dev/null
@@ -1,170 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.*
-import com.intellij.psi.javadoc.PsiDocTag
-import com.intellij.psi.javadoc.PsiDocTagValue
-import com.intellij.psi.javadoc.PsiDocToken
-import com.intellij.psi.javadoc.PsiInlineDocTag
-import org.jsoup.Jsoup
-import org.jsoup.nodes.Element
-import org.jsoup.nodes.Node
-import org.jsoup.nodes.TextNode
-
-data class JavadocParseResult(val content: Content, val deprecatedContent: Content?) {
- companion object {
- val Empty = JavadocParseResult(Content.Empty, null)
- }
-}
-
-interface JavaDocumentationParser {
- fun parseDocumentation(element: PsiNamedElement): JavadocParseResult
-}
-
-class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentationParser {
- override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
- val docComment = (element as? PsiDocCommentOwner)?.docComment
- if (docComment == null) return JavadocParseResult.Empty
- val result = MutableContent()
- var deprecatedContent: Content? = null
- val para = ContentParagraph()
- result.append(para)
- para.convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() })
- docComment.tags.forEach { tag ->
- when(tag.name) {
- "see" -> result.convertSeeTag(tag)
- "deprecated" -> {
- deprecatedContent = Content()
- deprecatedContent!!.convertJavadocElements(tag.contentElements())
- }
- else -> {
- val subjectName = tag.getSubjectName()
- val section = result.addSection(javadocSectionDisplayName(tag.name), subjectName)
-
- section.convertJavadocElements(tag.contentElements())
- }
- }
- }
- return JavadocParseResult(result, deprecatedContent)
- }
-
- private fun PsiDocTag.contentElements(): Iterable<PsiElement> {
- val tagValueElements = children
- .dropWhile { it.node?.elementType == JavaDocTokenType.DOC_TAG_NAME }
- .dropWhile { it is PsiWhiteSpace }
- .filterNot { it.node?.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS }
- return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements
- }
-
- private fun ContentBlock.convertJavadocElements(elements: Iterable<PsiElement>) {
- val htmlBuilder = StringBuilder()
- elements.forEach {
- if (it is PsiInlineDocTag) {
- htmlBuilder.append(convertInlineDocTag(it))
- } else {
- htmlBuilder.append(it.text)
- }
- }
- val doc = Jsoup.parse(htmlBuilder.toString().trimStart())
- doc.body().childNodes().forEach {
- convertHtmlNode(it)
- }
- }
-
- private fun ContentBlock.convertHtmlNode(node: Node) {
- if (node is TextNode) {
- append(ContentText(node.text()))
- } else if (node is Element) {
- val childBlock = createBlock(node)
- node.childNodes().forEach {
- childBlock.convertHtmlNode(it)
- }
- append(childBlock)
- }
- }
-
- private fun createBlock(element: Element): ContentBlock = when(element.tagName()) {
- "p" -> ContentParagraph()
- "b", "strong" -> ContentStrong()
- "i", "em" -> ContentEmphasis()
- "s", "del" -> ContentStrikethrough()
- "code" -> ContentCode()
- "pre" -> ContentBlockCode()
- "ul" -> ContentUnorderedList()
- "ol" -> ContentOrderedList()
- "li" -> ContentListItem()
- "a" -> createLink(element)
- else -> ContentBlock()
- }
-
- private fun createLink(element: Element): ContentBlock {
- val docref = element.attr("docref")
- if (docref != null) {
- return ContentNodeLazyLink(docref, { -> refGraph.lookup(docref)})
- }
- val href = element.attr("href")
- if (href != null) {
- return ContentExternalLink(href)
- } else {
- return ContentBlock()
- }
- }
-
- private fun MutableContent.convertSeeTag(tag: PsiDocTag) {
- val linkElement = tag.linkElement()
- if (linkElement == null) {
- return
- }
- val seeSection = findSectionByTag(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null)
- val linkSignature = resolveLink(linkElement)
- val text = ContentText(linkElement.text)
- if (linkSignature != null) {
- val linkNode = ContentNodeLazyLink(tag.valueElement!!.text, { -> refGraph.lookup(linkSignature)})
- linkNode.append(text)
- seeSection.append(linkNode)
- } else {
- seeSection.append(text)
- }
- }
-
- private fun convertInlineDocTag(tag: PsiInlineDocTag) = when (tag.name) {
- "link", "linkplain" -> {
- val valueElement = tag.linkElement()
- val linkSignature = resolveLink(valueElement)
- if (linkSignature != null) {
- val labelText = tag.dataElements.firstOrNull { it is PsiDocToken }?.text ?: valueElement!!.text
- val link = "<a docref=\"$linkSignature\">${labelText.htmlEscape()}</a>"
- if (tag.name == "link") "<code>$link</code>" else link
- }
- else if (valueElement != null) {
- valueElement.text
- } else {
- ""
- }
- }
- "code", "literal" -> {
- val text = StringBuilder()
- tag.dataElements.forEach { text.append(it.text) }
- val escaped = text.toString().trimStart().htmlEscape()
- if (tag.name == "code") "<code>$escaped</code>" else escaped
- }
- else -> tag.text
- }
-
- private fun PsiDocTag.linkElement(): PsiElement? =
- valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
-
- private fun resolveLink(valueElement: PsiElement?): String? {
- val target = valueElement?.reference?.resolve()
- if (target != null) {
- return getSignature(target)
- }
- return null
- }
-
- fun PsiDocTag.getSubjectName(): String? {
- if (name == "param" || name == "throws" || name == "exception") {
- return valueElement?.text
- }
- return null
- }
-}
diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt
deleted file mode 100644
index c4bb18de..00000000
--- a/src/Kotlin/ContentBuilder.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.jetbrains.dokka
-
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.intellij.markdown.html.entities.EntityConverter
-import java.util.*
-
-public fun buildContent(tree: MarkdownNode, linkResolver: (String) -> ContentBlock, inline: Boolean = false): MutableContent {
- val result = MutableContent()
- if (inline) {
- buildInlineContentTo(tree, result, linkResolver)
- }
- else {
- buildContentTo(tree, result, linkResolver)
- }
- return result
-}
-
-public fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) {
-// println(tree.toTestString())
- val nodeStack = ArrayDeque<ContentBlock>()
- nodeStack.push(target)
-
- tree.visit {node, processChildren ->
- val parent = nodeStack.peek()
-
- fun appendNodeWithChildren(content: ContentBlock) {
- nodeStack.push(content)
- processChildren()
- parent.append(nodeStack.pop())
- }
-
- when (node.type) {
- MarkdownElementTypes.ATX_1 -> appendNodeWithChildren(ContentHeading(1))
- MarkdownElementTypes.ATX_2 -> appendNodeWithChildren(ContentHeading(2))
- MarkdownElementTypes.ATX_3 -> appendNodeWithChildren(ContentHeading(3))
- MarkdownElementTypes.ATX_4 -> appendNodeWithChildren(ContentHeading(4))
- MarkdownElementTypes.ATX_5 -> appendNodeWithChildren(ContentHeading(5))
- MarkdownElementTypes.ATX_6 -> appendNodeWithChildren(ContentHeading(6))
- MarkdownElementTypes.UNORDERED_LIST -> appendNodeWithChildren(ContentUnorderedList())
- MarkdownElementTypes.ORDERED_LIST -> appendNodeWithChildren(ContentOrderedList())
- MarkdownElementTypes.LIST_ITEM -> appendNodeWithChildren(ContentListItem())
- MarkdownElementTypes.EMPH -> appendNodeWithChildren(ContentEmphasis())
- MarkdownElementTypes.STRONG -> appendNodeWithChildren(ContentStrong())
- MarkdownElementTypes.CODE_SPAN -> appendNodeWithChildren(ContentCode())
- MarkdownElementTypes.CODE_BLOCK,
- MarkdownElementTypes.CODE_FENCE -> appendNodeWithChildren(ContentBlockCode())
- MarkdownElementTypes.PARAGRAPH -> appendNodeWithChildren(ContentParagraph())
-
- MarkdownElementTypes.INLINE_LINK -> {
- val label = node.child(MarkdownElementTypes.LINK_TEXT)?.child(MarkdownTokenTypes.TEXT)
- val destination = node.child(MarkdownElementTypes.LINK_DESTINATION)
- if (label != null) {
- if (destination != null) {
- val link = ContentExternalLink(destination.text)
- link.append(ContentText(label.text))
- parent.append(link)
- } else {
- val link = ContentExternalLink(label.text)
- link.append(ContentText(label.text))
- parent.append(link)
- }
- }
- }
- MarkdownElementTypes.SHORT_REFERENCE_LINK,
- MarkdownElementTypes.FULL_REFERENCE_LINK -> {
- val label = node.child(MarkdownElementTypes.LINK_LABEL)?.child(MarkdownTokenTypes.TEXT)
- if (label != null) {
- val link = linkResolver(label.text)
- val linkText = node.child(MarkdownElementTypes.LINK_TEXT)?.child(MarkdownTokenTypes.TEXT)
- link.append(ContentText(linkText?.text ?: label.text))
- parent.append(link)
- }
- }
- MarkdownTokenTypes.WHITE_SPACE,
- MarkdownTokenTypes.EOL -> {
- if (keepWhitespace(nodeStack.peek()) && node.parent?.children?.last() != node) {
- parent.append(ContentText(node.text))
- }
- }
-
- MarkdownTokenTypes.CODE -> {
- val block = ContentBlockCode()
- block.append(ContentText(node.text))
- parent.append(block)
- }
-
- MarkdownTokenTypes.TEXT -> {
- fun createEntityOrText(text: String): ContentNode {
- if (text == "&amp;" || text == "&quot;" || text == "&lt;" || text == "&gt;") {
- return ContentEntity(text)
- }
- if (text == "&") {
- return ContentEntity("&amp;")
- }
- val decodedText = EntityConverter.replaceEntities(text, true, true)
- if (decodedText != text) {
- return ContentEntity(text)
- }
- return ContentText(text)
- }
-
- parent.append(createEntityOrText(node.text))
- }
-
- MarkdownTokenTypes.COLON,
- MarkdownTokenTypes.DOUBLE_QUOTE,
- MarkdownTokenTypes.LT,
- MarkdownTokenTypes.GT,
- MarkdownTokenTypes.LPAREN,
- MarkdownTokenTypes.RPAREN,
- MarkdownTokenTypes.LBRACKET,
- MarkdownTokenTypes.RBRACKET,
- MarkdownTokenTypes.CODE_FENCE_CONTENT -> {
- parent.append(ContentText(node.text))
- }
- else -> {
- processChildren()
- }
- }
- }
-}
-
-private fun keepWhitespace(node: ContentNode) = node is ContentParagraph || node is ContentSection
-
-public fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) {
- val inlineContent = tree.children.singleOrNull { it.type == MarkdownElementTypes.PARAGRAPH }?.children ?: listOf(tree)
- inlineContent.forEach {
- buildContentTo(it, target, linkResolver)
- }
-}
-
diff --git a/src/Kotlin/DeclarationLinkResolver.kt b/src/Kotlin/DeclarationLinkResolver.kt
deleted file mode 100644
index 2569bc71..00000000
--- a/src/Kotlin/DeclarationLinkResolver.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
-
-class DeclarationLinkResolver
- @Inject constructor(val resolutionFacade: DokkaResolutionFacade,
- val refGraph: NodeReferenceGraph,
- val logger: DokkaLogger) {
- fun resolveContentLink(fromDescriptor: DeclarationDescriptor, href: String): ContentBlock {
- val symbol = try {
- val symbols = resolveKDocLink(resolutionFacade, fromDescriptor, null, href.split('.').toList())
- findTargetSymbol(symbols)
- } catch(e: Exception) {
- null
- }
-
- // don't include unresolved links in generated doc
- // assume that if an href doesn't contain '/', it's not an attempt to reference an external file
- if (symbol != null) {
- return ContentNodeLazyLink(href, { -> refGraph.lookup(symbol.signature()) })
- }
- if ("/" in href) {
- return ContentExternalLink(href)
- }
- logger.warn("Unresolved link to $href in doc comment of ${fromDescriptor.signatureWithSourceLocation()}")
- return ContentExternalLink("#")
- }
-
- fun findTargetSymbol(symbols: Collection<DeclarationDescriptor>): DeclarationDescriptor? {
- if (symbols.isEmpty()) {
- return null
- }
- val symbol = symbols.first()
- if (symbol is CallableMemberDescriptor && symbol.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
- return symbol.overriddenDescriptors.firstOrNull()
- }
- return symbol
- }
-
-} \ No newline at end of file
diff --git a/src/Kotlin/DescriptorDocumentationParser.kt b/src/Kotlin/DescriptorDocumentationParser.kt
deleted file mode 100644
index b7705ec9..00000000
--- a/src/Kotlin/DescriptorDocumentationParser.kt
+++ /dev/null
@@ -1,199 +0,0 @@
-package org.jetbrains.dokka.Kotlin
-
-import com.google.inject.Inject
-import com.intellij.psi.PsiDocCommentOwner
-import com.intellij.psi.PsiNamedElement
-import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.dokka.*
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.idea.kdoc.KDocFinder
-import org.jetbrains.kotlin.idea.kdoc.getResolutionScope
-import org.jetbrains.kotlin.incremental.components.NoLookupLocation
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.psi.KtBlockExpression
-import org.jetbrains.kotlin.psi.KtDeclarationWithBody
-import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
-import org.jetbrains.kotlin.resolve.DescriptorUtils
-import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.ResolutionScope
-import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
-import org.jetbrains.kotlin.resolve.source.PsiSourceElement
-
-class DescriptorDocumentationParser
- @Inject constructor(val options: DocumentationOptions,
- val logger: DokkaLogger,
- val linkResolver: DeclarationLinkResolver,
- val resolutionFacade: DokkaResolutionFacade,
- val refGraph: NodeReferenceGraph)
-{
- fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false): Content =
- parseDocumentationAndDetails(descriptor, inline).first
-
- fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> {
- if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) {
- return parseJavadoc(descriptor)
- }
-
- val kdoc = KDocFinder.findKDoc(descriptor) ?: findStdlibKDoc(descriptor)
- if (kdoc == null) {
- if (options.reportUndocumented && !descriptor.isDeprecated() &&
- descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor &&
- descriptor !is PropertyAccessorDescriptor) {
- logger.warn("No documentation for ${descriptor.signatureWithSourceLocation()}")
- }
- return Content.Empty to { node -> }
- }
- var kdocText = kdoc.getContent()
- // workaround for code fence parsing problem in IJ markdown parser
- if (kdocText.endsWith("```") || kdocText.endsWith("~~~")) {
- kdocText += "\n"
- }
- val tree = parseMarkdown(kdocText)
- val content = buildContent(tree, { href -> linkResolver.resolveContentLink(descriptor, href) }, inline)
- if (kdoc is KDocSection) {
- val tags = kdoc.getTags()
- tags.forEach {
- when (it.name) {
- "sample" ->
- content.append(functionBody(descriptor, it.getSubjectName()))
- "see" ->
- content.addTagToSeeAlso(descriptor, it)
- else -> {
- val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName())
- val sectionContent = it.getContent()
- val markdownNode = parseMarkdown(sectionContent)
- buildInlineContentTo(markdownNode, section, { href -> linkResolver.resolveContentLink(descriptor, href) })
- }
- }
- }
- }
- return content to { node -> }
- }
-
- /**
- * Special case for generating stdlib documentation (the Any class to which the override chain will resolve
- * is not the same one as the Any class included in the source scope).
- */
- fun findStdlibKDoc(descriptor: DeclarationDescriptor): KDocTag? {
- if (descriptor !is CallableMemberDescriptor) {
- return null
- }
- val name = descriptor.name.asString()
- if (name == "equals" || name == "hashCode" || name == "toString") {
- var deepestDescriptor: CallableMemberDescriptor = descriptor
- while (!deepestDescriptor.overriddenDescriptors.isEmpty()) {
- deepestDescriptor = deepestDescriptor.overriddenDescriptors.first()
- }
- if (DescriptorUtils.getFqName(deepestDescriptor.containingDeclaration).asString() == "kotlin.Any") {
- val anyClassDescriptors = resolutionFacade.resolveSession.getTopLevelClassDescriptors(
- FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE)
- anyClassDescriptors.forEach {
- val anyMethod = it.getMemberScope(listOf())
- .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS, { it == descriptor.name })
- .single()
- val kdoc = KDocFinder.findKDoc(anyMethod)
- if (kdoc != null) {
- return kdoc
- }
- }
- }
- }
- return null
- }
-
- fun parseJavadoc(descriptor: DeclarationDescriptor): Pair<Content, (DocumentationNode) -> Unit> {
- val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi
- if (psi is PsiDocCommentOwner) {
- val parseResult = JavadocParser(refGraph).parseDocumentation(psi as PsiNamedElement)
- return parseResult.content to { node ->
- parseResult.deprecatedContent?.let {
- val deprecationNode = DocumentationNode("", it, DocumentationNode.Kind.Modifier)
- node.append(deprecationNode, DocumentationReference.Kind.Deprecation)
- }
- }
- }
- return Content.Empty to { node -> }
- }
-
- fun KDocSection.getTags(): Array<KDocTag> = PsiTreeUtil.getChildrenOfType(this, KDocTag::class.java) ?: arrayOf()
-
- private fun MutableContent.addTagToSeeAlso(descriptor: DeclarationDescriptor, seeTag: KDocTag) {
- val subjectName = seeTag.getSubjectName()
- if (subjectName != null) {
- val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null)
- val link = linkResolver.resolveContentLink(descriptor, subjectName)
- link.append(ContentText(subjectName))
- val para = ContentParagraph()
- para.append(link)
- seeSection.append(para)
- }
- }
-
- private fun functionBody(descriptor: DeclarationDescriptor, functionName: String?): ContentNode {
- if (functionName == null) {
- logger.warn("Missing function name in @sample in ${descriptor.signature()}")
- return ContentBlockCode().let() { it.append(ContentText("Missing function name in @sample")); it }
- }
- val scope = getResolutionScope(resolutionFacade, descriptor)
- val rootPackage = resolutionFacade.moduleDescriptor.getPackage(FqName.ROOT)
- val rootScope = rootPackage.memberScope
- val symbol = resolveInScope(functionName, scope) ?: resolveInScope(functionName, rootScope)
- if (symbol == null) {
- logger.warn("Unresolved function $functionName in @sample in ${descriptor.signature()}")
- return ContentBlockCode().let() { it.append(ContentText("Unresolved: $functionName")); it }
- }
- val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(symbol)
- if (psiElement == null) {
- logger.warn("Can't find source for function $functionName in @sample in ${descriptor.signature()}")
- return ContentBlockCode().let() { it.append(ContentText("Source not found: $functionName")); it }
- }
-
- val text = when (psiElement) {
- is KtDeclarationWithBody -> ContentBlockCode().let() {
- val bodyExpression = psiElement.bodyExpression
- when (bodyExpression) {
- is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}")
- else -> bodyExpression!!.text
- }
- }
- else -> psiElement.text
- }
-
- val lines = text.trimEnd().split("\n".toRegex()).toTypedArray().filterNot { it.length == 0 }
- val indent = lines.map { it.takeWhile { it.isWhitespace() }.count() }.min() ?: 0
- val finalText = lines.map { it.drop(indent) }.joinToString("\n")
- return ContentBlockCode("kotlin").let() { it.append(ContentText(finalText)); it }
- }
-
- private fun resolveInScope(functionName: String, scope: ResolutionScope): DeclarationDescriptor? {
- var currentScope = scope
- val parts = functionName.split('.')
-
- var symbol: DeclarationDescriptor? = null
-
- for (part in parts) {
- // short name
- val symbolName = Name.guess(part)
- val partSymbol = currentScope.getContributedDescriptors(DescriptorKindFilter.ALL, { it == symbolName })
- .filter { it.name == symbolName }
- .firstOrNull()
-
- if (partSymbol == null) {
- symbol = null
- break
- }
- currentScope = if (partSymbol is ClassDescriptor)
- partSymbol.defaultType.memberScope
- else
- getResolutionScope(resolutionFacade, partSymbol)
- symbol = partSymbol
- }
-
- return symbol
- }
-}
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
deleted file mode 100644
index 6551ded6..00000000
--- a/src/Kotlin/DocumentationBuilder.kt
+++ /dev/null
@@ -1,653 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.openapi.util.text.StringUtil
-import com.intellij.psi.PsiJavaFile
-import org.jetbrains.dokka.DocumentationNode.Kind
-import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser
-import org.jetbrains.kotlin.builtins.KotlinBuiltIns
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.descriptors.annotations.Annotated
-import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
-import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
-import org.jetbrains.kotlin.idea.caches.resolve.KotlinCacheService
-import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo
-import org.jetbrains.kotlin.idea.kdoc.KDocFinder
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
-import org.jetbrains.kotlin.lexer.KtTokens
-import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.KtModifierListOwner
-import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.resolve.DescriptorUtils
-import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
-import org.jetbrains.kotlin.resolve.constants.ConstantValue
-import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant
-import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
-import org.jetbrains.kotlin.resolve.descriptorUtil.isDocumentedAnnotation
-import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
-import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
-import org.jetbrains.kotlin.resolve.source.PsiSourceElement
-import org.jetbrains.kotlin.resolve.source.getPsi
-import org.jetbrains.kotlin.types.ErrorUtils
-import org.jetbrains.kotlin.types.KotlinType
-import org.jetbrains.kotlin.types.TypeProjection
-
-public data class DocumentationOptions(val outputDir: String,
- val outputFormat: String,
- val includeNonPublic: Boolean = false,
- val reportUndocumented: Boolean = true,
- val skipEmptyPackages: Boolean = true,
- val skipDeprecated: Boolean = false,
- val sourceLinks: List<SourceLinkDefinition>)
-
-private fun isSamePackage(descriptor1: DeclarationDescriptor, descriptor2: DeclarationDescriptor): Boolean {
- val package1 = DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor::class.java)
- val package2 = DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor::class.java)
- return package1 != null && package2 != null && package1.fqName == package2.fqName
-}
-
-interface PackageDocumentationBuilder {
- fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>)
-}
-
-class DocumentationBuilder
- @Inject constructor(val resolutionFacade: DokkaResolutionFacade,
- val descriptorDocumentationParser: DescriptorDocumentationParser,
- val options: DocumentationOptions,
- val refGraph: NodeReferenceGraph,
- val logger: DokkaLogger)
-{
- val visibleToDocumentation = setOf(Visibilities.PROTECTED, Visibilities.PUBLIC)
- val boringBuiltinClasses = setOf(
- "kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean",
- "kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any")
- val knownModifiers = setOf(
- KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.INTERNAL_KEYWORD, KtTokens.PRIVATE_KEYWORD,
- KtTokens.OPEN_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.ABSTRACT_KEYWORD, KtTokens.SEALED_KEYWORD,
- KtTokens.OVERRIDE_KEYWORD)
-
- fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind) {
- refGraph.link(node, descriptor.signature(), kind)
- }
-
- fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: DocumentationReference.Kind) {
- if (fromDescriptor != null && toDescriptor != null) {
- refGraph.link(fromDescriptor.signature(), toDescriptor.signature(), kind)
- }
- }
-
- fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) {
- refGraph.register(descriptor.signature(), node)
- }
-
- fun <T> nodeForDescriptor(descriptor: T, kind: Kind): DocumentationNode where T : DeclarationDescriptor, T : Named {
- val (doc, callback) = descriptorDocumentationParser.parseDocumentationAndDetails(descriptor, kind == Kind.Parameter)
- val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(descriptor)
- callback(node)
- return node
- }
-
- private fun DocumentationNode.withModifiers(descriptor: DeclarationDescriptor) : DocumentationNode{
- if (descriptor is MemberDescriptor) {
- appendVisibility(descriptor)
- if (descriptor !is ConstructorDescriptor) {
- appendModality(descriptor)
- }
- }
- return this
- }
-
- fun DocumentationNode.appendModality(descriptor: MemberDescriptor) {
- var modality = descriptor.modality
- if (modality == Modality.OPEN) {
- val containingClass = descriptor.containingDeclaration as? ClassDescriptor
- if (containingClass?.modality == Modality.FINAL) {
- modality = Modality.FINAL
- }
- }
- val modifier = modality.name.toLowerCase()
- appendTextNode(modifier, DocumentationNode.Kind.Modifier)
- }
-
- fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) {
- val modifier = descriptor.visibility.normalize().displayName
- appendTextNode(modifier, DocumentationNode.Kind.Modifier)
- }
-
- fun DocumentationNode.appendSupertypes(descriptor: ClassDescriptor) {
- val superTypes = descriptor.typeConstructor.supertypes
- for (superType in superTypes) {
- if (!ignoreSupertype(superType)) {
- appendType(superType, DocumentationNode.Kind.Supertype)
- val superclass = superType?.constructor?.declarationDescriptor
- link(superclass, descriptor, DocumentationReference.Kind.Inheritor)
- link(descriptor, superclass, DocumentationReference.Kind.Superclass)
- }
- }
- }
-
- private fun ignoreSupertype(superType: KotlinType): Boolean {
- val superClass = superType.constructor.declarationDescriptor as? ClassDescriptor
- if (superClass != null) {
- val fqName = DescriptorUtils.getFqNameSafe(superClass).asString()
- return fqName == "kotlin.Annotation" || fqName == "kotlin.Enum" || fqName == "kotlin.Any"
- }
- return false
- }
-
- fun DocumentationNode.appendProjection(projection: TypeProjection, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) {
- if (projection.isStarProjection) {
- appendTextNode("*", Kind.Type)
- }
- else {
- appendType(projection.type, kind, projection.projectionKind.label)
- }
- }
-
- fun DocumentationNode.appendType(kotlinType: KotlinType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix: String = "") {
- if (kotlinType == null)
- return
- val classifierDescriptor = kotlinType.constructor.declarationDescriptor
- val name = when (classifierDescriptor) {
- is ClassDescriptor -> {
- if (classifierDescriptor.isCompanionObject) {
- classifierDescriptor.containingDeclaration.name.asString() +
- "." + classifierDescriptor.name.asString()
- }
- else {
- classifierDescriptor.name.asString()
- }
- }
- is Named -> classifierDescriptor.name.asString()
- else -> "<anonymous>"
- }
- val node = DocumentationNode(name, Content.Empty, kind)
- if (prefix != "") {
- node.appendTextNode(prefix, Kind.Modifier)
- }
- if (kotlinType.isMarkedNullable) {
- node.appendTextNode("?", Kind.NullabilityModifier)
- }
- if (classifierDescriptor != null) {
- link(node, classifierDescriptor,
- if (classifierDescriptor.isBoringBuiltinClass()) DocumentationReference.Kind.HiddenLink else DocumentationReference.Kind.Link)
- }
-
- append(node, DocumentationReference.Kind.Detail)
- node.appendAnnotations(kotlinType)
- for (typeArgument in kotlinType.arguments) {
- node.appendProjection(typeArgument)
- }
- }
-
- fun ClassifierDescriptor.isBoringBuiltinClass(): Boolean =
- DescriptorUtils.getFqName(this).asString() in boringBuiltinClasses
-
- fun DocumentationNode.appendAnnotations(annotated: Annotated) {
- annotated.annotations.filter { it.isDocumented() }.forEach {
- val annotationNode = it.build()
- if (annotationNode != null) {
- append(annotationNode,
- if (annotationNode.isDeprecation()) DocumentationReference.Kind.Deprecation else DocumentationReference.Kind.Annotation)
- }
- }
- }
-
- fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) {
- val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return
- KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach {
- if (psi.hasModifier(it)) {
- appendTextNode(it.value, Kind.Modifier)
- }
- }
- }
-
- fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated"
-
- fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
- appendSourceLink(sourceElement.getPsi(), options.sourceLinks)
- }
-
- fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind): DocumentationNode? {
- // do not include generated code
- if (descriptor is CallableMemberDescriptor && descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION)
- return null
-
- if (descriptor.isDocumented()) {
- val node = descriptor.build()
- append(node, kind)
- return node
- }
- return null
- }
-
- fun DeclarationDescriptor.isDocumented(): Boolean {
- return (options.includeNonPublic
- || this !is MemberDescriptor
- || this.visibility in visibleToDocumentation) &&
- !isDocumentationSuppressed() &&
- (!options.skipDeprecated || !isDeprecated())
- }
-
- fun DocumentationNode.appendMembers(descriptors: Iterable<DeclarationDescriptor>): List<DocumentationNode> {
- val nodes = descriptors.map { descriptor ->
- if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
- val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull()
- if (baseDescriptor != null) {
- link(this, baseDescriptor, DocumentationReference.Kind.InheritedMember)
- }
- null
- }
- else {
- val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original
- appendChild(descriptorToUse, DocumentationReference.Kind.Member)
- }
- }
- return nodes.filterNotNull()
- }
-
- fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) {
- descriptors.forEach { descriptor ->
- val node = appendChild(descriptor, kind)
- node?.addReferenceTo(this, DocumentationReference.Kind.TopLevelPage)
- }
- }
-
- fun DocumentationModule.appendFragments(fragments: Collection<PackageFragmentDescriptor>,
- packageContent: Map<String, Content>,
- packageDocumentationBuilder: PackageDocumentationBuilder) {
- val allFqNames = fragments.map { it.fqName }.distinct()
-
- for (packageName in allFqNames) {
- val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() }
-
- if (options.skipEmptyPackages && declarations.none { it.isDocumented() }) continue
- logger.info(" package $packageName: ${declarations.count()} declarations")
- val packageNode = findOrCreatePackageNode(packageName.asString(), packageContent)
- packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode, declarations)
- }
- }
-
- fun DeclarationDescriptor.build(): DocumentationNode = when (this) {
- is ClassDescriptor -> build()
- is ConstructorDescriptor -> build()
- is PropertyDescriptor -> build()
- is FunctionDescriptor -> build()
- is TypeParameterDescriptor -> build()
- is ValueParameterDescriptor -> build()
- is ReceiverParameterDescriptor -> build()
- else -> throw IllegalStateException("Descriptor $this is not known")
- }
-
- fun ClassDescriptor.build(): DocumentationNode {
- val kind = when (kind) {
- ClassKind.OBJECT -> Kind.Object
- ClassKind.INTERFACE -> Kind.Interface
- ClassKind.ENUM_CLASS -> Kind.Enum
- ClassKind.ANNOTATION_CLASS -> Kind.AnnotationClass
- ClassKind.ENUM_ENTRY -> Kind.EnumItem
- else -> Kind.Class
- }
- val node = nodeForDescriptor(this, kind)
- node.appendSupertypes(this)
- if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
- node.appendInPageChildren(typeConstructor.parameters, DocumentationReference.Kind.Detail)
- val constructorsToDocument = if (getKind() == ClassKind.ENUM_CLASS)
- constructors.filter { it.valueParameters.size > 0 }
- else
- constructors
- node.appendMembers(constructorsToDocument)
- }
- val members = defaultType.memberScope.getContributedDescriptors().filter { it != companionObjectDescriptor }
- node.appendMembers(members)
- node.appendMembers(staticScope.getContributedDescriptors()).forEach {
- it.appendTextNode("static", Kind.Modifier)
- }
- val companionObjectDescriptor = companionObjectDescriptor
- if (companionObjectDescriptor != null) {
- node.appendMembers(companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors())
- }
- node.appendAnnotations(this)
- node.appendModifiers(this)
- node.appendSourceLink(source)
- register(this, node)
- return node
- }
-
- fun ConstructorDescriptor.build(): DocumentationNode {
- val node = nodeForDescriptor(this, Kind.Constructor)
- node.appendInPageChildren(valueParameters, DocumentationReference.Kind.Detail)
- register(this, node)
- return node
- }
-
- private fun CallableMemberDescriptor.inCompanionObject(): Boolean {
- val containingDeclaration = containingDeclaration
- if ((containingDeclaration as? ClassDescriptor)?.isCompanionObject ?: false) {
- return true
- }
- val receiver = extensionReceiverParameter
- return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false
- }
-
- fun FunctionDescriptor.build(): DocumentationNode {
- if (ErrorUtils.containsErrorType(this)) {
- logger.warn("Found an unresolved type in ${signatureWithSourceLocation()}")
- }
-
- val node = nodeForDescriptor(this, if (inCompanionObject()) Kind.CompanionObjectFunction else Kind.Function)
-
- node.appendInPageChildren(typeParameters, DocumentationReference.Kind.Detail)
- extensionReceiverParameter?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
- node.appendInPageChildren(valueParameters, DocumentationReference.Kind.Detail)
- node.appendType(returnType)
- node.appendAnnotations(this)
- node.appendModifiers(this)
- node.appendSourceLink(source)
-
- overriddenDescriptors.forEach {
- addOverrideLink(it, this)
- }
-
- register(this, node)
- return node
- }
-
- fun addOverrideLink(baseClassFunction: CallableMemberDescriptor, overridingFunction: CallableMemberDescriptor) {
- val source = baseClassFunction.original.source.getPsi()
- if (source != null) {
- link(overridingFunction, baseClassFunction, DocumentationReference.Kind.Override)
- } else {
- baseClassFunction.overriddenDescriptors.forEach {
- addOverrideLink(it, overridingFunction)
- }
- }
- }
-
- fun PropertyDescriptor.build(): DocumentationNode {
- val node = nodeForDescriptor(this, if (inCompanionObject()) Kind.CompanionObjectProperty else Kind.Property)
- node.appendInPageChildren(typeParameters, DocumentationReference.Kind.Detail)
- extensionReceiverParameter?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
- node.appendType(returnType)
- node.appendAnnotations(this)
- node.appendModifiers(this)
- node.appendSourceLink(source)
- if (isVar) {
- node.appendTextNode("var", DocumentationNode.Kind.Modifier)
- }
- getter?.let {
- if (!it.isDefault) {
- node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Getter")
- }
- }
- setter?.let {
- if (!it.isDefault) {
- node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Setter")
- }
- }
-
- overriddenDescriptors.forEach {
- addOverrideLink(it, this)
- }
-
- register(this, node)
- return node
- }
-
- fun DocumentationNode.addAccessorDocumentation(documentation: Content, prefix: String) {
- if (documentation == Content.Empty) return
- updateContent {
- if (!documentation.children.isEmpty()) {
- val section = addSection(prefix, null)
- documentation.children.forEach { section.append(it) }
- }
- documentation.sections.forEach {
- val section = addSection("$prefix ${it.tag}", it.subjectName)
- it.children.forEach { section.append(it) }
- }
- }
- }
-
- fun ValueParameterDescriptor.build(): DocumentationNode {
- val node = nodeForDescriptor(this, Kind.Parameter)
- node.appendType(varargElementType ?: type)
- if (declaresDefaultValue()) {
- val psi = source.getPsi() as? KtParameter
- if (psi != null) {
- val defaultValueText = psi.defaultValue?.text
- if (defaultValueText != null) {
- node.appendTextNode(defaultValueText, Kind.Value)
- }
- }
- }
- node.appendAnnotations(this)
- node.appendModifiers(this)
- if (varargElementType != null && node.details(Kind.Modifier).none { it.name == "vararg" }) {
- node.appendTextNode("vararg", Kind.Modifier)
- }
- register(this, node)
- return node
- }
-
- fun TypeParameterDescriptor.build(): DocumentationNode {
- val doc = descriptorDocumentationParser.parseDocumentation(this)
- val name = name.asString()
- val prefix = variance.label
-
- val node = DocumentationNode(name, doc, DocumentationNode.Kind.TypeParameter)
- if (prefix != "") {
- node.appendTextNode(prefix, Kind.Modifier)
- }
- if (isReified) {
- node.appendTextNode("reified", Kind.Modifier)
- }
-
- for (constraint in upperBounds) {
- if (KotlinBuiltIns.isDefaultBound(constraint)) {
- continue
- }
- node.appendType(constraint, Kind.UpperBound)
- }
-
- for (constraint in lowerBounds) {
- if (KotlinBuiltIns.isNothing(constraint))
- continue
- node.appendType(constraint, Kind.LowerBound)
- }
- return node
- }
-
- fun ReceiverParameterDescriptor.build(): DocumentationNode {
- var receiverClass: DeclarationDescriptor = type.constructor.declarationDescriptor!!
- if ((receiverClass as? ClassDescriptor)?.isCompanionObject ?: false) {
- receiverClass = receiverClass.containingDeclaration!!
- }
- link(receiverClass,
- containingDeclaration,
- DocumentationReference.Kind.Extension)
-
- val node = DocumentationNode(name.asString(), Content.Empty, Kind.Receiver)
- node.appendType(type)
- return node
- }
-
- fun AnnotationDescriptor.build(): DocumentationNode? {
- val annotationClass = type.constructor.declarationDescriptor
- if (annotationClass == null || ErrorUtils.isError(annotationClass)) {
- return null
- }
- val node = DocumentationNode(annotationClass.name.asString(), Content.Empty, DocumentationNode.Kind.Annotation)
- val arguments = allValueArguments.toList().sortedBy { it.first.index }
- arguments.forEach {
- val valueNode = it.second.toDocumentationNode()
- if (valueNode != null) {
- val paramNode = DocumentationNode(it.first.name.asString(), Content.Empty, DocumentationNode.Kind.Parameter)
- paramNode.append(valueNode, DocumentationReference.Kind.Detail)
- node.append(paramNode, DocumentationReference.Kind.Detail)
- }
- }
- return node
- }
-
- fun CompileTimeConstant<Any?>.build(): DocumentationNode? = when (this) {
- is TypedCompileTimeConstant -> constantValue.toDocumentationNode()
- else -> null
- }
-
- fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value?.let { value ->
- when (value) {
- is String ->
- "\"" + StringUtil.escapeStringCharacters(value) + "\""
- is EnumEntrySyntheticClassDescriptor ->
- value.containingDeclaration.name.asString() + "." + value.name.asString()
- else -> value.toString()
- }.let { valueString ->
- DocumentationNode(valueString, Content.Empty, DocumentationNode.Kind.Value)
- }
- }
-}
-
-class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
- override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>) {
- val externalClassNodes = hashMapOf<FqName, DocumentationNode>()
- declarations.forEach { descriptor ->
- with(documentationBuilder) {
- if (descriptor.isDocumented()) {
- val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes)
- parent.appendChild(descriptor, DocumentationReference.Kind.Member)
- }
- }
- }
- }
-}
-
-class KotlinJavaDocumentationBuilder
- @Inject constructor(val documentationBuilder: DocumentationBuilder,
- val logger: DokkaLogger) : JavaDocumentationBuilder
-{
- override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
- val packageNode = module.findOrCreatePackageNode(file.packageName, packageContent)
-
- file.classes.forEach {
- val javaDescriptorResolver = KotlinCacheService.getInstance(file.project).getProjectService(JvmPlatform,
- it.getModuleInfo(), JavaDescriptorResolver::class.java)
-
- val descriptor = javaDescriptorResolver.resolveClass(JavaClassImpl(it))
- if (descriptor == null) {
- logger.warn("Cannot find descriptor for Java class ${it.qualifiedName}")
- }
- else {
- with(documentationBuilder) {
- packageNode.appendChild(descriptor, DocumentationReference.Kind.Member)
- }
- }
- }
- }
-}
-
-private fun AnnotationDescriptor.isDocumented(): Boolean {
- if (source.getPsi() != null && mustBeDocumented()) return true
- val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString()
- return annotationClassName == "kotlin.Extension"
-}
-
-fun AnnotationDescriptor.mustBeDocumented(): Boolean {
- val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false
- return annotationClass.isDocumentedAnnotation()
-}
-
-fun DeclarationDescriptor.isDocumentationSuppressed(): Boolean {
- val doc = KDocFinder.findKDoc(this)
- return doc is KDocSection && doc.findTagByName("suppress") != null
-}
-
-fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any {
- DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated"
-} || (this is ConstructorDescriptor && containingDeclaration.isDeprecated())
-
-fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor,
- externalClassNodes: MutableMap<FqName, DocumentationNode>): DocumentationNode {
- if (descriptor is CallableMemberDescriptor) {
- val extensionClassDescriptor = descriptor.getExtensionClassDescriptor()
- if (extensionClassDescriptor != null && !isSamePackage(descriptor, extensionClassDescriptor) &&
- !ErrorUtils.isError(extensionClassDescriptor)) {
- val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor)
- return externalClassNodes.getOrPut(fqName, {
- val newNode = DocumentationNode(fqName.asString(), Content.Empty, Kind.ExternalClass)
- append(newNode, DocumentationReference.Kind.Member)
- newNode
- })
- }
- }
- return this
-}
-
-fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor? {
- val extensionReceiver = extensionReceiverParameter
- if (extensionReceiver != null) {
- val type = extensionReceiver.type
- return type.constructor.declarationDescriptor as? ClassDescriptor
- }
- return null
-}
-
-fun DeclarationDescriptor.signature(): String = when(this) {
- is ClassDescriptor, is PackageFragmentDescriptor -> DescriptorUtils.getFqName(this).asString()
- is PropertyDescriptor -> containingDeclaration.signature() + "#" + name + receiverSignature()
- is FunctionDescriptor -> containingDeclaration.signature() + "#" + name + parameterSignature()
- is ValueParameterDescriptor -> containingDeclaration.signature() + ":" + name
- is TypeParameterDescriptor -> containingDeclaration.signature() + "<" + name
-
- else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
-}
-
-fun PropertyDescriptor.receiverSignature(): String {
- val receiver = extensionReceiverParameter
- if (receiver != null) {
- return "#" + receiver.type.signature()
- }
- return ""
-}
-
-fun CallableMemberDescriptor.parameterSignature(): String {
- val params = valueParameters.map { it.type }.toArrayList()
- val extensionReceiver = extensionReceiverParameter
- if (extensionReceiver != null) {
- params.add(0, extensionReceiver.type)
- }
- return "(" + params.map { it.signature() }.joinToString() + ")"
-}
-
-fun KotlinType.signature(): String {
- val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>"
- val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString()
- if (typeName == "Array" && arguments.size == 1) {
- return "Array<" + arguments.first().type.signature() + ">"
- }
- return typeName
-}
-
-fun DeclarationDescriptor.signatureWithSourceLocation(): String {
- val signature = signature()
- val sourceLocation = sourceLocation()
- return if (sourceLocation != null) "$signature ($sourceLocation)" else signature
-}
-
-fun DeclarationDescriptor.sourceLocation(): String? {
- if (this is DeclarationDescriptorWithSource) {
- val psi = (this.source as? PsiSourceElement)?.getPsi()
- if (psi != null) {
- val fileName = psi.containingFile.name
- val lineNumber = psi.lineNumber()
- return if (lineNumber != null) "$fileName:$lineNumber" else fileName
- }
- }
- return null
-}
diff --git a/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt
deleted file mode 100644
index 7a1d591c..00000000
--- a/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.psi.JavaPsiFacade
-import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiNamedElement
-import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser
-import org.jetbrains.kotlin.asJava.KtLightElement
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.lexer.KtTokens
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.KtDeclaration
-import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.psi.KtPropertyAccessor
-
-class KotlinAsJavaDocumentationBuilder
- @Inject constructor(val kotlinAsJavaDocumentationParser: KotlinAsJavaDocumentationParser) : PackageDocumentationBuilder
-{
- override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>) {
- val project = documentationBuilder.resolutionFacade.project
- val psiPackage = JavaPsiFacade.getInstance(project).findPackage(packageName.asString())
- if (psiPackage == null) {
- documentationBuilder.logger.error("Cannot find Java package by qualified name: ${packageName.asString()}")
- return
- }
-
- val javaDocumentationBuilder = JavaPsiDocumentationBuilder(documentationBuilder.options,
- documentationBuilder.refGraph,
- kotlinAsJavaDocumentationParser)
-
- psiPackage.classes.filter { it is KtLightElement<*, *> }.filter { it.isVisibleInDocumentation() }.forEach {
- javaDocumentationBuilder.appendClasses(packageNode, arrayOf(it))
- }
- }
-
- fun PsiClass.isVisibleInDocumentation() : Boolean {
- val origin: KtDeclaration? = (this as KtLightElement<*, *>).getOrigin()
- return origin?.hasModifier(KtTokens.INTERNAL_KEYWORD) != true &&
- origin?.hasModifier(KtTokens.PRIVATE_KEYWORD) != true
- }
-}
-
-class KotlinAsJavaDocumentationParser
- @Inject constructor(val resolutionFacade: DokkaResolutionFacade,
- val descriptorDocumentationParser: DescriptorDocumentationParser) : JavaDocumentationParser
-{
- override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
- val kotlinLightElement = element as? KtLightElement<*, *> ?: return JavadocParseResult.Empty
- val origin = kotlinLightElement.getOrigin() ?: return JavadocParseResult.Empty
- if (origin is KtParameter) {
- // LazyDeclarationResolver does not support setter parameters
- val grandFather = origin.parent?.parent
- if (grandFather is KtPropertyAccessor) {
- return JavadocParseResult.Empty
- }
- }
- val descriptor = resolutionFacade.resolveToDescriptor(origin)
- val content = descriptorDocumentationParser.parseDocumentation(descriptor, origin is KtParameter)
- return JavadocParseResult(content, null)
- }
-}
diff --git a/src/Kotlin/KotlinLanguageService.kt b/src/Kotlin/KotlinLanguageService.kt
deleted file mode 100644
index 0d39f410..00000000
--- a/src/Kotlin/KotlinLanguageService.kt
+++ /dev/null
@@ -1,409 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.LanguageService.RenderMode
-
-/**
- * Implements [LanguageService] and provides rendering of symbols in Kotlin language
- */
-class KotlinLanguageService : LanguageService {
- private val fullOnlyModifiers = setOf("public", "protected", "private", "inline", "noinline", "crossinline", "reified")
-
- override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
- return content {
- when (node.kind) {
- DocumentationNode.Kind.Package -> if (renderMode == RenderMode.FULL) renderPackage(node)
- in DocumentationNode.Kind.classLike -> renderClass(node, renderMode)
-
- DocumentationNode.Kind.EnumItem,
- DocumentationNode.Kind.ExternalClass -> if (renderMode == RenderMode.FULL) identifier(node.name)
-
- DocumentationNode.Kind.TypeParameter -> renderTypeParameter(node, renderMode)
- DocumentationNode.Kind.Type,
- DocumentationNode.Kind.UpperBound -> renderType(node, renderMode)
-
- DocumentationNode.Kind.Modifier -> renderModifier(node)
- DocumentationNode.Kind.Constructor,
- DocumentationNode.Kind.Function,
- DocumentationNode.Kind.CompanionObjectFunction -> renderFunction(node, renderMode)
- DocumentationNode.Kind.Property,
- DocumentationNode.Kind.CompanionObjectProperty -> renderProperty(node, renderMode)
- else -> identifier(node.name)
- }
- }
- }
-
- override fun renderName(node: DocumentationNode): String {
- return when (node.kind) {
- DocumentationNode.Kind.Constructor -> node.owner!!.name
- else -> node.name
- }
- }
-
- override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? {
- if (nodes.size < 2) return null
- val receiverKind = nodes.getReceiverKind() ?: return null
- val functionWithTypeParameter = nodes.firstOrNull { it.details(DocumentationNode.Kind.TypeParameter).any() } ?: return null
- return content {
- val typeParameter = functionWithTypeParameter.details(DocumentationNode.Kind.TypeParameter).first()
- if (functionWithTypeParameter.kind == DocumentationNode.Kind.Function) {
- renderFunction(functionWithTypeParameter, RenderMode.SUMMARY, SummarizingMapper(receiverKind, typeParameter.name))
- }
- else {
- renderProperty(functionWithTypeParameter, RenderMode.SUMMARY, SummarizingMapper(receiverKind, typeParameter.name))
- }
- }
- }
-
- private fun List<DocumentationNode>.getReceiverKind(): ReceiverKind? {
- val qNames = map { it.getReceiverQName() }.filterNotNull()
- if (qNames.size != size)
- return null
-
- return ReceiverKind.values.firstOrNull { kind -> qNames.all { it in kind.classes } }
- }
-
- private fun DocumentationNode.getReceiverQName(): String? {
- if (kind != DocumentationNode.Kind.Function && kind != DocumentationNode.Kind.Property) return null
- val receiver = details(DocumentationNode.Kind.Receiver).singleOrNull() ?: return null
- return receiver.detail(DocumentationNode.Kind.Type).qualifiedNameFromType()
- }
-
- companion object {
- private val arrayClasses = setOf(
- "kotlin.Array",
- "kotlin.BooleanArray",
- "kotlin.ByteArray",
- "kotlin.CharArray",
- "kotlin.ShortArray",
- "kotlin.IntArray",
- "kotlin.LongArray",
- "kotlin.FloatArray",
- "kotlin.DoubleArray"
- )
-
- private val arrayOrListClasses = setOf("kotlin.List") + arrayClasses
-
- private val iterableClasses = setOf(
- "kotlin.Collection",
- "kotlin.Sequence",
- "kotlin.Iterable",
- "kotlin.Map",
- "kotlin.String",
- "kotlin.CharSequence") + arrayOrListClasses
- }
-
- private enum class ReceiverKind(val receiverName: String, val classes: Collection<String>) {
- ARRAY("any_array", arrayClasses),
- ARRAY_OR_LIST("any_array_or_list", arrayOrListClasses),
- ITERABLE("any_iterable", iterableClasses),
- }
-
- interface SignatureMapper {
- fun renderReceiver(receiver: DocumentationNode, to: ContentBlock)
- }
-
- private class SummarizingMapper(val kind: ReceiverKind, val typeParameterName: String): SignatureMapper {
- override fun renderReceiver(receiver: DocumentationNode, to: ContentBlock) {
- to.append(ContentIdentifier(kind.receiverName, IdentifierKind.SummarizedTypeName))
- to.text("<$typeParameterName>")
- }
- }
-
- private fun ContentBlock.renderPackage(node: DocumentationNode) {
- keyword("package")
- text(" ")
- identifier(node.name)
- }
-
- private fun ContentBlock.renderList(nodes: List<DocumentationNode>, separator: String = ", ",
- noWrap: Boolean = false, renderItem: (DocumentationNode) -> Unit) {
- if (nodes.none())
- return
- renderItem(nodes.first())
- nodes.drop(1).forEach {
- if (noWrap) {
- symbol(separator.removeSuffix(" "))
- nbsp()
- } else {
- symbol(separator)
- }
- renderItem(it)
- }
- }
-
- private fun ContentBlock.renderLinked(node: DocumentationNode, body: ContentBlock.(DocumentationNode)->Unit) {
- val to = node.links.firstOrNull()
- if (to == null)
- body(node)
- else
- link(to) {
- body(node)
- }
- }
-
- private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) {
- var typeArguments = node.details(DocumentationNode.Kind.Type)
- if (node.name == "Function${typeArguments.count() - 1}") {
- // lambda
- val isExtension = node.annotations.any { it.name == "Extension" }
- if (isExtension) {
- renderType(typeArguments.first(), renderMode)
- symbol(".")
- typeArguments = typeArguments.drop(1)
- }
- symbol("(")
- renderList(typeArguments.take(typeArguments.size - 1), noWrap = true) {
- renderType(it, renderMode)
- }
- symbol(")")
- nbsp()
- symbol("->")
- nbsp()
- renderType(typeArguments.last(), renderMode)
- return
- }
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode, true)
- renderLinked(node) { identifier(it.name, IdentifierKind.TypeName) }
- if (typeArguments.any()) {
- symbol("<")
- renderList(typeArguments, noWrap = true) {
- renderType(it, renderMode)
- }
- symbol(">")
- }
- val nullabilityModifier = node.details(DocumentationNode.Kind.NullabilityModifier).singleOrNull()
- if (nullabilityModifier != null) {
- symbol(nullabilityModifier.name)
- }
- }
-
- private fun ContentBlock.renderModifier(node: DocumentationNode, nowrap: Boolean = false) {
- when (node.name) {
- "final", "public", "var" -> {}
- else -> {
- keyword(node.name)
- if (nowrap) {
- nbsp()
- }
- else {
- text(" ")
- }
- }
- }
- }
-
- private fun ContentBlock.renderTypeParameter(node: DocumentationNode, renderMode: RenderMode) {
- renderModifiersForNode(node, renderMode, true)
-
- identifier(node.name)
-
- val constraints = node.details(DocumentationNode.Kind.UpperBound)
- if (constraints.any()) {
- nbsp()
- symbol(":")
- nbsp()
- renderList(constraints, noWrap=true) {
- renderType(it, renderMode)
- }
- }
- }
- private fun ContentBlock.renderParameter(node: DocumentationNode, renderMode: RenderMode) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- identifier(node.name, IdentifierKind.ParameterName)
- symbol(":")
- nbsp()
- val parameterType = node.detail(DocumentationNode.Kind.Type)
- renderType(parameterType, renderMode)
- val valueNode = node.details(DocumentationNode.Kind.Value).firstOrNull()
- if (valueNode != null) {
- nbsp()
- symbol("=")
- nbsp()
- text(valueNode.name)
- }
- }
-
- private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode, renderMode: RenderMode) {
- val typeParameters = node.details(DocumentationNode.Kind.TypeParameter)
- if (typeParameters.any()) {
- symbol("<")
- renderList(typeParameters) {
- renderTypeParameter(it, renderMode)
- }
- symbol(">")
- }
- }
-
- private fun ContentBlock.renderSupertypesForNode(node: DocumentationNode, renderMode: RenderMode) {
- val supertypes = node.details(DocumentationNode.Kind.Supertype)
- if (supertypes.any()) {
- nbsp()
- symbol(":")
- nbsp()
- renderList(supertypes) {
- indentedSoftLineBreak()
- renderType(it, renderMode)
- }
- }
- }
-
- private fun ContentBlock.renderModifiersForNode(node: DocumentationNode,
- renderMode: RenderMode,
- nowrap: Boolean = false) {
- val modifiers = node.details(DocumentationNode.Kind.Modifier)
- for (it in modifiers) {
- if (node.kind == org.jetbrains.dokka.DocumentationNode.Kind.Interface && it.name == "abstract")
- continue
- if (renderMode == RenderMode.SUMMARY && it.name in fullOnlyModifiers) {
- continue
- }
- renderModifier(it, nowrap)
- }
- }
-
- private fun ContentBlock.renderAnnotationsForNode(node: DocumentationNode) {
- node.annotations.forEach {
- renderAnnotation(it)
- }
- }
-
- private fun ContentBlock.renderAnnotation(node: DocumentationNode) {
- identifier("@" + node.name, IdentifierKind.AnnotationName)
- val parameters = node.details(DocumentationNode.Kind.Parameter)
- if (!parameters.isEmpty()) {
- symbol("(")
- renderList(parameters) {
- text(it.detail(DocumentationNode.Kind.Value).name)
- }
- symbol(")")
- }
- text(" ")
- }
-
- private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- DocumentationNode.Kind.Class,
- DocumentationNode.Kind.AnnotationClass,
- DocumentationNode.Kind.Enum -> keyword("class ")
- DocumentationNode.Kind.Interface -> keyword("interface ")
- DocumentationNode.Kind.EnumItem -> keyword("enum val ")
- DocumentationNode.Kind.Object -> keyword("object ")
- else -> throw IllegalArgumentException("Node $node is not a class-like object")
- }
-
- identifierOrDeprecated(node)
- renderTypeParametersForNode(node, renderMode)
- renderSupertypesForNode(node, renderMode)
- }
-
- private fun ContentBlock.renderFunction(node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- DocumentationNode.Kind.Constructor -> identifier(node.owner!!.name)
- DocumentationNode.Kind.Function,
- DocumentationNode.Kind.CompanionObjectFunction -> keyword("fun ")
- else -> throw IllegalArgumentException("Node $node is not a function-like object")
- }
- renderTypeParametersForNode(node, renderMode)
- if (node.details(DocumentationNode.Kind.TypeParameter).any()) {
- text(" ")
- }
-
- renderReceiver(node, renderMode, signatureMapper)
-
- if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor)
- identifierOrDeprecated(node)
-
- symbol("(")
- val parameters = node.details(DocumentationNode.Kind.Parameter)
- renderList(parameters) {
- indentedSoftLineBreak()
- renderParameter(it, renderMode)
- }
- if (needReturnType(node)) {
- if (parameters.isNotEmpty()) {
- softLineBreak()
- }
- symbol(")")
- symbol(": ")
- renderType(node.detail(DocumentationNode.Kind.Type), renderMode)
- }
- else {
- symbol(")")
- }
- }
-
- private fun ContentBlock.renderReceiver(node: DocumentationNode, renderMode: RenderMode, signatureMapper: SignatureMapper?) {
- val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull()
- if (receiver != null) {
- if (signatureMapper != null) {
- signatureMapper.renderReceiver(receiver, this)
- } else {
- renderType(receiver.detail(DocumentationNode.Kind.Type), renderMode)
- }
- symbol(".")
- }
- }
-
- private fun needReturnType(node: DocumentationNode) = when(node.kind) {
- DocumentationNode.Kind.Constructor -> false
- else -> !node.isUnitReturnType()
- }
-
- fun DocumentationNode.isUnitReturnType(): Boolean =
- detail(DocumentationNode.Kind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit"
-
- private fun ContentBlock.renderProperty(node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- DocumentationNode.Kind.Property,
- DocumentationNode.Kind.CompanionObjectProperty -> keyword("${node.getPropertyKeyword()} ")
- else -> throw IllegalArgumentException("Node $node is not a property")
- }
- renderTypeParametersForNode(node, renderMode)
- if (node.details(DocumentationNode.Kind.TypeParameter).any()) {
- text(" ")
- }
-
- renderReceiver(node, renderMode, signatureMapper)
-
- identifierOrDeprecated(node)
- symbol(": ")
- renderType(node.detail(DocumentationNode.Kind.Type), renderMode)
- }
-
- fun DocumentationNode.getPropertyKeyword() =
- if (details(DocumentationNode.Kind.Modifier).any { it.name == "var" }) "var" else "val"
-
- fun ContentBlock.identifierOrDeprecated(node: DocumentationNode) {
- if (node.deprecation != null) {
- val strike = ContentStrikethrough()
- strike.identifier(node.name)
- append(strike)
- } else {
- identifier(node.name)
- }
- }
-}
-
-fun DocumentationNode.qualifiedNameFromType() = (links.firstOrNull() ?: hiddenLinks.firstOrNull())?.qualifiedName() ?: name
diff --git a/src/Languages/JavaLanguageService.kt b/src/Languages/JavaLanguageService.kt
deleted file mode 100644
index 7e40beff..00000000
--- a/src/Languages/JavaLanguageService.kt
+++ /dev/null
@@ -1,162 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.DocumentationNode.Kind
-import org.jetbrains.dokka.LanguageService.RenderMode
-
-/**
- * Implements [LanguageService] and provides rendering of symbols in Java language
- */
-public class JavaLanguageService : LanguageService {
- override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
- return ContentText(when (node.kind) {
- Kind.Package -> renderPackage(node)
- in Kind.classLike -> renderClass(node)
-
- Kind.TypeParameter -> renderTypeParameter(node)
- Kind.Type,
- Kind.UpperBound -> renderType(node)
-
- Kind.Constructor,
- Kind.Function -> renderFunction(node)
- Kind.Property -> renderProperty(node)
- else -> "${node.kind}: ${node.name}"
- })
- }
-
- override fun renderName(node: DocumentationNode): String {
- return when (node.kind) {
- Kind.Constructor -> node.owner!!.name
- else -> node.name
- }
- }
-
- override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? = null
-
- private fun renderPackage(node: DocumentationNode): String {
- return "package ${node.name}"
- }
-
- private fun renderModifier(node: DocumentationNode): String {
- return when (node.name) {
- "open" -> ""
- "internal" -> ""
- else -> node.name
- }
- }
-
- public fun getArrayElementType(node: DocumentationNode): DocumentationNode? = when (node.name) {
- "Array" -> node.details(Kind.Type).singleOrNull()?.let { et -> getArrayElementType(et) ?: et } ?: DocumentationNode("Object", node.content, DocumentationNode.Kind.ExternalClass)
- "IntArray", "LongArray", "ShortArray", "ByteArray", "CharArray", "DoubleArray", "FloatArray", "BooleanArray" -> DocumentationNode(node.name.removeSuffix("Array").toLowerCase(), node.content, DocumentationNode.Kind.Type)
- else -> null
- }
-
- public fun getArrayDimension(node: DocumentationNode): Int = when (node.name) {
- "Array" -> 1 + (node.details(DocumentationNode.Kind.Type).singleOrNull()?.let { getArrayDimension(it) } ?: 0)
- "IntArray", "LongArray", "ShortArray", "ByteArray", "CharArray", "DoubleArray", "FloatArray", "BooleanArray" -> 1
- else -> 0
- }
-
- public fun renderType(node: DocumentationNode): String {
- return when (node.name) {
- "Unit" -> "void"
- "Int" -> "int"
- "Long" -> "long"
- "Double" -> "double"
- "Float" -> "float"
- "Char" -> "char"
- "Boolean" -> "bool"
- // TODO: render arrays
- else -> node.name
- }
- }
-
- private fun renderTypeParameter(node: DocumentationNode): String {
- val constraints = node.details(Kind.UpperBound)
- return if (constraints.none())
- node.name
- else {
- node.name + " extends " + constraints.map { renderType(node) }.joinToString()
- }
- }
-
- private fun renderParameter(node: DocumentationNode): String {
- return "${renderType(node.detail(Kind.Type))} ${node.name}"
- }
-
- private fun renderTypeParametersForNode(node: DocumentationNode): String {
- return StringBuilder().apply {
- val typeParameters = node.details(Kind.TypeParameter)
- if (typeParameters.any()) {
- append("<")
- append(typeParameters.map { renderTypeParameter(it) }.joinToString())
- append("> ")
- }
- }.toString()
- }
-
- private fun renderModifiersForNode(node: DocumentationNode): String {
- val modifiers = node.details(Kind.Modifier).map { renderModifier(it) }.filter { it != "" }
- if (modifiers.none())
- return ""
- return modifiers.joinToString(" ", postfix = " ")
- }
-
- private fun renderClass(node: DocumentationNode): String {
- return StringBuilder().apply {
- when (node.kind) {
- Kind.Class -> append("class ")
- Kind.Interface -> append("interface ")
- Kind.Enum -> append("enum ")
- Kind.EnumItem -> append("enum value ")
- Kind.Object -> append("class ")
- else -> throw IllegalArgumentException("Node $node is not a class-like object")
- }
-
- append(node.name)
- append(renderTypeParametersForNode(node))
- }.toString()
- }
-
- private fun renderFunction(node: DocumentationNode): String {
- return StringBuilder().apply {
- when (node.kind) {
- Kind.Constructor -> append(node.owner?.name)
- Kind.Function -> {
- append(renderTypeParametersForNode(node))
- append(renderType(node.detail(Kind.Type)))
- append(" ")
- append(node.name)
- }
- else -> throw IllegalArgumentException("Node $node is not a function-like object")
- }
-
- val receiver = node.details(Kind.Receiver).singleOrNull()
- append("(")
- if (receiver != null)
- (listOf(receiver) + node.details(Kind.Parameter)).map { renderParameter(it) }.joinTo(this)
- else
- node.details(Kind.Parameter).map { renderParameter(it) }.joinTo(this)
-
- append(")")
- }.toString()
- }
-
- private fun renderProperty(node: DocumentationNode): String {
- return StringBuilder().apply {
- when (node.kind) {
- Kind.Property -> append("val ")
- else -> throw IllegalArgumentException("Node $node is not a property")
- }
- append(renderTypeParametersForNode(node))
- val receiver = node.details(Kind.Receiver).singleOrNull()
- if (receiver != null) {
- append(renderType(receiver.detail(Kind.Type)))
- append(".")
- }
-
- append(node.name)
- append(": ")
- append(renderType(node.detail(Kind.Type)))
- }.toString()
- }
-} \ No newline at end of file
diff --git a/src/Languages/LanguageService.kt b/src/Languages/LanguageService.kt
deleted file mode 100644
index b0f4bbc9..00000000
--- a/src/Languages/LanguageService.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.jetbrains.dokka
-
-/**
- * Provides facility for rendering [DocumentationNode] as a language-dependent declaration
- */
-interface LanguageService {
- enum class RenderMode {
- /** Brief signature (used in a list of all members of the class). */
- SUMMARY,
- /** Full signature (used in the page describing the member itself */
- FULL
- }
-
- /**
- * Renders a [node] as a class, function, property or other signature in a target language.
- * @param node A [DocumentationNode] to render
- * @return [ContentNode] which is a root for a rich content tree suitable for formatting with [FormatService]
- */
- fun render(node: DocumentationNode, renderMode: RenderMode = RenderMode.FULL): ContentNode
-
- /**
- * Tries to summarize the signatures of the specified documentation nodes in a compact representation.
- * Returns the representation if successful, or null if the signatures could not be summarized.
- */
- fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode?
-
- /**
- * Renders [node] as a named representation in the target language
- *
- * For example:
- * ${code org.jetbrains.dokka.example}
- *
- * $node: A [DocumentationNode] to render
- * $returns: [String] which is a string representation of the node's name
- */
- fun renderName(node: DocumentationNode): String
-}
-
-fun example(service: LanguageService, node: DocumentationNode) {
- println("Node name: ${service.renderName(node)}")
-} \ No newline at end of file
diff --git a/src/Locations/FoldersLocationService.kt b/src/Locations/FoldersLocationService.kt
deleted file mode 100644
index 89b34ed1..00000000
--- a/src/Locations/FoldersLocationService.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import java.io.File
-
-public fun FoldersLocationService(root: String): FoldersLocationService = FoldersLocationService(File(root), "")
-public class FoldersLocationService @Inject constructor(@Named("outputDir") val rootFile: File, val extension: String) : FileLocationService {
- override val root: Location
- get() = FileLocation(rootFile)
-
- override fun withExtension(newExtension: String): FileLocationService {
- return if (extension.isEmpty()) FoldersLocationService(rootFile, newExtension) else this
- }
-
- override fun location(qualifiedName: List<String>, hasMembers: Boolean): FileLocation {
- return FileLocation(File(rootFile, relativePathToNode(qualifiedName, hasMembers)).appendExtension(extension))
- }
-}
-
-fun relativePathToNode(qualifiedName: List<String>, hasMembers: Boolean): String {
- val parts = qualifiedName.map { identifierToFilename(it) }.filterNot { it.isEmpty() }
- return if (!hasMembers) {
- // leaf node, use file in owner's folder
- parts.joinToString("/")
- } else {
- parts.joinToString("/") + (if (parts.none()) "" else "/") + "index"
- }
-}
diff --git a/src/Locations/LocationService.kt b/src/Locations/LocationService.kt
deleted file mode 100644
index 80bc0236..00000000
--- a/src/Locations/LocationService.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.jetbrains.dokka
-
-import java.io.File
-
-public interface Location {
- val path: String get
- fun relativePathTo(other: Location, anchor: String? = null): String
-}
-
-/**
- * Represents locations in the documentation in the form of [path](File).
- *
- * Locations are provided by [LocationService.location] function.
- *
- * $file: [File] for this location
- * $path: [String] representing path of this location
- */
-public data class FileLocation(val file: File): Location {
- override val path : String
- get() = file.path
-
- override fun relativePathTo(other: Location, anchor: String?): String {
- if (other !is FileLocation) {
- throw IllegalArgumentException("$other is not a FileLocation")
- }
- if (file.path.substringBeforeLast(".") == other.file.path.substringBeforeLast(".") && anchor == null) {
- return "."
- }
- val ownerFolder = file.parentFile!!
- val relativePath = ownerFolder.toPath().relativize(other.file.toPath()).toString()
- return if (anchor == null) relativePath else relativePath + "#" + anchor
- }
-}
-
-/**
- * Provides means of retrieving locations for [DocumentationNode](documentation nodes)
- *
- * `LocationService` determines where documentation for particular node should be generated
- *
- * * [FoldersLocationService] – represent packages and types as folders, members as files in those folders.
- * * [SingleFolderLocationService] – all documentation is generated into single folder using fully qualified names
- * for file names.
- */
-public interface LocationService {
- fun withExtension(newExtension: String) = this
-
- fun location(node: DocumentationNode): Location = location(node.path.map { it.name }, node.members.any())
-
- /**
- * Calculates a location corresponding to the specified [qualifiedName].
- * @param hasMembers if true, the node for which the location is calculated has member nodes.
- */
- fun location(qualifiedName: List<String>, hasMembers: Boolean): Location
-
- val root: Location
-}
-
-
-public interface FileLocationService: LocationService {
- override fun withExtension(newExtension: String): FileLocationService = this
-
- override fun location(node: DocumentationNode): FileLocation = location(node.path.map { it.name }, node.members.any())
- override fun location(qualifiedName: List<String>, hasMembers: Boolean): FileLocation
-}
-
-
-public fun identifierToFilename(path: String): String {
- val escaped = path.replace('<', '-').replace('>', '-')
- val lowercase = escaped.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() }
- return if (lowercase == "index") "--index--" else lowercase
-}
-
-/**
- * Returns relative location between two nodes. Used for relative links in documentation.
- */
-fun LocationService.relativePathToLocation(owner: DocumentationNode, node: DocumentationNode): String {
- return location(owner).relativePathTo(location(node), null)
-}
diff --git a/src/Locations/SingleFolderLocationService.kt b/src/Locations/SingleFolderLocationService.kt
deleted file mode 100644
index e313ac28..00000000
--- a/src/Locations/SingleFolderLocationService.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.name.Named
-import java.io.File
-
-public fun SingleFolderLocationService(root: String): SingleFolderLocationService = SingleFolderLocationService(File(root), "")
-public class SingleFolderLocationService @Inject constructor(@Named("outputDir") val rootFile: File, val extension: String) : FileLocationService {
- override fun withExtension(newExtension: String): FileLocationService =
- SingleFolderLocationService(rootFile, newExtension)
-
- override fun location(qualifiedName: List<String>, hasMembers: Boolean): FileLocation {
- val filename = qualifiedName.map { identifierToFilename(it) }.joinToString("-")
- return FileLocation(File(rootFile, filename).appendExtension(extension))
- }
-
- override val root: Location
- get() = FileLocation(rootFile)
-} \ No newline at end of file
diff --git a/src/Markdown/MarkdownProcessor.kt b/src/Markdown/MarkdownProcessor.kt
deleted file mode 100644
index 99caddc4..00000000
--- a/src/Markdown/MarkdownProcessor.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.jetbrains.dokka
-
-import org.intellij.markdown.IElementType
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.ast.ASTNode
-import org.intellij.markdown.ast.LeafASTNode
-import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
-import org.intellij.markdown.parser.MarkdownParser
-
-class MarkdownNode(val node: ASTNode, val parent: MarkdownNode?, val markdown: String) {
- val children: List<MarkdownNode> = node.children.map { MarkdownNode(it, this, markdown) }
- val type: IElementType get() = node.type
- val text: String get() = markdown.substring(node.startOffset, node.endOffset)
- fun child(type: IElementType): MarkdownNode? = children.firstOrNull { it.type == type }
-
- override fun toString(): String = StringBuilder().apply { presentTo(this) }.toString()
-}
-
-fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) {
- action(this) {
- for (child in children) {
- child.visit(action)
- }
- }
-}
-
-public fun MarkdownNode.toTestString(): String {
- val sb = StringBuilder()
- var level = 0
- visit { node, visitChildren ->
- sb.append(" ".repeat(level * 2))
- node.presentTo(sb)
- level++
- visitChildren()
- level--
- }
- return sb.toString()
-}
-
-private fun MarkdownNode.presentTo(sb: StringBuilder) {
- sb.append(type.toString())
- sb.append(":" + text.replace("\n", "\u23CE"))
- sb.appendln()
-}
-
-fun parseMarkdown(markdown: String): MarkdownNode {
- if (markdown.isEmpty())
- return MarkdownNode(LeafASTNode(MarkdownElementTypes.MARKDOWN_FILE, 0, 0), null, markdown)
- return MarkdownNode(MarkdownParser(CommonMarkFlavourDescriptor()).buildMarkdownTreeFromString(markdown), null, markdown)
-}
diff --git a/src/Model/Content.kt b/src/Model/Content.kt
deleted file mode 100644
index 6556b09e..00000000
--- a/src/Model/Content.kt
+++ /dev/null
@@ -1,231 +0,0 @@
-package org.jetbrains.dokka
-
-public interface ContentNode {
- val textLength: Int
-}
-
-public object ContentEmpty : ContentNode {
- override val textLength: Int get() = 0
-}
-
-public open class ContentBlock() : ContentNode {
- val children = arrayListOf<ContentNode>()
-
- fun append(node: ContentNode) {
- children.add(node)
- }
-
- fun isEmpty() = children.isEmpty()
-
- override fun equals(other: Any?): Boolean =
- other is ContentBlock && javaClass == other.javaClass && children == other.children
-
- override fun hashCode(): Int =
- children.hashCode()
-
- override val textLength: Int
- get() = children.sumBy { it.textLength }
-}
-
-enum class IdentifierKind {
- TypeName,
- ParameterName,
- AnnotationName,
- SummarizedTypeName,
- Other
-}
-
-public data class ContentText(val text: String) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-public data class ContentKeyword(val text: String) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-public data class ContentIdentifier(val text: String, val kind: IdentifierKind = IdentifierKind.Other) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-public data class ContentSymbol(val text: String) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-public data class ContentEntity(val text: String) : ContentNode {
- override val textLength: Int
- get() = text.length
-}
-
-public object ContentNonBreakingSpace: ContentNode {
- override val textLength: Int
- get() = 1
-}
-
-public object ContentSoftLineBreak: ContentNode {
- override val textLength: Int
- get() = 0
-}
-
-public object ContentIndentedSoftLineBreak: ContentNode {
- override val textLength: Int
- get() = 0
-}
-
-public class ContentParagraph() : ContentBlock()
-public class ContentEmphasis() : ContentBlock()
-public class ContentStrong() : ContentBlock()
-public class ContentStrikethrough() : ContentBlock()
-public class ContentCode() : ContentBlock()
-public class ContentBlockCode(val language: String = "") : ContentBlock()
-
-public abstract class ContentNodeLink() : ContentBlock() {
- abstract val node: DocumentationNode?
-}
-
-public class ContentNodeDirectLink(override val node: DocumentationNode): ContentNodeLink() {
- override fun equals(other: Any?): Boolean =
- super.equals(other) && other is ContentNodeDirectLink && node.name == other.node.name
-
- override fun hashCode(): Int =
- children.hashCode() * 31 + node.name.hashCode()
-}
-
-public class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> DocumentationNode?): ContentNodeLink() {
- override val node: DocumentationNode? get() = lazyNode()
-
- override fun equals(other: Any?): Boolean =
- super.equals(other) && other is ContentNodeLazyLink && linkText == other.linkText
-
- override fun hashCode(): Int =
- children.hashCode() * 31 + linkText.hashCode()
-}
-
-public class ContentExternalLink(val href : String) : ContentBlock() {
- override fun equals(other: Any?): Boolean =
- super.equals(other) && other is ContentExternalLink && href == other.href
-
- override fun hashCode(): Int =
- children.hashCode() * 31 + href.hashCode()
-}
-
-public class ContentUnorderedList() : ContentBlock()
-public class ContentOrderedList() : ContentBlock()
-public class ContentListItem() : ContentBlock()
-
-public class ContentHeading(val level: Int) : ContentBlock()
-
-public class ContentSection(public val tag: String, public val subjectName: String?) : ContentBlock() {
- override fun equals(other: Any?): Boolean =
- super.equals(other) && other is ContentSection && tag == other.tag && subjectName == other.subjectName
-
- override fun hashCode(): Int =
- children.hashCode() * 31 * 31 + tag.hashCode() * 31 + (subjectName?.hashCode() ?: 0)
-}
-
-public object ContentTags {
- val Description = "Description"
- val SeeAlso = "See Also"
-}
-
-fun content(body: ContentBlock.() -> Unit): ContentBlock {
- val block = ContentBlock()
- block.body()
- return block
-}
-
-fun ContentBlock.text(value: String) = append(ContentText(value))
-fun ContentBlock.keyword(value: String) = append(ContentKeyword(value))
-fun ContentBlock.symbol(value: String) = append(ContentSymbol(value))
-fun ContentBlock.identifier(value: String, kind: IdentifierKind = IdentifierKind.Other) = append(ContentIdentifier(value, kind))
-fun ContentBlock.nbsp() = append(ContentNonBreakingSpace)
-fun ContentBlock.softLineBreak() = append(ContentSoftLineBreak)
-fun ContentBlock.indentedSoftLineBreak() = append(ContentIndentedSoftLineBreak)
-
-fun ContentBlock.strong(body: ContentBlock.() -> Unit) {
- val strong = ContentStrong()
- strong.body()
- append(strong)
-}
-
-fun ContentBlock.code(body: ContentBlock.() -> Unit) {
- val code = ContentCode()
- code.body()
- append(code)
-}
-
-fun ContentBlock.link(to: DocumentationNode, body: ContentBlock.() -> Unit) {
- val block = ContentNodeDirectLink(to)
- block.body()
- append(block)
-}
-
-public open class Content(): ContentBlock() {
- public open val sections: List<ContentSection> get() = emptyList()
- public open val summary: ContentNode get() = ContentEmpty
- public open val description: ContentNode get() = ContentEmpty
-
- fun findSectionByTag(tag: String): ContentSection? =
- sections.firstOrNull { tag.equals(it.tag, ignoreCase = true) }
-
- companion object {
- val Empty = Content()
-
- fun of(vararg child: ContentNode): Content {
- val result = MutableContent()
- child.forEach { result.append(it) }
- return result
- }
- }
-}
-
-public open class MutableContent() : Content() {
- private val sectionList = arrayListOf<ContentSection>()
- public override val sections: List<ContentSection>
- get() = sectionList
-
- fun addSection(tag: String?, subjectName: String?): ContentSection {
- val section = ContentSection(tag ?: "", subjectName)
- sectionList.add(section)
- return section
- }
-
- public override val summary: ContentNode get() = children.firstOrNull() ?: ContentEmpty
-
- public override val description: ContentNode by lazy {
- val descriptionNodes = children.drop(1)
- if (descriptionNodes.isEmpty()) {
- ContentEmpty
- } else {
- val result = ContentSection(ContentTags.Description, null)
- result.children.addAll(descriptionNodes)
- result
- }
- }
-
- override fun equals(other: Any?): Boolean {
- if (other !is Content)
- return false
- return sections == other.sections && children == other.children
- }
-
- override fun hashCode(): Int {
- return sections.map { it.hashCode() }.sum()
- }
-
- override fun toString(): String {
- if (sections.isEmpty())
- return "<empty>"
- return (listOf(summary, description) + sections).joinToString()
- }
-}
-
-fun javadocSectionDisplayName(sectionName: String?): String? =
- when(sectionName) {
- "param" -> "Parameters"
- "throws", "exception" -> "Exceptions"
- else -> sectionName?.capitalize()
- }
diff --git a/src/Model/DocumentationNode.kt b/src/Model/DocumentationNode.kt
deleted file mode 100644
index 52881f65..00000000
--- a/src/Model/DocumentationNode.kt
+++ /dev/null
@@ -1,162 +0,0 @@
-package org.jetbrains.dokka
-
-import java.util.*
-
-public open class DocumentationNode(val name: String,
- content: Content,
- val kind: DocumentationNode.Kind) {
-
- private val references = LinkedHashSet<DocumentationReference>()
-
- var content: Content = content
- private set
-
- public val summary: ContentNode get() = content.summary
-
- public val owner: DocumentationNode?
- get() = references(DocumentationReference.Kind.Owner).singleOrNull()?.to
- public val details: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.Detail).map { it.to }
- public val members: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.Member).map { it.to }
- public val inheritedMembers: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.InheritedMember).map { it.to }
- public val extensions: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.Extension).map { it.to }
- public val inheritors: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.Inheritor).map { it.to }
- public val overrides: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.Override).map { it.to }
- public val links: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.Link).map { it.to }
- public val hiddenLinks: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.HiddenLink).map { it.to }
- public val annotations: List<DocumentationNode>
- get() = references(DocumentationReference.Kind.Annotation).map { it.to }
- public val deprecation: DocumentationNode?
- get() = references(DocumentationReference.Kind.Deprecation).singleOrNull()?.to
-
- // TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice
- public fun addReferenceTo(to: DocumentationNode, kind: DocumentationReference.Kind) {
- references.add(DocumentationReference(this, to, kind))
- }
-
- public fun addAllReferencesFrom(other: DocumentationNode) {
- references.addAll(other.references)
- }
-
- public fun updateContent(body: MutableContent.() -> Unit) {
- if (content !is MutableContent) {
- content = MutableContent()
- }
- (content as MutableContent).body()
- }
-
- public fun details(kind: DocumentationNode.Kind): List<DocumentationNode> = details.filter { it.kind == kind }
- public fun members(kind: DocumentationNode.Kind): List<DocumentationNode> = members.filter { it.kind == kind }
- public fun inheritedMembers(kind: DocumentationNode.Kind): List<DocumentationNode> = inheritedMembers.filter { it.kind == kind }
- public fun links(kind: DocumentationNode.Kind): List<DocumentationNode> = links.filter { it.kind == kind }
-
- public fun detail(kind: DocumentationNode.Kind): DocumentationNode = details.filter { it.kind == kind }.single()
- public fun member(kind: DocumentationNode.Kind): DocumentationNode = members.filter { it.kind == kind }.single()
- public fun link(kind: DocumentationNode.Kind): DocumentationNode = links.filter { it.kind == kind }.single()
-
- public fun references(kind: DocumentationReference.Kind): List<DocumentationReference> = references.filter { it.kind == kind }
- public fun allReferences(): Set<DocumentationReference> = references
-
- public override fun toString(): String {
- return "$kind:$name"
- }
-
- public enum class Kind {
- Unknown,
-
- Package,
- Class,
- Interface,
- Enum,
- AnnotationClass,
- EnumItem,
- Object,
-
- Constructor,
- Function,
- Property,
- Field,
-
- CompanionObjectProperty,
- CompanionObjectFunction,
-
- Parameter,
- Receiver,
- TypeParameter,
- Type,
- Supertype,
- UpperBound,
- LowerBound,
- Exception,
-
- Modifier,
- NullabilityModifier,
-
- Module,
-
- ExternalClass,
- Annotation,
-
- Value,
-
- SourceUrl,
- SourcePosition,
-
- /**
- * A note which is rendered once on a page documenting a group of overloaded functions.
- * Needs to be generated equally on all overloads.
- */
- OverloadGroupNote;
-
- companion object {
- val classLike = setOf(Class, Interface, Enum, AnnotationClass, Object)
- }
- }
-}
-
-public class DocumentationModule(name: String, content: Content = Content.Empty)
- : DocumentationNode(name, content, DocumentationNode.Kind.Module) {
-}
-
-val DocumentationNode.path: List<DocumentationNode>
- get() {
- val parent = owner ?: return listOf(this)
- return parent.path + this
- }
-
-fun DocumentationNode.findOrCreatePackageNode(packageName: String, packageContent: Map<String, Content>): DocumentationNode {
- val existingNode = members(DocumentationNode.Kind.Package).firstOrNull { it.name == packageName }
- if (existingNode != null) {
- return existingNode
- }
- val newNode = DocumentationNode(packageName,
- packageContent.getOrElse(packageName) { Content.Empty },
- DocumentationNode.Kind.Package)
- append(newNode, DocumentationReference.Kind.Member)
- return newNode
-}
-
-fun DocumentationNode.append(child: DocumentationNode, kind: DocumentationReference.Kind) {
- addReferenceTo(child, kind)
- when (kind) {
- DocumentationReference.Kind.Detail -> child.addReferenceTo(this, DocumentationReference.Kind.Owner)
- DocumentationReference.Kind.Member -> child.addReferenceTo(this, DocumentationReference.Kind.Owner)
- DocumentationReference.Kind.Owner -> child.addReferenceTo(this, DocumentationReference.Kind.Member)
- else -> { /* Do not add any links back for other types */ }
- }
-}
-
-fun DocumentationNode.appendTextNode(text: String,
- kind: DocumentationNode.Kind,
- refKind: DocumentationReference.Kind = DocumentationReference.Kind.Detail) {
- append(DocumentationNode(text, Content.Empty, kind), refKind)
-}
-
-fun DocumentationNode.qualifiedName() = path.drop(1).map { it.name }.filter { it.length > 0 }.joinToString(".")
diff --git a/src/Model/DocumentationReference.kt b/src/Model/DocumentationReference.kt
deleted file mode 100644
index 898c92d7..00000000
--- a/src/Model/DocumentationReference.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Singleton
-
-public data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: DocumentationReference.Kind) {
- public enum class Kind {
- Owner,
- Member,
- InheritedMember,
- Detail,
- Link,
- HiddenLink,
- Extension,
- Inheritor,
- Superclass,
- Override,
- Annotation,
- Deprecation,
- TopLevelPage
- }
-}
-
-class PendingDocumentationReference(val lazyNodeFrom: () -> DocumentationNode?,
- val lazyNodeTo: () -> DocumentationNode?,
- val kind: DocumentationReference.Kind) {
- fun resolve() {
- val fromNode = lazyNodeFrom()
- val toNode = lazyNodeTo()
- if (fromNode != null && toNode != null) {
- fromNode.addReferenceTo(toNode, kind)
- }
- }
-}
-
-@Singleton
-class NodeReferenceGraph() {
- private val nodeMap = hashMapOf<String, DocumentationNode>()
- val references = arrayListOf<PendingDocumentationReference>()
-
- fun register(signature: String, node: DocumentationNode) {
- nodeMap.put(signature, node)
- }
-
- fun link(fromNode: DocumentationNode, toSignature: String, kind: DocumentationReference.Kind) {
- references.add(PendingDocumentationReference({ -> fromNode}, { -> nodeMap[toSignature]}, kind))
- }
-
- fun link(fromSignature: String, toNode: DocumentationNode, kind: DocumentationReference.Kind) {
- references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> toNode}, kind))
- }
-
- fun link(fromSignature: String, toSignature: String, kind: DocumentationReference.Kind) {
- references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> nodeMap[toSignature]}, kind))
- }
-
- fun lookup(signature: String): DocumentationNode? = nodeMap[signature]
-
- fun resolveReferences() {
- references.forEach { it.resolve() }
- }
-}
diff --git a/src/Model/PackageDocs.kt b/src/Model/PackageDocs.kt
deleted file mode 100644
index 044c73d8..00000000
--- a/src/Model/PackageDocs.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.Singleton
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor
-import java.io.File
-
-@Singleton
-public class PackageDocs
- @Inject constructor(val linkResolver: DeclarationLinkResolver?,
- val logger: DokkaLogger)
-{
- public val moduleContent: MutableContent = MutableContent()
- private val _packageContent: MutableMap<String, MutableContent> = hashMapOf()
- public val packageContent: Map<String, Content>
- get() = _packageContent
-
- fun parse(fileName: String, linkResolveContext: LazyPackageDescriptor?) {
- val file = File(fileName)
- if (file.exists()) {
- val text = file.readText()
- val tree = parseMarkdown(text)
- var targetContent: MutableContent = moduleContent
- tree.children.forEach {
- if (it.type == MarkdownElementTypes.ATX_1) {
- val headingText = it.child(MarkdownTokenTypes.ATX_CONTENT)?.text
- if (headingText != null) {
- targetContent = findTargetContent(headingText.trimStart())
- }
- } else {
- buildContentTo(it, targetContent, { resolveContentLink(it, linkResolveContext) })
- }
- }
- } else {
- logger.warn("Include file $file was not found.")
- }
- }
-
- private fun findTargetContent(heading: String): MutableContent {
- if (heading.startsWith("Module") || heading.startsWith("module")) {
- return moduleContent
- }
- if (heading.startsWith("Package") || heading.startsWith("package")) {
- return findOrCreatePackageContent(heading.substring("package".length).trim())
- }
- return findOrCreatePackageContent(heading)
- }
-
- private fun findOrCreatePackageContent(packageName: String) =
- _packageContent.getOrPut(packageName) { -> MutableContent() }
-
- private fun resolveContentLink(href: String, linkResolveContext: LazyPackageDescriptor?): ContentBlock {
- if (linkResolveContext != null && linkResolver != null) {
- return linkResolver.resolveContentLink(linkResolveContext, href)
- }
- return ContentExternalLink("#")
- }
-} \ No newline at end of file
diff --git a/src/Model/SourceLinks.kt b/src/Model/SourceLinks.kt
deleted file mode 100644
index 956bfe4b..00000000
--- a/src/Model/SourceLinks.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.PsiElement
-import java.io.File
-import com.intellij.psi.PsiDocumentManager
-import com.intellij.psi.PsiNameIdentifierOwner
-import org.jetbrains.kotlin.psi.psiUtil.startOffset
-
-class SourceLinkDefinition(val path: String, val url: String, val lineSuffix: String?)
-
-fun DocumentationNode.appendSourceLink(psi: PsiElement?, sourceLinks: List<SourceLinkDefinition>) {
- val path = psi?.containingFile?.virtualFile?.path ?: return
-
- val target = if (psi is PsiNameIdentifierOwner) psi.nameIdentifier else psi
- val absPath = File(path).absolutePath
- val linkDef = sourceLinks.firstOrNull { absPath.startsWith(it.path) }
- if (linkDef != null) {
- var url = linkDef.url + path.substring(linkDef.path.length)
- if (linkDef.lineSuffix != null) {
- val line = target?.lineNumber()
- if (line != null) {
- url += linkDef.lineSuffix + line.toString()
- }
- }
- append(DocumentationNode(url, Content.Empty, DocumentationNode.Kind.SourceUrl),
- DocumentationReference.Kind.Detail);
- }
-
- if (target != null) {
- append(DocumentationNode(target.sourcePosition(), Content.Empty, DocumentationNode.Kind.SourcePosition), DocumentationReference.Kind.Detail)
- }
-}
-
-private fun PsiElement.sourcePosition(): String {
- val path = containingFile.virtualFile.path
- val lineNumber = lineNumber()
- val columnNumber = columnNumber()
-
- return when {
- lineNumber == null -> path
- columnNumber == null -> "$path:$lineNumber"
- else -> "$path:$lineNumber:$columnNumber"
- }
-}
-
-fun PsiElement.lineNumber(): Int? {
- val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile)
- // IJ uses 0-based line-numbers; external source browsers use 1-based
- return doc?.getLineNumber(textRange.startOffset)?.plus(1)
-}
-
-fun PsiElement.columnNumber(): Int? {
- val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile) ?: return null
- val lineNumber = doc.getLineNumber(textRange.startOffset)
- return startOffset - doc.getLineStartOffset(lineNumber)
-} \ No newline at end of file
diff --git a/src/Utilities/DokkaModule.kt b/src/Utilities/DokkaModule.kt
deleted file mode 100644
index 1eb82313..00000000
--- a/src/Utilities/DokkaModule.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.jetbrains.dokka.Utilities
-
-import com.google.inject.Binder
-import com.google.inject.Module
-import com.google.inject.Provider
-import com.google.inject.name.Names
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Formats.FormatDescriptor
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import java.io.File
-
-class DokkaModule(val environment: AnalysisEnvironment,
- val options: DocumentationOptions,
- val logger: DokkaLogger) : Module {
- override fun configure(binder: Binder) {
- binder.bind(File::class.java).annotatedWith(Names.named("outputDir")).toInstance(File(options.outputDir))
-
- binder.bindNameAnnotated<LocationService, SingleFolderLocationService>("singleFolder")
- binder.bindNameAnnotated<FileLocationService, SingleFolderLocationService>("singleFolder")
- binder.bindNameAnnotated<LocationService, FoldersLocationService>("folders")
- binder.bindNameAnnotated<FileLocationService, FoldersLocationService>("folders")
-
- // defaults
- binder.bind(LocationService::class.java).to(FoldersLocationService::class.java)
- binder.bind(FileLocationService::class.java).to(FoldersLocationService::class.java)
- binder.bind(LanguageService::class.java).to(KotlinLanguageService::class.java)
-
- binder.bind(HtmlTemplateService::class.java).toProvider(object : Provider<HtmlTemplateService> {
- override fun get(): HtmlTemplateService = HtmlTemplateService.default("style.css")
- })
-
- binder.registerCategory<LanguageService>("language")
- binder.registerCategory<OutlineFormatService>("outline")
- binder.registerCategory<FormatService>("format")
- binder.registerCategory<Generator>("generator")
-
- val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", options.outputFormat)
-
- descriptor.outlineServiceClass?.let { clazz ->
- binder.bind(OutlineFormatService::class.java).to(clazz.java)
- }
- descriptor.formatServiceClass?.let { clazz ->
- binder.bind(FormatService::class.java).to(clazz.java)
- }
- binder.bind<PackageDocumentationBuilder>().to(descriptor.packageDocumentationBuilderClass.java)
- binder.bind<JavaDocumentationBuilder>().to(descriptor.javaDocumentationBuilderClass.java)
-
- binder.bind<Generator>().to(descriptor.generatorServiceClass.java)
-
- val coreEnvironment = environment.createCoreEnvironment()
- binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
-
- val dokkaResolutionFacade = environment.createResolutionFacade(coreEnvironment)
- binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
-
- binder.bind<DocumentationOptions>().toInstance(options)
- binder.bind<DokkaLogger>().toInstance(logger)
- }
-}
-
-private inline fun <reified T: Any> Binder.registerCategory(category: String) {
- ServiceLocator.allServices(category).forEach {
- @Suppress("UNCHECKED_CAST")
- bind(T::class.java).annotatedWith(Names.named(it.name)).to(T::class.java.classLoader.loadClass(it.className) as Class<T>)
- }
-}
-
-private inline fun <reified Base : Any, reified T : Base> Binder.bindNameAnnotated(name: String) {
- bind(Base::class.java).annotatedWith(Names.named(name)).to(T::class.java)
-}
-
-
-inline fun <reified T: Any> Binder.bind() = bind(T::class.java)
diff --git a/src/Utilities/Html.kt b/src/Utilities/Html.kt
deleted file mode 100644
index ce3a1982..00000000
--- a/src/Utilities/Html.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.jetbrains.dokka
-
-
-/**
- * Replaces symbols reserved in HTML with their respective entities.
- * Replaces & with &amp;, < with &lt; and > with &gt;
- */
-public fun String.htmlEscape(): String = replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
diff --git a/src/Utilities/Path.kt b/src/Utilities/Path.kt
deleted file mode 100644
index 05838499..00000000
--- a/src/Utilities/Path.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.jetbrains.dokka
-
-import java.io.File
-
-fun File.appendExtension(extension: String) = if (extension.isEmpty()) this else File(path + "." + extension)
diff --git a/src/Utilities/ServiceLocator.kt b/src/Utilities/ServiceLocator.kt
deleted file mode 100644
index 7a5aff79..00000000
--- a/src/Utilities/ServiceLocator.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.jetbrains.dokka.Utilities
-
-import java.io.File
-import java.util.*
-import java.util.jar.JarFile
-import java.util.zip.ZipEntry
-
-data class ServiceDescriptor(val name: String, val category: String, val description: String?, val className: String)
-
-class ServiceLookupException(message: String) : Exception(message)
-
-public object ServiceLocator {
- public fun <T : Any> lookup(clazz: Class<T>, category: String, implementationName: String): T {
- val descriptor = lookupDescriptor(category, implementationName)
- val loadedClass = javaClass.classLoader.loadClass(descriptor.className)
- val constructor = loadedClass.constructors
- .filter { it.parameterTypes.isEmpty() }
- .firstOrNull() ?: throw ServiceLookupException("Class ${descriptor.className} has no corresponding constructor")
-
- val implementationRawType: Any = if (constructor.parameterTypes.isEmpty()) constructor.newInstance() else constructor.newInstance(constructor)
-
- if (!clazz.isInstance(implementationRawType)) {
- throw ServiceLookupException("Class ${descriptor.className} is not a subtype of ${clazz.name}")
- }
-
- @Suppress("UNCHECKED_CAST")
- return implementationRawType as T
- }
-
- private fun lookupDescriptor(category: String, implementationName: String): ServiceDescriptor {
- val properties = javaClass.classLoader.getResourceAsStream("dokka/$category/$implementationName.properties")?.use { stream ->
- Properties().let { properties ->
- properties.load(stream)
- properties
- }
- } ?: throw ServiceLookupException("No implementation with name $implementationName found in category $category")
-
- val className = properties["class"]?.toString() ?: throw ServiceLookupException("Implementation $implementationName has no class configured")
-
- return ServiceDescriptor(implementationName, category, properties["description"]?.toString(), className)
- }
-
- fun allServices(category: String): List<ServiceDescriptor> {
- val entries = this.javaClass.classLoader.getResources("dokka/$category")?.toList() ?: emptyList()
-
- return entries.flatMap {
- when (it.protocol) {
- "file" -> File(it.file).listFiles()?.filter { it.extension == "properties" }?.map { lookupDescriptor(category, it.nameWithoutExtension) } ?: emptyList()
- "jar" -> {
- val file = JarFile(it.file.removePrefix("file:").substringBefore("!"))
- try {
- val jarPath = it.file.substringAfterLast("!").removePrefix("/")
- file.entries()
- .asSequence()
- .filter { entry -> !entry.isDirectory && entry.path == jarPath && entry.extension == "properties" }
- .map { entry ->
- lookupDescriptor(category, entry.fileName.substringBeforeLast("."))
- }.toList()
- } finally {
- file.close()
- }
- }
- else -> emptyList<ServiceDescriptor>()
- }
- }
- }
-}
-
-public inline fun <reified T : Any> ServiceLocator.lookup(category: String, implementationName: String): T = lookup(T::class.java, category, implementationName)
-
-private val ZipEntry.fileName: String
- get() = name.substringAfterLast("/", name)
-
-private val ZipEntry.path: String
- get() = name.substringBeforeLast("/", "").removePrefix("/")
-
-private val ZipEntry.extension: String?
- get() = fileName.let { fn -> if ("." in fn) fn.substringAfterLast(".") else null }
diff --git a/src/main.kt b/src/main.kt
deleted file mode 100644
index 5a7514c4..00000000
--- a/src/main.kt
+++ /dev/null
@@ -1,262 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Guice
-import com.google.inject.Injector
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiJavaFile
-import com.intellij.psi.PsiManager
-import com.sampullara.cli.Args
-import com.sampullara.cli.Argument
-import org.jetbrains.dokka.Utilities.DokkaModule
-import org.jetbrains.kotlin.cli.common.arguments.ValueDescription
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
-import org.jetbrains.kotlin.cli.common.messages.MessageCollector
-import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
-import org.jetbrains.kotlin.config.CommonConfigurationKeys
-import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzerForTopLevel
-import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
-import org.jetbrains.kotlin.utils.PathUtil
-import java.io.File
-import kotlin.util.measureTimeMillis
-
-class DokkaArguments {
- @set:Argument(value = "src", description = "Source file or directory (allows many paths separated by the system path separator)")
- @ValueDescription("<path>")
- public var src: String = ""
-
- @set:Argument(value = "srcLink", description = "Mapping between a source directory and a Web site for browsing the code")
- @ValueDescription("<path>=<url>[#lineSuffix]")
- public var srcLink: String = ""
-
- @set:Argument(value = "include", description = "Markdown files to load (allows many paths separated by the system path separator)")
- @ValueDescription("<path>")
- public var include: String = ""
-
- @set:Argument(value = "samples", description = "Source root for samples")
- @ValueDescription("<path>")
- public var samples: String = ""
-
- @set:Argument(value = "output", description = "Output directory path")
- @ValueDescription("<path>")
- public var outputDir: String = "out/doc/"
-
- @set:Argument(value = "format", description = "Output format (text, html, markdown, jekyll, kotlin-website)")
- @ValueDescription("<name>")
- public var outputFormat: String = "html"
-
- @set:Argument(value = "module", description = "Name of the documentation module")
- @ValueDescription("<name>")
- public var moduleName: String = ""
-
- @set:Argument(value = "classpath", description = "Classpath for symbol resolution")
- @ValueDescription("<path>")
- public var classpath: String = ""
-
- @set:Argument(value = "nodeprecated", description = "Exclude deprecated members from documentation")
- public var nodeprecated: Boolean = false
-
-}
-
-private fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition {
- val (path, urlAndLine) = srcLink.split('=')
- return SourceLinkDefinition(File(path).absolutePath,
- urlAndLine.substringBefore("#"),
- urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it })
-}
-
-public fun main(args: Array<String>) {
- val arguments = DokkaArguments()
- val freeArgs: List<String> = Args.parse(arguments, args) ?: listOf()
- val sources = if (arguments.src.isNotEmpty()) arguments.src.split(File.pathSeparatorChar).toList() + freeArgs else freeArgs
- val samples = if (arguments.samples.isNotEmpty()) arguments.samples.split(File.pathSeparatorChar).toList() else listOf()
- val includes = if (arguments.include.isNotEmpty()) arguments.include.split(File.pathSeparatorChar).toList() else listOf()
-
- val sourceLinks = if (arguments.srcLink.isNotEmpty() && arguments.srcLink.contains("="))
- listOf(parseSourceLinkDefinition(arguments.srcLink))
- else {
- if (arguments.srcLink.isNotEmpty()) {
- println("Warning: Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.")
- }
- listOf()
- }
-
- val classPath = arguments.classpath.split(File.pathSeparatorChar).toList()
- val generator = DokkaGenerator(
- DokkaConsoleLogger,
- classPath,
- sources,
- samples,
- includes,
- arguments.moduleName,
- arguments.outputDir.let { if (it.endsWith('/')) it else it + '/' },
- arguments.outputFormat,
- sourceLinks,
- arguments.nodeprecated)
-
- generator.generate()
- DokkaConsoleLogger.report()
-}
-
-interface DokkaLogger {
- fun info(message: String)
- fun warn(message: String)
- fun error(message: String)
-}
-
-object DokkaConsoleLogger: DokkaLogger {
- var warningCount: Int = 0
-
- override fun info(message: String) = println(message)
- override fun warn(message: String) {
- println("WARN: $message")
- warningCount++
- }
-
- override fun error(message: String) = println("ERROR: $message")
-
- fun report() {
- if (warningCount > 0) {
- println("Generation completed with $warningCount warnings")
- } else {
- println("Generation completed successfully")
- }
- }
-}
-
-class DokkaMessageCollector(val logger: DokkaLogger): MessageCollector {
- override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
- logger.error(MessageRenderer.PLAIN_FULL_PATHS.render(severity, message, location))
- }
-}
-
-class DokkaGenerator(val logger: DokkaLogger,
- val classpath: List<String>,
- val sources: List<String>,
- val samples: List<String>,
- val includes: List<String>,
- val moduleName: String,
- val outputDir: String,
- val outputFormat: String,
- val sourceLinks: List<SourceLinkDefinition>,
- val skipDeprecated: Boolean = false) {
- fun generate() {
- val environment = createAnalysisEnvironment()
-
- logger.info("Module: $moduleName")
- logger.info("Output: ${File(outputDir)}")
- logger.info("Sources: ${environment.sources.joinToString()}")
- logger.info("Classpath: ${environment.classpath.joinToString()}")
-
- logger.info("Analysing sources and libraries... ")
- val startAnalyse = System.currentTimeMillis()
-
- val options = DocumentationOptions(outputDir, outputFormat, false, sourceLinks = sourceLinks, skipDeprecated = skipDeprecated)
-
- val injector = Guice.createInjector(DokkaModule(environment, options, logger))
-
- val documentation = buildDocumentationModule(injector, moduleName, { isSample(it) }, includes)
-
- val timeAnalyse = System.currentTimeMillis() - startAnalyse
- logger.info("done in ${timeAnalyse / 1000} secs")
-
- val timeBuild = measureTimeMillis {
- logger.info("Generating pages... ")
- injector.getInstance(Generator::class.java).buildAll(documentation)
- }
- logger.info("done in ${timeBuild / 1000} secs")
-
- Disposer.dispose(environment)
- }
-
- fun createAnalysisEnvironment(): AnalysisEnvironment {
- val environment = AnalysisEnvironment(DokkaMessageCollector(logger))
-
- environment.apply {
- addClasspath(PathUtil.getJdkClassesRoots())
- // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath())
- for (element in this@DokkaGenerator.classpath) {
- addClasspath(File(element))
- }
-
- addSources(this@DokkaGenerator.sources)
- addSources(this@DokkaGenerator.samples)
- }
-
- return environment
- }
-
- fun isSample(file: PsiFile): Boolean {
- val sourceFile = File(file.virtualFile!!.path)
- return samples.none { sample ->
- val canonicalSample = File(sample).canonicalPath
- val canonicalSource = sourceFile.canonicalPath
- canonicalSource.startsWith(canonicalSample)
- }
- }
-}
-
-fun buildDocumentationModule(injector: Injector,
- moduleName: String,
- filesToDocumentFilter: (PsiFile) -> Boolean = { file -> true },
- includes: List<String> = listOf()): DocumentationModule {
-
- val coreEnvironment = injector.getInstance(KotlinCoreEnvironment::class.java)
- val fragmentFiles = coreEnvironment.getSourceFiles().filter(filesToDocumentFilter)
-
- val resolutionFacade = injector.getInstance(DokkaResolutionFacade::class.java)
- val analyzer = resolutionFacade.getFrontendService(LazyTopDownAnalyzerForTopLevel::class.java)
- analyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, fragmentFiles)
-
- val fragments = fragmentFiles
- .map { resolutionFacade.resolveSession.getPackageFragment(it.packageFqName) }
- .filterNotNull()
- .distinct()
-
- val packageDocs = injector.getInstance(PackageDocs::class.java)
- for (include in includes) {
- packageDocs.parse(include, fragments.firstOrNull())
- }
- val documentationModule = DocumentationModule(moduleName, packageDocs.moduleContent)
-
- with(injector.getInstance(DocumentationBuilder::class.java)) {
- documentationModule.appendFragments(fragments, packageDocs.packageContent,
- injector.getInstance(PackageDocumentationBuilder::class.java))
- }
-
- val javaFiles = coreEnvironment.getJavaSourceFiles().filter(filesToDocumentFilter)
- with(injector.getInstance(JavaDocumentationBuilder::class.java)) {
- javaFiles.map { appendFile(it, documentationModule, packageDocs.packageContent) }
- }
-
- injector.getInstance(NodeReferenceGraph::class.java).resolveReferences()
-
- return documentationModule
-}
-
-
-fun KotlinCoreEnvironment.getJavaSourceFiles(): List<PsiJavaFile> {
- val sourceRoots = configuration.get(CommonConfigurationKeys.CONTENT_ROOTS)
- ?.filterIsInstance<JavaSourceRoot>()
- ?.map { it.file }
- ?: listOf()
-
- val result = arrayListOf<PsiJavaFile>()
- val localFileSystem = VirtualFileManager.getInstance().getFileSystem("file")
- sourceRoots.forEach { sourceRoot ->
- sourceRoot.absoluteFile.walkTopDown().forEach {
- val vFile = localFileSystem.findFileByPath(it.path)
- if (vFile != null) {
- val psiFile = PsiManager.getInstance(project).findFile(vFile)
- if (psiFile is PsiJavaFile) {
- result.add(psiFile)
- }
- }
- }
- }
- return result
-}