Expand description
Provides integration that allows document generation from SDML modules using the Tera template engine.
This package provides a set of rendering functions as well as a set of context functions. By
default all render functions will create new context value using the module_to_value
function
to convert a Module
into a context object. However, you may provide your own context to add custom
values.
The documentation for the [context
] module describes the simplifications made in the creation of
the context object(s).
§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, None, "outline.md")
.expect("Issue in template rendering");
println!("{}", rendered);
}
§Features
This crate also has a binary that allows you to test the development of templates. The tool takes a glob expression for Tera to load templates and a specific template name to use for a specific test. The input/output allows for file read/write and stdin/stdout, or for input you can specify a module name for the standard resolver to find for you.
❯ sdml-tera --help
Simple Domain Modeling Language (SDML) Tera Integration
Usage: sdml-tera [OPTIONS] --template-name <TEMPLATE_NAME> [MODULE]
Arguments:
[MODULE] SDML module, loaded using the standard resolver
Options:
-o, --output <OUTPUT> File name to write to, or '-' to write to stdout [default: -]
-i, --input <INPUT> Input SDML file name to read from, or '-' to read from stdin [default: -]
-g, --template-glob <TEMPLATE_GLOB> [default: templates/**/*.md]
-n, --template-name <TEMPLATE_NAME>
-h, --help Print help
-V, --version Print version
The error messages produced by the tool are also verbose to help as much as possible to diagnose issues as you develop templates. For example, the following shows the output when a syntax error is found in a template.
An error occurred creating the Tera engine; most likely this is a syntax error in one of your templates.
Error: A template error occurred; source:
* Failed to parse "/Users/simonjo/Projects/sdm-lang/rust-sdml/sdml-tera/tests/templates/module.md"
--> 35:25
|
35 | event {{ definition.name$ }} source {{ definition.source }}
| ^---
|
= expected `or`, `and`, `not`, `<=`, `>=`, `<`, `>`, `==`, `!=`, `+`, `-`, `*`, `/`, `%`, a filter, or a variable end (`}}`)
Functions§
- make_
engine_ from - A local wrapper around the Tera engine creation.
- render_
module - Render
module
, with the template in the filetemplate_name
, and usingengine
. - render_
module_ to - Render
module
, with the template in the filetemplate_name
, and usingengine
. - render_
module_ to_ file - Render
module
, with the template in the filetemplate_name
, and usingengine
. - render_
modules - Render the set of
modules
, with the template in the filetemplate_name
, and usingengine
. - render_
modules_ to - Render the set of
modules
, with the template in the filetemplate_name
, and usingengine
. Ifcontext
is not specified a new blank object is created, and in either case a map is created under the key"modules"
as a map from module name to module representation. - render_
modules_ to_ file - Render the set of
modules
, with the template in the filetemplate_name
, and usingengine
.