#module #tera-templates #sdml #domain #integration #modeling

bin+lib sdml-tera

Simple Domain Modeling Language (SDML) Tera Integration

1 unstable release

0.1.0 Oct 14, 2024

#157 in Template engine


Used in sdml-cli

Custom license

1MB
20K SLoC

Package sdml-tera

Rust integration between the SDML core model and the Tera template engine.

https://crates.io/crates/sdml_cli

This package is part of the Rust SDML project and specifically implements an integration between the SDML core model and the Tera template engine to allow template-based generation from one or more SDML modules. The project's intent is to provide an idiomatic implementation of the in-memory model, parser, generators, and the CLI tool.

It is planned for a more complete version of the CLI functionality to be integrated into the overall SDML CLI at some point.

The following figure demonstrates this package in the broader project context.

                         ╭───────╮
                         │  CLI  │
                    ╔══  │ crate │  ══╗
                    ║    ╰───────╯    ║
┌╌╌╌╌╌╌╌╌┐          V                 V
┆        ┆       ╭───────╮       ╭──────────╮       Formatted Source
┆ source ┆  ══>  │ parse │  ══>  │ generate │  ══>  RDF Representation 
┆  file  ┆   ╭───│ crate │───────│   crate  │───╮   Documentation
┆        ┆   │   ╰───────╯       ╰──────────╯   │   Diagrams
└╌╌╌╌╌╌╌╌┘   │        core/errors crate         │
             ╰──────────────────────────────────╯
 ┌───────┐                  ⋀
 │ other │                  ║
 │ tools │  ════════════════╝
 └───────┘

Example

We wish to produce an output such as the following, a bulleted outline of a module.

# Module `campaign` Outline

* **campaign** (Module)
  * **Name** <- *xsd:string* (Datatype)
  * **CampaignId** <- *xsd:string* (Datatype)
  * **State** (Enum)
    * Running
    * Paused
    * error
  * **Tag** (Structure)
    * key -> *xsd:NMTOKEN*
    * value -> *rdf:langString*
  * **Ad** (Entity)
  * **AdGroup** (Entity)
  * **Campaign** (Entity)
    * identity campaignId -> *CampaignId*
    * name -> *unknown*
    * tag -> *Tag*
    * target -> *TargetCriteria*
  * **AudienceTarget** (Entity)
  * **GeographicTarget** (Entity)
  * **TargetCriteria** (Union)
    * Audience (Audience)
    * Geographic (Geographic)

To do this we create a file named outline.md with the following content.

{% macro member(item) %}
{%- if item.__type == "reference" -%}
*{{ item.type_ref }}*
{% elif item.__type == "definition" -%}
{{ item.name }} -> *{{ item.type_ref }}*
{% endif -%}
{% endmacro member %}

# Module `{{ module.name }}` Outline

* **{{ module.name }}** (Module)
{% for def in module.definitions %}  * **{{ def.name }}**
{%- if def.__type == "datatype" %} <- *{{ def.base_type }}*
{%- endif %} ({{ def.__type | capitalize | replace(from="-", to=" ") }})
{% if def.__type == "entity" -%}
{%- if def.identity -%}
    * identity {{ self::member(item=def.identity) }}
{%- endif -%}
{%- if def.members -%}
{% for member in def.members -%}
    * {{ self::member(item=member) }}
{%- endfor -%}
{%- endif -%}
{%- elif def.__type == "enum" -%}
{% for var in def.variants %}    * {{ var.name }}
{% endfor -%}
{% elif def.__type == "event" -%}
{%- if def.members -%}
{% for member in def.members -%}
    * {{ self::member(item=member) }}
{%- endfor -%}
{%- endif -%}
{% elif def.__type == "structure" -%}
{%- if def.identity -%}
  * identity {{ self::member(item=def.identity) }}
{%- endif -%}
{%- if def.members -%}
{% for member in def.members -%}
    * {{ self::member(item=member) }}
{%- endfor -%}
{%- endif -%}
{%- elif def.__type == "union" -%}
{% for var in def.variants -%}
    * {% if var.rename %}{{ var.rename }} ({{ var.name }})
{%- else %}{{ var.name }}
{%- endif %}
{% endfor -%}
{% endif -%}
{% endfor %}

Once we have finished testing using the sdml-tera tool we can write the following code to render any module with the template above.

use sdml_core::model::modules::Module;
use sdml_core::store::ModuleStore;
use sdml_tera::make_engine_from;
use sdml_tera::render_module;

fn print_module(module: &Module, cache: &impl ModuleStore) {

    let engine = make_engine_from("tests/templates/**/*.md")
        .expect("Could not parse template files");


    let rendered = render_module(&engine, module, cache, None, "outline.md")
        .expect("Issue in template rendering");

    println!("{}", rendered);
}

Changes

Version 0.1.0

Initial release.

Dependencies

~17–30MB
~445K SLoC