@@ -3394,11 +3394,17 @@ object Build {
33943394 val testcasesSourceRoot = taskKey[String ](" Root directory where tests sources are generated" )
33953395 val testDocumentationRoot = taskKey[String ](" Root directory where tests documentation are stored" )
33963396 val generateSelfDocumentation = taskKey[Unit ](" Generate example documentation" )
3397- // Note: the two tasks below should be one, but a bug in Tasty prevents that
3398- val generateScalaDocumentation = inputKey[Unit ](" Generate documentation for dotty lib" )
3399- val generateStableScala3Documentation = inputKey[Unit ](" Generate documentation for stable dotty lib" )
34003397 val generateTestcasesDocumentation = taskKey[Unit ](" Generate documentation for testcases, useful for debugging tests" )
34013398
3399+ // Published on https://dotty.epfl.ch/ by nightly builds
3400+ // Contains additional internal/contributing docs
3401+ val generateScalaDocumentation = inputKey[Unit ](" Generate documentation for snapshot release" )
3402+
3403+ // Published on https://docs.scala-lang.org/api/all.html
3404+ val generateStableScala3Documentation = inputKey[Unit ](" Generate documentation for stable release" )
3405+
3406+ // Published on https://docs.scala-lang.org/scala3/reference/
3407+ // Does not produce API docs, contains additional redirects for improved stablity
34023408 val generateReferenceDocumentation = inputKey[Unit ](" Generate language reference documentation for Scala 3" )
34033409
34043410 lazy val `scaladoc-testcases` = project.in(file(" scaladoc-testcases" )).
@@ -3525,31 +3531,135 @@ object Build {
35253531 val outputDirOverride = extraArgs.headOption.fold(identity[GenerationConfig ](_))(newDir => {
35263532 config : GenerationConfig => config.add(OutputDir (newDir))
35273533 })
3528- val justAPIArg : Option [String ] = extraArgs.drop(1 ).find(_ == " --justAPI" )
3529- val justAPI = justAPIArg.fold(identity[GenerationConfig ](_))(_ => {
3530- config : GenerationConfig => config.remove[SiteRoot ]
3531- })
3532- val overrideFunc = outputDirOverride.andThen(justAPI)
3534+ val justAPI = extraArgs.contains(" --justAPI" )
3535+ def justAPIOverride (config : GenerationConfig ): GenerationConfig = {
3536+ if (! justAPI) config
3537+ else {
3538+ val siteRoot = IO .createTemporaryDirectory.getAbsolutePath()
3539+ config.add(SiteRoot (siteRoot))
3540+ }
3541+ }
3542+
3543+ // It would be the easiest to create a temp directory and apply patches there, but this task would be used frequently during development
3544+ // If we'd build using copy the emitted warnings would point developers to copies instead of original sources. Any fixes made in there would be lost.
3545+ // Instead let's apply revertable patches to the files as part snapshot doc generation process
3546+ abstract class SourcePatch (val file : File ) {
3547+ def apply (): Unit
3548+ def revert (): Unit
3549+ }
3550+ val docs = file(" docs" )
3551+ val sourcePatches = if (justAPI) Nil else Seq (
3552+ // Generate full sidebar.yml based on template and reference content
3553+ new SourcePatch (docs / " sidebar.yml" ) {
3554+ val referenceSideBarCopy = IO .temporaryDirectory / " sidebar.yml.copy"
3555+ IO .copyFile(file, referenceSideBarCopy)
3556+
3557+ override def apply (): Unit = {
3558+ val yaml = new org.yaml.snakeyaml.Yaml ()
3559+ type YamlObject = java.util.Map [String , AnyRef ]
3560+ type YamlList [T ] = java.util.List [T ]
3561+ def loadYaml (file : File ): YamlObject = {
3562+ val reader = Files .newBufferedReader(file.toPath)
3563+ try yaml.load(reader).asInstanceOf [YamlObject ]
3564+ finally reader.close()
3565+ }
3566+ // Ensure to always operate on original (Map, List) instances
3567+ val template = loadYaml(docs / " sidebar.nightly.template.yml" )
3568+ template.get(" subsection" )
3569+ .asInstanceOf [YamlList [YamlObject ]]
3570+ .stream()
3571+ .filter(_.get(" title" ) == " Reference" )
3572+ .findFirst()
3573+ .orElseThrow(() => new IllegalStateException (" Reference subsection not found in sidebar.nightly.template.yml" ))
3574+ .putAll(loadYaml(referenceSideBarCopy))
3575+
3576+ val sidebarWriter = Files .newBufferedWriter(this .file.toPath)
3577+ try yaml.dump(template, sidebarWriter)
3578+ finally sidebarWriter.close()
3579+ }
3580+ override def revert (): Unit = IO .move(referenceSideBarCopy, file)
3581+ },
3582+ // Add patch about nightly version usage
3583+ new SourcePatch (docs / " _layouts" / " static-site-main.html" ) {
3584+ lazy val originalContent = IO .read(file)
3585+
3586+ val warningMessage = """ {% if page.nightlyOf %}
3587+ | <aside class="warning">
3588+ | <div class='icon'></div>
3589+ | <div class='content'>
3590+ | This is a nightly documentation. The content of this page may not be consistent with the current stable version of language.
3591+ | Click <a href="{{ page.nightlyOf }}">here</a> to find the stable version of this page.
3592+ | </div>
3593+ | </aside>
3594+ |{% endif %}""" .stripMargin
3595+
3596+ override def apply (): Unit = {
3597+ IO .write(file,
3598+ originalContent
3599+ .replace(" {{ content }}" , s " $warningMessage {{ content }} " )
3600+ .ensuring(_.contains(warningMessage), " patch to static-site-main layout not applied!" )
3601+ )
3602+ }
3603+ override def revert (): Unit = IO .write(file, originalContent)
3604+ }
3605+ )
35333606
35343607 val config = Def .task {
3535- overrideFunc(Scala3 .value)
3608+ outputDirOverride
3609+ .andThen(justAPIOverride)
3610+ .apply(Scala3 .value)
35363611 }
35373612
35383613 val writeAdditionalFiles = Def .task {
35393614 val dest = file(config.value.get[OutputDir ].get.value)
3540- if (justAPIArg.isEmpty ) {
3615+ if (! justAPI ) {
35413616 IO .write(dest / " versions" / " latest-nightly-base" , majorVersion)
35423617 // This file is used by GitHub Pages when the page is available in a custom domain
35433618 IO .write(dest / " CNAME" , " dotty.epfl.ch" )
35443619 }
35453620 }
3621+ val applyPatches = Def .task {
3622+ streams.value.log.info(s " Generating snapshot scaladoc, would apply patches to ${sourcePatches.map(_.file)}" )
3623+ sourcePatches.foreach(_.apply())
3624+ }
3625+ val revertPatches = Def .task {
3626+ streams.value.log.info(s " Generated snapshot scaladoc, reverting changes made to ${sourcePatches.map(_.file)}" )
3627+ sourcePatches.foreach(_.revert())
3628+ }
35463629
3547- writeAdditionalFiles.dependsOn(generateDocumentation(config))
3630+ writeAdditionalFiles.dependsOn(
3631+ revertPatches.dependsOn(
3632+ generateDocumentation(config)
3633+ .dependsOn(applyPatches)
3634+ )
3635+ )
35483636 }.evaluated,
35493637
35503638 generateStableScala3Documentation := Def .inputTaskDyn {
35513639 val extraArgs = spaceDelimited(" <version>" ).parsed
3552- val config = stableScala3(extraArgs.head)
3640+ val version = baseVersion
3641+ // In the early days of scaladoc there was a practice to precompile artifacts of Scala 3 and generate docs using different version of scaladoc
3642+ // It's no longer needed after its stablisation.
3643+ // Allow to use explcit version check to detect using incorrect revision during release process
3644+ extraArgs.headOption.foreach { explicitVersion =>
3645+ assert(
3646+ explicitVersion == version,
3647+ s " Version of the build ( $version) does not match the explicit verion ( $explicitVersion) "
3648+ )
3649+ }
3650+
3651+ val docs = IO .createTemporaryDirectory
3652+ IO .copyDirectory(file(" docs" ), docs)
3653+ IO .delete(docs / " _blog" )
3654+
3655+ val config = Def .task {
3656+ Scala3 .value
3657+ .add(ProjectVersion (version))
3658+ .add(Revision (version))
3659+ .add(OutputDir (s " scaladoc/output/ ${version}" ))
3660+ .add(SiteRoot (docs.getAbsolutePath))
3661+ .remove[ApiSubdirectory ]
3662+ }
35533663 generateDocumentation(config)
35543664 }.evaluated,
35553665
@@ -3564,20 +3674,13 @@ object Build {
35643674 generateStaticAssetsTask.value
35653675
35663676 // Move all the source files to a temporary directory and apply some changes specific to the reference documentation
3567- val temp = IO .createTemporaryDirectory
3568- IO .copyDirectory(file(" docs" ), temp / " docs" )
3569- IO .delete(temp / " docs" / " _blog" )
3570-
3571- // Overwrite the main layout and the sidebar
3572- IO .copyDirectory(
3573- file(" project" ) / " resources" / " referenceReplacements" ,
3574- temp / " docs" ,
3575- overwrite = true
3576- )
3677+ val docs = IO .createTemporaryDirectory
3678+ IO .copyDirectory(file(" docs" ), docs)
3679+ IO .delete(docs / " _blog" )
35773680
35783681 // Add redirections from previously supported URLs, for some pages
35793682 for (name <- Seq (" changed-features" , " contextual" , " dropped-features" , " metaprogramming" , " other-new-features" )) {
3580- val path = temp / " docs" / " _docs" / " reference" / name / s " ${name}.md "
3683+ val path = docs / " _docs" / " reference" / name / s " ${name}.md "
35813684 val contentLines = IO .read(path).linesIterator.to[collection.mutable.ArrayBuffer ]
35823685 contentLines.insert(1 , s " redirectFrom: / ${name}.html " ) // Add redirection
35833686 val newContent = contentLines.mkString(" \n " )
@@ -3587,12 +3690,12 @@ object Build {
35873690 val languageReferenceConfig = Def .task {
35883691 Scala3 .value
35893692 .add(OutputDir (" scaladoc/output/reference" ))
3590- .add(SiteRoot (s " ${temp .getAbsolutePath} /docs " ))
3693+ .add(SiteRoot (docs .getAbsolutePath))
35913694 .add(ProjectName (" Scala 3 Reference" ))
35923695 .add(ProjectVersion (baseVersion))
35933696 .remove[VersionsDictionaryUrl ]
35943697 .add(SourceLinks (List (
3595- s " ${temp .getAbsolutePath}=github://scala/scala3/language-reference-stable "
3698+ s " ${docs.getParentFile() .getAbsolutePath}=github://scala/scala3/language-reference-stable "
35963699 )))
35973700 .withTargets(List (" ___fake___.scala" ))
35983701 }
@@ -4063,57 +4166,40 @@ object ScaladocConfigs {
40634166 }
40644167
40654168 lazy val Scala3 = Def .task {
4169+ val stdlib = { // relative path to the stdlib directory ('library/')
4170+ val projectRoot = (ThisBuild / baseDirectory).value.toPath
4171+ val stdlibRoot = (`scala-library-bootstrapped` / baseDirectory).value
4172+ projectRoot.relativize(stdlibRoot.toPath.normalize())
4173+ }
4174+
40664175 DefaultGenerationSettings .value
40674176 .add(ProjectName (" Scala 3" ))
40684177 .add(OutputDir (file(" scaladoc/output/scala3" ).getAbsoluteFile.getAbsolutePath))
40694178 .add(Revision (" main" ))
40704179 .add(ExternalMappings (List (javaExternalMapping)))
4071- .add(DocRootContent (((`scala-library-bootstrapped` / baseDirectory).value / " src" / " rootdoc.txt" ).toString))
4180+ .add(DocRootContent ((stdlib / " src" / " rootdoc.txt" ).toString))
40724181 .add(CommentSyntax (List (
4073- // s"${dottyLibRoot}=markdown",
4074- // s"${stdLibRoot}=wiki",
4182+ // Only the files below use markdown syntax (Scala 3 specific sources)
4183+ s " $stdlib/src/scala/NamedTuple.scala=markdown " ,
4184+ s " $stdlib/src/scala/Tuple.scala=markdown " ,
4185+ s " $stdlib/src/scala/compiletime=markdown " ,
4186+ s " $stdlib/src/scala/quoted=markdown " ,
4187+ s " $stdlib/src/scala/util/boundary.scala=markdown " ,
4188+ // Scala 2 sources use wiki syntax, we keep it as the default
40754189 " wiki"
40764190 )))
40774191 .add(VersionsDictionaryUrl (" https://scala-lang.org/api/versions.json" ))
40784192 .add(DocumentSyntheticTypes (true ))
4079- // .add(SnippetCompiler(List(
4080- // s"$dottyLibRoot/src/scala=compile",
4081- // s"$dottyLibRoot/src/scala/compiletime=compile",
4082- // s"$dottyLibRoot/src/scala/util=compile",
4083- // s"$dottyLibRoot/src/scala/util/control=compile"
4084- // )))
4193+ .add(SnippetCompiler (List (
4194+ s " $stdlib/src/scala/compiletime=compile " ,
4195+ s " $stdlib/src/scala/quoted=compile " ,
4196+ s " $stdlib/src/scala/util/control=compile " ,
4197+ s " $stdlib/src/scala/util=compile " ,
4198+ s " $stdlib/src/scala=compile " ,
4199+ )))
40854200 .add(SiteRoot (" docs" ))
40864201 .add(ApiSubdirectory (true ))
40874202 .withTargets((`scala-library-bootstrapped` / Compile / products).value.map(_.getAbsolutePath))
40884203 }
40894204
4090- def stableScala3 (version : String ) = Def .task {
4091- val scalaLibrarySrc = s " out/bootstrap/scala2-library-bootstrapped/scala- $version-bin-SNAPSHOT-nonbootstrapped/src_managed "
4092- val dottyLibrarySrc = " library/src"
4093- Scala3 .value
4094- .add(defaultSourceLinks(version = version))
4095- .add(ProjectVersion (version))
4096- .add(SnippetCompiler (
4097- List (
4098- s " $dottyLibrarySrc/scala/quoted=compile " ,
4099- s " $dottyLibrarySrc/scala/compiletime=compile " ,
4100- s " $dottyLibrarySrc/scala/util=compile " ,
4101- s " $dottyLibrarySrc/scala/util/control=compile "
4102- )
4103- ))
4104- .add(CommentSyntax (List (
4105- s " $dottyLibrarySrc=markdown " ,
4106- s " $scalaLibrarySrc=wiki " ,
4107- " wiki"
4108- )))
4109- .add(DocRootContent (s " $scalaLibrarySrc/rootdoc.txt " ))
4110- .withTargets(
4111- Seq (
4112- s " tmp/interfaces/target/classes " ,
4113- s " out/bootstrap/tasty-core-bootstrapped/scala- $version-bin-SNAPSHOT-nonbootstrapped/classes "
4114- )
4115- )
4116- .remove[SiteRoot ]
4117- .remove[ApiSubdirectory ]
4118- }
41194205}
0 commit comments