# ggen - Ontology-Driven Code Generation

[![Crates.io](https://img.shields.io/crates/v/ggen.svg)](https://crates.io/crates/ggen)
[![Documentation](https://docs.rs/ggen/badge.svg)](https://docs.rs/ggen)
[![License](https://img.shields.io/crates/l/ggen.svg)](LICENSE)
[![Build Status](https://github.com/seanchatmangpt/ggen/workflows/CI/badge.svg)](https://github.com/seanchatmangpt/ggen/actions)

**Transform RDF ontologies into typed code through SPARQL queries and Tera templates.**

---

## 📖 What is ggen? (Explanation)

ggen is a **deterministic code generator** that bridges semantic web technologies (RDF, SPARQL, OWL) with modern programming languages. Instead of manually maintaining data models in multiple languages, you define your domain once as an **RDF ontology** and generate type-safe code across Rust, TypeScript, Python, and more.

### Why ontologies?

- **Single Source of Truth**: Define your domain model once, generate everywhere
- **Semantic Validation**: Use OWL constraints to catch domain violations at generation time
- **Inference**: SPARQL CONSTRUCT queries materialize implicit relationships before code generation
- **Deterministic**: Same ontology + templates = identical output (reproducible builds)

### Use Cases

- **API Development**: Generate client libraries from OpenAPI specs converted to RDF
- **Data Modeling**: Ensure consistency across microservices
- **Academic Research**: Generate code from domain ontologies (biology, chemistry, finance)
- **Multi-Language Projects**: Keep Rust backend and TypeScript frontend in sync

---

## 🚀 Quick Start (Tutorial)

### Installation

```bash
# Install via cargo
cargo install ggen

# Verify installation
ggen --version  # Should show: ggen 5.0.0
```

### Your First Sync (5 minutes)

**Step 1: Create a minimal ontology** (`schema/domain.ttl`)

```turtle
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ex: <https://example.com/> .

ex:Person a rdfs:Class ;
    rdfs:label "Person" ;
    rdfs:comment "Represents a person in the system" .

ex:name a rdf:Property ;
    rdfs:domain ex:Person ;
    rdfs:range rdfs:Literal ;
    rdfs:label "name" .

ex:email a rdf:Property ;
    rdfs:domain ex:Person ;
    rdfs:range rdfs:Literal ;
    rdfs:label "email" .
```

**Step 2: Create a configuration** (`ggen.toml`)

```toml
[project]
name = "my-first-ggen"
version = "0.1.0"
description = "Learning ggen with a simple Person model"

[generation]
ontology_dir = "schema/"
templates_dir = "templates/"
output_dir = "src/generated/"
```

**Step 3: Create a Rust template** (`templates/rust-struct.tera`)

```rust
// Generated by ggen from {{ ontology }}
{% for class in classes %}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct {{ class.name }} {
    {% for property in class.properties %}
    pub {{ property.name }}: {{ property.rust_type }},
    {% endfor %}
}
{% endfor %}
```

**Step 4: Run sync**

```bash
ggen sync

# Output:
# ✅ Loaded ontology: schema/domain.ttl (3 triples)
# ✅ Rendered template: rust-struct.tera
# ✅ Generated: src/generated/domain.rs (42 lines)
# ✅ Sync complete in 0.2s
```

**What you'll get** (`src/generated/domain.rs`):

```rust
// Generated by ggen from domain.ttl
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Person {
    pub name: String,
    pub email: String,
}
```

---

## 📘 How-To Guides (Problem-Oriented)

### How to sync a workspace with multiple crates

```bash
# Sync all workspace members
ggen sync --from . --mode full --verbose

# Sync specific member
ggen sync --from crates/domain --to crates/domain/src/generated.rs
```

### How to preview changes before applying

```bash
# Dry-run mode (no file writes)
ggen sync --dry-run

# Verify mode (CI/CD validation)
ggen sync --mode verify || exit 1
```

### How to preserve manual edits in generated files

Mark custom code with `// MANUAL` comments:

```rust
// GENERATED CODE (readonly)
#[derive(Debug, Clone)]
pub struct User {
    pub id: i64,
    pub username: String,
}

// MANUAL: Custom validation logic (preserved during sync)
impl User {
    pub fn validate_username(&self) -> Result<(), Error> {
        // This survives incremental sync
        if self.username.len() < 3 {
            return Err(Error::InvalidUsername);
        }
        Ok(())
    }
}
```

Then use incremental mode:

```bash
ggen sync --mode incremental
```

### How to use SPARQL CONSTRUCT for inference

Add inference rules to your ontology:

```turtle
@prefix ggen: <https://ggen.io/ns#> .

ex:InferredRule a ggen:ConstructQuery ;
    ggen:query """
        CONSTRUCT {
            ?person ex:hasContactInfo ?email .
        }
        WHERE {
            ?person ex:email ?email .
        }
    """ .
```

The CONSTRUCT query materializes new triples before code generation.

### How to integrate with CI/CD

**GitHub Actions** (`.github/workflows/codegen.yml`):

```yaml
name: Code Generation
on: [push, pull_request]

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - run: cargo install ggen
      - run: ggen sync --mode verify
      - name: Fail if generated code is out of sync
        run: git diff --exit-code src/generated/
```

### How to publish a package to the ggen marketplace

Create `gpack.toml`:

```toml
[package]
name = "awesome-templates"
version = "1.0.0"
author = "Your Name"
email = "you@example.com"
description = "Reusable Tera templates for API generation"
license = "MIT"
repository = "https://github.com/yourname/awesome-templates"

[templates]
templates = ["api-client.tera", "server-stubs.tera"]

[dependencies]
requires = ["ggen >= 5.0.0"]
```

Then publish:

```bash
ggen marketplace publish gpack.toml
```

---

## 📚 Reference (Information-Oriented)

### Command: `ggen sync`

**Signature**:
```
ggen sync [OPTIONS] [--from <SOURCE>] [--to <TARGET>]
```

**Options**:

| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--from` | STRING | `.` | Source path (ontology or workspace) |
| `--to` | STRING | Auto | Target output directory |
| `--mode` | STRING | `full` | Sync mode: `full`, `incremental`, `verify` |
| `--dry-run` | BOOL | `false` | Preview changes without writing files |
| `--force` | BOOL | `false` | Override conflicts (use with caution) |
| `--verbose` | BOOL | `false` | Show detailed operation logs |

**Sync Modes**:

- **`full`**: Regenerate all artifacts from scratch (initial setup, major updates)
- **`incremental`**: Update only changed elements, preserve `// MANUAL` sections (development iteration)
- **`verify`**: Check consistency without modifying files (CI/CD validation)

**Exit Codes**:

| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | Manifest validation error |
| 2 | Ontology load error |
| 3 | SPARQL query error |
| 4 | Template rendering error |
| 5 | File I/O error |
| 6 | Timeout exceeded |

### Configuration: `ggen.toml`

Located at repository root (same level as `Cargo.toml`).

**Minimal configuration**:

```toml
[project]
name = "my-project"
version = "1.0.0"

[generation]
ontology_dir = "schema/"
output_dir = "src/generated/"
```

**Complete schema**:

```toml
[project]
name = STRING              # Project identifier (required)
version = STRING           # Semantic version (required)
description = STRING       # Project description
authors = [STRING, ...]    # Author list
license = STRING           # SPDX license (MIT, Apache-2.0, etc.)

[generation]
ontology_dir = STRING      # Ontology directory (default: "schema/")
templates_dir = STRING     # Templates directory (default: "templates/")
output_dir = STRING        # Output directory (default: "generated/")
incremental = BOOL         # Enable incremental sync (default: true)
overwrite = BOOL           # Overwrite existing files (default: false)

[sync]
enabled = BOOL             # Enable sync (default: true)
on_change = STRING         # Trigger: "save" | "commit" | "manual" (default: "save")
validate_after = BOOL      # Run validation after sync (default: true)
conflict_mode = STRING     # Handle conflicts: "fail" | "warn" | "ignore" (default: "fail")

[rdf]
formats = [STRING, ...]    # Supported formats: ["turtle", "rdf-xml", "n-triples"]
default_format = STRING    # Default format (default: "turtle")
base_uri = STRING          # Base URI for ontology (optional)
strict_validation = BOOL   # Strict RDF validation (default: false)

[templates]
enable_caching = BOOL      # Cache compiled templates (default: true)
auto_reload = BOOL         # Reload on file change (default: true)

[marketplace]
registry_url = STRING      # Package registry URL
cache_dir = STRING         # Cache directory (default: ".ggen/cache/")
verify_signatures = BOOL   # Verify signatures (default: true)

[output]
formatting = STRING        # Formatter: "default" | "rustfmt" | "prettier" | "black"
line_length = INTEGER      # Max line length (default: 100)
indent = INTEGER           # Indentation width (default: 2)
```

**Environment variable expansion**:

```toml
[generation]
ontology_dir = "${SCHEMA_DIR:schema/}"  # Use SCHEMA_DIR env var or default
output_dir = "${OUT_DIR:generated/}"
```

**CLI overrides**:

```bash
ggen sync --config-override generation.output_dir=custom_output/
```

### Package Distribution: `gpack.toml`

For publishing reusable templates to the marketplace.

```toml
[package]
name = STRING              # Package identifier
version = STRING           # Semantic version
author = STRING            # Author name
email = STRING             # Contact email
description = STRING       # Package description
license = STRING           # SPDX license
repository = STRING        # Git repository URL
documentation = STRING     # Documentation URL
keywords = [STRING, ...]   # Search keywords

[templates]
templates = [STRING, ...]  # Template files to include

[dependencies]
requires = [STRING, ...]   # Version requirements (e.g., "ggen >= 5.0.0")
```

---

## 🗺️ Project Structure Example

```
my-project/
├── ggen.toml                    # Project configuration
├── schema/
│   ├── domain.ttl               # RDF ontology (Turtle format)
│   └── constraints.ttl          # OWL constraints
├── templates/
│   ├── rust-struct.tera         # Tera template for Rust
│   ├── ts-interface.tera        # Tera template for TypeScript
│   └── python-dataclass.tera    # Tera template for Python
├── src/
│   ├── generated/               # Output of ggen sync
│   │   ├── domain.rs
│   │   ├── types.ts
│   │   ├── models.py
│   │   └── .manifest            # Sync metadata
│   └── main.rs
└── Cargo.toml                   # Rust workspace
```

---

## 🔗 Links

- **Documentation**: [https://docs.ggen.io](https://docs.ggen.io)
- **GitHub**: [https://github.com/seanchatmangpt/ggen](https://github.com/seanchatmangpt/ggen)
- **Crates.io**: [https://crates.io/crates/ggen](https://crates.io/crates/ggen)
- **Examples**: [examples/](examples/)
- **Contributing**: [CONTRIBUTING.md](CONTRIBUTING.md)

---

## 📜 License

Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

---

## 🤝 Contributing

Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

**Built with**:
- 🦀 Rust 1.75+ (edition 2021)
- 🔗 Oxigraph (RDF store)
- 🔍 SPARQL 1.1
- 🎨 Tera (template engine)
- ⚙️ cargo-make (build automation)
- 🧪 Chicago School TDD (state-based testing)
