WhyML supports conversion to multiple output formats through specialized converters. Each converter transforms YAML manifests into format-specific code while preserving the semantic structure and styling.
# Basic conversion
whyml convert --from manifest.yaml --to page.html --as html
# With configuration file
whyml convert --from manifest.yaml --to page.html --as html --config config.yaml
config:
html:
doctype: "html5" # html5, html4, xhtml
include_meta_tags: true # Include SEO meta tags
responsive_design: true # Include responsive viewport
minify_output: false # Minify HTML output
semantic_elements: true # Use semantic HTML5 elements
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Title</title>
<style>
.container { max-width: 1200px; margin: 0 auto; }
</style>
</head>
<body>
<div class="container">
<header class="header">
<h1>Welcome</h1>
</header>
</div>
</body>
</html>
# TypeScript React component
whyml convert --from manifest.yaml --to Component.tsx --as react
# JavaScript React component
whyml convert --from manifest.yaml --to Component.jsx --as react
config:
react:
use_typescript: true # Generate TypeScript interfaces
use_hooks: true # Use React hooks (useState, useEffect)
css_framework: "css-modules" # css-modules, styled-components, emotion
export_default: true # Use default export
component_type: "functional" # functional, class
import React, { useState, useEffect } from 'react';
import styles from './Component.module.css';
interface Props {
className?: string;
style?: React.CSSProperties;
}
const Component: React.FC<Props> = (props) => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Component mounted');
}, []);
const handleClick = () => {
setCount(count + 1);
};
return (
<div className={styles.container}>
<h1>Welcome</h1>
<button onClick={handleClick}>
Count: {count}
</button>
</div>
);
};
export default Component;
# Vue 3 with Composition API
whyml convert manifest.yaml --to vue --composition-api --output Component.vue
# Vue 2 compatible
whyml convert manifest.yaml --to vue --vue-version 2 --output Component.vue
config:
vue:
version: 3 # Vue version (2 or 3)
use_composition_api: true # Use Composition API (Vue 3)
scoped_styles: true # Use scoped CSS
typescript: true # Use TypeScript in script
css_preprocessor: "scss" # css, scss, sass, less
<template>
<div class="container">
<h1></h1>
<button @click="increment">
Count: 8
</button>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'Component',
setup() {
const count = ref(0);
const title = ref('Welcome');
const increment = () => {
count.value++;
};
return {
count,
title,
increment
};
}
});
</script>
<style scoped>
.container {
max-width: 1200px;
margin: 0 auto;
}
</style>
# PHP class with namespace
whyml convert manifest.yaml --to php --namespace "App\\Components" --output Component.php
# With type declarations
whyml convert manifest.yaml --to php --type-declarations --output Component.php
config:
php:
namespace: "App\\Components" # PHP namespace
use_type_declarations: true # Use PHP type hints
class_suffix: "Component" # Class name suffix
extends_class: null # Parent class to extend
implements: [] # Interfaces to implement
<?php
namespace App\Components;
class PageComponent
{
private array $data = [];
private array $styles = [
'container' => 'max-width: 1200px; margin: 0 auto;'
];
public function __construct(array $data = []): void
{
$this->data = $data;
}
public function render(): string
{
$html = '';
$html .= '<div class="container">';
$html .= '<h1>' . $this->escapeHtml($this->getData('title', 'Welcome')) . '</h1>';
$html .= '</div>';
return $html;
}
public function getStyles(): string
{
$css = '';
foreach ($this->styles as $selector => $rules) {
$css .= ".{$selector} { {$rules} }\n";
}
return $css;
}
private function escapeHtml(string $content): string
{
return htmlspecialchars($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
private function getData(string $key, mixed $default = null): mixed
{
return $this->data[$key] ?? $default;
}
}
All converters support template variable substitution:
variables:
primary_color: "#007bff"
component_name: "MyComponent"
structure:
div:
style: "color: "
text: "Welcome to "
Converters can integrate with popular CSS frameworks:
imports:
css:
- "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
config:
css_framework: "bootstrap" # bootstrap, tailwind, foundation
All converters support responsive design patterns:
styles:
.container:
max-width: "1200px"
margin: "0 auto"
"@media (max-width: 768px)":
.container:
padding: "10px"
Converters automatically include accessibility features:
import asyncio
from whyml import WhyMLProcessor
async def convert_manifest():
processor = WhyMLProcessor()
# Convert to HTML
html_result = await processor.convert_to_html('manifest.yaml')
html_result.save_to_file('output.html')
# Convert to React with options
react_result = await processor.convert_to_react(
'manifest.yaml',
use_typescript=True,
css_modules=True
)
react_result.save_to_file('Component.tsx')
# Convert to Vue
vue_result = await processor.convert_to_vue(
'manifest.yaml',
composition_api=True
)
vue_result.save_to_file('Component.vue')
# Convert to PHP
php_result = await processor.convert_to_php(
'manifest.yaml',
namespace='App\\Components'
)
php_result.save_to_file('Component.php')
asyncio.run(convert_manifest())
Each converter returns a ConversionResult object:
class ConversionResult:
content: str # Generated code content
filename: str # Suggested filename
format_type: str # Output format (html, react, vue, php)
metadata: dict # Conversion metadata
def save_to_file(self, path: str) -> None:
"""Save content to file"""
def get_size(self) -> int:
"""Get content size in bytes"""
HTML:
React:
Vue:
PHP:
Enable debug mode for detailed conversion information:
whyml convert manifest.yaml --to react --debug --output Component.tsx
See the examples directory for complete working examples of each converter type.