diff --git a/src/lib.rs b/src/lib.rs index 7160a58..4b7e647 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,8 @@ //! //! * [`compile()`][] //! — turn MDX into JavaScript +//! * [`compile_with_ast()`][] +//! — turn MDX into JavaScript, but also return the original Markdown AST #![deny(clippy::pedantic)] #![allow(clippy::must_use_candidate)] #![allow(clippy::too_many_lines)] @@ -13,7 +15,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; @@ -30,29 +32,19 @@ use crate::{ swc::{parse_esm, parse_expression, serialize}, swc_util_build_jsx::{swc_util_build_jsx, Options as BuildOptions}, }; -use markdown::{to_mdast, Constructs, Location, ParseOptions}; +use hast_util_to_swc::Program; +use markdown::{mdast, to_mdast, Constructs, Location, ParseOptions}; pub use crate::configuration::{MdxConstructs, MdxParseOptions, Options}; pub use crate::mdx_plugin_recma_document::JsxRuntime; -/// Turn MDX into JavaScript. -/// -/// ## Examples -/// -/// ``` -/// use mdxjs::compile; -/// # fn main() -> Result<(), String> { -/// -/// assert_eq!(compile("# Hi!", &Default::default())?, "import { jsx as _jsx } from \"react/jsx-runtime\";\nfunction _createMdxContent(props) {\n const _components = Object.assign({\n h1: \"h1\"\n }, props.components);\n return _jsx(_components.h1, {\n children: \"Hi!\"\n });\n}\nfunction MDXContent(props = {}) {\n const { wrapper: MDXLayout } = props.components || {};\n return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n children: _jsx(_createMdxContent, props)\n })) : _createMdxContent(props);\n}\nexport default MDXContent;\n"); -/// # Ok(()) -/// # } -/// ``` +/// Turn MDX into an mdast node. /// /// ## Errors /// /// 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 { +pub fn parse_to_mdast(value: &str, options: &Options) -> Result { let parse_options = ParseOptions { constructs: Constructs { attention: options.parse.constructs.attention, @@ -95,6 +87,31 @@ pub fn compile(value: &str, options: &Options) -> Result { mdx_esm_parse: Some(Box::new(parse_esm)), mdx_expression_parse: Some(Box::new(parse_expression)), }; + + to_mdast(value, &parse_options) +} + +/// Turn a mdast node into an hast one. +/// +/// ## Errors +/// +/// This project errors for many different reasons, such as syntax errors in +/// the MDX format or misconfiguration. +pub fn mdast_to_hast(mdast: &mdast::Node) -> hast::Node { + mdast_util_to_hast(mdast) +} + +/// Turn an hast node into an SWC program. +/// +/// ## Errors +/// +/// This project errors for many different reasons, such as syntax errors in +/// the MDX format or misconfiguration. +pub fn hast_to_program( + hast: &hast::Node, + original_source: &str, + options: &Options, +) -> Result { let document_options = DocumentOptions { pragma: options.pragma.clone(), pragma_frag: options.pragma_frag.clone(), @@ -110,10 +127,9 @@ pub fn compile(value: &str, options: &Options) -> Result { development: options.development, }; - 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))?; + let location = Location::new(original_source.as_bytes()); + + let mut program = hast_util_to_swc(hast, options.filepath.clone(), Some(&location))?; mdx_plugin_recma_document(&mut program, &document_options, Some(&location))?; mdx_plugin_recma_jsx_rewrite(&mut program, &rewrite_options, Some(&location)); @@ -121,5 +137,34 @@ pub fn compile(value: &str, options: &Options) -> Result { swc_util_build_jsx(&mut program, &build_options, Some(&location))?; } - Ok(serialize(&mut program.module, Some(&program.comments))) + Ok(program) +} + +pub fn program_to_string(program: &mut Program) -> String { + serialize(&mut program.module, Some(&program.comments)) +} + +/// Turn MDX into JavaScript. +/// +/// ## Examples +/// +/// ``` +/// use mdxjs::compile; +/// # fn main() -> Result<(), String> { +/// +/// assert_eq!(compile("# Hi!", &Default::default())?, "import { jsx as _jsx } from \"react/jsx-runtime\";\nfunction _createMdxContent(props) {\n const _components = Object.assign({\n h1: \"h1\"\n }, props.components);\n return _jsx(_components.h1, {\n children: \"Hi!\"\n });\n}\nfunction MDXContent(props = {}) {\n const { wrapper: MDXLayout } = props.components || {};\n return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n children: _jsx(_createMdxContent, props)\n })) : _createMdxContent(props);\n}\nexport default MDXContent;\n"); +/// # Ok(()) +/// # } +/// ``` +/// +/// ## Errors +/// +/// 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 = parse_to_mdast(value, options)?; + let hast = mdast_to_hast(&mdast); + let mut program = hast_to_program(&hast, value, options)?; + + Ok(program_to_string(&mut program)) }