|
| 1 | +#' Check if a Quarto document uses parameters |
| 2 | +#' |
| 3 | +#' Determines whether a Quarto document uses parameters by examining the document |
| 4 | +#' structure and metadata. This function works with both knitr and Jupyter engines, |
| 5 | +#' using different detection methods for each: |
| 6 | +#' |
| 7 | +#' - **Knitr engine (.qmd files)**: Checks for a "params" field in the document's |
| 8 | +#' YAML metadata using `quarto_inspect()` |
| 9 | +#' - **Jupyter engine (.ipynb files)**: Looks for code cells tagged with "parameters" |
| 10 | +#' following the papermill convention. For .ipynb files, the function parses the |
| 11 | +#' notebook JSON directly due to limitations in `quarto inspect`. |
| 12 | +#' |
| 13 | +#' @param input Path to the Quarto document (.qmd or .ipynb file) to inspect. |
| 14 | +#' |
| 15 | +#' @return Logical. `TRUE` if the document uses parameters, `FALSE` otherwise. |
| 16 | +#' |
| 17 | +#' @details |
| 18 | +#' Parameters in Quarto enable creating dynamic, reusable documents. This function |
| 19 | +#' helps identify parameterized documents programmatically, which is useful for: |
| 20 | +#' |
| 21 | +#' - Document processing workflows |
| 22 | +#' - Automated report generation |
| 23 | +#' - Parameter validation before rendering |
| 24 | +#' - Project analysis and organization |
| 25 | +#' |
| 26 | +#' For more information about using parameters in Quarto, see |
| 27 | +#' <https://quarto.org/docs/computations/parameters.html> |
| 28 | +#' |
| 29 | +#' @examples |
| 30 | +#' \dontrun{ |
| 31 | +#' # Check if a document uses parameters |
| 32 | +#' has_parameters("my-document.qmd") |
| 33 | +#' |
| 34 | +#' # Check a parameterized report |
| 35 | +#' has_parameters("parameterized-report.qmd") |
| 36 | +#' |
| 37 | +#' # Check a Jupyter notebook |
| 38 | +#' has_parameters("analysis.ipynb") |
| 39 | +#' |
| 40 | +#' # Use in a workflow |
| 41 | +#' if (has_parameters("report.qmd")) { |
| 42 | +#' message("This document accepts parameters") |
| 43 | +#' } |
| 44 | +#' } |
| 45 | +#' |
| 46 | +#' @export |
| 47 | +has_parameters <- function(input) { |
| 48 | + if (!file.exists(input)) { |
| 49 | + cli::cli_abort( |
| 50 | + c( |
| 51 | + "File {.file {input}} does not exist.", |
| 52 | + ">" = "Please provide a valid Quarto document." |
| 53 | + ), |
| 54 | + call = rlang::caller_env() |
| 55 | + ) |
| 56 | + } |
| 57 | + |
| 58 | + # Check for Jupyter engine: look for cells with "parameters" tag |
| 59 | + # Note: quarto_inspect() has limitations with Jupyter notebooks and may not |
| 60 | + # detect code cells properly, so we fall back to direct JSON parsing for .ipynb files |
| 61 | + if (identical(fs::path_ext(input), "ipynb")) { |
| 62 | + return(has_parameters_jupyter_direct(input)) |
| 63 | + } |
| 64 | + |
| 65 | + inspect <- quarto::quarto_inspect(input) |
| 66 | + |
| 67 | + if (identical(inspect$engines, "jupyter")) { |
| 68 | + return( |
| 69 | + "parameters" %in% inspect$fileInformation[[input]]$codeCells$metadata$tags |
| 70 | + ) |
| 71 | + } else if (identical(inspect$engines, "knitr")) { |
| 72 | + return( |
| 73 | + "params" %in% names(inspect$fileInformation[[input]]$metadata) |
| 74 | + ) |
| 75 | + } else { |
| 76 | + return(FALSE) |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +# Helper function to directly parse Jupyter notebook JSON for parameters |
| 81 | +# This is needed because quarto_inspect() has limitations with detecting |
| 82 | +# code cells in Jupyter notebooks |
| 83 | +has_parameters_jupyter_direct <- function(notebook_path) { |
| 84 | + tryCatch( |
| 85 | + { |
| 86 | + # Read and parse the notebook JSON with simplifyDataFrame = FALSE |
| 87 | + # to preserve the original structure |
| 88 | + notebook_json <- jsonlite::fromJSON( |
| 89 | + notebook_path, |
| 90 | + simplifyDataFrame = FALSE |
| 91 | + ) |
| 92 | + |
| 93 | + # Check if there are cells |
| 94 | + if (length(notebook_json$cells) == 0) { |
| 95 | + return(FALSE) |
| 96 | + } |
| 97 | + # Look through cells for parameters tag |
| 98 | + any(sapply(notebook_json$cells, function(cell) { |
| 99 | + "parameters" %in% cell$metadata$tags |
| 100 | + })) |
| 101 | + }, |
| 102 | + error = function(e) { |
| 103 | + # If JSON parsing fails, return FALSE |
| 104 | + return(FALSE) |
| 105 | + } |
| 106 | + ) |
| 107 | +} |
0 commit comments