whyml

WhyML Converters

PyPI version Python Support License WhyML Ecosystem

๐Ÿš€ Multi-format code generation from WhyML manifests - HTML, React, Vue.js, and PHP applications

Advanced code generation system that converts structured YAML manifests into production-ready applications across multiple technologies. Built with modern patterns, best practices, and comprehensive framework support.

๐Ÿ”ง Recent API Updates (2025)

โœ… ENHANCED COMPATIBILITY: All converters now include synchronous convert() methods that wrap the existing async convert_manifest() methods for better test compatibility and direct usage.

โœ… CONSTRUCTOR PARAMETERS: Added expected constructor parameters:

โœ… BASE CONVERTER: Enhanced BaseConverter to accept css_framework, namespace, use_typescript and other common parameters via flexible kwargs system.

โœ… CONVERSION RESULT: Added filename parameter and format_type property to ConversionResult class for enhanced compatibility.

๐Ÿš€ Features

Multi-Format Support

Advanced Generation Capabilities

Code Quality Features

๐Ÿ“ฆ Installation

pip install whyml-converters

Or install with development dependencies:

pip install whyml-converters[dev]

๐Ÿ Quick Start

Basic Usage

from whyml_converters import HTMLConverter, ReactConverter, VueConverter, PHPConverter

# Load your WhyML manifest
manifest = {
    "metadata": {
        "title": "My App",
        "description": "A sample application"
    },
    "structure": {
        "tag": "div",
        "attributes": {"class": "container"},
        "children": [
            {
                "tag": "h1",
                "content": "Welcome to "
            }
        ]
    }
}

# Convert to different formats
html_converter = HTMLConverter()
html_output = await html_converter.convert_manifest(manifest)

react_converter = ReactConverter()
react_output = await react_converter.convert_manifest(
    manifest, 
    typescript=True,
    component_type='functional'
)

vue_converter = VueConverter()
vue_output = await vue_converter.convert_manifest(
    manifest,
    composition_api=True,
    scoped=True
)

php_converter = PHPConverter()
php_output = await php_converter.convert_manifest(
    manifest,
    use_classes=True,
    namespace="MyApp"
)

Save to Files

# Save generated code to files
await html_converter.save_to_file(manifest, "output/index.html")
await react_converter.save_to_file(manifest, "output/App.tsx", typescript=True)
await vue_converter.save_to_file(manifest, "output/App.vue")
await php_converter.save_to_file(manifest, "output/Page.php")

๐ŸŽฏ Converter-Specific Features

HTML Converter

html_output = await HTMLConverter().convert_manifest(
    manifest,
    doctype="html5",              # HTML5 doctype
    semantic_structure=True,      # Use semantic HTML5 tags  
    include_meta_viewport=True,   # Responsive viewport meta
    css_framework="bootstrap",    # CSS framework integration
    minify=False                  # Readable output
)

Features:

React Converter

react_output = await ReactConverter().convert_manifest(
    manifest,
    typescript=True,              # TypeScript support
    component_type='functional',  # Functional components
    use_hooks=True,              # React Hooks
    css_in_js=True,              # CSS-in-JS styling
    props_interface=True,        # TypeScript interfaces
    export_default=True          # Default export
)

Features:

Vue.js Converter

vue_output = await VueConverter().convert_manifest(
    manifest,
    composition_api=True,         # Composition API
    typescript=True,              # TypeScript in <script setup>
    scoped=True,                 # Scoped CSS
    css_preprocessor='scss',     # SCSS support
    component_name='MyComponent' # Custom component name
)

Features:

PHP Converter

php_output = await PHPConverter().convert_manifest(
    manifest,
    use_classes=True,            # Class-based approach
    namespace="MyApp\\Pages",    # PSR-4 namespacing
    strict_types=True,           # Strict type declarations
    php_version="8.1",          # Target PHP version
    extends="BasePage",          # Class inheritance
    include_usage=True           # Usage examples
)

Features:

๐Ÿ—๏ธ Advanced Usage

Custom Template Variables

manifest_with_variables = {
    "metadata": {
        "title": "",
        "variables": {
            "app_name": "My Custom App",
            "version": "1.0.0",
            "author": "Developer Name"
        }
    },
    "structure": {
        "tag": "header",
        "children": [
            {
                "tag": "h1", 
                "content": " v"
            },
            {
                "tag": "p",
                "content": "Created by "
            }
        ]
    }
}

# Variables will be substituted during conversion
output = await converter.convert_manifest(manifest_with_variables)

Component Generation

# React component with props
react_component = await ReactConverter().convert_manifest(
    manifest,
    component_name="ProductCard",
    props={
        "title": {"type": "string", "required": True},
        "price": {"type": "number", "required": True},
        "onAddToCart": {"type": "function", "required": False}
    },
    typescript=True
)

# Vue component with props
vue_component = await VueConverter().convert_manifest(
    manifest,
    component_name="ProductCard",
    props={
        "title": {"type": "String", "required": True},
        "price": {"type": "Number", "required": True}
    },
    composition_api=True
)

