From f9759a328ec7fa4b739381c82afa57486638ab6d Mon Sep 17 00:00:00 2001 From: Stefan Zeiger Date: Mon, 4 Oct 2010 14:35:59 +0200 Subject: [PATCH] Improved json-multi output: TypeEntities as HTML, better page-mapping --- .../extradoc/json/AbstractJsonFactory.scala | 4 +- .../com/novocode/extradoc/json/JBase.scala | 7 ++- .../novocode/extradoc/json/JsonBuilder.scala | 38 ++++++++++++---- .../extradoc/json/JsonMultiFactory.scala | 45 +++++++++++-------- 4 files changed, 64 insertions(+), 30 deletions(-) diff --git a/src/main/scala/com/novocode/extradoc/json/AbstractJsonFactory.scala b/src/main/scala/com/novocode/extradoc/json/AbstractJsonFactory.scala index aed865d..7888c09 100644 --- a/src/main/scala/com/novocode/extradoc/json/AbstractJsonFactory.scala +++ b/src/main/scala/com/novocode/extradoc/json/AbstractJsonFactory.scala @@ -7,9 +7,10 @@ import comment._ import java.io.{PrintStream, FileOutputStream, BufferedOutputStream, StringWriter, File => JFile} import scala.collection._ -abstract class AbstractJsonFactory { +abstract class AbstractJsonFactory { self => val doInline = true + val typeEntitiesAsHtml = false def prepareModel(universe: Universe) = { println("Building JSON model") @@ -29,6 +30,7 @@ abstract class AbstractJsonFactory { val allModels = new mutable.HashMap[Int, JBase] val allModelsReverse = new mutable.HashMap[JBase, Int] val builder = new JsonBuilder[Link] { + val typeEntitiesAsHtml = self.typeEntitiesAsHtml def global[T <: Entity](e: T)(f: T => JBase) = globalEntityOrdinals.get(EntityHash(e)) match { case Some(ord) => Link(ord) case None => diff --git a/src/main/scala/com/novocode/extradoc/json/JBase.scala b/src/main/scala/com/novocode/extradoc/json/JBase.scala index ffce666..b828bba 100644 --- a/src/main/scala/com/novocode/extradoc/json/JBase.scala +++ b/src/main/scala/com/novocode/extradoc/json/JBase.scala @@ -4,7 +4,7 @@ import scala.tools.nsc.doc._ import model._ import comment._ -import java.io.Writer +import java.io.{Writer, StringWriter} import scala.collection._ abstract class CanBeValue[-T] { @@ -59,6 +59,11 @@ sealed abstract class JBase { f(this) children foreach { _.foreachRec(f) } } + override def toString = { + val wr = new StringWriter + writeTo(wr, {_.target}) + wr.toString + } } object JBase { diff --git a/src/main/scala/com/novocode/extradoc/json/JsonBuilder.scala b/src/main/scala/com/novocode/extradoc/json/JsonBuilder.scala index c7b4239..4e1c3c9 100644 --- a/src/main/scala/com/novocode/extradoc/json/JsonBuilder.scala +++ b/src/main/scala/com/novocode/extradoc/json/JsonBuilder.scala @@ -5,10 +5,12 @@ import model._ import comment._ import scala.collection._ -import scala.xml.{Xhtml, NodeSeq} +import scala.xml.{Xhtml, NodeSeq, NodeBuffer, Text, Elem} abstract class JsonBuilder[Link : CanBeValue] { + val typeEntitiesAsHtml: Boolean + def global[T <: Entity](e: T)(f: T => JBase): Link def as[T](o: AnyRef)(f: T => Unit)(implicit m: ClassManifest[T]): Unit = @@ -76,20 +78,38 @@ abstract class JsonBuilder[Link : CanBeValue] { def createTypeEntity(t: TypeEntity): JObject = { val j = new JObject - j += "name" -> t.name - j +?= "refEntity" -> JObject(t.refEntity.map { - case (k,v) => - val vv = new JObject - vv += "e" -> global(v._1)(createEntity _) - vv += "l" -> v._2 - k.toString -> vv - }) + if(typeEntitiesAsHtml) { + val b = new NodeBuffer + val links = new mutable.ArrayBuffer[Link] + val name = t.name + var pos = 0 + t.refEntity foreach { case (start, (ref, len)) => + if(pos < start) b += Text(name.substring(pos, start)) + links += global(ref)(createEntity _) + b += Elem(null, "a", null, xml.TopScope, Text(name.substring(start, start+len))) + pos = start+len + } + if(pos < name.length-1) b += Text(name.substring(pos)) + j += "_xname" -> Xhtml.toXhtml(b) + j +?= "_refs" -> JArray(links) + } else { + j += "name" -> t.name + j +?= "refEntity" -> JArray(t.refEntity.map { + case (k,v) => + val vv = new JObject + vv += "s" -> k + vv += "l" -> v._2 + vv += "e" -> global(v._1)(createEntity _) + vv + }) + } j } def createEntity(e: Entity): JObject = { val j = new JObject j += "inTemplate" -> global(e.inTemplate)(createEntity _) + // "toRoot" is own ID plus recursively toRoot of inTemplate //j += "toRoot" -> JArray(e.toRoot.map(e => global(e)(createEntity _))) val qName = e.qualifiedName var name = e.name diff --git a/src/main/scala/com/novocode/extradoc/json/JsonMultiFactory.scala b/src/main/scala/com/novocode/extradoc/json/JsonMultiFactory.scala index ce24d16..0a1bbd5 100644 --- a/src/main/scala/com/novocode/extradoc/json/JsonMultiFactory.scala +++ b/src/main/scala/com/novocode/extradoc/json/JsonMultiFactory.scala @@ -13,6 +13,8 @@ class JsonMultiFactory(val universe: Universe) extends AbstractJsonFactory { // the size of extra objects which are included in many pages override val doInline = false + override val typeEntitiesAsHtml = true + case class Page(no: Int, main: Int) { val objects = new mutable.HashSet[Int] val renumbered = new mutable.ArrayBuffer[Int] @@ -22,37 +24,42 @@ class JsonMultiFactory(val universe: Universe) extends AbstractJsonFactory { val (allModels, _) = prepareModel(universe) val pages = findGlobal(allModels).toSeq.sorted. zipWithIndex map { case (ord,idx) => (ord, Page(idx, ord))} toMap; - def findPage(j: JBase): Option[Page] = j match { - case j: JObject => j("inTemplate") match { - case Some(Link(target)) => - pages get target orElse (allModels get target flatMap (findPage _)) - case Some(j: JObject) => findPage(j) - case None => None - } + def findPage(ord: Int, j: JBase): Option[Page] = j match { + case j: JObject => + // Don't map external packages to their parents + if(ord >= 0 && j("isPackage").getOrElse(false) == true && !(pages contains ord)) None + else j("inTemplate") match { + case Some(Link(target)) => + pages get target orElse (allModels get target flatMap (ch => findPage(target, ch))) + case Some(j: JObject) => findPage(-1, j) + case None => None + } case _ => None } var extra = new mutable.HashSet[Int] allModels foreach { case (ord, j) => - (findPage(j) map (_.objects) getOrElse extra) += ord + (pages get ord orElse findPage(ord, j) map (_.objects) getOrElse extra) += ord } println("Mapping "+extra.size+" extra objects to all pages that need them") var extraTotal = 0 - pages.values foreach { p => - p.objects map allModels foreach { - _ foreachRec { - _.links foreach { l => - if(extra contains l.target) { - if(!(p.objects contains l.target)) { - extraTotal += 1 - p.objects += l.target - } + def mapExtras(p: Page, j: JBase) { + j foreachRec { + _.links foreach { l => + if(extra contains l.target) { + if(!(p.objects contains l.target)) { + extraTotal += 1 + p.objects += l.target + mapExtras(p, allModels(l.target)) } } } } } + pages.values foreach { p => + p.objects map allModels foreach { j => mapExtras(p, j) } + } println("Total number of extra objects on all pages: "+extraTotal) - println("Inlining extras on all pages") + println("Inlining objects on all pages") val keepHtmlLinks = new mutable.HashSet[Int] allModels.values foreach { _ foreachRec { @@ -95,7 +102,7 @@ class JsonMultiFactory(val universe: Universe) extends AbstractJsonFactory { for(p <- pages.values) { p.renumbered += p.main remappedIDs += Link(p.main) -> (p.no, 0) - p.objects foreach { ord => + for(ord <- p.objects if ord != p.main) { remappedIDs += Link(ord) -> (p.no, p.renumbered.size) p.renumbered += ord }