Skip to content

Commit 265ade0

Browse files
authored
Merge pull request #1453 from felixmulder/topic/dottydoc
Add dottydoc
2 parents 76c3e99 + 0b69be6 commit 265ade0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+4315
-70
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
*.DS_Store
22
*.class
33
*.log
4+
*.swp
45
*~
56
*.swp
67

@@ -37,6 +38,7 @@ scala-scala
3738

3839
# Ignore output files but keep the directory
3940
out/
41+
build/
4042
!out/.keep
4143

4244
# Ignore build-file
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/* sbt -- Simple Build Tool
2+
* Copyright 2008, 2009 Mark Harrah
3+
*/
4+
package xsbt
5+
6+
import xsbti.Logger
7+
import dotty.tools.dottydoc.api.scala.Dottydoc
8+
import java.net.URL
9+
10+
class ScaladocInterface {
11+
def run(args: Array[String], log: Logger, delegate: xsbti.Reporter) =
12+
(new DottydocRunner(args, log, delegate)).run()
13+
}
14+
15+
class DottydocRunner(args: Array[String], log: Logger, delegate: xsbti.Reporter) extends Dottydoc {
16+
def run(): Unit = getOutputFolder(args).map { outputFolder =>
17+
val index = createIndex(args)
18+
val resources = getResources(args)
19+
val template = getTemplate(resources)
20+
21+
template.fold(writeJson(index, outputFolder)) { tpl =>
22+
buildDocs(outputFolder, tpl, resources, index)
23+
}
24+
} getOrElse {
25+
delegate.log(
26+
NoPosition,
27+
"No output folder set for API documentation (\"-d\" parameter should be passed to the documentation tool)",
28+
xsbti.Severity.Error
29+
)
30+
}
31+
32+
private[this] val NoPosition = new xsbti.Position {
33+
val line = xsbti.Maybe.nothing[Integer]
34+
val lineContent = ""
35+
val offset = xsbti.Maybe.nothing[Integer]
36+
val sourcePath = xsbti.Maybe.nothing[String]
37+
val sourceFile = xsbti.Maybe.nothing[java.io.File]
38+
val pointer = xsbti.Maybe.nothing[Integer]
39+
val pointerSpace = xsbti.Maybe.nothing[String]
40+
}
41+
42+
private def getStringSetting(name: String): Option[String] =
43+
args find (_.startsWith(name)) map (_.drop(name.length))
44+
45+
private def getOutputFolder(args: Array[String]): Option[String] =
46+
args sliding(2) find { case Array(x, _) => x == "-d" } map (_.tail.head.trim)
47+
48+
private def getTemplate(resources: List[URL]): Option[URL] =
49+
resources.find(_.getFile.endsWith("template.html"))
50+
51+
private def getResources(args: Array[String]): List[URL] = {
52+
val cp = args sliding (2) find { case Array(x, _) => x == "-classpath" } map (_.tail.head.trim) getOrElse ""
53+
54+
cp.split(":").find(_.endsWith("dottydoc-client.jar")).map { resourceJar =>
55+
import java.util.jar.JarFile
56+
val jarEntries = (new JarFile(resourceJar)).entries
57+
var entries: List[URL] = Nil
58+
59+
while (jarEntries.hasMoreElements) {
60+
val entry = jarEntries.nextElement()
61+
62+
if (!entry.isDirectory()) {
63+
val path = s"jar:file:$resourceJar!/${entry.getName}"
64+
val url = new URL(path)
65+
entries = url :: entries
66+
}
67+
}
68+
69+
entries
70+
} getOrElse (Nil)
71+
}
72+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package dotty.tools
2+
package dottydoc
3+
4+
import core._
5+
import core.transform._
6+
import dotc.config.CompilerCommand
7+
import dotc.config.Printers.dottydoc
8+
import dotc.core.Contexts._
9+
import dotc.core.Phases.Phase
10+
import dotc.typer.FrontEnd
11+
import dotc.{ CompilationUnit, Compiler, Driver, Run }
12+
import io.PlainFile
13+
import model.Package
14+
import model.json._
15+
16+
import _root_.java.util.{ Map => JMap }
17+
18+
/** Custom Compiler with phases for the documentation tool
19+
*
20+
* The idea here is to structure `dottydoc` around the new infrastructure. As
21+
* such, dottydoc will itself be a compiler. It will, however, produce a format
22+
* that can be used by other tools or web-browsers.
23+
*
24+
* Example:
25+
* 1. Use the existing FrontEnd to typecheck the code being fed to dottydoc
26+
* 2. Create an AST that is serializable
27+
* 3. Serialize to JS object
28+
*/
29+
class DocCompiler extends Compiler {
30+
override def phases: List[List[Phase]] = List(
31+
List(new DocFrontEnd),
32+
List(new DocImplicitsPhase),
33+
List(new DocASTPhase),
34+
List(DocMiniTransformations(new LinkReturnTypes,
35+
new LinkParamListTypes,
36+
new LinkImplicitlyAddedTypes,
37+
new LinkSuperTypes,
38+
new AlternateConstructors,
39+
new SortMembers))
40+
)
41+
}
42+
43+
class DocFrontEnd extends FrontEnd {
44+
override protected def discardAfterTyper(unit: CompilationUnit)(implicit ctx: Context) =
45+
unit.isJava
46+
}
47+
48+
abstract class DocDriver extends Driver {
49+
import scala.collection.JavaConverters._
50+
51+
override def setup(args: Array[String], rootCtx: Context): (List[String], Context) = {
52+
val ctx = rootCtx.fresh
53+
val summary = CompilerCommand.distill(args)(ctx)
54+
55+
ctx.setSettings(summary.sstate)
56+
ctx.setSetting(ctx.settings.YkeepComments, true)
57+
58+
val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)(ctx)
59+
(fileNames, ctx)
60+
}
61+
62+
override def newCompiler(implicit ctx: Context): Compiler = new DocCompiler
63+
64+
def compiledDocs(args: Array[String]): collection.Map[String, Package] = {
65+
val (fileNames, ctx) = setup(args, initCtx.fresh)
66+
doCompile(newCompiler(ctx), fileNames)(ctx)
67+
68+
ctx.docbase.packages[Package]
69+
}
70+
71+
def compiledDocsJava(args: Array[String]): JMap[String, Package] =
72+
compiledDocs(args).asJava
73+
74+
def indexToJson(index: collection.Map[String, Package]): String =
75+
index.json
76+
77+
def indexToJsonJava(index: JMap[String, Package]): String =
78+
indexToJson(index.asScala)
79+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package dotty.tools.dottydoc.api.java;
2+
3+
import dotty.tools.dottydoc.DocDriver;
4+
import dotty.tools.dottydoc.model.Package;
5+
import dotty.tools.dottydoc.util.OutputWriter;
6+
import java.util.Map;
7+
import java.util.List;
8+
import java.net.URL;
9+
10+
/**
11+
* The Dottydoc API is fairly simple. The tool creates an index by calling:
12+
* "createIndex" with the same argument list as you would the compiler - e.g:
13+
*
14+
* {{{
15+
* String[] array = {
16+
* "-language:Scala2"
17+
* };
18+
*
19+
* Map<String, Package> index = createIndex(array);
20+
* }}}
21+
*
22+
* Once the index has been generated, the tool can also build a documentation
23+
* API given a Mustache template and a flat resources structure (i.e. absolute
24+
* paths to each resource, which will be put in the same directory).
25+
*
26+
* {{{
27+
* buildDocs("path/to/output/dir", templateURL, resources, index);
28+
* }}}
29+
*
30+
* The tool can also generate JSON from the created index using "toJson(index)"
31+
* or directly using "createJsonIndex"
32+
*/
33+
public class Dottydoc extends DocDriver {
34+
35+
/** Creates index from compiler arguments */
36+
public Map<String, Package> createIndex(String[] args) {
37+
return compiledDocsJava(args);
38+
}
39+
40+
/** Creates JSON from compiler arguments */
41+
public String createJsonIndex(String[] args) {
42+
return indexToJsonJava(createIndex(args));
43+
}
44+
45+
public String toJson(Map<String, Package> index) {
46+
return indexToJsonJava(index);
47+
}
48+
49+
/** Creates a documentation from the given parameters */
50+
public void buildDocs(
51+
String outputDir,
52+
URL template,
53+
List<URL> resources,
54+
Map<String, Package> index
55+
) {
56+
new OutputWriter().writeJava(index, outputDir, template, resources);
57+
}
58+
59+
/** Writes JSON to an output directory as "index.json" */
60+
public void writeJson(Map<String, Package> index, String outputDir) {
61+
new OutputWriter().writeJsonJava(index, outputDir);
62+
}
63+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package dotty.tools.dottydoc.api.scala
2+
3+
import dotty.tools.dottydoc.DocDriver
4+
import dotty.tools.dottydoc.model.Package
5+
import dotty.tools.dottydoc.util.OutputWriter
6+
7+
import scala.collection.Map
8+
import java.net.URL
9+
10+
/**
11+
* The Dottydoc API is fairly simple. The tool creates an index by calling:
12+
* "createIndex" with the same argument list as you would the compiler - e.g:
13+
*
14+
* {{{
15+
* val array: Array[String] = Array(
16+
* "-language:Scala2"
17+
* )
18+
*
19+
* val index: Map[String, Package] = createIndex(array)
20+
* }}}
21+
*
22+
* Once the index has been generated, the tool can also build a documentation
23+
* API given a Mustache template and a flat resources structure (i.e. absolute
24+
* paths to each resource, which will be put in the same directory).
25+
*
26+
* {{{
27+
* buildDocs("path/to/output/dir", templateURL, resources, index)
28+
* }}}
29+
*
30+
* The tool can also generate JSON from the created index using "indexToJson"
31+
* or directly using "createJsonIndex"
32+
*/
33+
trait Dottydoc extends DocDriver {
34+
/** Creates index from compiler arguments */
35+
def createIndex(args: Array[String]): Map[String, Package] =
36+
compiledDocs(args)
37+
38+
/** Creates JSON from compiler arguments */
39+
def createJsonIndex(args: Array[String]): String =
40+
indexToJson(compiledDocs(args))
41+
42+
/** Creates a documentation from the given parameters */
43+
def buildDocs(outDir: String, template: URL, resources: List[URL], index: Map[String, Package]) =
44+
new OutputWriter().write(index, outDir, template, resources)
45+
46+
/** Writes JSON to an output directory as "index.json" */
47+
def writeJson(index: Map[String, Package], outputDir: String) =
48+
new OutputWriter().writeJson(index, outputDir)
49+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package dotty.tools
2+
package dottydoc
3+
package core
4+
5+
import dotc.core.Contexts.Context
6+
7+
import transform.DocMiniPhase
8+
import model._
9+
import model.internal._
10+
11+
/** This DocMiniPhase adds the alternate constructors, currently defined as
12+
* methods with the name `<init>`, to the Entity#constructors list
13+
*/
14+
class AlternateConstructors extends DocMiniPhase {
15+
def partitionMembers(ent: Entity with Constructors with Members): (List[List[ParamList]], List[Entity]) = {
16+
val (constructors, members) = ent.members.partition(x => x.name == "<init>")
17+
18+
val paramLists: List[List[ParamList]] = constructors.collect {
19+
case df: Def => df.paramLists
20+
}
21+
22+
(ent.constructors ++ paramLists, members)
23+
}
24+
25+
override def transformClass(implicit ctx: Context) = { case cls: ClassImpl =>
26+
val (constructors, members) = partitionMembers(cls)
27+
cls.copy(members = members, constructors = constructors)
28+
}
29+
30+
override def transformCaseClass(implicit ctx: Context) = { case cc: CaseClassImpl =>
31+
val (constructors, members) = partitionMembers(cc)
32+
cc.copy(members = members, constructors = constructors)
33+
}
34+
}

0 commit comments

Comments
 (0)