diff --git a/src/hast_util_to_swc.rs b/src/hast_util_to_swc.rs index bc19e43..8b101a4 100644 --- a/src/hast_util_to_swc.rs +++ b/src/hast_util_to_swc.rs @@ -27,7 +27,7 @@ //! SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. use crate::hast; -use crate::swc::{parse_esm_to_tree, parse_expression_to_tree}; +use crate::swc::{parse_esm_to_tree, parse_expression_to_tree, serialize}; use crate::swc_utils::{ create_jsx_attr_name_from_str, create_jsx_name_from_str, inter_element_whitespace, position_to_span, @@ -53,6 +53,13 @@ pub struct Program { pub comments: Vec, } +impl Program { + /// Serialize to JS. + pub fn serialize(&mut self) -> String { + serialize(&mut self.module, Some(&self.comments)) + } +} + /// Whether we’re in HTML or SVG. #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Space { diff --git a/src/lib.rs b/src/lib.rs index b8ca572..38bb830 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ extern crate markdown; mod configuration; -mod hast; +pub mod hast; mod hast_util_to_swc; mod mdast_util_to_hast; mod mdx_plugin_recma_document; @@ -23,17 +23,25 @@ mod swc_util_build_jsx; mod swc_utils; use crate::{ - hast_util_to_swc::hast_util_to_swc, - mdast_util_to_hast::mdast_util_to_hast, - mdx_plugin_recma_document::{mdx_plugin_recma_document, Options as DocumentOptions}, - mdx_plugin_recma_jsx_rewrite::{mdx_plugin_recma_jsx_rewrite, Options as RewriteOptions}, + hast_util_to_swc::hast_util_to_swc as to_swc, + mdx_plugin_recma_document::{ + mdx_plugin_recma_document as wrap_document, Options as DocumentOptions, + }, + mdx_plugin_recma_jsx_rewrite::{ + mdx_plugin_recma_jsx_rewrite as jsx_rewrite, Options as RewriteOptions, + }, swc::{parse_esm, parse_expression, serialize}, swc_util_build_jsx::{swc_util_build_jsx, Options as BuildOptions}, }; -use markdown::{message, to_mdast, Constructs, Location, ParseOptions}; -use swc_core::alloc::collections::FxHashSet; +use hast_util_to_swc::Program; +use markdown::{ + message::{self, Message}, + to_mdast, Constructs, Location, ParseOptions, +}; +use swc_core::{alloc::collections::FxHashSet, common::Span}; pub use crate::configuration::{MdxConstructs, MdxParseOptions, Options}; +pub use crate::mdast_util_to_hast::mdast_util_to_hast; pub use crate::mdx_plugin_recma_document::JsxRuntime; /// Turn MDX into JavaScript. @@ -54,6 +62,40 @@ pub use crate::mdx_plugin_recma_document::JsxRuntime; /// This project errors for many different reasons, such as syntax errors in /// the MDX format or misconfiguration. pub fn compile(value: &str, options: &Options) -> Result { + let mdast = mdast_util_from_mdx(value, options)?; + let hast = mdast_util_to_hast(&mdast); + let location = Location::new(value.as_bytes()); + let mut explicit_jsxs = FxHashSet::default(); + let mut program = hast_util_to_swc(&hast, options, Some(&location), &mut explicit_jsxs)?; + mdx_plugin_recma_document(&mut program, options, Some(&location))?; + mdx_plugin_recma_jsx_rewrite(&mut program, options, Some(&location), &explicit_jsxs)?; + Ok(serialize(&mut program.module, Some(&program.comments))) +} + +/// Turn markdown into a syntax tree. +/// +/// ## Errors +/// +/// There are several errors that can occur with how +/// JSX, expressions, or ESM are written. +/// +/// ## Examples +/// +/// ``` +/// use mdxjs::{mdast_util_from_mdx, Options}; +/// # fn main() -> Result<(), markdown::message::Message> { +/// +/// let tree = mdast_util_from_mdx("# Hey, *you*!", &Options::default())?; +/// +/// println!("{:?}", tree); +/// // => Root { children: [Heading { children: [Text { value: "Hey, ", position: Some(1:3-1:8 (2-7)) }, Emphasis { children: [Text { value: "you", position: Some(1:9-1:12 (8-11)) }], position: Some(1:8-1:13 (7-12)) }, Text { value: "!", position: Some(1:13-1:14 (12-13)) }], position: Some(1:1-1:14 (0-13)), depth: 1 }], position: Some(1:1-1:14 (0-13)) } +/// # Ok(()) +/// # } +/// ``` +pub fn mdast_util_from_mdx( + value: &str, + options: &Options, +) -> Result { let parse_options = ParseOptions { constructs: Constructs { attention: options.parse.constructs.attention, @@ -96,6 +138,36 @@ pub fn compile(value: &str, options: &Options) -> Result, + explicit_jsxs: &mut FxHashSet, +) -> Result { + to_swc(hast, options.filepath.clone(), location, explicit_jsxs) +} + +/// Wrap the SWC ES AST nodes coming from hast into a whole document. +/// +/// ## Errors +/// +/// This project errors for many different reasons, such as syntax errors in +/// the MDX format or misconfiguration. +pub fn mdx_plugin_recma_document( + program: &mut Program, + options: &Options, + location: Option<&Location>, +) -> Result<(), markdown::message::Message> { let document_options = DocumentOptions { pragma: options.pragma.clone(), pragma_frag: options.pragma_frag.clone(), @@ -103,36 +175,36 @@ pub fn compile(value: &str, options: &Options) -> Result, + explicit_jsxs: &FxHashSet, +) -> Result<(), markdown::message::Message> { let rewrite_options = RewriteOptions { development: options.development, provider_import_source: options.provider_import_source.clone(), }; - let build_options = BuildOptions { - development: options.development, - }; - let mut explicit_jsxs = FxHashSet::default(); - - let location = Location::new(value.as_bytes()); - let mdast = to_mdast(value, &parse_options)?; - let hast = mdast_util_to_hast(&mdast); - let mut program = hast_util_to_swc( - &hast, - options.filepath.clone(), - Some(&location), - &mut explicit_jsxs, - )?; - mdx_plugin_recma_document(&mut program, &document_options, Some(&location))?; - mdx_plugin_recma_jsx_rewrite( - &mut program, - &rewrite_options, - Some(&location), - explicit_jsxs, - ); + jsx_rewrite(program, &rewrite_options, location, explicit_jsxs); if !options.jsx { - swc_util_build_jsx(&mut program, &build_options, Some(&location))?; + let build_options = BuildOptions { + development: options.development, + }; + + swc_util_build_jsx(program, &build_options, location)?; } - Ok(serialize(&mut program.module, Some(&program.comments))) + Ok(()) } diff --git a/src/mdast_util_to_hast.rs b/src/mdast_util_to_hast.rs index 65aef9a..ba29a7b 100644 --- a/src/mdast_util_to_hast.rs +++ b/src/mdast_util_to_hast.rs @@ -231,9 +231,10 @@ pub fn mdast_util_to_hast(mdast: &mdast::Node) -> hast::Node { })); } - tail_element - .children - .append(&mut backreference_opt.take().unwrap()); + if let Some(mut backreference) = backreference_opt { + backreference_opt = None; + tail_element.children.append(&mut backreference); + } } } diff --git a/src/mdx_plugin_recma_jsx_rewrite.rs b/src/mdx_plugin_recma_jsx_rewrite.rs index ab50db2..1bbed21 100644 --- a/src/mdx_plugin_recma_jsx_rewrite.rs +++ b/src/mdx_plugin_recma_jsx_rewrite.rs @@ -43,7 +43,7 @@ pub fn mdx_plugin_recma_jsx_rewrite( program: &mut Program, options: &Options, location: Option<&Location>, - explicit_jsxs: FxHashSet, + explicit_jsxs: &FxHashSet, ) { let mut state = State { scopes: vec![], @@ -137,7 +137,7 @@ struct Scope { } /// Context. -#[derive(Debug, Default, Clone)] +#[derive(Debug, Clone)] struct State<'a> { /// Location info. location: Option<&'a Location>, @@ -157,7 +157,7 @@ struct State<'a> { /// helper function to throw when they are missing. create_error_helper: bool, - explicit_jsxs: FxHashSet, + explicit_jsxs: &'a FxHashSet, } impl State<'_> { @@ -1044,7 +1044,7 @@ mod tests { let mut program = hast_util_to_swc(&hast, filepath, Some(&location), &mut explicit_jsxs)?; mdx_plugin_recma_document(&mut program, &DocumentOptions::default(), Some(&location))?; - mdx_plugin_recma_jsx_rewrite(&mut program, options, Some(&location), explicit_jsxs); + mdx_plugin_recma_jsx_rewrite(&mut program, options, Some(&location), &explicit_jsxs); Ok(serialize(&mut program.module, Some(&program.comments))) } @@ -1867,7 +1867,7 @@ function _missingMdxReference(id, component, place) { }))))], }, }; - mdx_plugin_recma_jsx_rewrite(&mut program, &Options::default(), None, explicit_jsxs); + mdx_plugin_recma_jsx_rewrite(&mut program, &Options::default(), None, &explicit_jsxs); assert_eq!( serialize(&mut program.module, None), "let a = ;\n", @@ -1899,7 +1899,7 @@ function _missingMdxReference(id, component, place) { }))))], }, }; - mdx_plugin_recma_jsx_rewrite(&mut program, &Options::default(), None, explicit_jsxs); + mdx_plugin_recma_jsx_rewrite(&mut program, &Options::default(), None, &explicit_jsxs); assert_eq!( serialize(&mut program.module, None), "let ;\n", @@ -1931,7 +1931,7 @@ function _missingMdxReference(id, component, place) { }))))], }, }; - mdx_plugin_recma_jsx_rewrite(&mut program, &Options::default(), None, explicit_jsxs); + mdx_plugin_recma_jsx_rewrite(&mut program, &Options::default(), None, &explicit_jsxs); assert_eq!( serialize(&mut program.module, None), "let a;\n",