Atomic utility for validating template processing and variable substitution across multiple template engines
npm install @bernierllc/template-validatorAtomic utility package for validating template processing and variable substitution across multiple template engines.
``bash`
npm install @bernierllc/template-validator
- Multi-Engine Support - Validates Liquid, Handlebars, Mustache, and EJS templates
- Variable Detection - Detects unreplaced template variables
- Syntax Validation - Validates template syntax and structure
- Type Checking - Validates variable types against requirements
- Scoring System - Provides 0-100 quality score for templates
- Zero Dependencies - Pure TypeScript with no external dependencies (except @bernierllc/template-engine)
- TypeScript First - Full type safety with comprehensive interfaces
`typescript
import { validateTemplate, TemplateEngine } from '@bernierllc/template-validator';
const template = 'Hello {{ name }}, welcome to {{ site }}!';
const data = { name: 'Alice', site: 'Portal' };
const result = validateTemplate(template, data, TemplateEngine.LIQUID);
console.log(result.isValid); // true
console.log(result.score); // 100
`
#### validateTemplate(template, data, engine?, options?)
Complete template validation with all checks.
`typescript
interface TemplateValidationResult {
isValid: boolean;
unreplacedVariables: UnreplacedVariable[];
syntaxErrors: TemplateSyntaxError[];
missingVariables: MissingVariable[];
conditionalIssues: ConditionalIssue[];
score: number; // 0-100
}
function validateTemplate(
template: string,
data: Record
engine?: TemplateEngine,
options?: ValidationOptions
): TemplateValidationResult;
`
Parameters:
- template - Template content to validatedata
- - Data object for variable checkingengine
- - Template engine (default: AUTO for auto-detection)options
- - Validation options
Options:
`typescript`
interface ValidationOptions {
strictMode?: boolean; // Enable strict validation
allowPartialTemplates?: boolean; // Allow templates with missing data
customPatterns?: VariablePattern[]; // Custom variable patterns
}
Example:
`typescript`
const result = validateTemplate(
'{{ user.name }} - {{ user.email }}',
{ user: { name: 'Alice', email: 'alice@example.com' } },
TemplateEngine.LIQUID,
{ strictMode: true }
);
#### detectUnreplacedVariables(content, engines?, customPatterns?)
Detect all unreplaced template variables.
`typescript`
function detectUnreplacedVariables(
content: string,
engines?: TemplateEngine[],
customPatterns?: VariablePattern[]
): UnreplacedVariable[];
Example:
`typescript
import { detectUnreplacedVariables, TemplateEngine } from '@bernierllc/template-validator';
const vars = detectUnreplacedVariables(
'Hello {{ name }}, email: {{ email }}',
[TemplateEngine.LIQUID]
);
console.log(vars);
// [
// { variable: 'name', pattern: '{{ name }}', location: {...} },
// { variable: 'email', pattern: '{{ email }}', location: {...} }
// ]
`
#### validateTemplateSyntax(template, engine?)
Validate template syntax for structural errors.
`typescript`
function validateTemplateSyntax(
template: string,
engine?: TemplateEngine
): SyntaxValidationResult;
Example:
`typescript
import { validateTemplateSyntax, TemplateEngine } from '@bernierllc/template-validator';
const result = validateTemplateSyntax(
'{% if user %}{{ user.name }}{% endif %}',
TemplateEngine.LIQUID
);
console.log(result.isValid); // true
console.log(result.errors); // []
console.log(result.supportedEngines); // [TemplateEngine.LIQUID]
`
#### validateRequiredVariables(template, data, requirements)
Validate that required variables are present and correctly typed.
`typescript`
function validateRequiredVariables(
template: string,
data: Record
requirements: VariableRequirement[]
): MissingVariable[];
Example:
`typescript
import { validateRequiredVariables } from '@bernierllc/template-validator';
const missing = validateRequiredVariables(
'Hello {{ name }}',
{ age: 30 },
[{ name: 'name', type: 'string', required: true }]
);
console.log(missing);
// [{ name: 'name', required: true, type: 'string' }]
`
#### extractVariableRequirements(template)
Extract variable requirements from template content.
`typescript`
function extractVariableRequirements(
template: string
): VariableRequirement[];
Example:
`typescript
import { extractVariableRequirements } from '@bernierllc/template-validator';
const requirements = extractVariableRequirements(
'{{ user.name }} - {% if active %}{{ status }}{% endif %}'
);
console.log(requirements);
// [
// { name: 'user.name', type: 'any', required: true },
// { name: 'active', type: 'any', required: true },
// { name: 'status', type: 'any', required: true }
// ]
`
`typescript`
enum TemplateEngine {
LIQUID = 'liquid', // {{ variable }}, {% if %}, {% for %}
HANDLEBARS = 'handlebars', // {{variable}}, {{#if}}, {{#each}}
MUSTACHE = 'mustache', // {{variable}}, {{#section}}
EJS = 'ejs', // <%= variable %>
AUTO = 'auto' // Auto-detect from content
}
`typescript
import { validateTemplate, TemplateEngine } from '@bernierllc/template-validator';
const emailTemplate =
Dear {{ customer.name }},
Your order #{{ order.id }} has been shipped!
{% for item in order.items %}
- {{ item.name }} x {{ item.quantity }}
{% endfor %}
Tracking: {{ shipping.trackingNumber }}
Thank you,
{{ company.name }};
const data = {
customer: { name: 'Alice Johnson' },
order: {
id: 'ORD-12345',
items: [
{ name: 'Widget Pro', quantity: 2 },
{ name: 'Gadget Lite', quantity: 1 }
]
},
shipping: { trackingNumber: 'TRACK123' },
company: { name: 'ACME Corp' }
};
const result = validateTemplate(emailTemplate, data, TemplateEngine.LIQUID);
if (result.isValid) {
console.log('Template is valid! Score:', result.score);
} else {
console.error('Template has issues:');
console.error('Syntax errors:', result.syntaxErrors);
console.error('Missing variables:', result.unreplacedVariables);
}
`
`typescript
import {
detectUnreplacedVariables,
filterMissingVariables,
TemplateEngine
} from '@bernierllc/template-validator';
const template = 'Hello {{ name }}, email: {{ email }}, age: {{ age }}';
const data = { name: 'Bob' };
const allVars = detectUnreplacedVariables(template, [TemplateEngine.LIQUID]);
const missingVars = filterMissingVariables(allVars, data);
console.log('Missing variables:');
missingVars.forEach(v => {
console.log( - ${v.variable} at line ${v.location.line});`
});
// Output:
// - email at line 1
// - age at line 1
`typescript
import { validateRequiredVariables } from '@bernierllc/template-validator';
const template = 'User #{{ userId }}: {{ userName }}';
const data = {
userId: 'abc123', // String instead of number!
userName: 'Alice'
};
const requirements = [
{ name: 'userId', type: 'number', required: true },
{ name: 'userName', type: 'string', required: true }
];
const missing = validateRequiredVariables(template, data, requirements);
if (missing.length > 0) {
console.log('Type mismatches:');
missing.forEach(m => {
console.log( - ${m.name} should be ${m.type});`
});
}
// Output: userId should be number
`typescript
import { validateTemplate, TemplateEngine } from '@bernierllc/template-validator';
const handlebarsTemplate =
{{#if hasOrders}}
;const data = {
user: { firstName: 'Jane', lastName: 'Doe' },
hasOrders: true,
orders: [
{ id: 'A1', total: 99.99 },
{ id: 'A2', total: 149.99 }
]
};
const result = validateTemplate(handlebarsTemplate, data, TemplateEngine.HANDLEBARS);
console.log('Valid:', result.isValid, 'Score:', result.score);
`$3
`typescript
import { validateTemplate, TemplateEngine } from '@bernierllc/template-validator';const template = 'Hello %name%, welcome to %site%!';
const data = { name: 'Alice', site: 'Portal' };
const customPattern = {
engine: TemplateEngine.AUTO,
pattern: /%([a-zA-Z_][a-zA-Z0-9_]*)%/g,
extractName: (match: string) => match.replace(/%/g, '')
};
const result = validateTemplate(template, data, TemplateEngine.AUTO, {
customPatterns: [customPattern]
});
console.log('Unreplaced vars:', result.unreplacedVariables.length); // 0
`$3
`typescript
import { validateTemplateSyntax, TemplateEngine } from '@bernierllc/template-validator';const template =
;const result = validateTemplateSyntax(template, TemplateEngine.LIQUID);
if (!result.isValid) {
console.error('Syntax errors:');
result.errors.forEach(err => {
console.error(
${err.message} at line ${err.location?.line});
});
}if (result.warnings.length > 0) {
console.warn('Warnings:');
result.warnings.forEach(warn => {
console.warn(
${warn.message});
});
}
`Score Calculation
The validation score (0-100) is calculated as follows:
- -20 points per syntax error (major issues)
- -15 points per missing required variable
- -10 points per unreplaced variable
- -8 points per conditional issue
- -5 points per missing optional variable
A score of 100 indicates a perfect template with no issues.
TypeScript Types
`typescript
interface UnreplacedVariable {
variable: string;
pattern: string;
location: TextLocation;
expectedValue?: unknown;
}interface MissingVariable {
name: string;
required: boolean;
type: VariableType;
location?: TextLocation;
}
interface TemplateSyntaxError {
type: 'syntax';
message: string;
location?: TextLocation;
engine: TemplateEngine;
}
interface VariableRequirement {
name: string;
type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'any';
required: boolean;
defaultValue?: unknown;
}
`Integration Status
- Logger Integration: Not applicable - Pure validation utility with no logging requirements. This is an atomic core package that performs deterministic validation without side effects.
- Docs-Suite: Ready - Markdown documentation with TypeScript examples
- NeverHub Integration: Not applicable - Core atomic utility package with no event publishing or service discovery requirements. This package provides pure validation functions that can be used by higher-level packages that integrate with NeverHub.
Dependencies
-
@bernierllc/template-engine - Template engine type definitionsDevelopment
`bash
Install dependencies
npm installRun tests
npm testRun tests with coverage
npm run test:coverageBuild
npm run buildLint
npm run lint
``This package achieves 90%+ test coverage with comprehensive tests covering:
- Variable detection across all supported engines
- Syntax validation for each template engine
- Type validation for all variable types
- Real-world email and document templates
- Edge cases and error conditions
- @bernierllc/template-engine - Template rendering engine
- @bernierllc/email-validator - Email content validation
- @bernierllc/csv-validator - CSV data validation
Copyright (c) 2025 Bernier LLC. All rights reserved.
This file is licensed to the client under a limited-use license.
The client may use and modify this code only within the scope of the project it was delivered for.
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.