2018-03-01 21:35:00 +09:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2016-2018 Lightbend Inc. <https://www.lightbend.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka
|
|
|
|
|
|
|
|
|
|
import _root_.io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
|
|
|
|
import com.lightbend.paradox.markdown._
|
|
|
|
|
import com.lightbend.paradox.sbt.ParadoxPlugin.autoImport._
|
|
|
|
|
import org.pegdown.Printer
|
2018-03-09 17:12:54 +09:00
|
|
|
import org.pegdown.ast.DirectiveNode.Source
|
2018-03-01 21:35:00 +09:00
|
|
|
import org.pegdown.ast._
|
|
|
|
|
import sbt.Keys._
|
|
|
|
|
import sbt._
|
|
|
|
|
|
|
|
|
|
import scala.collection.JavaConverters._
|
|
|
|
|
|
|
|
|
|
object ParadoxSupport {
|
|
|
|
|
val paradoxWithCustomDirectives = Seq(
|
|
|
|
|
paradoxDirectives ++= Def.taskDyn {
|
|
|
|
|
val classpath = (fullClasspath in Compile).value.files.map(_.toURI.toURL).toArray
|
|
|
|
|
val classloader = new java.net.URLClassLoader(classpath, this.getClass().getClassLoader())
|
|
|
|
|
lazy val scanner = new FastClasspathScanner("akka").addClassLoader(classloader).scan()
|
|
|
|
|
val allClasses = scanner.getNamesOfAllClasses.asScala.toVector
|
|
|
|
|
Def.task { Seq(
|
|
|
|
|
{ _: Writer.Context ⇒ new UnidocDirective(allClasses) }
|
|
|
|
|
)}
|
|
|
|
|
}.value
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
class UnidocDirective(allClasses: IndexedSeq[String]) extends InlineDirective("unidoc") {
|
|
|
|
|
def render(node: DirectiveNode, visitor: Visitor, printer: Printer): Unit = {
|
2018-03-09 17:12:54 +09:00
|
|
|
val (directive, label, source) = node.source match {
|
|
|
|
|
case direct: Source.Direct => (s"@unidoc[${node.label}](${direct.value})", node.label, direct.value)
|
|
|
|
|
case ref: Source.Ref => (s"@unidoc[${node.label}](${ref.value})", node.label, ref.value)
|
|
|
|
|
case Source.Empty => (s"@unidoc[${node.label}]", node.label.split('.').last, node.label)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (source.split('[')(0).contains('.')) {
|
|
|
|
|
val fqcn = source
|
2018-03-01 21:35:00 +09:00
|
|
|
if (allClasses.contains(fqcn)) {
|
|
|
|
|
syntheticNode("java", javaLabel(label), fqcn, node).accept(visitor)
|
2018-03-09 17:12:54 +09:00
|
|
|
syntheticNode("scala", scalaLabel(label), fqcn, node).accept(visitor)
|
2018-03-01 21:35:00 +09:00
|
|
|
} else {
|
2018-03-09 17:12:54 +09:00
|
|
|
throw new java.lang.IllegalStateException(s"fqcn not found by $directive")
|
2018-03-01 21:35:00 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2018-03-09 17:12:54 +09:00
|
|
|
renderByClassName(directive, source, node, visitor, printer)
|
2018-03-01 21:35:00 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-09 17:12:54 +09:00
|
|
|
def javaLabel(splitLabel: String): String =
|
|
|
|
|
splitLabel.replaceAll("\\\\_", "_").replaceAll("\\[", "<").replaceAll("\\]", ">").replace('_', '?')
|
|
|
|
|
|
|
|
|
|
def scalaLabel(splitLabel: String): String =
|
|
|
|
|
splitLabel.replaceAll("\\\\_", "_")
|
2018-03-01 21:35:00 +09:00
|
|
|
|
|
|
|
|
def syntheticNode(group: String, label: String, fqcn: String, node: DirectiveNode): DirectiveNode = {
|
|
|
|
|
val syntheticSource = new DirectiveNode.Source.Direct(fqcn)
|
|
|
|
|
val attributes = new org.pegdown.ast.DirectiveAttributes.AttributeMap()
|
|
|
|
|
new DirectiveNode(DirectiveNode.Format.Inline, group, null, null, attributes, null,
|
|
|
|
|
new DirectiveNode(DirectiveNode.Format.Inline, group + "doc", label, syntheticSource, node.attributes, fqcn,
|
|
|
|
|
new TextNode(label)
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-09 17:12:54 +09:00
|
|
|
def renderByClassName(directive: String, source: String, node: DirectiveNode, visitor: Visitor, printer: Printer): Unit = {
|
|
|
|
|
val sourceWithoutGenericParameters = source.replaceAll("\\\\_", "_").split("\\[")(0)
|
|
|
|
|
val labelWithScalaGenerics = scalaLabel(node.label)
|
|
|
|
|
val labelWithJavaGenerics = javaLabel(node.label)
|
|
|
|
|
val matches = allClasses.filter(_.endsWith('.' + sourceWithoutGenericParameters))
|
2018-03-01 21:35:00 +09:00
|
|
|
matches.size match {
|
|
|
|
|
case 0 =>
|
2018-03-09 17:12:54 +09:00
|
|
|
throw new java.lang.IllegalStateException(
|
|
|
|
|
s"No matches found for $directive. " +
|
|
|
|
|
s"You may want to use the fully qualified class name as @unidoc[fqcn]."
|
|
|
|
|
)
|
2018-03-01 21:35:00 +09:00
|
|
|
case 1 if matches(0).contains("adsl") =>
|
2018-03-09 17:12:54 +09:00
|
|
|
throw new java.lang.IllegalStateException(s"Match for $directive only found in one language: ${matches(0)}")
|
2018-03-01 21:35:00 +09:00
|
|
|
case 1 =>
|
2018-03-09 17:12:54 +09:00
|
|
|
syntheticNode("scala", labelWithScalaGenerics, matches(0), node).accept(visitor)
|
2018-03-01 21:35:00 +09:00
|
|
|
syntheticNode("java", labelWithJavaGenerics, matches(0), node).accept(visitor)
|
|
|
|
|
case 2 if matches.forall(_.contains("adsl")) =>
|
|
|
|
|
matches.foreach(m => {
|
|
|
|
|
if (!m.contains("javadsl"))
|
2018-03-09 17:12:54 +09:00
|
|
|
syntheticNode("scala", labelWithScalaGenerics, m, node).accept(visitor)
|
2018-03-01 21:35:00 +09:00
|
|
|
if (!m.contains("scaladsl"))
|
|
|
|
|
syntheticNode("java", labelWithJavaGenerics, m, node).accept(visitor)
|
|
|
|
|
})
|
|
|
|
|
case n =>
|
|
|
|
|
throw new java.lang.IllegalStateException(
|
2018-03-09 17:12:54 +09:00
|
|
|
s"$n matches found for $directive, but not javadsl/scaladsl: ${matches.mkString(", ")}. " +
|
|
|
|
|
s"You may want to use the fully qualified class name as @unidoc[fqcn] instead of ."
|
2018-03-01 21:35:00 +09:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|