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 == "" + 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+;)|(?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|code|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""")
-
- 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 = "^([A-Za-z]+)>$".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 == "