A comprehensive command-line interface for working with the Common Architecture Language Model (CALM)
NOTE: This is a CLI-only command. @finos/calm-cli does not export functions for programmatic use.
The template command generates files from a CALM model using Handlebars templates. It supports template bundles, single template files, or directories of templates, enabling code generation, configuration file creation, and custom output formats from CALM architectures.
Generate files from a CALM model using templates.
/**
* Generate files from a CALM model using a template bundle, single file, or directory
* @command calm template [options]
*/
interface TemplateCommandOptions {
/** Path to CALM architecture JSON file
* CLI flags: -a, --architecture <file>
* Required: yes
*/
architecture: string;
/** Path to output directory or file
* CLI flags: -o, --output <file>
* Required: yes
*/
output: string;
/** Delete output directory contents before processing
* CLI flags: --clear-output-directory
* Default: false
*/
clearOutputDirectory?: boolean;
/** Path to template bundle directory
* CLI flags: -b, --bundle <path>
*/
bundle?: string;
/** Path to single .hbs or .md template file
* CLI flags: -t, --template <path>
*/
template?: string;
/** Path to directory of .hbs/.md templates
* CLI flags: -d, --template-dir <path>
*/
templateDir?: string;
/** Path to JSON file mapping URLs to local file paths
* CLI flags: -u, --url-to-local-file-mapping <path>
*/
urlToLocalFileMapping?: string;
/** Enable verbose logging
* CLI flags: -v, --verbose
* Default: false
*/
verbose?: boolean;
}Requirements:
bundle, template, or templateDir must be specifiedUsage Examples:
# Using a template bundle
calm template -a architecture.json -b ./template-bundle -o ./output
# Using a single template file
calm template -a architecture.json -t ./template.hbs -o ./output.txt
# Using a directory of templates
calm template -a architecture.json -d ./templates -o ./output
# Clear output directory before generation
calm template -a architecture.json -b ./bundle -o ./output --clear-output-directory
# With URL-to-local-file mapping
calm template -a architecture.json -b ./bundle -o ./output -u ./url-mappings.json
# With verbose logging
calm template -a architecture.json -b ./bundle -o ./output -vA template bundle is a directory containing:
index.json: Bundle configuration defining template structure.hbs)Bundle Structure Example:
template-bundle/
├── index.json
├── main.hbs
├── partials/
│ ├── header.hbs
│ └── footer.hbs
└── helpers/
└── custom-helpers.jsUsage:
calm template -a architecture.json -b ./template-bundle -o ./outputA single Handlebars or Markdown template file for simple transformations.
Usage:
# Handlebars template
calm template -a architecture.json -t ./template.hbs -o ./output.html
# Markdown template
calm template -a architecture.json -t ./template.md -o ./output.mdA directory containing multiple template files, each processed independently.
Directory Structure Example:
templates/
├── api.hbs
├── database.hbs
├── frontend.hbs
└── README.md.hbsUsage:
calm template -a architecture.json -d ./templates -o ./outputEach template file generates a corresponding output file with the same name (minus .hbs extension).
Templates use Handlebars syntax with access to the CALM architecture model.
Templates have access to the complete CALM architecture:
{{!-- Access nodes --}}
{{#each nodes}}
Node: {{this.name}}
Type: {{this.node-type}}
ID: {{this.unique-id}}
{{/each}}
{{!-- Access relationships --}}
{{#each relationships}}
From: {{this.relationship-type.connects.source.node}}
To: {{this.relationship-type.connects.destination.node}}
{{/each}}
{{!-- Access metadata --}}
Schema: {{$schema}}Handlebars provides standard helpers:
{{#each}} - Iterate over arrays{{#if}} - Conditional rendering{{#unless}} - Negative conditional{{#with}} - Change contextTemplate bundles can provide custom helpers for specialized transformations.
When CALM models reference external URLs (e.g., for flows or patterns), you can map these to local files for offline processing.
{
"https://calm.finos.org/docuflow/flow/document-upload": "flows/flow-document-upload.json",
"https://calm.finos.org/patterns/api-gateway": "patterns/api-gateway.json"
}Path Resolution:
calm template \
-a architecture.json \
-b ./template-bundle \
-o ./output \
-u ./url-mappings.jsonWhen the template processor encounters a URL reference in the architecture, it will load the content from the mapped local file instead of fetching from the URL.
With --clear-output-directory flag:
calm template -a architecture.json -b ./bundle -o ./output --clear-output-directoryWarning: This completely deletes all files and subdirectories in the output directory before generation. Use with caution!
The CLI uses different processing modes from @finos/calm-shared:
mode: 'bundle'
templatePath: './template-bundle'Processes a complete template bundle with configuration.
mode: 'template'
templatePath: './template.hbs'Processes a single template file.
mode: 'template-directory'
templatePath: './templates'Processes all templates in a directory.
Generate source code from CALM architectures:
{{!-- api.hbs --}}
// Generated API interfaces from CALM architecture
{{#each nodes}}
{{#if (eq this.node-type "service")}}
export interface {{this.name}}Service {
{{#each this.interfaces}}
// {{this.protocol}} interface on {{this.host}}:{{this.port}}
{{/each}}
}
{{/if}}
{{/each}}Generate configuration files for deployment:
{{!-- docker-compose.yml.hbs --}}
version: '3.8'
services:
{{#each nodes}}
{{this.unique-id}}:
image: {{this.name}}:latest
ports:
{{#each this.interfaces}}
- "{{this.port}}:{{this.port}}"
{{/each}}
{{/each}}Generate architecture documentation:
{{!-- README.md.hbs --}}
# Architecture Documentation
## Services
{{#each nodes}}
### {{this.name}}
- **Type:** {{this.node-type}}
- **ID:** {{this.unique-id}}
{{#if this.description}}
- **Description:** {{this.description}}
{{/if}}
#### Interfaces
{{#each this.interfaces}}
- {{this.protocol}} on {{this.host}}:{{this.port}}
{{/each}}
{{/each}}Generate Terraform or CloudFormation templates:
{{!-- main.tf.hbs --}}
{{#each nodes}}
{{#if (eq this.node-type "database")}}
resource "aws_db_instance" "{{this.unique-id}}" {
identifier = "{{this.unique-id}}"
engine = "{{this.metadata.engine}}"
{{#each this.interfaces}}
port = {{this.port}}
{{/each}}
}
{{/if}}
{{/each}}Multiple Template Options:
❌ Please specify exactly one of --template, --template-dir, or --bundleSolution: Use only one template source option.
Missing Required Options:
error: required option '-a, --architecture <path>' not specifiedSolution: Provide required architecture and output options.
Architecture File Not Found:
Error: ENOENT: no such file or directorySolution: Verify architecture file path is correct.
Template Not Found:
Error: Template file not foundSolution: Verify template path is correct and file exists.
Invalid URL Mapping File:
Error reading url to local file mapping fileSolution: Verify mapping file is valid JSON with correct format.
Template Syntax Error:
Error: Parse error on line XSolution: Check Handlebars template syntax for errors.
Template generation is typically used after architecture creation and validation:
# Step 1: Generate architecture from pattern
calm generate -p pattern.json -o architecture.json
# Step 2: Edit and validate architecture
calm validate -a architecture.json -p pattern.json
# Step 3: Generate code/configuration from architecture
calm template -a architecture.json -b ./code-gen-bundle -o ./src
# Step 4: Use generated code in project
npm install
npm run buildCreate a template bundle that generates multiple files:
index.json:
{
"name": "microservices-generator",
"version": "1.0.0",
"templates": [
{
"input": "service.hbs",
"output": "src/services/{{unique-id}}.ts"
},
{
"input": "dockerfile.hbs",
"output": "docker/{{unique-id}}/Dockerfile"
}
]
}Use conditionals to generate different outputs based on architecture content:
{{#each nodes}}
{{#if (eq this.node-type "database")}}
{{> database-config this}}
{{else if (eq this.node-type "service")}}
{{> service-config this}}
{{else}}
{{> default-config this}}
{{/if}}
{{/each}}Template bundles can include custom transformers to pre-process the CALM model:
// transformer.ts
export class CustomTransformer {
transform(architecture: any): any {
// Transform architecture structure for templates
return {
...architecture,
serviceNodes: architecture.nodes.filter(n => n['node-type'] === 'service'),
databaseNodes: architecture.nodes.filter(n => n['node-type'] === 'database')
};
}
}For architectures with many nodes/relationships:
--clear-output-directory for clean slate generationThe TemplateProcessor from @finos/calm-shared may cache:
Subsequent runs with same inputs are faster.
Enable verbose logging to debug template processing:
calm template -a architecture.json -b ./bundle -o ./output -vShows:
Test templates with minimal architectures:
{
"$schema": "https://calm.finos.org/schemas/calm-v1.json",
"nodes": [
{
"unique-id": "test-node",
"node-type": "service",
"name": "Test Service"
}
]
}Review generated files to verify template logic:
calm template -a test-arch.json -t test-template.hbs -o test-output.txt
cat test-output.txtInstall with Tessl CLI
npx tessl i tessl/npm-finos--calm-cli