aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Analysis/AnalysisEnvironment.kt40
-rw-r--r--src/Analysis/CommentsAPI.kt4
-rw-r--r--src/Analysis/CompilerAPI.kt37
-rw-r--r--src/Formats/HtmlFormatService.kt20
-rw-r--r--src/Formats/KotlinWebsiteFormatService.kt4
-rw-r--r--src/Formats/MarkdownFormatService.kt10
-rw-r--r--src/Formats/StructuredFormatService.kt32
-rw-r--r--src/Formats/TextFormatService.kt4
-rw-r--r--src/Generation/ConsoleGenerator.kt2
-rw-r--r--src/Kotlin/ContentBuilder.kt69
-rw-r--r--src/Kotlin/Diagnostics.kt40
-rw-r--r--src/Kotlin/DocumentationBuilder.kt329
-rw-r--r--src/Kotlin/DocumentationBuildingVisitor.kt127
-rw-r--r--src/Kotlin/DocumentationContext.kt62
-rw-r--r--src/Kotlin/DocumentationNodeBuilder.kt206
-rw-r--r--src/Kotlin/KotlinLanguageService.kt (renamed from src/Languages/KotlinLanguageService.kt)103
-rw-r--r--src/Kotlin/ResolveReferences.kt75
-rw-r--r--src/Locations/LocationService.kt2
-rw-r--r--src/Markdown/MarkdownProcessor.kt4
-rw-r--r--src/Markdown/markdown.bnf11
-rw-r--r--src/Model/Content.kt12
-rw-r--r--src/Model/DocumentationModule.kt2
-rw-r--r--src/Model/DocumentationNode.kt12
-rw-r--r--src/main.kt75
24 files changed, 624 insertions, 658 deletions
diff --git a/src/Analysis/AnalysisEnvironment.kt b/src/Analysis/AnalysisEnvironment.kt
index 1d51b8a2..3c7f6767 100644
--- a/src/Analysis/AnalysisEnvironment.kt
+++ b/src/Analysis/AnalysisEnvironment.kt
@@ -11,6 +11,7 @@ import org.jetbrains.jet.cli.common.*
import org.jetbrains.jet.cli.jvm.*
import com.intellij.openapi.util.*
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
+import org.jetbrains.jet.lang.resolve.lazy.ResolveSession
/**
* Kotlin as a service entry point
@@ -30,27 +31,28 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector, body: A
* Executes [processor] when analysis is complete.
* $processor is a function to receive compiler environment, module and context for symbol resolution
*/
- public fun withContext<T>(processor: (JetCoreEnvironment, ModuleDescriptor, BindingContext) -> T): T {
+ public fun withContext<T>(processor: (JetCoreEnvironment, ResolveSession) -> T): T {
val environment = JetCoreEnvironment.createForProduction(this, configuration)
- val exhaust = environment.analyze()
- return processor(environment, exhaust.getModuleDescriptor(), exhaust.getBindingContext())
+ val resolveSession = environment.analyze()
+ resolveSession.forceResolveAll()
+ return processor(environment, resolveSession)
}
/**
* Executes [processor] when analysis is complete.
* $processor is a function to receive compiler module and context for symbol resolution
*/
- public fun withContext<T>(processor: (ModuleDescriptor, BindingContext) -> T): T {
- return withContext { environment, module, context -> processor(module, context) }
+ public fun withContext<T>(processor: (ResolveSession) -> T): T {
+ return withContext { environment, session -> processor(session) }
}
/**
* Streams files into [processor] and returns a stream of its results
* $processor is a function to receive context for symbol resolution and file for processing
*/
- public fun streamFiles<T>(processor: (BindingContext, JetFile) -> T): Stream<T> {
- return withContext { environment, module, context ->
- environment.getSourceFiles().stream().map { file -> processor(context, file) }
+ public fun streamFiles<T>(processor: (ResolveSession, JetFile) -> T): Stream<T> {
+ return withContext { environment, session ->
+ environment.getSourceFiles().stream().map { file -> processor(session, file) }
}
}
@@ -58,19 +60,9 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector, body: A
* Runs [processor] for each file and collects its results into single list
* $processor is a function to receive context for symbol resolution and file for processing
*/
- public fun processFiles<T>(processor: (BindingContext, JetFile) -> T): List<T> {
- return withContext { environment, module, context ->
- environment.getSourceFiles().map { file -> processor(context, file) }
- }
- }
-
- /**
- * Runs [processor] for each file and collects its results into single list
- * $processor is a function to receive context for symbol resolution, module and file for processing
- */
- public fun processFiles<T>(processor: (BindingContext, ModuleDescriptor, JetFile) -> T): List<T> {
- return withContext { environment, module, context ->
- environment.getSourceFiles().map { file -> processor(context, module, file) }
+ public fun processFiles<T>(processor: (ResolveSession, JetFile) -> T): List<T> {
+ return withContext { environment, session ->
+ environment.getSourceFiles().map { file -> processor(session, file) }
}
}
@@ -78,9 +70,9 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector, body: A
* Runs [processor] for each file and collects its results into single list
* $processor is a function to receive context for symbol resolution and file for processing
*/
- public fun processFilesFlat<T>(processor: (BindingContext, JetFile) -> List<T>): List<T> {
- return withContext { environment, module, context ->
- environment.getSourceFiles().flatMap { file -> processor(context, file) }
+ public fun processFilesFlat<T>(processor: (ResolveSession, JetFile) -> List<T>): List<T> {
+ return withContext { environment, session ->
+ environment.getSourceFiles().flatMap { file -> processor(session, file) }
}
}
diff --git a/src/Analysis/CommentsAPI.kt b/src/Analysis/CommentsAPI.kt
index a17b6aa4..2407de76 100644
--- a/src/Analysis/CommentsAPI.kt
+++ b/src/Analysis/CommentsAPI.kt
@@ -5,8 +5,8 @@ import org.jetbrains.jet.lang.resolve.*
import org.jetbrains.jet.kdoc.psi.api.*
import org.jetbrains.jet.lang.psi.*
-fun BindingContext.getDocumentationElements(descriptor: DeclarationDescriptor): List<KDoc> {
- val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)
+fun DeclarationDescriptor.getDocumentationElements(): List<KDoc> {
+ val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(this)
if (psiElement == null)
return listOf()
diff --git a/src/Analysis/CompilerAPI.kt b/src/Analysis/CompilerAPI.kt
index 03d4dde6..8216c549 100644
--- a/src/Analysis/CompilerAPI.kt
+++ b/src/Analysis/CompilerAPI.kt
@@ -1,19 +1,19 @@
package org.jetbrains.dokka
import org.jetbrains.jet.cli.common.arguments.*
-import org.jetbrains.jet.cli.common.messages.*
-import org.jetbrains.jet.cli.jvm.*
import org.jetbrains.jet.cli.jvm.compiler.*
import org.jetbrains.jet.utils.*
import java.io.*
import org.jetbrains.jet.lang.resolve.java.*
-import com.google.common.base.*
-import com.intellij.psi.*
import org.jetbrains.jet.lang.resolve.*
import org.jetbrains.jet.lang.psi.*
import org.jetbrains.jet.analyzer.*
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.lang.resolve.scopes.*
+import org.jetbrains.jet.context.GlobalContext
+import com.intellij.psi.search.GlobalSearchScope
+import org.jetbrains.jet.lang.resolve.name.Name
+import org.jetbrains.jet.lang.resolve.lazy.ResolveSession
private fun getAnnotationsPath(paths: KotlinPaths, arguments: K2JVMCompilerArguments): MutableList<File> {
val annotationsPath = arrayListOf<File>()
@@ -27,21 +27,24 @@ private fun getAnnotationsPath(paths: KotlinPaths, arguments: K2JVMCompilerArgum
return annotationsPath
}
-fun JetCoreEnvironment.analyze(): AnalyzeExhaust {
+fun JetCoreEnvironment.analyze(): ResolveSession {
+ val globalContext = GlobalContext()
val project = getProject()
val sourceFiles = getSourceFiles()
- val support = CliLightClassGenerationSupport.getInstanceForCli(project)!!
- val sharedTrace = support.getTrace()
- val sharedModule = support.newModule()
- val exhaust = TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(project, sourceFiles, sharedTrace,
- Predicates.alwaysFalse<PsiFile>(),
- sharedModule,
- null,
- null)
- return exhaust
-}
-fun BindingContext.getPackageFragment(file: JetFile): PackageFragmentDescriptor? = get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, file)
+ val module = object : ModuleInfo {
+ override val name: Name = Name.special("<module>")
+ override fun dependencies(): List<ModuleInfo> = listOf(this)
+ }
+ val resolverForProject = JvmAnalyzerFacade.setupResolverForProject(
+ globalContext,
+ project,
+ listOf(module),
+ { ModuleContent(sourceFiles, GlobalSearchScope.allScope(project)) },
+ JvmPlatformParameters { module }
+ )
+ return resolverForProject.resolverForModule(module).lazyResolveSession
+}
fun DeclarationDescriptor.isUserCode() =
when (this) {
@@ -117,7 +120,7 @@ public fun getPropertyInnerScope(outerScope: JetScope, descriptor: PropertyDescr
return propertyScope
}
-fun BindingContext.getResolutionScope(descriptor: DeclarationDescriptor): JetScope {
+fun getResolutionScope(descriptor: DeclarationDescriptor): JetScope {
when (descriptor) {
is PackageFragmentDescriptor ->
return getPackageInnerScope(descriptor)
diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt
index 20cd4f83..c337b69b 100644
--- a/src/Formats/HtmlFormatService.kt
+++ b/src/Formats/HtmlFormatService.kt
@@ -20,15 +20,15 @@ public open class HtmlFormatService(locationService: LocationService,
}
override fun appendBlockCode(to: StringBuilder, line: String) {
- to.appendln("<code>")
- to.appendln(line)
- to.appendln("</code>")
+ to.append("<pre><code>")
+ to.append(line)
+ to.append("</code></pre>")
}
override fun appendBlockCode(to: StringBuilder, lines: Iterable<String>) {
- to.appendln("<code>")
- to.appendln(lines.join("\n"))
- to.appendln("</code>")
+ to.append("<pre><code>")
+ to.append(lines.join("\n"))
+ to.append("</code></pre>")
}
override fun appendHeader(to: StringBuilder, text: String, level: Int) {
@@ -85,8 +85,12 @@ public open class HtmlFormatService(locationService: LocationService,
return "<a href=\"${href}\">${text}</a>"
}
- override fun formatBold(text: String): String {
- return "<b>${text}</b>"
+ override fun formatStrong(text: String): String {
+ return "<strong>${text}</strong>"
+ }
+
+ override fun formatEmphasis(text: String): String {
+ return "<emph>${text}</emph>"
}
override fun formatCode(code: String): String {
diff --git a/src/Formats/KotlinWebsiteFormatService.kt b/src/Formats/KotlinWebsiteFormatService.kt
index 8170b5a9..e694e222 100644
--- a/src/Formats/KotlinWebsiteFormatService.kt
+++ b/src/Formats/KotlinWebsiteFormatService.kt
@@ -29,10 +29,6 @@ public class KotlinWebsiteFormatService(locationService: LocationService,
return "<a href=\"${href}\">${text}</a>"
}
- override fun appendText(to: StringBuilder, text: String) {
- to.appendln("<p markdown=\"1\">${text}</p>")
- }
-
override fun appendTable(to: StringBuilder, body: () -> Unit) {
to.appendln("<table class=\"api-docs-table\">")
body()
diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt
index a835a673..8f9699c2 100644
--- a/src/Formats/MarkdownFormatService.kt
+++ b/src/Formats/MarkdownFormatService.kt
@@ -30,10 +30,14 @@ public open class MarkdownFormatService(locationService: LocationService,
return "`$code`"
}
- override public fun formatBold(text: String): String {
+ override public fun formatStrong(text: String): String {
return "**$text**"
}
+ override fun formatEmphasis(text: String): String {
+ return "*$text*"
+ }
+
override public fun formatLink(text: String, location: Location): String {
return "[$text](${location.path})"
}
@@ -51,7 +55,9 @@ public open class MarkdownFormatService(locationService: LocationService,
}
override public fun appendText(to: StringBuilder, text: String) {
- to.append(text)
+ to.appendln()
+ to.appendln(text)
+ to.appendln()
}
override public fun appendHeader(to: StringBuilder, text: String, level: Int) {
diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt
index df11b835..280aa6b5 100644
--- a/src/Formats/StructuredFormatService.kt
+++ b/src/Formats/StructuredFormatService.kt
@@ -27,7 +27,8 @@ public abstract class StructuredFormatService(val locationService: LocationServi
public abstract fun formatLink(text: String, location: Location): String
public abstract fun formatLink(text: String, href: String): String
public open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.location)
- public abstract fun formatBold(text: String): String
+ public abstract fun formatStrong(text: String): String
+ public abstract fun formatEmphasis(text: String): String
public abstract fun formatCode(code: String): String
public abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String
@@ -42,7 +43,9 @@ public abstract class StructuredFormatService(val locationService: LocationServi
is ContentSymbol -> append(formatSymbol(content.text))
is ContentKeyword -> append(formatKeyword(content.text))
is ContentIdentifier -> append(formatIdentifier(content.text))
- is ContentEmphasis -> append(formatBold(formatText(location, content.children)))
+ is ContentStrong -> append(formatStrong(formatText(location, content.children)))
+ is ContentCode -> append(formatCode(formatText(location, content.children)))
+ is ContentEmphasis -> append(formatEmphasis(formatText(location, content.children)))
is ContentNodeLink -> {
val linkTo = locationService.relativeLocation(location, content.node, extension)
val linkText = formatText(location, content.children)
@@ -52,6 +55,12 @@ public abstract class StructuredFormatService(val locationService: LocationServi
val linkText = formatText(location, content.children)
append(formatLink(linkText, content.href))
}
+ is ContentParagraph -> {
+ appendText(this, formatText(location, content.children))
+ }
+ is ContentBlockCode -> {
+ appendBlockCode(this, formatText(location, content.children))
+ }
else -> append(formatText(location, content.children))
}
}.toString()
@@ -64,7 +73,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi
}
fun appendDescription(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
- val described = nodes.filter { !it.doc.isEmpty }
+ val described = nodes.filter { !it.content.isEmpty }
if (described.any()) {
val single = described.size == 1
appendHeader(to, "Description", 3)
@@ -72,14 +81,15 @@ public abstract class StructuredFormatService(val locationService: LocationServi
if (!single) {
appendBlockCode(to, formatText(location, languageService.render(node)))
}
- appendLine(to, formatText(location,node.doc.description))
+ appendLine(to, formatText(location,node.content.description))
appendLine(to)
- for ((label, section) in node.doc.sections) {
+ for ((label, section) in node.content.sections) {
if (label.startsWith("$"))
continue
- appendLine(to, formatBold(formatText(label)))
+ if (node.members.any { it.name == label })
+ continue
+ appendLine(to, formatStrong(formatText(label)))
appendLine(to, formatText(location, section))
- appendLine(to)
}
}
}
@@ -87,14 +97,14 @@ public abstract class StructuredFormatService(val locationService: LocationServi
fun appendSummary(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
val breakdownBySummary = nodes.groupByTo(LinkedHashMap()) { node ->
- node.doc.summary
+ formatText(location, node.summary)
}
for ((summary, items) in breakdownBySummary) {
items.forEach {
appendBlockCode(to, formatText(location, languageService.render(it)))
}
- appendLine(to, formatText(location, summary))
+ appendLine(to, summary)
appendLine(to)
}
}
@@ -123,14 +133,14 @@ public abstract class StructuredFormatService(val locationService: LocationServi
appendText(to, formatLink(memberLocation))
}
appendTableCell(to) {
- val breakdownBySummary = members.groupBy { it.doc.summary }
+ val breakdownBySummary = members.groupBy { formatText(location, it.summary) }
for ((summary, items) in breakdownBySummary) {
for (signature in items) {
appendBlockCode(to, formatText(location, languageService.render(signature)))
}
if (!summary.isEmpty()) {
- appendText(to, formatText(location, summary))
+ appendText(to, summary)
}
}
}
diff --git a/src/Formats/TextFormatService.kt b/src/Formats/TextFormatService.kt
index 63d2ce42..4e43cbcc 100644
--- a/src/Formats/TextFormatService.kt
+++ b/src/Formats/TextFormatService.kt
@@ -7,9 +7,9 @@ public class TextFormatService(val signatureGenerator: LanguageService) : Format
with (to) {
appendln(signatureGenerator.render(node))
appendln()
- appendln(node.doc.summary)
+ appendln(node.content.summary)
- for ((label, section) in node.doc.sections) {
+ for ((label, section) in node.content.sections) {
appendln(label)
}
}
diff --git a/src/Generation/ConsoleGenerator.kt b/src/Generation/ConsoleGenerator.kt
index 78164bb9..f52c6f4b 100644
--- a/src/Generation/ConsoleGenerator.kt
+++ b/src/Generation/ConsoleGenerator.kt
@@ -13,7 +13,7 @@ public class ConsoleGenerator(val signatureGenerator: LanguageService, val locat
public fun generateHeader(node: DocumentationNode, indent: String = "") {
println(indent + signatureGenerator.render(node))
- val docString = node.doc.toString()
+ val docString = node.content.toString()
if (!docString.isEmpty())
println("$indent\"${docString.replace("\n", "\n$indent")}\"")
println()
diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt
index b7290b58..635fc74f 100644
--- a/src/Kotlin/ContentBuilder.kt
+++ b/src/Kotlin/ContentBuilder.kt
@@ -2,15 +2,20 @@ package org.jetbrains.dokka
import org.jetbrains.markdown.MarkdownElementTypes
import java.util.ArrayDeque
+import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
+import org.jetbrains.jet.lang.resolve.name.Name
+import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
+import org.jetbrains.jet.lang.resolve.scopes.JetScope
+import org.jetbrains.jet.lang.resolve.name.FqName
-public fun MarkdownTree.toContent(): Content {
+public fun DocumentationBuilder.buildContent(tree: MarkdownTree, descriptor: DeclarationDescriptor): Content {
val nodeStack = ArrayDeque<ContentNode>()
nodeStack.push(Content())
- visit {(node, text, processChildren) ->
+ tree.visit {(node, text, processChildren) ->
val parent = nodeStack.peek()!!
val nodeType = node.getTokenType()
- val nodeText = getNodeText(node)
+ val nodeText = tree.getNodeText(node)
when (nodeType) {
MarkdownElementTypes.BULLET_LIST -> {
nodeStack.push(ContentList())
@@ -39,20 +44,32 @@ public fun MarkdownTree.toContent(): Content {
processChildren()
parent.append(nodeStack.pop())
}
+ MarkdownElementTypes.CODE -> {
+ nodeStack.push(ContentCode())
+ processChildren()
+ parent.append(nodeStack.pop())
+ }
MarkdownElementTypes.ANONYMOUS_SECTION -> {
nodeStack.push(ContentSection(""))
processChildren()
parent.append(nodeStack.pop())
}
+ MarkdownElementTypes.DIRECTIVE -> {
+ val name = tree.findChildByType(node, MarkdownElementTypes.DIRECTIVE_NAME)?.let { tree.getNodeText(it) } ?: ""
+ val params = tree.findChildByType(node, MarkdownElementTypes.DIRECTIVE_PARAMS)?.let { tree.getNodeText(it) } ?: ""
+ when (name) {
+ "code" -> parent.append(functionBody(descriptor, params))
+ }
+ }
MarkdownElementTypes.NAMED_SECTION -> {
- val label = findChildByType(node, MarkdownElementTypes.SECTION_NAME)?.let { getNodeText(it) } ?: ""
+ val label = tree.findChildByType(node, MarkdownElementTypes.SECTION_NAME)?.let { tree.getNodeText(it) } ?: ""
nodeStack.push(ContentSection(label))
processChildren()
parent.append(nodeStack.pop())
}
MarkdownElementTypes.LINK -> {
- val target = findChildByType(node, MarkdownElementTypes.TARGET)?.let { getNodeText(it) } ?: ""
- val href = findChildByType(node, MarkdownElementTypes.HREF)?.let { getNodeText(it) }
+ val target = tree.findChildByType(node, MarkdownElementTypes.TARGET)?.let { tree.getNodeText(it) } ?: ""
+ val href = tree.findChildByType(node, MarkdownElementTypes.HREF)?.let { tree.getNodeText(it) }
val link = if (href != null) ContentExternalLink(href) else ContentExternalLink(target)
link.append(ContentText(target))
parent.append(link)
@@ -71,7 +88,7 @@ public fun MarkdownTree.toContent(): Content {
processChildren()
}
MarkdownElementTypes.PARA -> {
- nodeStack.push(ContentBlock())
+ nodeStack.push(ContentParagraph())
processChildren()
parent.append(nodeStack.pop())
}
@@ -84,3 +101,41 @@ public fun MarkdownTree.toContent(): Content {
}
+fun DocumentationBuilder.functionBody(descriptor: DeclarationDescriptor, functionName: String): ContentNode {
+ val scope = getResolutionScope(descriptor)
+ val rootPackage = session.getModuleDescriptor().getPackage(FqName.ROOT)!!
+ val rootScope = rootPackage.getMemberScope()
+ val symbol = resolveInScope(functionName, scope) ?: resolveInScope(functionName, rootScope)
+ if (symbol == null)
+ return ContentBlockCode().let() { it.append(ContentText("Unresolved: $functionName")); it }
+ val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(symbol)
+ if (psiElement == null)
+ return ContentBlockCode().let() { it.append(ContentText("Source not found: $functionName")); it }
+
+ return ContentBlockCode().let() { it.append(ContentText(psiElement.getText())); it }
+}
+
+private fun DocumentationBuilder.resolveInScope(functionName: String, scope: JetScope): 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.getLocalVariable(symbolName) ?:
+ currentScope.getProperties(symbolName).firstOrNull() ?:
+ currentScope.getFunctions(symbolName).firstOrNull() ?:
+ currentScope.getClassifier(symbolName) ?:
+ currentScope.getPackage(symbolName)
+
+ if (partSymbol == null) {
+ symbol = null
+ break
+ }
+ currentScope = getResolutionScope(partSymbol)
+ symbol = partSymbol
+ }
+
+ return symbol
+} \ No newline at end of file
diff --git a/src/Kotlin/Diagnostics.kt b/src/Kotlin/Diagnostics.kt
deleted file mode 100644
index 5548bc01..00000000
--- a/src/Kotlin/Diagnostics.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.jet.lang.descriptors.*
-import org.jetbrains.jet.lang.resolve.name.*
-import org.jetbrains.jet.lang.resolve.BindingContext
-
-fun DocumentationContext.checkResolveChildren(node: DocumentationNode) {
- if (node.kind != DocumentationNode.Kind.Module && node.kind != DocumentationNode.Kind.Package) {
- // TODO: we don't resolve packages and modules for now
-
- val parentScope = getResolutionScope(node)
- for (item in node.details + node.members) {
- val symbolName = item.name
- val symbol: DeclarationDescriptor? = when (item.kind) {
- DocumentationNode.Kind.Modifier -> continue // do not resolve modifiers, they are not names
- DocumentationNode.Kind.Receiver -> continue // what is receiver's name in platform?
- DocumentationNode.Kind.Parameter -> parentScope.getLocalVariable(Name.guess(symbolName))
- DocumentationNode.Kind.Function -> parentScope.getFunctions(Name.guess(symbolName)).firstOrNull()
- DocumentationNode.Kind.Property -> parentScope.getProperties(Name.guess(symbolName)).firstOrNull()
- DocumentationNode.Kind.Constructor -> parentScope.getFunctions(Name.guess(symbolName)).firstOrNull()
- else -> parentScope.getClassifier(Name.guess(symbolName))
- }
-
- if (symbol == null)
- println("WARNING: Cannot resolve $item in ${path(node)}")
- }
- }
-
- for (reference in node.allReferences().filterNot { it.kind == DocumentationReference.Kind.Owner }) {
- checkResolveChildren(reference.to)
- }
-}
-
-fun path(node: DocumentationNode): String {
- val owner = node.owner
- if (owner != null)
- return "$node in ${path(owner)}"
- else
- return "$node"
-} \ No newline at end of file
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
new file mode 100644
index 00000000..f91c922c
--- /dev/null
+++ b/src/Kotlin/DocumentationBuilder.kt
@@ -0,0 +1,329 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.jet.lang.descriptors.*
+import org.jetbrains.dokka.DocumentationNode.Kind
+import org.jetbrains.jet.lang.types.TypeProjection
+import org.jetbrains.jet.lang.types.Variance
+import org.jetbrains.jet.lang.types.JetType
+import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
+import org.jetbrains.jet.lang.resolve.BindingContext
+import org.jetbrains.jet.lang.resolve.name.Name
+import org.jetbrains.jet.lang.resolve.scopes.JetScope
+import org.jetbrains.jet.lang.psi.JetFile
+import org.jetbrains.jet.lang.resolve.name.FqName
+import org.jetbrains.jet.lang.resolve.lazy.ResolveSession
+
+public data class DocumentationOptions(val includeNonPublic: Boolean = false)
+
+class DocumentationBuilder(val session: ResolveSession, val options: DocumentationOptions) {
+ val visibleToDocumentation = setOf(Visibilities.INTERNAL, Visibilities.PROTECTED, Visibilities.PUBLIC)
+ val descriptorToNode = hashMapOf<DeclarationDescriptor, DocumentationNode>()
+ val nodeToDescriptor = hashMapOf<DocumentationNode, DeclarationDescriptor>()
+ val links = hashMapOf<DocumentationNode, DeclarationDescriptor>()
+ val packages = hashMapOf<FqName, DocumentationNode>()
+
+ fun parseDocumentation(descriptor: DeclarationDescriptor): Content {
+ val docText = descriptor.getDocumentationElements().map { it.extractText() }.join("\n")
+ val tree = MarkdownProcessor.parse(docText)
+ //println(tree.toTestString())
+ val content = buildContent(tree, descriptor)
+ return content
+ }
+
+ fun link(node: DocumentationNode, descriptor: DeclarationDescriptor) {
+ links.put(node, descriptor)
+ }
+
+ fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) {
+ descriptorToNode.put(descriptor, node)
+ nodeToDescriptor.put(node, descriptor)
+ }
+
+ fun DocumentationNode<T>(descriptor: T, kind: Kind): DocumentationNode where T : DeclarationDescriptor, T : Named {
+ val doc = parseDocumentation(descriptor)
+ val node = DocumentationNode(descriptor.getName().asString(), doc, kind)
+ if (descriptor is MemberDescriptor) {
+ if (descriptor !is ConstructorDescriptor) {
+ node.appendModality(descriptor)
+ }
+ node.appendVisibility(descriptor)
+ }
+ return node
+ }
+
+ 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)
+ }
+ }
+
+ fun DocumentationNode.appendModality(descriptor: MemberDescriptor) {
+ val modifier = descriptor.getModality().name().toLowerCase()
+ val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier)
+ append(node, DocumentationReference.Kind.Detail)
+ }
+
+ fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) {
+ val modifier = descriptor.getVisibility().toString()
+ val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier)
+ append(node, DocumentationReference.Kind.Detail)
+ }
+
+ fun DocumentationNode.appendSupertypes(descriptor: ClassDescriptor) {
+ val superTypes = descriptor.getTypeConstructor().getSupertypes()
+ for (superType in superTypes) {
+ if (superType.toString() != "Any")
+ appendType(superType, DocumentationNode.Kind.Supertype)
+ }
+ }
+
+ fun DocumentationNode.appendProjection(projection: TypeProjection, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) {
+ val prefix = when (projection.getProjectionKind()) {
+ Variance.IN_VARIANCE -> "in "
+ Variance.OUT_VARIANCE -> "out "
+ else -> ""
+ }
+ appendType(projection.getType(), kind, prefix)
+ }
+
+ fun DocumentationNode.appendType(jetType: JetType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix: String = "") {
+ if (jetType == null)
+ return
+ val classifierDescriptor = jetType.getConstructor().getDeclarationDescriptor()
+ val name = when (classifierDescriptor) {
+ is Named -> prefix + classifierDescriptor.getName().asString() + if (jetType.isNullable()) "?" else ""
+ else -> "<anonymous>"
+ }
+ val node = DocumentationNode(name, Content.Empty, kind)
+ if (classifierDescriptor != null)
+ link(node, classifierDescriptor)
+
+ append(node, DocumentationReference.Kind.Detail)
+ for (typeArgument in jetType.getArguments())
+ node.appendProjection(typeArgument)
+ }
+
+ fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind) {
+ // do not include generated code
+ if (descriptor is CallableMemberDescriptor && descriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION)
+ return
+
+ if (options.includeNonPublic
+ || descriptor !is MemberDescriptor
+ || descriptor.getVisibility() in visibleToDocumentation) {
+ append(descriptor.build(), kind)
+ }
+ }
+
+ fun DocumentationNode.appendChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) {
+ descriptors.forEach { descriptor -> appendChild(descriptor, kind) }
+ }
+
+ fun DocumentationNode.appendFragments(fragments: Collection<PackageFragmentDescriptor>) {
+ val descriptors = hashMapOf<String, List<DeclarationDescriptor>>()
+ for ((name, parts) in fragments.groupBy { it.fqName }) {
+ descriptors.put(name.asString(), parts.flatMap { it.getMemberScope().getAllDescriptors() })
+ }
+ for ((packageName, declarations) in descriptors) {
+ println(" package $packageName: ${declarations.count()} nodes")
+ val packageNode = DocumentationNode(packageName, Content.Empty, Kind.Package)
+ packageNode.appendChildren(declarations, DocumentationReference.Kind.Member)
+ append(packageNode, DocumentationReference.Kind.Member)
+ }
+ }
+
+ fun DeclarationDescriptor.build(): DocumentationNode = when (this) {
+ is ClassDescriptor -> build()
+ is ConstructorDescriptor -> build()
+ is ScriptDescriptor -> build()
+ is FunctionDescriptor -> build()
+ is PropertyDescriptor -> build()
+ is PropertyGetterDescriptor -> build()
+ is PropertySetterDescriptor -> build()
+ is TypeParameterDescriptor -> build()
+ is ValueParameterDescriptor -> build()
+ is ReceiverParameterDescriptor -> build()
+ else -> throw IllegalStateException("Descriptor $this is not known")
+ }
+
+ fun ScriptDescriptor.build(): DocumentationNode = getClassDescriptor().build()
+ fun ClassDescriptor.build(): DocumentationNode {
+ val kind = when (getKind()) {
+ ClassKind.OBJECT -> Kind.Object
+ ClassKind.CLASS_OBJECT -> Kind.Object
+ ClassKind.TRAIT -> Kind.Interface
+ ClassKind.ENUM_CLASS -> Kind.Enum
+ ClassKind.ENUM_ENTRY -> Kind.EnumItem
+ else -> Kind.Class
+ }
+ val node = DocumentationNode(this, kind)
+ node.appendSupertypes(this)
+ if (getKind() != ClassKind.OBJECT) {
+ node.appendChildren(getTypeConstructor().getParameters(), DocumentationReference.Kind.Detail)
+ node.appendChildren(getConstructors(), DocumentationReference.Kind.Member)
+ val classObjectDescriptor = getClassObjectDescriptor()
+ if (classObjectDescriptor != null)
+ node.appendChild(classObjectDescriptor, DocumentationReference.Kind.Member)
+ }
+ node.appendChildren(getDefaultType().getMemberScope().getAllDescriptors(), DocumentationReference.Kind.Member)
+ register(this, node)
+ return node
+ }
+
+ fun ConstructorDescriptor.build(): DocumentationNode {
+ val node = DocumentationNode(this, Kind.Constructor)
+ node.appendChildren(getValueParameters(), DocumentationReference.Kind.Detail)
+ register(this, node)
+ return node
+ }
+
+ fun FunctionDescriptor.build(): DocumentationNode {
+ val node = DocumentationNode(this, Kind.Function)
+
+ node.appendChildren(getTypeParameters(), DocumentationReference.Kind.Detail)
+ getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
+ node.appendChildren(getValueParameters(), DocumentationReference.Kind.Detail)
+ node.appendType(getReturnType())
+ register(this, node)
+ return node
+
+ }
+
+ fun PropertyDescriptor.build(): DocumentationNode {
+ val node = DocumentationNode(this, Kind.Property)
+ node.appendChildren(getTypeParameters(), DocumentationReference.Kind.Detail)
+ getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
+ node.appendType(getReturnType())
+ getGetter()?.let {
+ if (!it.isDefault())
+ node.appendChild(it, DocumentationReference.Kind.Member)
+ }
+ getSetter()?.let {
+ if (!it.isDefault())
+ node.appendChild(it, DocumentationReference.Kind.Member)
+ }
+
+ register(this, node)
+ return node
+ }
+
+ fun ValueParameterDescriptor.build(): DocumentationNode {
+ val node = DocumentationNode(this, Kind.Parameter)
+ node.appendType(getType())
+ return node
+ }
+
+ fun TypeParameterDescriptor.build(): DocumentationNode {
+ val doc = parseDocumentation(this)
+ val name = getName().asString()
+ val prefix = when (getVariance()) {
+ Variance.IN_VARIANCE -> "in "
+ Variance.OUT_VARIANCE -> "out "
+ else -> ""
+ }
+
+ val node = DocumentationNode(prefix + name, doc, DocumentationNode.Kind.TypeParameter)
+
+ val builtIns = KotlinBuiltIns.getInstance()
+ for (constraint in getUpperBounds()) {
+ if (constraint == builtIns.getDefaultBound())
+ continue
+ val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.UpperBound)
+ node.append(constraintNode, DocumentationReference.Kind.Detail)
+ }
+
+ for (constraint in getLowerBounds()) {
+ if (builtIns.isNothing(constraint))
+ continue
+ val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.LowerBound)
+ node.append(constraintNode, DocumentationReference.Kind.Detail)
+ }
+ return node
+ }
+
+ fun ReceiverParameterDescriptor.build(): DocumentationNode {
+ val node = DocumentationNode(getName().asString(), Content.Empty, Kind.Receiver)
+ node.appendType(getType())
+ return node
+ }
+
+ /**
+ * Generates cross-references for documentation such as extensions for a type, inheritors, etc
+ *
+ * $receiver: [DocumentationContext] for node/descriptor resolutions
+ * $node: [DocumentationNode] to visit
+ */
+ public fun resolveReferences(node: DocumentationNode) {
+ node.details(DocumentationNode.Kind.Receiver).forEach { detail ->
+ val receiverType = detail.detail(DocumentationNode.Kind.Type)
+ val descriptor = links[receiverType]
+ if (descriptor != null) {
+ val typeNode = descriptorToNode[descriptor]
+ // if typeNode is null, extension is to external type like in a library
+ // should we create dummy node here?
+ typeNode?.addReferenceTo(node, DocumentationReference.Kind.Extension)
+ }
+ }
+ node.details(DocumentationNode.Kind.Supertype).forEach { detail ->
+ val descriptor = links[detail]
+ if (descriptor != null) {
+ val typeNode = descriptorToNode[descriptor]
+ typeNode?.addReferenceTo(node, DocumentationReference.Kind.Inheritor)
+ }
+ }
+ node.details.forEach { detail ->
+ val descriptor = links[detail]
+ if (descriptor != null) {
+ val typeNode = descriptorToNode[descriptor]
+ if (typeNode != null) {
+ detail.addReferenceTo(typeNode, DocumentationReference.Kind.Link)
+ }
+ }
+ }
+
+ resolveContentLinks(node, node.content)
+
+ for (child in node.members) {
+ resolveReferences(child)
+ }
+ for (child in node.details) {
+ resolveReferences(child)
+ }
+ }
+
+ fun getResolutionScope(node: DocumentationNode): JetScope {
+ val descriptor = nodeToDescriptor[node] ?: throw IllegalArgumentException("Node is not known to this context")
+ return getResolutionScope(descriptor)
+ }
+
+ fun resolveContentLinks(node: DocumentationNode, content: ContentNode) {
+ val snapshot = content.children.toList()
+ for (child in snapshot) {
+ if (child is ContentExternalLink) {
+ val referenceText = child.href
+ if (Name.isValidIdentifier(referenceText)) {
+ val scope = getResolutionScope(node)
+ val symbolName = Name.guess(referenceText)
+ val symbol = scope.getLocalVariable(symbolName) ?:
+ scope.getProperties(symbolName).firstOrNull() ?:
+ scope.getFunctions(symbolName).firstOrNull() ?:
+ scope.getClassifier(symbolName)
+
+ if (symbol != null) {
+ val targetNode = descriptorToNode[symbol]
+ val contentLink = if (targetNode != null) ContentNodeLink(targetNode) else ContentExternalLink("#")
+
+ val index = content.children.indexOf(child)
+ content.children.remove(index)
+ contentLink.children.addAll(child.children)
+ content.children.add(index, contentLink)
+ }
+ }
+ }
+ resolveContentLinks(node, child)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Kotlin/DocumentationBuildingVisitor.kt b/src/Kotlin/DocumentationBuildingVisitor.kt
deleted file mode 100644
index 81ac2430..00000000
--- a/src/Kotlin/DocumentationBuildingVisitor.kt
+++ /dev/null
@@ -1,127 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.jet.lang.descriptors.*
-import org.jetbrains.jet.lang.resolve.name.*
-import org.jetbrains.jet.lang.resolve.*
-
-public data class DocumentationOptions(val includeNonPublic: Boolean = false)
-
-class DocumentationBuildingVisitor(val context: BindingContext,
- val options: DocumentationOptions,
- private val worker: DeclarationDescriptorVisitor<DocumentationNode, DocumentationNode>)
-: DeclarationDescriptorVisitor<DocumentationNode, DocumentationNode> {
-
- val visibleToDocumentation = setOf(Visibilities.INTERNAL, Visibilities.PROTECTED, Visibilities.PUBLIC)
-
- private fun visitChildren(descriptors: Collection<DeclarationDescriptor>, data: DocumentationNode) {
- for (descriptor in descriptors) {
- visitChild(descriptor, data)
- }
- }
-
- private fun visitChild(descriptor: DeclarationDescriptor?, data: DocumentationNode) {
- if (descriptor != null && descriptor.isUserCode()) {
- if (options.includeNonPublic
- || descriptor !is MemberDescriptor
- || descriptor.getVisibility() in visibleToDocumentation) {
- descriptor.accept(this, data)
- }
- }
- }
-
- private fun createDocumentation(descriptor: DeclarationDescriptor, data: DocumentationNode): DocumentationNode {
- return descriptor.accept(worker, data)
- }
-
- private fun processCallable(descriptor: CallableDescriptor, data: DocumentationNode): DocumentationNode {
- val node = createDocumentation(descriptor, data)
- visitChildren(descriptor.getTypeParameters(), node)
- visitChild(descriptor.getExtensionReceiverParameter(), node)
- visitChildren(descriptor.getValueParameters(), node)
- return node
- }
-
- public override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = createDocumentation(descriptor!!, data!!)
- visitChildren(descriptor.getMemberScope().getAllDescriptors(), node)
- return node
- }
-
- public override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = createDocumentation(descriptor!!, data!!)
- visitChildren(descriptor.getMemberScope().getAllDescriptors(), node)
- return node
- }
-
- public override fun visitVariableDescriptor(descriptor: VariableDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = processCallable(descriptor!!, data!!)
- return node
- }
-
- public override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = processCallable(descriptor!!, data!!)
- visitChild(descriptor.getGetter(), node)
- visitChild(descriptor.getSetter(), node)
- return node
- }
-
- public override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = processCallable(descriptor!!, data!!)
- return node
- }
-
- public override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = createDocumentation(descriptor!!, data!!)
- return node
- }
-
- public override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = createDocumentation(descriptor!!, data!!)
- if (descriptor.getKind() != ClassKind.OBJECT) {
- // do not go inside object for class object and constructors, they are generated
- visitChildren(descriptor.getTypeConstructor().getParameters(), node)
- visitChildren(descriptor.getConstructors(), node)
- visitChild(descriptor.getClassObjectDescriptor(), node)
- }
- visitChildren(descriptor.getDefaultType().getMemberScope().getAllDescriptors(), node)
- return node
- }
-
- public override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: DocumentationNode): DocumentationNode {
- val node = createDocumentation(descriptor, data)
- visitChild(descriptor.getPackage(FqName.ROOT), node)
- return node
- }
-
- public override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = createDocumentation(descriptor!!, data!!)
- visitChildren(descriptor.getValueParameters(), node)
- return node
- }
-
- public override fun visitScriptDescriptor(scriptDescriptor: ScriptDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val classDescriptor = scriptDescriptor!!.getClassDescriptor()
- val node = visitClassDescriptor(classDescriptor, data)
- return node
- }
-
- public override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = visitVariableDescriptor(descriptor!!, data)
- return node
- }
-
- public override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = visitFunctionDescriptor(descriptor!!, data)
- return node
- }
-
- public override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = visitFunctionDescriptor(descriptor!!, data)
- return node
- }
-
- public override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = createDocumentation(descriptor!!, data!!)
- return node
- }
-}
diff --git a/src/Kotlin/DocumentationContext.kt b/src/Kotlin/DocumentationContext.kt
deleted file mode 100644
index 95c3ded1..00000000
--- a/src/Kotlin/DocumentationContext.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
-import org.jetbrains.jet.lang.resolve.BindingContext
-import org.jetbrains.jet.lang.resolve.scopes.JetScope
-import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
-import org.jetbrains.jet.lang.resolve.name.FqName
-
-/**
- * Context for documentation generation.
- *
- * Holds information about relations between [nodes](DocumentationNode) and [descriptors](DeclarationDescriptor) during documentation generation
- *
- * $bindingContext: symbol resolution context
- */
-public class DocumentationContext(val bindingContext: BindingContext) {
- val descriptorToNode = hashMapOf<DeclarationDescriptor, DocumentationNode>()
- val nodeToDescriptor = hashMapOf<DocumentationNode, DeclarationDescriptor>()
-
- val relations = hashMapOf<DocumentationNode, DeclarationDescriptor>()
-
- fun attach(node: DocumentationNode, descriptor: DeclarationDescriptor) {
- relations.put(node, descriptor)
- }
-
- fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) {
- descriptorToNode.put(descriptor, node)
- nodeToDescriptor.put(node, descriptor)
- }
-
- fun getResolutionScope(node: DocumentationNode): JetScope {
- val descriptor = nodeToDescriptor[node] ?: throw IllegalArgumentException("Node is not known to this context")
- return bindingContext.getResolutionScope(descriptor)
- }
-
- fun parseDocumentation(descriptor: DeclarationDescriptor): Content {
- val docText = bindingContext.getDocumentationElements(descriptor).map { it.extractText() }.join("\n")
- val tree = MarkdownProcessor.parse(docText)
- //println(tree.toTestString())
- val content = tree.toContent()
- return content
- }
-}
-
-fun BindingContext.createDocumentationModule(name: String,
- module: ModuleDescriptor,
- packages: Set<FqName>,
- options: DocumentationOptions = DocumentationOptions()): DocumentationModule {
- val documentationModule = DocumentationModule(name)
- val context = DocumentationContext(this)
- val visitor = DocumentationNodeBuilder(context)
- for (packageName in packages) {
- val pkg = module.getPackage(packageName)
- pkg!!.accept(DocumentationBuildingVisitor(this, options, visitor), documentationModule)
- }
-
- context.resolveReferences(documentationModule)
-
- // TODO: Uncomment for resolve verification
- // checkResolveChildren(documentationModule)
- return documentationModule
-}
diff --git a/src/Kotlin/DocumentationNodeBuilder.kt b/src/Kotlin/DocumentationNodeBuilder.kt
deleted file mode 100644
index 8f77a3d6..00000000
--- a/src/Kotlin/DocumentationNodeBuilder.kt
+++ /dev/null
@@ -1,206 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
-import org.jetbrains.jet.lang.descriptors.MemberDescriptor
-import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
-import org.jetbrains.jet.lang.types.JetType
-import org.jetbrains.jet.lang.descriptors.Named
-import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor
-import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
-import org.jetbrains.jet.lang.descriptors.ClassDescriptor
-import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
-import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
-import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
-import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
-import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor
-import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor
-import org.jetbrains.jet.lang.descriptors.ClassKind
-import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
-import org.jetbrains.jet.lang.types.TypeProjection
-import org.jetbrains.jet.lang.types.Variance
-
-class DocumentationNodeBuilder(val context: DocumentationContext) : DeclarationDescriptorVisitorEmptyBodies<DocumentationNode, DocumentationNode>() {
-
- fun reference(from: DocumentationNode, to: DocumentationNode, kind: DocumentationReference.Kind) {
- from.addReferenceTo(to, kind)
- when (kind) {
- DocumentationReference.Kind.Detail -> to.addReferenceTo(from, DocumentationReference.Kind.Owner)
- DocumentationReference.Kind.Member -> to.addReferenceTo(from, DocumentationReference.Kind.Owner)
- DocumentationReference.Kind.Owner -> to.addReferenceTo(from, DocumentationReference.Kind.Member)
- }
- }
-
- fun addModality(descriptor: MemberDescriptor, data: DocumentationNode) {
- val modifier = descriptor.getModality().name().toLowerCase()
- val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier)
- reference(data, node, DocumentationReference.Kind.Detail)
- }
-
- fun addVisibility(descriptor: MemberDescriptor, data: DocumentationNode) {
- val modifier = descriptor.getVisibility().toString()
- val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier)
- reference(data, node, DocumentationReference.Kind.Detail)
- }
-
- fun addSupertypes(descriptor: ClassDescriptor, data: DocumentationNode) {
- val superTypes = descriptor.getTypeConstructor().getSupertypes()
- for (superType in superTypes) {
- if (superType.toString() != "Any")
- addType(superType, data, DocumentationNode.Kind.Supertype)
- }
- }
-
- fun addProjection(projection: TypeProjection, data: DocumentationNode, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) {
- val prefix = when (projection.getProjectionKind()) {
- Variance.IN_VARIANCE -> "in "
- Variance.OUT_VARIANCE -> "out "
- else -> ""
- }
- addType(projection.getType(), data, kind, prefix)
- }
-
- fun addType(jetType: JetType?, data: DocumentationNode, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix : String = "") {
- if (jetType == null)
- return
- val classifierDescriptor = jetType.getConstructor().getDeclarationDescriptor()
- val name = when (classifierDescriptor) {
- is Named -> prefix + classifierDescriptor.getName().asString() + if (jetType.isNullable()) "?" else ""
- else -> "<anonymous>"
- }
- val node = DocumentationNode(name, Content.Empty, kind)
- if (classifierDescriptor != null)
- context.attach(node, classifierDescriptor)
-
- reference(data, node, DocumentationReference.Kind.Detail)
- for (typeArgument in jetType.getArguments())
- addProjection(typeArgument, node)
- }
-
- override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val doc = context.parseDocumentation(descriptor)
- val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Unknown)
- reference(data!!, node, DocumentationReference.Kind.Member)
- context.register(descriptor, node)
- return node
- }
-
- override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val node = DocumentationNode(descriptor.getName().asString(), Content.Empty, DocumentationNode.Kind.Receiver)
- reference(data!!, node, DocumentationReference.Kind.Detail)
-
- addType(descriptor.getType(), node)
-
- return node
- }
-
- override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val doc = context.parseDocumentation(descriptor)
- val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Parameter)
- reference(data!!, node, DocumentationReference.Kind.Detail)
-
- addType(descriptor.getType(), node)
-
- return node
- }
-
- override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val doc = context.parseDocumentation(descriptor)
- val node = DocumentationNode(descriptor.getName().asString(), doc, when (descriptor.getKind()) {
- ClassKind.OBJECT -> org.jetbrains.dokka.DocumentationNode.Kind.Object
- ClassKind.CLASS_OBJECT -> org.jetbrains.dokka.DocumentationNode.Kind.Object
- ClassKind.TRAIT -> org.jetbrains.dokka.DocumentationNode.Kind.Interface
- ClassKind.ENUM_CLASS -> org.jetbrains.dokka.DocumentationNode.Kind.Enum
- ClassKind.ENUM_ENTRY -> org.jetbrains.dokka.DocumentationNode.Kind.EnumItem
- else -> DocumentationNode.Kind.Class
- })
- reference(data!!, node, DocumentationReference.Kind.Member)
- addModality(descriptor, node)
- addVisibility(descriptor, node)
- addSupertypes(descriptor, node)
- context.register(descriptor, node)
- return node
- }
-
- override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val doc = context.parseDocumentation(descriptor)
- val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Function)
- reference(data!!, node, DocumentationReference.Kind.Member)
-
- addType(descriptor.getReturnType(), node)
- addModality(descriptor, node)
- addVisibility(descriptor, node)
- context.register(descriptor, node)
- return node
- }
-
- override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val doc = context.parseDocumentation(descriptor)
- val name = descriptor.getName().asString()
- val prefix = when (descriptor.getVariance()) {
- Variance.IN_VARIANCE -> "in "
- Variance.OUT_VARIANCE -> "out "
- else -> ""
- }
-
- val node = DocumentationNode(prefix + name, doc, DocumentationNode.Kind.TypeParameter)
- reference(data!!, node, DocumentationReference.Kind.Detail)
- val builtIns = KotlinBuiltIns.getInstance()
- for (constraint in descriptor.getUpperBounds()) {
- if (constraint == builtIns.getDefaultBound())
- continue
- val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.UpperBound)
- reference(node, constraintNode, DocumentationReference.Kind.Detail)
- }
- for (constraint in descriptor.getLowerBounds()) {
- if (builtIns.isNothing(constraint))
- continue
- val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.LowerBound)
- reference(node, constraintNode, DocumentationReference.Kind.Detail)
- }
- return node
- }
-
- override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val doc = context.parseDocumentation(descriptor)
- val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Property)
- reference(data!!, node, DocumentationReference.Kind.Member)
-
- addType(descriptor.getType(), node)
- addModality(descriptor, node)
- addVisibility(descriptor, node)
- context.register(descriptor, node)
- return node
- }
-
- override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val doc = context.parseDocumentation(descriptor)
- val node = DocumentationNode("<constructor>", doc, DocumentationNode.Kind.Constructor)
- reference(data!!, node, DocumentationReference.Kind.Member)
-
- addVisibility(descriptor, node)
- context.register(descriptor, node)
- return node
- }
-
- override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val node = DocumentationNode(descriptor.getFqName().asString(), Content.Empty, DocumentationNode.Kind.Package)
- reference(data!!, node, DocumentationReference.Kind.Member)
- return node
- }
-
- override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? {
- descriptor!!
- val node = DocumentationNode(descriptor.fqName.asString(), Content.Empty, DocumentationNode.Kind.Package)
- reference(data!!, node, DocumentationReference.Kind.Member)
- return node
- }
-} \ No newline at end of file
diff --git a/src/Languages/KotlinLanguageService.kt b/src/Kotlin/KotlinLanguageService.kt
index f806dd19..c7fabda9 100644
--- a/src/Languages/KotlinLanguageService.kt
+++ b/src/Kotlin/KotlinLanguageService.kt
@@ -1,29 +1,35 @@
package org.jetbrains.dokka
-import org.jetbrains.dokka.DocumentationNode.*
+import org.jetbrains.dokka.symbol
+import org.jetbrains.dokka.text
+import org.jetbrains.dokka.identifier
+import org.jetbrains.dokka.link
+import org.jetbrains.dokka.keyword
+import org.jetbrains.dokka.LanguageService
+import org.jetbrains.dokka.DocumentationNode
+import org.jetbrains.dokka.ContentNode
+import org.jetbrains.dokka
+import org.jetbrains.dokka.ContentText
-/**
- * Implements [LanguageService] and provides rendering of symbols in Kotlin language
- */
class KotlinLanguageService : LanguageService {
override fun render(node: DocumentationNode): ContentNode {
- return content {
+ return dokka.content {
when (node.kind) {
- Kind.Package -> renderPackage(node)
- Kind.Class,
- Kind.Interface,
- Kind.Enum,
- Kind.EnumItem,
- Kind.Object -> renderClass(node)
-
- Kind.TypeParameter -> renderTypeParameter(node)
- Kind.Type,
- Kind.UpperBound -> renderType(node)
-
- Kind.Modifier -> renderModifier(node)
- Kind.Constructor,
- Kind.Function -> renderFunction(node)
- Kind.Property -> renderProperty(node)
+ DocumentationNode.Kind.Package -> renderPackage(node)
+ DocumentationNode.Kind.Class,
+ DocumentationNode.Kind.Interface,
+ DocumentationNode.Kind.Enum,
+ DocumentationNode.Kind.EnumItem,
+ DocumentationNode.Kind.Object -> renderClass(node)
+
+ DocumentationNode.Kind.TypeParameter -> renderTypeParameter(node)
+ DocumentationNode.Kind.Type,
+ DocumentationNode.Kind.UpperBound -> renderType(node)
+
+ DocumentationNode.Kind.Modifier -> renderModifier(node)
+ DocumentationNode.Kind.Constructor,
+ DocumentationNode.Kind.Function -> renderFunction(node)
+ DocumentationNode.Kind.Property -> renderProperty(node)
else -> ContentText("${node.kind}: ${node.name}")
}
}
@@ -31,7 +37,7 @@ class KotlinLanguageService : LanguageService {
override fun renderName(node: DocumentationNode): String {
return when (node.kind) {
- Kind.Constructor -> node.owner!!.name
+ DocumentationNode.Kind.Constructor -> node.owner!!.name
else -> node.name
}
}
@@ -63,7 +69,7 @@ class KotlinLanguageService : LanguageService {
}
private fun ContentNode.renderType(node: DocumentationNode) {
- val typeArguments = node.details(Kind.Type)
+ val typeArguments = node.details(DocumentationNode.Kind.Type)
if (node.name == "Function${typeArguments.count() - 1}") {
// lambda
symbol("(")
@@ -104,14 +110,16 @@ class KotlinLanguageService : LanguageService {
private fun ContentNode.renderModifier(node: DocumentationNode) {
when (node.name) {
- "final", "internal" -> {
+ "final", "internal" -> {}
+ else -> {
+ keyword(node.name)
+ text(" ")
}
- else -> keyword(node.name)
}
}
private fun ContentNode.renderTypeParameter(node: DocumentationNode) {
- val constraints = node.details(Kind.UpperBound)
+ val constraints = node.details(DocumentationNode.Kind.UpperBound)
identifier(node.name)
if (constraints.any()) {
symbol(" : ")
@@ -124,12 +132,12 @@ class KotlinLanguageService : LanguageService {
private fun ContentNode.renderParameter(node: DocumentationNode) {
identifier(node.name)
symbol(": ")
- val parameterType = node.detail(Kind.Type)
+ val parameterType = node.detail(DocumentationNode.Kind.Type)
renderType(parameterType)
}
private fun ContentNode.renderTypeParametersForNode(node: DocumentationNode) {
- val typeParameters = node.details(Kind.TypeParameter)
+ val typeParameters = node.details(DocumentationNode.Kind.TypeParameter)
if (typeParameters.any()) {
symbol("<")
renderList(typeParameters) {
@@ -140,7 +148,7 @@ class KotlinLanguageService : LanguageService {
}
private fun ContentNode.renderSupertypesForNode(node: DocumentationNode) {
- val supertypes = node.details(Kind.Supertype)
+ val supertypes = node.details(DocumentationNode.Kind.Supertype)
if (supertypes.any()) {
symbol(" : ")
renderList(supertypes) {
@@ -150,23 +158,22 @@ class KotlinLanguageService : LanguageService {
}
private fun ContentNode.renderModifiersForNode(node: DocumentationNode) {
- val modifiers = node.details(Kind.Modifier)
+ val modifiers = node.details(DocumentationNode.Kind.Modifier)
for (it in modifiers) {
- if (node.kind == Kind.Interface && it.name == "abstract")
+ if (node.kind == org.jetbrains.dokka.DocumentationNode.Kind.Interface && it.name == "abstract")
continue
renderModifier(it)
- text(" ")
}
}
private fun ContentNode.renderClass(node: DocumentationNode) {
renderModifiersForNode(node)
when (node.kind) {
- Kind.Class -> keyword("class ")
- Kind.Interface -> keyword("trait ")
- Kind.Enum -> keyword("enum class ")
- Kind.EnumItem -> keyword("enum val ")
- Kind.Object -> keyword("object ")
+ DocumentationNode.Kind.Class -> keyword("class ")
+ DocumentationNode.Kind.Interface -> keyword("trait ")
+ DocumentationNode.Kind.Enum -> keyword("enum class ")
+ DocumentationNode.Kind.EnumItem -> keyword("enum val ")
+ DocumentationNode.Kind.Object -> keyword("object ")
else -> throw IllegalArgumentException("Node $node is not a class-like object")
}
@@ -178,46 +185,46 @@ class KotlinLanguageService : LanguageService {
private fun ContentNode.renderFunction(node: DocumentationNode) {
renderModifiersForNode(node)
when (node.kind) {
- Kind.Constructor -> identifier(node.owner!!.name)
- Kind.Function -> keyword("fun ")
+ DocumentationNode.Kind.Constructor -> identifier(node.owner!!.name)
+ DocumentationNode.Kind.Function -> keyword("fun ")
else -> throw IllegalArgumentException("Node $node is not a function-like object")
}
renderTypeParametersForNode(node)
- val receiver = node.details(Kind.Receiver).singleOrNull()
+ val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull()
if (receiver != null) {
- renderType(receiver.detail(Kind.Type))
+ renderType(receiver.detail(DocumentationNode.Kind.Type))
symbol(".")
}
- if (node.kind != Kind.Constructor)
+ if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor)
identifier(node.name)
symbol("(")
- renderList(node.details(Kind.Parameter)) {
+ renderList(node.details(DocumentationNode.Kind.Parameter)) {
renderParameter(it)
}
symbol(")")
- if (node.kind != Kind.Constructor) {
+ if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor) {
symbol(": ")
- renderType(node.detail(Kind.Type))
+ renderType(node.detail(DocumentationNode.Kind.Type))
}
}
private fun ContentNode.renderProperty(node: DocumentationNode) {
renderModifiersForNode(node)
when (node.kind) {
- Kind.Property -> keyword("val ")
+ DocumentationNode.Kind.Property -> keyword("val ")
else -> throw IllegalArgumentException("Node $node is not a property")
}
renderTypeParametersForNode(node)
- val receiver = node.details(Kind.Receiver).singleOrNull()
+ val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull()
if (receiver != null) {
- renderType(receiver.detail(Kind.Type))
+ renderType(receiver.detail(DocumentationNode.Kind.Type))
symbol(".")
}
identifier(node.name)
symbol(": ")
- renderType(node.detail(Kind.Type))
+ renderType(node.detail(DocumentationNode.Kind.Type))
}
} \ No newline at end of file
diff --git a/src/Kotlin/ResolveReferences.kt b/src/Kotlin/ResolveReferences.kt
deleted file mode 100644
index 1349c69e..00000000
--- a/src/Kotlin/ResolveReferences.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.jet.lang.resolve.name.Name
-
-/**
- * Generates cross-references for documentation such as extensions for a type, inheritors, etc
- *
- * $receiver: [DocumentationContext] for node/descriptor resolutions
- * $node: [DocumentationNode] to visit
- */
-public fun DocumentationContext.resolveReferences(node: DocumentationNode) {
- node.details(DocumentationNode.Kind.Receiver).forEach { detail ->
- val receiverType = detail.detail(DocumentationNode.Kind.Type)
- val descriptor = relations[receiverType]
- if (descriptor != null) {
- val typeNode = descriptorToNode[descriptor]
- // if typeNode is null, extension is to external type like in a library
- // should we create dummy node here?
- typeNode?.addReferenceTo(node, DocumentationReference.Kind.Extension)
- }
- }
- node.details(DocumentationNode.Kind.Supertype).forEach { detail ->
- val descriptor = relations[detail]
- if (descriptor != null) {
- val typeNode = descriptorToNode[descriptor]
- typeNode?.addReferenceTo(node, DocumentationReference.Kind.Inheritor)
- }
- }
- node.details.forEach { detail ->
- val descriptor = relations[detail]
- if (descriptor != null) {
- val typeNode = descriptorToNode[descriptor]
- if (typeNode != null) {
- detail.addReferenceTo(typeNode, DocumentationReference.Kind.Link)
- }
- }
- }
-
- resolveContentLinks(node, node.doc)
-
- for (child in node.members) {
- resolveReferences(child)
- }
- for (child in node.details) {
- resolveReferences(child)
- }
-}
-
-fun DocumentationContext.resolveContentLinks(node: DocumentationNode, content: ContentNode) {
- val snapshot = content.children.toList()
- for (child in snapshot) {
- if (child is ContentExternalLink) {
- val referenceText = child.href
- if (Name.isValidIdentifier(referenceText)) {
- val scope = getResolutionScope(node)
- val symbolName = Name.guess(referenceText)
- val symbol = scope.getLocalVariable(symbolName) ?:
- scope.getProperties(symbolName).firstOrNull() ?:
- scope.getFunctions(symbolName).firstOrNull() ?:
- scope.getClassifier(symbolName)
-
- if (symbol != null) {
- val targetNode = descriptorToNode[symbol]
- val contentLink = if (targetNode != null) ContentNodeLink(targetNode) else ContentExternalLink("#")
-
- val index = content.children.indexOf(child)
- content.children.remove(index)
- contentLink.children.addAll(child.children)
- content.children.add(index, contentLink)
- }
- }
- }
- resolveContentLinks(node, child)
- }
-} \ No newline at end of file
diff --git a/src/Locations/LocationService.kt b/src/Locations/LocationService.kt
index f89fedd0..3c3ed3e1 100644
--- a/src/Locations/LocationService.kt
+++ b/src/Locations/LocationService.kt
@@ -12,7 +12,7 @@ public trait LocationService {
}
-public fun escapeUri(path: String): String = path.replace('<', '_').replace('>', '_')
+public fun escapeUri(path: String): String = path.replace('<', '-').replace('>', '-')
fun LocationService.relativeLocation(owner: DocumentationNode, node: DocumentationNode, extension: String): Location {
return relativeLocation(location(owner), node, extension)
diff --git a/src/Markdown/MarkdownProcessor.kt b/src/Markdown/MarkdownProcessor.kt
index 19d5a8fb..040f2ad5 100644
--- a/src/Markdown/MarkdownProcessor.kt
+++ b/src/Markdown/MarkdownProcessor.kt
@@ -30,7 +30,7 @@ public class MarkdownTree(private val text: String, private val structure: Flywe
}
fun findChildByType(node: LighterASTNode, findType: IElementType) : LighterASTNode? {
- val ref = Ref.create<Array<LighterASTNode>?>()
+ val ref: Ref<Array<LighterASTNode>?> = Ref.create<Array<LighterASTNode>?>()
val count = structure.getChildren(node, ref)
val children = ref.get()
if (children != null) {
@@ -53,7 +53,7 @@ public class MarkdownTree(private val text: String, private val structure: Flywe
fun visit(node: LighterASTNode, action: (LighterASTNode, String, visitChildren: () -> Unit) -> Unit) {
action(node, text) {
- val ref = Ref.create<Array<LighterASTNode>?>()
+ val ref : Ref<Array<LighterASTNode>?> = Ref.create<Array<LighterASTNode>?>()
val count = structure.getChildren(node, ref)
val children = ref.get()
if (children != null) {
diff --git a/src/Markdown/markdown.bnf b/src/Markdown/markdown.bnf
index d6fd2ed2..2e4979ec 100644
--- a/src/Markdown/markdown.bnf
+++ b/src/Markdown/markdown.bnf
@@ -47,6 +47,7 @@ Block ::= BlankLine* (
OrderedList
| BulletList
| HorizontalRule
+ | Directive
| Para
)
@@ -58,6 +59,10 @@ HorizontalRule ::= NonindentSpace
| '_' OptionalSpace '_' OptionalSpace '_' (OptionalSpace '_')*)
OptionalSpace EOL BlankLine+
+Directive ::= '{' DirectiveName Space+ DirectiveParams '}'
+DirectiveName ::= Word
+DirectiveParams ::= PlainText
+
Bullet ::= !HorizontalRule NonindentSpace ('+' | '*' | '-') Space+
Enumerator ::= NonindentSpace Number '.' Space+
@@ -75,13 +80,15 @@ ListContinuationBlock ::= BlankLine* (Indent ListBlock)+
// ---- INLINES ----
private Inlines ::= (!EndLine Inline | EndLine &Inline )+ EndLine?
-Inline ::= Strong | Emph | Link | PlainText
-PlainText ::= (Word | Number | Space+)+
+Inline ::= Strong | Emph | Code | Link | PlainText
+PlainText ::= (Word | Number | Space | ':')+
Emph ::= EmphStar | EmphUnderscore
private EmphStar ::= '*' !Whitespace (!'*' Inline)+ '*'
private EmphUnderscore ::= '_' !Whitespace (!'_' Inline)+ '_'
+Code ::= '`' !Whitespace (!'`' Inline)+ '`'
+
Strong ::= StrongStar | StrongUnderscore
StrongStar ::= '**' !Whitespace (!'**' Inline)+ '**'
StrongUnderscore ::= '__' !Whitespace (!'__' Inline)+ '__'
diff --git a/src/Model/Content.kt b/src/Model/Content.kt
index ce438835..794faf50 100644
--- a/src/Model/Content.kt
+++ b/src/Model/Content.kt
@@ -23,10 +23,14 @@ public class ContentText(val text: String) : ContentNode()
public class ContentKeyword(val text: String) : ContentNode()
public class ContentIdentifier(val text: String) : ContentNode()
public class ContentSymbol(val text: String) : ContentNode()
+
+public class ContentParagraph() : ContentBlock()
public class ContentEmphasis() : ContentBlock()
+public class ContentStrong() : ContentBlock()
+public class ContentCode() : ContentBlock()
+public class ContentBlockCode() : ContentBlock()
public class ContentNodeLink(val node : DocumentationNode) : ContentBlock()
public class ContentExternalLink(val href : String) : ContentBlock()
-public class ContentStrong() : ContentBlock()
public class ContentList() : ContentBlock()
public class ContentSection(public val label: String) : ContentBlock()
@@ -49,7 +53,7 @@ fun ContentNode.link(to: DocumentationNode, body: ContentNode.() -> Unit) {
public class Content() : ContentNode() {
public val sections: Map<String, ContentSection> by Delegates.lazy {
- val map = hashMapOf<String, ContentSection>()
+ val map = linkedMapOf<String, ContentSection>()
for (child in children) {
if (child is ContentSection)
map.put(child.label, child)
@@ -80,7 +84,9 @@ public class Content() : ContentNode() {
map
}
- public val summary: ContentNode get() = sections["\$summary"] ?: ContentNode.empty
+ public val summary: ContentNode get() {
+ return sections["\$summary"] ?: ContentNode.empty
+ }
public val description: ContentNode get() = sections["\$description"] ?: ContentNode.empty
override fun equals(other: Any?): Boolean {
diff --git a/src/Model/DocumentationModule.kt b/src/Model/DocumentationModule.kt
index 6084ea5e..e74c544b 100644
--- a/src/Model/DocumentationModule.kt
+++ b/src/Model/DocumentationModule.kt
@@ -1,6 +1,6 @@
package org.jetbrains.dokka
-public class DocumentationModule(name: String) : DocumentationNode(name, Content.Empty, DocumentationNode.Kind.Module) {
+public class DocumentationModule(name: String, content: Content = Content.Empty) : DocumentationNode(name, content, DocumentationNode.Kind.Module) {
fun merge(other: DocumentationModule): DocumentationModule {
val model = DocumentationModule(name)
model.addAllReferencesFrom(other)
diff --git a/src/Model/DocumentationNode.kt b/src/Model/DocumentationNode.kt
index 18efaa9b..2be5bf15 100644
--- a/src/Model/DocumentationNode.kt
+++ b/src/Model/DocumentationNode.kt
@@ -3,11 +3,21 @@ package org.jetbrains.dokka
import java.util.LinkedHashSet
public open class DocumentationNode(val name: String,
- val doc: Content,
+ val content: Content,
val kind: DocumentationNode.Kind) {
private val references = LinkedHashSet<DocumentationReference>()
+ public val summary: ContentNode get() {
+ val contentSection = content.sections["\$summary"]
+ if (contentSection != null)
+ return contentSection
+ val ownerSection = owner?.content?.sections?.get(name)
+ if (ownerSection != null)
+ return ownerSection
+ return ContentNode.empty
+ }
+
public val owner: DocumentationNode?
get() = references(DocumentationReference.Kind.Owner).singleOrNull()?.to
public val details: List<DocumentationNode>
diff --git a/src/main.kt b/src/main.kt
index 970bbd8c..6f5cf796 100644
--- a/src/main.kt
+++ b/src/main.kt
@@ -6,11 +6,22 @@ import org.jetbrains.jet.cli.common.messages.*
import org.jetbrains.jet.cli.common.arguments.*
import org.jetbrains.jet.utils.PathUtil
import java.io.File
+import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
+import org.jetbrains.jet.lang.resolve.name.FqName
+import java.lang.reflect.Constructor
class DokkaArguments {
Argument(value = "src", description = "Source file or directory (allows many paths separated by the system path separator)")
ValueDescription("<path>")
- public var src: String? = null
+ public var src: String = ""
+
+ Argument(value = "include", description = "Markdown files to load (allows many paths separated by the system path separator)")
+ ValueDescription("<path>")
+ public var include: String = ""
+
+ Argument(value = "samples", description = "Source root for samples")
+ ValueDescription("<path>")
+ public var samples: String = ""
Argument(value = "output", description = "Output directory path for .md files")
ValueDescription("<path>")
@@ -23,21 +34,25 @@ class DokkaArguments {
Argument(value = "classpath", description = "Classpath for symbol resolution")
ValueDescription("<path>")
public var classpath: String = ""
+
}
public fun main(args: Array<String>) {
-
val arguments = DokkaArguments()
- val sourceFiles = Args.parse(arguments, args)
- val sources: List<String> = sourceFiles ?: listOf()
+ 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 environment = AnalysisEnvironment(MessageCollectorPlainTextToStream.PLAIN_TEXT_TO_SYSTEM_ERR) {
addClasspath(PathUtil.getJdkClassesRoots())
+ // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath())
for (element in arguments.classpath.split(File.pathSeparatorChar)) {
addClasspath(File(element))
}
- // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath())
+
addSources(sources)
+ addSources(samples)
}
println("Module: ${arguments.moduleName}")
@@ -47,15 +62,50 @@ public fun main(args: Array<String>) {
println()
- print("Analysing sources and libraries... ")
+ println("Analysing sources and libraries... ")
val startAnalyse = System.currentTimeMillis()
- val documentation = environment.withContext<DocumentationModule> { environment, module, context ->
- val packageSet = environment.getSourceFiles().map { file ->
- context.getPackageFragment(file)!!.fqName
- }.toSet()
- context.createDocumentationModule(arguments.moduleName, module, packageSet)
+
+ val documentation = environment.withContext { environment, session ->
+ val fragmentFiles = environment.getSourceFiles().filter {
+ val sourceFile = File(it.getVirtualFile()!!.getPath())
+ samples.none { sample ->
+ val canonicalSample = File(sample).canonicalPath
+ val canonicalSource = sourceFile.canonicalPath
+ canonicalSource.startsWith(canonicalSample)
+ }
+ }
+ val fragments = fragmentFiles.map { session.getPackageFragment(it.getPackageFqName()) }.filterNotNull().distinct()
+ val options = DocumentationOptions()
+ val documentationBuilder = DocumentationBuilder(session, options)
+
+ with(documentationBuilder) {
+
+ val moduleContent = Content()
+ for (include in includes) {
+ val text = File(include).readText()
+ val tree = MarkdownProcessor.parse(text)
+ val content = buildContent(tree, session.getPackageFragment(FqName.ROOT))
+ moduleContent.children.addAll(content.children)
+ }
+
+ val documentationModule = DocumentationModule(arguments.moduleName, moduleContent)
+
+ val descriptors = hashMapOf<String, List<DeclarationDescriptor>>()
+ for ((name, parts) in fragments.groupBy { it.fqName }) {
+ descriptors.put(name.asString(), parts.flatMap { it.getMemberScope().getAllDescriptors() })
+ }
+ for ((packageName, declarations) in descriptors) {
+ println(" package $packageName: ${declarations.count()} nodes")
+ val packageNode = DocumentationNode(packageName, Content.Empty, DocumentationNode.Kind.Package)
+ packageNode.appendChildren(declarations, DocumentationReference.Kind.Member)
+ documentationModule.append(packageNode, DocumentationReference.Kind.Member)
+ }
+ documentationBuilder.resolveReferences(documentationModule)
+ documentationModule
+ }
}
+
val timeAnalyse = System.currentTimeMillis() - startAnalyse
println("done in ${timeAnalyse / 1000} secs")
@@ -64,9 +114,10 @@ public fun main(args: Array<String>) {
val locationService = FoldersLocationService(arguments.outputDir)
val templateService = HtmlTemplateService.default("/dokka/styles/style.css")
+// val formatter = HtmlFormatService(locationService, signatureGenerator, templateService)
val formatter = KotlinWebsiteFormatService(locationService, signatureGenerator)
val generator = FileGenerator(signatureGenerator, locationService, formatter)
- print("Building pages... ")
+ print("Generating pages... ")
generator.buildPage(documentation)
generator.buildOutline(documentation)
val timeBuild = System.currentTimeMillis() - startBuild