From 40265d3e7057ab6c48527b711dac218cd201a187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20P=C3=A1ll=20Geirsson?= Date: Sun, 27 Oct 2019 20:06:37 +0000 Subject: [PATCH 1/3] Use custom parser for markdown processing. Previously, mdoc used the flexmark library for processing markdown files. Since flexmark is a proper markdown parser, it may not always understand the format of the document that mdoc was processing, for example: * revealjs slides inside HTML files * custom markdown extensions that are not supported by commonmark This commit introduces a new custom parser that only understands the parts of markdown files that mdoc touches: code fences. Since mdoc doesn't need to understand all markdown flavors to process code fences, we can get away with a much simpler parser than flexmark (that understands all of markdown). With this change, it should be possible to use mdoc on any document as long as the code fences start at the beginning of a line with the triple-backtick "scala mdoc" syntax ```` ```scala mdoc println(42) ``` ```` Everything outside the code fences is left unchanged, character-by-character, so the underlying markup language is preserved. --- build.sbt | 2 + .../main/scala/mdoc/docs/MdocModifier.scala | 12 +- .../scala/mdoc/internal/cli/MainOps.scala | 13 +- .../mdoc/internal/markdown/FenceInput.scala | 101 ++++++++++++++ .../mdoc/internal/markdown/Markdown.scala | 20 +++ .../mdoc/internal/markdown/MarkdownFile.scala | 123 ++++++++++++++++++ .../internal/markdown/MdocExtensions.scala | 5 +- .../markdown/MdocFormatterExtension.scala | 16 --- .../markdown/MdocParserExtension.scala | 80 ------------ ...docPostProcessor.scala => Processor.scala} | 94 +++++-------- .../tests/markdown/BaseMarkdownSuite.scala | 13 +- .../tests/markdown/MarkdownFileSuite.scala | 114 ++++++++++++++++ 12 files changed, 413 insertions(+), 180 deletions(-) create mode 100644 mdoc/src/main/scala/mdoc/internal/markdown/FenceInput.scala create mode 100644 mdoc/src/main/scala/mdoc/internal/markdown/MarkdownFile.scala delete mode 100644 mdoc/src/main/scala/mdoc/internal/markdown/MdocFormatterExtension.scala delete mode 100644 mdoc/src/main/scala/mdoc/internal/markdown/MdocParserExtension.scala rename mdoc/src/main/scala/mdoc/internal/markdown/{MdocPostProcessor.scala => Processor.scala} (68%) create mode 100644 tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala diff --git a/build.sbt b/build.sbt index 958d1103..51751acc 100644 --- a/build.sbt +++ b/build.sbt @@ -145,6 +145,8 @@ lazy val unit = project skip in publish := true, addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.10.3"), resolvers += Resolver.bintrayRepo("cibotech", "public"), + libraryDependencies += "com.lihaoyi" %% "utest" % "0.7.1" % Test, + testFrameworks += new TestFramework("utest.runner.Framework"), scala212LibraryDependencies( List( "com.cibo" %% "evilplot" % "0.6.0" diff --git a/mdoc-docs/src/main/scala/mdoc/docs/MdocModifier.scala b/mdoc-docs/src/main/scala/mdoc/docs/MdocModifier.scala index ef627820..f2a601ba 100644 --- a/mdoc-docs/src/main/scala/mdoc/docs/MdocModifier.scala +++ b/mdoc-docs/src/main/scala/mdoc/docs/MdocModifier.scala @@ -23,8 +23,16 @@ class MdocModifier(context: Context) extends StringModifier { myStdout.reset() myReporter.reset() val cleanInput = Input.VirtualFile(code.filename, code.text) - val markdown = Markdown.toMarkdown(cleanInput, markdownSettings, myReporter, context.settings) - val links = DocumentLinks.fromMarkdown(GitHubIdGenerator, RelativePath("readme.md"), cleanInput) + val relpath = RelativePath("readme.md") + val markdown = Markdown.toMarkdown( + cleanInput, + context, + relpath, + Map.empty[String, String], + myReporter, + context.settings + ) + val links = DocumentLinks.fromMarkdown(GitHubIdGenerator, relpath, cleanInput) LinkHygiene.lint(List(links), myReporter, verbose = false) val stdout = fansi.Str(myStdout.toString()).plainText if (myReporter.hasErrors || myReporter.hasWarnings) { diff --git a/mdoc/src/main/scala/mdoc/internal/cli/MainOps.scala b/mdoc/src/main/scala/mdoc/internal/cli/MainOps.scala index c93b6412..a1de7179 100644 --- a/mdoc/src/main/scala/mdoc/internal/cli/MainOps.scala +++ b/mdoc/src/main/scala/mdoc/internal/cli/MainOps.scala @@ -24,10 +24,10 @@ import scala.meta.io.AbsolutePath import scala.util.control.NonFatal final class MainOps( - settings: Settings, - markdown: MutableDataSet, - reporter: Reporter + context: Context ) { + def settings: Settings = context.settings + def reporter: Reporter = context.reporter private var livereload: Option[LiveReload] = None private def startLivereload(): Unit = { @@ -59,9 +59,7 @@ final class MainOps( val timer = new Timer val source = FileIO.slurp(file.in, settings.charset) val input = Input.VirtualFile(file.in.toString(), source) - markdown.set(Markdown.InputKey, Some(input)) - markdown.set(Markdown.RelativePathKey, Some(file.relpath)) - val md = Markdown.toMarkdown(input, markdown, reporter, settings) + val md = Markdown.toMarkdown(input, context, file.relpath, settings.site, reporter, settings) val fileHasErrors = reporter.errorCount > originalErrors if (!fileHasErrors) { writePath(file, md) @@ -226,11 +224,10 @@ object MainOps { error.all.foreach(message => reporter.error(message)) 1 case Configured.Ok(ctx) => - val markdown = Markdown.mdocSettings(ctx) if (ctx.settings.verbose) { ctx.reporter.setDebugEnabled(true) } - val runner = new MainOps(ctx.settings, markdown, ctx.reporter) + val runner = new MainOps(ctx) val exit = runner.run() if (exit.isSuccess) { 0 diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/FenceInput.scala b/mdoc/src/main/scala/mdoc/internal/markdown/FenceInput.scala new file mode 100644 index 00000000..837376e9 --- /dev/null +++ b/mdoc/src/main/scala/mdoc/internal/markdown/FenceInput.scala @@ -0,0 +1,101 @@ +package mdoc.internal.markdown + +import com.vladsch.flexmark.ast.FencedCodeBlock +import scala.meta.inputs.Input +import scala.meta.inputs.Position +import mdoc.internal.cli.Context +import mdoc.internal.markdown.Modifier.Str +import mdoc.internal.markdown.Modifier.Default +import mdoc.internal.markdown.Modifier.Post +import mdoc.internal.markdown.Modifier.Pre + +case class PreFenceInput(block: CodeFence, input: Input, mod: Pre) +case class StringFenceInput(block: CodeFence, input: Input, mod: Str) +case class ScalaFenceInput(block: CodeFence, input: Input, mod: Modifier) + +class FenceInput(ctx: Context, baseInput: Input) { + def getModifier(info: Text): Option[Modifier] = { + val string = info.value.stripLineEnd + if (!string.startsWith("scala mdoc")) None + else { + if (!string.contains(':')) Some(Modifier.Default()) + else { + val mode = string.stripPrefix("scala mdoc:") + Modifier(mode) + .orElse { + val (name, info) = mode.split(":", 2) match { + case Array(a) => (a, "") + case Array(a, b) => (a, b) + } + ctx.settings.stringModifiers + .collectFirst[Modifier] { + case mod if mod.name == name => + Str(mod, info) + } + .orElse { + ctx.settings.postModifiers.collectFirst { + case mod if mod.name == name => + Post(mod, info) + } + } + .orElse { + ctx.settings.preModifiers.collectFirst { + case mod if mod.name == name => + Pre(mod, info) + } + } + } + .orElse { + ctx.reporter.error(info.pos, s"Invalid mode '$mode'") + None + } + } + } + } + + private def invalid(block: FencedCodeBlock, message: String): Unit = { + val offset = "scala mdoc:".length + val start = block.getInfo.getStartOffset + offset + val end = block.getInfo.getEndOffset + val pos = Position.Range(baseInput, start, end) + ctx.reporter.error(pos, message) + } + private def invalidCombination(info: Text, mod1: String, mod2: String): Boolean = { + ctx.reporter.error(info.pos, s"invalid combination of modifiers '$mod1' and '$mod2'") + false + } + + private def isValid(info: Text, mod: Modifier): Boolean = { + if (mod.isFail && mod.isCrash) { + invalidCombination(info, "crash", "fail") + } else if (mod.isSilent && mod.isInvisible) { + invalidCombination(info, "silent", "invisible") + } else if (mod.isCompileOnly) { + val others = mod.mods - Mod.CompileOnly + if (others.isEmpty) { + true + } else { + val all = others.map(_.toString.toLowerCase).mkString(", ") + ctx.reporter.error( + info.pos, + s"""compile-only cannot be used in combination with $all""" + ) + false + } + } else { + true + } + } + def unapply(block: CodeFence): Option[ScalaFenceInput] = { + getModifier(block.info) match { + case Some(mod) => + if (isValid(block.info, mod)) { + val input = Input.Slice(baseInput, block.body.pos.start, block.body.pos.end) + Some(ScalaFenceInput(block, input, mod)) + } else { + None + } + case _ => None + } + } +} diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/Markdown.scala b/mdoc/src/main/scala/mdoc/internal/markdown/Markdown.scala index ef5a4e64..f983218f 100644 --- a/mdoc/src/main/scala/mdoc/internal/markdown/Markdown.scala +++ b/mdoc/src/main/scala/mdoc/internal/markdown/Markdown.scala @@ -99,6 +99,26 @@ object Markdown { ) } + def toMarkdown( + input: Input, + context: Context, + relativePath: RelativePath, + siteVariables: Map[String, String], + reporter: Reporter, + settings: Settings + ): String = { + val textWithVariables = VariableRegex.replaceVariables( + input, + siteVariables, + reporter, + settings + ) + val file = MarkdownFile.parse(textWithVariables, relativePath, reporter) + val processor = new Processor()(context) + processor.processDocument(file) + file.renderToString + } + def toMarkdown( input: Input, markdownSettings: MutableDataSet, diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/MarkdownFile.scala b/mdoc/src/main/scala/mdoc/internal/markdown/MarkdownFile.scala new file mode 100644 index 00000000..eccfe32f --- /dev/null +++ b/mdoc/src/main/scala/mdoc/internal/markdown/MarkdownFile.scala @@ -0,0 +1,123 @@ +package mdoc.internal.markdown + +import scala.meta.inputs.Position +import scala.meta.inputs.Input +import mdoc.Reporter +import scala.collection.mutable +import scala.tools.nsc.doc.DocParser +import scala.meta.io.RelativePath + +final case class MarkdownFile(input: Input, relativePath: RelativePath, parts: List[MarkdownPart]) { + private val appends = mutable.ListBuffer.empty[String] + def appendText(text: String): Unit = appends += text + def renderToString: String = { + val out = new StringBuilder() + parts.foreach(_.renderToString(out)) + out.toString() + } +} +object MarkdownFile { + sealed abstract class State + object State { + case class CodeFence(start: Int, backticks: String, info: String) extends State + case object Text extends State + } + class Parser(input: Input, reporter: Reporter) { + private val text = input.text + private def newPos(start: Int, end: Int): Position = { + Position.Range(input, start, end) + } + private def newText(start: Int, end: Int): Text = { + val part = Text(text.substring(start, end)) + part.pos = newPos(start, end) + part + } + private def newCodeFence( + state: State.CodeFence, + backtickStart: Int, + backtickEnd: Int + ): CodeFence = { + val open = newText(state.start, state.start + state.backticks.length()) + val info = newText(open.pos.end, open.pos.end + state.info.length()) + val body = newText(info.pos.end, backtickStart - 1) + val close = newText(backtickStart - 1, backtickEnd) + val part = CodeFence(open, info, body, close) + part.pos = newPos(state.start, backtickEnd) + part + } + def acceptParts(): List[MarkdownPart] = { + var state: State = State.Text + val parts = mutable.ListBuffer.empty[MarkdownPart] + var curr = 0 + text.linesWithSeparators.foreach { line => + val end = curr + line.length() + state match { + case State.Text => + if (line.startsWith("```")) { + val backticks = line.takeWhile(_ == '`') + val info = line.substring(backticks.length()) + state = State.CodeFence(curr, backticks, info) + } else { + parts += newText(curr, end) + } + case s: State.CodeFence => + if (line.startsWith(s.backticks) && + line.forall(ch => ch == '`' || ch.isWhitespace)) { + parts += newCodeFence(s, curr, end) + state = State.Text + } + } + curr += line.length() + } + state match { + case s: State.CodeFence => + parts += newCodeFence(s, text.length(), text.length()) + case _ => + } + parts.toList + } + } + def parse(input: Input, relativePath: RelativePath, reporter: Reporter): MarkdownFile = { + val parser = new Parser(input, reporter) + val parts = parser.acceptParts() + MarkdownFile(input, relativePath, parts) + } +} + +sealed abstract class MarkdownPart { + var pos: Position = Position.None + final def renderToString(out: StringBuilder): Unit = this match { + case Text(value) => + out.append(value) + case fence: CodeFence => + fence.newPart match { + case Some(newPart) => + out.append(newPart) + case None => + fence.openBackticks.renderToString(out) + fence.newInfo match { + case None => + fence.info.renderToString(out) + case Some(newInfo) => + out.append(newInfo) + if (!newInfo.endsWith("\n")) { + out.append("\n") + } + } + fence.newBody match { + case None => + fence.body.renderToString(out) + case Some(newBody) => + out.append(newBody) + } + fence.closeBackticks.renderToString(out) + } + } +} +final case class Text(value: String) extends MarkdownPart +final case class CodeFence(openBackticks: Text, info: Text, body: Text, closeBackticks: Text) + extends MarkdownPart { + var newPart = Option.empty[String] + var newInfo = Option.empty[String] + var newBody = Option.empty[String] +} diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/MdocExtensions.scala b/mdoc/src/main/scala/mdoc/internal/markdown/MdocExtensions.scala index 81a08f48..c1fcc90a 100644 --- a/mdoc/src/main/scala/mdoc/internal/markdown/MdocExtensions.scala +++ b/mdoc/src/main/scala/mdoc/internal/markdown/MdocExtensions.scala @@ -24,10 +24,7 @@ object MdocExtensions { * @return A sequence of extensions to be applied to Flexmark's options. */ def mdoc(context: Context): List[Extension] = { - plain ++ List( - MdocParserExtension.create(context), - MdocFormatterExtension.create(context.settings) - ) + plain } def plain: List[Extension] = { diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/MdocFormatterExtension.scala b/mdoc/src/main/scala/mdoc/internal/markdown/MdocFormatterExtension.scala deleted file mode 100644 index 49d731a7..00000000 --- a/mdoc/src/main/scala/mdoc/internal/markdown/MdocFormatterExtension.scala +++ /dev/null @@ -1,16 +0,0 @@ -package mdoc.internal.markdown - -import com.vladsch.flexmark.Extension -import com.vladsch.flexmark.formatter.Formatter -import com.vladsch.flexmark.util.options.MutableDataHolder -import mdoc.internal.cli.Settings - -// To be used later, it adds extensions to the formatter -class MdocFormatterExtension(options: Settings) extends Formatter.FormatterExtension { - override def rendererOptions(options: MutableDataHolder): Unit = () - override def extend(builder: Formatter.Builder): Unit = () -} - -object MdocFormatterExtension { - def create(options: Settings): Extension = new MdocFormatterExtension(options) -} diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/MdocParserExtension.scala b/mdoc/src/main/scala/mdoc/internal/markdown/MdocParserExtension.scala deleted file mode 100644 index c171ec9a..00000000 --- a/mdoc/src/main/scala/mdoc/internal/markdown/MdocParserExtension.scala +++ /dev/null @@ -1,80 +0,0 @@ -package mdoc.internal.markdown - -import com.vladsch.flexmark.Extension -import com.vladsch.flexmark.ast.Text -import com.vladsch.flexmark.util.ast -import com.vladsch.flexmark.parser.LinkRefProcessor -import com.vladsch.flexmark.parser.LinkRefProcessorFactory -import com.vladsch.flexmark.parser.Parser -import com.vladsch.flexmark.util.options.DataHolder -import com.vladsch.flexmark.util.options.MutableDataHolder -import com.vladsch.flexmark.util.sequence.BasedSequence -import com.vladsch.flexmark.util.sequence.PrefixedSubSequence -import mdoc.internal.cli.Context - -class MdocParserExtension(context: Context) extends Parser.ParserExtension { - class SiteVariableInjector(site: Map[String, String], document: ast.Document) - extends LinkRefProcessor { - - /** - * Creates a text node with the value of a site variable. - * - * Using `PrefixedSubSequence` and then removing suffix is the only way I found to simulate - * `replace`. Converting from `String` to `BasedSequence` via `stringToCharSequence` does not - * work because Flexmark's `Text` only uses the start and end offsets and does not do an - * in-place replacement of the contents of the returned sequence. These start and end offsets - * select from the original text, not the modified value that we wanted to insert. - * Creating a custom node extending `ContentNode` or `CustomNode` did not help either. - */ - override def createNode(nodeChars: BasedSequence): ast.Node = { - nodeChars.toString match { - case VariableInjectionPattern(key) => - val value = site.getOrElse(key, sys.error(s"Missing '$key' site variable.")) - new Text(PrefixedSubSequence.of(value, nodeChars).removeSuffix(nodeChars)) - case _ => - sys.error("Flexmark matched a variable injection which is not of the expected shape.") - } - } - - private final val totalLength = document.getTextLength - private final val VariableInjectionPattern = "!\\[([^\\]\\[]*)\\]".r - override def isMatch(nodeChars: BasedSequence): Boolean = { - val matches = nodeChars.toString.matches(VariableInjectionPattern.regex) - val startNext = nodeChars.getEndOffset - val endNext = startNext + 1 - // As bracket nesting level is 0, we need to check that the following char does not start with `[` - matches && ( - startNext == totalLength || - !document.getChars.baseSubSequence(startNext, endNext).startsWith("[") - ) - } - - override def adjustInlineText(doc: ast.Document, node: ast.Node): BasedSequence = node.getChars - override def getBracketNestingLevel: Int = 0 - override def getWantExclamationPrefix: Boolean = true - override def updateNodeElements(document: ast.Document, node: ast.Node): Unit = () - override def allowDelimiters(chars: BasedSequence, doc: ast.Document, node: ast.Node): Boolean = - true - } - - class SiteVariableInjectorFactory extends LinkRefProcessorFactory { - override def getBracketNestingLevel(options: DataHolder): Int = 0 - override def getWantExclamationPrefix(options: DataHolder): Boolean = true - override def create(document: ast.Document): LinkRefProcessor = - new SiteVariableInjector(context.settings.site, document) - } - - override def extend(parserBuilder: Parser.Builder): Unit = { - parserBuilder.linkRefProcessorFactory(new SiteVariableInjectorFactory) - parserBuilder.postProcessorFactory( - new MdocPostProcessor.Factory(context) - ) - } - override def parserOptions(options: MutableDataHolder): Unit = () -} - -object MdocParserExtension { - def create(context: Context): Extension = { - new MdocParserExtension(context) - } -} diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/MdocPostProcessor.scala b/mdoc/src/main/scala/mdoc/internal/markdown/Processor.scala similarity index 68% rename from mdoc/src/main/scala/mdoc/internal/markdown/MdocPostProcessor.scala rename to mdoc/src/main/scala/mdoc/internal/markdown/Processor.scala index 78a032e5..167bea20 100644 --- a/mdoc/src/main/scala/mdoc/internal/markdown/MdocPostProcessor.scala +++ b/mdoc/src/main/scala/mdoc/internal/markdown/Processor.scala @@ -2,8 +2,6 @@ package mdoc.internal.markdown import com.vladsch.flexmark.ast.FencedCodeBlock import com.vladsch.flexmark.util.ast -import com.vladsch.flexmark.util.ast.Document -import com.vladsch.flexmark.util.ast.Node import com.vladsch.flexmark.parser.block.DocumentPostProcessor import com.vladsch.flexmark.parser.block.DocumentPostProcessorFactory import com.vladsch.flexmark.util.options.MutableDataSet @@ -24,18 +22,13 @@ import mdoc.internal.pos.PositionSyntax._ import pprint.TPrintColors import scala.meta.io.RelativePath -class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor { +class Processor(implicit ctx: Context) { - override def processDocument(doc: Document): Document = { - val docInput = doc - .get(Markdown.InputKey) - .getOrElse(sys.error(s"Missing DataKey ${Markdown.InputKey}")) - val (scalaInputs, customInputs, preInputs) = collectBlockInputs(doc, docInput) + def processDocument(doc: MarkdownFile): MarkdownFile = { + val docInput = doc.input + val (scalaInputs, customInputs, preInputs) = collectFenceInputs(doc) val filename = docInput.toFilename(ctx.settings) - val inputFile = - doc - .get(Markdown.RelativePathKey) - .getOrElse(throw new NoSuchElementException(s"InputFile: $filename")) + val inputFile = doc.relativePath customInputs.foreach { block => processStringInput(doc, block) } @@ -65,15 +58,10 @@ class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor { } } - def postProcess(doc: Document, inputFile: RelativePath): Unit = {} - - def processPreInput(doc: Document, custom: PreBlockInput): Unit = { - val PreBlockInput(block, input, Pre(mod, info)) = custom + def processPreInput(doc: MarkdownFile, custom: PreFenceInput): Unit = { + val PreFenceInput(block, input, Pre(mod, info)) = custom try { - val inputFile = - doc - .get(Markdown.RelativePathKey) - .getOrElse(throw new NoSuchElementException(s"relativepath")) + val inputFile = doc.relativePath val preCtx = new PreModifierContext( info, input, @@ -92,8 +80,8 @@ class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor { } } - def processStringInput(doc: Document, custom: StringBlockInput): Unit = { - val StringBlockInput(block, input, Str(mod, info)) = custom + def processStringInput(doc: MarkdownFile, custom: StringFenceInput): Unit = { + val StringFenceInput(block, input, Str(mod, info)) = custom try { val newText = mod.process(info, input, ctx.reporter) replaceNodeWithText(doc, block, newText) @@ -107,13 +95,13 @@ class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor { } def processScalaInputs( - doc: Document, - inputs: List[ScalaBlockInput], + doc: MarkdownFile, + inputs: List[ScalaFenceInput], inputFile: RelativePath, filename: String ): Unit = { val sectionInputs = inputs.map { - case ScalaBlockInput(_, input, mod) => + case ScalaFenceInput(_, input, mod) => import scala.meta._ dialects.Sbt1(input).parse[Source] match { case parsers.Parsed.Success(source) => @@ -136,8 +124,8 @@ class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor { filename ) rendered.sections.zip(inputs).foreach { - case (section, ScalaBlockInput(block, _, mod)) => - block.setInfo(CharSubSequence.of("scala")) + case (section, ScalaFenceInput(block, _, mod)) => + block.newInfo = Some("scala") def defaultRender: String = Renderer.renderEvaluatedSection( rendered, section, @@ -188,7 +176,7 @@ class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor { } else if (m.isSilent) { () // Do nothing } else { - block.setContent(List[BasedSequence](CharSubSequence.of(defaultRender)).asJava) + block.newBody = Some(defaultRender) } case c: Modifier.Str => throw new IllegalArgumentException(c.toString) @@ -212,55 +200,35 @@ class MdocPostProcessor(implicit ctx: Context) extends DocumentPostProcessor { } } - def asBasedSequence(string: String): util.List[BasedSequence] = { - List[BasedSequence](CharSubSequence.of(string)).asJava - } - - def appendChild(doc: Document, text: String): Unit = { + def appendChild(doc: MarkdownFile, text: String): Unit = { if (text.nonEmpty) { - doc.appendChild(parseMarkdown(doc, text)) + doc.appendText(text) } } - def parseMarkdown(doc: Document, text: String): Node = { - val markdownOptions = new MutableDataSet() - markdownOptions.setAll(doc) - Markdown.parse(CharSubSequence.of(text), markdownOptions) - } - - def replaceNodeWithText(doc: Document, toReplace: Node, text: String): Unit = { - val child = parseMarkdown(doc, text) - toReplace.insertAfter(child) - toReplace.unlink() + def replaceNodeWithText(doc: MarkdownFile, toReplace: CodeFence, text: String): Unit = { + toReplace.newPart = Some(text) } - def collectBlockInputs( - doc: Document, - docInput: Input - ): (List[ScalaBlockInput], List[StringBlockInput], List[PreBlockInput]) = { - val InterestingCodeFence = new BlockInput(ctx, docInput) - val inputs = List.newBuilder[ScalaBlockInput] - val strings = List.newBuilder[StringBlockInput] - val pres = List.newBuilder[PreBlockInput] - Markdown.traverse[FencedCodeBlock](doc) { + def collectFenceInputs( + doc: MarkdownFile + ): (List[ScalaFenceInput], List[StringFenceInput], List[PreFenceInput]) = { + val InterestingCodeFence = new FenceInput(ctx, doc.input) + val inputs = List.newBuilder[ScalaFenceInput] + val strings = List.newBuilder[StringFenceInput] + val pres = List.newBuilder[PreFenceInput] + doc.parts.foreach { case InterestingCodeFence(input) => input.mod match { case string: Str => - strings += StringBlockInput(input.block, input.input, string) + strings += StringFenceInput(input.block, input.input, string) case pre: Pre => - pres += PreBlockInput(input.block, input.input, pre) + pres += PreFenceInput(input.block, input.input, pre) case _ => inputs += input } + case _ => } (inputs.result(), strings.result(), pres.result()) } } - -object MdocPostProcessor { - class Factory(context: Context) extends DocumentPostProcessorFactory { - override def create(document: ast.Document): DocumentPostProcessor = { - new MdocPostProcessor()(context) - } - } -} diff --git a/tests/unit/src/test/scala/tests/markdown/BaseMarkdownSuite.scala b/tests/unit/src/test/scala/tests/markdown/BaseMarkdownSuite.scala index 21db1c8a..ab20dfe7 100644 --- a/tests/unit/src/test/scala/tests/markdown/BaseMarkdownSuite.scala +++ b/tests/unit/src/test/scala/tests/markdown/BaseMarkdownSuite.scala @@ -17,6 +17,7 @@ import scala.meta.io.AbsolutePath import scala.meta.testkit.DiffAssertions import tests.markdown.StringSyntax._ import mdoc.internal.pos.PositionSyntax._ +import scala.meta.io.RelativePath abstract class BaseMarkdownSuite extends org.scalatest.FunSuite with DiffAssertions { def createTempDirectory(): AbsolutePath = { @@ -43,6 +44,7 @@ abstract class BaseMarkdownSuite extends org.scalatest.FunSuite with DiffAsserti def postProcessExpected: Map[String, String => String] = Map.empty private val myStdout = new ByteArrayOutputStream() private def newReporter(): ConsoleReporter = { + myStdout.reset() new ConsoleReporter(new PrintStream(myStdout)) } protected def scalacOptions: String = "" @@ -53,11 +55,6 @@ abstract class BaseMarkdownSuite extends org.scalatest.FunSuite with DiffAsserti Context(settings, reporter, compiler) } - def getMarkdownSettings(context: Context): MutableDataSet = { - myStdout.reset() - Markdown.mdocSettings(context) - } - def checkError( name: String, original: String, @@ -69,7 +66,8 @@ abstract class BaseMarkdownSuite extends org.scalatest.FunSuite with DiffAsserti val reporter = newReporter() val context = newContext(settings, reporter) val input = Input.VirtualFile(name + ".md", original) - Markdown.toMarkdown(input, getMarkdownSettings(context), reporter, settings) + val relpath = RelativePath(input.path) + Markdown.toMarkdown(input, context, relpath, baseSettings.site, reporter, settings) assert(reporter.hasErrors, "Expected errors but reporter.hasErrors=false") val obtainedErrors = Compat.postProcess( fansi.Str(myStdout.toString).plainText.trimLineEnds, @@ -89,8 +87,9 @@ abstract class BaseMarkdownSuite extends org.scalatest.FunSuite with DiffAsserti val reporter = newReporter() val context = newContext(settings, reporter) val input = Input.VirtualFile(name + ".md", original) + val relpath = RelativePath(input.path) val obtained = - Markdown.toMarkdown(input, getMarkdownSettings(context), reporter, settings).trimLineEnds + Markdown.toMarkdown(input, context, relpath, baseSettings.site, reporter, settings) val colorOut = myStdout.toString() print(colorOut) val stdout = fansi.Str(colorOut).plainText diff --git a/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala b/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala new file mode 100644 index 00000000..15fcc96e --- /dev/null +++ b/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala @@ -0,0 +1,114 @@ +package tests.markdown + +import org.scalatest.FunSuite +import scala.meta.testkit.DiffAssertions +import mdoc.internal.markdown.MarkdownFile +import scala.meta.inputs.Input +import mdoc.internal.io.ConsoleReporter +import mdoc.internal.markdown.Text +import mdoc.internal.markdown.MarkdownPart +import mdoc.internal.markdown.CodeFence +import utest._ +import scala.meta.io.RelativePath + +object MarkdownFileSuite extends TestSuite { + val tests = Tests { + val reporter = new ConsoleReporter(System.out) + + def check(original: String, expected: MarkdownPart*)( + implicit path: utest.framework.TestPath + ): Unit = { + reporter.reset() + val input = Input.VirtualFile(path.value.mkString("."), original) + val relpath = RelativePath(input.path) + val obtained = MarkdownFile.parse(input, relpath, reporter).parts + require(!reporter.hasErrors) + val expectedParts = expected.toList + assert(obtained == expectedParts) + } + + test("basic") { + check( + """# Hello + |World + |```scala mdoc + |println(42) + |``` + |End. + |""".stripMargin, + Text("# Hello\n"), + Text("World\n"), + CodeFence( + Text("```"), + Text("scala mdoc\n"), + Text("println(42)\n"), + Text("```\n") + ), + Text("End.\n") + ) + } + + test("four-backtick") { + check( + """# Hello + |World + |````scala mdoc + |``` + |println(42) + |``` + |```` + |End. + |""".stripMargin, + Text("# Hello\n"), + Text("World\n"), + CodeFence( + Text("````"), + Text("scala mdoc\n"), + Text("```\nprintln(42)\n```\n"), + Text("````\n") + ), + Text("End.\n") + ) + } + + test("two-backtick") { + check( + """# Hello + |World + |``scala mdoc + |println(42) + |`` + |End. + |""".stripMargin, + Text("# Hello\n"), + Text("World\n"), + Text("``scala mdoc\n"), + Text("println(42)\n"), + Text("``\n"), + Text("End.\n") + ) + } + + test("backtick-mismatch") { + check( + """|````scala mdoc + |````` + |```` + |42 + |""".stripMargin, + CodeFence( + Text("````"), + Text("scala mdoc\n"), + Text(""), + Text("`````\n") + ), + CodeFence( + Text("````"), + Text("\n"), + Text("42\n"), + Text("") + ) + ) + } + } +} From 6071d2b3c25f5b8dd7332b18af20e436bb43bd40 Mon Sep 17 00:00:00 2001 From: Olafur Pall Geirsson Date: Wed, 30 Oct 2019 09:55:01 +0000 Subject: [PATCH 2/3] Fix failing test cases. --- .../mdoc/internal/markdown/FenceInput.scala | 14 +++--- .../mdoc/internal/markdown/MarkdownFile.scala | 15 ++++-- .../scala-2.12/tests/markdown/JsSuite.scala | 38 ++++----------- .../src/test/scala/tests/cli/CliSuite.scala | 1 - .../scala/tests/cli/ScalacOptionsSuite.scala | 1 - .../tests/markdown/CompileOnlySuite.scala | 2 - .../test/scala/tests/markdown/FailSuite.scala | 1 - .../tests/markdown/MarkdownFileSuite.scala | 46 +++++++++++-------- .../scala/tests/markdown/MultiModsSuite.scala | 8 ++-- .../scala/tests/markdown/ResetSuite.scala | 8 +++- .../tests/markdown/ScastieModifierSuite.scala | 32 ++++++------- .../scala/tests/markdown/SilentSuite.scala | 1 + .../markdown/SiteVariableInjectorSuite.scala | 6 +-- .../scala/tests/markdown/ToStringSuite.scala | 1 - 14 files changed, 80 insertions(+), 94 deletions(-) diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/FenceInput.scala b/mdoc/src/main/scala/mdoc/internal/markdown/FenceInput.scala index 837376e9..90d14cdf 100644 --- a/mdoc/src/main/scala/mdoc/internal/markdown/FenceInput.scala +++ b/mdoc/src/main/scala/mdoc/internal/markdown/FenceInput.scala @@ -46,22 +46,22 @@ class FenceInput(ctx: Context, baseInput: Input) { } } .orElse { - ctx.reporter.error(info.pos, s"Invalid mode '$mode'") + invalid(info, s"Invalid mode '$mode'") None } } } } - private def invalid(block: FencedCodeBlock, message: String): Unit = { + private def invalid(info: Text, message: String): Unit = { val offset = "scala mdoc:".length - val start = block.getInfo.getStartOffset + offset - val end = block.getInfo.getEndOffset + val start = info.pos.start + offset + val end = info.pos.end - 1 val pos = Position.Range(baseInput, start, end) ctx.reporter.error(pos, message) } private def invalidCombination(info: Text, mod1: String, mod2: String): Boolean = { - ctx.reporter.error(info.pos, s"invalid combination of modifiers '$mod1' and '$mod2'") + invalid(info, s"invalid combination of modifiers '$mod1' and '$mod2'") false } @@ -76,8 +76,8 @@ class FenceInput(ctx: Context, baseInput: Input) { true } else { val all = others.map(_.toString.toLowerCase).mkString(", ") - ctx.reporter.error( - info.pos, + invalid( + info, s"""compile-only cannot be used in combination with $all""" ) false diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/MarkdownFile.scala b/mdoc/src/main/scala/mdoc/internal/markdown/MarkdownFile.scala index eccfe32f..95086c8a 100644 --- a/mdoc/src/main/scala/mdoc/internal/markdown/MarkdownFile.scala +++ b/mdoc/src/main/scala/mdoc/internal/markdown/MarkdownFile.scala @@ -9,10 +9,13 @@ import scala.meta.io.RelativePath final case class MarkdownFile(input: Input, relativePath: RelativePath, parts: List[MarkdownPart]) { private val appends = mutable.ListBuffer.empty[String] - def appendText(text: String): Unit = appends += text + def appendText(text: String): Unit = { + appends += text + } def renderToString: String = { val out = new StringBuilder() parts.foreach(_.renderToString(out)) + appends.foreach(a => out.append(a).append("\n")) out.toString() } } @@ -28,8 +31,9 @@ object MarkdownFile { Position.Range(input, start, end) } private def newText(start: Int, end: Int): Text = { - val part = Text(text.substring(start, end)) - part.pos = newPos(start, end) + val adaptedEnd = math.max(start, end) + val part = Text(text.substring(start, adaptedEnd)) + part.pos = newPos(start, adaptedEnd) part } private def newCodeFence( @@ -39,8 +43,9 @@ object MarkdownFile { ): CodeFence = { val open = newText(state.start, state.start + state.backticks.length()) val info = newText(open.pos.end, open.pos.end + state.info.length()) - val body = newText(info.pos.end, backtickStart - 1) - val close = newText(backtickStart - 1, backtickEnd) + val adaptedBacktickStart = math.max(0, backtickStart - 1) + val body = newText(info.pos.end, adaptedBacktickStart) + val close = newText(adaptedBacktickStart, backtickEnd) val part = CodeFence(open, info, body, close) part.pos = newPos(state.start, backtickEnd) part diff --git a/tests/unit/src/test/scala-2.12/tests/markdown/JsSuite.scala b/tests/unit/src/test/scala-2.12/tests/markdown/JsSuite.scala index fa365631..c5ace36d 100644 --- a/tests/unit/src/test/scala-2.12/tests/markdown/JsSuite.scala +++ b/tests/unit/src/test/scala-2.12/tests/markdown/JsSuite.scala @@ -15,7 +15,6 @@ class JsSuite extends BaseMarkdownSuite { def suffix(name: String): String = s"""| - | | |""".stripMargin @@ -25,15 +24,12 @@ class JsSuite extends BaseMarkdownSuite { |```scala mdoc:js |println("hello world!") |``` - """.stripMargin, + |""".stripMargin, """|```scala |println("hello world!") |``` - | |
- | | - | | """.stripMargin ) @@ -64,21 +60,17 @@ class JsSuite extends BaseMarkdownSuite { |```scala mdoc:js |println("hello 2!") |``` - """.stripMargin, + |""".stripMargin, """|```scala |println("hello 1!") |``` - | |
| |```scala |println("hello 2!") |``` - | |
- | | - | | |""".stripMargin ) @@ -143,7 +135,7 @@ class JsSuite extends BaseMarkdownSuite { |```scala mdoc:js |println(x) |``` - """.stripMargin, + |""".stripMargin, """|```scala |val x = 1 |``` @@ -151,11 +143,8 @@ class JsSuite extends BaseMarkdownSuite { |```scala |println(x) |``` - | |
- | | - | | """.stripMargin ) @@ -199,7 +188,7 @@ class JsSuite extends BaseMarkdownSuite { | | c | '''.stripMargin |``` - """.stripMargin.triplequoted, + |""".stripMargin.triplequoted, s"""|```scala |val x = ''' | |a @@ -207,9 +196,7 @@ class JsSuite extends BaseMarkdownSuite { | | c | '''.stripMargin |``` - | |
- | |${suffix("stripMargin")} |""".stripMargin.triplequoted ) @@ -220,10 +207,9 @@ class JsSuite extends BaseMarkdownSuite { |```scala mdoc:js:invisible |println("Hello!") |``` - """.stripMargin, + |""".stripMargin, s"""| |
- | |${suffix("invisible")} |""".stripMargin ) @@ -263,7 +249,7 @@ class JsSuite extends BaseMarkdownSuite { |```scala mdoc:js:shared:not |println(1) |``` - """.stripMargin, + |""".stripMargin, """|error: mods-error.md:2:25: invalid modifier 'not' |```scala mdoc:js:shared:not | ^^^ @@ -276,19 +262,14 @@ class JsSuite extends BaseMarkdownSuite { |```scala mdoc:js |println("Hello!") |``` - """.stripMargin, + |""".stripMargin, """|```scala |println("Hello!") |``` - | |
- | | - | | - | | - | | |""".stripMargin, settings = { @@ -314,14 +295,11 @@ class JsSuite extends BaseMarkdownSuite { |```scala mdoc:js:invisible |println("Hello!") |``` - """.stripMargin, + |""".stripMargin, s"""| |
- | |$unpkgReact - | | - | | |""".stripMargin, settings = { diff --git a/tests/unit/src/test/scala/tests/cli/CliSuite.scala b/tests/unit/src/test/scala/tests/cli/CliSuite.scala index 2cdd1a41..4eca3a38 100644 --- a/tests/unit/src/test/scala/tests/cli/CliSuite.scala +++ b/tests/unit/src/test/scala/tests/cli/CliSuite.scala @@ -137,7 +137,6 @@ class CliSuite extends BaseCliSuite { """ |/before-index.md |# Header - | |[Head](#head) """.stripMargin, // did not generate index.md expectedExitCode = 1, diff --git a/tests/unit/src/test/scala/tests/cli/ScalacOptionsSuite.scala b/tests/unit/src/test/scala/tests/cli/ScalacOptionsSuite.scala index 4ea22011..8cb84cd3 100644 --- a/tests/unit/src/test/scala/tests/cli/ScalacOptionsSuite.scala +++ b/tests/unit/src/test/scala/tests/cli/ScalacOptionsSuite.scala @@ -87,7 +87,6 @@ class ScalacOptionsSuite extends BaseCliSuite { |println("1") |// 1 |``` - | |```scala |println("2") |// 2 diff --git a/tests/unit/src/test/scala/tests/markdown/CompileOnlySuite.scala b/tests/unit/src/test/scala/tests/markdown/CompileOnlySuite.scala index f9cda158..1e76d8f1 100644 --- a/tests/unit/src/test/scala/tests/markdown/CompileOnlySuite.scala +++ b/tests/unit/src/test/scala/tests/markdown/CompileOnlySuite.scala @@ -33,12 +33,10 @@ class CompileOnlySuite extends BaseMarkdownSuite { |val message = "Enter: " |// message: String = "Enter: " |``` - | |```scala |println(message) |println(System.in.read()) |``` - | |```scala |println(message) |// Enter: diff --git a/tests/unit/src/test/scala/tests/markdown/FailSuite.scala b/tests/unit/src/test/scala/tests/markdown/FailSuite.scala index 5cd898a3..56c68cf9 100644 --- a/tests/unit/src/test/scala/tests/markdown/FailSuite.scala +++ b/tests/unit/src/test/scala/tests/markdown/FailSuite.scala @@ -106,7 +106,6 @@ class FailSuite extends BaseMarkdownSuite { |println(42) |// 42 |``` - | |```scala |val x: Int = "String" |// error: type mismatch; diff --git a/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala b/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala index 15fcc96e..6ea7e336 100644 --- a/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala +++ b/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala @@ -11,21 +11,27 @@ import mdoc.internal.markdown.CodeFence import utest._ import scala.meta.io.RelativePath +object Assertions extends DiffAssertions + object MarkdownFileSuite extends TestSuite { - val tests = Tests { - val reporter = new ConsoleReporter(System.out) + import Assertions._ + val reporter = new ConsoleReporter(System.out) - def check(original: String, expected: MarkdownPart*)( - implicit path: utest.framework.TestPath - ): Unit = { - reporter.reset() - val input = Input.VirtualFile(path.value.mkString("."), original) - val relpath = RelativePath(input.path) - val obtained = MarkdownFile.parse(input, relpath, reporter).parts - require(!reporter.hasErrors) - val expectedParts = expected.toList - assert(obtained == expectedParts) - } + def check(original: String, expected: MarkdownPart*)( + implicit path: utest.framework.TestPath + ): Unit = { + reporter.reset() + val input = Input.VirtualFile(path.value.mkString("."), original) + val relpath = RelativePath(input.path) + val obtained = MarkdownFile.parse(input, relpath, reporter).parts + require(!reporter.hasErrors) + val expectedParts = expected.toList + assertNoDiff( + pprint.tokenize(obtained).mkString, + pprint.tokenize(expectedParts).mkString + ) + } + val tests = Tests { test("basic") { check( @@ -41,8 +47,8 @@ object MarkdownFileSuite extends TestSuite { CodeFence( Text("```"), Text("scala mdoc\n"), - Text("println(42)\n"), - Text("```\n") + Text("println(42)"), + Text("\n```\n") ), Text("End.\n") ) @@ -64,8 +70,8 @@ object MarkdownFileSuite extends TestSuite { CodeFence( Text("````"), Text("scala mdoc\n"), - Text("```\nprintln(42)\n```\n"), - Text("````\n") + Text("```\nprintln(42)\n```"), + Text("\n````\n") ), Text("End.\n") ) @@ -100,13 +106,13 @@ object MarkdownFileSuite extends TestSuite { Text("````"), Text("scala mdoc\n"), Text(""), - Text("`````\n") + Text("\n`````\n") ), CodeFence( Text("````"), Text("\n"), - Text("42\n"), - Text("") + Text("42"), + Text("\n") ) ) } diff --git a/tests/unit/src/test/scala/tests/markdown/MultiModsSuite.scala b/tests/unit/src/test/scala/tests/markdown/MultiModsSuite.scala index 81a1c06c..5f62b2fd 100644 --- a/tests/unit/src/test/scala/tests/markdown/MultiModsSuite.scala +++ b/tests/unit/src/test/scala/tests/markdown/MultiModsSuite.scala @@ -12,8 +12,9 @@ class MultiModsSuite extends BaseMarkdownSuite { |```scala mdoc:reset:fail |println(x) |``` - """.stripMargin, - """|```scala + |""".stripMargin, + """| + |```scala |val x = 1 |// x: Int = 1 |``` @@ -24,7 +25,7 @@ class MultiModsSuite extends BaseMarkdownSuite { |// println(x) |// ^ |``` - """.stripMargin + |""".stripMargin ) check( @@ -69,6 +70,7 @@ class MultiModsSuite extends BaseMarkdownSuite { |// x: Int = 1 |``` | + | |```scala |println(x) |// 2 diff --git a/tests/unit/src/test/scala/tests/markdown/ResetSuite.scala b/tests/unit/src/test/scala/tests/markdown/ResetSuite.scala index f6ce178a..b9bce5ed 100644 --- a/tests/unit/src/test/scala/tests/markdown/ResetSuite.scala +++ b/tests/unit/src/test/scala/tests/markdown/ResetSuite.scala @@ -50,6 +50,7 @@ class ResetSuite extends BaseMarkdownSuite { |``` | |```scala mdoc + |implicit val x: Int = 41 |println(x) |``` """.stripMargin, @@ -58,12 +59,15 @@ class ResetSuite extends BaseMarkdownSuite { |// x: Int = 42 |``` | - |```scala mdoc:reset + |```scala + | |``` | |```scala + |implicit val x: Int = 41 + |// x: Int = 41 |println(x) - |// 42 + |// 41 |``` """.stripMargin ) diff --git a/tests/unit/src/test/scala/tests/markdown/ScastieModifierSuite.scala b/tests/unit/src/test/scala/tests/markdown/ScastieModifierSuite.scala index 18a2247a..463d9ec8 100644 --- a/tests/unit/src/test/scala/tests/markdown/ScastieModifierSuite.scala +++ b/tests/unit/src/test/scala/tests/markdown/ScastieModifierSuite.scala @@ -34,17 +34,15 @@ class ScastieModifierSuite extends BaseMarkdownSuite { """.stripMargin, s""" | - | |

-       |
        |
     """.stripMargin
   )
@@ -58,17 +56,15 @@ class ScastieModifierSuite extends BaseMarkdownSuite {
     """.stripMargin,
     s"""
        |
-       |
        |

-       |
        |
     """.stripMargin,
     settings = darkThemeSettings
diff --git a/tests/unit/src/test/scala/tests/markdown/SilentSuite.scala b/tests/unit/src/test/scala/tests/markdown/SilentSuite.scala
index 0935e025..56e40f24 100644
--- a/tests/unit/src/test/scala/tests/markdown/SilentSuite.scala
+++ b/tests/unit/src/test/scala/tests/markdown/SilentSuite.scala
@@ -8,6 +8,7 @@ class SilentSuite extends BaseMarkdownSuite {
       |```scala mdoc:silent
       |val x = 4
       |```
+      |
       |```scala mdoc
       |println(x)
       |```
diff --git a/tests/unit/src/test/scala/tests/markdown/SiteVariableInjectorSuite.scala b/tests/unit/src/test/scala/tests/markdown/SiteVariableInjectorSuite.scala
index 321fa548..513cb20b 100644
--- a/tests/unit/src/test/scala/tests/markdown/SiteVariableInjectorSuite.scala
+++ b/tests/unit/src/test/scala/tests/markdown/SiteVariableInjectorSuite.scala
@@ -7,7 +7,7 @@ class SiteVariableInjectorSuite extends BaseMarkdownSuite {
       |# Hey ![version]
     """.stripMargin,
     """
-      |# Hey 1.0
+      |# Hey ![version]
     """.stripMargin
   )
 
@@ -17,7 +17,7 @@ class SiteVariableInjectorSuite extends BaseMarkdownSuite {
       |I am ![version]
     """.stripMargin,
     """
-      |I am 1.0
+      |I am ![version]
     """.stripMargin
   )
 
@@ -32,7 +32,7 @@ class SiteVariableInjectorSuite extends BaseMarkdownSuite {
       |
       || C1 | C2 |
       || == | == |
-      || 1.0 | hello |
+      || ![version] | hello |
     """.stripMargin
   )
 
diff --git a/tests/unit/src/test/scala/tests/markdown/ToStringSuite.scala b/tests/unit/src/test/scala/tests/markdown/ToStringSuite.scala
index 6e0369e3..84971066 100644
--- a/tests/unit/src/test/scala/tests/markdown/ToStringSuite.scala
+++ b/tests/unit/src/test/scala/tests/markdown/ToStringSuite.scala
@@ -16,7 +16,6 @@ class ToStringSuite extends BaseMarkdownSuite {
        |List("a")
        |// res0: List[String] = List(a)
        |```
-       |
        |```scala
        |List("a")
        |// res1: List[String] = List("a")

From ec09ef4c640cd30c6a3ea9a6f6864cea1c377186 Mon Sep 17 00:00:00 2001
From: Olafur Pall Geirsson 
Date: Wed, 30 Oct 2019 10:32:53 +0000
Subject: [PATCH 3/3] Fix test failures on 2.12/2.11

---
 build.sbt                                     |   2 -
 .../src/sbt-test/sbt-mdoc/basic/build.sbt     |   3 -
 .../tests/markdown/MarkdownFileSuite.scala    | 190 +++++++++---------
 3 files changed, 90 insertions(+), 105 deletions(-)

diff --git a/build.sbt b/build.sbt
index 51751acc..958d1103 100644
--- a/build.sbt
+++ b/build.sbt
@@ -145,8 +145,6 @@ lazy val unit = project
     skip in publish := true,
     addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.10.3"),
     resolvers += Resolver.bintrayRepo("cibotech", "public"),
-    libraryDependencies += "com.lihaoyi" %% "utest" % "0.7.1" % Test,
-    testFrameworks += new TestFramework("utest.runner.Framework"),
     scala212LibraryDependencies(
       List(
         "com.cibo" %% "evilplot" % "0.6.0"
diff --git a/mdoc-sbt/src/sbt-test/sbt-mdoc/basic/build.sbt b/mdoc-sbt/src/sbt-test/sbt-mdoc/basic/build.sbt
index 5ba3e8ba..34c60a60 100644
--- a/mdoc-sbt/src/sbt-test/sbt-mdoc/basic/build.sbt
+++ b/mdoc-sbt/src/sbt-test/sbt-mdoc/basic/build.sbt
@@ -18,11 +18,8 @@ println(example.Example.greeting)
 ```scala
 println("Hello Scala.js!")
 ```
-
 
- - """.trim, "\"\"\"\n" + obtained + "\n\"\"\"" diff --git a/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala b/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala index 6ea7e336..a726fd56 100644 --- a/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala +++ b/tests/unit/src/test/scala/tests/markdown/MarkdownFileSuite.scala @@ -8,113 +8,103 @@ import mdoc.internal.io.ConsoleReporter import mdoc.internal.markdown.Text import mdoc.internal.markdown.MarkdownPart import mdoc.internal.markdown.CodeFence -import utest._ import scala.meta.io.RelativePath -object Assertions extends DiffAssertions - -object MarkdownFileSuite extends TestSuite { - import Assertions._ +class MarkdownFileSuite extends FunSuite with DiffAssertions { val reporter = new ConsoleReporter(System.out) - def check(original: String, expected: MarkdownPart*)( - implicit path: utest.framework.TestPath - ): Unit = { - reporter.reset() - val input = Input.VirtualFile(path.value.mkString("."), original) - val relpath = RelativePath(input.path) - val obtained = MarkdownFile.parse(input, relpath, reporter).parts - require(!reporter.hasErrors) - val expectedParts = expected.toList - assertNoDiff( - pprint.tokenize(obtained).mkString, - pprint.tokenize(expectedParts).mkString - ) - } - val tests = Tests { - - test("basic") { - check( - """# Hello - |World - |```scala mdoc - |println(42) - |``` - |End. - |""".stripMargin, - Text("# Hello\n"), - Text("World\n"), - CodeFence( - Text("```"), - Text("scala mdoc\n"), - Text("println(42)"), - Text("\n```\n") - ), - Text("End.\n") + def check(name: String, original: String, expected: MarkdownPart*): Unit = { + test(name) { + reporter.reset() + val input = Input.VirtualFile(name, original) + val relpath = RelativePath(input.path) + val obtained = MarkdownFile.parse(input, relpath, reporter).parts + require(!reporter.hasErrors) + val expectedParts = expected.toList + assertNoDiff( + pprint.tokenize(obtained).mkString, + pprint.tokenize(expectedParts).mkString ) } + } - test("four-backtick") { - check( - """# Hello - |World - |````scala mdoc - |``` - |println(42) - |``` - |```` - |End. - |""".stripMargin, - Text("# Hello\n"), - Text("World\n"), - CodeFence( - Text("````"), - Text("scala mdoc\n"), - Text("```\nprintln(42)\n```"), - Text("\n````\n") - ), - Text("End.\n") - ) - } + check( + "basic", + """# Hello + |World + |```scala mdoc + |println(42) + |``` + |End. + |""".stripMargin, + Text("# Hello\n"), + Text("World\n"), + CodeFence( + Text("```"), + Text("scala mdoc\n"), + Text("println(42)"), + Text("\n```\n") + ), + Text("End.\n") + ) - test("two-backtick") { - check( - """# Hello - |World - |``scala mdoc - |println(42) - |`` - |End. - |""".stripMargin, - Text("# Hello\n"), - Text("World\n"), - Text("``scala mdoc\n"), - Text("println(42)\n"), - Text("``\n"), - Text("End.\n") - ) - } + check( + "four-backtick", + """# Hello + |World + |````scala mdoc + |``` + |println(42) + |``` + |```` + |End. + |""".stripMargin, + Text("# Hello\n"), + Text("World\n"), + CodeFence( + Text("````"), + Text("scala mdoc\n"), + Text("```\nprintln(42)\n```"), + Text("\n````\n") + ), + Text("End.\n") + ) - test("backtick-mismatch") { - check( - """|````scala mdoc - |````` - |```` - |42 - |""".stripMargin, - CodeFence( - Text("````"), - Text("scala mdoc\n"), - Text(""), - Text("\n`````\n") - ), - CodeFence( - Text("````"), - Text("\n"), - Text("42"), - Text("\n") - ) - ) - } - } + check( + "two-backtick", + """# Hello + |World + |``scala mdoc + |println(42) + |`` + |End. + |""".stripMargin, + Text("# Hello\n"), + Text("World\n"), + Text("``scala mdoc\n"), + Text("println(42)\n"), + Text("``\n"), + Text("End.\n") + ) + + check( + "backtick-mismatch", + """|````scala mdoc + |````` + |```` + |42 + |""".stripMargin, + CodeFence( + Text("````"), + Text("scala mdoc\n"), + Text(""), + Text("\n`````\n") + ), + CodeFence( + Text("````"), + Text("\n"), + Text("42"), + Text("\n") + ) + ) }