Skip to main content

Templates

Templates are the foundation of any plugin, as they are used to generate the final source code.

ScyScaff uses Scriban for template parsing, a language that bears a strong resemblance to Liquid, but offers far more capabilities.

Template Tree and File Structure

If you've read the other sections of the documentation before this, you've probably noticed the term "Template Tree" being used rather than just templates. That's because the Scaffolder reads not just a list of files, but an entire folder, inheriting the initially provided file structure. For example:

Provided template directory:
└── Folder A/
├── File_A.js.liquid
└── Folder B/
└── File_B.js.liquid

When processed, it yields:

Generated directory:
└── Folder A/
├── File_A.js
└── Folder B/
└── File_B.js

Therefore, when you create your templates, organize the source folder with them as you would like to see it in the generated project. Template filenames should consist of: name.extension.liquid. If a file doesn't end with ".liquid", the Scaffolder will skip it.

Syntax

As mentioned, the syntax is similar to Liquid. Let's look at an example from aspnet-ddd:

public sealed class {{ model.key }}(Guid id) : Entity(id)
{
{{~ for field in model.value ~}}
public {{ field.value }} {{ field.key }} { get; set; }
{{~ end ~}}
}

The result of processing such a template would be:

# Configuration parameters:

Services:
Products:
Models:
Category:
Title: string
Description: string
public sealed class Category(Guid id) : Entity(id)
{
public string Title { get; set; }
public string Description { get; set; }
}

As we can see, parameter application can be declared within double curly braces ( {{ model.key }} ), and the "for" loop is denoted by double curly braces ( {{~ for field in model.value ~}} ). The tilde (~) in this case signifies that the lines declaring the start and end of the loop won't leave empty lines after themselves. To learn more about writing templates in Scriban, refer to this or inspect the code of the standard plugin package.

Important note: If the contents of the file are empty after processing, Scaffolder will skip writing it.

Flags

To provide greater flexibility in your templates, Scaffolder offers the functionality of parameters (Flags) for all types of entities (Framework, Dashboard, GlobalWorker):

# Confiugration File:

Dashboard:
Name: svelte-crud
Flags:
Architecture: graphql

GlobalWorkers:
- Name: grafana-prometheus
Flags:
Panel: 19924-asp-net-core

Services:
Products:
Flags:
Metrics: prometheus

This way, you can access the parameter provided from the configuration for any task that requires selecting a value from a strict list or a custom one from the user:

// Example of using a specific value (Services -> Products -> Flags):

{{~ if entity.flags["Metrics"] == "prometheus" ~}}
builder.AddPrometheusExporter();
{{~ end ~}}

// Example of using any value (Global Workers -> grafana-prometheus -> Flags):

string grafanaPanelUrl = "https://grafana.com/grafana/dashboards/" + "{{ entity.flags["Panel"] }}";

For more details on how to declare a strict list of allowed values and, conversely, how to allow any value to be specified, refer to the building page, on step №6.

Passed Parameters

Obviously, a template can only read the parameters provided to it by the Scaffolder. Here's the complete list:

  • config - Project configuration file.
  • entity - Current iterated entity. Depending on the context, is a ScaffolderService, ScaffolderDashboard or ScaffolderGlobalWorker.
  • entity_name - Name of the current iterated entity, a string. For a service, this is the service's name; for Dashboard, it's the word "Dashboard"; for Global Worker, it's the word "Global".
  • model - Current iterated service model. Available only when using the model iterator; otherwise, it's null.
  • model_entity_name - Name of the service to which the "model" belongs, a string. Available under the same conditions as "model"; otherwise, it's also null.
  • compose_services - List of generated Docker services. Don't forget to read about the order of service generation in the documentation; it's crucial if you want to use this parameter.

Remember, references to parameters in PascalCase are converted to snake_case. All fields should be accessed in this form.

Special Files

Currently, the Scaffolder has only one special file, which allows duplicating the template tree structure for each model. To do this, create an empty file named "[...modelIterator...]" in the folder where you want to do this.

If you're processing a Framework plugin, it will iterate over all models of the current service; if it's any other plugin (Dashboard, GlobalWorker), it will iterate over all models from all services in the configuration.

Example:

# Generation configuration

Services:
Products:
Models:
Category:
Title: string
Description: string
Supplier:
Name: string
Template tree:
└── Models/
├── [...modelIterator...]
└── {{ model.key }}.cs.liquid
Generation result:
└── Models/
├── Category.cs
└── Supplier.cs

Only in this iteration do the "model" and "model_entity_name" parameters cease to be null.

Special Naming

As you may have noticed in the special files example, filenames are also subjected to templating. Simply insert the parameter name in the same double curly braces in your template tree, and the Scaffolder will be able to process it. For example:

Template tree:
└── Folder_A/
└── {{ project_name }}.txt.liquid
Result:
└── Folder_A/
└── TestProjectName.txt

But what if I want to use a character that simply can't be inserted into the file system? For such cases, the Scaffolder has several predefined keywords that will be replaced with corresponding characters during parsing.

Example:

Template tree:
└── Folder_A/
└── {{ project_name SCF_PIPE stringSCF_DOTupcase }}.txt.liquid
Result:
└── Folder_A/
└── TESTPROJECTNAME.txt

As we can see, we managed to reference the "|" operator, which is incompatible with the Windows file system. At the parsing stage, it transformed into {{ project_name | string.upcase }}, resulting in the conversion of our project's name to uppercase letters.

The full list of special namings is available here.