Skip to content

Commit efd1596

Browse files
committed
Apply flat packages in cases where static site is not provided
1 parent 31751b9 commit efd1596

13 files changed

+245
-187
lines changed

scala3doc/src/dotty/dokka/DottyDokkaConfig.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ case class DottyDokkaConfig(args: Scala3doc.Args, docContext: DocContext) extend
1919

2020
lazy val sourceLinks: SourceLinks = SourceLinks.load(args)
2121

22+
lazy val displaySourceSets = getSourceSets.toDisplaySourceSet
23+
2224
lazy val staticSiteContext = args.docsRoot.map(path => StaticSiteContext(
2325
File(path).getAbsoluteFile(),
2426
Set(mkSourceSet.asInstanceOf[SourceSetWrapper]),

scala3doc/src/dotty/dokka/DottyDokkaPlugin.scala

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ import dotty.dokka.model.api._
2323
import org.jetbrains.dokka.CoreExtensions
2424
import org.jetbrains.dokka.base.DokkaBase
2525

26+
import dotty.dokka.site.NavigationCreator
2627
import dotty.dokka.site.SitePagesCreator
2728
import dotty.dokka.site.StaticSiteContext
28-
import dotty.dokka.site.RootIndexPageCreator
2929
import dotty.dokka.site.SiteResourceManager
3030
import dotty.dokka.site.StaticSiteLocationProviderFactory
3131

@@ -49,7 +49,7 @@ class DottyDokkaPlugin extends DokkaJavaPlugin:
4949
// Just turn off another translator since multiple overrides does not work
5050
val disableDescriptorTranslator = extend(
5151
_.extensionPoint(CoreExtensions.INSTANCE.getSourceToDocumentableTranslator)
52-
.fromRecipe(ctx => new ScalaModuleProvider(using ctx.docContext))
52+
.fromRecipe(ctx => new ScalaModuleProvider(using ctx.config.docContext))
5353
.overrideExtension(dokkaBase.getDescriptorToDocumentableTranslator)
5454
.name("disableDescriptorTranslator")
5555
)
@@ -70,7 +70,7 @@ class DottyDokkaPlugin extends DokkaJavaPlugin:
7070

7171
val scalaResourceInstaller = extend(
7272
_.extensionPoint(dokkaBase.getHtmlPreprocessors)
73-
.fromRecipe(ctx => new ScalaResourceInstaller(ctx.args))
73+
.fromRecipe(ctx => new ScalaResourceInstaller(ctx.config.args))
7474
.after(dokkaBase.getCustomResourceInstaller)
7575
)
7676

@@ -111,7 +111,7 @@ class DottyDokkaPlugin extends DokkaJavaPlugin:
111111

112112
val ourRenderer = extend(
113113
_.extensionPoint(CoreExtensions.INSTANCE.getRenderer)
114-
.fromRecipe(ctx => ScalaHtmlRenderer(ctx, ctx.args))
114+
.fromRecipe(ctx => ScalaHtmlRenderer(ctx, ctx.config.args))
115115
.overrideExtension(dokkaBase.getHtmlRenderer)
116116
)
117117

@@ -129,7 +129,7 @@ class DottyDokkaPlugin extends DokkaJavaPlugin:
129129

130130
val customDocumentationProvider = extend(
131131
_.extensionPoint(dokkaBase.getHtmlPreprocessors)
132-
.fromRecipe(c => SitePagesCreator(c.siteContext))
132+
.fromRecipe(c => SitePagesCreator(c.config.staticSiteContext))
133133
.name("customDocumentationProvider")
134134
.ordered(
135135
before = Seq(
@@ -142,25 +142,27 @@ class DottyDokkaPlugin extends DokkaJavaPlugin:
142142
)
143143
)
144144

145-
val customIndexRootProvider = extend(
145+
val customNavigation = extend(
146146
_.extensionPoint(dokkaBase.getHtmlPreprocessors)
147-
.fromRecipe(c => RootIndexPageCreator(c.siteContext))
148-
.name("customIndexRootProvider")
147+
.fromRecipe(c => NavigationCreator(c.config)) // Adding a parameter to constuctor to NavigationCreator failed inc compilation
148+
.name("customNavigation")
149149
.ordered(
150150
before = Seq(
151151
dokkaBase.getScriptsInstaller,
152152
dokkaBase.getStylesInstaller,
153153
),
154-
after = Seq(dokkaBase.getNavigationPageInstaller)
154+
after = Seq(customDocumentationProvider.getValue)
155155
)
156+
.overrideExtension(dokkaBase.getNavigationPageInstaller)
156157
)
157158

158159
val customDocumentationResources = extend(
159160
_.extensionPoint(dokkaBase.getHtmlPreprocessors)
160-
.fromRecipe(c => SiteResourceManager(c.siteContext))
161+
.fromRecipe(c => SiteResourceManager(c.config.staticSiteContext))
161162
.name("customDocumentationResources")
162163
.after(
163-
scalaEmbeddedResourceAppender.getValue
164+
scalaEmbeddedResourceAppender.getValue,
165+
customDocumentationProvider.getValue
164166
)
165167
)
166168

@@ -171,9 +173,7 @@ class DottyDokkaPlugin extends DokkaJavaPlugin:
171173
)
172174

173175
extension (ctx: DokkaContext):
174-
def siteContext: Option[StaticSiteContext] = ctx.getConfiguration.asInstanceOf[DottyDokkaConfig].staticSiteContext
175-
def args: Scala3doc.Args = ctx.getConfiguration.asInstanceOf[DottyDokkaConfig].args
176-
def docContext = ctx.getConfiguration.asInstanceOf[DottyDokkaConfig].docContext
176+
def config = ctx.getConfiguration.asInstanceOf[DottyDokkaConfig]
177177

178178
// TODO (https://github.com/lampepfl/scala3doc/issues/232): remove once problem is fixed in Dokka
179179
extension [T] (builder: ExtensionBuilder[T]):

scala3doc/src/dotty/dokka/compat.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type JHashMap[K, V] = java.util.HashMap[K, V]
2929
type JMapEntry[K, V] = java.util.Map.Entry[K, V]
3030

3131
type DRI = org.jetbrains.dokka.links.DRI
32+
val topLevelDri = org.jetbrains.dokka.links.DRI.Companion.getTopLevel
3233

3334
type SourceSetWrapper = DokkaConfiguration$DokkaSourceSet
3435
type DokkaSourceSet = DokkaConfiguration.DokkaSourceSet
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package dotty.dokka
2+
package site
3+
4+
import org.jetbrains.dokka.base.renderers.html.{NavigationNode, NavigationPage}
5+
import org.jetbrains.dokka.model.DPackage
6+
import org.jetbrains.dokka.model.DModule
7+
import org.jetbrains.dokka.pages._
8+
import org.jetbrains.dokka.transformers.pages.PageTransformer
9+
10+
import scala.collection.JavaConverters._
11+
12+
class NavigationCreator(ctx: DottyDokkaConfig) extends PageTransformer:
13+
14+
private def processApiPages(pages: List[PageNode]): JList[NavigationNode] =
15+
def flatMapPackages(pn: PageNode): List[NavigationNode] =
16+
def processChildren = pn.getChildren.asScala.flatMap(flatMapPackages).toList
17+
pn match
18+
case cp: ContentPage => cp.getDocumentable match
19+
case null =>
20+
processChildren
21+
// Left over package from dokka
22+
case p: DPackage if p.getName == "<empty>" && p.getChildren.isEmpty =>
23+
Nil
24+
case p: DPackage =>
25+
val ss = p.getSourceSets.asScala.toSet.toDisplay
26+
List(new NavigationNode(p.getName, p.getDri, ss, JList())) ++ processChildren
27+
case _: DModule =>
28+
processChildren
29+
case _ =>
30+
Nil
31+
case _ =>
32+
Nil
33+
34+
pages.flatMap(flatMapPackages).sortBy(_.getName).asJava
35+
36+
private def processStaticPages(input: PageNode)(staticSiteContext: StaticSiteContext) =
37+
def toNavigationNode(page: StaticPageNode): NavigationNode = NavigationNode(
38+
page.title(),
39+
page.getDri.asScala.head,
40+
ctx.displaySourceSets,
41+
page.getChildren.asScala
42+
.collect { case p: StaticPageNode => toNavigationNode(p)}.asJava
43+
)
44+
45+
def singleContentPage(p: PageNode) =
46+
p.getChildren.asScala.collectFirst { case c: ContentPage => c }.get
47+
val pageRoot = singleContentPage(input)
48+
val docsRoot =
49+
if !pageRoot.getDri.contains(topLevelDri) then pageRoot
50+
else singleContentPage(pageRoot)
51+
val apiPages = docsRoot.getChildren.asScala.filterNot(_.isInstanceOf[StaticPageNode])
52+
val staticPages = staticSiteContext.mainPages.map(toNavigationNode).toList.asJava
53+
val apiNodes = processApiPages(apiPages.toList)
54+
staticPages ++
55+
JList(new NavigationNode("API", apiPageDRI, ctx.displaySourceSets, apiNodes))
56+
57+
private def emptyNavigationJson =
58+
val strategy = new RenderingStrategy.Write("[]")
59+
new RendererSpecificResourcePage("scripts/navigation-pane.json", JList(), strategy)
60+
61+
final override def invoke(input: RootPageNode): RootPageNode =
62+
def defaultApiPages = processApiPages(input.getChildren.asScala.toList)
63+
val nodes = ctx.staticSiteContext.fold(defaultApiPages)(processStaticPages(input))
64+
65+
val navigationPage = new NavigationPage(new NavigationNode(
66+
ctx.args.name,
67+
ctx.staticSiteContext.fold(topLevelDri)(_ => docsRootDRI),
68+
ctx.displaySourceSets,
69+
nodes
70+
))
71+
val newChildren = input.getChildren ++ JList(emptyNavigationJson, navigationPage)
72+
input.modified(input.getName, newChildren)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package dotty.dokka
2+
package site
3+
4+
import java.io.File
5+
import java.nio.file.Files
6+
import java.nio.file.FileVisitOption
7+
8+
import org.jetbrains.dokka.model.Documentable
9+
import org.jetbrains.dokka.pages._
10+
11+
import scala.collection.JavaConverters._
12+
import dotty.dokka.model.api._
13+
14+
15+
class SitePagesCreator(ctx: Option[StaticSiteContext]) extends BaseStaticSiteProcessor(ctx):
16+
private def mkRootPage(input: RootPageNode, children: List[PageNode]): AContentPage =
17+
input match
18+
case input: ContentPage =>
19+
AContentPage(
20+
input.getName,
21+
children.asJava,
22+
input.getContent,
23+
JSet(apiPageDRI),
24+
input.getEmbeddedResources
25+
)
26+
case _: RendererSpecificRootPage =>
27+
children.filter(_.isInstanceOf[RootPageNode]) match
28+
case List(nestedRoot: RootPageNode) =>
29+
mkRootPage(nestedRoot, children.filter { _ != nestedRoot } ++
30+
nestedRoot.getChildren.asScala)
31+
case other =>
32+
throw new RuntimeException(s"Expected single nested roor but get: $other")
33+
34+
case _ => throw new RuntimeException(s"UNSUPPORTED! ${input.getClass.getName}")
35+
36+
37+
override def transform(input: RootPageNode, ctx: StaticSiteContext): RootPageNode =
38+
val (contentPage, others) =
39+
input.getChildren.asScala.toList.partition { _.isInstanceOf[ContentPage] }
40+
41+
val apiRoot = mkRootPage(input, contentPage)
42+
val (indexes, children) = ctx.allPages.partition(f =>
43+
f.template.isIndexPage() && f.template.file.toPath.getParent() == ctx.docsPath )
44+
// TODO (https://github.com/lampepfl/scala3doc/issues/238): provide proper error handling
45+
if (indexes.size > 1) println(s"ERROR: Multiple index pages found ${indexes.map(_.template.file)}")
46+
47+
def emptyContent = ctx.asContent(Text(), mkDRI(extra = "root_content")).get(0)
48+
49+
val root = ctx.indexPage().toList.map(_.copy(getDri = JSet(docsRootDRI)))
50+
val docsRoot = AContentPage(
51+
ctx.args.name,
52+
(List(apiRoot.modified("API", apiRoot.getChildren)) ++ children ++ root).asJava,
53+
indexes.headOption.fold(emptyContent)(_.getContent),
54+
JSet(docsDRI),
55+
JList()
56+
)
57+
58+
new RendererSpecificRootPage(
59+
apiRoot.getName,
60+
(List(docsRoot) ++ others).asJava,
61+
RenderingStrategy.DoNothing.INSTANCE
62+
)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package dotty.dokka
2+
package site
3+
4+
import java.nio.file.Files
5+
import java.nio.file.FileVisitOption
6+
7+
import org.jetbrains.dokka.model.Documentable
8+
import org.jetbrains.dokka.pages._
9+
10+
import scala.collection.JavaConverters._
11+
import dotty.dokka.model.api._
12+
13+
class SiteResourceManager(ctx: Option[StaticSiteContext])
14+
extends BaseStaticSiteProcessor(ctx):
15+
private def listResources(nodes: Seq[PageNode]): Set[String] =
16+
nodes.flatMap {
17+
case it: AContentPage =>
18+
listResources(it.getChildren.asScala.toList)
19+
case it: StaticPageNode =>
20+
listResources(it.getChildren.asScala.toList) ++ it.resources()
21+
case _ => Seq.empty
22+
}.toSet
23+
24+
override def transform(input: RootPageNode, ctx: StaticSiteContext): RootPageNode =
25+
val rootPath = ctx.root.toPath
26+
val imgPath = rootPath.resolve("images")
27+
val images =
28+
if !Files.exists(imgPath) then Nil
29+
else
30+
val allPaths = Files.walk(imgPath, FileVisitOption.FOLLOW_LINKS)
31+
val files = allPaths.filter(Files.isRegularFile(_)).iterator().asScala
32+
files.map(p => rootPath.relativize(p).toString).toList
33+
34+
val resources = images ++ listResources(input.getChildren.asScala.toList)
35+
println(s"#### $resources")
36+
val resourcePages = resources.map { path =>
37+
val strategy = new RenderingStrategy.Copy(rootPath.resolve(path).toString)
38+
new RendererSpecificResourcePage(path, JList(), strategy)
39+
}
40+
41+
val modified = input.transformContentPagesTree {
42+
case it: StaticPageNode =>
43+
it.copy(getEmbeddedResources =
44+
if it.template.hasFrame then it.getEmbeddedResources ++ it.resources().asJava
45+
else it.resources().asJava
46+
)
47+
case it => it
48+
}
49+
val newChildren = (resourcePages ++ modified.getChildren.asScala).asJava
50+
modified.modified(modified.getName, newChildren)

scala3doc/src/dotty/dokka/site/StaticSiteLocationProvider.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory
77
import org.jetbrains.dokka.pages.ContentPage
88
import org.jetbrains.dokka.pages.PageNode
99
import org.jetbrains.dokka.pages.RootPageNode
10+
import org.jetbrains.dokka.pages.ModulePage
1011
import org.jetbrains.dokka.plugability.DokkaContext
1112

1213
import scala.collection.JavaConverters._
@@ -16,21 +17,21 @@ import java.nio.file.Path
1617
class StaticSiteLocationProviderFactory(private val ctx: DokkaContext) extends LocationProviderFactory:
1718
override def getLocationProvider(pageNode: RootPageNode): LocationProvider =
1819
try new StaticSiteLocationProvider(ctx, pageNode)
19-
catch
20+
catch
2021
case e: Error =>
2122
// TODO (https://github.com/lampepfl/scala3doc/issues/238) error handling
2223
e.printStackTrace()
2324
// We encounter bug in Kotlin coroutines (race) when this method throws exception
2425
// In such case we want to return null to trigger NPE in other piece of code to fail properly coroutine context
25-
// Making generated DRIs not-unique will reproduce this behavior
26+
// Making generated DRIs not-unique will reproduce this behavior
2627
null
2728

2829
class StaticSiteLocationProvider(ctx: DokkaContext, pageNode: RootPageNode)
2930
extends DokkaLocationProvider(pageNode, ctx, ".html"):
3031
private def updatePageEntry(page: PageNode, jpath: JList[String]): JList[String] =
3132
page match
3233
case page: StaticPageNode =>
33-
ctx.siteContext.fold(jpath) { context =>
34+
ctx.config.staticSiteContext.fold(jpath) { context =>
3435
val rawFilePath = context.root.toPath.relativize(page.template.file.toPath)
3536
val pageName = page.template.file.getName
3637
val dotIndex = pageName.lastIndexOf('.')
@@ -60,7 +61,7 @@ class StaticSiteLocationProvider(ctx: DokkaContext, pageNode: RootPageNode)
6061
case _ if jpath.size() > 1 && jpath.get(0) == "--root--" && jpath.get(1) == "-a-p-i" =>
6162
(List("api") ++ jpath.asScala.drop(2)).asJava
6263

63-
case _: org.jetbrains.dokka.pages.ModulePage if ctx.siteContext.isEmpty =>
64+
case _: ModulePage if ctx.config.staticSiteContext.isEmpty =>
6465
JList("index")
6566
case _ =>
6667
jpath

scala3doc/src/dotty/dokka/site/common.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import com.vladsch.flexmark.ext.yaml.front.matter.{AbstractYamlFrontMatterVisito
1414
import com.vladsch.flexmark.parser.{Parser, ParserEmulationProfile}
1515
import com.vladsch.flexmark.util.options.{DataHolder, MutableDataSet}
1616
import com.vladsch.flexmark.ext.wikilink.WikiLinkExtension
17+
1718
import org.jetbrains.dokka.model.doc.Text
19+
import org.jetbrains.dokka.model.Documentable
20+
import org.jetbrains.dokka.transformers.pages.PageTransformer
21+
import org.jetbrains.dokka.pages._
1822

1923
import scala.collection.JavaConverters._
2024

@@ -112,3 +116,31 @@ def loadTemplateFile(file: File): TemplateFile = {
112116
}
113117

114118
def Text(msg: String = "") = new Text(msg, JList(), JMap())
119+
120+
abstract class BaseStaticSiteProcessor(staticSiteContext: Option[StaticSiteContext])
121+
extends PageTransformer:
122+
final override def invoke(input: RootPageNode): RootPageNode =
123+
staticSiteContext.fold(input)(transform(input, _))
124+
125+
protected def transform(input: RootPageNode, ctx: StaticSiteContext): RootPageNode
126+
127+
case class AContentPage(
128+
override val getName: String,
129+
override val getChildren: JList[PageNode],
130+
override val getContent: ContentNode,
131+
override val getDri: JSet[DRI],
132+
override val getEmbeddedResources: JList[String] = JList(),
133+
) extends ContentPage:
134+
override def getDocumentable: Documentable = null
135+
136+
override def modified(
137+
name: String,
138+
content: ContentNode,
139+
dri: JSet[DRI],
140+
embeddedResources: JList[String],
141+
children: JList[_ <: PageNode]
142+
): ContentPage =
143+
copy(name, children.asInstanceOf[JList[PageNode]], content, dri, embeddedResources)
144+
145+
override def modified(name: String, children: JList[_ <: PageNode]): PageNode =
146+
copy(name, getChildren = children.asInstanceOf[JList[PageNode]])

0 commit comments

Comments
 (0)