├── .gitignore ├── .Rproj.user ├── A78EF6A1 │ └── sources │ │ └── prop │ │ ├── F68E1CC │ │ ├── 2A363ADA │ │ ├── C147A9B8 │ │ ├── 12722A51 │ │ ├── 1A729DDD │ │ ├── 66E46F1D │ │ ├── 6DB63491 │ │ ├── 9D1C6C67 │ │ ├── D165D19A │ │ └── INDEX └── shared │ └── notebooks │ ├── patch-chunk-names │ ├── 3F09346C-README │ └── 1 │ │ └── s │ │ └── chunks.json │ └── paths ├── LICENSE ├── .Rbuildignore ├── man ├── run.Rd ├── cli.Rd └── writeMDX.Rd ├── NAMESPACE ├── writeMDX.Rproj ├── DESCRIPTION ├── R ├── writeMDX.R ├── run.R ├── cli.R ├── utils.R └── mdx_format.R ├── LICENSE.md ├── README.mdx ├── README.Rmd └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/F68E1CC: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /.Rproj.user/shared/notebooks/patch-chunk-names: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/2A363ADA: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/C147A9B8: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Robert Myles McDonnell 3 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/12722A51: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "0,0", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/1A729DDD: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "30,10", 3 | "scrollLine" : "14" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/66E46F1D: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "12,0", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/6DB63491: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "1,44", 3 | "scrollLine" : "1" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/9D1C6C67: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "3,41", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/D165D19A: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "4,0", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/shared/notebooks/3F09346C-README/1/s/chunks.json: -------------------------------------------------------------------------------- 1 | {"chunk_definitions":[],"doc_write_time":1557867144} -------------------------------------------------------------------------------- /.Rproj.user/shared/notebooks/paths: -------------------------------------------------------------------------------- 1 | /Users/f64k1s8/Documents/writeMDx/DESCRIPTION="5DC9DBF2" 2 | /Users/f64k1s8/Documents/writeMDx/R/writeMDX.R="82B2C520" 3 | /Users/f64k1s8/Documents/writeMDx/README.Rmd="93BA70C6" 4 | /Users/f64k1s8/Documents/writeMDx/README.mdx="D80FC0A2" 5 | -------------------------------------------------------------------------------- /man/run.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/run.R 3 | \name{run} 4 | \alias{run} 5 | \title{Run the command line interface} 6 | \usage{ 7 | run() 8 | } 9 | \description{ 10 | Run the command line interface 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(cli) 4 | export(run) 5 | export(writeMDX) 6 | importFrom(docopt,docopt) 7 | importFrom(rmarkdown,render) 8 | importFrom(strex,str_after_first) 9 | importFrom(strex,str_after_last) 10 | importFrom(strex,str_before_first) 11 | -------------------------------------------------------------------------------- /man/cli.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cli.R 3 | \name{cli} 4 | \alias{cli} 5 | \title{Install the command line interface} 6 | \usage{ 7 | cli() 8 | } 9 | \description{ 10 | Install the command line interface 11 | } 12 | \examples{ 13 | \dontrun{ 14 | writeMDX::cli() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /writeMDX.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: writeMDX 2 | Type: Package 3 | Title: Writes MDX output from RMarkdown files 4 | Version: 0.1.0 5 | Author: Robert Myles McDonnell 6 | Maintainer: Rpobert Myles McDonnell 7 | Description: MDX is an authorable format that lets you seamlessly use JSX 8 | in your markdown documents. JSX in turn is a syntax extension to JavaScript 9 | that allows you to include React components. writeMDX writes Rmarkdown files 10 | to MDX format. 11 | License: MIT + file LICENSE 12 | Encoding: UTF-8 13 | LazyData: true 14 | RoxygenNote: 7.0.2 15 | Imports: rmarkdown (>= 1.12), 16 | docopt (>= 0.6.1), 17 | strex (>= 1.2.0) 18 | -------------------------------------------------------------------------------- /man/writeMDX.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/writeMDX.R 3 | \name{writeMDX} 4 | \alias{writeMDX} 5 | \title{writeMDX} 6 | \usage{ 7 | writeMDX( 8 | input, 9 | config = list(include = list("date", "title", "featuredImage"), exclude = 10 | list("author", "output")) 11 | ) 12 | } 13 | \arguments{ 14 | \item{input}{Input file (.Rmd format).} 15 | 16 | \item{config}{\code{list}. Configurable YAML fields to check for. Default is 17 | config = list("date", "title", "featuredImage")} 18 | } 19 | \description{ 20 | write and Rmarkdown (.Rmd) file to MDX (.mdx) format. 21 | } 22 | \examples{ 23 | \dontrun{ 24 | # supposing you have a 'test.Rmd' file: 25 | writeMDX("test.Rmd") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.Rproj.user/A78EF6A1/sources/prop/INDEX: -------------------------------------------------------------------------------- 1 | ~%2FDocuments%2FwriteMDx%2F.gitignore="D98535A6" 2 | ~%2FDocuments%2FwriteMDx%2FDESCRIPTION="667FC547" 3 | ~%2FDocuments%2FwriteMDx%2FLICENSE="91204C57" 4 | ~%2FDocuments%2FwriteMDx%2FR%2Fcli.R="8991E36" 5 | ~%2FDocuments%2FwriteMDx%2FR%2Fmdx_format.R="E4E82562" 6 | ~%2FDocuments%2FwriteMDx%2FR%2Frun.R="7488C468" 7 | ~%2FDocuments%2FwriteMDx%2FR%2FwriteMDX.R="3B243FA1" 8 | ~%2FDocuments%2FwriteMDx%2FREADME.Rmd="A21FBD8A" 9 | ~%2FDocuments%2FwriteMDx%2FREADME.mdx="F225DEC6" 10 | ~%2FwriteMDX%2FDESCRIPTION="66E46F1D" 11 | ~%2FwriteMDX%2FLICENSE="2A363ADA" 12 | ~%2FwriteMDX%2FLICENSE.md="F68E1CC" 13 | ~%2FwriteMDX%2FNAMESPACE="D165D19A" 14 | ~%2FwriteMDX%2FR%2Fhello.R="C147A9B8" 15 | ~%2FwriteMDX%2FR%2Fmdx_format.R="12722A51" 16 | ~%2FwriteMDX%2FR%2Futils.R="6DB63491" 17 | ~%2FwriteMDX%2FR%2FwriteMDX.R="9D1C6C67" 18 | ~%2FwriteMDX%2FREADME.Rmd="1A729DDD" 19 | -------------------------------------------------------------------------------- /R/writeMDX.R: -------------------------------------------------------------------------------- 1 | #' @importFrom rmarkdown render 2 | #' @importFrom strex str_after_first str_after_last str_before_first 3 | #' @title writeMDX 4 | #' @description write and Rmarkdown (.Rmd) file to MDX (.mdx) format. 5 | #' @param input Input file (.Rmd format). 6 | #' @param config \code{list}. Configurable YAML fields to check for. Default is 7 | #' config = list("date", "title", "featuredImage") 8 | #' @examples 9 | #' \dontrun{ 10 | #' # supposing you have a 'test.Rmd' file: 11 | #' writeMDX("test.Rmd") 12 | #' } 13 | #' @export 14 | writeMDX <- function(input, 15 | config = list( 16 | include = list("date", "title", "featuredImage"), 17 | exclude = list("author", "output") 18 | )) { 19 | if (tools::file_ext(input) != "Rmd") stop("This only works with Rmarkdown files (.Rmd).") 20 | rmarkdown::render(input, mdx_format(cfig = config)) 21 | } 22 | -------------------------------------------------------------------------------- /R/run.R: -------------------------------------------------------------------------------- 1 | #' Run the command line interface 2 | # Inspired by: https://github.com/ankane/jetpack/blob/master/R/run.R 3 | #' @importFrom docopt docopt 4 | #' @export 5 | #' @keywords internal 6 | run <- function() { 7 | 8 | doc <- "Usage: 9 | writeMDX 10 | writeMDX help" 11 | 12 | opts <- NULL 13 | tryCatch({ 14 | opts <- docopt(doc) 15 | }, error = function(err){ 16 | msg <- conditionMessage(err) 17 | if (!grepl("usage:", msg)) { 18 | warning(msg) 19 | } 20 | message(doc) 21 | quit(status = 1) 22 | }) 23 | 24 | tryCatch({ 25 | if(opts$help){ 26 | message(doc) 27 | } else{ 28 | writeMDX(input = opts$input, 29 | config = list( 30 | include = list("date", "title", "featuredImage"), 31 | exclude = list("author", "output") 32 | )) 33 | } 34 | }, error=function(err) { 35 | msg <- conditionMessage(err) 36 | quit(status = 1) 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /R/cli.R: -------------------------------------------------------------------------------- 1 | #' Install the command line interface 2 | # Inspired by: https://github.com/ankane/jetpack/blob/master/R/cli.R 3 | #' @export 4 | #' @examples \dontrun{ 5 | #' writeMDX::cli() 6 | #' } 7 | cli <- function() { 8 | if (.Platform$OS.type != "unix") { 9 | file <- "C:/ProgramData/writeMDX/bin/writemdx.cmd" 10 | rscript <- file.path(R.home("bin"), "Rscript.exe") 11 | dir <- dirname(file) 12 | if (!file.exists(dir)) { 13 | dir.create(dir, recursive=TRUE) 14 | } 15 | write(paste0("@", rscript, " -e \"writeMDX::run()\" %* "), file = file) 16 | message(paste("Wrote", windowsPath(file))) 17 | message(paste0("Be sure to add '", windowsPath(dir), "' to your PATH")) 18 | } else { 19 | file <- "/usr/local/bin/writeMDX" 20 | write("#!/usr/bin/env Rscript\n\nwriteMDX::run()", file = file) 21 | Sys.chmod(file, "755") 22 | message(paste("Wrote", file)) 23 | } 24 | } 25 | 26 | windowsPath <- function(path) { 27 | gsub("/", "\\\\", path) 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2019 Robert Myles McDonnell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | writeMDX :japanese\_ogre: 7 | ========================= 8 | 9 | `writeMDX` writes Rmarkdown (`.Rmd`) files to 10 | [MDX](https://github.com/mdx-js/mdx). Nice and simple :sunglasses: 11 | 12 | Install :open\_hands: 13 | --------------------- 14 | 15 | You can install it with 16 | `remotes::install_github("RobertMyles/writeMDX")`. 17 | 18 | Use :point\_down: 19 | ----------------- 20 | 21 | With a file named “heyho.Rmd”: 22 | 23 | writeMDX("heyho.Rmd") 24 | 25 | Why?? :confused: 26 | ---------------- 27 | 28 | I love [React](https://reactjs.org/), and I just rebuilt my 29 | [website](https://www.robertmylesmcdonnell.com/) using 30 | [gatsby.js](https://www.gatsbyjs.org/), so now I want all the ease and 31 | power of MDX. The only missing piece of the puzzle was doing some stuff 32 | in R, and then writing it out to an `.mdx` file that I can use to add in 33 | all the other stuff I want, like D3 graphs. R + React + Markdown = 34 | :purple\_heart: 35 | 36 | No CRAN? :cry: 37 | -------------- 38 | 39 | This won’t go on CRAN, since it’s mainly [rmarkdown 40 | package](https://rmarkdown.rstudio.com/) functions with an added format, 41 | which you can do yourself [quite 42 | easily](https://bookdown.org/yihui/rmarkdown/format-custom.html). 43 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | # These functions are from the rmarkdown R package (https://github.com/rstudio/rmarkdown) 2 | # they are included here as dependencies for writeMDX() 3 | 4 | # read and write UTF-8 5 | read_utf8 <- function(file, encoding = 'UTF-8') { 6 | if (inherits(file, 'connection')) con <- file else { 7 | con <- base::file(file, encoding = encoding); on.exit(close(con), add = TRUE) 8 | } 9 | enc2utf8(readLines(con, warn = FALSE)) 10 | } 11 | 12 | write_utf8 <- function (text, con, ...) { 13 | opts <- options(encoding = "native.enc"); on.exit(options(opts), add = TRUE) 14 | writeLines(enc2utf8(text), con, ..., useBytes = TRUE) 15 | } 16 | 17 | #------------------------------------------------------- 18 | # blank check 19 | is_blank <- function (x){ 20 | if (length(x)) 21 | all(grepl("^\\s*$", x)) 22 | else TRUE 23 | } 24 | 25 | #------------------------------------------------------ 26 | # preserve YAML 27 | partition_yaml_front_matter <- function(input_lines){ 28 | validate_front_matter <- function(delimiters) { 29 | if (length(delimiters) >= 2 && (delimiters[2] - delimiters[1] > 30 | 1) && grepl("^---\\s*$", input_lines[delimiters[1]])) { 31 | if (delimiters[1] == 1) 32 | TRUE 33 | else is_blank(input_lines[1:delimiters[1] - 1]) 34 | } 35 | else { 36 | FALSE 37 | } 38 | } 39 | delimiters <- grep("^(---|\\.\\.\\.)\\s*$", input_lines) 40 | if (validate_front_matter(delimiters)) { 41 | front_matter <- input_lines[(delimiters[1]):(delimiters[2])] 42 | input_body <- c() 43 | if (delimiters[1] > 1) 44 | input_body <- c(input_body, input_lines[1:delimiters[1] - 45 | 1]) 46 | if (delimiters[2] < length(input_lines)) 47 | input_body <- c(input_body, input_lines[-(1:delimiters[2])]) 48 | list(front_matter = front_matter, body = input_body) 49 | } 50 | else { 51 | list(front_matter = NULL, body = input_lines) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /R/mdx_format.R: -------------------------------------------------------------------------------- 1 | mdx_format <- function(variant = "markdown", preserve_yaml = TRUE, 2 | dev = "png", df_print = "tibble", fig_width = 7, 3 | fig_height = 5, cfig) { 4 | args <- "" 5 | 6 | # add post_processor for yaml preservation 7 | post_processor <- function(metadata, input_file, output_file, clean, verbose) { 8 | input_lines <- read_utf8(input_file) 9 | partitioned <- partition_yaml_front_matter(input_lines) 10 | 11 | if (length(cfig) > 0) { 12 | yaml_headers <- partitioned$front_matter 13 | last <- length(yaml_headers) 14 | yaml_headers <- yaml_headers[-last] 15 | yaml_headers <- yaml_headers[-1] 16 | if (length(cfig$include) > 0) { 17 | yaml_fields_include <- unlist(cfig$include) 18 | } else { 19 | yaml_fields_include <- NULL 20 | } 21 | if (length(cfig$exclude) > 0) { 22 | yaml_fields_exclude <- unlist(cfig$exclude) 23 | } else { 24 | yaml_fields_exclude <- NULL 25 | } 26 | if (!is.null(yaml_fields_include)) { 27 | for (i in 1:length(yaml_fields_include)) { 28 | param <- yaml_fields_include[[i]] 29 | present <- which(grepl(param, yaml_headers)) 30 | if (length(present) > 1) stop("There are duplicate YAML header entries.") 31 | if (length(present == 1) & param == "date") { 32 | date_string <- str_after_first(yaml_headers[[present]], "date: ") 33 | date_string <- gsub(x = date_string, pattern = '"', replacement = "") 34 | first <- strex::str_before_first(date_string, "/") 35 | if (nchar(first) < 2) first <- paste0("0", first) 36 | second <- str_after_first(date_string, "/") 37 | third <- str_after_last(second, "/") 38 | second <- str_before_first(second, "/") 39 | if (nchar(second) < 2) second <- paste0("0", second) 40 | # account for RStudio default RMarkdown creating dates as "2/28/2020" 41 | date_out <- paste0(third, "-", first, "-", second) 42 | date_position <- which(grepl("date", partitioned$front_matter)) 43 | yaml_date_out <- paste0("date: '", date_out, "'") 44 | partitioned$front_matter[date_position] <- yaml_date_out 45 | } else if (length(present) < 1) { 46 | stop(paste0("Config item '", param, "' is missing from YAML.")) 47 | } 48 | } 49 | } 50 | if (!is.null(yaml_fields_exclude)) { 51 | for (j in 1:length(yaml_fields_exclude)) { 52 | param <- yaml_fields_exclude[[j]] 53 | take_out <- which(grepl(param, partitioned$front_matter)) 54 | if (length(take_out) > 0) { 55 | partitioned$front_matter <- partitioned$front_matter[-take_out] 56 | } 57 | } 58 | } 59 | } 60 | if (!is.null(partitioned$front_matter)) { 61 | output_lines <- c(partitioned$front_matter, "", read_utf8(output_file)) 62 | write_utf8(output_lines, output_file) 63 | } 64 | output_file 65 | } 66 | 67 | # return format 68 | rmarkdown:::output_format( 69 | knitr = rmarkdown:::knitr_options_html(fig_width, fig_height, fig_retina = NULL, FALSE, dev), 70 | pandoc = rmarkdown:::pandoc_options( 71 | to = variant, 72 | from = rmarkdown::from_rmarkdown(), 73 | args = args, 74 | ext = ".mdx" 75 | ), 76 | keep_md = FALSE, 77 | clean_supporting = FALSE, 78 | df_print = df_print, 79 | post_processor = post_processor 80 | ) 81 | } 82 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | # writeMDX :japanese_ogre: 16 | 17 | `writeMDX` writes Rmarkdown (`.Rmd`) files to [MDX](https://github.com/mdx-js/mdx). Nice and simple :sunglasses: 18 | 19 | ## Install :open_hands: 20 | 21 | You can install it with `remotes::install_github("RobertMyles/writeMDX")`. 22 | 23 | ## Use :point_down: 24 | 25 | With a file named "heyho.Rmd": 26 | 27 | ```{r eval=FALSE} 28 | writeMDX("heyho.Rmd") 29 | ``` 30 | 31 | If you'd like to use it from the command line, first run `writeMDX::cli()`. Then it's just: 32 | 33 | ```{bash eval = FALSE} 34 | writeMDX heyho.Rmd 35 | ``` 36 | 37 | 38 | writeMDX has a few defaults that are set up for me, but you can easily change them. The `config` argument accepts a list of two named lists: `inlcude` and `exclude`. These are the fields you'd like to remove, or for which you want to check for inclusion on the YAML header. The command line version isn't set up to take anything other than the defaults yet. 39 | 40 | ## Example 41 | 42 | I use this for my blog, for example [here](https://www.robertmylesmcdonnell.com/content/posts/UKelections2019/). 43 | 44 | 45 | My workflow for my website is usually: 46 | 47 | - Open up new Rmarkdown document in RStudio; 48 | - Write something kewlz about R; 49 | - Do some repetitive boring stuff to get it into a suitable format for rendering with [Gatsby.js](https://www.gatsbyjs.org/). 50 | 51 | writeMDX helps with that last part. Let's say we open up a new .Rmd in RStudio, it will look like this in the YAML header (unless you use a template or some other format): 52 | 53 | ``` 54 | --- 55 | title: "MDXtest" 56 | author: "Robert McDonnell" 57 | date: "2/29/2020" 58 | output: html_document 59 | featuredImage: "image/png.png" 60 | --- 61 | ``` 62 | Well, it probably won't say `"Robert McDonnell"`, but you get the idea. `featuredImage` I put in. 63 | 64 | So that's all fine, but the MDX that I use to include React on my Gatsby-powered blog has this YAML header: 65 | 66 | ``` 67 | --- 68 | title: "MDXtest 69 | date: "2020-02-29" 70 | featuredImage: "images/some_image.png" 71 | --- 72 | ``` 73 | 74 | Changing this manually every time I want to blog about something gets pretty old pretty quickly. So I use writeMDX, which will convert the former to the latter. It also creates a proper MDX document that follows pandoc's [markdown](https://pandoc.org/MANUAL.html#pandocs-markdown) spec. So a full RMarkdown might be this (ignore the `#` at the code chunks, just for formatting the README correctly): 75 | 76 | ``` 77 | --- 78 | title: "MDXtest" 79 | author: "Robert McDonnell" 80 | date: "2/29/2020" 81 | output: html_document 82 | featuredImage: "image/png.png" 83 | --- 84 | 85 | #```{r setup, include=FALSE} 86 | knitr::opts_chunk$set(echo = TRUE) 87 | #``` 88 | 89 | ## writeMDX test 90 | 91 | This is a test document for writeMDX. It has **bold**, *italic* 92 | 93 | - lists 94 | - sublists 95 | - and so on 96 | 97 | It also has equations $y_{ij} = \alpha_j * beta_i$ 98 | 99 | $$y_{ij} = \alpha_j * beta_i$$ 100 | 101 | And it has code. For R: 102 | #```{r} 103 | x <- 5 104 | print(x) 105 | 106 | print(head(mtcars)) 107 | #``` 108 | 109 | And Python: 110 | #```{python} 111 | x = 3 112 | print(x) 113 | #``` 114 | ``` 115 | 116 | And the MDX resulting from writeMDX will be: 117 | 118 | ``` 119 | --- 120 | title: "MDXtest" 121 | date: '2020-02-29' 122 | featuredImage: "image/png.png" 123 | --- 124 | 125 | writeMDX test 126 | ------------- 127 | 128 | This is a test document for writeMDX. It has **bold**, *italic* 129 | 130 | - lists 131 | - sublists 132 | - and so on 133 | 134 | It also has equations $y_{ij} = \alpha_j * beta_i$ 135 | 136 | $$y_{ij} = \alpha_j * beta_i$$ 137 | 138 | And it has code. For R: 139 | 140 | #``` {.r} 141 | x <- 5 142 | print(x) 143 | #``` 144 | 145 | ## [1] 5 146 | 147 | #``` {.r} 148 | print(head(mtcars)) 149 | #``` 150 | 151 | ## mpg cyl disp hp drat wt qsec vs am gear carb 152 | ## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 153 | ## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 154 | ## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 155 | ## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 156 | ## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 157 | ## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 158 | 159 | And Python: 160 | 161 | #``` {.python} 162 | x = 3 163 | print(x) 164 | #``` 165 | 166 | ## 3 167 | ``` 168 | 169 | It's not perfect, as you can see. The indentations could be removed, emojis work differently, and equations need a different set up. These are on my [to-do list](https://github.com/RobertMyles/writeMDX/projects/1); they may or may not get done. If you'd like to make a PR for any of these, feel free. 170 | 171 | 172 | ## Why?? :confused: 173 | 174 | I love [React](https://reactjs.org/), and I just rebuilt my [website](https://www.robertmylesmcdonnell.com/) using [gatsby.js](https://www.gatsbyjs.org/), so now I want all the ease and power of MDX. The only missing piece of the puzzle was doing some stuff in R, and then writing it out to an `.mdx` file that I can use to add in all the other stuff I want, like D3 graphs. R + React + Markdown = :purple_heart: 175 | 176 | ## No CRAN? :cry: 177 | 178 | This won't go on CRAN, since it's mainly [rmarkdown package](https://rmarkdown.rstudio.com/) functions with an added format, which you can do yourself [quite easily](https://bookdown.org/yihui/rmarkdown/format-custom.html). 179 | 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # writeMDX :japanese\_ogre: 5 | 6 | `writeMDX` writes Rmarkdown (`.Rmd`) files to 7 | [MDX](https://github.com/mdx-js/mdx). Nice and simple :sunglasses: 8 | 9 | ## Install :open\_hands: 10 | 11 | You can install it with 12 | `remotes::install_github("RobertMyles/writeMDX")`. 13 | 14 | ## Use :point\_down: 15 | 16 | With a file named “heyho.Rmd”: 17 | 18 | ``` r 19 | writeMDX("heyho.Rmd") 20 | ``` 21 | 22 | If you’d like to use it from the command line, first run 23 | `writeMDX::cli()`. Then it’s just: 24 | 25 | ``` bash 26 | writeMDX heyho.Rmd 27 | ``` 28 | 29 | writeMDX has a few defaults that are set up for me, but you can easily 30 | change them. The `config` argument accepts a list of two named lists: 31 | `inlcude` and `exclude`. These are the fields you’d like to remove, or 32 | for which you want to check for inclusion on the YAML header. The 33 | command line version isn’t set up to take anything other than the 34 | defaults yet. 35 | 36 | ## Example 37 | 38 | I use this for my blog, for example 39 | [here](https://www.robertmylesmcdonnell.com/content/posts/UKelections2019/). 40 | 41 | My workflow for my [website](https://www.robertmylesmcdonnell.com/) is 42 | usually: 43 | 44 | - Open up new Rmarkdown document in RStudio; 45 | - Write something kewlz about R; 46 | - Do some repetitive boring stuff to get it into a suitable format for 47 | rendering with [Gatsby.js](https://www.gatsbyjs.org/). 48 | 49 | writeMDX helps with that last part. Let’s say we open up a new .Rmd in 50 | RStudio, it will look like this in the YAML header (unless you use a 51 | template or some other format): 52 | 53 | --- 54 | title: "MDXtest" 55 | author: "Robert McDonnell" 56 | date: "2/29/2020" 57 | output: html_document 58 | featuredImage: "image/png.png" 59 | --- 60 | 61 | Well, it probably won’t say `"Robert McDonnell"`, but you get the idea. 62 | `featuredImage` I put in. 63 | 64 | So that’s all fine, but the MDX that I use to include React on my 65 | Gatsby-powered blog has this YAML header: 66 | 67 | --- 68 | title: "MDXtest 69 | date: "2020-02-29" 70 | featuredImage: "images/some_image.png" 71 | --- 72 | 73 | Changing this manually every time I want to blog about something gets 74 | pretty old pretty quickly. So I use writeMDX, which will convert the 75 | former to the latter. It also creates a proper MDX document that follows 76 | pandoc’s [markdown](https://pandoc.org/MANUAL.html#pandocs-markdown) 77 | spec. So a full RMarkdown might be this (ignore the `#` at the code 78 | chunks, just for formatting the README correctly): 79 | 80 | --- 81 | title: "MDXtest" 82 | author: "Robert McDonnell" 83 | date: "2/29/2020" 84 | output: html_document 85 | featuredImage: "image/png.png" 86 | --- 87 | 88 | #```{r setup, include=FALSE} 89 | knitr::opts_chunk$set(echo = TRUE) 90 | #``` 91 | 92 | ## writeMDX test 93 | 94 | This is a test document for writeMDX. It has **bold**, *italic* 95 | 96 | - lists 97 | - sublists 98 | - and so on 99 | 100 | It also has equations $y_{ij} = \alpha_j * beta_i$ 101 | 102 | $$y_{ij} = \alpha_j * beta_i$$ 103 | 104 | And it has code. For R: 105 | #```{r} 106 | x <- 5 107 | print(x) 108 | 109 | print(head(mtcars)) 110 | #``` 111 | 112 | And Python: 113 | #```{python} 114 | x = 3 115 | print(x) 116 | #``` 117 | 118 | And the MDX resulting from writeMDX will be: 119 | 120 | --- 121 | title: "MDXtest" 122 | date: '2020-02-29' 123 | featuredImage: "image/png.png" 124 | --- 125 | 126 | writeMDX test 127 | ------------- 128 | 129 | This is a test document for writeMDX. It has **bold**, *italic* 130 | 131 | - lists 132 | - sublists 133 | - and so on 134 | 135 | It also has equations $y_{ij} = \alpha_j * beta_i$ 136 | 137 | $$y_{ij} = \alpha_j * beta_i$$ 138 | 139 | And it has code. For R: 140 | 141 | #``` {.r} 142 | x <- 5 143 | print(x) 144 | #``` 145 | 146 | ## [1] 5 147 | 148 | #``` {.r} 149 | print(head(mtcars)) 150 | #``` 151 | 152 | ## mpg cyl disp hp drat wt qsec vs am gear carb 153 | ## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 154 | ## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 155 | ## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 156 | ## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 157 | ## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 158 | ## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 159 | 160 | And Python: 161 | 162 | #``` {.python} 163 | x = 3 164 | print(x) 165 | #``` 166 | 167 | ## 3 168 | 169 | It’s not perfect, as you can see. The indentations could be removed, 170 | emojis work differently, and equations need a different set up. These 171 | are on my [to-do 172 | list](https://github.com/RobertMyles/writeMDX/projects/1); they may or 173 | may not get done. If you’d like to make a PR for any of these, feel 174 | free. 175 | 176 | ## Why?? :confused: 177 | 178 | I love [React](https://reactjs.org/), and I just rebuilt my 179 | [website](https://www.robertmylesmcdonnell.com/) using 180 | [gatsby.js](https://www.gatsbyjs.org/), so now I want all the ease and 181 | power of MDX. The only missing piece of the puzzle was doing some stuff 182 | in R, and then writing it out to an `.mdx` file that I can use to add in 183 | all the other stuff I want, like D3 graphs. R + React + Markdown = 184 | :purple\_heart: 185 | 186 | ## No CRAN? :cry: 187 | 188 | This won’t go on CRAN, since it’s mainly [rmarkdown 189 | package](https://rmarkdown.rstudio.com/) functions with an added format, 190 | which you can do yourself [quite 191 | easily](https://bookdown.org/yihui/rmarkdown/format-custom.html). 192 | --------------------------------------------------------------------------------