ojs_define <- function(...) {
  # validate that we aren't in a cached chunk
  cache <- knitr:::opts_current$get("cache")
  if (is.numeric(cache) && cache > 0) {
    stop("ojs_define() cannot be cached\n",
      "Add cache: false to this cell's options to disable caching",
      call. = FALSE
    )
  }
  quos <- rlang::enquos(...)
  vars <- rlang::list2(...)
  nm <- names(vars)
  if (is.null(nm)) {
    nm <- rep_len("", length(vars))
  }
  contents <- jsonlite::toJSON(
    list(contents = I(mapply(
      function(q, nm, val) {
        # Infer name, if possible
        if (nm == "") {
          tryCatch(
            {
              nm <- rlang::as_name(q)
            },
            error = function(e) {
              code <- paste(collapse = "\n", deparse(rlang::f_rhs(q)))
              stop("ojs_define() could not create a name for the argument: ", code)
            }
          )
        }
        list(name = nm, value = val)
      }, quos, nm, vars,
      SIMPLIFY = FALSE, USE.NAMES = FALSE
    ))),
    dataframe = "columns", null = "null", na = "null", auto_unbox = TRUE
  )
  script_string <- c(
    "<script type=\"ojs-define\">",
    contents,
    "</script>"
  )
  invisible(
    knitr::knit_meta_add(
      list(structure(class = "ojs-define", script_string))
    )
  )
}
