Skip to content

Commit

Permalink
Add exports of functions for each phase
Browse files Browse the repository at this point in the history
Closes GH-60.
  • Loading branch information
devongovett authored Jan 30, 2025
1 parent c860d49 commit fb4b491
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 41 deletions.
9 changes: 8 additions & 1 deletion src/hast_util_to_swc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -53,6 +53,13 @@ pub struct Program {
pub comments: Vec<swc_core::common::comments::Comment>,
}

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 {
Expand Down
132 changes: 102 additions & 30 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand All @@ -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<String, message::Message> {
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<markdown::mdast::Node, Message> {
let parse_options = ParseOptions {
constructs: Constructs {
attention: options.parse.constructs.attention,
Expand Down Expand Up @@ -96,43 +138,73 @@ pub fn compile(value: &str, options: &Options) -> Result<String, message::Messag
mdx_esm_parse: Some(Box::new(parse_esm)),
mdx_expression_parse: Some(Box::new(parse_expression)),
};

to_mdast(value, &parse_options)
}

/// Compile hast into SWC’s ES AST.
///
/// ## Errors
///
/// This project errors for many different reasons, such as syntax errors in
/// the MDX format or misconfiguration.
pub fn hast_util_to_swc(
hast: &hast::Node,
options: &Options,
location: Option<&Location>,
explicit_jsxs: &mut FxHashSet<Span>,
) -> Result<Program, markdown::message::Message> {
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(),
pragma_import_source: options.pragma_import_source.clone(),
jsx_import_source: options.jsx_import_source.clone(),
jsx_runtime: options.jsx_runtime,
};
wrap_document(program, &document_options, location)
}

/// Rewrite JSX in an MDX file so that components can be passed in and provided.
/// Also compiles JSX to function calls unless `options.jsx` is true.
///
/// ## Errors
///
/// This project errors for many different reasons, such as syntax errors in
/// the MDX format or misconfiguration.
pub fn mdx_plugin_recma_jsx_rewrite(
program: &mut Program,
options: &Options,
location: Option<&Location>,
explicit_jsxs: &FxHashSet<Span>,
) -> 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(())
}
7 changes: 4 additions & 3 deletions src/mdast_util_to_hast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/mdx_plugin_recma_jsx_rewrite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub fn mdx_plugin_recma_jsx_rewrite(
program: &mut Program,
options: &Options,
location: Option<&Location>,
explicit_jsxs: FxHashSet<Span>,
explicit_jsxs: &FxHashSet<Span>,
) {
let mut state = State {
scopes: vec![],
Expand Down Expand Up @@ -137,7 +137,7 @@ struct Scope {
}

/// Context.
#[derive(Debug, Default, Clone)]
#[derive(Debug, Clone)]
struct State<'a> {
/// Location info.
location: Option<&'a Location>,
Expand All @@ -157,7 +157,7 @@ struct State<'a> {
/// helper function to throw when they are missing.
create_error_helper: bool,

explicit_jsxs: FxHashSet<Span>,
explicit_jsxs: &'a FxHashSet<Span>,
}

impl State<'_> {
Expand Down Expand Up @@ -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)))
}

Expand Down Expand Up @@ -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 = <b/>;\n",
Expand Down Expand Up @@ -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 <invalid>;\n",
Expand Down Expand Up @@ -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",
Expand Down

0 comments on commit fb4b491

Please sign in to comment.