diff --git a/DESCRIPTION b/DESCRIPTION index 029d1567c8..90360d3175 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: rmarkdown Type: Package Title: Dynamic Documents for R -Version: 2.9.4 +Version: 2.9.5 Authors@R: c( person("JJ", "Allaire", role = "aut", email = "jj@rstudio.com"), person("Yihui", "Xie", role = c("aut", "cre"), email = "xie@yihui.name", comment = c(ORCID = "0000-0003-0645-5666")), diff --git a/NEWS.md b/NEWS.md index 4818f37c70..e92e49a1f4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,12 @@ rmarkdown 2.10 ================================================================================ +- `md_document()` will now handle correctly `preserve_yaml` value for all variants and all pandoc versions (#2190). + * with `preserve_yaml = TRUE`, markdown output will keep the YAML metadata block from the Rmd file. + * with `preserve_yaml = FALSE`, markdown output will have no YAML metadata block. + + This fixes a breaking change in Pandoc 2.13 regarding `gfm`, `commonmark` and `commonmark_x` which now supports `yaml_metadata_block` by default (#2118). + - New supported syntax for Shiny prerendered documents: you can now use `server: shiny` or `server: type: shiny`. - Ability to inject additional functions into Shiny prerendered server scope using the "server-extras" context. diff --git a/R/md_document.R b/R/md_document.R index 95f577c111..9df7e9db86 100644 --- a/R/md_document.R +++ b/R/md_document.R @@ -11,11 +11,11 @@ #' see the documentation on R Markdown \link[=rmd_metadata]{metadata}. #' @inheritParams html_document #' @param variant Markdown variant to produce (defaults to "markdown_strict"). -#' Other valid values are "commonmark", "markdown_github", "markdown_mmd", -#' markdown_phpextra", or even "markdown" (which produces pandoc markdown). -#' You can also compose custom markdown variants, see the -#' \href{https://pandoc.org/MANUAL.html}{pandoc online documentation} -#' for details. +#' Other valid values are "commonmark", "gfm", "commonmark_x", "markdown_mmd", +#' markdown_phpextra", "markdown_github", or even "markdown" (which produces +#' pandoc markdown). You can also compose custom markdown variants, see the +#' \href{https://pandoc.org/MANUAL.html}{pandoc online documentation} for +#' details. #' @param preserve_yaml Preserve YAML front matter in final document. #' @param fig_retina Scaling to perform for retina displays. Defaults to #' \code{NULL} which performs no scaling. A setting of 2 will work for all @@ -48,8 +48,9 @@ md_document <- function(variant = "markdown_strict", pandoc_args = NULL, ext = ".md") { + # base pandoc options for all markdown output - args <- c(if (variant != "markdown" || preserve_yaml) "--standalone") + args <- c(if (preserve_yaml) "--standalone") # table of contents args <- c(args, pandoc_toc_args(toc, toc_depth)) @@ -60,8 +61,11 @@ md_document <- function(variant = "markdown_strict", # pandoc args args <- c(args, pandoc_args) - # add post_processor for yaml preservation - post_processor <- if (preserve_yaml && variant != 'markdown') { + # variants + variant <- adapt_md_variant(variant, preserve_yaml) + + # add post_processor for yaml preservation if not supported by pandoc + post_processor <- if (preserve_yaml && !grepl('yaml_metadata_block', variant, fixed = TRUE)) { function(metadata, input_file, output_file, clean, verbose) { input_lines <- read_utf8(input_file) partitioned <- partition_yaml_front_matter(input_lines) @@ -88,3 +92,41 @@ md_document <- function(variant = "markdown_strict", post_processor = post_processor ) } + +adapt_md_variant <- function(variant, preserve_yaml) { + variant_base <- gsub("^([^+-]*).*", "\\1", variant) + variant_extensions <- gsub(sprintf("^%s", variant_base), "", variant) + + set_extension <- function(format, ext, add = TRUE) { + ext <- paste0(ifelse(add, "+", "-"), ext) + if (grepl(ext, format, fixed = TRUE)) return(format) + paste0(format, ext, collapse = "") + } + + add_yaml_block_ext <- function(extensions, preserve_yaml) { + set_extension(variant_extensions, "yaml_metadata_block", preserve_yaml) + } + + # yaml_metadata_block extension + variant_extensions <- switch( + variant_base, + gfm =, + commonmark =, + commonmark_x = { + if (pandoc_available(2.13)) { + add_yaml_block_ext(variant_extensions, preserve_yaml) + } else { + variant_extensions + } + }, + markdown =, + markdown_phpextra =, + markdown_github =, + markdown_mmd =, + markdown_strict = add_yaml_block_ext(variant_extensions, preserve_yaml), + # do not modified for unknown (yet) md variant + variant_extensions + ) + + paste0(variant_base, variant_extensions, collapse = "") +} diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown-meta.md b/tests/testthat/_snaps/md_document/yaml-block-markdown-meta.md new file mode 100644 index 0000000000..673e544bc7 --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown-meta.md @@ -0,0 +1,5 @@ +--- +title: test +--- + +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown.md b/tests/testthat/_snaps/md_document/yaml-block-markdown.md new file mode 100644 index 0000000000..d95f3ad14d --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown.md @@ -0,0 +1 @@ +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown_github-meta.md b/tests/testthat/_snaps/md_document/yaml-block-markdown_github-meta.md new file mode 100644 index 0000000000..673e544bc7 --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown_github-meta.md @@ -0,0 +1,5 @@ +--- +title: test +--- + +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown_github.md b/tests/testthat/_snaps/md_document/yaml-block-markdown_github.md new file mode 100644 index 0000000000..d95f3ad14d --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown_github.md @@ -0,0 +1 @@ +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown_mmd-meta.md b/tests/testthat/_snaps/md_document/yaml-block-markdown_mmd-meta.md new file mode 100644 index 0000000000..673e544bc7 --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown_mmd-meta.md @@ -0,0 +1,5 @@ +--- +title: test +--- + +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown_mmd.md b/tests/testthat/_snaps/md_document/yaml-block-markdown_mmd.md new file mode 100644 index 0000000000..d95f3ad14d --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown_mmd.md @@ -0,0 +1 @@ +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown_phpextra-meta.md b/tests/testthat/_snaps/md_document/yaml-block-markdown_phpextra-meta.md new file mode 100644 index 0000000000..673e544bc7 --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown_phpextra-meta.md @@ -0,0 +1,5 @@ +--- +title: test +--- + +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown_phpextra.md b/tests/testthat/_snaps/md_document/yaml-block-markdown_phpextra.md new file mode 100644 index 0000000000..d95f3ad14d --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown_phpextra.md @@ -0,0 +1 @@ +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown_strict-meta.md b/tests/testthat/_snaps/md_document/yaml-block-markdown_strict-meta.md new file mode 100644 index 0000000000..673e544bc7 --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown_strict-meta.md @@ -0,0 +1,5 @@ +--- +title: test +--- + +content diff --git a/tests/testthat/_snaps/md_document/yaml-block-markdown_strict.md b/tests/testthat/_snaps/md_document/yaml-block-markdown_strict.md new file mode 100644 index 0000000000..d95f3ad14d --- /dev/null +++ b/tests/testthat/_snaps/md_document/yaml-block-markdown_strict.md @@ -0,0 +1 @@ +content diff --git a/tests/testthat/test-md_document.R b/tests/testthat/test-md_document.R new file mode 100644 index 0000000000..19818d26c5 --- /dev/null +++ b/tests/testthat/test-md_document.R @@ -0,0 +1,75 @@ +local_edition(3) + +test_that("adapt_md_variant() adds extensions to markdown variants", { + expect_identical(adapt_md_variant("markdown", TRUE), "markdown+yaml_metadata_block") + expect_identical(adapt_md_variant("markdown_phpextra", TRUE), "markdown_phpextra+yaml_metadata_block") + expect_identical(adapt_md_variant("markdown_mmd", TRUE), "markdown_mmd+yaml_metadata_block") + expect_identical(adapt_md_variant("markdown_strict", TRUE), "markdown_strict+yaml_metadata_block") + expect_identical(adapt_md_variant("markdown_github", TRUE), "markdown_github+yaml_metadata_block") + + expect_identical(adapt_md_variant("markdown", FALSE), "markdown-yaml_metadata_block") + expect_identical(adapt_md_variant("markdown_phpextra", FALSE), "markdown_phpextra-yaml_metadata_block") + expect_identical(adapt_md_variant("markdown_mmd", FALSE), "markdown_mmd-yaml_metadata_block") + expect_identical(adapt_md_variant("markdown_strict", FALSE), "markdown_strict-yaml_metadata_block") + expect_identical(adapt_md_variant("markdown_github", FALSE), "markdown_github-yaml_metadata_block") + + expect_identical(adapt_md_variant("markdown+yaml_metadata_block", TRUE), "markdown+yaml_metadata_block") + expect_identical(adapt_md_variant("markdown-yaml_metadata_block", TRUE), "markdown-yaml_metadata_block+yaml_metadata_block") + expect_identical(adapt_md_variant("markdown+yaml_metadata_block", FALSE), "markdown+yaml_metadata_block-yaml_metadata_block") + expect_identical(adapt_md_variant("markdown-yaml_metadata_block", FALSE), "markdown-yaml_metadata_block") + + # ignore correctly unsupported variants + expect_identical(adapt_md_variant("markdown_new", TRUE), "markdown_new") + expect_identical(adapt_md_variant("markdown_new", FALSE), "markdown_new") +}) + +test_that("adapt_md_variant() ignored unknown variants", { + expect_identical(adapt_md_variant("markdown_new", TRUE), "markdown_new") + expect_identical(adapt_md_variant("markdown_new", FALSE), "markdown_new") +}) + +test_that("adapt_md_variant() with special variants (pandoc >= 2.13)", { + skip_if_not_pandoc('2.13') + expect_identical(adapt_md_variant("commonmark", TRUE), "commonmark+yaml_metadata_block") + expect_identical(adapt_md_variant("gfm", TRUE), "gfm+yaml_metadata_block") + expect_identical(adapt_md_variant("commonmark_x", TRUE), "commonmark_x+yaml_metadata_block") + expect_identical(adapt_md_variant("commonmark", FALSE), "commonmark-yaml_metadata_block") + expect_identical(adapt_md_variant("gfm", FALSE), "gfm-yaml_metadata_block") + expect_identical(adapt_md_variant("commonmark_x", FALSE), "commonmark_x-yaml_metadata_block") + + expect_identical(adapt_md_variant("gfm+yaml_metadata_block", TRUE), "gfm+yaml_metadata_block") + expect_identical(adapt_md_variant("gfm-yaml_metadata_block", TRUE), "gfm-yaml_metadata_block+yaml_metadata_block") + expect_identical(adapt_md_variant("gfm+yaml_metadata_block", FALSE), "gfm+yaml_metadata_block-yaml_metadata_block") + expect_identical(adapt_md_variant("gfm-yaml_metadata_block", FALSE), "gfm-yaml_metadata_block") + +}) + +test_that("adapt_md_variant() with special variants (pandoc < 2.13)", { + skip_if_pandoc('2.13') + expect_identical(adapt_md_variant("commonmark", TRUE), "commonmark") + expect_identical(adapt_md_variant("gfm", TRUE), "gfm") + expect_identical(adapt_md_variant("commonmark_x", TRUE), "commonmark_x") + expect_identical(adapt_md_variant("commonmark", FALSE), "commonmark") + expect_identical(adapt_md_variant("gfm", FALSE), "gfm") + expect_identical(adapt_md_variant("commonmark_x", FALSE), "commonmark_x") +}) + +test_that("md_document() can preserve yaml", { + skip_on_cran() # avoid pandoc issue on CRAN + expect_snapshot_md <- function(variant, preserve_yaml) { + rmd <- local_rmd_file(c("---", "title: test", "---", "", "content")) + res <- render(rmd, md_document(variant, preserve_yaml = preserve_yaml), quiet = TRUE) + expect_snapshot_file(res, sprintf("yaml-block-%s%s.md", variant, if (preserve_yaml) "-meta" else "")) + } + expect_snapshot_md("markdown", preserve_yaml = FALSE) + expect_snapshot_md("markdown_phpextra", preserve_yaml = FALSE) + expect_snapshot_md("markdown_mmd", preserve_yaml = FALSE) + expect_snapshot_md("markdown_strict", preserve_yaml = FALSE) + expect_snapshot_md("markdown_github", preserve_yaml = FALSE) + expect_snapshot_md("markdown", preserve_yaml = TRUE) + expect_snapshot_md("markdown_phpextra", preserve_yaml = TRUE) + expect_snapshot_md("markdown_mmd", preserve_yaml = TRUE) + expect_snapshot_md("markdown_strict", preserve_yaml = TRUE) + expect_snapshot_md("markdown_github", preserve_yaml = TRUE) +}) +