From 489c12f695827de1167d549873f8c907c5637ed9 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 22 Oct 2020 09:43:08 +0200 Subject: [PATCH] Remove tastydoc --- build.sbt | 2 - project/Build.scala | 14 +- tastydoc/.gitignore | 1 - tastydoc/input/project/build.properties | 1 - .../main/scala/example/Documentation2.scala | 12 - .../src/main/scala/example/Inheritance.scala | 5 - .../scala/example/level2/Documentation.scala | 161 ------ .../example/level2/SameLevelTypeLinking.scala | 5 - .../level2/level3/level4/ClassLevel4.scala | 13 - tastydoc/project/build.properties | 1 - tastydoc/readme.md | 11 - tastydoc/src/dotty/tastydoc/DocPrinter.scala | 437 -------------- tastydoc/src/dotty/tastydoc/Main.scala | 105 ---- .../src/dotty/tastydoc/TastyExtractor.scala | 185 ------ .../dotty/tastydoc/TastyTypeConverter.scala | 103 ---- .../dotty/tastydoc/TastydocInspector.scala | 17 - .../dotty/tastydoc/comment/BodyEntities.scala | 94 --- .../src/dotty/tastydoc/comment/Comment.scala | 167 ------ .../tastydoc/comment/CommentCleaner.scala | 25 - .../tastydoc/comment/CommentParser.scala | 219 ------- .../dotty/tastydoc/comment/CommentRegex.scala | 82 --- .../dotty/tastydoc/comment/HtmlParsers.scala | 188 ------ .../tastydoc/comment/MarkdownShortener.scala | 82 --- .../dotty/tastydoc/comment/WikiParser.scala | 543 ------------------ .../tastydoc/comment/util/MemberLookup.scala | 88 --- .../tastydoc/comment/util/traversing.scala | 45 -- tastydoc/src/dotty/tastydoc/mdscala.scala | 107 ---- tastydoc/src/dotty/tastydoc/references.scala | 18 - .../src/dotty/tastydoc/representations.scala | 245 -------- tastydoc/test/dotty/tastydoc/Tests.scala | 74 --- 30 files changed, 1 insertion(+), 3049 deletions(-) delete mode 100644 tastydoc/.gitignore delete mode 100644 tastydoc/input/project/build.properties delete mode 100644 tastydoc/input/src/main/scala/example/Documentation2.scala delete mode 100644 tastydoc/input/src/main/scala/example/Inheritance.scala delete mode 100644 tastydoc/input/src/main/scala/example/level2/Documentation.scala delete mode 100644 tastydoc/input/src/main/scala/example/level2/SameLevelTypeLinking.scala delete mode 100644 tastydoc/input/src/main/scala/example/level2/level3/level4/ClassLevel4.scala delete mode 100644 tastydoc/project/build.properties delete mode 100644 tastydoc/readme.md delete mode 100644 tastydoc/src/dotty/tastydoc/DocPrinter.scala delete mode 100644 tastydoc/src/dotty/tastydoc/Main.scala delete mode 100644 tastydoc/src/dotty/tastydoc/TastyExtractor.scala delete mode 100644 tastydoc/src/dotty/tastydoc/TastyTypeConverter.scala delete mode 100644 tastydoc/src/dotty/tastydoc/TastydocInspector.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/BodyEntities.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/Comment.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/CommentCleaner.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/CommentParser.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/CommentRegex.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/HtmlParsers.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/MarkdownShortener.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/WikiParser.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/util/MemberLookup.scala delete mode 100644 tastydoc/src/dotty/tastydoc/comment/util/traversing.scala delete mode 100644 tastydoc/src/dotty/tastydoc/mdscala.scala delete mode 100644 tastydoc/src/dotty/tastydoc/references.scala delete mode 100644 tastydoc/src/dotty/tastydoc/representations.scala delete mode 100644 tastydoc/test/dotty/tastydoc/Tests.scala diff --git a/build.sbt b/build.sbt index b2f7208dc478..a8d447d7c001 100644 --- a/build.sbt +++ b/build.sbt @@ -20,8 +20,6 @@ val `stdlib-bootstrapped-tasty-tests` = Build.`stdlib-bootstrapped-tasty-tests` val `tasty-core` = Build.`tasty-core` val `tasty-core-bootstrapped` = Build.`tasty-core-bootstrapped` val `tasty-core-scala2` = Build.`tasty-core-scala2` -val `scala3-tastydoc` = Build.`scala3-tastydoc` -val `scala3-tastydoc-input` = Build.`scala3-tastydoc-input` val `scala3-bench-run` = Build.`scala3-bench-run` val dist = Build.dist val `community-build` = Build.`community-build` diff --git a/project/Build.scala b/project/Build.scala index 8c3092876a0c..5f62eed05293 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1153,9 +1153,6 @@ object Build { lazy val `scala3-bench-bootstrapped` = project.in(file("bench")).asDottyBench(Bootstrapped) lazy val `scala3-bench-run` = project.in(file("bench-run")).asDottyBench(Bootstrapped) - lazy val `scala3-tastydoc` = project.in(file("tastydoc")).asDottyTastydoc(Bootstrapped) - lazy val `scala3-tastydoc-input` = project.in(file("tastydoc/input")).asDottyTastydocInput(Bootstrapped) - // sbt plugin to use Dotty in your own build, see // https://github.com/lampepfl/scala3-example-project for usage. lazy val `sbt-dotty` = project.in(file("sbt-dotty")). @@ -1395,7 +1392,7 @@ object Build { // FIXME: we do not aggregate `bin` because its tests delete jars, thus breaking other tests def asDottyRoot(implicit mode: Mode): Project = project.withCommonSettings. aggregate(`scala3-interfaces`, dottyLibrary, dottyCompiler, tastyCore, dottyDoc, `scala3-sbt-bridge`). - bootstrappedAggregate(`scala3-language-server`, `scala3-staging`, `scala3-tasty-inspector`, `scala3-tastydoc`, + bootstrappedAggregate(`scala3-language-server`, `scala3-staging`, `scala3-tasty-inspector`, `scala3-library-bootstrappedJS`). dependsOn(tastyCore). dependsOn(dottyCompiler). @@ -1443,15 +1440,6 @@ object Build { settings(commonBenchmarkSettings). enablePlugins(JmhPlugin) - def asDottyTastydoc(implicit mode: Mode): Project = project.withCommonSettings. - aggregate(`scala3-tastydoc-input`). - dependsOn(dottyCompiler). - dependsOn(`scala3-tasty-inspector`). - settings(commonDocSettings) - - def asDottyTastydocInput(implicit mode: Mode): Project = project.withCommonSettings. - dependsOn(dottyCompiler) - def asDist(implicit mode: Mode): Project = project. enablePlugins(PackPlugin). withCommonSettings. diff --git a/tastydoc/.gitignore b/tastydoc/.gitignore deleted file mode 100644 index d2018f967c61..000000000000 --- a/tastydoc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -documentation/* diff --git a/tastydoc/input/project/build.properties b/tastydoc/input/project/build.properties deleted file mode 100644 index 0cd8b07982e1..000000000000 --- a/tastydoc/input/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.2.3 diff --git a/tastydoc/input/src/main/scala/example/Documentation2.scala b/tastydoc/input/src/main/scala/example/Documentation2.scala deleted file mode 100644 index 52eb51f348cc..000000000000 --- a/tastydoc/input/src/main/scala/example/Documentation2.scala +++ /dev/null @@ -1,12 +0,0 @@ -package example - -class ReturnTypeClass[T] { -} - -class UserDocLinkingClass { - def linkMeFromUserDoc() = ??? -} - -object ReturnObjectWithType { - type returnType = Int -} \ No newline at end of file diff --git a/tastydoc/input/src/main/scala/example/Inheritance.scala b/tastydoc/input/src/main/scala/example/Inheritance.scala deleted file mode 100644 index 0ae4f4f5ab2d..000000000000 --- a/tastydoc/input/src/main/scala/example/Inheritance.scala +++ /dev/null @@ -1,5 +0,0 @@ -package example - -import example.level2.Documentation - -abstract class DocumentationInheritance[T, A <: Int, B >: String, -X, +Y] extends Documentation[T, A, B, X, Y] {} \ No newline at end of file diff --git a/tastydoc/input/src/main/scala/example/level2/Documentation.scala b/tastydoc/input/src/main/scala/example/level2/Documentation.scala deleted file mode 100644 index e6f8a3f73f98..000000000000 --- a/tastydoc/input/src/main/scala/example/level2/Documentation.scala +++ /dev/null @@ -1,161 +0,0 @@ -package example -/** Test -*/ -package level2 - -import scala.collection._ -import scala.deprecated -import scala.annotation._ -import scala.math.{Pi, max} - -/** This class is used for testing tasty doc generation - * @constructor create new object - * @author Bryan Abate - * @param c1 class parameter 1 - * @param c2 class parameter 2 - * @tparam T class type parameter - */ -@strictfp -abstract class Documentation[T, A <: Int, B >: String, -X, +Y](c1: String, val c2: List[T]) extends Seq[T] with Product with Serializable{ - - /** Auxiliary constructor - * @param ac auxiliary parameter - */ - def this(ac: String) = this(ac, Nil) - - def this() = this("", Nil) - - def this(x: T) = this() - - class innerDocumentationClass { - - } - - sealed trait CaseImplementThis(id: Int) - case class IAmACaseClass(x: T, id: Int) extends CaseImplementThis(id) - case object IAmACaseObject extends CaseImplementThis(0) - - object testObject { - - } - - def defReturningInnerClass(): innerDocumentationClass = ??? - - /** Test methods with params - * - * @param x parameter 1 - * @param y parameter 2 - * - * @return something is returned - */ - def methodsWithParams(x : T, y: Int) : List[Map[Int, T]] = ??? - - def methodsWithImplicit(x: Int)(implicit imp: Int, notImp: String) = ??? - - def methodsWithCallByName(x: => Int) = ??? - - def methodsWithDefault(x: Int = 42) = ??? - - class Graph { - type Node = Int - } - def linkingGraph(g: Graph): g.Node = ??? - - val refinementTest: - Graph { - //def x(a: String, b: Double)(c: Float): Int - def x: Int - def x2: innerDocumentationClass - type Y = String - val z: Boolean - } - - /** Test value - */ - @showAsInfix - val v : Int = ??? - - protected def protectedMethod = ??? - private def privateMethod = ??? - - protected val protectedVal = ??? - private val privateVal = ??? - - def abstractDefinition : Int - - def apply(idx: Int) = ??? - def iterator = ??? - override def length = ??? - - /** method: [[example.UserDocLinkingClass.linkMeFromUserDoc]] - * - * method:[[example.level2.Documentation.apply]] - * - * class: [[example.UserDocLinkingClass]] - */ - def linkMethodInDoc() = ??? - - /** An example documention with markdown formatting - * - * **I'm bold** - * - * *I'm italic* - * - * `some code` - * ```scala - * def someScalaCode(x: String) = println("Hello " + x) - * ``` - * - *# Title of level 1 - *# Title of level 1 - * - * 1. I'm a list - * - * - * * Multilevel List - * 1. level 2 - * 1. level 2 2 - * * level 1 again - * - * * multilevel try2 - * * try2 level2 - */ - def docWithMd = ??? - - def functionWithType[U >: String]() : U - - val complexTypeVal : Int | List[List[T]] & String | (Double | Int, Double) | ((Int) => (String)) - - type typeExample[X] >: X <: String //TypeBound - - type abstractType - - def useOfOutsideType(): ReturnTypeClass[T] = ??? - def useOfOutsideTypeInsideObject(): ReturnObjectWithType.returnType = ??? - def useOfSameLevelOutsideType(): SameLevelTypeLinking = ??? - - protected[example] val valWithScopeModifier = ??? - protected[this] val valWithScopeModifierThis = ??? - - var iAmAVar = ??? -} - -/** Companion object - */ -object Documentation { - val valInsideDocObject = ??? -} - -sealed abstract class ClassExtendingDocumentation[T, A <: Int, B >: String, -X, +Y] extends Documentation[T, A, B, X, Y] {} - -trait TraitTest { - -} - -val valueInAPackage = 0 - -def defInAPackage(abc: String): List[Int] = ??? - -trait TraitWithCompanion{} - -object TraitWithCompanion{} \ No newline at end of file diff --git a/tastydoc/input/src/main/scala/example/level2/SameLevelTypeLinking.scala b/tastydoc/input/src/main/scala/example/level2/SameLevelTypeLinking.scala deleted file mode 100644 index 5294185e487a..000000000000 --- a/tastydoc/input/src/main/scala/example/level2/SameLevelTypeLinking.scala +++ /dev/null @@ -1,5 +0,0 @@ -package example.level2 - -class SameLevelTypeLinking { - -} \ No newline at end of file diff --git a/tastydoc/input/src/main/scala/example/level2/level3/level4/ClassLevel4.scala b/tastydoc/input/src/main/scala/example/level2/level3/level4/ClassLevel4.scala deleted file mode 100644 index 40d962fc43e1..000000000000 --- a/tastydoc/input/src/main/scala/example/level2/level3/level4/ClassLevel4.scala +++ /dev/null @@ -1,13 +0,0 @@ -package example.level2.level3.level4 - -import example.level2.Documentation - -sealed abstract class ClassLevel4[T, A <: Int, B >: String, -X, +Y]() extends Documentation[T, A, B, X, Y] { - - /** - * [[example.level2.Documentation]] - * [[example.level2.Documentation$.valInsideDocObject]] - * [[example.level2.Documentation.abstractType]] - */ - def linkingToDocMethodInUserDoc = ??? -} \ No newline at end of file diff --git a/tastydoc/project/build.properties b/tastydoc/project/build.properties deleted file mode 100644 index 72f902892a13..000000000000 --- a/tastydoc/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.2.7 diff --git a/tastydoc/readme.md b/tastydoc/readme.md deleted file mode 100644 index 436600045d9a..000000000000 --- a/tastydoc/readme.md +++ /dev/null @@ -1,11 +0,0 @@ -# Tastydoc - -This tool produces Markdown documentation files for Scala projects using TASTy files. - -## How to run -Call main with the following arguments to produce Markdown documentation files: -* **[--syntax SYNTAX]** Syntax for parsing user documentation (either *wiki or markdown*) -* **[--packagestolink REGEXES...]** Regexes of packages or entities (example: `scala.collection.*`). Only the types with a path matching these regexes will produce links in the documentation files -* **[--classpath URI]** Extra classpath for input files -* **[-i FILES...]** TASTy files -* **[-d DIRECTORIES...]** Directories to recursively find TASTy files \ No newline at end of file diff --git a/tastydoc/src/dotty/tastydoc/DocPrinter.scala b/tastydoc/src/dotty/tastydoc/DocPrinter.scala deleted file mode 100644 index bc968d68ffff..000000000000 --- a/tastydoc/src/dotty/tastydoc/DocPrinter.scala +++ /dev/null @@ -1,437 +0,0 @@ -package dotty.tastydoc - -import representations._ -import references._ -import comment.Comment - -import scala.annotation.tailrec - -import java.io._ - -class DocPrinter(mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation], userDocSyntax: String, packagesToLink: List[String]){ - - val packagesMap = mutablePackagesMap.toMap - - private def htmlPreCode(content: String, language: String = ""): String = { - "
" + content + "
" - } - - private def makeLink(label: String, link: String, hasOwnFile: Boolean, declarationPath: List[String]): String = { - val labelName = label.stripSuffix("$") - - val packageFormLink = link.replaceFirst("/", "").replaceAll("/", ".") - - if(packagesToLink.exists(packageFormLink.matches(_))){ - @tailrec - def ascendPath(path: List[String], link: List[String]): String = path match { - case x::xs if link.nonEmpty && link.head == x => ascendPath(xs, link.tail) - case _ => (if(path.isEmpty) "." else path.map(_ => "..").mkString("/")) + (if(link.isEmpty) "" else link.mkString("/", "/", "")) - } - - val relativeLink = { - if(link == ""){ - if(hasOwnFile){ - if(declarationPath.isEmpty){ - "." - }else { - declarationPath.map(_ => "..").mkString("/") - } - }else{ - "" - } - }else{ - ascendPath(declarationPath, link.split("/").toList.tail) - } - } - - if(hasOwnFile){ - "" + labelName + "" - } else if(relativeLink == "") { - labelName - } else if(relativeLink == "."){ - "" + labelName + "" - } else{ - "" + labelName + "" - } - }else{ - labelName - } - } - - private def formatReferences(reference: Reference, declarationPath: List[String]) : String = reference match { - case CompanionReference(label, link, kind) => - makeLink(label, link, true, declarationPath) - case TypeReference(label, link, typeParams, hasOwnFile) => - if(typeParams.isEmpty){ - makeLink(label, link, hasOwnFile, declarationPath) - }else{ - makeLink(label, link, hasOwnFile, declarationPath) + typeParams.map(formatReferences(_, declarationPath)).mkString("[", ", ", "]") - } - case OrTypeReference(left, right) => - formatReferences(left, declarationPath) + " | " + formatReferences(right, declarationPath) - case AndTypeReference(left, right) => - formatReferences(left, declarationPath) + " & " + formatReferences(right, declarationPath) - case FunctionReference(args, returnValue, isImplicit) => - args.map(formatReferences(_, declarationPath)).mkString("(", ", ", ") => ") + formatReferences(returnValue, declarationPath) - case TupleReference(args) => - args.map(formatReferences(_, declarationPath)).mkString("(", ", ", ")") - case BoundsReference(low, high) => - formatReferences(low, declarationPath) + " <: " + formatReferences(high, declarationPath) - case ByNameReference(ref) => - "=> " + formatReferences(ref, declarationPath) - case ConstantReference(label) => label - case NamedReference(name, ref, isRepeated) => name + ": " + formatReferences(ref, declarationPath) + (if(isRepeated) "*" else "") - case RefinedReference(parent, ls) => - formatReferences(parent, declarationPath) + - ls.map((kind, name, tpe) => kind + " " + name + ": " + formatReferences(tpe, declarationPath)).mkString("{ ", "; ", " }") - - case EmptyReference => "" - } - - private def formatParamList(paramList: ParamList, declarationPath: List[String]) : String = paramList.list.map(x => formatReferences(x, declarationPath)).mkString( - "(" + (if(paramList.isImplicit) "implicit " else ""), - ", ", - ")" - ) - - private def formatModifiers(modifiers: List[String], privateWithin: Option[Reference], protectedWithin: Option[Reference], annotations: List[TypeReference], declarationPath: List[String]): String = { - val hasInlineAnnot = annotations.contains(TypeReference("forceInline", "/scala", Nil, true)) - val filteredModifiers = modifiers.filter(x => x != "private" && x != "protected" && (!hasInlineAnnot || x != "inline")) - - (privateWithin match { - case Some(r) => formatReferences(r, declarationPath).mkString("private[", "", "] ") - case None if modifiers.contains("private") => "private " - case None => "" - }) + - (protectedWithin match { - case Some(r) => formatReferences(r, declarationPath).mkString("private[", "", "] ") - case None if modifiers.contains("protected") => "protected " - case None => "" - }) + - (if(filteredModifiers.nonEmpty) filteredModifiers.mkString("", " ", " ") else "") - } - - private def formatComments(comment: (Map[String, EmulatedPackageRepresentation], String) => Option[Comment]) : String = comment(packagesMap, userDocSyntax) match { - case Some(c) => - def removeLineEnds(str: String): String = { - if(str.isEmpty){ - str - }else{ - str.last match { - case '\n' => removeLineEnds(str.stripLineEnd) - case _ => str + "\n\n" - } - } - } - - removeLineEnds(c.body) + - (if(c.authors.nonEmpty) Md.bold(Md.italics("authors")) + " " + c.authors.mkString(", ") + "\n" else "") + - (if(c.see.nonEmpty) Md.bold(Md.italics("see")) + " " + c.see.mkString(", ") + "\n" else "") + - (if(c.result.isDefined) Md.bold(Md.italics("return")) + " " + c.result.get + "\n" else "") + - (if(c.throws.nonEmpty) c.throws.map { case (x, y) => Md.bold(Md.italics(x)) + " " + y }.mkString("\n") else "") + - (if(c.valueParams.nonEmpty) c.valueParams.map { case (x, y) => Md.bold(Md.italics(x)) + " " + y }.mkString("\n") + "\n" else "") + - (if(c.typeParams.nonEmpty) c.typeParams.map { case (x, y) => Md.bold(Md.italics(x)) + " " + y }.mkString("\n") + "\n" else "") + - (if(c.version.isDefined) Md.bold(Md.italics("version")) + " " + c.version.get + "\n" else "") + - (if(c.since.isDefined) Md.bold(Md.italics("since")) + " " + c.since.get + "\n" else "") + - (if(c.todo.nonEmpty) Md.bold(Md.italics("TODO")) + " " + c.todo.mkString(", ") + "\n" else "") + - (if(c.deprecated.isDefined) Md.bold(Md.italics("deprecated")) + " " + c.deprecated.get + "\n" else "") + - (if(c.note.nonEmpty) Md.bold(Md.italics("Note")) + " " + c.note.mkString("\n") + "\n"else "") + - (if(c.example.nonEmpty) Md.bold(Md.italics("Example")) + " " + c.example.mkString("\n") + "\n" else "") + - (if(c.constructor.isDefined) Md.bold(Md.italics("Constructor")) + " " + c.constructor.get + "\n" else "") + - (if(c.group.isDefined) Md.bold(Md.italics("Group")) + " " + c.group.get + "\n" else "") + - (if(c.groupDesc.nonEmpty) c.groupDesc.map { case (x, y) => Md.bold(Md.italics(x)) + " " + y }.mkString("\n") else "") + - (if(c.groupNames.nonEmpty) c.groupNames.map { case (x, y) => Md.bold(Md.italics(x)) + " " + y }.mkString("\n") + "\n" else "") + - (if(c.groupPrio.nonEmpty) c.groupPrio.map { case (x, y) => Md.bold(Md.italics(x)) + " " + y }.mkString("\n") + "\n" else "") + - (if(c.hideImplicitConversions.nonEmpty) Md.bold(Md.italics("Hide Implicit Conversions")) + " " + c.hideImplicitConversions.mkString(", ") + "\n" else "") - case None => "" - } - - private def formatAnnotations(annotations: List[TypeReference], declarationPath: List[String]): String = { - val str = annotations.map("@" + formatReferences(_, declarationPath)).mkString(" ") - if(str.isEmpty) str else str + " " - } - - private def formatSimplifiedClassRepresentation(representation: ClassRepresentation, declarationPath: List[String]): String = { - def formatSimplifiedSignature(): String = { - htmlPreCode( - formatAnnotations(representation.annotations, declarationPath) + - formatModifiers(representation.modifiers, representation.privateWithin, representation.protectedWithin, representation.annotations, declarationPath) + - representation.kind + - " " + - makeLink(representation.name, representation.path.mkString("/", "/", ""), true, declarationPath) - , "scala") + - "\n" - } - - formatSimplifiedSignature() + - formatComments(representation.comments) - } - - private def formatClassRepresentation(representation: ClassRepresentation, declarationPath: List[String]): String = { - def formatCompanion(): String = representation.companion match { - case Some(ref@CompanionReference(_, _, kind)) => - Md.header2("Companion " + - kind + - " " + - formatReferences(ref, declarationPath) - ) + - "\n" - case _ => "" - } - - def formatSignature(): String = { - htmlPreCode(formatModifiers(representation.modifiers, representation.privateWithin, representation.protectedWithin, representation.annotations, representation.path) + - representation.kind + - " " + - (if(representation.isObject) representation.name.stripSuffix("$") else representation.name) + - (if(representation.typeParams.nonEmpty) representation.typeParams.mkString("[", ", ", "]") else "") + - (if(representation.parents.nonEmpty) " extends " + formatReferences(representation.parents.head, representation.path) + representation.parents.tail.map(" with " + formatReferences(_, representation.path)).mkString("") else "") - , "scala") + - "\n" - } - - def formatClassAnnotations(): String = { - if(representation.annotations.isEmpty){ - "" - }else{ - Md.header2("Annotations:") + - formatAnnotations(representation.annotations, declarationPath) + - "\n" - } - } - - def formatKnownSubclasses(): String = { - if(representation.knownSubclasses.isEmpty){ - "" - }else{ - Md.header2("Known subclasses:") + - representation.knownSubclasses.map(formatReferences(_, declarationPath)).mkString(", ") + - "\n" - } - } - - def formatConstructors(): String = { - if(representation.constructors.isEmpty || representation.isObject || (representation.constructors.size == 1 && representation.constructors.head.paramLists.size == 1 && representation.constructors.head.paramLists.head.list == Nil)){ - "" - }else{ - Md.header2("Constructors:") + - representation.constructors.map(ls => htmlPreCode(representation.name + ls.paramLists.map(formatParamList(_, representation.path)).mkString(""), "scala") + "\n" + formatComments(ls.comments)).mkString("") + - "\n" - } - } - - def formatMembers(): String = { - - val nonPrivateMembers = representation.members.filter(!_.isPrivate) - - val typeMembers = nonPrivateMembers.flatMap { - case r: TypeRepresentation => Some(r) - case _ => None - } - val objectMembers = nonPrivateMembers.flatMap { - case r: ClassRepresentation if r.isObject => Some(r) - case _ => None - } - val classMembers = nonPrivateMembers.flatMap { - case r: ClassRepresentation if !r.isObject && !r.isTrait => Some(r) - case _ => None - } - val traitMembers = nonPrivateMembers.flatMap { - case r: ClassRepresentation if r.isTrait => Some(r) - case _ => None - } - val defMembers = nonPrivateMembers.flatMap { - case r: DefRepresentation => Some(r) - case _ => None - } - val valMembers = nonPrivateMembers.flatMap { - case r: ValRepresentation => Some(r) - case _ => None - } - - val abstractTypeMembers = - typeMembers.filter(_.isAbstract).map(x => Md.header3(x.name) + formatRepresentationToMarkdown(x, declarationPath)).mkString("") + - objectMembers.filter(_.isAbstract).map{x => - traverseRepresentation(x) - - Md.header3(x.name.stripSuffix("$")) + - formatSimplifiedClassRepresentation(x, declarationPath) - }.mkString("") + - classMembers.filter(_.isAbstract).map{x => - traverseRepresentation(x) - - Md.header3(x.name) + - formatSimplifiedClassRepresentation(x, declarationPath) - }.mkString("") + - traitMembers.filter(_.isAbstract).map{x => - traverseRepresentation(x) - - Md.header3(x.name) + - formatSimplifiedClassRepresentation(x, declarationPath) - }.mkString("") - - val concreteTypeMembers = - typeMembers.filter(!_.isAbstract).map(x => Md.header3(x.name) + formatRepresentationToMarkdown(x, declarationPath)).mkString("") + - objectMembers.filter(!_.isAbstract).map{x => - traverseRepresentation(x) - - Md.header3(x.name.stripSuffix("$")) + - formatSimplifiedClassRepresentation(x, declarationPath) - }.mkString("") + - classMembers.filter(!_.isAbstract).map{x => - traverseRepresentation(x) - - Md.header3(x.name) + - formatSimplifiedClassRepresentation(x, declarationPath) - }.mkString("") + - traitMembers.filter(!_.isAbstract).map{x => - traverseRepresentation(x) - - Md.header3(x.name) + - formatSimplifiedClassRepresentation(x, declarationPath) - }.mkString("") - - val abstractValueMembers = - defMembers.filter(_.isAbstract).map(x => Md.header3(x.name) + formatRepresentationToMarkdown(x, declarationPath)).mkString("") + - valMembers.filter(_.isAbstract).map(x => Md.header3(x.name) + formatRepresentationToMarkdown(x, declarationPath)).mkString("") - val concreteValueMembers = - defMembers.filter(!_.isAbstract).map(x => Md.header3(x.name) + formatRepresentationToMarkdown(x, declarationPath)).mkString("") + - valMembers.filter(!_.isAbstract).map(x => Md.header3(x.name) + formatRepresentationToMarkdown(x, declarationPath)).mkString("") - - (if(abstractTypeMembers.nonEmpty){ - Md.header2("Abstract Type Members:") + - abstractTypeMembers - }else{ - "" - }) + - (if(concreteTypeMembers.nonEmpty){ - Md.header2("Concrete Type Members:") + - concreteTypeMembers - }else{ - "" - }) + - (if(abstractValueMembers.nonEmpty){ - Md.header2("Abstract Value Members:") + - abstractValueMembers - }else{ - "" - }) + - (if(concreteValueMembers.nonEmpty){ - Md.header2("Concrete Value Members:") + - concreteValueMembers - }else{ - "" - }) - } - - representation.path.mkString(".") + - "\n" + - Md.header1(representation.kind + " " + (if(representation.isObject) representation.name.stripSuffix("$") else representation.name)) + - "\n" + - formatCompanion() + - formatSignature() + - formatComments(representation.comments) + - formatClassAnnotations() + - formatKnownSubclasses() + - formatConstructors() + - formatMembers() - } - - private def formatDefRepresentation(representation: DefRepresentation, declarationPath: List[String]): String = { - htmlPreCode( - formatAnnotations(representation.annotations, declarationPath) + - formatModifiers(representation.modifiers, representation.privateWithin, representation.protectedWithin, representation.annotations, declarationPath) + - "def " + - representation.name + - (if(representation.typeParams.nonEmpty) representation.typeParams.mkString("[", ", ", "]") else "") + - representation.paramLists.map(formatParamList(_, declarationPath)).mkString("") + - ": " + - formatReferences(representation.returnValue, declarationPath) - , "scala") + - "\n" + - { - val com = formatComments(representation.comments) - if(com == "") "\n" else com - } - } - - private def formatValRepresentation(representation: ValRepresentation, declarationPath: List[String]): String = { - htmlPreCode( - formatAnnotations(representation.annotations, declarationPath) + - formatModifiers(representation.modifiers, representation.privateWithin, representation.protectedWithin, representation.annotations, declarationPath) + - (if(representation.isVar) "var " else "val ") + - representation.name + - ": " + - formatReferences(representation.returnValue, declarationPath) - , "scala") + - "\n" + - formatComments(representation.comments) + - "\n" - } - - private def formatTypeRepresentation(representation: TypeRepresentation, declarationPath: List[String]): String = { - htmlPreCode( - formatAnnotations(representation.annotations, declarationPath) + - formatModifiers(representation.modifiers, representation.privateWithin, representation.protectedWithin, representation.annotations, declarationPath) + - "type " + - representation.name + - (if(representation.isAbstract) "" else ": " + formatReferences(representation.alias.get, declarationPath)) - , "scala") + - "\n" + - formatComments(representation.comments) + - "\n" - } - - def formatRepresentationToMarkdown(representation: Representation, declarationPath: List[String], useSimplifiedFormat: Boolean = false): String = representation match { - case r: EmulatedPackageRepresentation => - if(useSimplifiedFormat){ - htmlPreCode("package " + makeLink(r.name, (r.path :+ r.name).mkString("/", "/", ""), true, declarationPath), "scala") //Package file are at one level below the current package - }else{ - Md.header1("Package " + r.name) + - Md.header2("Members:") + - r.members.foldLeft("")((acc, m) => acc + formatRepresentationToMarkdown(m, declarationPath, true)) - } - - case r : PackageRepresentation => - htmlPreCode("package " + makeLink(r.name, (r.path :+ r.name).mkString("/", "/", ""), true, declarationPath), "scala") //Package file are at one level below the current package - - case r: ImportRepresentation => "" - - case r: ClassRepresentation => - if(useSimplifiedFormat){ - formatSimplifiedClassRepresentation(r, declarationPath) - }else{ - formatClassRepresentation(r, declarationPath) - } - - case r: DefRepresentation => formatDefRepresentation(r, declarationPath) - - case r: ValRepresentation => formatValRepresentation(r, declarationPath) - - case r: TypeRepresentation => formatTypeRepresentation(r, declarationPath) - } - - val folderPrefix = "tastydoc/documentation/" - /** Traversing a Representation recursively producing markdown files along the way. In principle, this should be the only method called from outside of the class. */ - def traverseRepresentation(representation: Representation): Unit = representation match { - case r: EmulatedPackageRepresentation => - r.members.foreach(traverseRepresentation) - val file = new File("./" + folderPrefix + (r.path :+ r.name).mkString("/", "/", "/") + r.name + ".md") - file.getParentFile.mkdirs - val pw = new PrintWriter(file) - pw.write(formatRepresentationToMarkdown(r, (r.path :+ r.name))) - pw.close - - case r: PackageRepresentation => - r.members.foreach(traverseRepresentation) - - case r: ClassRepresentation => - val file = new File("./" + folderPrefix + r.path.mkString("", "/", "/") + r.name + ".md") - file.getParentFile.mkdirs - val pw = new PrintWriter(file) - pw.write(formatRepresentationToMarkdown(r, r.path)) - pw.close - - case _ => - } -} diff --git a/tastydoc/src/dotty/tastydoc/Main.scala b/tastydoc/src/dotty/tastydoc/Main.scala deleted file mode 100644 index 0c85a0d0694a..000000000000 --- a/tastydoc/src/dotty/tastydoc/Main.scala +++ /dev/null @@ -1,105 +0,0 @@ -package dotty.tastydoc - -import scala.tasty.inspector._ - -import dotty.tastydoc.representations._ - -import java.io._ - -object Main { - - /** Call main with the following arguments to produce Markdown documentation files: - * * **[--syntax SYNTAX]** Syntax for parsing user documentation (either *wiki or markdown*) - * * **[--packagestolink REGEXES...]** Regexes of packages or entities (example: `scala.collection.*`). Only the types with a path matching these regexes will produce links in the documentation files - * * **[--classpath URI]** Extra classpath for input files - * * **[-i FILES...]** TASTy files - * * **[-d DIRECTORIES...]** Directories to recursively find TASTy files - */ - def main(args: Array[String]): Unit = { - val userDocSyntax = { - val idx = args.indexOf("--syntax") - if(idx >= 0 && args.size > idx + 1){ - if(args(idx + 1) == "markdown"){ - "markdown" - }else if(args(idx + 1) == "wiki"){ - "wiki" - }else{ - println("Wrong parameter for -syntax. Using default: wiki") - "wiki" - } - }else{ - "wiki" - } - } - - val packagesToLink = { - val idx = args.indexOf("--packagestolink") - if(idx >= 0 && args.size > idx + 1){ - args.drop(idx + 1).takeWhile(! _.startsWith("-")).toList - }else{ - Nil - } - } - - - val extraClasspath = { - val idx = args.indexOf("--classpath") - if(idx >= 0 && args.size > idx + 1){ - args(idx + 1) - }else{ - "." - } - } - - val classesI = { - val idx = args.indexOf("-i") - if(idx >= 0 && args.size > idx + 1){ - args.drop(idx + 1).takeWhile(_!= "-d").toList - }else{ - Nil - } - } - - val classesD = { - val idx = args.indexOf("-d") - if(idx >= 0 && args.size > idx + 1){ - val dirs = args.drop(idx + 1).takeWhile(_!= "-i").toList - - def findTastyFiles(f: File): Array[String] = { - val allFiles = f.listFiles - val tastyFiles = allFiles.filter(f => f.getName.endsWith(".tasty")).map(x => x.getPath.stripPrefix(extraClasspath + "/").stripSuffix(".tasty").replaceAll("\\/", ".")) - tastyFiles ++ allFiles.filter(_.isDirectory).flatMap(findTastyFiles) - } - - dirs.flatMap{d => - val f = new File(extraClasspath + "/" + d) - if(f.exists){ - findTastyFiles(f) - }else{ - println("[warn] Ignoring invalid directory name: " + d) - Nil - } - } - }else{ - Nil - } - } - - val classes = classesI ++ classesD - - if (classes.isEmpty) { - println("Dotty Tastydoc: No classes were passed as argument") - } else { - println("Running Dotty Tastydoc on: " + classes.mkString(" ")) - val mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation] = new scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]() - val tc = new TastydocInspector(mutablePackagesMap) - tc.inspect(extraClasspath, classes) - - representations.setSubClasses(mutablePackagesMap) - - val docPrinter = new DocPrinter(mutablePackagesMap, userDocSyntax, packagesToLink) - - mutablePackagesMap.foreach((_, v) => docPrinter.traverseRepresentation(v)) - } - } -} diff --git a/tastydoc/src/dotty/tastydoc/TastyExtractor.scala b/tastydoc/src/dotty/tastydoc/TastyExtractor.scala deleted file mode 100644 index 194fca9d2ecd..000000000000 --- a/tastydoc/src/dotty/tastydoc/TastyExtractor.scala +++ /dev/null @@ -1,185 +0,0 @@ -package dotty.tastydoc - -import scala.quoted._ -import dotty.tastydoc.comment.{CommentParser, CommentCleaner, Comment, WikiComment, MarkdownComment} -import dotty.tastydoc.references._ -import dotty.tastydoc.representations._ - -/** A trait containing useful methods for extracting information from the reflect API */ -trait TastyExtractor extends TastyTypeConverter with CommentParser with CommentCleaner{ - def extractPath(using QuoteContext)(symbol: qctx.reflect.Symbol) : List[String] = { - import qctx.reflect._ - - val pathArray = symbol.show.split("\\.") // NOTE: this should print w/o colors, inspect afterwards - pathArray.iterator.slice(0, pathArray.length - 1).toList - } - - def extractModifiers(using QuoteContext)(flags: qctx.reflect.Flags, privateWithin: Option[qctx.reflect.Type], protectedWithin: Option[qctx.reflect.Type]) : (List[String], Option[Reference], Option[Reference]) = { - import qctx.reflect._ - - (((if(flags.is(Flags.Override)) "override" else "") :: - (if(flags.is(Flags.Private)) "private" else ""):: - (if(flags.is(Flags.Protected)) "protected" else "") :: - (if(flags.is(Flags.Final)) "final" else "") :: - (if(flags.is(Flags.Sealed)) "sealed" else "") :: - (if(flags.is(Flags.Implicit)) "implicit" else "") :: - (if(flags.is(Flags.Abstract)) "abstract" else "") :: - // (if(flags.is(Flags.AbsOverride)) "absOverride" else "") :: //TOFIX Not visible, fix in Dotty. When fixed, need fix in output as well - // (if(flags.is(Flags.Deferred)) "deferred" else "") :: //TOFIX Not visible, fix in Dotty. When fixed, need fix in output as well - (if(flags.is(Flags.Inline)) "inline" else "") :: - Nil) filter (_ != ""), - - privateWithin match { - case Some(t) => Some(convertTypeToReference(t)) - case None => None - }, - protectedWithin match { - case Some(t) => Some(convertTypeToReference(t)) - case None => None - }) - } - - def extractComments(using QuoteContext)(comment: Option[qctx.reflect.Documentation], rep: Representation) : (Map[String, EmulatedPackageRepresentation], String) => Option[Comment] = { - comment match { - case Some(com) => - (packages, userDocSyntax) => { - val parsed = parse(rep, packages, clean(com.raw), com.raw) - if (userDocSyntax == "markdown") { - Some(MarkdownComment(rep, parsed, packages).comment) - }else if(userDocSyntax == "wiki"){ - Some(WikiComment(rep, parsed, packages).comment) - }else{ - Some(WikiComment(rep, parsed, packages).comment) - } - } - case None => (_, _) => None - } - } - - def extractClassMembers(using QuoteContext)(body: List[qctx.reflect.Statement], symbol: qctx.reflect.Symbol, parentRepresentation: Some[Representation])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) : List[Representation with Modifiers] = { - import qctx.reflect._ - - /** Filter fields which shouldn't be displayed in the doc - */ - def filterSymbol(symbol: Symbol): Boolean = { - val ownerPath = extractPath(symbol.owner) - - !symbol.flags.is(Flags.Synthetic) && - !symbol.flags.is(Flags.Artifact) && - !symbol.flags.is(Flags.StableRealizable) && //Remove val generated for object definitions inside classes - !symbol.name.contains("$default$") &&//Remove artifact methods generated for methods with default parameters - !(symbol.owner.name == "Object" && ownerPath == List("java", "lang")) && - !(symbol.owner.name == "Any" && ownerPath == List("scala")) - } - - (body.flatMap { - case _: DefDef => None //No definitions, they are appended with symbol.methods below - case _: ValDef => None //No val/var, they are appended with symbol.fields below - case _: Inlined => None //Inlined aren't desirable members - case x => Some(x) - }.filter(x => filterSymbol(x.symbol)).map(convertToRepresentation(_, parentRepresentation)) ++ - symbol.methods.filter(x => filterSymbol(x)).map{x => convertToRepresentation(x.tree, parentRepresentation)} ++ - symbol.fields.filter { x => - filterSymbol(x) - }.flatMap { - case x if x.isValDef => Some(x) - // case qctx.reflect.IsValDefSymbol(x) => Some(x) - case _ => None - }.map { x => - convertToRepresentation(x.tree, parentRepresentation) - } - ) - .flatMap{ - case r: Representation with Modifiers => Some(r) - case _ => None - } - .sortBy(_.name) - } - - def extractParents(using QuoteContext)(parents: List[qctx.reflect.Tree]): List[Reference] = { - import qctx.reflect._ - - val parentsReferences = parents.map{ - case c: TypeTree => convertTypeToReference(c.tpe) - case c: Term => convertTypeToReference(c.tpe) - case _ => throw Exception("Unhandeld case in parents. Please open an issue.") - } - - parentsReferences.filter{_ match{ - case TypeReference("Object", "/lang", _, _) | TypeReference("Object", "/java/lang", _, _) => false - case _ => true - }} - } - - /** The kind of a ClassDef can be one of the following: class, case class, object, case object, trait - * - * @return (is case, is a trait, is an object, the kind as a String) - */ - def extractKind(using QuoteContext)(flags: qctx.reflect.Flags): (Boolean, Boolean, Boolean, String) = { - import qctx.reflect._ - - val isCase = flags.is(Flags.Case) - val isTrait = flags.is(Flags.Trait) - val isObject = flags.is(Flags.Object) - val kind = { - if(isTrait){ - "trait" - }else{ - (if(isCase){ - "case " - }else{ - "" - }) + - (if(isObject){ - "object" - }else{ - "class" - }) - } - } - (isCase, isTrait, isObject, kind) - } - - def extractCompanion(using QuoteContext)(companionModule: Option[qctx.reflect.Symbol], companionClass: Option[qctx.reflect.Symbol], companionIsObject: Boolean): Option[CompanionReference] = { - import qctx.reflect._ - - if(companionIsObject){ - companionModule match { - case Some(c) => - val path = extractPath(c) - val (_, _, _, kind) = extractKind(c.flags) - Some(CompanionReference(c.name + "$", path.mkString("/", "/", ""), kind)) - case None => None - } - }else{ - companionClass match { - case Some(c) => - val path = extractPath(c) - val (_, _, _, kind) = extractKind(c.flags) - Some(CompanionReference(c.name, path.mkString("/", "/", ""), kind)) - case None => None - } - } - } - - def extractAnnotations(using QuoteContext)(annots: List[qctx.reflect.Term]): List[TypeReference] = { - import qctx.reflect._ - - def keepAnnot(label: String, link: String): Boolean = { - !(label == "SourceFile" && link == "/internal") && - !(label == "Child" && link == "/internal") - } - - annots.flatMap{a => - convertTypeToReference(a.tpe) match { - case ref@TypeReference(label, link, _, _) if keepAnnot(label, link) => Some(ref) - case _ => None - } - } - } - - def extractPackageNameAndPath(pidShowNoColor: String): (String, List[String]) = { - val pidSplit = pidShowNoColor.split("\\.") - (pidSplit.last, pidSplit.init.toList) - } -} diff --git a/tastydoc/src/dotty/tastydoc/TastyTypeConverter.scala b/tastydoc/src/dotty/tastydoc/TastyTypeConverter.scala deleted file mode 100644 index 5f709b2f7ce4..000000000000 --- a/tastydoc/src/dotty/tastydoc/TastyTypeConverter.scala +++ /dev/null @@ -1,103 +0,0 @@ -package dotty.tastydoc - -import scala.quoted._ -import dotty.tastydoc.references._ - -/** Trait containing methods for converting from Reflect types to References */ -trait TastyTypeConverter { - - def convertTypeToReference(using QuoteContext)(tp: qctx.reflect.Type): Reference = { - import qctx.reflect._ - - //Inner method to avoid passing the reflection each time - def inner(tp: Type): Reference = tp match { - case OrType(left, right) => OrTypeReference(inner(left), inner(right)) - case AndType(left, right) => AndTypeReference(inner(left), inner(right)) - case ByNameType(tpe) => ByNameReference(inner(tpe)) - case ConstantType(constant) => ConstantReference(constant.value.toString) - case ThisType(tpe) => inner(tpe) - case AnnotatedType(tpe, _) => inner(tpe) - case TypeLambda(paramNames, paramTypes, resType) => ConstantReference(tp.show) //TOFIX - case Refinement(parent, name, info) => - val tuple = convertTypeToReference(info) match { - case r if (info match {case info: TypeBounds => true case _ => false}) => ("type", name, r) - case r@TypeReference(_, _, _, _) => ("val", name, r) - case ByNameReference(rChild) => ("def", name, rChild) - case r => throw new Exception("Match error in info of Refinement. This should not happen, please open an issue. " + r) - } - convertTypeToReference(parent) match { - case RefinedReference(p, ls) => - RefinedReference(p, ls:+tuple) - case t => RefinedReference(t, List(tuple)) - } - case AppliedType(tpe, typeOrBoundsList) => - inner(tpe) match { - case TypeReference(label, link, _, hasOwnFile) => - if(link == "/scala"){ - if(label.matches("Function[1-9]") || label.matches("Function[1-9][0-9]")){ - val argsAndReturn = typeOrBoundsList.map(convertTypeToReference(_)) - FunctionReference(argsAndReturn.take(argsAndReturn.size - 1), argsAndReturn.last, false) - }else if(label.matches("Tuple[1-9]") || label.matches("Tuple[1-9][0-9]")){ - TupleReference(typeOrBoundsList.map(convertTypeToReference(_))) - }else{ - TypeReference(label, link, typeOrBoundsList.map(convertTypeToReference(_)), hasOwnFile) - } - }else{ - TypeReference(label, link, typeOrBoundsList.map(convertTypeToReference(_)), hasOwnFile) - } - case _ => throw Exception("Match error in AppliedType. This should not happen, please open an issue. " + tp) - } - case tp @ TypeRef(qual, typeName) => - convertTypeToReference(qual) match { - case TypeReference(label, link, xs, _) => TypeReference(typeName, link + "/" + label, xs, true) - case EmptyReference => TypeReference(typeName, "", Nil, true) - case _ if tp.typeSymbol.exists => - tp.typeSymbol match { - // NOTE: Only TypeRefs can reference ClassDefSymbols - case sym if sym.isClassDef => //Need to be split because these types have their own file - convertTypeToReference(qual) match { - case TypeReference(label, link, xs, _) => TypeReference(sym.name, link + "/" + label, xs, true) - case EmptyReference if sym.name == "" | sym.name == "_root_" => EmptyReference - case EmptyReference => TypeReference(sym.name, "", Nil, true) - case _ => throw Exception("Match error in SymRef/Types/ClassDef. This should not happen, please open an issue. " + convertTypeToReference(qual)) - } - - // NOTE: This branch handles packages, which are now TypeRefs - case sym if sym.isTerm || sym.isTypeDef => - convertTypeToReference(qual) match { - case TypeReference(label, link, xs, _) => TypeReference(sym.name, link + "/" + label, xs) - case EmptyReference if sym.name == "" | sym.name == "_root_" => EmptyReference - case EmptyReference => TypeReference(sym.name, "", Nil) - case _ => throw Exception("Match error in SymRef/Types/Other. This should not happen, please open an issue. " + convertTypeToReference(qual)) - } - case sym => throw Exception("Match error in SymRef. This should not happen, please open an issue. " + sym) - } - case _ => - throw Exception("Match error in TypeRef. This should not happen, please open an issue. " + convertTypeToReference(qual)) - } - case TermRef(qual, typeName) => - convertTypeToReference(qual) match { - case TypeReference(label, link, xs, _) => TypeReference(typeName + "$", link + "/" + label, xs) - case EmptyReference => TypeReference(typeName, "", Nil) - case _ => throw Exception("Match error in TermRef. This should not happen, please open an issue. " + convertTypeToReference(qual)) - } - case TypeBounds(low, hi) => - val lowRef = convertTypeToReference(low) - val hiRef = convertTypeToReference(hi) - if(hiRef == lowRef){ - hiRef - }else{ - BoundsReference(lowRef, hiRef) - } - case NoPrefix() => EmptyReference - - // NOTE: old SymRefs are now either TypeRefs or TermRefs - the logic here needs to be moved into above branches - // NOTE: _.symbol on *Ref returns its symbol - // case SymRef(symbol, typeOrBounds) => symbol match { - // } - // case _ => throw Exception("No match for type in conversion to Reference. This should not happen, please open an issue. " + tp) - } - - inner(tp) - } -} diff --git a/tastydoc/src/dotty/tastydoc/TastydocInspector.scala b/tastydoc/src/dotty/tastydoc/TastydocInspector.scala deleted file mode 100644 index adf240f0fdf1..000000000000 --- a/tastydoc/src/dotty/tastydoc/TastydocInspector.scala +++ /dev/null @@ -1,17 +0,0 @@ -package dotty.tastydoc - -import scala.quoted._ -import scala.tasty.inspector.TastyInspector - -import dotty.tastydoc.representations._ - -/* Extends TastyInspector and consumes Tasty Files to produce Representations - * - * @param mutablePackagesMap A mutable HashMap where seen packages are added - */ -class TastydocInspector(mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) extends TastyInspector { - - protected def processCompilationUnit(using QuoteContext)(root: qctx.tasty.Tree): Unit = { - representations.convertToRepresentation(root, None)(using mutablePackagesMap) - } -} diff --git a/tastydoc/src/dotty/tastydoc/comment/BodyEntities.scala b/tastydoc/src/dotty/tastydoc/comment/BodyEntities.scala deleted file mode 100644 index 5dcb285986be..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/BodyEntities.scala +++ /dev/null @@ -1,94 +0,0 @@ -package dotty.tastydoc -package comment - -import scala.collection.{Seq => _, _} -import representations._ - -/** A body of text. A comment has a single body, which is composed of - * at least one block. Inside every body is exactly one summary (see - * [[scala.tools.nsc.doc.model.comment.Summary]]). */ -final case class Body(blocks: Seq[Block]) { - - /** The summary text of the comment body. */ - lazy val summary: Option[Body] = { - def summaryInBlock(block: Block): Seq[Inline] = block match { - case Title(text, _) => summaryInInline(text) - case Paragraph(text) => summaryInInline(text) - case UnorderedList(items) => items flatMap summaryInBlock - case OrderedList(items, _) => items flatMap summaryInBlock - case DefinitionList(items) => items.values.toSeq flatMap summaryInBlock - case _ => Nil - } - def summaryInInline(text: Inline): Seq[Inline] = text match { - case Summary(text) => List(text) - case Chain(items) => items flatMap summaryInInline - case Italic(text) => summaryInInline(text) - case Bold(text) => summaryInInline(text) - case Underline(text) => summaryInInline(text) - case Superscript(text) => summaryInInline(text) - case Subscript(text) => summaryInInline(text) - case Link(_, title) => summaryInInline(title) - case _ => Nil - } - (blocks flatMap summaryInBlock).toList match { - case Nil => None - case inl :: Nil => Some(Body(Seq(Paragraph(inl)))) - case inls => Some(Body(Seq(Paragraph(Chain(inls))))) - } - } -} - -/** A block-level element of text, such as a paragraph or code block. */ -sealed abstract class Block - -final case class Title(text: Inline, level: Int) extends Block -final case class Paragraph(text: Inline) extends Block -final case class Code(data: String) extends Block -final case class UnorderedList(items: Seq[Block]) extends Block -final case class OrderedList(items: Seq[Block], style: String) extends Block -final case class DefinitionList(items: SortedMap[Inline, Block]) extends Block -final case class HorizontalRule() extends Block - -/** An section of text inside a block, possibly with formatting. */ -sealed abstract class Inline - -final case class Chain(items: Seq[Inline]) extends Inline -final case class Italic(text: Inline) extends Inline -final case class Bold(text: Inline) extends Inline -final case class Underline(text: Inline) extends Inline -final case class Superscript(text: Inline) extends Inline -final case class Subscript(text: Inline) extends Inline -final case class Link(target: String, title: Inline) extends Inline -final case class Monospace(text: Inline) extends Inline -final case class Text(text: String) extends Inline -abstract class RepresentationLink(val title: Inline) extends Inline { def link: LinkTo } -object RepresentationLink { - def apply(title: Inline, linkTo: LinkTo) = new RepresentationLink(title) { def link: LinkTo = linkTo } - def unapply(el: RepresentationLink): Some[(Inline, LinkTo)] = Some((el.title, el.link)) -} -final case class HtmlTag(data: String) extends Inline { - private val Pattern = """(?ms)\A<(/?)(.*?)[\s>].*\z""".r - private val (isEnd, tagName) = data match { - case Pattern(s1, s2) => - (! s1.isEmpty, Some(s2.toLowerCase)) - case _ => - (false, None) - } - - def canClose(open: HtmlTag) = { - isEnd && tagName == open.tagName - } - - private val TagsNotToClose = Set("br", "img") - def close = tagName collect { case name if !TagsNotToClose(name) => HtmlTag(s"") } -} - -/** The summary of a comment, usually its first sentence. There must be exactly one summary per body. */ -final case class Summary(text: Inline) extends Inline - -sealed trait LinkTo -final case class LinkToExternal(name: String, url: String) extends LinkTo -final case class Tooltip(name: String) extends LinkTo - -/** Linking directly to entities is not picklable because of cyclic references */ -final case class LinkToRepresentation(representation: Representation) extends LinkTo diff --git a/tastydoc/src/dotty/tastydoc/comment/Comment.scala b/tastydoc/src/dotty/tastydoc/comment/Comment.scala deleted file mode 100644 index 2af21095548c..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/Comment.scala +++ /dev/null @@ -1,167 +0,0 @@ -package dotty.tastydoc -package comment - -import com.vladsch.flexmark.util.ast.{ Node => MarkdownNode } -import HtmlParsers._ -import util.MemberLookup -import representations._ - -import com.vladsch.flexmark.formatter.Formatter; -import com.vladsch.flexmark.util.options.MutableDataSet; - -case class Comment ( - body: String, - short: String, - authors: List[String], - see: List[String], - result: Option[String], - throws: Map[String, String], - valueParams: Map[String, String], - typeParams: Map[String, String], - version: Option[String], - since: Option[String], - todo: List[String], - deprecated: Option[String], - note: List[String], - example: List[String], - constructor: Option[String], - group: Option[String], - groupDesc: Map[String, String], - groupNames: Map[String, String], - groupPrio: Map[String, String], - /** List of conversions to hide - containing e.g: `scala.Predef.FloatArrayOps` */ - hideImplicitConversions: List[String] -) - -private[comment] case class ParsedComment ( - body: String, - authors: List[String], - see: List[String], - result: List[String], - throws: Map[String, String], - valueParams: Map[String, String], - typeParams: Map[String, String], - version: List[String], - since: List[String], - todo: List[String], - deprecated: List[String], - note: List[String], - example: List[String], - constructor: List[String], - group: List[String], - groupDesc: Map[String, String], - groupNames: Map[String, String], - groupPrio: Map[String, String], - hideImplicitConversions: List[String], - shortDescription: List[String] -) - -trait MarkupConversion[T](packages: Map[String, EmulatedPackageRepresentation]) extends MemberLookup { - def ent: Representation - def parsed: ParsedComment - - protected def linkedExceptions(m: Map[String, String]): Map[String, String] - protected def stringToMarkup(str: String): T - protected def markupToMarkdown(t: T): String - protected def stringToShortMarkdown(str: String): String - protected def filterEmpty(xs: List[String]): List[T] - protected def filterEmpty(xs: Map[String, String]): Map[String, T] - - private def single(annot: String, xs: List[String], filter: Boolean = true): Option[T] = - (if (filter) filterEmpty(xs) else xs.map(stringToMarkup)) match { - case x :: xs => - Some(x) - case _ => None - } - - final def comment: Comment = Comment( - body = markupToMarkdown(stringToMarkup(parsed.body)), - short = stringToShortMarkdown(parsed.body), - authors = filterEmpty(parsed.authors).map(markupToMarkdown), - see = filterEmpty(parsed.see).map(markupToMarkdown), - result = single("@result", parsed.result).map(markupToMarkdown), - throws = linkedExceptions(parsed.throws), - valueParams = filterEmpty(parsed.valueParams).view.mapValues(markupToMarkdown).toMap, - typeParams = filterEmpty(parsed.typeParams).view.mapValues(markupToMarkdown).toMap, - version = single("@version", parsed.version).map(markupToMarkdown), - since = single("@since", parsed.since).map(markupToMarkdown), - todo = filterEmpty(parsed.todo).map(markupToMarkdown), - deprecated = single("@deprecated", parsed.deprecated, filter = false).map(markupToMarkdown), - note = filterEmpty(parsed.note).map(markupToMarkdown), - example = filterEmpty(parsed.example).map(markupToMarkdown), - constructor = single("@constructor", parsed.constructor).map(markupToMarkdown), - group = single("@group", parsed.group).map(markupToMarkdown), - groupDesc = filterEmpty(parsed.groupDesc).view.mapValues(markupToMarkdown).toMap, - groupNames = filterEmpty(parsed.groupNames).view.mapValues(markupToMarkdown).toMap, - groupPrio = filterEmpty(parsed.groupPrio).view.mapValues(markupToMarkdown).toMap, - hideImplicitConversions = filterEmpty(parsed.hideImplicitConversions).map(markupToMarkdown) - ) -} - -case class MarkdownComment(ent: Representation, parsed: ParsedComment, packages: Map[String, EmulatedPackageRepresentation]) -extends MarkupConversion[MarkdownNode](packages) { - - def stringToMarkup(str: String) = - str.toMarkdown(ent, packages) - - def stringToShortMarkdown(str: String) = - str.toMarkdown(ent, packages).shortenAndShow - - def markupToMarkdown(md: MarkdownNode) = - md.show - - def linkedExceptions(m: Map[String, String]) = { - val inlineToMarkdown = InlineToMarkdown(ent) - m.map { case (targetStr, body) => - val link = makeRepresentationLink(ent, packages, Monospace(Text(targetStr)), targetStr) - (targetStr, inlineToMarkdown(link)) - } - } - - def filterEmpty(xs: List[String]) = - xs.map(_.trim) - .filterNot(_.isEmpty) - .map(stringToMarkup) - - def filterEmpty(xs: Map[String, String]) = - xs.view.mapValues(_.trim).toMap - .filterNot { case (_, v) => v.isEmpty } - .view.mapValues(stringToMarkup).toMap -} - -case class WikiComment(ent: Representation, parsed: ParsedComment, packages: Map[String, EmulatedPackageRepresentation]) -extends MarkupConversion[Body](packages) { - - def filterEmpty(xs: Map[String,String]) = - xs.view.mapValues(_.toWiki(ent, packages)).toMap - .filterNot { case (_, v) => v.blocks.isEmpty } - - def filterEmpty(xs: List[String]) = - xs.map(_.toWiki(ent, packages)) - - def markupToMarkdown(t: Body) = - t.show(ent) - - def stringToMarkup(str: String) = - str.toWiki(ent, packages) - - def stringToShortMarkdown(str: String) = { - val parsed = stringToMarkup(str) - parsed.summary.getOrElse(parsed).show(ent) - } - - def linkedExceptions(m: Map[String, String]) = { - m.view.mapValues(_.toWiki(ent, packages)).toMap.map { case (targetStr, body) => - val link = lookup(Some(ent), packages, targetStr) - val newBody = body match { - case Body(List(Paragraph(Chain(content)))) => - val descr = Text(" ") +: content - val link = makeRepresentationLink(ent, packages, Monospace(Text(targetStr)), targetStr) - Body(List(Paragraph(Chain(link +: descr)))) - case _ => body - } - - (targetStr, newBody.show(ent)) - } - } -} diff --git a/tastydoc/src/dotty/tastydoc/comment/CommentCleaner.scala b/tastydoc/src/dotty/tastydoc/comment/CommentCleaner.scala deleted file mode 100644 index a48be97ef8b1..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/CommentCleaner.scala +++ /dev/null @@ -1,25 +0,0 @@ -package dotty.tastydoc -package comment - -trait CommentCleaner { - import Regexes._ - import java.util.regex.Matcher - - def clean(comment: String): List[String] = { - def cleanLine(line: String): String = { - // Remove trailing whitespaces - TrailingWhitespace.replaceAllIn(line, "") match { - case CleanCommentLine(ctl) => ctl - case tl => tl - } - } - val strippedComment = comment.trim.stripPrefix("/*").stripSuffix("*/") - val safeComment = DangerousTags.replaceAllIn(strippedComment, { htmlReplacement(_) }) - val javadoclessComment = JavadocTags.replaceAllIn(safeComment, { javadocReplacement(_) }) - val markedTagComment = - SafeTags.replaceAllIn(javadoclessComment, { mtch => - Matcher.quoteReplacement(s"$safeTagMarker${mtch.matched}$safeTagMarker") - }) - markedTagComment.linesIterator.toList map (cleanLine) - } -} diff --git a/tastydoc/src/dotty/tastydoc/comment/CommentParser.scala b/tastydoc/src/dotty/tastydoc/comment/CommentParser.scala deleted file mode 100644 index 17b84258f7db..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/CommentParser.scala +++ /dev/null @@ -1,219 +0,0 @@ -package dotty.tastydoc -package comment - -import scala.collection.mutable -import scala.util.matching.Regex -import com.vladsch.flexmark.util.ast.{ Node => MarkdownNode } -import com.vladsch.flexmark.parser.{ Parser => MarkdownParser } -import dotty.tastydoc.representations._ - -trait CommentParser { - import Regexes._ - - /** Parses a raw comment string into a `Comment` object. - * @param packages all packages parsed by Scaladoc tool, used for lookup - * @param cleanComment a cleaned comment to be parsed - * @param src the raw comment source string. - * @param span the position of the comment in source. - */ - def parse( - representation: Representation, - packages: Map[String, EmulatedPackageRepresentation], - comment: List[String], - src: String - ): ParsedComment = { - - /** Parses a comment (in the form of a list of lines) to a `Comment` - * instance, recursively on lines. To do so, it splits the whole comment - * into main body and tag bodies, then runs the `WikiParser` on each body - * before creating the comment instance. - * - * @param docBody The body of the comment parsed until now. - * @param tags All tags parsed until now. - * @param lastTagKey The last parsed tag, or `None` if the tag section - * hasn't started. Lines that are not tagged are part - * of the previous tag or, if none exists, of the body. - * @param remaining The lines that must still recursively be parsed. - * @param inCodeBlock Whether the next line is part of a code block (in - * which no tags must be read). - */ - def parseComment ( - docBody: StringBuilder, - tags: Map[TagKey, List[String]], - lastTagKey: Option[TagKey], - remaining: List[String], - inCodeBlock: Boolean - ): ParsedComment = remaining match { - - case CodeBlockStartRegex(before, marker, after) :: ls if (!inCodeBlock) => - if (!before.trim.isEmpty && !after.trim.isEmpty) - parseComment(docBody, tags, lastTagKey, before :: marker :: after :: ls, inCodeBlock = false) - else if (!before.trim.isEmpty) - parseComment(docBody, tags, lastTagKey, before :: marker :: ls, inCodeBlock = false) - else if (!after.trim.isEmpty) - parseComment(docBody, tags, lastTagKey, marker :: after :: ls, inCodeBlock = true) - else lastTagKey match { - case Some(key) => - val value = - ((tags get key): @unchecked) match { - case Some(b :: bs) => (b + endOfLine + marker) :: bs - case None => oops("lastTagKey set when no tag exists for key") - } - parseComment(docBody, tags + (key -> value), lastTagKey, ls, inCodeBlock = true) - case None => - parseComment(docBody append endOfLine append marker, tags, lastTagKey, ls, inCodeBlock = true) - } - - case CodeBlockEndRegex(before, marker, after) :: ls => { - if (!before.trim.isEmpty && !after.trim.isEmpty) - parseComment(docBody, tags, lastTagKey, before :: marker :: after :: ls, inCodeBlock = true) - if (!before.trim.isEmpty) - parseComment(docBody, tags, lastTagKey, before :: marker :: ls, inCodeBlock = true) - else if (!after.trim.isEmpty) - parseComment(docBody, tags, lastTagKey, marker :: after :: ls, inCodeBlock = false) - else lastTagKey match { - case Some(key) => - val value = - ((tags get key): @unchecked) match { - case Some(b :: bs) => (b + endOfLine + marker) :: bs - case None => oops("lastTagKey set when no tag exists for key") - } - parseComment(docBody, tags + (key -> value), lastTagKey, ls, inCodeBlock = false) - case None => - parseComment(docBody append endOfLine append marker, tags, lastTagKey, ls, inCodeBlock = false) - } - } - - case SymbolTagRegex(name, sym, body) :: ls if (!inCodeBlock) => { - val key = SymbolTagKey(name, sym) - val value = body :: tags.getOrElse(key, Nil) - parseComment(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) - } - - case SimpleTagRegex(name, body) :: ls if (!inCodeBlock) => { - val key = SimpleTagKey(name) - val value = body :: tags.getOrElse(key, Nil) - parseComment(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) - } - - case SingleTagRegex(name) :: ls if (!inCodeBlock) => { - val key = SimpleTagKey(name) - val value = "" :: tags.getOrElse(key, Nil) - parseComment(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) - } - - case line :: ls if (lastTagKey.isDefined) => { - val newtags = if (!line.isEmpty) { - val key = lastTagKey.get - val value = - ((tags get key): @unchecked) match { - case Some(b :: bs) => (b + endOfLine + line) :: bs - case None => oops("lastTagKey set when no tag exists for key") - } - tags + (key -> value) - } else tags - parseComment(docBody, newtags, lastTagKey, ls, inCodeBlock) - } - - case line :: ls => { - if (docBody.length > 0) docBody append endOfLine - docBody append line - parseComment(docBody, tags, lastTagKey, ls, inCodeBlock) - } - - case Nil => { - // Take the {inheritance, content} diagram keys aside, as it doesn't need any parsing - val inheritDiagramTag = SimpleTagKey("inheritanceDiagram") - val contentDiagramTag = SimpleTagKey("contentDiagram") - - val inheritDiagramText: List[String] = tags.get(inheritDiagramTag) match { - case Some(list) => list - case None => List.empty - } - - val contentDiagramText: List[String] = tags.get(contentDiagramTag) match { - case Some(list) => list - case None => List.empty - } - - val stripTags = List(inheritDiagramTag, contentDiagramTag, SimpleTagKey("template"), SimpleTagKey("documentable")) - val tagsWithoutDiagram = tags.filterNot(pair => stripTags.contains(pair._1)) - - val bodyTags: mutable.Map[TagKey, List[String]] = - mutable.Map((tagsWithoutDiagram).toSeq: _*) - - def allTags(key: SimpleTagKey): List[String] = - (bodyTags remove key).getOrElse(Nil).reverse - - def allSymsOneTag(key: TagKey, filterEmpty: Boolean = true): Map[String, String] = { - val keys: Seq[SymbolTagKey] = - bodyTags.keys.toSeq flatMap { - case stk: SymbolTagKey if (stk.name == key.name) => Some(stk) - case stk: SimpleTagKey if (stk.name == key.name) => - // dottydoc.println(s"$span: tag '@${stk.name}' must be followed by a symbol name") - None - case _ => None - } - val pairs: Seq[(String, String)] = - for (key <- keys) yield { - val bs = (bodyTags remove key).get - // if (bs.length > 1) - // dottydoc.println(s"$span: only one '@${key.name}' tag for symbol ${key.symbol} is allowed") - (key.symbol, bs.head) - } - Map.empty[String, String] ++ pairs - } - - val cmt = ParsedComment( - body = docBody.toString, - authors = allTags(SimpleTagKey("author")), - see = allTags(SimpleTagKey("see")), - result = allTags(SimpleTagKey("return")), - throws = allSymsOneTag(SimpleTagKey("throws")), - valueParams = allSymsOneTag(SimpleTagKey("param")), - typeParams = allSymsOneTag(SimpleTagKey("tparam")), - version = allTags(SimpleTagKey("version")), - since = allTags(SimpleTagKey("since")), - todo = allTags(SimpleTagKey("todo")), - deprecated = allTags(SimpleTagKey("deprecated")), - note = allTags(SimpleTagKey("note")), - example = allTags(SimpleTagKey("example")), - constructor = allTags(SimpleTagKey("constructor")), - group = allTags(SimpleTagKey("group")), - groupDesc = allSymsOneTag(SimpleTagKey("groupdesc")), - groupNames = allSymsOneTag(SimpleTagKey("groupname")), - groupPrio = allSymsOneTag(SimpleTagKey("groupprio")), - hideImplicitConversions = allTags(SimpleTagKey("hideImplicitConversion")), - shortDescription = allTags(SimpleTagKey("shortDescription")) - ) - - // for ((key, _) <- bodyTags) ctx.docbase.warn( - // hl"Tag '${"@" + key.name}' is not recognised", - // // FIXME: here the position is stretched out over the entire comment, - // // with the point being at the very end. This ensures that the entire - // // comment will be visible in error reporting. A more fine-grained - // // reporting would be amazing here. - // entity.symbol.sourcePosition(Span(span.start, span.end, span.end)) - // ) - - cmt - } - } - - parseComment(new StringBuilder(comment.size), Map.empty, None, comment, inCodeBlock = false) - } - - /** A key used for a tag map. The key is built from the name of the tag and - * from the linked symbol if the tag has one. - * Equality on tag keys is structural. */ - private sealed abstract class TagKey { - def name: String - } - - private /*final*/ case class SimpleTagKey(name: String) extends TagKey - private /*final*/ case class SymbolTagKey(name: String, symbol: String) extends TagKey - - /** Something that should not have happened, happened, and Scaladoc should exit. */ - private def oops(msg: String): Nothing = - throw new IllegalArgumentException("program logic: " + msg) -} diff --git a/tastydoc/src/dotty/tastydoc/comment/CommentRegex.scala b/tastydoc/src/dotty/tastydoc/comment/CommentRegex.scala deleted file mode 100644 index cd17e06999bf..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/CommentRegex.scala +++ /dev/null @@ -1,82 +0,0 @@ -package dotty.tastydoc.comment - -import scala.util.matching.Regex - -object Regexes { - val TrailingWhitespace = """\s+$""".r - - /** The body of a line, dropping the (optional) start star-marker, - * one leading whitespace and all trailing whitespace - */ - val CleanCommentLine = - new Regex("""(?:\s*\*\s?\s?)?(.*)""") - - /** Dangerous HTML tags that should be replaced by something safer, - * such as wiki syntax, or that should be dropped - */ - val DangerousTags = - new Regex("""<(/?(div|ol|ul|li|h[1-6]|p))( [^>]*)?/?>|""") - - /** Javadoc tags that should be replaced by something useful, such as wiki - * syntax, or that should be dropped. */ - val JavadocTags = - new Regex("""\{\@(code|docRoot|linkplain|link|literal|value)\p{Zs}*([^}]*)\}""") - - /** Maps a javadoc tag to a useful wiki replacement, or an empty string if it cannot be salvaged. */ - def javadocReplacement(mtch: Regex.Match): String = { - mtch.group(1) match { - case "code" => "" + mtch.group(2) + "" - case "docRoot" => "" - case "link" => "`[[" + mtch.group(2) + "]]`" - case "linkplain" => "[[" + mtch.group(2) + "]]" - case "literal" => "`" + mtch.group(2) + "`" - case "value" => "`" + mtch.group(2) + "`" - case _ => "" - } - } - - /** Maps a dangerous HTML tag to a safe wiki replacement, or an empty string - * if it cannot be salvaged. */ - def htmlReplacement(mtch: Regex.Match): String = mtch.group(1) match { - case "p" | "div" => "\n\n" - case "h1" => "\n= " - case "/h1" => " =\n" - case "h2" => "\n== " - case "/h2" => " ==\n" - case "h3" => "\n=== " - case "/h3" => " ===\n" - case "h4" | "h5" | "h6" => "\n==== " - case "/h4" | "/h5" | "/h6" => " ====\n" - case "li" => "\n * - " - case _ => "" - } - - /** Safe HTML tags that can be kept. */ - val SafeTags = - new Regex("""((&\w+;)|(&#\d+;)|(]*)?/?>))""") - - val safeTagMarker = '\u000E' - val endOfLine = '\u000A' - val endOfText = '\u0003' - - /** A Scaladoc tag not linked to a symbol and not followed by text */ - val SingleTagRegex = - new Regex("""\s*@(\S+)\s*""") - - /** A Scaladoc tag not linked to a symbol. Returns the name of the tag, and the rest of the line. */ - val SimpleTagRegex = - new Regex("""\s*@(\S+)\s+(.*)""") - - /** A Scaladoc tag linked to a symbol. Returns the name of the tag, the name - * of the symbol, and the rest of the line. */ - val SymbolTagRegex = - new Regex("""\s*@(param|tparam|throws|groupdesc|groupname|groupprio)\s+(\S*)\s*(.*)""") - - /** The start of a Scaladoc code block */ - val CodeBlockStartRegex = - new Regex("""(.*?)((?:\{\{\{)|(?:\u000E]*)?>\u000E))(.*)""") - - /** The end of a Scaladoc code block */ - val CodeBlockEndRegex = - new Regex("""(.*?)((?:\}\}\})|(?:\u000E\u000E))(.*)""") -} diff --git a/tastydoc/src/dotty/tastydoc/comment/HtmlParsers.scala b/tastydoc/src/dotty/tastydoc/comment/HtmlParsers.scala deleted file mode 100644 index 10417df10a71..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/HtmlParsers.scala +++ /dev/null @@ -1,188 +0,0 @@ -package dotty.tastydoc.comment - -import util.MemberLookup - -import dotty.tastydoc.representations._ - -import java.util.{ Arrays } - -import com.vladsch.flexmark.util.ast.{ Node => MarkdownNode} -import com.vladsch.flexmark.formatter.Formatter -import com.vladsch.flexmark.parser.Parser -import com.vladsch.flexmark.util.sequence.CharSubSequence -import com.vladsch.flexmark.parser.ParserEmulationProfile -import com.vladsch.flexmark.ext.gfm.tables.TablesExtension -import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension -import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension -import com.vladsch.flexmark.ext.emoji.EmojiExtension -import com.vladsch.flexmark.ext.autolink.AutolinkExtension -import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension -import com.vladsch.flexmark.ext.yaml.front.matter.YamlFrontMatterExtension -import com.vladsch.flexmark.util.options.{ DataHolder, MutableDataSet } - -object HtmlParsers { - - val markdownOptions: DataHolder = - new MutableDataSet() - .setFrom(ParserEmulationProfile.KRAMDOWN.getOptions) - .set(Parser.EXTENSIONS, Arrays.asList( - TablesExtension.create(), - TaskListExtension.create(), - AutolinkExtension.create(), - AnchorLinkExtension.create(), - EmojiExtension.create(), - YamlFrontMatterExtension.create(), - StrikethroughExtension.create() - )) - .set(EmojiExtension.ROOT_IMAGE_PATH, - "https://github.global.ssl.fastly.net/images/icons/emoji/") - - val RENDERER = Formatter.builder(markdownOptions).build() - - implicit class StringToMarkdown(val text: String) extends AnyVal { - def toMarkdown(origin: Representation, packages: Map[String, EmulatedPackageRepresentation]): MarkdownNode = { - import com.vladsch.flexmark.ast.Link - import com.vladsch.flexmark.util.ast.{Visitor, VisitHandler, NodeVisitor } - - val inlineToMarkdown = InlineToMarkdown(origin) - - val node = Parser.builder(markdownOptions) - .build.parse(text) - - def isOuter(url: String) = - url.startsWith("http://") || - url.startsWith("https://") || - url.startsWith("ftp://") || - url.startsWith("ftps://") - - def isRelative(url: String) = - url.startsWith("../") || - url.startsWith("./") - - val linkVisitor = new NodeVisitor( - new VisitHandler(classOf[Link], new Visitor[Link] with MemberLookup { - def queryToUrl(title: String, link: String) = makeRepresentationLink(origin, packages, Text(title), link).link match { - case Tooltip(_) => "#" - case LinkToExternal(_, url) => url - case LinkToRepresentation(t: Representation) => t match { - case e: Representation with Members => inlineToMarkdown.relativePath(t) - case x => x.parentRepresentation.fold("#") { xpar => inlineToMarkdown.relativePath(xpar) } - } - } - - override def visit(link: Link) = { - val linkUrl = link.getUrl.toString - if (!isOuter(linkUrl) && !isRelative(linkUrl)) - link.setUrl(CharSubSequence.of(queryToUrl(link.getTitle.toString, linkUrl))) - } - }) - ) - - linkVisitor.visit(node) - node - } - - def toMarkdownString(origin: Representation, packages: Map[String, EmulatedPackageRepresentation]): String = - toMarkdown(origin, packages).show - } - - implicit class MarkdownToHtml(val markdown: MarkdownNode) extends AnyVal { - def show: String = - RENDERER.render(markdown) - - def shortenAndShow: String = - (new MarkdownShortener).shorten(markdown).show - } - - implicit class StringToWiki(val text: String) extends AnyVal { - def toWiki(origin: Representation, packages: Map[String, EmulatedPackageRepresentation]): Body = - new WikiParser(origin, packages, text).document() - } - - implicit class BodyToMarkdown(val body: Body) extends AnyVal { - def show(origin: Representation): String = { - val inlineToMarkdown = InlineToMarkdown(origin) - - def bodyToMarkdown(body: Body): String = - (body.blocks map blockToMarkdown).mkString - - def listItemsToMarkdown(items: Seq[Block], level: Int = 0, ordered: Boolean = false): String ={ - if(ordered){ - items.foldLeft(("", 1)){ (list, item) => - item match { - case OrderedList(itemsLvl2, _) => val x = itemsLvl2; (list._1 + s"${listItemsToMarkdown(x, level + 1, true)}\n", list._2 + 1) - case UnorderedList(itemsLvl2) => val x = itemsLvl2; (list._1 + s"${listItemsToMarkdown(x, level + 1, false)}\n", list._2 + 1) - case Paragraph(inl) => (list._1 + s"${"\t"*level}${list._2}. ${inlineToMarkdown(inl)}\n", list._2 + 1) - case block => (list._1 + s"${"\t"*level}${list._2}. ${blockToMarkdown(block)}\n", list._2 + 1) - } - }._1 - }else{ - items.foldLeft(""){ (list, item) => - item match { - case OrderedList(itemsLvl2, _) => val x = itemsLvl2; list + s"${listItemsToMarkdown(x, level + 1, true)}\n" - case UnorderedList(itemsLvl2) => val x = itemsLvl2; list + s"${listItemsToMarkdown(x, level + 1, false)}\n" - case Paragraph(inl) => list + s"${"\t"*level}* ${inlineToMarkdown(inl)}\n" - case block => list + s"${"\t"*level}* ${blockToMarkdown(block)}\n" - } - } - } - } - - def blockToMarkdown(block: Block): String = { - (block match { - case Title(in, 1) => s"# ${inlineToMarkdown(in)}" - case Title(in, 2) => s"## ${inlineToMarkdown(in)}" - case Title(in, 3) => s"### ${inlineToMarkdown(in)}" - case Title(in, _) => s"#### ${inlineToMarkdown(in)}" - case Paragraph(in) => s"${inlineToMarkdown(in)}" - case Code(data) => s"```scala\n$data\n```" - case UnorderedList(items) => s"${listItemsToMarkdown(items)}" - case OrderedList(items, listStyle) => s"${listItemsToMarkdown(items, ordered=true)}" - case DefinitionList(items) => - s"${items map { case (t, d) => s"${inlineToMarkdown(t)}\n: ${blockToMarkdown(d)}" } }" //Not widely supported - case HorizontalRule() => - "***" - }) + - "\n" - } - - bodyToMarkdown(body) - } - } - - case class InlineToMarkdown(origin: Representation) { - def apply(inl: Inline) = toMarkdown(inl) - - def relativePath(target: Representation) = - util.traversing.relativePath(origin, target) - - def toMarkdown(inl: Inline): String = inl match { - case Chain(items) => (items map toMarkdown).mkString - case Italic(in) => s"*${toMarkdown(in)}*" - case Bold(in) => s"**${toMarkdown(in)}**" - case Underline(in) => s"__${toMarkdown(in)}__" - case Superscript(in) => s"${toMarkdown(in)}" //No Markdown equival - case Subscript(in) => s"${toMarkdown(in) }" //No Markdown equivalent - case Link(raw, title) => s"[${toMarkdown(title)}]($raw)" - case Monospace(in) => s"`${toMarkdown(in)}`" - case Text(text) => text - case Summary(in) => toMarkdown(in) - case HtmlTag(tag) => tag - case RepresentationLink(target, link) => enityLinktoMarkdown(target, link) - } - - def enityLinktoMarkdown(target: Inline, link: LinkTo) = link match { - case Tooltip(_) => toMarkdown(target) - case LinkToExternal(n, url) => s"[$n]($url)" - case LinkToRepresentation(t: Representation) => t match { - // Representation is a package member - case e: Representation with Members => - s"[${toMarkdown(target)}](${relativePath(t)}.md)" - // Representation is a Val / Def - case x => x.parentRepresentation.fold(toMarkdown(target)) { xpar => - s"[${toMarkdown(target)}](${relativePath(xpar)}.md#${x.name})" - } - } - } - } -} diff --git a/tastydoc/src/dotty/tastydoc/comment/MarkdownShortener.scala b/tastydoc/src/dotty/tastydoc/comment/MarkdownShortener.scala deleted file mode 100644 index e81e9c481d2b..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/MarkdownShortener.scala +++ /dev/null @@ -1,82 +0,0 @@ -package dotty.tastydoc -package comment - -/** The `MarkdownShortener` takes a node and *mutates* it and all children so - * that the displayed length of the generated HTML doesn't exceeed `maxLen`. - * This number defaults to 150 characters. - * - * @note calling `shorten` **will** mutate the Markdown AST node. - */ -class MarkdownShortener { - import com.vladsch.flexmark.ast.{Text, Code, Image, FencedCodeBlock, BulletList, BulletListItem, OrderedListItem} - import com.vladsch.flexmark.util.ast.{Node, NodeVisitor, VisitHandler, Visitor} - - def shorten(node: Node, maxLen: Int = 150): Node = { - var len = 0 - var didUnlink = false - - def count(node: Node, length: => Int, shortenOrUnlink: Int => Unit) = { - val remaining = math.max(maxLen - len, 0) - if (didUnlink || remaining == 0) node.unlink() - else { - if (length <= remaining) len += length - else { - shortenOrUnlink(remaining) - len = maxLen - } - } - } - - val nodeVisitor = new NodeVisitor( - new VisitHandler(classOf[Text], new Visitor[Text] { - override def visit(node: Text) = count( - node, - node.getChars.length, - remaining => node.setChars( - node.getChars.subSequence(0, remaining).trimEnd.append("...") - ) - ) - }), - new VisitHandler(classOf[Code], new Visitor[Code] { - override def visit(node: Code) = count( - node, - node.getText.length, - remaining => node.setText( - node.getText.subSequence(0, remaining).trimEnd.append("...") - ) - ) - }), - new VisitHandler(classOf[Image], new Visitor[Image] { - override def visit(node: Image) = count(node, maxLen, _ => node.unlink()) - }), - new VisitHandler(classOf[FencedCodeBlock], new Visitor[FencedCodeBlock] { - override def visit(node: FencedCodeBlock) = count(node, maxLen, _ => node.unlink()) - }), - new VisitHandler(classOf[BulletListItem], new Visitor[BulletListItem] { - override def visit(node: BulletListItem) = count( - node, - if (didUnlink) maxLen - else node.getSegments.map(_.length).reduceLeft(_ + _), - _ => { - node.unlink() - didUnlink = true // unlink all following bullets - } - ) - }), - new VisitHandler(classOf[OrderedListItem], new Visitor[OrderedListItem] { - override def visit(node: OrderedListItem) = count( - node, - if (didUnlink) maxLen - else node.getSegments.map(_.length).reduceLeft(_ + _), - _ => { - node.unlink() - didUnlink = true // unlink all following bullets - } - ) - }) - ) - - nodeVisitor.visit(node) - node - } -} diff --git a/tastydoc/src/dotty/tastydoc/comment/WikiParser.scala b/tastydoc/src/dotty/tastydoc/comment/WikiParser.scala deleted file mode 100644 index f5dc1d512e65..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/WikiParser.scala +++ /dev/null @@ -1,543 +0,0 @@ -package dotty.tastydoc -package comment - -import util.MemberLookup -import representations._ -import scala.collection.mutable - -import Regexes._ - -/** Original wikiparser from NSC - * @author Ingo Maier - * @author Manohar Jonnalagedda - * @author Gilles Dubochet - */ -private[comment] final class WikiParser( - representation: Representation, - packages: Map[String, EmulatedPackageRepresentation], - val buffer: String -) extends CharReader(buffer) with MemberLookup { wiki => - var summaryParsed = false - - def document(): Body = { - val blocks = new mutable.ListBuffer[Block] - while (char != endOfText) - blocks += block() - Body(blocks.toList) - } - - /* BLOCKS */ - - /** {{{ block ::= code | title | hrule | listBlock | para }}} */ - def block(): Block = { - if (checkSkipInitWhitespace("{{{")) - code() - else if (checkSkipInitWhitespace('=')) - title() - else if (checkSkipInitWhitespace("----")) - hrule() - else if (checkList) - listBlock() - else { - para() - } - } - - /** listStyle ::= '-' spc | '1.' spc | 'I.' spc | 'i.' spc | 'A.' spc | 'a.' spc - * Characters used to build lists and their constructors */ - protected val listStyles = Map[String, (Seq[Block] => Block)]( - "- " -> ( UnorderedList(_) ), - "1. " -> ( OrderedList(_,"decimal") ), - "I. " -> ( OrderedList(_,"upperRoman") ), - "i. " -> ( OrderedList(_,"lowerRoman") ), - "A. " -> ( OrderedList(_,"upperAlpha") ), - "a. " -> ( OrderedList(_,"lowerAlpha") ) - ) - - /** Checks if the current line is formed with more than one space and one the listStyles */ - def checkList = - (countWhitespace > 0) && (listStyles.keys exists { checkSkipInitWhitespace(_) }) - - /** {{{ - * nListBlock ::= nLine { mListBlock } - * nLine ::= nSpc listStyle para '\n' - * }}} - * Where n and m stand for the number of spaces. When `m > n`, a new list is nested. */ - def listBlock(): Block = { - - /** Consumes one list item block and returns it, or None if the block is - * not a list or a different list. */ - def listLine(indent: Int, style: String): Option[Block] = - if (countWhitespace > indent && checkList) - Some(listBlock()) - else if (countWhitespace != indent || !checkSkipInitWhitespace(style)) - None - else { - jumpWhitespace() - jump(style) - val p = Paragraph(getInline(isInlineEnd = false)) - blockEnded("end of list line ") - Some(p) - } - - /** Consumes all list item blocks (possibly with nested lists) of the - * same list and returns the list block. */ - def listLevel(indent: Int, style: String): Block = { - val lines = mutable.ListBuffer.empty[Block] - var line: Option[Block] = listLine(indent, style) - while (line.isDefined) { - lines += line.get - line = listLine(indent, style) - } - val constructor = listStyles(style) - constructor(lines.toList) - } - - val indent = countWhitespace - val style = (listStyles.keys find { checkSkipInitWhitespace(_) }).getOrElse(listStyles.keys.head) - listLevel(indent, style) - } - - def code(): Block = { - jumpWhitespace() - jump("{{{") - val str = readUntil("}}}") - if (char == endOfText) - reportError("unclosed code block") - else - jump("}}}") - blockEnded("code block") - Code(normalizeIndentation(str)) - } - - /** {{{ title ::= ('=' inline '=' | "==" inline "==" | ...) '\n' }}} */ - def title(): Block = { - jumpWhitespace() - val inLevel = repeatJump('=') - val text = getInline(check("=" * inLevel)) - val outLevel = repeatJump('=', inLevel) - if (inLevel != outLevel) - reportError("unbalanced or unclosed heading") - blockEnded("heading") - Title(text, inLevel) - } - - /** {{{ hrule ::= "----" { '-' } '\n' }}} */ - def hrule(): Block = { - jumpWhitespace() - repeatJump('-') - blockEnded("horizontal rule") - HorizontalRule() - } - - /** {{{ para ::= inline '\n' }}} */ - def para(): Block = { - val p = - if (summaryParsed) - Paragraph(getInline(isInlineEnd = false)) - else { - val s = summary() - val r = - if (checkParaEnded()) List(s) else List(s, getInline(isInlineEnd = false)) - summaryParsed = true - Paragraph(Chain(r)) - } - while (char == endOfLine && char != endOfText) - nextChar() - p - } - - /* INLINES */ - - val OPEN_TAG = "^<([A-Za-z]+)( [^>]*)?(/?)>$".r - val CLOSE_TAG = "^$".r - private def readHTMLFrom(begin: HtmlTag): String = { - val list = mutable.ListBuffer.empty[String] - val stack = mutable.ListBuffer.empty[String] - - begin.close match { - case Some(HtmlTag(CLOSE_TAG(s))) => - stack += s - case _ => - return "" - } - - while ({ - val str = readUntil { char == safeTagMarker || char == endOfText } - nextChar() - - list += str - - str match { - case OPEN_TAG(s, _, standalone) => { - if (standalone != "/") { - stack += s - } - } - case CLOSE_TAG(s) => { - if (s == stack.last) { - stack.remove(stack.length-1) - } - } - case _ => ; - } - - stack.length > 0 && char != endOfText - }) do {} - - list mkString "" - } - - def getInline(isInlineEnd: => Boolean): Inline = { - - def inline0(): Inline = { - if (char == safeTagMarker) { - val tag = htmlTag() - HtmlTag(tag.data + readHTMLFrom(tag)) - } - else if (check("'''")) bold() - else if (check("''")) italic() - else if (check("`")) monospace() - else if (check("__")) underline() - else if (check("^")) superscript() - else if (check(",,")) subscript() - else if (check("[[")) link() - else { - val str = readUntil { - char == safeTagMarker || - check("''") || - char == '`' || - check("__") || - char == '^' || - check(",,") || - check("[[") || - isInlineEnd || - checkParaEnded() || - char == endOfLine - } - Text(str) - } - } - - val inlines: List[Inline] = { - val iss = mutable.ListBuffer.empty[Inline] - iss += inline0() - while (!isInlineEnd && !checkParaEnded()) { - val skipEndOfLine = if (char == endOfLine) { - nextChar() - true - } else { - false - } - - val current = inline0() - (iss.last, current) match { - case (Text(t1), Text(t2)) if skipEndOfLine => - iss.update(iss.length - 1, Text(t1 + endOfLine + t2)) - case (i1, i2) if skipEndOfLine => - iss ++= List(Text(endOfLine.toString), i2) - case _ => iss += current - } - } - iss.toList - } - - inlines match { - case Nil => Text("") - case i :: Nil => i - case is => Chain(is) - } - - } - - def htmlTag(): HtmlTag = { - jump(safeTagMarker) - val read = readUntil(safeTagMarker) - if (char != endOfText) jump(safeTagMarker) - HtmlTag(read) - } - - def bold(): Inline = { - jump("'''") - val i = getInline(check("'''")) - jump("'''") - Bold(i) - } - - def italic(): Inline = { - jump("''") - val i = getInline(check("''")) - jump("''") - Italic(i) - } - - def monospace(): Inline = { - jump("`") - val i = getInline(check("`")) - jump("`") - Monospace(i) - } - - def underline(): Inline = { - jump("__") - val i = getInline(check("__")) - jump("__") - Underline(i) - } - - def superscript(): Inline = { - jump("^") - val i = getInline(check("^")) - if (jump("^")) { - Superscript(i) - } else { - Chain(Seq(Text("^"), i)) - } - } - - def subscript(): Inline = { - jump(",,") - val i = getInline(check(",,")) - jump(",,") - Subscript(i) - } - - def summary(): Inline = { - val i = getInline(checkSentenceEnded()) - Summary( - if (jump(".")) - Chain(List(i, Text("."))) - else - i - ) - } - - def link(): Inline = { - val SchemeUri = """([a-z]+:.*)""".r - jump("[[") - val parens = 2 + repeatJump('[') - val stop = "]" * parens - val target = readUntil { check(stop) || isWhitespaceOrNewLine(char) } - val title = - if (!check(stop)) Some({ - jumpWhitespaceOrNewLine() - getInline(check(stop)) - }) - else None - jump(stop) - - (target, title) match { - case (SchemeUri(uri), optTitle) => - Link(uri, optTitle getOrElse Text(uri)) - case (qualName, optTitle) => - makeRepresentationLink(representation, packages, optTitle getOrElse Text(target), target) - } - } - - /* UTILITY */ - - /** {{{ eol ::= { whitespace } '\n' }}} */ - def blockEnded(blockType: String): Unit = { - if (char != endOfLine && char != endOfText) { - reportError("no additional content on same line after " + blockType) - jumpUntil(endOfLine) - } - while (char == endOfLine) - nextChar() - } - - /** - * Eliminates the (common) leading spaces in all lines, based on the first line - * For indented pieces of code, it reduces the indent to the least whitespace prefix: - * {{{ - * indented example - * another indented line - * if (condition) - * then do something; - * ^ this is the least whitespace prefix - * }}} - */ - def normalizeIndentation(_code: String): String = { - - val code = _code.replaceAll("\\s+$", "").dropWhile(_ == '\n') // right-trim + remove all leading '\n' - val lines = code.split("\n") - - // maxSkip - size of the longest common whitespace prefix of non-empty lines - val nonEmptyLines = lines.filter(_.trim.nonEmpty) - val maxSkip = if (nonEmptyLines.isEmpty) 0 else nonEmptyLines.map(line => line.iterator.takeWhile(_ == ' ').size).min - - // remove common whitespace prefix - lines.map(line => if (line.trim.nonEmpty) line.substring(maxSkip) else line).mkString("\n") - } - - def checkParaEnded(): Boolean = { - (char == endOfText) || - ((char == endOfLine) && { - val poff = offset - nextChar() // read EOL - val ok = { - checkSkipInitWhitespace(endOfLine) || - checkSkipInitWhitespace('=') || - checkSkipInitWhitespace("{{{") || - checkList || - checkSkipInitWhitespace('\u003D') - } - offset = poff - ok - }) - } - - def checkSentenceEnded(): Boolean = { - (char == '.') && { - val poff = offset - nextChar() // read '.' - val ok = char == endOfText || char == endOfLine || isWhitespace(char) - offset = poff - ok - } - } - - def reportError(message: String) = println(s"$message") -} - -sealed class CharReader(buffer: String) { reader => - - var offset: Int = 0 - def char: Char = - if (offset >= buffer.length) endOfText else buffer charAt offset - - final def nextChar() = - offset += 1 - - final def check(chars: String): Boolean = { - val poff = offset - val ok = jump(chars) - offset = poff - ok - } - - def checkSkipInitWhitespace(c: Char): Boolean = { - val poff = offset - jumpWhitespace() - val ok = jump(c) - offset = poff - ok - } - - def checkSkipInitWhitespace(chars: String): Boolean = { - val poff = offset - jumpWhitespace() - val (ok0, chars0) = - if (chars.charAt(0) == ' ') - (offset > poff, chars substring 1) - else - (true, chars) - val ok = ok0 && jump(chars0) - offset = poff - ok - } - - def countWhitespace: Int = { - var count = 0 - val poff = offset - while (isWhitespace(char) && char != endOfText) { - nextChar() - count += 1 - } - offset = poff - count - } - - /* Jumpers */ - - /** Jumps a character and consumes it - * @return true only if the correct character has been jumped */ - final def jump(ch: Char): Boolean = { - if (char == ch) { - nextChar() - true - } - else false - } - - /** Jumps all the characters in chars, consuming them in the process. - * @return true only if the correct characters have been jumped - */ - final def jump(chars: String): Boolean = { - var index = 0 - while (index < chars.length && char == chars.charAt(index) && char != endOfText) { - nextChar() - index += 1 - } - index == chars.length - } - - final def repeatJump(c: Char, max: Int = Int.MaxValue): Int = { - var count = 0 - while (jump(c) && count < max) - count += 1 - count - } - - final def jumpUntil(ch: Char): Int = { - var count = 0 - while (char != ch && char != endOfText) { - nextChar() - count += 1 - } - count - } - - final def jumpUntil(pred: => Boolean): Int = { - var count = 0 - while (!pred && char != endOfText) { - nextChar() - count += 1 - } - count - } - - def jumpWhitespace() = jumpUntil(!isWhitespace(char)) - - def jumpWhitespaceOrNewLine() = jumpUntil(!isWhitespaceOrNewLine(char)) - - /* Readers */ - final def readUntil(c: Char): String = { - withRead { - while (char != c && char != endOfText) { - nextChar() - } - } - } - - final def readUntil(chars: String): String = { - assert(chars.length > 0) - withRead { - val c = chars.charAt(0) - while (!check(chars) && char != endOfText) { - nextChar() - while (char != c && char != endOfText) - nextChar() - } - } - } - - final def readUntil(pred: => Boolean): String = { - withRead { - while (char != endOfText && !pred) { - nextChar() - } - } - } - - private def withRead(read: => Unit): String = { - val start = offset - read - buffer.substring(start, offset) - } - - /* Chars classes */ - def isWhitespace(c: Char) = c == ' ' || c == '\t' - - def isWhitespaceOrNewLine(c: Char) = isWhitespace(c) || c == '\n' -} diff --git a/tastydoc/src/dotty/tastydoc/comment/util/MemberLookup.scala b/tastydoc/src/dotty/tastydoc/comment/util/MemberLookup.scala deleted file mode 100644 index b67059f496b3..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/util/MemberLookup.scala +++ /dev/null @@ -1,88 +0,0 @@ -package dotty.tastydoc -package comment -package util - -import dotty.tastydoc.representations._ - -trait MemberLookup { - /** Performs a lookup based on the provided (pruned) query string - * - * Will return a `Tooltip` if unsuccessful, otherwise a LinkToRepresentation or - * LinkToExternal - */ - def lookup(representation: Option[Representation], packages: Map[String, EmulatedPackageRepresentation], query: String): Option[Representation] = { - val notFound: Option[Representation] = None - val querys = query.split("\\.").toList - - /** Looks for the specified Representation among `ent`'s members */ - def localLookup(ent: Representation with Members, searchStr: String): Option[Representation] = - ent - .members - .collect { case x if x.name == searchStr => x } - .sortBy(_.path.last) - .headOption - - /** Looks for a Representation down in the structure, if the search list is Nil, - * the search stops - */ - def downwardLookup(ent: Representation with Members, search: List[String]): Option[Representation] = - search match { - case Nil => notFound - case x :: Nil => - localLookup(ent, x) - case x :: xs => - ent - .members - .collectFirst { - case e: Representation with Members if e.name == x => e - case e: Representation with Members if e.name == x.init && x.last == '$' => e - } - .fold(notFound)(e => downwardLookup(e, xs)) - } - - /** Finds package with longest matching name, then does downwardLookup in - * the package - */ - def globalLookup: Option[Representation] = { - def longestMatch(list: List[String]): List[String] = - if (list eq Nil) Nil - else - packages - .get(list.mkString(".")) - .map(_ => list) - .getOrElse(longestMatch(list.dropRight(1))) - - longestMatch(querys) match { - case Nil => notFound - case xs => downwardLookup(packages(xs.mkString(".")), querys diff xs) - } - } - - (querys, representation) match { - case (xs, None) => globalLookup - case (x :: Nil, Some(e: Representation with Members)) => - localLookup(e, x) - case (x :: _, Some(e: Representation with Members)) if x == e.name => - downwardLookup(e, querys) - case (x :: xs, _) => - if (xs.nonEmpty) globalLookup - else lookup(representation, packages, "scala." + query) - case (Nil, _) => - throw new IllegalArgumentException("`query` cannot be empty") - } - } - - def makeRepresentationLink( - representation: Representation, - packages: Map[String, EmulatedPackageRepresentation], - title: Inline, - query: String - ): RepresentationLink = { - val link = - lookup(Some(representation), packages, query) - .map(LinkToRepresentation) - .getOrElse(Tooltip(query)) - - RepresentationLink(title, link) - } -} diff --git a/tastydoc/src/dotty/tastydoc/comment/util/traversing.scala b/tastydoc/src/dotty/tastydoc/comment/util/traversing.scala deleted file mode 100644 index c93f407d0b57..000000000000 --- a/tastydoc/src/dotty/tastydoc/comment/util/traversing.scala +++ /dev/null @@ -1,45 +0,0 @@ -package dotty.tastydoc -package comment -package util - -import representations._ - -object traversing { - - def mutateEntities(e: Representation)(trans: Representation => Unit): Unit = e match { - case e: Representation with Members => - trans(e) - e.members.map(mutateEntities(_)(trans)) - case e: Representation => trans(e) - } - - def relativePath(from: Representation, to: Representation) = { - val offset = from match { - case _: ValRepresentation | _: DefRepresentation => 1 - case _ => 0 - } - - "../" * (from.path.length - offset) + - (to match { - case r => (to.path :+ to.name).mkString("/") - }) - } - - - def rootPackages(pkgs: Map[String, PackageRepresentation]): List[PackageRepresentation] = { - var currentDepth = Int.MaxValue - var packs = List.empty[String] - - for (key <- pkgs.keys) { - val keyDepth = key.split("\\.").length - packs = - if (keyDepth < currentDepth) { - currentDepth = keyDepth - key :: Nil - } else if (keyDepth == currentDepth) { - key :: packs - } else packs - } - packs.map(pkgs.apply) - } -} diff --git a/tastydoc/src/dotty/tastydoc/mdscala.scala b/tastydoc/src/dotty/tastydoc/mdscala.scala deleted file mode 100644 index 0352d1caf3f6..000000000000 --- a/tastydoc/src/dotty/tastydoc/mdscala.scala +++ /dev/null @@ -1,107 +0,0 @@ -package dotty.tastydoc - -/** Contains function to generate markdown (follows CommonMarkdown specifications)*/ -object Md { - /** Form a header - * - * @param obj Label of the header, usually a String - * @param level Header level, 1-6 - * @return The formed header as a String - */ - def header(obj: Any, level: Int) : String = { - require(level <= 6 && level >= 1, "Wrong header level") - "#" * level + " " + obj.toString + "\n" - } - - /** Form a header of level 1 - * - * @param obj Label of the header, usually a String - * @return The formed header as a String - */ - def header1(obj: Any) : String = { - header(obj, 1) - } - - /** Form a header of level 2 - * - * @param obj Label of the header, usually a String - * @return The formed header as a String - */ - def header2(obj: Any) : String = { - header(obj, 2) - } - - /** Form a header of level 3 - * - * @param obj Label of the header, usually a String - * @return The formed header as a String - */ - def header3(obj: Any) : String = { - header(obj, 3) - } - - /** Form a header of level 4 - * - * @param obj Label of the header, usually a String - * @return The formed header as a String - */ - def header4(obj: Any) : String = { - header(obj, 4) - } - - /** Form a header of level 5 - * - * @param obj Label of the header, usually a String - * @return The formed header as a String - */ - def header5(obj: Any) : String = { - header(obj, 5) - } - - /** Form a header of level 6 - * - * @param obj Label of the header, usually a String - * @return The formed header as a String - */ - def header6(obj: Any) : String = { - header(obj, 6) - } - - /** Form a fenced code block - * - * @param obj The content of the code block - * @param language Specific language for the syntax highlight (default: no language) - * @return The formed code block - */ - def codeBlock(obj: Any, language : String = "") : String = { - "```" + language + "\n" + obj.toString + "\n```\n" - } - /** Transform something in bold - * - * @param obj The content of the code block - * @return The object string in bold - */ - def bold(obj: Any) : String = { - "**" + obj.toString + "**" - } - - /** Transform something in italics - * - * @param obj The content of the code block - * @return The object string in italics - */ - def italics(obj: Any) : String = { - "*" + obj.toString + "*" - } - - /** Add a link to something - * - * @param obj The label of the link - * @param link The link - * - * @return The label linking to the desired link - */ - def link(label: Any, link: String): String = { - "[" + label.toString + "](" + link + ")" - } -} \ No newline at end of file diff --git a/tastydoc/src/dotty/tastydoc/references.scala b/tastydoc/src/dotty/tastydoc/references.scala deleted file mode 100644 index 2ce09886ed3d..000000000000 --- a/tastydoc/src/dotty/tastydoc/references.scala +++ /dev/null @@ -1,18 +0,0 @@ -package dotty.tastydoc - -object references { - sealed trait Reference - //Be aware that the label may end with a "$" in case it is referencing an object - final case class TypeReference(label: String, path: String, typeParams: List[Reference], hasOwnFile: Boolean = false) extends Reference - final case class OrTypeReference(left: Reference, right: Reference) extends Reference - final case class AndTypeReference(left: Reference, right: Reference) extends Reference - final case class FunctionReference(args: List[Reference], returnValue: Reference, isImplicit: Boolean) extends Reference - final case class TupleReference(args: List[Reference]) extends Reference - final case class BoundsReference(low: Reference, high: Reference) extends Reference - final case class NamedReference(name: String, ref: Reference, isRepeated: Boolean = false) extends Reference - final case class ByNameReference(ref: Reference) extends Reference - final case class ConstantReference(label: String) extends Reference - final case class CompanionReference(label: String, path: String, kind: String) extends Reference - final case class RefinedReference(parent: Reference, ls: List[(String, String, Reference)]) extends Reference - case object EmptyReference extends Reference -} \ No newline at end of file diff --git a/tastydoc/src/dotty/tastydoc/representations.scala b/tastydoc/src/dotty/tastydoc/representations.scala deleted file mode 100644 index 1c6f245d1e32..000000000000 --- a/tastydoc/src/dotty/tastydoc/representations.scala +++ /dev/null @@ -1,245 +0,0 @@ -package dotty.tastydoc - -import scala.quoted._ -import scala.annotation.tailrec -import dotty.tastydoc.comment.Comment -import dotty.tastydoc.references._ - -object representations extends TastyExtractor { - - trait Representation { - val name : String - val path : List[String] - def comments(packages: Map[String, EmulatedPackageRepresentation], userDocSyntax: String): Option[Comment] - val parentRepresentation: Option[Representation] //Called simply "parent" in dotty-doc - val annotations: List[TypeReference] - } - - trait Parents { - val parents : List[Reference] //Inheritance similar to supertypes in dotty-doc - } - - trait Members { - def members : List[Representation] //Is a def so we can override with either a var or a val (Needed for EmulatedPackage) - } - - trait Modifiers { - val modifiers: List[String] - val privateWithin: Option[Reference] - val protectedWithin: Option[Reference] - - def isPrivate: Boolean = modifiers.contains("private") - def isProtected: Boolean = modifiers.contains("protected") - def isAbstract: Boolean = modifiers.contains("abstract") - } - - trait Companion { - val companion: Option[CompanionReference] - - def hasCompanion: Boolean = companion.isDefined //To be consistent with dotty-doc - } - - trait ParamList { - val list: List[NamedReference] - val isImplicit: Boolean - } - - trait MultipleParamList { - val paramLists: List[ParamList] - } - - trait Constructors { - val constructors: List[DefRepresentation] - } - - trait ReturnValue { - val returnValue: Reference - } - - trait TypeParams { - val typeParams: List[String] - } - - /** This contains all the PackageRepresentation representing a single package - */ - class EmulatedPackageRepresentation(val name: String, val path: List[String])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) extends Representation with Members { - override val parentRepresentation = None - override val annotations = Nil - override def comments(packages: Map[String, EmulatedPackageRepresentation], userDocSyntax: String) = None - var packagesMembers: List[PackageRepresentation] = Nil - - //From the outisde, calling members is seemless and appears like calling members on a PackageRepresentation - override def members = { - @tailrec - def noDuplicates(seenPackages: Set[String], members: List[Representation], acc: List[Representation]): (List[Representation], Set[String]) = members match { - case Nil => (acc, seenPackages) - case (x: PackageRepresentation)::xs if seenPackages.contains(x.name) => noDuplicates(seenPackages, xs, acc) - case (x: PackageRepresentation)::xs => noDuplicates(seenPackages + x.name, xs, mutablePackagesMap((x.path :+ x.name).mkString(".")) :: acc) - case x::xs => noDuplicates(seenPackages, xs, x::acc) - } - - packagesMembers.foldLeft((List.empty[Representation], Set.empty[String]))((acc, p) => noDuplicates(acc._2, p.members, acc._1))._1 - } - } - - class PackageRepresentation(using QuoteContext)(internal: qctx.reflect.PackageClause, override val parentRepresentation: Option[Representation])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) extends Representation with Members { - import qctx.reflect._ - - override val (name, path) = extractPackageNameAndPath(internal.pid.show) - override val members = internal.stats.map(convertToRepresentation(_, Some(this))) - override val annotations = extractAnnotations(internal.symbol.annots) - - override def comments(packages: Map[String, EmulatedPackageRepresentation], userDocSyntax: String) = extractComments(internal.symbol.documentation, this)(packages, userDocSyntax) - } - - class ImportRepresentation(using QuoteContext)(internal: qctx.reflect.Import, override val parentRepresentation: Option[Representation])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) extends Representation { - import qctx.reflect._ - - override val name = if (internal.selectors.size > 1){ - internal.selectors.map(_.toString).mkString("{", ", ", "}") - } else { - internal.selectors.head.toString - } - override val path = internal.expr.symbol.show.split("\\.").toList - override val annotations = extractAnnotations(internal.symbol.annots) - - override def comments(packages: Map[String, EmulatedPackageRepresentation], userDocSyntax: String) = extractComments(internal.symbol.documentation, this)(packages, userDocSyntax) - } - - class ClassRepresentation(using QuoteContext)(internal: qctx.reflect.ClassDef, override val parentRepresentation: Option[Representation])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) extends Representation with Members with Parents with Modifiers with Companion with Constructors with TypeParams { - import qctx.reflect._ - - override val path = extractPath(internal.symbol) - override val parents = extractParents(internal.parents) - override val (modifiers, privateWithin, protectedWithin) = extractModifiers(internal.symbol.flags, internal.symbol.privateWithin, internal.symbol.protectedWithin) - override val constructors = - (convertToRepresentation(internal.constructor, Some(this)) :: - (internal.body.flatMap{_ match { - case d: DefDef => if(d.name == "") Some(d) else None - case _ => None - } - }.map(convertToRepresentation(_, Some(this))) - )).flatMap{r => r match { - case r: DefRepresentation => Some(r) - case _ => None - } - } - override val typeParams = internal.constructor.typeParams.map(x => x.show.stripPrefix("type ")) - override val annotations = extractAnnotations(internal.symbol.annots) - var knownSubclasses: List[Reference] = Nil - - val (isCase, isTrait, isObject, kind) = extractKind(internal.symbol.flags) - - override val name = internal.name - - override val companion = extractCompanion( - Some(internal.symbol.companionModule).filter(_.exists), // TODO: refactor later, there is now a NoSymbol - Some(internal.symbol.companionClass).filter(_.exists), // TODO: refactor later, there is now a NoSymbol - !isObject - ) - override val members: List[Representation with Modifiers] = extractClassMembers(internal.body, internal.symbol, Some(this)) - - override def comments(packages: Map[String, EmulatedPackageRepresentation], userDocSyntax: String) = extractComments(internal.symbol.documentation, this)(packages, userDocSyntax) - } - - class DefRepresentation(using QuoteContext)(internal: qctx.reflect.DefDef, override val parentRepresentation: Option[Representation])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) extends Representation with Modifiers with TypeParams with MultipleParamList with ReturnValue { - import qctx.reflect._ - - override val name = internal.name - override val path = extractPath(internal.symbol) - override val (modifiers, privateWithin, protectedWithin) = extractModifiers(internal.symbol.flags, internal.symbol.privateWithin, internal.symbol.protectedWithin) - override val typeParams = internal.typeParams.map(x => x.show.stripPrefix("type ")) - - override val paramLists = internal.paramss.map{p => - new ParamList { - override val list = p.map(x => NamedReference(x.name, convertTypeToReference(x.tpt.tpe))) - override val isImplicit = if(p.nonEmpty) p.head.symbol.flags.is(Flags.Implicit) else false - } - } - override val returnValue = convertTypeToReference(internal.returnTpt.tpe) - override val annotations = extractAnnotations(internal.symbol.annots) - override def comments(packages: Map[String, EmulatedPackageRepresentation], userDocSyntax: String) = extractComments(internal.symbol.documentation, this)(packages, userDocSyntax) - } - - class ValRepresentation(using QuoteContext)(internal: qctx.reflect.ValDef, override val parentRepresentation: Option[Representation])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) extends Representation with Modifiers with ReturnValue { - import qctx.reflect._ - - override val name = internal.name - override val path = extractPath(internal.symbol) - override val (modifiers, privateWithin, protectedWithin) = extractModifiers(internal.symbol.flags, internal.symbol.privateWithin, internal.symbol.protectedWithin) - override val returnValue = convertTypeToReference(internal.tpt.tpe) - override val annotations = extractAnnotations(internal.symbol.annots) - val isVar: Boolean = internal.symbol.flags.is(Flags.Mutable) - - override def comments(packages: Map[String, EmulatedPackageRepresentation], userDocSyntax: String) = extractComments(internal.symbol.documentation, this)(packages, userDocSyntax) - } - - class TypeRepresentation(using QuoteContext)(internal: qctx.reflect.TypeDef, override val parentRepresentation: Option[Representation])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]) extends Representation with Modifiers with TypeParams { - import qctx.reflect._ - - override val name = internal.name - override val path = extractPath(internal.symbol) - override val (modifiers, privateWithin, protectedWithin) = extractModifiers(internal.symbol.flags, internal.symbol.privateWithin, internal.symbol.protectedWithin) - override val typeParams = Nil - override val annotations = extractAnnotations(internal.symbol.annots) - val alias: Option[Reference] = internal.rhs match{ - case t: TypeBoundsTree => Some(convertTypeToReference(t.tpe)) - case t: TypeTree => Some(convertTypeToReference(t.tpe)) - case _ => None - } - override def isAbstract: Boolean = !alias.isDefined - override def comments(packages: Map[String, EmulatedPackageRepresentation], userDocSyntax: String) = extractComments(internal.symbol.documentation, this)(packages, userDocSyntax) - } - - def convertToRepresentation(using QuoteContext)(tree: qctx.reflect.Tree, parentRepresentation: Option[Representation])(using mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]): Representation = { - import qctx.reflect._ - - tree match { - case t: PackageClause => - val noColorPid = t.pid.symbol.show - val emulatedPackage = mutablePackagesMap.get(noColorPid) match { - case Some(x) => x - case None => - val (name, path) = extractPackageNameAndPath(noColorPid) - val x = new EmulatedPackageRepresentation(name, path) - mutablePackagesMap += ((noColorPid, x)) - x - } - val r = new PackageRepresentation()(t, parentRepresentation) - emulatedPackage.packagesMembers = r :: emulatedPackage.packagesMembers - r - - case t: Import => new ImportRepresentation()(t, parentRepresentation) - - case t: ClassDef => new ClassRepresentation()(t, parentRepresentation) - - case t: DefDef => new DefRepresentation()(t, parentRepresentation) - - case t: ValDef => new ValRepresentation()(t, parentRepresentation) - - case t: TypeDef => new TypeRepresentation()(t, parentRepresentation) - - case _ => throw new Exception("Tree match error in conversion to representation. Please open an issue. " + tree) - }} - - def setSubClasses(mutablePackagesMap: scala.collection.mutable.HashMap[String, EmulatedPackageRepresentation]): Unit = { - def innerLogic(representation: Representation): Unit = representation match { - case r: ClassRepresentation => - r.parents.foreach{_ match { - case ref@TypeReference(label, path, _, _) => mutablePackagesMap.get(path.replaceFirst("/", "").replaceAll("/", ".")) match { - case Some(p) => - p.members.filter(_.name == label).foreach{_ match { - case parent: ClassRepresentation => parent.knownSubclasses = TypeReference(r.name, r.path.mkString("/", "/", ""), Nil, true) :: parent.knownSubclasses - case _ => - }} - case None => - } - case _ => - }} - case r: Representation with Members => r.members.foreach(innerLogic) - case _ => - } - - mutablePackagesMap.foreach((_, v) => innerLogic(v)) - } -} diff --git a/tastydoc/test/dotty/tastydoc/Tests.scala b/tastydoc/test/dotty/tastydoc/Tests.scala deleted file mode 100644 index b3e8f848441e..000000000000 --- a/tastydoc/test/dotty/tastydoc/Tests.scala +++ /dev/null @@ -1,74 +0,0 @@ -package dotty.tastydoc - -import scala.tasty.Reflection -import scala.collection.mutable.HashMap - -import org.junit.Test -import org.junit.Assert._ -import java.nio.file._ -import scala.collection.JavaConverters._ -import java.io.File -import scala.tasty.Reflection -import java.lang.reflect.InvocationTargetException - -class Tests { - @Test def testDocumentation(): Unit = { - Main.main(Array( - "--classpath", - "tastydoc/out/bootstrap/dotty-tastydoc-input/scala-0.21/classes", - "--syntax", - "wiki", - //"markdown", - "--packagestolink", - "example.*", - //"scala.*", - "-i", - "example.level2.Documentation", - "example.level2.ClassExtendingDocumentation", - "example.DocumentationInheritance", - "example.ReturnTypeClass", - "example.level2.SameLevelTypeLinking", - "example.ReturnObjectWithType", - "example.level2.TraitWithCompanion", - "example.level2.level3.level4.ClassLevel4", - "example.UserDocLinkingClass" - )) - } - @Test def testDotty(): Unit = { - Main.main(Array( - "--classpath", - "tastydoc/dotty-0.16.0-RC3/lib", - "--syntax", - "wiki", - "--packagestolink", - "dotty.*", - "scala.annotation.*", - "scala.compiletime.*", - "scala.implicits.*", - "scala.internal.*", - "scala.quoted.*", - "scala.reflect.*", - "scala.runtime.*", - "scala.tasty.*", - "scala.testing.*", - "scalaShadowing.*", - //Individual files - "scala.\\$times\\$colon*", - "scala.Conversion*", - "scala.Eql*", - "scala.forceInline*", - "scala.FunctionXXL*", - "scala.IArray*", - "scala.NonEmptyTuple*", - "scala.Product0*", - "scala.Selectable*", - "scala.Tuple*", - "scala.TupleXXL*", - "scala.ValueOf*", - "-d", - "dotty", - "scala", - "scalaShadowing" - )) - } -}