diff --git a/DESCRIPTION b/DESCRIPTION index a95255f1b..eb905638e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -44,7 +44,7 @@ Imports: Suggests: covr, diffviewer, - evaluate, + evaluate (>= 0.23.0.9000), gert, gt, htmltools, @@ -71,3 +71,4 @@ Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.1 SystemRequirements: pandoc +Remotes: r-lib/evaluate diff --git a/NEWS.md b/NEWS.md index 1ba1aa126..2f5fe8cc5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,13 @@ # pkgdown (development version) +* `build_news()` only syntax highlights the page once, not twice, which prevents every block of R code getting a blank line at the start (#2630). + + ```R + 1 + 1 + ``` + +* `build_reference()` no longer displays `\dontshow{}` or `\testonly{}` blocks in examples. It will run the code in `\dontshow{}`; it won't run the code in `\testonly{}`(#2188). +* `build_article()` no long has a `data` argument. This is technically a breaking change, but I can't figure out why anyone would have ever used it. * `build_reference()` does a better job of parsing `\value{}` blocks (#2371). * When built on GitHub, source urls now use the name of the current upstream branch (rather than `HEAD`), which is more likely to generate correct links (#2597). * New `vignette("non-english")` that discusses non-English sites including how to submit new translations (#2605). diff --git a/R/build-article.R b/R/build-article.R index 91f78e9a7..d7fc69cdc 100644 --- a/R/build-article.R +++ b/R/build-article.R @@ -3,18 +3,17 @@ #' @rdname build_articles #' @param name Name of article to render. This should be either a path #' relative to `vignettes/` without extension, or `index` or `README`. -#' @param data Additional data to pass on to template. #' @param new_process Build the article in a clean R process? The default, #' `TRUE`, ensures that every article is build in a fresh environment, but #' you may want to set it to `FALSE` to make debugging easier. +#' @param pandoc_args Pass additional arguments to pandoc. Used for testing. build_article <- function(name, pkg = ".", - data = list(), lazy = FALSE, seed = 1014L, new_process = TRUE, + pandoc_args = character(), quiet = TRUE) { - pkg <- as_pkgdown(pkg) # Look up in pkg vignette data - this allows convenient automatic @@ -22,9 +21,7 @@ build_article <- function(name, # allow code sharing with building of the index. vig <- match(name, pkg$vignettes$name) if (is.na(vig)) { - cli::cli_abort( - "Can't find article {.file {name}}" - ) + cli::cli_abort("Can't find article {.file {name}}") } input <- pkg$vignettes$file_in[vig] @@ -38,141 +35,23 @@ build_article <- function(name, return(invisible()) } - local_envvar_pkgdown(pkg) - local_options_link(pkg, depth = depth) - - front <- rmarkdown::yaml_front_matter(input_path) - # Take opengraph from article's yaml front matter - front_opengraph <- check_open_graph(pkg, front$opengraph, input) - data$opengraph <- modify_list(data$opengraph, front_opengraph) - - # Allow users to opt-in to their own template - ext <- purrr::pluck(front, "pkgdown", "extension", .default = "html") - as_is <- isTRUE(purrr::pluck(front, "pkgdown", "as_is")) + cli::cli_inform("Reading {src_path(input)}") + digest <- file_digest(output_path) - default_data <- list( - pagetitle = escape_html(front$title), - toc = front$toc %||% TRUE, - opengraph = list(description = front$description %||% pkg$package), - source = repo_source(pkg, input), - filename = path_file(input), - output_file = output_file, - as_is = as_is - ) - data <- modify_list(default_data, data) - - if (as_is) { - format <- NULL - - if (identical(ext, "html")) { - data$as_is <- TRUE - template <- rmarkdown_template(pkg, "article", depth = depth, data = data) - output <- rmarkdown::default_output_format(input_path) - - # Override defaults & values supplied in metadata - options <- list( - template = template$path, - self_contained = FALSE - ) - if (output$name != "rmarkdown::html_vignette") { - # Force to NULL unless overridden by user - options$theme <- output$options$theme - } + data <- data_article(pkg, input) + if (data$as_is) { + if (identical(data$ext, "html")) { + setup <- rmarkdown_setup_custom(pkg, input_path, depth = depth, data = data) } else { - options <- list() + setup <- list(format = NULL, options = NULL) } } else { - format <- build_rmarkdown_format( - pkg = pkg, - name = "article", - depth = depth, - data = data, - toc = TRUE - ) - options <- NULL - } - - render_rmarkdown( - pkg, - input = input, - output = output_file, - output_format = format, - output_options = options, - seed = seed, - new_process = new_process, - quiet = quiet - ) -} - -build_rmarkdown_format <- function(pkg, - name, - depth = 1L, - data = list(), - toc = TRUE) { - - template <- rmarkdown_template(pkg, name, depth = depth, data = data) - - out <- rmarkdown::html_document( - toc = toc, - toc_depth = 2, - self_contained = FALSE, - theme = NULL, - template = template$path, - anchor_sections = FALSE, - math_method = config_math_rendering(pkg), - extra_dependencies = bs_theme_deps_suppress() - ) - out$knitr$opts_chunk <- fig_opts_chunk(pkg$figures, out$knitr$opts_chunk) - - old_pre <- out$pre_knit - width <- config_pluck_number_whole(pkg, "code.width", default = 80) - - out$pre_knit <- function(...) { - options(width = width) - if (is.function(old_pre)) { - old_pre(...) - } - } - - attr(out, "__cleanup") <- template$cleanup - - out -} - -# Generates pandoc template format by rendering -# inst/template/article-vignette.html -# Output is a path + environment; when the environment is garbage collected -# the path will be deleted -rmarkdown_template <- function(pkg, name, data, depth) { - path <- tempfile(fileext = ".html") - render_page(pkg, name, data, path, depth = depth, quiet = TRUE) - - # Remove template file when format object is GC'd - e <- env() - reg.finalizer(e, function(e) file_delete(path)) - - list(path = path, cleanup = e) -} - -render_rmarkdown <- function(pkg, - input, - output, - ..., - seed = NULL, - copy_images = TRUE, - new_process = TRUE, - quiet = TRUE, - call = caller_env()) { - - input_path <- path_abs(input, pkg$src_path) - output_path <- path_abs(output, pkg$dst_path) - - if (!file_exists(input_path)) { - cli::cli_abort("Can't find {src_path(input)}.", call = call) + setup <- rmarkdown_setup_pkgdown(pkg, depth = depth, data = data, pandoc_args = pandoc_args) } - cli::cli_inform("Reading {src_path(input)}") - digest <- file_digest(output_path) + local_envvar_pkgdown(pkg) + local_texi2dvi_envvars(input_path) + withr::local_envvar(R_CLI_NUM_COLORS = 256) args <- list( input = input_path, @@ -181,34 +60,14 @@ render_rmarkdown <- function(pkg, intermediates_dir = tempdir(), encoding = "UTF-8", seed = seed, - ..., + output_format = setup$format, + output_options = setup$options, quiet = quiet ) - - withr::local_envvar( - callr::rcmd_safe_env(), - BSTINPUTS = bst_paths(input_path), - TEXINPUTS = tex_paths(input_path), - BIBINPUTS = bib_paths(input_path), - R_CLI_NUM_COLORS = 256 - ) - if (new_process) { path <- withCallingHandlers( callr::r_safe(rmarkdown_render_with_seed, args = args, show = !quiet), - error = function(cnd) { - lines <- strsplit(gsub("^\r?\n", "", cnd$stderr), "\r?\n")[[1]] - lines <- escape_cli(lines) - cli::cli_abort( - c( - "!" = "Failed to render {.path {input}}.", - set_names(lines, "x") - ), - parent = cnd$parent %||% cnd, - trace = cnd$parent$trace, - call = call - ) - } + error = function(cnd) wrap_rmarkdown_error(cnd, input) ) } else { path <- inject(rmarkdown_render_with_seed(!!!args)) @@ -216,6 +75,7 @@ render_rmarkdown <- function(pkg, is_html <- identical(path_ext(path)[[1]], "html") if (is_html) { + local_options_link(pkg, depth = depth) update_html( path, tweak_rmarkdown_html, @@ -224,51 +84,139 @@ render_rmarkdown <- function(pkg, ) } if (digest != file_digest(output_path)) { - writing_file(path_rel(output_path, pkg$dst_path), output) + writing_file(path_rel(output_path, pkg$dst_path), output_file) } + if (is_html) { + copy_article_images(path, input_path, output_path) + check_missing_images(pkg, input_path, output_file) + } + + invisible(path) + +} + +data_article <- function(pkg, input, call = caller_env()) { + yaml <- rmarkdown::yaml_front_matter(path_abs(input, pkg$src_path)) + + opengraph <- check_open_graph(pkg, yaml$opengraph, input, call = call) + opengraph$description <- opengraph$description %||% yaml$description + + list( + opengraph = opengraph, + pagetitle = escape_html(yaml$title), + toc = yaml$toc %||% TRUE, + source = repo_source(pkg, input), + filename = path_file(input), + as_is = isTRUE(purrr::pluck(yaml, "pkgdown", "as_is")), + ext = purrr::pluck(yaml, "pkgdown", "extension", .default = "html") + ) +} + +rmarkdown_setup_custom <- function(pkg, + input_path, + depth = 1L, + data = list(), + env = caller_env()) { + template <- rmarkdown_template(pkg, depth = depth, data = data, env = env) - # Copy over images needed by the document - if (copy_images && is_html) { - ext_src <- rmarkdown::find_external_resources(input_path) - - # temporarily copy the rendered html into the input path directory and scan - # again for additional external resources that may be been included by R code - tempfile <- path(path_dir(input_path), "--find-assets.html") - withr::defer(try(file_delete(tempfile))) - file_copy(path, tempfile) - ext_post <- rmarkdown::find_external_resources(tempfile) - - ext <- rbind(ext_src, ext_post) - ext <- ext[!duplicated(ext$path), ] - - # copy web + explicit files beneath vignettes/ - is_child <- path_has_parent(ext$path, ".") - ext_path <- ext$path[(ext$web | ext$explicit) & is_child] - - src <- path(path_dir(input_path), ext_path) - dst <- path(path_dir(output_path), ext_path) - # Make sure destination paths exist before copying files there - dir_create(unique(path_dir(dst))) - file_copy(src, dst, overwrite = TRUE) + # Override defaults & values supplied in metadata + options <- list( + template = template, + self_contained = FALSE + ) + + output <- rmarkdown::default_output_format(input_path) + if (output$name != "rmarkdown::html_vignette") { + # Force to NULL unless overridden by user + options$theme <- output$options$theme } - if (is_html) { - check_missing_images(pkg, input_path, output) + list(format = NULL, options = options) +} + +rmarkdown_setup_pkgdown <- function(pkg, + depth = 1L, + data = list(), + pandoc_args = character(), + env = caller_env()) { + + template <- rmarkdown_template(pkg, depth = depth, data = data, env = env) + + format <- rmarkdown::html_document( + self_contained = FALSE, + theme = NULL, + template = template, + anchor_sections = FALSE, + math_method = config_math_rendering(pkg), + extra_dependencies = bs_theme_deps_suppress(), + pandoc_args = pandoc_args + ) + format$knitr$opts_chunk <- fig_opts_chunk(pkg$figures, format$knitr$opts_chunk) + + width <- config_pluck_number_whole(pkg, "code.width", default = 80) + old_pre <- format$pre_knit + format$pre_knit <- function(...) { + options(width = width) + if (is.function(old_pre)) { + old_pre(...) + } } - invisible(path) + list(format = format, options = NULL) } -#' Escapes a cli msg -#' -#' Removes empty lines and escapes braces -#' @param msg A character vector with messages to be escaped -#' @noRd -escape_cli <- function(msg) { - msg <- msg[nchar(msg) >0] - msg <- gsub("{", "{{", msg, fixed = TRUE) - msg <- gsub("}", "}}", msg, fixed = TRUE) - msg +# Generates pandoc template by rendering templates/content-article.html +rmarkdown_template <- function(pkg, data = list(), depth = 1L, env = caller_env()) { + path <- withr::local_tempfile( + pattern = "pkgdown-rmd-template-", + fileext = ".html", + .local_envir = env + ) + render_page(pkg, "article", data, path, depth = depth, quiet = TRUE) + + path +} + +copy_article_images <- function(built_path, input_path, output_path) { + ext_src <- rmarkdown::find_external_resources(input_path) + + # temporarily copy the rendered html into the input path directory and scan + # again for additional external resources that may be been included by R code + tempfile <- path(path_dir(input_path), "--find-assets.html") + withr::defer(try(file_delete(tempfile))) + file_copy(built_path, tempfile) + ext_post <- rmarkdown::find_external_resources(tempfile) + + ext <- rbind(ext_src, ext_post) + ext <- ext[!duplicated(ext$path), ] + + # copy web + explicit files beneath vignettes/ + is_child <- path_has_parent(ext$path, ".") + ext_path <- ext$path[(ext$web | ext$explicit) & is_child] + + src <- path(path_dir(input_path), ext_path) + dst <- path(path_dir(output_path), ext_path) + # Make sure destination paths exist before copying files there + dir_create(unique(path_dir(dst))) + file_copy(src, dst, overwrite = TRUE) +} + +wrap_rmarkdown_error <- function(cnd, input, call = caller_env()) { + lines <- strsplit(gsub("^\r?\n", "", cnd$stderr), "\r?\n")[[1]] + lines <- lines[nchar(lines) > 0] + # Feeding random text back into cli, so have to escape + lines <- gsub("{", "{{", lines, fixed = TRUE) + lines <- gsub("}", "}}", lines, fixed = TRUE) + + cli::cli_abort( + c( + "!" = "Failed to render {.path {input}}.", + set_names(lines, "x") + ), + parent = cnd$parent %||% cnd, + trace = cnd$parent$trace, + call = call + ) } rmarkdown_render_with_seed <- function(..., seed = NULL) { @@ -285,28 +233,3 @@ rmarkdown_render_with_seed <- function(..., seed = NULL) { rmarkdown::render(envir = globalenv(), ...) } - -# adapted from tools::texi2dvi -bst_paths <- function(path) { - paths <- c( - Sys.getenv("BSTINPUTS"), - path_dir(path), - path(R.home("share"), "texmf", "bibtex", "bst") - ) - paste(paths, collapse = .Platform$path.sep) -} -tex_paths <- function(path) { - paths <- c( - Sys.getenv("TEXINPUTS"), - path_dir(path), - path(R.home("share"), "texmf", "tex", "latex") - ) - paste(paths, collapse = .Platform$path.sep) -} -bib_paths <- function(path) { - paths <- c( - Sys.getenv("BIBINPUTS"), - tex_paths(path) - ) - paste(paths, collapse = .Platform$path.sep) -} diff --git a/R/build-articles.R b/R/build-articles.R index c3f54108e..38411d683 100644 --- a/R/build-articles.R +++ b/R/build-articles.R @@ -173,13 +173,14 @@ #' Additionally, htmlwidgets do not work when `as_is: true`. #' #' # Suppressing vignettes -#' If you want articles that are not vignettes, either put them in -#' subdirectories or list in `.Rbuildignore`. An articles link will be +#' If you want [articles](https://r-pkgs.org/vignettes.html#sec-vignettes-article) +#' that are not vignettes, use `usethis::use_article()` to create it. An articles link will be #' automatically added to the default navbar if the vignettes directory is #' present: if you do not want this, you will need to customise the navbar. See #' [build_site()] details. #' #' @inheritSection build_reference Figures +#' @family site components #' #' @inheritParams as_pkgdown #' @param quiet Set to `FALSE` to display output of knitr and diff --git a/R/build-favicons.R b/R/build-favicons.R index 252f7fa61..1953ed811 100644 --- a/R/build-favicons.R +++ b/R/build-favicons.R @@ -1,16 +1,17 @@ -#' Create favicons from package logo +#' Initialise favicons from package logo #' +#' @description #' This function auto-detects the location of your package logo (with the name -#' `logo.svg` (recommended format) or `logo.png`) and runs it through the -#' API to build a complete set of favicons -#' with different sizes, as needed for modern web usage. +#' `logo.svg` (recommended format) or `logo.png`, created with `usethis::use_logo()`) +#' and runs it through the API to build a +#' complete set of favicons with different sizes, as needed for modern web usage. #' #' You only need to run the function once. The favicon set will be stored in #' `pkgdown/favicon` and copied by [init_site()] to the relevant location when #' the website is rebuilt. #' #' Once complete, you should add `pkgdown/` to `.Rbuildignore ` to avoid a NOTE -#' during package checking. +#' during package checking. (`usethis::use_logo()` does this for you!) #' #' @inheritParams as_pkgdown #' @param overwrite If `TRUE`, re-create favicons from package logo. diff --git a/R/build-home.R b/R/build-home.R index 9c205b00b..142378b33 100644 --- a/R/build-home.R +++ b/R/build-home.R @@ -283,7 +283,9 @@ #' sidebar: FALSE #' ``` #' @inheritParams build_articles +#' @family site components #' @export +#' @order 1 build_home <- function(pkg = ".", override = list(), preview = NA, diff --git a/R/build-news.R b/R/build-news.R index 14b7e4cae..9868637d7 100644 --- a/R/build-news.R +++ b/R/build-news.R @@ -66,6 +66,7 @@ #' news: #' cran_dates: false #' ``` +#' @family site components #' #' @seealso [Tidyverse style for News](https://style.tidyverse.org/news.html) #' @@ -76,7 +77,7 @@ build_news <- function(pkg = ".", preview = NA) { pkg <- section_init(pkg, depth = 1L, override = override) if (!has_news(pkg$src_path)) - return() + return(invisible()) cli::cli_rule("Building news") create_subdir(pkg, "news") @@ -144,12 +145,9 @@ build_news_multi <- function(pkg = ".") { ) } -utils::globalVariables(".") - -data_news <- function(pkg = list(), call = caller_env() ) { +data_news <- function(pkg, call = caller_env() ) { html <- markdown_body(pkg, path(pkg$src_path, "NEWS.md")) xml <- xml2::read_html(html) - downlit::downlit_html_node(xml) sections <- xml2::xml_find_all(xml, "./body/div") footnotes <- has_class(sections, "footnotes") diff --git a/R/build-reference.R b/R/build-reference.R index 87c425151..16ad706af 100644 --- a/R/build-reference.R +++ b/R/build-reference.R @@ -83,7 +83,7 @@ #' * `has_lifecycle("deprecated")` will select all topics with lifecycle #' deprecated. #' -#' All functions (except for `has_keywords()`) automatically exclude internal +#' All functions (except for `has_keyword()`) automatically exclude internal #' topics (i.e. those with `\keyword{internal}`). You can choose to include #' with (e.g.) `starts_with("build_", internal = TRUE)`. #' @@ -136,6 +136,7 @@ #' as HTML widgets. #' #' @inheritParams build_articles +#' @family site components #' @param lazy If `TRUE`, only rebuild pages where the `.Rd` #' is more recent than the `.html`. This makes it much easier to #' rapidly prototype. It is set to `FALSE` by [build_site()]. diff --git a/R/build-tutorials.R b/R/build-tutorials.R index 69ed969d9..1060a3e87 100644 --- a/R/build-tutorials.R +++ b/R/build-tutorials.R @@ -26,6 +26,7 @@ #' url: https://jjallaire.shinyapps.io/learnr-tutorial-01-data-basics/ #' ``` #' @inheritParams build_articles +#' @family site components #' @export build_tutorials <- function(pkg = ".", override = list(), preview = NA) { pkg <- section_init(pkg, depth = 1L, override = override) diff --git a/R/build.R b/R/build.R index 069ab58f1..24e17cb87 100644 --- a/R/build.R +++ b/R/build.R @@ -28,7 +28,7 @@ #' It specifies where the site will be published and is used to allow other #' pkgdown sites to link to your site when needed (`vignette("linking")`), #' generate a `sitemap.xml`, automatically generate a `CNAME` when -#' [deploying to github][deploy_site_github], generate the metadata needed +#' [deploying to github][build_site_github_pages()], generate the metadata needed #' rich social "media cards" (`vignette("metadata")`), and more. #' #' * `title` overrides the default site title, which is the package name. diff --git a/R/highlight.R b/R/highlight.R index 05a4e0a8e..19ce4f061 100644 --- a/R/highlight.R +++ b/R/highlight.R @@ -28,11 +28,23 @@ highlight_examples <- function(code, topic, env = globalenv()) { do.call(fig_save, c(list(plot, name), fig_settings())) } + hide_dontshow <- function(src, call) { + if (is_call(call, c("DONTSHOW", "TESTONLY"))) NULL else src + } + handler <- evaluate::new_output_handler( + value = pkgdown_print, + source = hide_dontshow + ) + + eval_env <- child_env(env) + eval_env$DONTSHOW <- function(x) invisible(x) + eval_env$TESTONLY <- function(x) invisible() + out <- downlit::evaluate_and_highlight( code, fig_save = fig_save_topic, - env = child_env(env), - output_handler = evaluate::new_output_handler(value = pkgdown_print) + env = eval_env, + output_handler = handler ) structure( sourceCode(pre(out, r_code = TRUE)), diff --git a/R/init.R b/R/init.R index fa0e2d50c..90ddc21d3 100644 --- a/R/init.R +++ b/R/init.R @@ -12,7 +12,7 @@ #' display of your site. #' #' # Build-ignored files -#' We recommend using [usethis::use_pkgdown()] to build-ignore `docs/` and +#' We recommend using [usethis::use_pkgdown_github_pages()] to build-ignore `docs/` and #' `_pkgdown.yml`. If use another directory, or create the site manually, #' you'll need to add them to `.Rbuildignore` yourself. A `NOTE` about #' an unexpected file during `R CMD CHECK` is an indication you have not diff --git a/R/package.R b/R/package.R index 9dba5dc0d..e5c3692bb 100644 --- a/R/package.R +++ b/R/package.R @@ -19,7 +19,7 @@ as_pkgdown <- function(pkg = ".", override = list()) { check_string(pkg) if (!dir_exists(pkg)) { - cli::cli_abort("{.file {src_path}} is not an existing directory") + cli::cli_abort("{.file {pkg}} is not an existing directory") } src_path <- pkg diff --git a/R/rd-example.R b/R/rd-example.R index 8738150d5..134796633 100644 --- a/R/rd-example.R +++ b/R/rd-example.R @@ -129,9 +129,9 @@ as_example.tag_dontrun <- function(x, run_dont_run = FALSE) { } else { ex <- flatten_ex(x, run_dont_run = run_dont_run) if (is_newline(x[[1]], trim = TRUE)) { - paste0("if (FALSE) {", ex, "}") + paste0("if (FALSE) { # \\dontrun{", ex, "} # }") } else { - paste0("if (FALSE) ", ex, "") + paste0("if (FALSE) ", ex, " # \\dontrun{}") } } } @@ -142,19 +142,24 @@ as_example.tag_donttest <- function(x, run_dont_run = FALSE) { } #' @export as_example.tag_dontshow <- function(x, run_dont_run = FALSE) { - block_tag_to_comment("\\dontshow", x, run_dont_run = run_dont_run) + ex <- flatten_ex(x, run_dont_run = run_dont_run) + paste0("DONTSHOW({", ex, "})") } #' @export as_example.tag_testonly <- function(x, run_dont_run = FALSE) { - block_tag_to_comment("\\testonly", x, run_dont_run = run_dont_run) + ex <- flatten_ex(x, run_dont_run = run_dont_run) + paste0("TESTONLY({", ex, "})") } block_tag_to_comment <- function(tag, x, run_dont_run = FALSE) { + ex <- flatten_ex(x, run_dont_run = run_dont_run) + + # Not easy to strip leading whitespace because it's attached to the previous + # tag. So instead we add a comment to occupy that space if (is_newline(x[[1]], trim = TRUE)) { - paste0("# ", tag, "{", flatten_ex(x, run_dont_run = run_dont_run), "# }") - } else { - flatten_ex(x, run_dont_run = run_dont_run) + ex <- paste0("# ", tag, "{", ex, "# }") } + ex } #' @export diff --git a/R/test.R b/R/test.R index 780588b16..b3e01d286 100644 --- a/R/test.R +++ b/R/test.R @@ -97,44 +97,61 @@ NULL #' @keywords internal #' @family tests #' @examples +#' # \dontrun{} -------------------------------------------------------- +#' # always shown; never run +#' +#' x <- 1 +#' \dontrun{x <- 2} #' \dontrun{ -#' abort("This is an error!") +#' x <- 3 +#' x <- 4 #' } +#' x # should be 1 #' -#' # Inline \donttest is silently ommitted -#' \donttest{message("Hi!")} +#' # \donttest{} ------------------------------------------------------- +#' # only multiline are shown; always run #' -#' # Block \donttest indicated with comments +#' x <- 1 +#' \donttest{x <- 2} #' \donttest{ -#' # This is a comment -#' 1 + 3 +#' x <- 3 +#' x <- 4 #' } +#' x # should be 4 #' -#' # And works even when not at the top level -#' if (TRUE) { -#' \donttest{ -#' 1 + 2 -#' } +#' # \testonly{} ----------------------------------------------------- +#' # never shown, never run +#' +#' x <- 1 +#' \testonly{x <- 2} +#' \testonly{ +#' x <- 3 +#' x <- 4 #' } +#' x # should be 1 +#' +#' # \dontshow{} ------------------------------------------------------- +#' # never shown, always run #' -#' answer <- 1 +#' x <- 1 +#' \dontshow{x <- 2} #' \dontshow{ -#' answer <- 42 +#' x <- 3 +#' x <- 4 #' } -#' answer # should be 42 -#' -#' # To hide the \dontshow part, for conditional examples -#' \dontshow{if (FALSE) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} -#' answer <- 43 -#' \dontshow{\}) # examplesIf} -#' answer # should be still 42 -#' -#' # But this one runs, and the condition is hidden -#' \dontshow{if (TRUE) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} -#' answer <- 43 -#' \dontshow{\}) # examplesIf} -#' answer - +#' x # should be 4 +#' +#' # @examplesIf ------------------------------------------------------ +#' # If FALSE, wrapped in if; if TRUE, not seen +#' +#' x <- 1 +#' +#' @examplesIf FALSE +#' x <- 2 +#' @examplesIf TRUE +#' x <- 3 +#' @examples +#' x # should be 3 NULL #' Test case: params diff --git a/R/usage.R b/R/usage.R index ace7e12db..1c4631fa0 100644 --- a/R/usage.R +++ b/R/usage.R @@ -11,14 +11,18 @@ as_data.tag_usage <- function(x, ...) { text <- paste(flatten_text(x, ..., escape = FALSE), collapse = "\n") text <- str_trim(text) - # Look for single line calls to non-syntactic functions and then use + # Look for single line calls to non-syntactic functions (except for `=` + # since that's probably a single argument on its own line) and then use # deparse1 to convert to standard style. We want to avoid reparsing # any other lines to avoid losing whitespace, comments etc. (These # are not generated by roxygen but can be added by the user.) lines <- strsplit(text, "\n", fixed = TRUE)[[1]] parsed <- lapply(lines, function(x) tryCatch(parse(text = x)[[1]], error = function(e) NULL)) - needs_tweak <- vapply(parsed, function(x) is_call(x) && !is_syntactic(x[[1]]), logical(1)) - lines[needs_tweak] <- vapply(parsed[needs_tweak], deparse1, character(1)) + needs_tweak <- function(x) { + is_call(x) && !is_call(x, "=") && !is_syntactic(x[[1]]) + } + to_tweak <- vapply(parsed, needs_tweak, logical(1)) + lines[to_tweak] <- vapply(parsed[to_tweak], deparse1, character(1)) text <- paste(lines, collapse = "\n") diff --git a/R/utils-pdf.R b/R/utils-pdf.R new file mode 100644 index 000000000..6150e53ab --- /dev/null +++ b/R/utils-pdf.R @@ -0,0 +1,34 @@ +# Set various env vars (copied from tools::texi2dvi) to ensure that +# latex can find bib and style files in the right places +local_texi2dvi_envvars <- function(input_path, env = caller_env()) { + withr::local_envvar( + BSTINPUTS = bst_paths(input_path), + TEXINPUTS = tex_paths(input_path), + BIBINPUTS = bib_paths(input_path), + .local_envir = env + ) +} + +bst_paths <- function(path) { + paths <- c( + Sys.getenv("BSTINPUTS"), + path_dir(path), + path(R.home("share"), "texmf", "bibtex", "bst") + ) + paste(paths, collapse = .Platform$path.sep) +} +tex_paths <- function(path) { + paths <- c( + Sys.getenv("TEXINPUTS"), + path_dir(path), + path(R.home("share"), "texmf", "tex", "latex") + ) + paste(paths, collapse = .Platform$path.sep) +} +bib_paths <- function(path) { + paths <- c( + Sys.getenv("BIBINPUTS"), + tex_paths(path) + ) + paste(paths, collapse = .Platform$path.sep) +} diff --git a/README.Rmd b/README.Rmd index b286a25e4..b24dccae9 100644 --- a/README.Rmd +++ b/README.Rmd @@ -44,17 +44,19 @@ pak::pak("r-lib/pkgdown") Get started with [usethis](https://usethis.r-lib.org/): ```{r, eval = FALSE} -# Run once to configure your package to use pkgdown -usethis::use_pkgdown() +# Run once to configure your package to use and deploy pkgdown +usethis::use_pkgdown_github_pages() ``` -Then use pkgdown to build your website: - ```{r, eval = FALSE} +# Preview your site locally before publishing pkgdown::build_site() ``` -This generates a `docs/` directory containing a website. Your `README.md` becomes the homepage, documentation in `man/` generates a function reference, and vignettes will be rendered into `articles/`. Read `vignette("pkgdown")` for more details, and to learn how to deploy your site to GitHub pages. +This adds the necessary components and sets up GitHub Actions[^1] for automatic site building when deploying. +Your `README.md` becomes the homepage, documentation in `man/` generates a function reference, and vignettes will be rendered into `articles/`. + +[^1]: If you don't use GitHub, you can use `usethis::use_pkgdown()` + `pkgdown::build_site()` to create a website. ### pkgdown 2.0.0 and Bootstrap 5 @@ -69,7 +71,7 @@ Then learn about the many new ways to customise your site in `vignette("customis ## In the wild -At last count, pkgdown is used [by over 11,000 packages](https://github.com/search?q=path%3A_pkgdown.yml+language%3AYAML&type=code&l=YAML). Here are a few examples created by contributors to pkgdown: +At last count, pkgdown is used [by over 12,000 packages](https://github.com/search?q=path%3A_pkgdown.yml+language%3AYAML&type=code&l=YAML). Here are a few examples: * [bayesplot](http://mc-stan.org/bayesplot/index.html) ([source](https://github.com/stan-dev/bayesplot/tree/gh-pages)): @@ -88,6 +90,8 @@ At last count, pkgdown is used [by over 11,000 packages](https://github.com/sear ([source](https://github.com/renozao/NMF)): a framework to perform non-negative matrix factorization (NMF). +* [tidyverse and r-lib packages source](https://github.com/search?q=path%3A%22_pkgdown.yml%22+AND+%28org%3Atidyverse+OR+org%3Ar-lib%29&type=code) + Comparing the source and output of these sites is a great way to learn new pkgdown techniques. ## Code of conduct diff --git a/README.md b/README.md index 6eb921abd..0a820511c 100644 --- a/README.md +++ b/README.md @@ -48,21 +48,19 @@ pak::pak("r-lib/pkgdown") Get started with [usethis](https://usethis.r-lib.org/): ``` r -# Run once to configure your package to use pkgdown -usethis::use_pkgdown() +# Run once to configure your package to use and deploy pkgdown +usethis::use_pkgdown_github_pages() ``` -Then use pkgdown to build your website: - ``` r +# Preview your site locally before publishing pkgdown::build_site() ``` -This generates a `docs/` directory containing a website. Your -`README.md` becomes the homepage, documentation in `man/` generates a -function reference, and vignettes will be rendered into `articles/`. -Read `vignette("pkgdown")` for more details, and to learn how to deploy -your site to GitHub pages. +This adds the necessary components and sets up GitHub Actions[^1] for +automatic site building when deploying. Your `README.md` becomes the +homepage, documentation in `man/` generates a function reference, and +vignettes will be rendered into `articles/`. ### pkgdown 2.0.0 and Bootstrap 5 @@ -82,9 +80,9 @@ Then learn about the many new ways to customise your site in ## In the wild -At last count, pkgdown is used [by over 11,000 +At last count, pkgdown is used [by over 12,000 packages](https://github.com/search?q=path%3A_pkgdown.yml+language%3AYAML&type=code&l=YAML). -Here are a few examples created by contributors to pkgdown: +Here are a few examples: - [bayesplot](http://mc-stan.org/bayesplot/index.html) ([source](https://github.com/stan-dev/bayesplot/tree/gh-pages)): @@ -103,6 +101,9 @@ Here are a few examples created by contributors to pkgdown: ([source](https://github.com/renozao/NMF)): a framework to perform non-negative matrix factorization (NMF). +- [tidyverse and r-lib packages + source](https://github.com/search?q=path%3A%22_pkgdown.yml%22+AND+%28org%3Atidyverse+OR+org%3Ar-lib%29&type=code) + Comparing the source and output of these sites is a great way to learn new pkgdown techniques. @@ -111,3 +112,6 @@ new pkgdown techniques. Please note that this project is released with a [Contributor Code of Conduct](https://pkgdown.r-lib.org/CODE_OF_CONDUCT.html). By participating in this project you agree to abide by its terms. + +[^1]: If you don’t use GitHub, you can use `usethis::use_pkgdown()` + + `pkgdown::build_site()` to create a website. diff --git a/man/build_articles.Rd b/man/build_articles.Rd index f50c58a38..3fff2a557 100644 --- a/man/build_articles.Rd +++ b/man/build_articles.Rd @@ -18,10 +18,10 @@ build_articles( build_article( name, pkg = ".", - data = list(), lazy = FALSE, seed = 1014L, new_process = TRUE, + pandoc_args = character(), quiet = TRUE ) @@ -48,11 +48,11 @@ freshly generated section in browser.} \item{name}{Name of article to render. This should be either a path relative to \verb{vignettes/} without extension, or \code{index} or \code{README}.} -\item{data}{Additional data to pass on to template.} - \item{new_process}{Build the article in a clean R process? The default, \code{TRUE}, ensures that every article is build in a fresh environment, but you may want to set it to \code{FALSE} to make debugging easier.} + +\item{pandoc_args}{Pass additional arguments to pandoc. Used for testing.} } \description{ \code{build_articles()} renders each R Markdown file underneath \verb{vignettes/} and @@ -227,8 +227,8 @@ Additionally, htmlwidgets do not work when \code{as_is: true}. } \section{Suppressing vignettes}{ -If you want articles that are not vignettes, either put them in -subdirectories or list in \code{.Rbuildignore}. An articles link will be +If you want \href{https://r-pkgs.org/vignettes.html#sec-vignettes-article}{articles} +that are not vignettes, use \code{usethis::use_article()} to create it. An articles link will be automatically added to the default navbar if the vignettes directory is present: if you do not want this, you will need to customise the navbar. See \code{\link[=build_site]{build_site()}} details. @@ -257,3 +257,11 @@ that will be available to custom graphics output devices such as HTML widgets. } +\seealso{ +Other site components: +\code{\link{build_home}()}, +\code{\link{build_news}()}, +\code{\link{build_reference}()}, +\code{\link{build_tutorials}()} +} +\concept{site components} diff --git a/man/build_favicons.Rd b/man/build_favicons.Rd index 245393ebf..678f60cfd 100644 --- a/man/build_favicons.Rd +++ b/man/build_favicons.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/build-favicons.R \name{build_favicons} \alias{build_favicons} -\title{Create favicons from package logo} +\title{Initialise favicons from package logo} \usage{ build_favicons(pkg = ".", overwrite = FALSE) } @@ -13,15 +13,14 @@ build_favicons(pkg = ".", overwrite = FALSE) } \description{ This function auto-detects the location of your package logo (with the name -\code{logo.svg} (recommended format) or \code{logo.png}) and runs it through the -\url{https://realfavicongenerator.net} API to build a complete set of favicons -with different sizes, as needed for modern web usage. -} -\details{ +\code{logo.svg} (recommended format) or \code{logo.png}, created with \code{usethis::use_logo()}) +and runs it through the \url{https://realfavicongenerator.net} API to build a +complete set of favicons with different sizes, as needed for modern web usage. + You only need to run the function once. The favicon set will be stored in \code{pkgdown/favicon} and copied by \code{\link[=init_site]{init_site()}} to the relevant location when the website is rebuilt. Once complete, you should add \verb{pkgdown/} to \code{.Rbuildignore } to avoid a NOTE -during package checking. +during package checking. (\code{usethis::use_logo()} does this for you!) } diff --git a/man/build_home.Rd b/man/build_home.Rd index a06f06596..224f4b5c6 100644 --- a/man/build_home.Rd +++ b/man/build_home.Rd @@ -1,25 +1,25 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/build-home-index.R, R/build-home.R -\name{build_home_index} -\alias{build_home_index} +% Please edit documentation in R/build-home.R, R/build-home-index.R +\name{build_home} \alias{build_home} +\alias{build_home_index} \title{Build home section} \usage{ -build_home_index(pkg = ".", quiet = TRUE) - build_home(pkg = ".", override = list(), preview = NA, quiet = TRUE) + +build_home_index(pkg = ".", quiet = TRUE) } \arguments{ \item{pkg}{Path to package.} -\item{quiet}{Set to \code{FALSE} to display output of knitr and -pandoc. This is useful when debugging.} - \item{override}{An optional named list used to temporarily override values in \verb{_pkgdown.yml}} \item{preview}{If \code{TRUE}, or \code{is.na(preview) && interactive()}, will preview freshly generated section in browser.} + +\item{quiet}{Set to \code{FALSE} to display output of knitr and +pandoc. This is useful when debugging.} } \description{ \code{build_home()} function generates pages at the top-level of the site @@ -292,3 +292,11 @@ Or completely remove it: }\if{html}{\out{}} } +\seealso{ +Other site components: +\code{\link{build_articles}()}, +\code{\link{build_news}()}, +\code{\link{build_reference}()}, +\code{\link{build_tutorials}()} +} +\concept{site components} diff --git a/man/build_news.Rd b/man/build_news.Rd index 4da4a3196..73f2d24f7 100644 --- a/man/build_news.Rd +++ b/man/build_news.Rd @@ -81,4 +81,11 @@ Suppress the default addition of CRAN release dates with: \seealso{ \href{https://style.tidyverse.org/news.html}{Tidyverse style for News} + +Other site components: +\code{\link{build_articles}()}, +\code{\link{build_home}()}, +\code{\link{build_reference}()}, +\code{\link{build_tutorials}()} } +\concept{site components} diff --git a/man/build_reference.Rd b/man/build_reference.Rd index 064a413fb..93742339b 100644 --- a/man/build_reference.Rd +++ b/man/build_reference.Rd @@ -133,7 +133,7 @@ or \code{sass::font_face} (topic name). deprecated. } -All functions (except for \code{has_keywords()}) automatically exclude internal +All functions (except for \code{has_keyword()}) automatically exclude internal topics (i.e. those with \verb{\\keyword\{internal\}}). You can choose to include with (e.g.) \code{starts_with("build_", internal = TRUE)}. @@ -189,3 +189,11 @@ that will be available to custom graphics output devices such as HTML widgets. } +\seealso{ +Other site components: +\code{\link{build_articles}()}, +\code{\link{build_home}()}, +\code{\link{build_news}()}, +\code{\link{build_tutorials}()} +} +\concept{site components} diff --git a/man/build_site.Rd b/man/build_site.Rd index 894edcf54..6b79760bc 100644 --- a/man/build_site.Rd +++ b/man/build_site.Rd @@ -88,7 +88,7 @@ whole site. It specifies where the site will be published and is used to allow other pkgdown sites to link to your site when needed (\code{vignette("linking")}), generate a \code{sitemap.xml}, automatically generate a \code{CNAME} when -\link[=deploy_site_github]{deploying to github}, generate the metadata needed +\link[=build_site_github_pages]{deploying to github}, generate the metadata needed rich social "media cards" (\code{vignette("metadata")}), and more. \item \code{title} overrides the default site title, which is the package name. It's used in the page title and default navbar. diff --git a/man/build_tutorials.Rd b/man/build_tutorials.Rd index 1d7abe923..cebe6612f 100644 --- a/man/build_tutorials.Rd +++ b/man/build_tutorials.Rd @@ -43,3 +43,11 @@ section. This should be a list where each element specifies: }\if{html}{\out{}} } +\seealso{ +Other site components: +\code{\link{build_articles}()}, +\code{\link{build_home}()}, +\code{\link{build_news}()}, +\code{\link{build_reference}()} +} +\concept{site components} diff --git a/man/init_site.Rd b/man/init_site.Rd index 7d638ddf6..5e0638c91 100644 --- a/man/init_site.Rd +++ b/man/init_site.Rd @@ -22,7 +22,7 @@ See \code{vignette("customise")} for the various ways you can customise the display of your site. } \section{Build-ignored files}{ -We recommend using \code{\link[usethis:use_pkgdown]{usethis::use_pkgdown()}} to build-ignore \verb{docs/} and +We recommend using \code{\link[usethis:use_pkgdown]{usethis::use_pkgdown_github_pages()}} to build-ignore \verb{docs/} and \verb{_pkgdown.yml}. If use another directory, or create the site manually, you'll need to add them to \code{.Rbuildignore} yourself. A \code{NOTE} about an unexpected file during \verb{R CMD CHECK} is an indication you have not diff --git a/man/test-dont.Rd b/man/test-dont.Rd index a8be6493b..e4b923f7f 100644 --- a/man/test-dont.Rd +++ b/man/test-dont.Rd @@ -7,43 +7,62 @@ Test case: don't } \examples{ +# \dontrun{} -------------------------------------------------------- +# always shown; never run + +x <- 1 +\dontrun{x <- 2} \dontrun{ - abort("This is an error!") + x <- 3 + x <- 4 } +x # should be 1 -# Inline \donttest is silently ommitted -\donttest{message("Hi!")} +# \donttest{} ------------------------------------------------------- +# only multiline are shown; always run -# Block \donttest indicated with comments +x <- 1 +\donttest{x <- 2} \donttest{ -# This is a comment -1 + 3 + x <- 3 + x <- 4 } +x # should be 4 + +# \testonly{} ----------------------------------------------------- +# never shown, never run -# And works even when not at the top level -if (TRUE) { - \donttest{ - 1 + 2 - } +x <- 1 +\testonly{x <- 2} +\testonly{ + x <- 3 + x <- 4 } +x # should be 1 + +# \dontshow{} ------------------------------------------------------- +# never shown, always run -answer <- 1 +x <- 1 +\dontshow{x <- 2} \dontshow{ -answer <- 42 + x <- 3 + x <- 4 } -answer # should be 42 +x # should be 4 + +# @examplesIf ------------------------------------------------------ +# If FALSE, wrapped in if; if TRUE, not seen + +x <- 1 -# To hide the \dontshow part, for conditional examples \dontshow{if (FALSE) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} -answer <- 43 +x <- 2 \dontshow{\}) # examplesIf} -answer # should be still 42 - -# But this one runs, and the condition is hidden \dontshow{if (TRUE) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} -answer <- 43 +x <- 3 \dontshow{\}) # examplesIf} -answer +x # should be 3 } \seealso{ Other tests: diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index 0833a5941..f47693756 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -9,9 +9,9 @@ authors: Maëlle Salmon: href: https://masalmon.eu Hadley Wickham: - href: http://hadley.nz + href: https://hadley.nz Posit Software, PBC: - href: https://www.posit.co + href: https://posit.co template: bootstrap: 5 @@ -51,21 +51,21 @@ articles: reference: - title: Build - + - subtitle: Build the complete site contents: - build_site - clean_site - preview_site - pkgdown_sitrep - + - subtitle: Build part of a site desc: These functions are useful for rapid iteration when you're working on a specific part of your site. contents: - - starts_with("build_") - - -build_site - - -build_site_github_pages + - has_concept("site components") + - build_search + - build_redirects - init_site - subtitle: Customisation @@ -85,6 +85,7 @@ reference: - as_pkgdown - in_pkgdown - render_page + - build_favicons - title: Regression tests contents: diff --git a/tests/testthat/_snaps/build-article.md b/tests/testthat/_snaps/build-article.md index aeaf1f03c..802524b72 100644 --- a/tests/testthat/_snaps/build-article.md +++ b/tests/testthat/_snaps/build-article.md @@ -1,41 +1,9 @@ -# warns about missing images - - Code - build_articles(pkg) - Message - -- Building articles ----------------------------------------------------------- - Writing `articles/index.html` - Reading vignettes/kitten.Rmd - Writing `articles/kitten.html` - Missing images in 'vignettes/kitten.Rmd': 'kitten.jpg' - i pkgdown can only use images in 'man/figures' and 'vignettes' - -# warns about missing alt-text - - Code - build_article("missing-images", pkg) - Message - Reading vignettes/missing-images.Rmd - Writing `articles/missing-images.html` - x Missing alt-text in 'vignettes/missing-images.Rmd' - * kitten.jpg - * missing-images_files/figure-html/unnamed-chunk-1-1.png - i Learn more in `vignette(pkgdown::accessibility)`. - -# can build article that uses html_vignette - - Code - expect_error(build_article("html-vignette", pkg), NA) - Message - Reading vignettes/html-vignette.Rmd - Writing `articles/html-vignette.html` - # bad width gives nice error Code - build_rmarkdown_format(pkg, "article") + rmarkdown_setup_pkgdown(pkg) Condition - Error in `build_rmarkdown_format()`: + Error in `rmarkdown_setup_pkgdown()`: ! In _pkgdown.yml, code.width must be a whole number, not the string "abc". # output is reproducible by default, i.e. 'seed' is respected @@ -48,45 +16,57 @@ # reports on bad open graph meta-data Code - build_article(pkg = pkg, name = "bad-opengraph") + build_article("test", pkg) + Message + Reading vignettes/test.Rmd Condition Error in `build_article()`: - ! In vignettes/bad-opengraph.Rmd, opengraph.twitter must be a list, not the number 1. + ! In vignettes/test.Rmd, opengraph.twitter must be a list, not the number 1. -# build_article copies image files in subdirectories +# build_article styles ANSI escapes + + ## X + +# build_article yields useful error if pandoc fails Code - build_article("test", pkg) + build_article("test", pkg, pandoc_args = "--fail-if-warnings") Message Reading vignettes/test.Rmd - Writing `articles/test.html` + Condition + Error in `build_article()`: + ! Failed to render 'vignettes/test.Rmd'. + x [WARNING] This document format requires a nonempty element. + x Defaulting to 'test.knit' as the title. + x To specify a title, use 'title' in metadata or --metadata title="...". + x Failing because there were warnings. + Caused by error: + ! pandoc document conversion failed with error 3 -# render_rmarkdown yields useful error if pandoc fails +# build_article yields useful error if R fails Code - render_rmarkdown(pkg, "assets/pandoc-fail.Rmd", "test.html", output_format = format) + build_article("test", pkg) Message - Reading assets/pandoc-fail.Rmd + Reading vignettes/test.Rmd Condition - Error: - ! Failed to render 'assets/pandoc-fail.Rmd'. - x [WARNING] Could not fetch resource path-to-image.png - x Failing because there were warnings. + Error in `build_article()`: + ! Failed to render 'vignettes/test.Rmd'. + x Quitting from lines 5-9 [unnamed-chunk-1] (test.Rmd) Caused by error: - ! pandoc document conversion failed with error 3 + ! Error! -# render_rmarkdown yields useful error if R fails +--- Code - # Test traceback - summary(expect_error(render_rmarkdown(pkg, "assets/r-fail.Rmd", "test.html"))) + summary(expect_error(build_article("test", pkg))) Message - Reading assets/r-fail.Rmd + Reading vignettes/test.Rmd Output <error/rlang_error> - Error: - ! Failed to render 'assets/r-fail.Rmd'. - x Quitting from lines 6-13 [unnamed-chunk-1] (r-fail.Rmd) + Error in `build_article()`: + ! Failed to render 'vignettes/test.Rmd'. + x Quitting from lines 5-9 [unnamed-chunk-1] (test.Rmd) Caused by error: ! Error! --- @@ -95,25 +75,33 @@ 1. \-global f() 2. \-global g() 3. \-global h() + +# build_article copies image files in subdirectories + Code - # Just test that it works; needed for browser() etc - expect_error(render_rmarkdown(pkg, "assets/r-fail.Rmd", "test.html", - new_process = FALSE)) + build_article("test", pkg) Message - Reading assets/r-fail.Rmd - - Quitting from lines 6-13 [unnamed-chunk-1] (r-fail.Rmd) + Reading vignettes/test.Rmd + Writing `articles/test.html` -# render_rmarkdown styles ANSI escapes +# warns about missing images Code - path <- render_rmarkdown(pkg, input = "assets/vignette-with-crayon.Rmd", - output = "test.html") + build_article("kitten", pkg) Message - Reading assets/vignette-with-crayon.Rmd - Writing `test.html` + Reading vignettes/kitten.Rmd + Writing `articles/kitten.html` + Missing images in 'vignettes/kitten.Rmd': 'kitten.jpg' + i pkgdown can only use images in 'man/figures' and 'vignettes' ---- +# warns about missing alt-text - <span class="co">#> <span style="color: #BB0000;">X</span></span> + Code + build_article("kitten", pkg) + Message + Reading vignettes/kitten.Rmd + Writing `articles/kitten.html` + x Missing alt-text in 'vignettes/kitten.Rmd' + * kitten.jpg + i Learn more in `vignette(pkgdown::accessibility)`. diff --git a/tests/testthat/_snaps/build-search-docs.md b/tests/testthat/_snaps/build-search-docs.md index 02b4825a4..47f6eb542 100644 --- a/tests/testthat/_snaps/build-search-docs.md +++ b/tests/testthat/_snaps/build-search-docs.md @@ -1,3 +1,19 @@ +# build_search_index() has expected structure + + Code + str(build_search_index(pkg)) + Output + List of 1 + $ :List of 8 + ..$ path : chr "https://example.com/index.html" + ..$ id : chr "my-package" + ..$ dir : chr "" + ..$ previous_headings: chr "" + ..$ what : chr "A test package" + ..$ title : chr "A test package" + ..$ text : chr "pakage " + ..$ code : chr "" + # build sitemap only messages when it updates Code diff --git a/tests/testthat/_snaps/build-search-docs/search-no-url.json b/tests/testthat/_snaps/build-search-docs/search-no-url.json deleted file mode 100644 index cca1c20ad..000000000 --- a/tests/testthat/_snaps/build-search-docs/search-no-url.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { - "path": ["/dev/authors.html"], - "id": [null], - "dir": [""], - "previous_headings": [""], - "what": ["Authors"], - "title": ["Authors and Citation"], - "text": ["Hadley Wickham. Author, maintainer. RStudio. Copyright holder, funder."], - "code": [""] - }, - { - "path": ["/dev/authors.html"], - "id": ["citation"], - "dir": [""], - "previous_headings": [""], - "what": ["Citation"], - "title": ["Authors and Citation"], - "text": ["Wickham H (2021). testpackage: test package. R package version 1.0.0."], - "code": ["@Manual{, title = {testpackage: A test package}, author = {Hadley Wickham}, year = {2021}, note = {R package version 1.0.0}, }"] - }, - { - "path": ["/dev/index.html"], - "id": ["testpackage"], - "dir": [""], - "previous_headings": [""], - "what": ["A test package"], - "title": ["A test package"], - "text": ["nice package"], - "code": [""] - }, - { - "path": ["/dev/index.html"], - "id": ["thing"], - "dir": [""], - "previous_headings": [""], - "what": ["Thing"], - "title": ["A test package"], - "text": ["cool!"], - "code": ["plot(1:10)"] - }, - { - "path": ["/dev/index.html"], - "id": ["this-section-is-unnumbered"], - "dir": [""], - "previous_headings": [""], - "what": ["This section is unnumbered"], - "title": ["A test package"], - "text": ["expect bug now."], - "code": [""] - }, - { - "path": ["/dev/news/index.html"], - "id": ["testpackage-1009000"], - "dir": ["Changelog"], - "previous_headings": [""], - "what": ["testpackage 1.0.0.9000"], - "title": ["testpackage 1.0.0.9000"], - "text": ["bullet (#222 @someone)"], - "code": [""] - }, - { - "path": [] - }, - { - "path": ["/dev/news/index.html"], - "id": ["sub-heading-1-0-0"], - "dir": ["Changelog"], - "previous_headings": [""], - "what": ["sub-heading"], - "title": ["testpackage 1.0.0"], - "text": ["first thing (#111 @githubuser) second thing"], - "code": [""] - } -] diff --git a/tests/testthat/_snaps/build-search-docs/search.json b/tests/testthat/_snaps/build-search-docs/search.json deleted file mode 100644 index 9973e6462..000000000 --- a/tests/testthat/_snaps/build-search-docs/search.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { - "path": ["https://example.com/dev/authors.html"], - "id": [null], - "dir": [""], - "previous_headings": [""], - "what": ["Authors"], - "title": ["Authors and Citation"], - "text": ["Hadley Wickham. Author, maintainer. RStudio. Copyright holder, funder."], - "code": [""] - }, - { - "path": ["https://example.com/dev/authors.html"], - "id": ["citation"], - "dir": [""], - "previous_headings": [""], - "what": ["Citation"], - "title": ["Authors and Citation"], - "text": ["Wickham H (2021). testpackage: test package. R package version 1.0.0."], - "code": ["@Manual{, title = {testpackage: A test package}, author = {Hadley Wickham}, year = {2021}, note = {R package version 1.0.0}, }"] - }, - { - "path": ["https://example.com/dev/index.html"], - "id": ["testpackage"], - "dir": [""], - "previous_headings": [""], - "what": ["A test package"], - "title": ["A test package"], - "text": ["nice package"], - "code": [""] - }, - { - "path": ["https://example.com/dev/index.html"], - "id": ["thing"], - "dir": [""], - "previous_headings": [""], - "what": ["Thing"], - "title": ["A test package"], - "text": ["cool!"], - "code": ["plot(1:10)"] - }, - { - "path": ["https://example.com/dev/index.html"], - "id": ["this-section-is-unnumbered"], - "dir": [""], - "previous_headings": [""], - "what": ["This section is unnumbered"], - "title": ["A test package"], - "text": ["expect bug now."], - "code": [""] - }, - { - "path": ["https://example.com/dev/news/index.html"], - "id": ["testpackage-1009000"], - "dir": ["Changelog"], - "previous_headings": [""], - "what": ["testpackage 1.0.0.9000"], - "title": ["testpackage 1.0.0.9000"], - "text": ["bullet (#222 @someone)"], - "code": [""] - }, - { - "path": [] - }, - { - "path": ["https://example.com/dev/news/index.html"], - "id": ["sub-heading-1-0-0"], - "dir": ["Changelog"], - "previous_headings": [""], - "what": ["sub-heading"], - "title": ["testpackage 1.0.0"], - "text": ["first thing (#111 @githubuser) second thing"], - "code": [""] - } -] diff --git a/tests/testthat/_snaps/highlight.md b/tests/testthat/_snaps/highlight.md index f0ea8d306..aab3b0cda 100644 --- a/tests/testthat/_snaps/highlight.md +++ b/tests/testthat/_snaps/highlight.md @@ -1,3 +1,11 @@ +# highlight_examples runs and hides DONTSHOW calls() + + Code + cat(strip_html_tags(out)) + Output + x + #> [1] 1 + # pre() can produce needed range of outputs Code diff --git a/tests/testthat/assets/articles-resources/DESCRIPTION b/tests/testthat/assets/articles-resources/DESCRIPTION deleted file mode 100644 index 56293fe3b..000000000 --- a/tests/testthat/assets/articles-resources/DESCRIPTION +++ /dev/null @@ -1,7 +0,0 @@ -Package: testpackage -Version: 1.0.0 -Title: A test package -Description: A longer statement about the package. -Authors@R: - person("Hadley", "Wickham", , "hadley@rstudio.com", role = c("aut", "cre")) -RoxygenNote: 6.0.1 diff --git a/tests/testthat/assets/articles-resources/vignettes/external.png b/tests/testthat/assets/articles-resources/vignettes/external.png deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/testthat/assets/articles-resources/vignettes/resources.Rmd b/tests/testthat/assets/articles-resources/vignettes/resources.Rmd deleted file mode 100644 index 0e44132bf..000000000 --- a/tests/testthat/assets/articles-resources/vignettes/resources.Rmd +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Hidden External resource" ---- - -There's a hidden external resource in this vignette. - -![external dependency](`r "external.png"`) - diff --git a/tests/testthat/assets/articles/DESCRIPTION b/tests/testthat/assets/articles/DESCRIPTION deleted file mode 100644 index f7d39ece5..000000000 --- a/tests/testthat/assets/articles/DESCRIPTION +++ /dev/null @@ -1,9 +0,0 @@ -Package: testpackage -Version: 1.0.0 -Title: A test package -Description: A longer statement about the package. -Authors@R: c( - person("Hadley", "Wickham", , "hadley@rstudio.com", role = c("aut", "cre")), - person("RStudio", role = c("cph", "fnd")) - ) -RoxygenNote: 6.0.1 diff --git a/tests/testthat/assets/articles/_pkgdown.yml b/tests/testthat/assets/articles/_pkgdown.yml deleted file mode 100644 index ec0a74054..000000000 --- a/tests/testthat/assets/articles/_pkgdown.yml +++ /dev/null @@ -1,2 +0,0 @@ -template: - bootstrap: 5 diff --git a/tests/testthat/assets/articles/vignettes/articles/nested.Rmd b/tests/testthat/assets/articles/vignettes/articles/nested.Rmd deleted file mode 100644 index 7118b3e2b..000000000 --- a/tests/testthat/assets/articles/vignettes/articles/nested.Rmd +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Standard article" ---- - -Source is nested in vignettes/articles, output should be in /articles/ diff --git a/tests/testthat/assets/articles/vignettes/bad-opengraph.Rmd b/tests/testthat/assets/articles/vignettes/bad-opengraph.Rmd deleted file mode 100644 index f6f31e13f..000000000 --- a/tests/testthat/assets/articles/vignettes/bad-opengraph.Rmd +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Introduction to poolnoodlr" -description: "A brief introduction to pool noodles in R." -author: "Mara Averick" -opengraph: - twitter: 1 ---- \ No newline at end of file diff --git a/tests/testthat/assets/articles/vignettes/html-deps.Rmd b/tests/testthat/assets/articles/vignettes/html-deps.Rmd deleted file mode 100644 index 103e85767..000000000 --- a/tests/testthat/assets/articles/vignettes/html-deps.Rmd +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: "HTML Deps" ---- - -```{r} -# Call some code that adds jquery/bootstrap -htmltools::tagList( - htmltools::p("hello"), - rmarkdown::html_dependency_jquery(), - rmarkdown::html_dependency_bootstrap("flatly") -) -``` - - -```{r} -knitr::knit_hooks$set(document = function(x) { - if (interactive()) { - browser() - } - x -}) -``` diff --git a/tests/testthat/assets/articles/vignettes/html-document.Rmd b/tests/testthat/assets/articles/vignettes/html-document.Rmd deleted file mode 100644 index 994fcfed9..000000000 --- a/tests/testthat/assets/articles/vignettes/html-document.Rmd +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "html_document + as_is" -output: - html_document: - number_sections: true -pkgdown: - as_is: true ---- - -```{r include = FALSE} -knitr::opts_chunk$set(collapse = TRUE, comment = "#>") -``` - -This should have section numbers on the headings. - -# Heading 1 - -# Heading 2 diff --git a/tests/testthat/assets/articles/vignettes/html-vignette.Rmd b/tests/testthat/assets/articles/vignettes/html-vignette.Rmd deleted file mode 100644 index 63e0892fc..000000000 --- a/tests/testthat/assets/articles/vignettes/html-vignette.Rmd +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: "html_vignette + as_is" -output: rmarkdown::html_vignette -pkgdown: - as_is: true -vignette: > - %\VignetteIndexEntry{html_vignette + as_is} ---- - -```{r include = FALSE} -knitr::opts_chunk$set(collapse = TRUE, comment = "#>") -``` - -This should not break page css/js (i.e. does the navbar look ok?) - -# Heading 1 - -# Heading 2 - diff --git a/tests/testthat/assets/articles/vignettes/needs-escape.Rmd b/tests/testthat/assets/articles/vignettes/needs-escape.Rmd deleted file mode 100644 index 0e0e710b9..000000000 --- a/tests/testthat/assets/articles/vignettes/needs-escape.Rmd +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "a <-> b" ---- - diff --git a/tests/testthat/assets/articles/vignettes/random.Rmd b/tests/testthat/assets/articles/vignettes/random.Rmd deleted file mode 100644 index a703ecae6..000000000 --- a/tests/testthat/assets/articles/vignettes/random.Rmd +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Random" ---- - -```{r, repro} -runif(5L) -``` diff --git a/tests/testthat/assets/articles/vignettes/standard.Rmd b/tests/testthat/assets/articles/vignettes/standard.Rmd deleted file mode 100644 index 937f954c7..000000000 --- a/tests/testthat/assets/articles/vignettes/standard.Rmd +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: "Standard vignette" ---- - -Nothing out of the ordinary here - -## One section - -Blabla - -## Another one - -Blop diff --git a/tests/testthat/assets/articles/vignettes/toc-false.Rmd b/tests/testthat/assets/articles/vignettes/toc-false.Rmd deleted file mode 100644 index c2fdfb0c9..000000000 --- a/tests/testthat/assets/articles/vignettes/toc-false.Rmd +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "No TOC" -toc: false ---- - -## Introduction - -An otherwise standard vignette, without a TOC. - -## More Content - -Adipiscing conubia leo molestie diam pulvinar turpis pellentesque augue? diff --git a/tests/testthat/assets/articles/vignettes/widget.Rmd b/tests/testthat/assets/articles/vignettes/widget.Rmd deleted file mode 100644 index 36070fed3..000000000 --- a/tests/testthat/assets/articles/vignettes/widget.Rmd +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: "Widgets" ---- - -```{r} -path1 <- tempfile() -writeLines(letters, path1) -path2 <- tempfile() -writeLines(letters[-(10:11)], path2) - -diffviewer::visual_diff(path1, path2) -``` - diff --git a/tests/testthat/assets/articles/vignettes/width.Rmd b/tests/testthat/assets/articles/vignettes/width.Rmd deleted file mode 100644 index 688165814..000000000 --- a/tests/testthat/assets/articles/vignettes/width.Rmd +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Width" ---- - -```{r} -getOption("width") -``` - diff --git a/tests/testthat/assets/news/DESCRIPTION b/tests/testthat/assets/news/DESCRIPTION deleted file mode 100644 index 781c58938..000000000 --- a/tests/testthat/assets/news/DESCRIPTION +++ /dev/null @@ -1,9 +0,0 @@ -Package: testpackage -Version: 1.0.0 -Title: A test package -Description: A test package -Authors@R: c( - person("Hadley", "Wickham", , "hadley@rstudio.com", role = c("aut", "cre")), - person("RStudio", role = c("cph", "fnd")) - ) -Date/Publication: 2021-01-01 diff --git a/tests/testthat/assets/news/NEWS.md b/tests/testthat/assets/news/NEWS.md deleted file mode 100644 index 5dfd56832..000000000 --- a/tests/testthat/assets/news/NEWS.md +++ /dev/null @@ -1,11 +0,0 @@ -# testpackage 1.0.0.9000 - -* bullet (#222 @someone) - -# testpackage 1.0.0 - -## sub-heading - -* first thing (#111 @githubuser) - -* second thing diff --git a/tests/testthat/assets/news/README.md b/tests/testthat/assets/news/README.md deleted file mode 100644 index 15b165039..000000000 --- a/tests/testthat/assets/news/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# testpackage - -Very nice package - -## Thing - -Very cool! - -```r -plot(1:10) -``` -## This section is unnumbered {-} - -But I do not expect a bug now. diff --git a/tests/testthat/assets/news/_pkgdown.yml b/tests/testthat/assets/news/_pkgdown.yml deleted file mode 100644 index ec0a74054..000000000 --- a/tests/testthat/assets/news/_pkgdown.yml +++ /dev/null @@ -1,2 +0,0 @@ -template: - bootstrap: 5 diff --git a/tests/testthat/assets/pandoc-fail.Rmd b/tests/testthat/assets/pandoc-fail.Rmd deleted file mode 100644 index 5b36457ca..000000000 --- a/tests/testthat/assets/pandoc-fail.Rmd +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "pandoc-fail" ---- - -![](path-to-image.png) diff --git a/tests/testthat/assets/r-fail.Rmd b/tests/testthat/assets/r-fail.Rmd deleted file mode 100644 index 101dc46a0..000000000 --- a/tests/testthat/assets/r-fail.Rmd +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: "r-fail" ---- - -```{r} -f <- function() g() -g <- function() h() -h <- function() { - rlang::abort("Error!") -} - -f() -``` \ No newline at end of file diff --git a/tests/testthat/assets/search-site/DESCRIPTION b/tests/testthat/assets/search-site/DESCRIPTION deleted file mode 100644 index 463a331d8..000000000 --- a/tests/testthat/assets/search-site/DESCRIPTION +++ /dev/null @@ -1,8 +0,0 @@ -Package: testpackage -Version: 1.0.0 -Title: A test package -Description: A test package -Authors@R: c( - person("Hadley", "Wickham", , "hadley@rstudio.com", role = c("aut", "cre")), - person("RStudio", role = c("cph", "fnd")) - ) diff --git a/tests/testthat/assets/search-site/_pkgdown.yml b/tests/testthat/assets/search-site/_pkgdown.yml deleted file mode 100644 index 0e5142a94..000000000 --- a/tests/testthat/assets/search-site/_pkgdown.yml +++ /dev/null @@ -1,9 +0,0 @@ -url: http://pkgdown.r-lib.org - -template: - bootstrap: 3 - params: - docsearch: - api_key: test-api-key - index_name: test-index-name - diff --git a/tests/testthat/assets/site-citation-UTF-8/DESCRIPTION b/tests/testthat/assets/site-citation-UTF-8/DESCRIPTION deleted file mode 100644 index cccfc4355..000000000 --- a/tests/testthat/assets/site-citation-UTF-8/DESCRIPTION +++ /dev/null @@ -1,9 +0,0 @@ -Package: testpackage -Type: Package -Title: Test package -Version: 0.2.5 -Date: 2018-02-02 -Authors@R: person("Florian", "Privé") -Description: Test non-ASCII characters in Authors@R -Encoding: UTF-8 -URL: http://github.com/test diff --git a/tests/testthat/assets/site-citation-UTF-8/inst/temp-citation b/tests/testthat/assets/site-citation-UTF-8/inst/temp-citation deleted file mode 100644 index 7d0c54f09..000000000 --- a/tests/testthat/assets/site-citation-UTF-8/inst/temp-citation +++ /dev/null @@ -1,10 +0,0 @@ -citEntry(entry = "Article", - title="test non-ASCII character in authors *and* citation(auto = meta)", - author="Florian Privé", - journal="test", - year="2017", - publisher="test", - textVersion="test" -) - -citation(auto = meta) diff --git a/tests/testthat/assets/site-citation-latin1/DESCRIPTION b/tests/testthat/assets/site-citation-latin1/DESCRIPTION deleted file mode 100644 index cc2e1e2eb..000000000 --- a/tests/testthat/assets/site-citation-latin1/DESCRIPTION +++ /dev/null @@ -1,8 +0,0 @@ -Package: testpackage -Type: Package -Title: Test package -Version: 0.2.5 -Date: 2018-02-02 -Authors@R: person("Florian", "Privé", role = c("aut", "cre")) -Description: Test non-ASCII characters in Authors@R -Encoding: latin1 diff --git a/tests/testthat/assets/site-citation-latin1/inst/temp-citation b/tests/testthat/assets/site-citation-latin1/inst/temp-citation deleted file mode 100644 index 985c82321..000000000 --- a/tests/testthat/assets/site-citation-latin1/inst/temp-citation +++ /dev/null @@ -1,10 +0,0 @@ -citEntry(entry = "Article", - title="test non-ASCII character in authors *and* citation(auto = meta)", - author="Florian Privé", - journal="test", - year="2017", - publisher="test", - textVersion="test" -) - -citation(auto = meta) diff --git a/tests/testthat/assets/site-citation-multi/DESCRIPTION b/tests/testthat/assets/site-citation-multi/DESCRIPTION deleted file mode 100644 index 58c608624..000000000 --- a/tests/testthat/assets/site-citation-multi/DESCRIPTION +++ /dev/null @@ -1,6 +0,0 @@ -Package: testpackage -Title: A test package -Version: 1.0.0 -Author: Sebastian Meyer -Maintainer: Sebastian Meyer <noreply@example.org> -Description: Test multiple citations. diff --git a/tests/testthat/assets/site-citation-multi/inst/temp-citation b/tests/testthat/assets/site-citation-multi/inst/temp-citation deleted file mode 100644 index 5bc0c82e6..000000000 --- a/tests/testthat/assets/site-citation-multi/inst/temp-citation +++ /dev/null @@ -1,3 +0,0 @@ -bibentry("misc", title="Proof of b < a > c", author=c("A", "B"), year="2021", - textVersion="A & B (2021): Proof of b < a > c.") -bibentry("misc", title="Title Two", author="Author Two", year="2022") diff --git a/tests/testthat/assets/search-site/sitemaps-schema-0.9.xsd b/tests/testthat/assets/sitemaps-schema-0.9.xsd similarity index 100% rename from tests/testthat/assets/search-site/sitemaps-schema-0.9.xsd rename to tests/testthat/assets/sitemaps-schema-0.9.xsd diff --git a/tests/testthat/assets/vignette-with-crayon.Rmd b/tests/testthat/assets/vignette-with-crayon.Rmd deleted file mode 100644 index 8ae245f83..000000000 --- a/tests/testthat/assets/vignette-with-crayon.Rmd +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Crayon" -output: html_fragment ---- - -```{r include = FALSE} -knitr::opts_chunk$set(collapse = TRUE, comment = "#>") -``` - -:::downlit -```{r} -cat(cli::col_red("X"), "\n") -``` -::: diff --git a/tests/testthat/assets/vignette-with-img.Rmd b/tests/testthat/assets/vignette-with-img.Rmd deleted file mode 100644 index 4ba2dc8ad..000000000 --- a/tests/testthat/assets/vignette-with-img.Rmd +++ /dev/null @@ -1,17 +0,0 @@ ---- -author: "Hadley Wickham" -title: "R Markdown Vignette with an Image" -description: "The image is in a subdirectory, and we must be sure to copy it." -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{R Markdown Vignette with an Image} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -Some words, and then an image like this: - -```{r, echo = FALSE} -#| fig-alt: The pkgdown logo -knitr::include_graphics("open-graph/logo.png") -``` diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index 34becaaf0..43d617c8b 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -1,13 +1,3 @@ -# A CITATION file anywhere except in `inst/CITATION` is an R CMD check note -local_citation_activate <- function(path, envir = caller_env()) { - old <- path(path, "inst", "temp-citation") - new <- path(path, "inst", "CITATION") - - file_move(old, new) - withr::defer(file_move(new, old), envir = envir) -} - - pkg_add_file <- function(pkg, path, lines = NULL) { full_path <- path(pkg$src_path, path) dir_create(path_dir(full_path)) @@ -31,3 +21,18 @@ pkg_add_kitten <- function(pkg, path) { file_copy(test_path("assets/kitten.jpg"), full_path) pkg } + +pkg_vignette <- function(..., title = "title") { + dots <- list2(title = title, ...) + meta <- dots[have_name(dots)] + contents <- unlist(dots[!have_name(dots)]) + + meta$vignette <- paste0("\n", " %\\VignetteIndexEntry{", title, "}") + yaml <- yaml::as.yaml( + meta, + handlers = list(logical = yaml::verbatim_logical) + ) + + c("---", yaml, "---", contents) +} +r_code_block <- function(...) c("```{r}", ..., "```") diff --git a/tests/testthat/test-build-article.R b/tests/testthat/test-build-article.R index c4c166dec..61bd6bf42 100644 --- a/tests/testthat/test-build-article.R +++ b/tests/testthat/test-build-article.R @@ -1,222 +1,107 @@ -test_that("image links relative to output", { - # weird path differences that I don't have the energy to dig into - skip_on_cran() - pkg <- local_pkgdown_site(test_path("assets/articles-images")) - - suppressMessages(init_site(pkg)) - suppressMessages(copy_figures(pkg)) - suppressMessages(build_article("kitten", pkg)) - - html <- xml2::read_html(path(pkg$dst_path, "articles", "kitten.html")) - src <- xpath_attr(html, "//main//img", "src") - - expect_equal(src, c( - # knitr::include_graphics() - "../reference/figures/kitten.jpg", - "another-kitten.jpg", - # rmarkdown image - "../reference/figures/kitten.jpg", - "another-kitten.jpg", - # magick::image_read() - "kitten_files/figure-html/magick-1.png", - # figure - "kitten_files/figure-html/plot-1.jpg" - )) - - # And files aren't copied - expect_false(dir_exists(path(pkg$dst_path, "man"))) -}) - -test_that("warns about missing images", { - # Added in #2509: I can't figure out why this is necessary :( - skip_on_covr() - - pkg <- local_pkgdown_site() - pkg <- pkg_add_file(pkg, "vignettes/kitten.Rmd", "![foo](kitten.jpg)") - - expect_snapshot(build_articles(pkg)) -}) - -test_that("warns about missing alt-text", { +test_that("can build article that uses html_vignette", { pkg <- local_pkgdown_site() - pkg <- pkg_add_file(pkg, "vignettes/missing-images.Rmd", c( - "![](kitten.jpg)", - "```{r}", - "plot(1)", - "```" + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette( + output = "rmarkdown::html_vignette", + pkgdown = list(as_is = TRUE) )) - pkg <- pkg_add_kitten(pkg, "vignettes") - - expect_snapshot(build_article("missing-images", pkg)) -}) - -test_that("articles don't include header-attrs.js script", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - - suppressMessages(path <- build_article("standard", pkg)) - - html <- xml2::read_html(path) - js <- xpath_attr(html, ".//body//script", "src") - # included for pandoc 2.7.3 - 2.9.2.1 improve accessibility - js <- js[path_file(js) != "empty-anchor.js"] - expect_equal(js, character()) -}) - -test_that("can build article that uses html_vignette", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) # theme is not set since html_vignette doesn't support it - expect_snapshot(expect_error(build_article("html-vignette", pkg), NA)) + suppressMessages(expect_no_error(build_article("test", pkg))) }) test_that("can override html_document() options", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - suppressMessages(path <- build_article("html-document", pkg)) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette( + output = list(html_document = list(number_sections = TRUE)), + pkgdown = list(as_is = TRUE), + "# Heading 1", + "# Heading 2" + )) + suppressMessages(path <- build_article("test", pkg)) # Check that number_sections is respected html <- xml2::read_html(path) expect_equal(xpath_text(html, ".//h2//span"), c("1", "2")) # But title isn't affected - expect_equal(xpath_text(html, ".//h1"), "html_document + as_is") + expect_equal(xpath_text(html, ".//h1"), "title") # And no links or scripts are inlined expect_equal(xpath_length(html, ".//body//link"), 0) expect_equal(xpath_length(html, ".//body//script"), 0) }) -test_that("html widgets get needed css/js", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - suppressMessages(path <- build_article("widget", pkg)) - - html <- xml2::read_html(path) - css <- xpath_attr(html, ".//body//link", "href") - js <- xpath_attr(html, ".//body//script", "src") - - expect_true("diffviewer.css" %in% path_file(css)) - expect_true("diffviewer.js" %in% path_file(js)) -}) - -test_that("can override options with _output.yml", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - suppressMessages(path <- build_article("html-document", pkg)) - - # Check that number_sections is respected - html <- xml2::read_html(path) - expect_equal(xpath_text(html, ".//h2//span"), c("1", "2")) -}) - test_that("can set width", { - pkg <- local_pkgdown_site( - test_path("assets/articles"), - list(code = list(width = 50)) - ) - suppressMessages(init_site(pkg)) + pkg <- local_pkgdown_site(meta = list(code = list(width = 50))) + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette( + r_code_block("getOption('width')") + )) - suppressMessages(path <- build_article("width", pkg)) + suppressMessages(path <- build_article("test", pkg)) html <- xml2::read_html(path) expect_equal(xpath_text(html, ".//pre")[[2]], "## [1] 50") }) test_that("bad width gives nice error", { pkg <- local_pkgdown_site(meta = list(code = list(width = "abc"))) - expect_snapshot(build_rmarkdown_format(pkg, "article"), error = TRUE) -}) - -test_that("finds external resources referenced by R code in the article html", { - # weird path differences that I don't have the energy to dig into - skip_on_cran() - pkg <- local_pkgdown_site(test_path("assets", "articles-resources")) - - suppressMessages(path <- build_article("resources", pkg)) - - # ensure that we the HTML references `<img src="external.png" />` directly - expect_equal( - xpath_attr(xml2::read_html(path), ".//img", "src"), - "external.png" - ) - - # expect that `external.png` was copied to the rendered article directory - expect_true( - file_exists(path(path_dir(path), "external.png")) - ) + expect_snapshot(rmarkdown_setup_pkgdown(pkg), error = TRUE) }) test_that("BS5 article laid out correctly with and without TOC", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - - suppressMessages(toc_true_path <- build_article("standard", pkg)) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/toc-true.Rmd", pkg_vignette( + "## Heading 1", + "## Heading 2" + )) + pkg <- pkg_add_file(pkg, "vignettes/toc-false.Rmd", pkg_vignette( + toc = FALSE, + "## Heading 1", + "## Heading 2" + )) + + suppressMessages(toc_true_path <- build_article("toc-true", pkg)) suppressMessages(toc_false_path <- build_article("toc-false", pkg)) toc_true <- xml2::read_html(toc_true_path) toc_false <- xml2::read_html(toc_false_path) # Always has class col-md-9 - expect_equal(xpath_attr(toc_false, ".//main", "class"), "col-md-9") expect_equal(xpath_attr(toc_true, ".//main", "class"), "col-md-9") + expect_equal(xpath_attr(toc_false, ".//main", "class"), "col-md-9") # The no sidebar without toc expect_equal(xpath_length(toc_true, ".//aside"), 1) expect_equal(xpath_length(toc_false, ".//aside"), 0) }) -test_that("pkgdown deps are included only once in articles", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - - suppressMessages(path <- build_article("html-deps", pkg)) - html <- xml2::read_html(path) - - # jquery is only loaded once, even though it's also added by code in the article - expect_equal(xpath_length(html, ".//script[(@src and contains(@src, '/jquery'))]"), 1) - - # same for bootstrap js and css - str_subset_bootstrap <- function(x) { - bs_rgx <- "bootstrap-[\\d.]+" # ex: bootstrap-5.1.0 not bootstrap-toc, - grep(bs_rgx, x, value = TRUE, perl = TRUE) - } - bs_js_src <- str_subset_bootstrap( - xpath_attr(html, ".//script[(@src and contains(@src, '/bootstrap'))]", "src") - ) - expect_length(bs_js_src, 1) - - bs_css_href <- str_subset_bootstrap( - xpath_attr(html, ".//link[(@href and contains(@href, '/bootstrap'))]", "href") - ) - expect_length(bs_css_href, 1) -}) - - test_that("titles are escaped when needed", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - suppressMessages(build_article(pkg = pkg, name = "needs-escape")) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette(title = "a <-> b")) + suppressMessages(path <- build_article("test", pkg)) - html <- xml2::read_html(path(pkg$dst_path, "articles/needs-escape.html")) + html <- xml2::read_html(path) expect_equal(xpath_text(html, "//title", trim = TRUE), "a <-> b • testpackage") expect_equal(xpath_text(html, "//h1", trim = TRUE), "a <-> b") }) test_that("output is reproducible by default, i.e. 'seed' is respected", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - suppressMessages(build_article(pkg = pkg, name = "random")) - - html <- xml2::read_html(path(pkg$dst_path, "articles/random.html")) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette( + r_code_block("runif(5L)") + )) + suppressMessages(path <- build_article("test", pkg)) + + html <- xml2::read_html(path) output <- xpath_text(html, "//main//pre")[[2]] expect_snapshot(cat(output)) }) test_that("reports on bad open graph meta-data", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - suppressMessages(init_site(pkg)) - expect_snapshot(build_article(pkg = pkg, name = "bad-opengraph"), error = TRUE) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette( + opengraph = list(twitter = 1) + )) + expect_snapshot(build_article("test", pkg), error = TRUE) }) test_that("can control math mode", { @@ -225,21 +110,20 @@ test_that("can control math mode", { pkg$meta$template$`math-rendering` <- "mathml" suppressMessages(init_site(pkg)) - suppressMessages(build_article("math", pkg)) - html <- xml2::read_html(path(pkg$dst_path, "articles", "math.html")) + suppressMessages(path <- build_article("math", pkg)) + html <- xml2::read_html(path) expect_equal(xpath_length(html, ".//math"), 1) pkg$meta$template$`math-rendering` <- "mathjax" suppressMessages(init_site(pkg)) - suppressMessages(build_article("math", pkg)) - html <- xml2::read_html(path(pkg$dst_path, "articles", "math.html")) + suppressMessages(path <- build_article("math", pkg)) + html <- xml2::read_html(path) expect_equal(xpath_length(html, ".//span[contains(@class, 'math')]"), 1) - pkg$meta$template$`math-rendering` <- "katex" suppressMessages(init_site(pkg)) - suppressMessages(build_article("math", pkg)) - html <- xml2::read_html(path(pkg$dst_path, "articles", "math.html")) + suppressMessages(path <- build_article("math", pkg)) + html <- xml2::read_html(path) expect_equal(xpath_length(html, ".//span[contains(@class, 'math')]"), 1) expect_contains( path_file(xpath_attr(html, ".//script", "src")), @@ -247,71 +131,186 @@ test_that("can control math mode", { ) }) -# render_markdown -------------------------------------------------------------- +test_that("rmarkdown_template cleans up after itself", { + pkg <- local_pkgdown_site() + path <- NULL -test_that("build_article copies image files in subdirectories", { - skip_if_no_pandoc() - - pkg <- local_pkgdown_site() - pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", c( - "```{r}", - "#| fig-alt: alt-text", - "knitr::include_graphics('test/kitten.jpg')", - "```" - )) - pkg <- pkg_add_kitten(pkg, "vignettes/test") - - expect_snapshot(build_article("test", pkg)) - expect_equal( - path_file(dir_ls(path(pkg$dst_path, "articles", "test"))), - "kitten.jpg" - ) - }) - -test_that("render_rmarkdown yields useful error if pandoc fails", { + local({ + path <<- rmarkdown_template(pkg) + expect_true(file_exists(path)) + }) + expect_false(file_exists(path)) +}) + +test_that("build_article styles ANSI escapes", { + skip_if_no_pandoc() + + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette( + r_code_block("cat(cli::col_red('X'), '\n')") + )) + + suppressMessages(path <- build_article("test", pkg)) + html <- xml2::read_html(path) + expect_snapshot_output(xpath_xml(html, ".//code//span[@class='co']")) +}) + +# Errors ----------------------------------------------------------------------- + +test_that("build_article yields useful error if pandoc fails", { skip_on_cran() # fragile due to pandoc dependency skip_if_no_pandoc("2.18") - tmp <- dir_create(file_temp()) - pkg <- list(src_path = test_path("."), dst_path = tmp, bs_version = 3) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", "Hi") - format <- rmarkdown::html_document(pandoc_args = "--fail-if-warnings") expect_snapshot( - render_rmarkdown(pkg, "assets/pandoc-fail.Rmd", "test.html", output_format = format), + build_article("test", pkg, pandoc_args = "--fail-if-warnings"), error = TRUE ) }) -test_that("render_rmarkdown yields useful error if R fails", { +test_that("build_article yields useful error if R fails", { skip_if_no_pandoc() - tmp <- dir_create(file_temp()) - pkg <- list(src_path = test_path("."), dst_path = tmp, bs_version = 3) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", c( + "---", + "title: title", + "---", + "```{r}", + "f <- function() g()", + "g <- function() h()", + "h <- function() rlang::abort('Error!')", + "f()", + "```" + )) - expect_snapshot( - { - "Test traceback" - summary(expect_error(render_rmarkdown(pkg, "assets/r-fail.Rmd", "test.html"))) - - "Just test that it works; needed for browser() etc" - expect_error(render_rmarkdown(pkg, "assets/r-fail.Rmd", "test.html", new_process = FALSE)) - }, - # work around xfun bug - transform = function(x) gsub("lines ?at lines", "lines", x) - ) + # check that error looks good + expect_snapshot(build_article("test", pkg), error = TRUE) + # check that traceback looks good - need extra work because rlang + # avoids tracebacks in snapshots + expect_snapshot(summary(expect_error(build_article("test", pkg)))) }) -test_that("render_rmarkdown styles ANSI escapes", { +# Images ----------------------------------------------------------------------- + +test_that("build_article copies image files in subdirectories", { skip_if_no_pandoc() - tmp <- dir_create(file_temp()) - pkg <- list(src_path = test_path("."), dst_path = tmp, bs_version = 5) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", c( + "```{r}", + "#| fig-alt: alt-text", + "knitr::include_graphics('test/kitten.jpg')", + "```" + )) + pkg <- pkg_add_kitten(pkg, "vignettes/test") + + expect_snapshot(build_article("test", pkg)) + expect_equal(path_file(dir_ls(path(pkg$dst_path, "articles", "test"))), "kitten.jpg") +}) + +test_that("finds external resources referenced by R code", { + # weird path differences that I don't have the energy to dig into + skip_on_cran() + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", c( + "![external dependency](`r 'kitten.jpg'`)" + )) + pkg <- pkg_add_kitten(pkg, "vignettes") + suppressMessages(path <- build_article("test", pkg)) + + # ensure that we the HTML references `<img src="external.png" />` directly + html <- xml2::read_html(path) + expect_equal(xpath_attr(html, ".//img", "src"), "kitten.jpg") + + # expect that `external.png` was copied to the rendered article directory + expect_true(file_exists(path(path_dir(path), "kitten.jpg"))) +}) + +test_that("image links relative to output", { + pkg <- local_pkgdown_site(test_path("assets/articles-images")) + + suppressMessages(init_site(pkg)) + suppressMessages(copy_figures(pkg)) + suppressMessages(build_article("kitten", pkg)) + + html <- xml2::read_html(path(pkg$dst_path, "articles", "kitten.html")) + src <- xpath_attr(html, "//main//img", "src") + + expect_equal(src, c( + # knitr::include_graphics() + "../reference/figures/kitten.jpg", + "another-kitten.jpg", + # rmarkdown image + "../reference/figures/kitten.jpg", + "another-kitten.jpg", + # magick::image_read() + "kitten_files/figure-html/magick-1.png", + # figure + "kitten_files/figure-html/plot-1.jpg" + )) + + # And files aren't copied + expect_false(dir_exists(path(pkg$dst_path, "man"))) +}) + +test_that("warns about missing images", { + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/kitten.Rmd", "![foo](kitten.jpg)") + + expect_snapshot(build_article("kitten", pkg)) +}) + +test_that("warns about missing alt-text", { + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/kitten.Rmd", "![](kitten.jpg)") + pkg <- pkg_add_kitten(pkg, "vignettes") + expect_snapshot(build_article("kitten", pkg)) +}) + +# External dependencies -------------------------------------------------------- - expect_snapshot({ - path <- render_rmarkdown(pkg, - input = "assets/vignette-with-crayon.Rmd", - output = "test.html" +test_that("pkgdown deps are included only once in articles", { + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette( + # Some code that adds jquery/bootstrap + r_code_block( + 'htmltools::tagList( + htmltools::p("hello"), + rmarkdown::html_dependency_jquery(), + rmarkdown::html_dependency_bootstrap("flatly") + )' ) - }) + )) + + # Rely on default init_site() from local_pkgdown_site() setting all + # the default includes to empty + suppressMessages(path <- build_article("test", pkg)) html <- xml2::read_html(path) - expect_snapshot_output(xpath_xml(html, ".//code//span[@class='co']")) + expect_equal(path_file(xpath_attr(html, ".//script", "src")), "pkgdown.js") + expect_equal(path_file(xpath_attr(html, ".//link", "href")), character()) +}) + +test_that("html widgets get needed css/js", { + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/test.Rmd", pkg_vignette( + r_code_block(' + path1 <- tempfile() + writeLines(letters, path1) + path2 <- tempfile() + writeLines(letters[-(10:11)], path2) + + diffviewer::visual_diff(path1, path2) + ') + )) + + suppressMessages(path <- build_article("test", pkg)) + + html <- xml2::read_html(path) + css <- xpath_attr(html, ".//body//link", "href") + js <- xpath_attr(html, ".//body//script", "src") + + expect_true("diffviewer.css" %in% path_file(css)) + expect_true("diffviewer.js" %in% path_file(js)) }) diff --git a/tests/testthat/test-build-articles.R b/tests/testthat/test-build-articles.R index acca02484..07705912d 100644 --- a/tests/testthat/test-build-articles.R +++ b/tests/testthat/test-build-articles.R @@ -56,10 +56,8 @@ test_that("articles in vignettes/articles/ are unnested into articles/", { # weird path differences that I don't have the energy to dig into skip_on_cran() - pkg <- local_pkgdown_site(test_path("assets/articles"), meta = list( - url = "https://example.com" - )) - suppressMessages(init_site(pkg)) + pkg <- local_pkgdown_site(meta = list(url = "https://example.com")) + pkg <- pkg_add_file(pkg, "vignettes/articles/nested.Rmd") nested <- pkg$vignettes[pkg$vignettes$name == "articles/nested", ] expect_equal(nested$file_out, "articles/nested.html") @@ -107,18 +105,11 @@ test_that("default template includes all articles", { }) test_that("check doesn't include getting started vignette", { - pkg <- local_pkgdown_site(test_path("assets/articles-resources")) - getting_started <- path(pkg$src_path, "vignettes", paste0(pkg$package, ".Rmd")) - file_create(getting_started) - withr::defer(file_delete(getting_started)) - - pkg <- local_pkgdown_site(test_path("assets/articles-resources"), meta = - list( - articles = list( - list(title = "Getting Started", contents = "resources") - ) - ) - ) + pkg <- local_pkgdown_site(meta = list( + articles = list(list(title = "Vignettes", contents = "a")) + )) + pkg <- pkg_add_file(pkg, "vignettes/a.Rmd") + pkg <- pkg_add_file(pkg, "vignettes/testpackage.Rmd") - expect_error(data_articles_index(pkg), NA) + expect_no_error(data_articles_index(pkg)) }) diff --git a/tests/testthat/test-build-home-authors.R b/tests/testthat/test-build-home-authors.R index f1292a23e..ed5dfaefa 100644 --- a/tests/testthat/test-build-home-authors.R +++ b/tests/testthat/test-build-home-authors.R @@ -102,22 +102,64 @@ test_that("can handle UTF-8 encoding (#416, #493)", { # Work around bug in utils::citation() local_options(warnPartialMatchDollar = FALSE) - path <- test_path("assets/site-citation-UTF-8") - local_citation_activate(path) + pkg <- local_pkgdown_site(desc = list( + Title = "A søphîstiçated pÃ¥ckagé", + Date = "2018-02-02" + )) + + meta <- create_citation_meta(pkg$src_path) + expect_type(meta, "list") + expect_equal(meta$Title, "A søphîstiçated pÃ¥ckagé") - cit <- read_citation(path) + pkg <- pkg_add_file(pkg, "inst/CITATION", c( + 'citEntry(', + ' entry = "Article",', + ' title="Title: é",', + ' author="Author: é",', + ' journal="Journal é",', + ' year="2017",', + ' textVersion = "é"', + ')' + )) + cit <- read_citation(pkg$src_path) expect_s3_class(cit, "citation") - meta <- create_citation_meta(path) - expect_type(meta, "list") - expect_equal(meta$`Authors@R`, 'person("Florian", "Privé")') + pkg <- pkg_add_file(pkg, "inst/CITATION", "citation(auto = meta)") + cit <- read_citation(pkg$src_path) + expect_s3_class(cit, "citation") }) test_that("can handle latin1 encoding (#689)", { - path <- test_path("assets/site-citation-latin1") - local_citation_activate(path) + pkg <- local_pkgdown_site(desc = list( + Title = "A søphîstiçated pÃ¥ckagé", + Date = "2018-02-02", + Encoding = "latin1" + )) + meta <- create_citation_meta(pkg$src_path) + expect_equal(meta$Title, "A søphîstiçated pÃ¥ckagé") + expect_equal(Encoding(meta$Title), "UTF-8") - cit <- read_citation(path) + pkg <- pkg_add_file(pkg, "inst/CITATION", c( + 'citEntry(', + ' entry = "Article",', + ' title="Title: é",', + ' author="Author: é",', + ' journal="Journal é",', + ' year="2017",', + ' textVersion = "é"', + ')' + )) + cit_path <- path(pkg$src_path, "inst/CITATION") + citation <- readLines(cit_path) # nolint + con <- file(cit_path, open = "w+", encoding = "native.enc") + withr::defer(close(con)) + base::writeLines(iconv(citation, to = "latin1"), con, useBytes = TRUE) # nolint + + cit <- read_citation(pkg$src_path) + expect_s3_class(cit, "citation") + + pkg <- pkg_add_file(pkg, "inst/CITATION", "citation(auto = meta)") + cit <- read_citation(pkg$src_path) expect_s3_class(cit, "citation") }) @@ -125,22 +167,34 @@ test_that("source link is added to citation page", { # Work around bug in utils::citation() local_options(warnPartialMatchDollar = FALSE) - path <- test_path("assets/site-citation-UTF-8") - local_citation_activate(path) - - pkg <- local_pkgdown_site(path) - suppressMessages(init_site(pkg)) - suppressMessages(build_home(pkg)) + pkg <- local_pkgdown_site(meta = list( + repo = list(url = list(source = "http://github.com/test/test")) + )) + pkg <- pkg_add_file(pkg, "inst/CITATION", c( + 'citEntry(', + ' entry = "Article",', + ' title="Title",', + ' author="Author",', + ' journal="Journal",', + ' year="2020",', + ' textVersion = ""', + ')' + )) + suppressMessages(build_citation_authors(pkg)) lines <- read_lines(path(pkg$dst_path, "authors.html")) - expect_true(any(grepl("<code>inst/CITATION</code></a></small>", lines))) + expect_true(any(grepl("<code>inst/CITATION</code></a>", lines))) }) test_that("multiple citations all have HTML and BibTeX formats", { - path <- test_path("assets/site-citation-multi") - local_citation_activate(path) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "inst/CITATION", c( + 'bibentry("misc", title="Proof of b < a > c", author=c("A", "B"), year="2021", + textVersion="A & B (2021): Proof of b < a > c.")', + 'bibentry("misc", title="Title Two", author="Author Two", year="2022")' + )) - citations <- data_citations(path) + citations <- data_citations(pkg$src_path) expect_snapshot_output(citations) }) diff --git a/tests/testthat/test-build-news.R b/tests/testthat/test-build-news.R index 2a4b0bc4d..36e0777d5 100644 --- a/tests/testthat/test-build-news.R +++ b/tests/testthat/test-build-news.R @@ -19,6 +19,19 @@ test_that("data_news works as expected for h1 & h2", { expect_snapshot_output(data_news(pkg)[c("version", "page", "anchor")]) }) +test_that("news is syntax highlighted once", { + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "NEWS.md", c( + "# testpackage 1.0.0.9000", + "```r", + "x <- 1", + "```" + )) + suppressMessages(build_news(pkg, preview = FALSE)) + html <- xml2::read_html(path(pkg$dst_path, "news", "index.html")) + expect_equal(xpath_text(html, "//code"), "x <- 1") +}) + test_that("multi-page news are rendered", { skip_if_no_pandoc() diff --git a/tests/testthat/test-build-search-docs.R b/tests/testthat/test-build-search-docs.R index 243d738d7..9ede7d086 100644 --- a/tests/testthat/test-build-search-docs.R +++ b/tests/testthat/test-build-search-docs.R @@ -1,36 +1,46 @@ test_that("docsearch.json and sitemap.xml are valid for BS 3 site", { - pkg <- local_pkgdown_site(test_path("assets/search-site")) - - suppressMessages(build_site(pkg, new_process = FALSE)) + pkg <- local_pkgdown_site( + meta = list( + url = "https://example.com", + template = list( + bootstrap = 3, + params = list( + docsearch = list( + api_key = "test-api-key", + index_name = "test-index-name" + ) + ) + ) + ) + ) + suppressMessages(build_docsearch_json(pkg)) json <- path(pkg$dst_path, "docsearch.json") expect_true(jsonlite::validate(read_lines(json))) - + + suppressMessages(build_sitemap(pkg)) xml <- path(pkg$dst_path, "sitemap.xml") - schema <- xml2::read_xml(path(pkg$src_path, "sitemaps-schema-0.9.xsd")) + schema <- xml2::read_xml(test_path("assets/sitemaps-schema-0.9.xsd")) expect_true(xml2::xml_validate(xml2::read_xml(xml), schema)) }) -test_that("build_search() builds the expected search.json with an URL", { +test_that("build_search_index() has expected structure", { pkg <- local_pkgdown_site( - test_path("assets/news"), - list(url = "https://example.com", development = list(mode = "devel")) + desc = list(Version = "1.0.0"), + meta = list(url = "https://example.com") ) + pkg <- pkg_add_file(pkg, "README.md", c( + "# My Package", + "What the pakage does" + )) suppressMessages(init_site(pkg)) - suppressMessages(build_news(pkg)) - suppressMessages(build_home(pkg)) - suppressMessages(build_sitemap(pkg)) + suppressMessages(build_home_index(pkg)) - json_path <- withr::local_tempfile() - jsonlite::write_json(build_search_index(pkg), json_path, pretty = TRUE) - expect_snapshot_file(json_path, "search.json") + expect_snapshot(str(build_search_index(pkg))) }) test_that("build sitemap only messages when it updates", { - pkg <- local_pkgdown_site( - test_path("assets/news"), - list(url = "https://example.com") - ) + pkg <- local_pkgdown_site(meta = list(url = "https://example.com")) suppressMessages(init_site(pkg)) suppressMessages(build_home(pkg)) @@ -41,19 +51,17 @@ test_that("build sitemap only messages when it updates", { }) test_that("build_search() builds the expected search.json with no URL", { - pkg <- local_pkgdown_site( - test_path("assets/news"), - list(development = list(mode = "devel")) - ) + pkg <- local_pkgdown_site(desc = list(Version = "1.0.0")) + pkg <- pkg_add_file(pkg, "README.md", c( + "# My Package", + "What the pakage does" + )) - suppressMessages(init_site(pkg)) - suppressMessages(build_news(pkg)) suppressMessages(build_home(pkg)) - suppressMessages(build_sitemap(pkg)) - json_path <- withr::local_tempfile() - jsonlite::write_json(build_search_index(pkg), json_path, pretty = TRUE) - expect_snapshot_file(json_path, "search-no-url.json") + index <- build_search_index(pkg) + paths <- purrr::map_chr(index, "path") + expect_equal(paths, c("/authors.html", "/authors.html", "/index.html")) }) test_that("sitemap excludes redirects", { diff --git a/tests/testthat/test-highlight.R b/tests/testthat/test-highlight.R index 38ce7dcb3..90abbf56f 100644 --- a/tests/testthat/test-highlight.R +++ b/tests/testthat/test-highlight.R @@ -9,6 +9,12 @@ test_that("highlight_examples captures dependencies", { expect_equal(attr(out, "dependencies")[-1], list(dummy_dep)) }) + +test_that("highlight_examples runs and hides DONTSHOW calls()", { + out <- highlight_examples("DONTSHOW(x <- 1)\nx") + expect_snapshot(cat(strip_html_tags(out))) +}) + test_that("highlight_text & highlight_examples include sourceCode div", { withr::defer(file_delete(test_path("Rplot001.png"))) diff --git a/tests/testthat/test-package.R b/tests/testthat/test-package.R index 142aaeda7..a84a593a4 100644 --- a/tests/testthat/test-package.R +++ b/tests/testthat/test-package.R @@ -23,9 +23,7 @@ test_that("check_bootstrap_version() allows 3, 4 (with warning), and 5", { }) test_that("check_bootstrap_version() gives informative error otherwise", { - pkg <- local_pkgdown_site(test_path("assets/articles")) - file_touch(path(pkg$src_path, "_pkgdown.yml")) - + pkg <- local_pkgdown_site() expect_snapshot(check_bootstrap_version(1, pkg), error = TRUE) }) @@ -49,10 +47,14 @@ test_that("package_vignettes() detects conflicts in final article paths", { }) test_that("package_vignettes() sorts articles alphabetically by file name", { - pkg <- local_pkgdown_site(test_path("assets/articles")) + pkg <- local_pkgdown_site() + pkg <- pkg_add_file(pkg, "vignettes/a.Rmd") + pkg <- pkg_add_file(pkg, "vignettes/b.Rmd") + pkg <- pkg_add_file(pkg, "vignettes/c.Rmd") + expect_equal( - order(path_file(pkg$vignettes$file_out)), - seq_len(nrow(pkg$vignettes)) + path_file(pkg$vignettes$file_out), + c("a.html", "b.html", "c.html") ) }) diff --git a/tests/testthat/test-rd-example.R b/tests/testthat/test-rd-example.R index d8c4c7159..2640625e4 100644 --- a/tests/testthat/test-rd-example.R +++ b/tests/testthat/test-rd-example.R @@ -9,17 +9,37 @@ test_that("warns if unparseable", { # as_example() ------------------------------------------------------------ -test_that("inline tags are stripped", { - expect_equal(rd2ex("\\donttest{1}"), "1") - expect_equal(rd2ex("\\dontshow{1}"), "1") - expect_equal(rd2ex("\\testonly{1}"), "1") - expect_equal(rd2ex("\\dontrun{1}"), "if (FALSE) 1") +test_that("dontrun{} wrapped in if(FALSE)", { + expect_equal(rd2ex("\\dontrun{1}"), "if (FALSE) 1 # \\dontrun{}") + expect_equal( + rd2ex("\\dontrun{\n 1\n}"), + c("if (FALSE) { # \\dontrun{", " 1", "} # }") + ) + + # unless run_dont_run is true expect_equal(rd2ex("\\dontrun{1}", run_dont_run = TRUE), "1") + expect_equal( + rd2ex("\\dontrun{\n 1\n}", run_dont_run = TRUE), + c("# \\dontrun{", " 1", "# }") + ) +}) + +test_that("block donttest{} gets a comment to preserve spacing", { + expect_equal(rd2ex("\\donttest{1}"), "1") + expect_equal( + rd2ex("\\donttest{\n 1\n}"), + c("# \\donttest{", " 1", "# }") + ) +}) + +test_that("dontshow{} becomes DONTSHOW", { + expect_equal(rd2ex("\\dontshow{1}"), "DONTSHOW({1})") + expect_equal(rd2ex("\\dontshow{\n 1\n}"), c("DONTSHOW({", " 1", "})")) }) -test_that("blocks get fillers to preserve spacing", { - expect_equal(rd2ex("\\donttest{\n 1\n}"), c("# \\donttest{", " 1", "# }")) - expect_equal(rd2ex("\\dontrun{\n 1\n}"), c("if (FALSE) {", " 1", "}")) +test_that("testonly{} becomes TESTONLY", { + expect_equal(rd2ex("\\testonly{1}"), "TESTONLY({1})") + expect_equal(rd2ex("\\testonly{\n 1\n}"), c("TESTONLY({", " 1", "})")) }) test_that("handles nested tags", { @@ -27,9 +47,9 @@ test_that("handles nested tags", { rd2ex("if(TRUE {\n \\dontrun{\n 1 + 2\n }\n}"), c( "if(TRUE {", - " if (FALSE) {", + " if (FALSE) { # \\dontrun{", " 1 + 2", - " }", + " } # }", "}" ) ) diff --git a/tests/testthat/test-usage.R b/tests/testthat/test-usage.R index 282c94b50..776f7df50 100644 --- a/tests/testthat/test-usage.R +++ b/tests/testthat/test-usage.R @@ -15,6 +15,9 @@ test_that("usage re-renders non-syntactic calls", { test_that("usage doesn't re-renders syntactic calls", { expect_equal(usage2text("foo(x , y) # hi"), "foo(x , y) # hi") + + multi_line <- "foo(\n x # x,\n y = 1 # y,\n)" + expect_equal(usage2text(multi_line), multi_line) }) test_that("usage generates user facing code for S3/S4 infix/replacement methods", { diff --git a/vignettes/pkgdown.Rmd b/vignettes/pkgdown.Rmd index 9cfdaee51..643dda46f 100644 --- a/vignettes/pkgdown.Rmd +++ b/vignettes/pkgdown.Rmd @@ -10,21 +10,24 @@ vignette: > --- The goal of pkgdown is to make it easy to make an elegant and useful package website with a minimum of work. -You can get a basic website up and running in just a couple of minutes: +You can get a basic website up and running in just a couple of minutes. If you're using GitHub, we recommend setting up pkgdown and GitHub actions to automatically build and publish your site: ```{r, eval = FALSE} -# Run once to configure package to use pkgdown -usethis::use_pkgdown() -# Run to build the website -pkgdown::build_site() +# Run this once to publish your site regularly +usethis::use_pkgdown_github_pages() ``` -If you're using GitHub, we also recommend setting up GitHub actions to automatically build and publish your site: +If you are not using GitHub, you will have to run `pkgdown::build_site()` manually everytime you want to update the site. ```{r, eval = FALSE} -usethis::use_pkgdown_github_pages() +# Run once +# Remove docs/ from gitignore to ensure it is checked into git. +usethis::use_pkgdown() +# Run everytime you want to update your site +pkgdown::build_site() ``` + While you'll get a decent website without any additional work, if you want a website that really pops, you'll need to read the rest of this vignette. It starts by showing you how to configure pkgdown with a `_pkgdown.yml`. You'll learn about the main components of the site (the home page, reference, articles, and news), and then how to publish and promote your site. @@ -105,7 +108,7 @@ reference: Note the use of `starts_with()` to select all functions with a common prefix. You can also use `ends_with()` and `matches()`. -See complete details in `?build_reference`. +See complete details in `?build_reference`, including other topic matching helper functions. While iterating on the reference index you might want to run `pkgdown::build_reference_index()`. It just re-builds the index page, making it faster to quickly change `_pkgdown.yml` and see how it affects your site. @@ -113,11 +116,12 @@ It just re-builds the index page, making it faster to quickly change `_pkgdown.y ## Articles pkgdown will automatically build all vignettes found in `vignettes/`, translating them to HTML files in `articles/`. -Due to the way that pkgdown has to integrate RMarkdown generated HTML with its own HTML, relatively little control is available over the output format. +It is recommended to name your intro article with your package name to generate a Get Started page automatically. + +Due to the way that pkgdown has to integrate R Markdown generated HTML with its own HTML, relatively little control is available over the output format. You can see the details in `?build_articles`. -If you want to include an article on the website but not in the package (e.g., because it's large), you can either place it in a subdirectory of `vignettes/` (e.g. `vignettes/web_only`) or add it to `.Rbuildignore` (and make sure that there's no `vignettes:` section in the yaml header). -In the extreme case where you want to produce only articles but not vignettes, you should add the complete `vignettes/` directory to `.Rbuildignore` and ensure that DESCRIPTION does not have a `VignetteBuilder` field. +If you want to include an [article](https://r-pkgs.org/website.html#non-vignette-articles) on the website but not in the package (e.g., because it's large), you can use `usethis::use_article()` to set it up. ## News @@ -145,12 +149,9 @@ See `?build_news` for more customisation options including how to: ## Publishing -If you use GitHub, there are two ways to publish your site on GitHub Pages: - -- Build the site locally, check in the docs directory, then configure GitHub Pages to [use that directory](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site). - -- Use GitHub actions to automatically build and publish the site every time you make a change. - The easiest way to set this up is to run `usethis::use_pkgdown_github_pages()`. +If you use GitHub, the easiest way to build and publish your site is via GitHub actions. +Using GitHub actions automatically builds and publishes the site every time you make a change. +The easiest way to set this up is to run `usethis::use_pkgdown_github_pages()`, and if you need to customize the action, see [README.md r-lib/actions](https://github.com/r-lib/actions/tree/v2-branch/examples#build-pkgdown-site). ## Promoting @@ -166,4 +167,4 @@ Once your finalized site is built and published on the web, you should publicize (`usethis::use_pkgdown_github_pages()` does this for you.) -3. On Twitter (make sure to include `#rstats`). +3. On social media (make sure to include `#rstats`). diff --git a/vignettes/translations.Rmd b/vignettes/translations.Rmd index eccb08e04..394825b3f 100644 --- a/vignettes/translations.Rmd +++ b/vignettes/translations.Rmd @@ -92,5 +92,5 @@ Then commit your changes to Git and submit your pull request for review: ```{r} #| eval: false -usethis::pr_submit() +usethis::pr_push() ```