colap 0.1.0

A lightweight, human-friendly configuration language parser & code generator
docs.rs failed to build colap-0.1.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

πŸ₯€ colap – A Refreshingly Simple Configuration Language Parser & Code Generator


Tired of fighting with your config files? So were we.

cola is a lightweight, human-friendly configuration language designed to avoid YAML’s whitespace traps, JSON’s curly-brace fatigue, and TOML’s dotted-key spaghetti. It’s backed by colap, a Rust parser and code generator that makes working with configurations effortless.

Cola is:

βœ… Readable – Clean nesting with minimal punctuation.
βœ… Writable – No indentation anxiety. No trailing comma drama.
βœ… Composable – Works standalone or embedded in Markdown as fenced cola ... blocks.


πŸš€ Why cola?

YAML: Tabs vs Spaces

Miss one indent, and your app silently loads nonsense.

JSON: Curly Braces Forever

Nested configs turn into a forest of {} and [].

TOML: Dotted-Key Spaghetti

Deep nesting forces verbose dotted keys or confusing table headers.

cola: Refreshingly Simple

  • πŸ†“ Not whitespace sensitive – Tabs? Spaces? Mix them. Cola doesn’t care.
  • βœ… Minimal punctuation – Just : for nesting and ; to end blocks.
  • 🏷️ Infix plural syntax – Explicitly name singular and plural forms for code generators.
  • πŸ“„ Markdown-native – Embed configs directly in documentation.

πŸ“– Example Configuration

Here's a real-world configuration defining multiple LLM providers:

llm plural llms:
    openai:
        api:
            type: "REST",
            key: "some_api_key",
            base_url: "some_base_url"
        ;

        model plural models:
            gpt-4.1:
                name: "gpt-4.1",
                max_input_tokens: 1048576,
                output_price: 8.0,
                supports_vision: true
            ;
            gpt-4o:
                name: "gpt-4o",
                max_input_tokens: 1048576,
                output_price: 8.0,
                supports_vision: true
            ;
        ;
    ;
;

πŸ†š cola vs YAML / JSON / TOML

Feature YAML JSON TOML cola
Whitespace sensitivity 😬 Yes πŸ‘ No πŸ‘ No βœ… No
Curly brace clutter πŸ‘ Minimal 😩 Lots πŸ‘ Minimal βœ… Minimal
Trailing commas allowed ❌ No ❌ No βœ… Yes βœ… Yes
Multi-line strings πŸ€” Hard πŸ˜• Escapes βœ… Easy βœ… Easy
Collections (arrays/maps) πŸ˜• Indents 😩 [], {} πŸ˜• Mixed βœ… Infix plural
Markdown embedding ❌ Awkward ❌ Awkward ❌ Awkward βœ… First-class

🎯 Design Philosophy

πŸ”Ή Why Semicolons?

Cola uses ; as a block terminator:

  • Prevents ambiguity at the end of nested blocks.
  • Avoids silent parsing errors from missing indentation (YAML) or commas (JSON).
  • Familiar and clear for both humans and parsers.

πŸ”Ή Why Infix plural?

model plural models:
    gpt-4:
        name: "gpt-4"
    ;
    gpt-4o:
        name: "gpt-4o"
    ;
;
  • Makes singular and plural forms explicit in configuration.
  • Eliminates brittle β€œadd an s” heuristics in code generation.
  • Supports irregular plurals (e.g. person plural people).
  • Improves clarity: developers instantly know single vs multiple semantics.

πŸ”§ Features

Parser

  • Parses standalone .cola files and Markdown files with embedded cola blocks
  • Produces structured configuration models

Code Generator

  • Generates idiomatic Rust structs and collections (HashMap) from cola models
  • Handles plural entities clearly
  • Renames Rust keywords (e.g., type to type_)
  • Provides constructors and accessor methods for easy integration

πŸ“¦ Installation

Add colap to your Rust project:

[dependencies]
colap = "0.1"

πŸ“‚ Codebase Structure

The colap codebase is organized into the following modules:

  • parser: Handles parsing of Cola syntax using rustemo
    • cola.rs: Generated parser code
    • cola_actions.rs: Parser actions
  • model: Contains the configuration model definitions
    • config_model.rs: Core configuration model and node types
    • model_builder.rs: Builds config model from parsed AST
    • source_location.rs: Source location tracking
  • generator: Code generation for Rust structs
    • generator_impl.rs: Main code generator implementation
    • templates/: Handlebars templates for code generation
  • grammar: Contains the rustemo grammar definition
    • cola.rustemo: Grammar rules for the Cola language

🚩 Usage

Command Line Interface

USAGE:
    colap [OPTIONS] <input>

ARGS:
    <input>    Input .cola file or markdown containing Cola code blocks

