Skip to content

Commit

Permalink
feat: compile jsx
Browse files Browse the repository at this point in the history
  • Loading branch information
Codpoe committed Jan 9, 2024
1 parent d5f454c commit 2aae01c
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 47 deletions.
52 changes: 50 additions & 2 deletions __test__/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,53 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`compile > should compile jsx 1`] = `
"<h1 id=\\"compile-jsx\\">
Compile JSX<a aria-hidden=\\"true\\" href=\\"#compile-jsx\\">#</a>
</h1>
"
`;
exports[`compile > should compile jsx 2`] = `
"import { jsxDEV as _jsxDEV } from \\"react/jsx-dev-runtime\\";
import { useMDXComponents as _provideComponents } from \\"@mdx-js/react\\";
function _createMdxContent(props) {
const _components = Object.assign({
h1: \\"h1\\",
a: \\"a\\"
}, _provideComponents(), props.components);
return _jsxDEV(_components.h1, {
id: \\"compile-jsx\\",
children: [
\\"Compile JSX\\",
_jsxDEV(_components.a, {
className: \\"header-anchor\\",
\\"aria-hidden\\": \\"true\\",
href: \\"#compile-jsx\\",
children: \\"#\\"
}, undefined, false, {
fileName: \\"xxx.mdx\\"
}, this)
]
}, undefined, true, {
fileName: \\"xxx.mdx\\",
lineNumber: 1,
columnNumber: 1
}, this);
}
function MDXContent(props = {}) {
const { wrapper: MDXLayout } = Object.assign({}, _provideComponents(), props.components);
return MDXLayout ? _jsxDEV(MDXLayout, Object.assign({}, props, {
children: _jsxDEV(_createMdxContent, props, undefined, false, {
fileName: \\"xxx.mdx\\"
}, this)
}), undefined, false, {
fileName: \\"xxx.mdx\\"
}, this) : _createMdxContent(props);
}
export default MDXContent;
"
`;
exports[`compile > should render container content correctly 1`] = `
"<div>
<div>TIP</div>
Expand Down Expand Up @@ -102,7 +150,7 @@ export default MDXContent;
exports[`compile > should render container title in mdx correctly 1`] = `
"<h2 id=\\"custom-title\\">
Container Title<a aria-hidden=\\"true\\" href=\\"#custom-title\\">#</a>
Container Title <a aria-hidden=\\"true\\" href=\\"#custom-title\\">#</a>
</h2>
<div>
<div>Custom Title</div>
Expand Down Expand Up @@ -141,7 +189,7 @@ function _createMdxContent(props) {
p: \\"p\\",
code: \\"code\\"
}, _provideComponents(), props.components);
return <><_components.h2 id=\\"custom-title\\">{\\"Container Title\\"}<_components.a className=\\"header-anchor\\" aria-hidden=\\"true\\" href=\\"#custom-title\\">{\\"#\\"}</_components.a></_components.h2>{\\"\\\\n\\"}<_components.div className=\\"rspress-directive tip\\"><_components.div className=\\"rspress-directive-title\\">{\\"Custom Title\\"}</_components.div><_components.div className=\\"rspress-directive-content\\"><_components.p>{\\"\\\\nThis is a \\"}<_components.code>{\\"block\\"}</_components.code>{\\" of \\"}<_components.code>{\\"Custom Title\\"}</_components.code>{\\"\\\\n\\"}</_components.p></_components.div></_components.div>{\\"\\\\n\\"}<_components.div className=\\"rspress-directive tip\\"><_components.div className=\\"rspress-directive-title\\">{\\"Custom Title\\"}</_components.div><_components.div className=\\"rspress-directive-content\\"><_components.p>{\\"\\\\nThis is a \\"}<_components.code>{\\"block\\"}</_components.code>{\\" of \\"}<_components.code>{\\"Custom Title\\"}</_components.code>{\\"\\\\n\\"}</_components.p></_components.div></_components.div>{\\"\\\\n\\"}<_components.div className=\\"rspress-directive tip\\"><_components.div className=\\"rspress-directive-title\\">{\\"Custom Title\\"}</_components.div><_components.div className=\\"rspress-directive-content\\"><_components.p>{\\"This is a \\"}<_components.code>{\\"block\\"}</_components.code>{\\" of \\"}<_components.code>{\\"Custom Title\\"}</_components.code>{\\"\\\\n\\"}</_components.p></_components.div></_components.div>{\\"\\\\n\\"}<_components.div className=\\"rspress-directive tip\\"><_components.div className=\\"rspress-directive-title\\">{\\"Custom Title\\"}</_components.div><_components.div className=\\"rspress-directive-content\\"><_components.p>{\\"This is a \\"}<_components.code>{\\"block\\"}</_components.code>{\\" of \\"}<_components.code>{\\"Custom Title\\"}</_components.code>{\\"\\\\n\\"}</_components.p></_components.div></_components.div></>;
return <><_components.h2 id=\\"custom-title\\">{\\"Container Title \\"}<_components.a className=\\"header-anchor\\" aria-hidden=\\"true\\" href=\\"#custom-title\\">{\\"#\\"}</_components.a></_components.h2>{\\"\\\\n\\"}<_components.div className=\\"rspress-directive tip\\"><_components.div className=\\"rspress-directive-title\\">{\\"Custom Title\\"}</_components.div><_components.div className=\\"rspress-directive-content\\"><_components.p>{\\"\\\\nThis is a \\"}<_components.code>{\\"block\\"}</_components.code>{\\" of \\"}<_components.code>{\\"Custom Title\\"}</_components.code>{\\"\\\\n\\"}</_components.p></_components.div></_components.div>{\\"\\\\n\\"}<_components.div className=\\"rspress-directive tip\\"><_components.div className=\\"rspress-directive-title\\">{\\"Custom Title\\"}</_components.div><_components.div className=\\"rspress-directive-content\\"><_components.p>{\\"\\\\nThis is a \\"}<_components.code>{\\"block\\"}</_components.code>{\\" of \\"}<_components.code>{\\"Custom Title\\"}</_components.code>{\\"\\\\n\\"}</_components.p></_components.div></_components.div>{\\"\\\\n\\"}<_components.div className=\\"rspress-directive tip\\"><_components.div className=\\"rspress-directive-title\\">{\\"Custom Title\\"}</_components.div><_components.div className=\\"rspress-directive-content\\"><_components.p>{\\"This is a \\"}<_components.code>{\\"block\\"}</_components.code>{\\" of \\"}<_components.code>{\\"Custom Title\\"}</_components.code>{\\"\\\\n\\"}</_components.p></_components.div></_components.div>{\\"\\\\n\\"}<_components.div className=\\"rspress-directive tip\\"><_components.div className=\\"rspress-directive-title\\">{\\"Custom Title\\"}</_components.div><_components.div className=\\"rspress-directive-content\\"><_components.p>{\\"This is a \\"}<_components.code>{\\"block\\"}</_components.code>{\\" of \\"}<_components.code>{\\"Custom Title\\"}</_components.code>{\\"\\\\n\\"}</_components.p></_components.div></_components.div></>;
}
function MDXContent(props = {}) {
const { wrapper: MDXLayout } = Object.assign({}, _provideComponents(), props.components);
Expand Down
1 change: 1 addition & 0 deletions __test__/compile-jsx.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Compile JSX
13 changes: 13 additions & 0 deletions __test__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,17 @@ describe("compile", () => {
expect(formatHTML(html)).toMatchSnapshot();
expect(result).toMatchSnapshot();
});

test("should compile jsx", async (t) => {
let { code: result, html } = await compile({
value: readFileSync(path.join(__dirname, "./compile-jsx.mdx"), "utf8"),
filepath: "xxx.mdx",
development: true,
root: "xxx",
jsx: false
});

expect(formatHTML(html)).toMatchSnapshot();
expect(result).toMatchSnapshot();
});
});
39 changes: 13 additions & 26 deletions crates/binding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub struct CompileOptions {
pub filepath: String,
pub development: bool,
pub root: String,
pub jsx: Option<bool>,
}

impl From<TocItem> for Toc {
Expand Down Expand Up @@ -89,47 +90,33 @@ impl Task for Compiler {
}

pub struct Compiler {
value: String,
filepath: String,
development: bool,
root: String,
options: CompileOptions,
}

impl Compiler {
pub fn new(value: String, filepath: String, development: bool, root: String) -> Self {
Self {
value,
filepath,
development,
root,
}
pub fn new(options: CompileOptions) -> Self {
Self { options }
}

fn compile(&mut self) -> CompileResult {
mdx_rs::compile(&self.value, &self.filepath, self.development, &self.root)
mdx_rs::compile(mdx_rs::CompileOptions {
value: self.options.value.clone(),
filepath: self.options.filepath.clone(),
development: self.options.development,
root: self.options.root.clone(),
jsx: self.options.jsx.unwrap_or(true),
})
}
}

/// Turn MDX into JavaScript.
#[napi(ts_return_type = "Promise<Output>")]
pub fn compile(options: CompileOptions) -> AsyncTask<Compiler> {
let CompileOptions {
value,
filepath,
development,
root,
} = options;
AsyncTask::new(Compiler::new(value, filepath, development, root))
AsyncTask::new(Compiler::new(options))
}

#[napi]
pub fn compile_sync(options: CompileOptions) -> Output {
let CompileOptions {
value,
filepath,
development,
root,
} = options;
let mut compiler = Compiler::new(value, filepath, development, root);
let mut compiler = Compiler::new(options);
compiler.compile().into()
}
61 changes: 44 additions & 17 deletions crates/mdx_rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use crate::{
swc_util_build_jsx::{swc_util_build_jsx, Options as BuildOptions},
};
use hast;
use hast_util_to_swc::Program;
use markdown::{to_mdast, Constructs, Location, ParseOptions};
use mdx_plugin_container::mdx_plugin_container;
use mdx_plugin_external_link::mdx_plugin_external_link;
Expand All @@ -40,9 +39,32 @@ use mdx_plugin_html::mdx_plugin_html;
use mdx_plugin_normalize_link::mdx_plugin_normalize_link;
use mdx_plugin_toc::{mdx_plugin_toc, TocItem};

pub use crate::configuration::{MdxConstructs, MdxParseOptions, Options};
pub use crate::mdx_plugin_recma_document::JsxRuntime;

pub struct CompileOptions {
pub value: String,
/// The root directory of the project.
pub root: String,
/// File path to the source file.
pub filepath: String,
/// Whether to add extra information to error messages in generated code
pub development: bool,
/// Whether to keep JSX (default: `true`).
pub jsx: bool,
}

impl Default for CompileOptions {
fn default() -> Self {
Self {
value: "".to_string(),
root: "".to_string(),
filepath: "".to_string(),
development: true,
jsx: true,
}
}
}

pub struct CompileResult {
pub code: String,
pub links: Vec<String>,
Expand All @@ -52,12 +74,15 @@ pub struct CompileResult {
pub frontmatter: String,
}

pub fn compile(
value: &String,
filepath: &String,
development: bool,
root: &String,
) -> CompileResult {
pub fn compile(options: CompileOptions) -> CompileResult {
let CompileOptions {
value,
filepath,
development,
root,
jsx,
} = options;

let is_mdx = filepath.ends_with(".mdx");
let parse_options = ParseOptions {
constructs: Constructs {
Expand Down Expand Up @@ -92,6 +117,7 @@ pub fn compile(
development,
provider_import_source: Some("@mdx-js/react".to_string()),
};
let build_options: BuildOptions = BuildOptions { development };
let location = Location::new(value.as_bytes());
let mut mdast = to_mdast(value.as_str(), &parse_options).unwrap_or_else(|error| {
eprintln!("File: {:?}\nError: {:?}", filepath, error);
Expand All @@ -107,7 +133,7 @@ pub fn compile(
mdx_plugin_header_anchor(&mut hast);
mdx_plugin_container(&mut hast);
mdx_plugin_external_link(&mut hast);
let links = mdx_plugin_normalize_link(&mut hast, root, filepath);
let links = mdx_plugin_normalize_link(&mut hast, &root, &filepath);
let html = mdx_plugin_html(&hast);
let mut program = hast_util_to_swc(&hast, Some(filepath.to_string()), Some(&location))
.unwrap_or_else(|error| {
Expand All @@ -129,8 +155,11 @@ pub fn compile(
},
);
mdx_plugin_recma_jsx_rewrite(&mut program, &rewrite_options, Some(&location));
// We keep the origin jsx here.
// swc_util_build_jsx(&mut program, &build_options, Some(&location)).unwrap();

if !jsx {
swc_util_build_jsx(&mut program, &build_options, Some(&location)).unwrap();
}

let code = serialize(&mut program.module, Some(&program.comments));
CompileResult {
code,
Expand All @@ -147,11 +176,9 @@ mod tests {
use super::*;
#[test]
fn test_collect_title_in_mdast() {
compile(
&"## Container Title {#custom-title}".to_string(),
&"".to_string(),
true,
&"".to_string(),
);
compile(CompileOptions {
value: "## Container Title {#custom-title}".to_string(),
..Default::default()
});
}
}
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface CompileOptions {
filepath: string
development: boolean
root: string
jsx?: boolean
}
/** Turn MDX into JavaScript. */
export function compile(options: CompileOptions): Promise<Output>
Expand Down
8 changes: 6 additions & 2 deletions tasks/benchmark/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ extern crate mdx_rs;
extern crate pico_args;

use criterion::{BenchmarkId, Criterion, Throughput};
use mdx_rs::compile;
use mdx_rs::{compile, CompileOptions};
use pico_args::Arguments;
use std::fs::File;
use std::io::prelude::*;
Expand Down Expand Up @@ -34,7 +34,11 @@ pub fn main() {
&contents,
|b, source_text| {
b.iter_with_large_drop(|| {
compile(&source_text, &"".to_string(), false, &"".to_string());
compile(CompileOptions {
value: source_text.to_string(),
development: false,
..Default::default()
});
})
},
);
Expand Down

0 comments on commit 2aae01c

Please sign in to comment.