mdxjs-py


Namemdxjs-py JSON
Version 0.1.0a2 PyPI version JSON
download
home_pagehttps://github.com/SamDc73/mdxjs-py
SummaryPython bindings for mdxjs-rs - Fast MDX to JavaScript compilation via Rust
upload_time2025-09-01 06:52:34
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT
keywords mdx markdown jsx compiler rust mdxjs
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # mdxjs-py

Python bindings for [mdxjs-rs](https://github.com/wooorm/mdxjs-rs), a Rust implementation of MDX.

**⚠️ Alpha Software**: This package is in early development. The API may change between versions.

## Features

- Fast MDX compilation via Rust (10-100x faster than Node.js subprocess)
- Simple Python API mirroring @mdx-js/mdx
- Zero dependencies (beyond the compiled extension)
- Helpful error messages with line/column information
- Full MDX 2 support via mdxjs-rs

## Installation

```bash
pip install mdxjs-py
```

**Note**: Currently only Linux x86_64 wheels are provided. For other platforms, you'll need Rust installed to build from source:

```bash
# Install Rust first
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Then install from PyPI (will compile automatically)
pip install mdxjs-py
```

## Usage

### Basic Compilation

```python
from mdxjs_py import compile

# Compile MDX to JavaScript
mdx_content = """
# Hello World

This is **MDX** content with <Button onClick={() => alert('hi!')}>JSX</Button>!
"""

try:
    js_output = compile(mdx_content)
    print(js_output)
except ValueError as e:
    print(f"MDX compilation failed: {e}")
```

### Validation

Use `compile()` to validate MDX syntax:

```python
from mdxjs_py import compile

def validate_mdx(content: str) -> tuple[bool, str | None]:
    """Validate MDX content.

    Returns:
        (is_valid, error_message)
    """
    try:
        compile(content)
        return True, None
    except ValueError as e:
        return False, str(e)

# Example usage
content = "<Button>Unclosed tag"
is_valid, error = validate_mdx(content)
if not is_valid:
    print(f"Invalid MDX: {error}")
    # Output: Invalid MDX: Expected a closing tag for `<Button>`
```

### Configuration Options

```python
from mdxjs_py import compile

# With options (matches @mdx-js/mdx API)
js_output = compile(
    mdx_content,
    development=True,  # Enable development mode
    jsx_runtime="automatic",  # or "classic"
    jsx_import_source="react",  # for automatic runtime
)
```

## API Reference

### `compile(source: str, **options) -> str`

Compile MDX source to JavaScript. API-compatible with @mdx-js/mdx.

**Parameters:**

- `source` (str): The MDX source code to compile
- `development` (bool, optional): Enable development mode
- `jsx` (bool, optional): Keep JSX (default: False, compiles to JS)
- `jsx_runtime` (str, optional): "automatic" or "classic"
- `jsx_import_source` (str, optional): Package for automatic JSX runtime
- `pragma` (str, optional): JSX pragma for classic runtime
- `pragma_frag` (str, optional): JSX pragma fragment for classic runtime
- `pragma_import_source` (str, optional): Pragma import source
- `provider_import_source` (str, optional): Provider import source

**Returns:**

- `str`: Compiled JavaScript code

**Raises:**

- `ValueError`: If MDX compilation fails with detailed error message

### `compile_sync(source: str, **options) -> str`

Synchronous version of `compile()` (alias for compatibility).

### `is_available() -> bool`

Check if the Rust module is built and available.

## Common Use Cases

### 1. Validate User-Generated MDX

```python
def process_user_mdx(content: str) -> dict:
    """Process and validate user MDX content."""
    try:
        js_output = compile(content)
        return {
            "success": True,
            "output": js_output
        }
    except ValueError as e:
        # Extract line/column from error
        error_str = str(e)
        return {
            "success": False,
            "error": error_str,
            "hint": "Check for unclosed tags or invalid JSX"
        }
```

### 2. MDX Syntax Checking in CI/CD

```python
import glob
from pathlib import Path
from mdxjs_py import compile

def check_all_mdx_files(directory: str) -> bool:
    """Validate all MDX files in a directory."""
    all_valid = True

    for mdx_path in Path(directory).glob("**/*.mdx"):
        try:
            with open(mdx_path, 'r') as f:
                compile(f.read())
            print(f"✅ {mdx_path}")
        except ValueError as e:
            print(f"❌ {mdx_path}: {e}")
            all_valid = False

    return all_valid
```

### 3. Pre-process MDX for Frontend

```python
def prepare_mdx_for_frontend(content: str, max_retries: int = 3) -> str:
    """Validate and prepare MDX for frontend rendering."""
    for attempt in range(max_retries):
        try:
            # Validate compilation
            compile(content)
            return content
        except ValueError as e:
            if attempt == max_retries - 1:
                # Return with warning comment
                return f"<!-- MDX validation warning: {e} -->\n{content}"
            # Could attempt to fix common issues here
            content = fix_common_mdx_issues(content)

    return content
```

## Performance

Benchmarked on an Intel i7-9750H:

```python
import time
from mdxjs_py import compile

content = "# Heading\n\nParagraph with **bold** text.\n\n" * 100

# Single compilation
start = time.time()
compile(content)
print(f"Single: {(time.time() - start) * 1000:.2f}ms")
# Result: ~0.5ms

# Bulk compilation
start = time.time()
for _ in range(1000):
    compile(content)
print(f"1000x: {time.time() - start:.2f}s")
# Result: ~0.5s (vs ~50s with Node.js subprocess)
```

## Development

### Building from Source

```bash
# Clone the repository
git clone https://github.com/SamDc73/mdxjs-py
cd mdxjs-py

# Create virtual environment
python -m venv venv
source venv/bin/activate

# Install build dependencies
pip install maturin pytest

# Build and install locally
maturin develop --release

# Run tests
pytest tests/
```

### Architecture

This is a minimal Python binding to mdxjs-rs, designed for:

- **Zero overhead** - Direct 1:1 binding to mdxjs-rs functions
- **API compatibility** - Matches @mdx-js/mdx compile() API
- **Simplicity** - No abstraction layers, just the binding

## Credits

This package is a thin Python wrapper around:

- **[mdxjs-rs](https://github.com/wooorm/mdxjs-rs)** by [Titus Wormer](https://github.com/wooorm) - The Rust MDX implementation that does all the heavy lifting
- Built with **[PyO3](https://pyo3.rs)** - Rust bindings for Python
- Packaged with **[maturin](https://maturin.rs)** - Build and publish Rust Python extensions

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT License - see [LICENSE](LICENSE) file for details.

This package is MIT licensed, same as mdxjs-rs.

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for release history.

## Support

- 🐛 [Report bugs](https://github.com/SamDc73/mdxjs-py/issues)
- 💡 [Request features](https://github.com/SamDc73/mdxjs-py/issues)
- 📖 [Documentation](https://github.com/SamDc73/mdxjs-py#readme)


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/SamDc73/mdxjs-py",
    "name": "mdxjs-py",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "mdx, markdown, jsx, compiler, rust, mdxjs",
    "author": null,
    "author_email": null,
    "download_url": null,
    "platform": null,
    "description": "# mdxjs-py\n\nPython bindings for [mdxjs-rs](https://github.com/wooorm/mdxjs-rs), a Rust implementation of MDX.\n\n**\u26a0\ufe0f Alpha Software**: This package is in early development. The API may change between versions.\n\n## Features\n\n- Fast MDX compilation via Rust (10-100x faster than Node.js subprocess)\n- Simple Python API mirroring @mdx-js/mdx\n- Zero dependencies (beyond the compiled extension)\n- Helpful error messages with line/column information\n- Full MDX 2 support via mdxjs-rs\n\n## Installation\n\n```bash\npip install mdxjs-py\n```\n\n**Note**: Currently only Linux x86_64 wheels are provided. For other platforms, you'll need Rust installed to build from source:\n\n```bash\n# Install Rust first\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n\n# Then install from PyPI (will compile automatically)\npip install mdxjs-py\n```\n\n## Usage\n\n### Basic Compilation\n\n```python\nfrom mdxjs_py import compile\n\n# Compile MDX to JavaScript\nmdx_content = \"\"\"\n# Hello World\n\nThis is **MDX** content with <Button onClick={() => alert('hi!')}>JSX</Button>!\n\"\"\"\n\ntry:\n    js_output = compile(mdx_content)\n    print(js_output)\nexcept ValueError as e:\n    print(f\"MDX compilation failed: {e}\")\n```\n\n### Validation\n\nUse `compile()` to validate MDX syntax:\n\n```python\nfrom mdxjs_py import compile\n\ndef validate_mdx(content: str) -> tuple[bool, str | None]:\n    \"\"\"Validate MDX content.\n\n    Returns:\n        (is_valid, error_message)\n    \"\"\"\n    try:\n        compile(content)\n        return True, None\n    except ValueError as e:\n        return False, str(e)\n\n# Example usage\ncontent = \"<Button>Unclosed tag\"\nis_valid, error = validate_mdx(content)\nif not is_valid:\n    print(f\"Invalid MDX: {error}\")\n    # Output: Invalid MDX: Expected a closing tag for `<Button>`\n```\n\n### Configuration Options\n\n```python\nfrom mdxjs_py import compile\n\n# With options (matches @mdx-js/mdx API)\njs_output = compile(\n    mdx_content,\n    development=True,  # Enable development mode\n    jsx_runtime=\"automatic\",  # or \"classic\"\n    jsx_import_source=\"react\",  # for automatic runtime\n)\n```\n\n## API Reference\n\n### `compile(source: str, **options) -> str`\n\nCompile MDX source to JavaScript. API-compatible with @mdx-js/mdx.\n\n**Parameters:**\n\n- `source` (str): The MDX source code to compile\n- `development` (bool, optional): Enable development mode\n- `jsx` (bool, optional): Keep JSX (default: False, compiles to JS)\n- `jsx_runtime` (str, optional): \"automatic\" or \"classic\"\n- `jsx_import_source` (str, optional): Package for automatic JSX runtime\n- `pragma` (str, optional): JSX pragma for classic runtime\n- `pragma_frag` (str, optional): JSX pragma fragment for classic runtime\n- `pragma_import_source` (str, optional): Pragma import source\n- `provider_import_source` (str, optional): Provider import source\n\n**Returns:**\n\n- `str`: Compiled JavaScript code\n\n**Raises:**\n\n- `ValueError`: If MDX compilation fails with detailed error message\n\n### `compile_sync(source: str, **options) -> str`\n\nSynchronous version of `compile()` (alias for compatibility).\n\n### `is_available() -> bool`\n\nCheck if the Rust module is built and available.\n\n## Common Use Cases\n\n### 1. Validate User-Generated MDX\n\n```python\ndef process_user_mdx(content: str) -> dict:\n    \"\"\"Process and validate user MDX content.\"\"\"\n    try:\n        js_output = compile(content)\n        return {\n            \"success\": True,\n            \"output\": js_output\n        }\n    except ValueError as e:\n        # Extract line/column from error\n        error_str = str(e)\n        return {\n            \"success\": False,\n            \"error\": error_str,\n            \"hint\": \"Check for unclosed tags or invalid JSX\"\n        }\n```\n\n### 2. MDX Syntax Checking in CI/CD\n\n```python\nimport glob\nfrom pathlib import Path\nfrom mdxjs_py import compile\n\ndef check_all_mdx_files(directory: str) -> bool:\n    \"\"\"Validate all MDX files in a directory.\"\"\"\n    all_valid = True\n\n    for mdx_path in Path(directory).glob(\"**/*.mdx\"):\n        try:\n            with open(mdx_path, 'r') as f:\n                compile(f.read())\n            print(f\"\u2705 {mdx_path}\")\n        except ValueError as e:\n            print(f\"\u274c {mdx_path}: {e}\")\n            all_valid = False\n\n    return all_valid\n```\n\n### 3. Pre-process MDX for Frontend\n\n```python\ndef prepare_mdx_for_frontend(content: str, max_retries: int = 3) -> str:\n    \"\"\"Validate and prepare MDX for frontend rendering.\"\"\"\n    for attempt in range(max_retries):\n        try:\n            # Validate compilation\n            compile(content)\n            return content\n        except ValueError as e:\n            if attempt == max_retries - 1:\n                # Return with warning comment\n                return f\"<!-- MDX validation warning: {e} -->\\n{content}\"\n            # Could attempt to fix common issues here\n            content = fix_common_mdx_issues(content)\n\n    return content\n```\n\n## Performance\n\nBenchmarked on an Intel i7-9750H:\n\n```python\nimport time\nfrom mdxjs_py import compile\n\ncontent = \"# Heading\\n\\nParagraph with **bold** text.\\n\\n\" * 100\n\n# Single compilation\nstart = time.time()\ncompile(content)\nprint(f\"Single: {(time.time() - start) * 1000:.2f}ms\")\n# Result: ~0.5ms\n\n# Bulk compilation\nstart = time.time()\nfor _ in range(1000):\n    compile(content)\nprint(f\"1000x: {time.time() - start:.2f}s\")\n# Result: ~0.5s (vs ~50s with Node.js subprocess)\n```\n\n## Development\n\n### Building from Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/SamDc73/mdxjs-py\ncd mdxjs-py\n\n# Create virtual environment\npython -m venv venv\nsource venv/bin/activate\n\n# Install build dependencies\npip install maturin pytest\n\n# Build and install locally\nmaturin develop --release\n\n# Run tests\npytest tests/\n```\n\n### Architecture\n\nThis is a minimal Python binding to mdxjs-rs, designed for:\n\n- **Zero overhead** - Direct 1:1 binding to mdxjs-rs functions\n- **API compatibility** - Matches @mdx-js/mdx compile() API\n- **Simplicity** - No abstraction layers, just the binding\n\n## Credits\n\nThis package is a thin Python wrapper around:\n\n- **[mdxjs-rs](https://github.com/wooorm/mdxjs-rs)** by [Titus Wormer](https://github.com/wooorm) - The Rust MDX implementation that does all the heavy lifting\n- Built with **[PyO3](https://pyo3.rs)** - Rust bindings for Python\n- Packaged with **[maturin](https://maturin.rs)** - Build and publish Rust Python extensions\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\nThis package is MIT licensed, same as mdxjs-rs.\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for release history.\n\n## Support\n\n- \ud83d\udc1b [Report bugs](https://github.com/SamDc73/mdxjs-py/issues)\n- \ud83d\udca1 [Request features](https://github.com/SamDc73/mdxjs-py/issues)\n- \ud83d\udcd6 [Documentation](https://github.com/SamDc73/mdxjs-py#readme)\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python bindings for mdxjs-rs - Fast MDX to JavaScript compilation via Rust",
    "version": "0.1.0a2",
    "project_urls": {
        "Changelog": "https://github.com/SamDc73/mdxjs-py/blob/main/CHANGELOG.md",
        "Documentation": "https://github.com/SamDc73/mdxjs-py#readme",
        "Homepage": "https://github.com/SamDc73/mdxjs-py",
        "Issues": "https://github.com/SamDc73/mdxjs-py/issues",
        "Repository": "https://github.com/SamDc73/mdxjs-py"
    },
    "split_keywords": [
        "mdx",
        " markdown",
        " jsx",
        " compiler",
        " rust",
        " mdxjs"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "76c57866d41c1c4ed980fff211f5bfb8b6713e00f17d94e510a80afd6b873212",
                "md5": "7d8d24667c39fe1ad25685d3e2bf25ac",
                "sha256": "5ef2b2c99ae57707a565a4a967a06157a5f3e12cb1f0dc992320af49e434b63d"
            },
            "downloads": -1,
            "filename": "mdxjs_py-0.1.0a2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "7d8d24667c39fe1ad25685d3e2bf25ac",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.8",
            "size": 2143432,
            "upload_time": "2025-09-01T06:52:34",
            "upload_time_iso_8601": "2025-09-01T06:52:34.827703Z",
            "url": "https://files.pythonhosted.org/packages/76/c5/7866d41c1c4ed980fff211f5bfb8b6713e00f17d94e510a80afd6b873212/mdxjs_py-0.1.0a2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-01 06:52:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "SamDc73",
    "github_project": "mdxjs-py",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "mdxjs-py"
}
        
Elapsed time: 1.23313s