OPTIONS:
    -h, --help                     Print help information
    -m, --mode <MODE>              Generation mode: 'crate' or 'module' (default: crate)
    -n, --crate-name <NAME>        Name of the generated library crate (default: input-file-stem-config)
    -o, --output <DIR>             Base output directory (default: generated)
    -V, --version                  Print version information

Examples

Basic Crate Generation (Default)

Generate a complete Rust crate from a cola file:

colap path/to/myconfig.cola

This will:

  1. Parse myconfig.cola
  2. Generate code in the directory generated/myconfig-config/
  3. Create a complete library crate with:
    • Cargo.toml with dependencies
    • src/lib.rs with generated structs
    • tests/integration.rs with integration tests
    • README.md with usage documentation

Module Generation

Generate a single Rust module file for embedding in your project:

colap path/to/myconfig.cola --mode module -o src -n config_parser

This will:

  1. Parse myconfig.cola
  2. Generate a single file src/config_parser.rs
  3. Include inline unit tests within the module
  4. Ready to be imported with mod config_parser; in your project

Custom crate name and output directory

colap path/to/myconfig.cola --crate-name my-custom-config --output custom/output/dir

This will:

  1. Parse myconfig.cola
  2. Generate code in the directory custom/output/dir/my-custom-config/
  3. Create a library crate with generated structs in custom/output/dir/my-custom-config/lib.rs

Code Generation Details

The code generator produces:

  1. Rust structs for each entity type in the configuration
  2. Collection structs (using HashMap) for plural entities
  3. Accessor methods to retrieve fields and collections
  4. Constructors for each entity type
  5. Integration tests for validating parsing functionality

Generated Code Structure

For a configuration file with entities like Root, Llm, and Model, the generator produces:

// Root entity struct
pub struct Root {
    llm: Llm,
    // other fields...
}

// Singular entity
pub struct Llm {
    provider: String,
    models: Models,  // plural entity reference
    // other fields...
}

// Plural entity (collection)
pub struct Models {
    entries: HashMap<String, Model>,
}

// Entity in a collection
pub struct Model {
    name: String,
    context_window: i64,
    // other fields...
}

Type Handling

The generator maps Cola types to Rust types as follows:

Cola Type Rust Type
String String
Integer i64
Float f64
Boolean bool
Entity Custom struct
Optional Entity Option<CustomStruct>

Default Crate Name

If the --crate-name option is not provided, the crate name is derived from the input file:

  1. Take the file stem (filename without extension)
  2. Replace underscores with hyphens
  3. Convert to lowercase
  4. Append -config suffix

For example:

  • my_config.cola β†’ my-config-config
  • API_Model.md β†’ api-model-config

Using the Generated Code

Loading and Parsing a Configuration File

The generated code includes integration tests that demonstrate how to parse configuration files:

use colap::cola::ColaParser;
use colap::model_builder::ModelBuilder;
use my_config::Root;  // Generated crate name

// Load and parse a configuration file
fn parse_config_file(path: &str) -> Root {
    // Read the file content
    let content = std::fs::read_to_string(path).expect("Failed to read config file");
    
    // Create a parser and parse the content
    let parser = ColaParser::new();
    let result = parser.parse(&content).expect("Failed to parse configuration");
    
    // Build the configuration model
    let model = ModelBuilder::build_config_model(&result).expect("Failed to build config model");
    
    // Create the root entity from the model
    Root::from_model(&model)
}

// Usage example
let config = parse_config_file("path/to/config.md");

Accessing Configuration Values

The generated code provides accessor methods for retrieving values:

// Get the LLM configuration
let llm = config.llm();

// Access a singular entity's properties
let provider = llm.provider();  // Returns a &String

// Access a collection (plural entity)
let models = llm.models();

// Get a specific model from the collection
if let Some(gpt4) = models.get("gpt-4.1") {
    let context_window = gpt4.context_window();  // Returns an i64
    println!("GPT-4.1 context window: {}", context_window);
}

// Iterate through all models
for (name, model) in models.iter() {
    println!("Model: {}, Context: {}", name, model.context_window());
}

Optional Fields

Optional fields are represented as Option<T> types:

// Optional field access with safe pattern matching
if let Some(api) = llm.api() {
    if let Some(key) = api.key() {
        println!("API Key: {}", key);
    }
}

// Using map() for clean optional chaining
let api_type = llm.api().and_then(|api| api.type_()).unwrap_or("No API type specified");

πŸ“„ Embedded Markdown Support

Colap parses configurations directly from Markdown. Any fenced block marked ```cola is automatically parsed, supporting documentation-driven development.


πŸ“œ License

This project is licensed under the Apache License 2.0.

Copyright 2025 Aivolution GmbH