Style Integration

manifest_with_styles = {
    "structure": {...},
    "styles": {
        "inline_styles": {
            "header": {
                "background-color": "#f8f9fa",
                "padding": "1rem",
                "border-radius": "0.5rem"
            }
        },
        "internal_styles": {
            "responsive": {
                "@media (max-width: 768px)": {
                    ".container": {
                        "padding": "0.5rem"
                    }
                }
            }
        }
    }
}

# Styles will be properly integrated into each format
html_output = await HTMLConverter().convert_manifest(manifest_with_styles)
vue_output = await VueConverter().convert_manifest(manifest_with_styles, scoped=True)

๐Ÿ”ง Configuration

Base Converter Settings

All converters inherit from BaseConverter and support:

converter = HTMLConverter(
    template_engine='jinja2',     # Template engine
    auto_escape=True,            # Template auto-escaping
    validate_manifest=True,      # Input validation
    include_comments=True,       # Code comments
    format_output=True          # Pretty formatting
)

Framework-Specific Options

# HTML-specific
html_converter = HTMLConverter(
    html_version="5",
    include_viewport_meta=True,
    semantic_structure=True
)

# React-specific  
react_converter = ReactConverter(
    react_version="18",
    use_strict_mode=True,
    jsx_pragma="React"
)

# Vue-specific
vue_converter = VueConverter(
    vue_version="3",
    use_composition_api=True,
    enable_devtools=True
)

# PHP-specific
php_converter = PHPConverter(
    php_version="8.1",
    use_declare_strict_types=True,
    psr_compliance=True
)

๐Ÿ“š API Reference

BaseConverter

The abstract base class for all converters:

class BaseConverter:
    async def convert_manifest(self, manifest: Dict[str, Any], **options) -> str
    async def save_to_file(self, manifest: Dict[str, Any], output_path: Path, **options) -> None
    def validate_manifest(self, manifest: Dict[str, Any]) -> bool
    def extract_metadata(self, manifest: Dict[str, Any]) -> Dict[str, Any]
    def extract_structure(self, manifest: Dict[str, Any]) -> Dict[str, Any]
    def extract_styles(self, manifest: Dict[str, Any]) -> Dict[str, Any]
    def extract_scripts(self, manifest: Dict[str, Any]) -> Dict[str, Any]

Format-Specific Converters

Each converter extends BaseConverter with format-specific methods:

# HTML Converter
class HTMLConverter(BaseConverter):
    def generate_doctype(self, version: str) -> str
    def generate_meta_tags(self, metadata: Dict[str, Any]) -> str
    def generate_html_structure(self, structure: Dict[str, Any]) -> str

# React Converter  
class ReactConverter(BaseConverter):
    def generate_jsx_component(self, structure: Dict[str, Any]) -> str
    def generate_typescript_interface(self, props: Dict[str, Any]) -> str
    def generate_react_hooks(self, component_logic: Dict[str, Any]) -> str

# Vue Converter
class VueConverter(BaseConverter):  
    def generate_vue_template(self, structure: Dict[str, Any]) -> str
    def generate_composition_api_logic(self, component_logic: Dict[str, Any]) -> str
    def generate_vue_style(self, styles: Dict[str, Any]) -> str

# PHP Converter
class PHPConverter(BaseConverter):
    def generate_php_class(self, manifest: Dict[str, Any]) -> str
    def generate_php_methods(self, structure: Dict[str, Any]) -> str
    def generate_php_properties(self, metadata: Dict[str, Any]) -> str

๐Ÿงช Testing

Run the test suite:

# Run all tests
pytest

# Run with coverage
pytest --cov=whyml_converters --cov-report=html

# Run specific converter tests
pytest tests/test_html_converter.py
pytest tests/test_react_converter.py
pytest tests/test_vue_converter.py  
pytest tests/test_php_converter.py

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

# Clone the repository
git clone https://github.com/dynapsys/whyml.git
cd whyml/whyml-converters

# Install development dependencies
pip install -e .[dev]

# Run formatting and linting
black whyml_converters/
isort whyml_converters/
flake8 whyml_converters/
mypy whyml_converters/

# Run tests
pytest

Adding New Converters

To add support for a new output format:

  1. Create a new converter class extending BaseConverter
  2. Implement the required abstract methods
  3. Add format-specific generation methods
  4. Create comprehensive tests
  5. Update documentation

Example:

from whyml_converters import BaseConverter

class CustomConverter(BaseConverter):
    def _get_output_format(self) -> str:
        return "custom"
    
    def _get_template_extension(self) -> str:
        return ".custom"
    
    async def convert_manifest(self, manifest: Dict[str, Any], **options) -> str:
        # Implement conversion logic
        pass

๐Ÿ“„ License

Licensed under the Apache License, Version 2.0. See LICENSE for details.

๐Ÿ“ž Support


WhyML Converters - Transform your ideas into code across multiple technologies. ๐Ÿš€