All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.specs2.html.Indexing.scala Maven / Gradle / Ivy

There is a newer version: 4.20.8
Show newest version
package org.specs2
package html

import io.{DirectoryPath, FilePath, FileSystem}
import specification.core._
import org.specs2.fp._
import org.specs2.fp.syntax._
import control._
import org.specs2.concurrent.ExecutionEnv
import origami._

/**
 * Fold functions to create index files
 */
object Indexing {

  implicit def executionEnv: ExecutionEnv =
    ExecutionEnv.fromGlobalExecutionContext

  /**
   * An Index fold creates an Index page based on all pages to index and
   * saves it to a given file path
   */
  def indexFold(path: FilePath): Fold[Operation, IndexedPage, Index] =
    origami.fold.fromMonoidMap[Operation, IndexedPage, Index](Index.createIndex).mapFlatten((index: Index) =>
      FileSystem.writeFile(path, Index.toJson(index)).as(index))

  def createIndexedPages(env: Env, specifications: List[SpecStructure], outDir: DirectoryPath): List[IndexedPage] =
    specifications.map(createIndexedPage(env, outDir))

  def createIndexedPage(env: Env, outDir: DirectoryPath) = (spec: SpecStructure) => {
    IndexedPage(
      path     = SpecHtmlPage.outputPath(outDir, spec).relativeTo(outDir),
      title    = spec.header.showWords,
      contents = spec.textsList.foldLeft(new StringBuilder)((res, cur) => res.append(cur.description.show)).toString,
      tags     = spec.tagsList.flatMap(_.names).map(sanitize).toIndexedSeq)
  }

  def createEntries(page: IndexedPage): Vector[IndexEntry] = 
    Vector(IndexEntry(page.title, page.contents, page.tags, page.path))

  /** remove quotes from names in order to add as json values */
  def sanitize(name: String): String =
    name.replace("\"", "\\\"")
}

case class IndexedPage(path: FilePath, title: String, contents: String, tags: IndexedSeq[String])

case class Index(entries: Vector[IndexEntry]) {
  def add(entry: IndexEntry) = copy(entries :+ entry)
  def add(other: Seq[IndexEntry]) = copy(entries ++ other)
}

object Index {

  val empty = Index(Vector())

  def toJson(index: Index): String = {
    s"""
       |var tipuesearch = {"pages": ${pages(index).mkString("[", ",\n", "]")}};
     """.stripMargin
  }

  def pages(index: Index): Seq[String] =
    index.entries.map(page)

  def page(entry: IndexEntry): String =
    s"""{"title":"${entry.title}", "text":"${sanitizeEntry(entry)}", "tags":${entry.tags.mkString("\""," ", "\"")}, "loc":"${entry.path.path}"}"""

  /**
   * the text that is used for indexing must be sanitized:
   * - no newlines
   * - ^ (because tipue search doesn't like it)
   * - no markdown characters
   */
  def sanitizeEntry(entry: IndexEntry): String =
    entry.text.replace("\"", "\\\"")
      .replace("\n", "")
      .replace("^", "")
      .replace("#####", "")
      .replace("####", "")
      .replace("###", "")
      .replace("##", "")
      .replace("  * ", "")
      .replace("```", "")
      .replace("", "")
      .replace("", "")

  implicit def IndexMonoid: Monoid[Index] = new Monoid[Index] {
    def zero = Index(Vector())
    def append(a: Index, b: =>Index) = Index(a.entries ++ b.entries)
  }

  val createIndex = (page: IndexedPage) => Index(Indexing.createEntries(page))
}

case class IndexEntry(title: String, text: String, tags: IndexedSeq[String], path: FilePath)





© 2015 - 2024 Weber Informatics LLC | Privacy Policy