Skip to content

Commit

Permalink
unify handling of raw content extensions - #56
Browse files Browse the repository at this point in the history
  • Loading branch information
jenshalm committed Jul 19, 2018
1 parent 1458cdc commit 630eecf
Show file tree
Hide file tree
Showing 16 changed files with 55 additions and 56 deletions.
2 changes: 2 additions & 0 deletions core/src/main/scala/laika/api/config/OperationConfig.scala
Expand Up @@ -75,6 +75,8 @@ case class OperationConfig (bundles: Seq[ExtensionBundle] = Nil,

def forStrictMode: OperationConfig = copy(bundleFilter = bundleFilter.copy(strict = true))

def forRawContent: OperationConfig = copy(bundleFilter = bundleFilter.copy(acceptRawContent = true))

}

object OperationConfig {
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/scala/laika/api/config/ParseConfigBuilder.scala
Expand Up @@ -28,4 +28,12 @@ trait ParseConfigBuilder extends OperationConfigBuilder {
*/
def strict: ThisType = withConfig(config.forStrictMode)

/** Enables all extensions that process raw content embedded into the host
* markup language.
* These are disabled by default as Laika is designed to render to multiple
* output formats from a single input document. With raw content embedded
* the markup document is tied to a specific output format.
*/
def withRawContent: ThisType = withConfig(config.forRawContent)

}
16 changes: 6 additions & 10 deletions core/src/main/scala/laika/parse/markdown/Markdown.scala
Expand Up @@ -22,6 +22,7 @@ import laika.factory.ParserFactory
import laika.io.Input
import laika.parse.core.combinator.Parsers
import laika.parse.core.markup.DocumentParser
import laika.parse.markdown.html.VerbatimHTML
import laika.tree.Documents.Document
import laika.tree.Paths.Path

Expand All @@ -41,24 +42,25 @@ import laika.tree.Paths.Path
* It must be enabled explicitly:
*
* {{{
* val document = Parse as Markdown using VerbatimHTML fromFile "hello.md"
* val document = Parse.as(Markdown).withRawContent.fromFile("hello.md")
* }}}
*
* To switch off all custom extensions like directives,
* configuration sections at the start of the document or automatic
* id generation for headers, you can run the parser in strict mode:
*
* {{{
* Transform from Markdown.strict to HTML fromFile "hello.md" toFile "hello.html"
* Transform.from(Markdown).to(HTML).strict
* .fromFile("hello.md").toFile("hello.html")
* }}}
*
* @author Jens Halm
*/
class Markdown private () extends ParserFactory {
object Markdown extends ParserFactory {

val fileSuffixes: Set[String] = Set("md","markdown")

val extensions = Seq()
val extensions = Seq(VerbatimHTML)

/** The actual parser function, fully parsing the specified input and
* returning a document tree.
Expand All @@ -72,9 +74,3 @@ class Markdown private () extends ParserFactory {
}

}

/** The default Markdown parser configuration, with verbatim HTML elements disabled.
*
* @author Jens Halm
*/
object Markdown extends Markdown()
Expand Up @@ -30,7 +30,7 @@ import laika.tree.Elements.{RenderFunction, Text, TextContainer}
* It must be applied explicitly as part of the `VerbatimHTML` bundle when enabling verbatim HTML:
*
* {{{
* val transform = Transform from Markdown to HTML using VerbatimHTML
* val transform = Transform.from(Markdown).to(HTML).withRawContent
* }}}
*
* @author Jens Halm
Expand Down
Expand Up @@ -27,17 +27,18 @@ import laika.render.{HTML, HTMLWriter}
* by this library as it aims to also support renderers for other formats than HTML,
* this extension is disabled by default.
*
* You can install it with the Transform API:
* You can enable it with the Transform API:
*
* {{{
* val transform = Transform from Markdown to HTML using VerbatimHTML
* val transform = Transform.from(Markdown).to(HTML).withRawContent
* }}}
*
* @author Jens Halm
*/
object VerbatimHTML extends ExtensionBundle {

override val useInStrictMode: Boolean = true
override val acceptRawContent: Boolean = true

override def parserDefinitions: ParserDefinitionBuilders = ParserDefinitionBuilders(
blockParsers = Seq(HTMLParsers.htmlBlockFragment),
Expand Down
18 changes: 4 additions & 14 deletions core/src/main/scala/laika/parse/rst/ReStructuredText.scala
Expand Up @@ -56,7 +56,7 @@ import laika.tree.Paths.Path
*
* @author Jens Halm
*/
class ReStructuredText private (rawContent: Boolean = false) extends ParserFactory { self =>
object ReStructuredText extends ParserFactory { self =>


val fileSuffixes: Set[String] = Set("rest","rst")
Expand All @@ -71,13 +71,9 @@ class ReStructuredText private (rawContent: Boolean = false) extends ParserFacto
}
},
RstExtensionSupport,
StandardExtensions
) ++ (if (rawContent) Seq(RawContentExtensions) else Nil) // TODO - move

/** Adds the `raw` directive and text roles to the parser.
* These are disabled by default as they present a potential security risk.
*/
def withRawContent: ReStructuredText = new ReStructuredText(true)
StandardExtensions,
RawContentExtensions
)

/** The actual parser function, fully parsing the specified input and
* returning a document tree.
Expand Down Expand Up @@ -105,9 +101,3 @@ class ReStructuredText private (rawContent: Boolean = false) extends ParserFacto
}

}

/** The default reStructuredText parser configuration.
*
* @author Jens Halm
*/
object ReStructuredText extends ReStructuredText(false)
Expand Up @@ -203,6 +203,7 @@ object StandardExtensions extends RstExtensionRegistry {

object RawContentExtensions extends RstExtensionRegistry {

override val acceptRawContent = true
lazy val blockDirectives = Seq((new StandardBlockDirectives).rawDirective)
lazy val spanDirectives = Seq()
lazy val textRoles = Seq((new StandardTextRoles).rawTextRole)
Expand Down
Expand Up @@ -286,7 +286,7 @@ class StandardBlockDirectives {

/** The raw directive, which is not enabled by default,
* see [[http://docutils.sourceforge.net/docs/ref/rst/directives.html#raw-data-pass-through]] for details.
* It can be enabled with `ReStructuredText.withRawContent`.
* It can be enabled with `Transform.from(ReStructuredText).to(HTML).withRawContent`.
*/
lazy val rawDirective: Directive[Block] = BlockDirective("raw") {
(argument(withWS = true) ~ content(Right(_))) { (formats, content) =>
Expand Down
Expand Up @@ -124,7 +124,7 @@ class StandardTextRoles {

/** The raw text role, which is not enabled by default,
* see [[http://docutils.sourceforge.net/docs/ref/rst/roles.html#raw]] for details.
* It can be enabled with `ReStructuredText.withRawContent`.
* It can be enabled with `Transform.from(ReStructuredText).to(HTML).withRawContent`.
*/
lazy val rawTextRole: TextRole =
TextRole("raw", (Nil:List[String],NoOpt:Options)) {
Expand Down
Expand Up @@ -60,7 +60,7 @@ class MarkdownToHTMLSpec extends FlatSpec
// TODO - remove once strict mode is handled properly
object StrictMarkdown extends ParserFactory {
val fileSuffixes: Set[String] = Set("md","markdown")
val extensions = Seq()
val extensions = Seq(VerbatimHTML)
def newParser (parserExtensions: ParserDefinitionBuilders): Input => Document = {
val rootParser = new RootParser(parserExtensions.blockParsers, parserExtensions.spanParsers, isStrict = true)
val configHeaderParsers = parserExtensions.configHeaderParsers :+ { _:Path => Parsers.success(Right(ConfigFactory.empty)) }
Expand All @@ -71,7 +71,7 @@ class MarkdownToHTMLSpec extends FlatSpec

def transformAndCompare (name: String): Unit = {
val path = classPathResource("/markdownTestSuite") + "/" + name
val actual = (Transform from StrictMarkdown to HTML using VerbatimHTML rendering { out => {
val actual = ((Transform from StrictMarkdown to HTML).withRawContent rendering { out => {
case QuotedBlock(content,_,_) => out << "<blockquote>" <<|> content <<| "</blockquote>" // Markdown always writes p tags inside blockquotes
}}).strict fromFile (path + ".md") toString
val expected = readFile(path + ".html")
Expand Down
Expand Up @@ -19,8 +19,8 @@ package laika.parse.markdown.html
import org.scalatest.FlatSpec
import org.scalatest.junit.JUnitRunner
import org.scalatest.Matchers

import laika.api.Render
import laika.api.{Parse, Render}
import laika.parse.markdown.Markdown
import laika.parse.markdown.html.HTMLElements._
import laika.render.HTML
import laika.tree.Elements.Element
Expand All @@ -31,9 +31,13 @@ class VerbatimHTMLRendererSpec extends FlatSpec
with Matchers
with ModelBuilder
with HTMLModelBuilder {


val renderer = {
val parser = Parse.as(Markdown).withRawContent
Render.as(HTML).withConfig(parser.config)
}

def render (elem: Element): String = Render as HTML using VerbatimHTML from elem toString
def render (elem: Element): String = renderer from elem toString


"The Verbatim HTML renderer" should "render an HTML character reference unescaped" in {
Expand Down
Expand Up @@ -16,15 +16,13 @@

package laika.parse.rst

import org.scalatest.FlatSpec
import org.scalatest.Matchers
import laika.api.Transform
import laika.parse.markdown.html.VerbatimHTML
import laika.render.HTML
import laika.transform.helper.FileTransformerUtil
import laika.tree.Elements._
import org.scalatest.{FlatSpec, Matchers}

import scala.io.Codec
import laika.io.Input

/**
* @author Jens Halm
Expand Down
Expand Up @@ -673,7 +673,7 @@ class StandardBlockDirectivesSpec extends FlatSpec
|
| some more""".stripMargin
val result = root (RawContent(List("format"), "some input\n\nsome more"))
(Parse as ReStructuredText.withRawContent fromString input).content should be (result)
Parse.as(ReStructuredText).withRawContent.fromString(input).content should be (result)
}


Expand Down
Expand Up @@ -179,7 +179,7 @@ class StandardTextRolesSpec extends FlatSpec
|
|some :foo:`text`""".stripMargin
val result = root(p(txt("some "), RawContent(List("AML","BML","CML"), "text", Styles("foo"))))
(Parse as ReStructuredText.withRawContent fromString input).content should be (result)
Parse.as(ReStructuredText).withRawContent.fromString(input).content should be (result)
}

it should "be disabled by default" in {
Expand Down
14 changes: 7 additions & 7 deletions docs/using-laika/markup.md
Expand Up @@ -27,8 +27,8 @@ Laika supports several convenient features for processing groups of documents.
These are built as extensions to both Markdown and reStructuredText parsers.
They can be switched off when you run these two parsers in strict mode:

Transform from Markdown.strict to
HTML fromFile "hello.md" toFile "hello.html"
Transform.from(Markdown).to(HTML).strict
.fromFile("hello.md").toFile("hello.html")

The extensions are documented in their respective section linked to from
the list below:
Expand Down Expand Up @@ -104,8 +104,8 @@ Finally there is one major difference to standard Markdown: the parsing of verba
is not enabled by default, but it can be switched on if required.

When using this feature
you need to be aware of the fact that it ties your markup files to HTML output. Future
versions of Laika are supposed to support formats like PDF, epub and DocBook, and markup
you need to be aware of the fact that it ties your markup files to HTML output. Laika
supports multiple output formats like HTML, PDF, XSL-FO and in the future epub, and markup
files containing raw HTML could not be used for those.

When the markup originates from user input in a web application, it would not be safe
Expand All @@ -115,11 +115,11 @@ customization hooks like [Document Tree Rewriting] or [Customizing Renderers].

To enable verbatim HTML elements you have to change this standard expression:

Transform from Markdown to HTML
Transform.from(Markdown).to(HTML)

to

Transform from Markdown to HTML using VerbatimHTML
Transform.from(Markdown).to(HTML).withRawContent

This installs both, the required parser and renderer extensions.

Expand Down Expand Up @@ -241,7 +241,7 @@ seamed too exotic to warrant inclusion in Laika.

Finally some of the defaults for these extensions can be changed through the API:

ReStructuredText.withRawContent
val transformer = Transform.from(ReStructuredText).to(HTML).withRawContent

enables both the `raw` directive and the `raw` text role. They are disabled by default as
they present a potential security risk.
Expand Down
15 changes: 7 additions & 8 deletions sbt/src/main/scala/laika/sbt/LaikaPlugin.scala
Expand Up @@ -17,15 +17,14 @@
package laika.sbt

import laika.api._
import laika.api.ext.ExtensionBundle.LaikaDefaults
import laika.directive.Directives._
import laika.directive.DirectiveRegistry
import laika.directive.Directives._
import laika.io.Input.LazyFileInput
import laika.io.{DocumentType, Input, InputTree, OutputTree}
import laika.parse.markdown.Markdown
import laika.parse.markdown.html.{HTMLRenderer, VerbatimHTML}
import laika.parse.rst.ext.{Directives, RstExtensionRegistry}
import laika.parse.markdown.html.HTMLRenderer
import laika.parse.rst.ext.TextRoles.TextRole
import laika.parse.rst.ext.{Directives, RstExtensionRegistry}
import laika.parse.rst.{ExtendedHTML, ReStructuredText}
import laika.render._
import laika.rewrite.{DocumentCursor, RewriteRules}
Expand Down Expand Up @@ -124,8 +123,8 @@ object LaikaPlugin extends AutoPlugin {

}

import autoImport._
import Tasks._
import autoImport._

override def projectSettings: Seq[Setting[_]] = Seq(
sourceDirectories in Laika := Seq(sourceDirectory.value / "docs"),
Expand Down Expand Up @@ -165,9 +164,9 @@ object LaikaPlugin extends AutoPlugin {
val spanDirectives = rstSpanDirectives.value
val textRoles = rstTextRoles.value
}
val rst = if (laikaRawContent.value) ReStructuredText.withRawContent else ReStructuredText
val parser = Parse.as(Markdown).or(rst).withoutRewrite.using(directives, rstExtensions)
val pWithRaw = if (laikaRawContent.value) parser using VerbatimHTML else parser
val parser = Parse.as(Markdown).or(ReStructuredText)
.withoutRewrite.using(directives, rstExtensions)
val pWithRaw = if (laikaRawContent.value) parser.withRawContent else parser
val pWithPar = if (laikaParallel.value) pWithRaw.inParallel else pWithRaw
if (laikaStrict.value) pWithPar.strict else pWithPar
},
Expand Down

0 comments on commit 630eecf

Please sign in to comment.