TypeDialog Logo
# Nickel Schema Support Full support for type-safe form schemas using the Nickel language. ## Overview TypeDialog integrates Nickel for: - **Type-safe schemas** - Validate form structure at parse time - **Contract validation** - Enforce type and content contracts - **I18n extraction** - Auto-extract translatable strings - **Template rendering** - Generate forms via Tera templates - **Roundtrip support** - Idempotent read/write transformations ## Quick Start ### Prerequisites Install Nickel CLI (optional, for schema validation): ```bash cargo install nickel-lang # Or download from: https://github.com/nickel-lang/nickel/releases ``` ### Run Examples ```bash # List all Nickel examples just test::list | grep nickel # Run basic Nickel schema cargo run --example basic_nickel_schema # Run with roundtrip (read, transform, write) cargo run --example nickel_roundtrip # Run with i18n extraction cargo run --example nickel_i18n_extraction ``` See [examples/07-nickel-generation/](../examples/07-nickel-generation/) for complete examples. ## Core Modules ### contract_parser Parse and validate Nickel contracts. ```rust use typedialog_core::nickel::ContractParser; let parser = ContractParser::new(); let contracts = parser.parse(nickel_schema)?; ``` **Validates:** - Type correctness - Field constraints - Required vs optional fields - Custom predicates ### i18n_extractor Automatically extract translatable strings from Nickel schemas. ```rust use typedialog_core::nickel::I18nExtractor; let extractor = I18nExtractor::new(); let strings = extractor.extract(nickel_ast)?; // Output: Map of translatable strings with locations ``` **Extracts:** - Field labels - Help text - Error messages - Custom metadata ### template_renderer Render Nickel schemas using Tera templates. ```rust use typedialog_core::nickel::NickelTemplateContext; let context = NickelTemplateContext::from_schema(schema)?; let rendered = template_engine.render("form.j2", &context)?; ``` **Supports:** - Tera template syntax - Schema introspection - Custom filters - Conditional rendering ### roundtrip Idempotent read/write for Nickel schemas. ```rust use typedialog_core::nickel::RoundtripConfig; let config = RoundtripConfig::default(); let schema = parser.parse_file("form.ncl")?; let modified = transform(schema)?; serializer.write_file("form.ncl", &modified, &config)?; ``` **Preserves:** - Comments - Formatting - Import structure - Custom layouts ## Schema Structure ### Basic Form ```nicl { title = "User Registration", fields = { name = { type = "text", label = "Full Name", required = true, }, email = { type = "email", label = "Email Address", required = true, }, } } ``` ### With Contracts ```nicl { fields = { password = { type = "text", label = "Password", contracts = [ { predicate = |s| string.length s >= 8, error = "Min 8 chars" }, { predicate = |s| string.contains s "!", error = "Need special char" }, ] } } } ``` ### With I18n ```nicl { i18n = "en-US", fields = { name = { label = "i18n:form.fields.name", help = "i18n:form.fields.name.help", } } } ``` ### With Templates ```nicl { template = "form.j2", context = { theme = "dark", layout = "grid", }, fields = { ... } } ``` ## Building with Nickel Build project with Nickel support: ```bash # Build (includes Nickel feature by default) just build::default # Test Nickel modules just test::core # Generate docs just dev::docs ``` ## Examples Complete examples in [examples/07-nickel-generation/](../examples/07-nickel-generation/): ### Schemas - **simple.ncl** - Basic form schema - **complex.ncl** - Advanced with sections and groups - **conditional.ncl** - Conditional field visibility - **i18n.ncl** - Internationalization example ### Templates - **config.ncl.j2** - Configuration form template - **deployment.ncl.j2** - Deployment spec template - **service_spec.ncl.j2** - Service specification template ### Usage ```bash cd examples/07-nickel-generation/ # Validate schema nickel export schemas/simple.ncl # Parse and render cargo run --manifest-path ../../Cargo.toml \ --example nickel_form_generation < schemas/simple.ncl ``` ## Integration Patterns ### CLI Backend ```bash typedialog --format nickel form.ncl ``` ### TUI Backend ```bash typedialog-tui form.ncl ``` ### Web Backend ```bash typedialog-web --config form.ncl ``` ## Advanced Topics ### Custom Contracts Define custom validation predicates: ```nicl { fields = { age = { type = "number", contracts = [ { predicate = |n| n >= 18, error = "Must be 18+" } ] } } } ``` ### Reusable Components ```nicl let address_fields = { street = { type = "text", label = "Street" }, city = { type = "text", label = "City" }, zip = { type = "text", label = "ZIP" }, }; { fields = address_fields & { country = { type = "select", label = "Country" } } } ``` ### Schema Inheritance Extend base schemas: ```nicl let base = import "schemas/base.ncl"; base & { fields = base.fields & { custom_field = { ... } } } ``` ### I18n Management Extract and manage translations: ```bash # Extract all translatable strings cargo run --example nickel_i18n_extraction < form.ncl > strings.json # Update translations # (use with translation management system) ``` ## Performance Considerations ### Parsing - Schemas parsed once at startup - AST cached in memory - Validation is O(n) in field count ### Rendering - Templates compiled once - Context generation O(n) - Output streamed for large forms ### Roundtrip - Preserves source formatting - Minimal allocations - In-place transformations ## Troubleshooting ### Schema validation fails Check syntax with Nickel CLI: ```bash nickel export form.ncl ``` ### Contract errors Verify predicates are boolean functions: ```nicl # ❌ Wrong contracts = [ { predicate = |s| string.length s, error = "..." } ] # ✓ Correct contracts = [ { predicate = |s| string.length s >= 8, error = "..." } ] ``` ### Template rendering fails Ensure Tera template exists and context matches: ```bash # Verify template ls -la templates/form.j2 # Check context keys cargo run --example nickel_template_context < form.ncl ``` ### I18n strings not extracted Verify string format: ```nicl # ❌ Plain string label = "Name" # ✓ I18n reference label = "i18n:form.name" ``` ## Best Practices 1. **Schema Organization** - Keep schemas modular - Use `import` for shared components - Version schemas in git 2. **Contracts** - Keep predicates simple - Provide clear error messages - Test edge cases 3. **I18n** - Use consistent key naming - Extract before translations - Validate all strings are referenced 4. **Templates** - Keep templates simple - Use filters for formatting - Test with multiple data types 5. **Roundtrip** - Always test read/write cycles - Preserve comments with care - Validate output structure ## API Reference ### ContractParser ```rust pub struct ContractParser; impl ContractParser { pub fn new() -> Self; pub fn parse(&self, source: &str) -> Result; } pub struct ParsedContracts { pub fields: Map, pub global: Vec, } ``` ### I18nExtractor ```rust pub struct I18nExtractor; impl I18nExtractor { pub fn new() -> Self; pub fn extract(&self, ast: &NickelAst) -> Result; } ``` ### NickelTemplateContext ```rust pub struct NickelTemplateContext { pub schema: NickelSchemaIR, pub fields: Map, } impl NickelTemplateContext { pub fn from_schema(schema: NickelSchemaIR) -> Result; } ``` ### RoundtripConfig ```rust pub struct RoundtripConfig { pub preserve_comments: bool, pub preserve_formatting: bool, pub indent: String, } impl Default for RoundtripConfig { fn default() -> Self { Self { preserve_comments: true, preserve_formatting: true, indent: " ".to_string(), } } } ``` ## Next Steps - [DEVELOPMENT.md](DEVELOPMENT.md) - Build and test - [CONFIGURATION.md](CONFIGURATION.md) - Backend configuration - [Examples](../examples/07-nickel-generation/) - Complete examples - [Nickel Language](https://nickel-lang.org) - Language reference --- **Latest Update**: December 2024 **Status**: Stable