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

laika.io.ops.TreeMapperOps.scala Maven / Gradle / Ivy

/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package laika.io.ops

import cats.implicits._
import cats.effect.Sync
import laika.ast.{Document, DocumentTree, TreeContent}
import laika.io.model.ParsedTree

/** Operations for builders of transformers that allow to modify the tree
  * or documents between parsing and rendering.
  * 
  * This hook differs from the rewrite rules in two ways: first it does not
  * only operate on the AST nodes of a document, therefore it can also change
  * its path or config. Secondly it allows for effectful transformations
  * which are not available in the pure laika-core module.
  * 
  * @author Jens Halm
  */
abstract class TreeMapperOps[F[_]: Sync] {

  val F: Sync[F] = Sync[F]
  
  type MapRes

  /** Creates a new transformer that applies the specified function to each document in the parsed tree
    * before rendering.
    */
  def mapDocuments (f: Document => Document): MapRes = evalMapDocuments(f.andThen(F.pure))

  /** Creates a new transformer that applies the specified effectful function to each document in the parsed tree
    * before rendering.
    */
  def evalMapDocuments (f: Document => F[Document]): MapRes = evalMapTree { parsed =>

    def mapTree(tree: DocumentTree): F[DocumentTree] = for {
      newContent <- tree.content.toList.traverse {
        case doc: Document      => f(doc).widen[TreeContent]
        case tree: DocumentTree => mapTree(tree).widen[TreeContent]
      }
      newTitle   <- tree.titleDocument.traverse(f)
    } yield tree.copy(content = newContent, titleDocument = newTitle)

    for {
      mappedTree  <- mapTree(parsed.root.tree)
      mappedCover <- parsed.root.coverDocument.traverse(f)
    } yield parsed.modifyRoot(_.copy(tree = mappedTree, coverDocument = mappedCover))

  }

  /** Creates a new transformer that applies the specified function to the parsed tree
    * before rendering.
    */
  def mapTree (f: ParsedTree[F] => ParsedTree[F]): MapRes = evalMapTree(f.andThen(F.pure))

  /** Creates a new transformer that applies the specified effectful function to the parsed tree
    * before rendering.
    */
  def evalMapTree (f: ParsedTree[F] => F[ParsedTree[F]]): MapRes
  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy