aboutsummaryrefslogblamecommitdiffstats
path: root/tests/xxx_mdx_plugin_recma_jsx_rewrite.rs
blob: 77c794ad5a044a82d850aa441175d344ad250bb2 (plain) (tree)
1
2
3
4
5
6
7
8
9
               
                                                 

                                 



                                                                                            
                                                  


                                                                                   
                                                   
                         
              
                       

                                                                   
                                 

          
                                          



                                                                                            


       
                                                              






























































































































































































































































































































                                                                                                                                                                     























                                                                                                                                                                                                                                                                    

          
mod test_utils;
use markdown::{to_mdast, Location, ParseOptions};
use pretty_assertions::assert_eq;
use test_utils::{
    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},
    swc::{parse_esm, parse_expression, serialize},
};

fn from_markdown(value: &str, options: &RewriteOptions) -> Result<String, String> {
    let location = Location::new(value.as_bytes());
    let mdast = to_mdast(
        value,
        &ParseOptions {
            mdx_esm_parse: Some(Box::new(parse_esm)),
            mdx_expression_parse: Some(Box::new(parse_expression)),
            ..ParseOptions::mdx()
        },
    )?;
    let hast = mdast_util_to_hast(&mdast);
    let mut program = hast_util_to_swc(&hast, Some("example.mdx".into()), Some(&location))?;
    mdx_plugin_recma_document(&mut program, &DocumentOptions::default(), Some(&location))?;
    mdx_plugin_recma_jsx_rewrite(&mut program, options, Some(&location));
    Ok(serialize(&program.module))
}

#[test]
fn mdx_plugin_recma_jsx_rewrite_test() -> Result<(), String> {
    assert_eq!(
        from_markdown("", &Default::default())?,
        "function _createMdxContent(props) {
    return <></>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = props.components || {};
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
",
        "should work on an empty file",
    );

    assert_eq!(
        from_markdown("# hi", &Default::default())?,
        "function _createMdxContent(props) {
    const _components = Object.assign({
        h1: \"h1\"
    }, props.components);
    return <_components.h1 >{\"hi\"}</_components.h1>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = props.components || {};
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
",
        "should support passing in a layout (as `wrapper`) and components for literal tags",
    );

    assert_eq!(
        from_markdown(
            "export {MyLayout as default} from './a.js'\n\n# hi",
            &Default::default()
        )?,
        "import { MyLayout as MDXLayout } from './a.js';
function _createMdxContent(props) {
    const _components = Object.assign({
        h1: \"h1\"
    }, props.components);
    return <_components.h1 >{\"hi\"}</_components.h1>;
}
function MDXContent(props = {}) {
    return <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout>;
}
export default MDXContent;
",
        "should not support passing in a layout if one is defined locally",
    );

    assert_eq!(
        from_markdown("# <Hi />", &Default::default())?,
        "function _createMdxContent(props) {
    const _components = Object.assign({
        h1: \"h1\"
    }, props.components), { Hi  } = _components;
    if (!Hi) _missingMdxReference(\"Hi\", true);
    return <_components.h1 ><Hi /></_components.h1>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = props.components || {};
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
function _missingMdxReference(id, component) {
    throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");
}
",
        "should support passing in a component",
    );

    assert_eq!(
        from_markdown("<X />, <X.y />, <Y.Z />", &Default::default())?,
        "function _createMdxContent(props) {
    const _components = Object.assign({
        p: \"p\"
    }, props.components), { X , Y  } = _components;
    if (!X) _missingMdxReference(\"X\", true);
    if (!X.y) _missingMdxReference(\"X.y\", true);
    if (!Y) _missingMdxReference(\"Y\", false);
    if (!Y.Z) _missingMdxReference(\"Y.Z\", true);
    return <_components.p ><X />{\", \"}<X.y />{\", \"}<Y.Z /></_components.p>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = props.components || {};
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
function _missingMdxReference(id, component) {
    throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");
}
",
        "should support passing in component objects",
    );

    assert_eq!(
        from_markdown("import {Hi} from './a.js'\n\n# <Hi />", &Default::default())?,
        "import { Hi } from './a.js';
function _createMdxContent(props) {
    const _components = Object.assign({
        h1: \"h1\"
    }, props.components);
    return <_components.h1 ><Hi /></_components.h1>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = props.components || {};
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
",
        "should not support passing in a component if one is defined locally",
    );

    assert_eq!(
        from_markdown("# <a-b />", &Default::default())?,
        "function _createMdxContent(props) {
    const _components = Object.assign({
        h1: \"h1\",
        \"a-b\": \"a-b\"
    }, props.components), _component0 = _components[\"a-b\"];
    return <_components.h1 ><_component0 /></_components.h1>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = props.components || {};
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
",
        "should support passing in a component for a JSX identifier that is not a valid JS identifier",
    );

    assert_eq!(
        from_markdown("# <Hi />", &RewriteOptions {
            provider_import_source: Some("x".into()),
            ..Default::default()
        })?,
        "import { useMDXComponents as _provideComponents } from \"x\";
function _createMdxContent(props) {
    const _components = Object.assign({
        h1: \"h1\"
    }, _provideComponents(), props.components), { Hi  } = _components;
    if (!Hi) _missingMdxReference(\"Hi\", true);
    return <_components.h1 ><Hi /></_components.h1>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = Object.assign({}, _provideComponents(), props.components);
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
function _missingMdxReference(id, component) {
    throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");
}
",
        "should support providing a layout, literal tags, and components",
    );

    assert_eq!(
        from_markdown("", &RewriteOptions {
            provider_import_source: Some("x".into()),
            ..Default::default()
        })?,
        "import { useMDXComponents as _provideComponents } from \"x\";
function _createMdxContent(props) {
    return <></>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = Object.assign({}, _provideComponents(), props.components);
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
",
        "should support a provider on an empty file",
    );

    assert_eq!(
        from_markdown("<X />, <X.y />, <Y.Z />", &RewriteOptions {
            provider_import_source: Some("x".into()),
            ..Default::default()
        })?,
        "import { useMDXComponents as _provideComponents } from \"x\";
function _createMdxContent(props) {
    const _components = Object.assign({
        p: \"p\"
    }, _provideComponents(), props.components), { X , Y  } = _components;
    if (!X) _missingMdxReference(\"X\", true);
    if (!X.y) _missingMdxReference(\"X.y\", true);
    if (!Y) _missingMdxReference(\"Y\", false);
    if (!Y.Z) _missingMdxReference(\"Y.Z\", true);
    return <_components.p ><X />{\", \"}<X.y />{\", \"}<Y.Z /></_components.p>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = Object.assign({}, _provideComponents(), props.components);
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
function _missingMdxReference(id, component) {
    throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");
}
",
        "should support providing component objects",
    );

    assert_eq!(
        from_markdown("export function A() {
    return <B />
}

<A />
", &Default::default())?,
        "export function A() {
    return <B />;
}
function _createMdxContent(props) {
    return <A />;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = props.components || {};
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
",
        "should not support passing components in locally defined components",
    );

    assert_eq!(
        from_markdown("export function A() {
    return <B />
}

<A />
", &RewriteOptions {
    provider_import_source: Some("x".into()),
    ..Default::default()
})?,
        "import { useMDXComponents as _provideComponents } from \"x\";
export function A() {
    const { B  } = _provideComponents();
    if (!B) _missingMdxReference(\"B\", true);
    return <B />;
}
function _createMdxContent(props) {
    return <A />;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = Object.assign({}, _provideComponents(), props.components);
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
function _missingMdxReference(id, component) {
    throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");
}
",
        "should support providing components in locally defined components",
    );

    assert_eq!(
        from_markdown("export function A() {
    return <b-c />
}

<A />
", &RewriteOptions {
    provider_import_source: Some("x".into()),
    ..Default::default()
})?,
        "import { useMDXComponents as _provideComponents } from \"x\";
export function A() {
    const _components = Object.assign({
        \"b-c\": \"b-c\"
    }, _provideComponents()), _component0 = _components[\"b-c\"];
    return <_component0 />;
}
function _createMdxContent(props) {
    return <A />;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = Object.assign({}, _provideComponents(), props.components);
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
",
        "should support providing components with JSX identifiers that are not JS identifiers in locally defined components",
    );

    assert_eq!(
        from_markdown("export function A() {
    return <X />, <X.y />, <Y.Z />
}

<A />
", &RewriteOptions {
    provider_import_source: Some("x".into()),
    ..Default::default()
})?,
        "import { useMDXComponents as _provideComponents } from \"x\";
export function A() {
    const { X , Y  } = _provideComponents();
    if (!X) _missingMdxReference(\"X\", true);
    if (!X.y) _missingMdxReference(\"X.y\", true);
    if (!Y) _missingMdxReference(\"Y\", false);
    if (!Y.Z) _missingMdxReference(\"Y.Z\", true);
    return <X />, <X.y />, <Y.Z />;
}
function _createMdxContent(props) {
    return <A />;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = Object.assign({}, _provideComponents(), props.components);
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
function _missingMdxReference(id, component) {
    throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");
}
",
        "should support providing components with JSX identifiers that are not JS identifiers in locally defined components",
    );

    assert_eq!(
        from_markdown("# <Hi />", &RewriteOptions {
            development: true,
            ..Default::default()
        })?,
        "function _createMdxContent(props) {
    const _components = Object.assign({
        h1: \"h1\"
    }, props.components), { Hi  } = _components;
    if (!Hi) _missingMdxReference(\"Hi\", true, \"1:3-1:9\");
    return <_components.h1 ><Hi /></_components.h1>;
}
function MDXContent(props = {}) {
    const { wrapper: MDXLayout  } = props.components || {};
    return MDXLayout ? <MDXLayout {...props}><_createMdxContent {...props}/></MDXLayout> : _createMdxContent(props);
}
export default MDXContent;
function _missingMdxReference(id, component, place) {
    throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\" + (place ? \"\\nIt’s referenced in your code at `\" + place + \"` in `example.mdx`\" : \"\"));
}
",
        "should create missing reference helpers w/o positional info in `development` mode",
    );

    Ok(())
}