@bernierllc/template-validator
v1.0.3
Published
Atomic utility for validating template processing and variable substitution across multiple template engines
Downloads
12
Readme
@bernierllc/template-validator
Atomic utility package for validating template processing and variable substitution across multiple template engines.
Installation
npm install @bernierllc/template-validatorFeatures
- 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
Quick Start
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); // 100API Reference
Core Functions
validateTemplate(template, data, engine?, options?)
Complete template validation with all checks.
interface TemplateValidationResult {
isValid: boolean;
unreplacedVariables: UnreplacedVariable[];
syntaxErrors: TemplateSyntaxError[];
missingVariables: MissingVariable[];
conditionalIssues: ConditionalIssue[];
score: number; // 0-100
}
function validateTemplate(
template: string,
data: Record<string, unknown>,
engine?: TemplateEngine,
options?: ValidationOptions
): TemplateValidationResult;Parameters:
template- Template content to validatedata- Data object for variable checkingengine- Template engine (default:AUTOfor auto-detection)options- Validation options
Options:
interface ValidationOptions {
strictMode?: boolean; // Enable strict validation
allowPartialTemplates?: boolean; // Allow templates with missing data
customPatterns?: VariablePattern[]; // Custom variable patterns
}Example:
const result = validateTemplate(
'{{ user.name }} - {{ user.email }}',
{ user: { name: 'Alice', email: '[email protected]' } },
TemplateEngine.LIQUID,
{ strictMode: true }
);detectUnreplacedVariables(content, engines?, customPatterns?)
Detect all unreplaced template variables.
function detectUnreplacedVariables(
content: string,
engines?: TemplateEngine[],
customPatterns?: VariablePattern[]
): UnreplacedVariable[];Example:
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.
function validateTemplateSyntax(
template: string,
engine?: TemplateEngine
): SyntaxValidationResult;Example:
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.
function validateRequiredVariables(
template: string,
data: Record<string, unknown>,
requirements: VariableRequirement[]
): MissingVariable[];Example:
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.
function extractVariableRequirements(
template: string
): VariableRequirement[];Example:
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 }
// ]Template Engines
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
}Usage Examples
Email Template Validation
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);
}Detecting Missing Variables
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 1Type Validation
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 numberHandlebars Template Validation
import { validateTemplate, TemplateEngine } from '@bernierllc/template-validator';
const handlebarsTemplate = `
<h1>Hello {{user.firstName}} {{user.lastName}}</h1>
{{#if hasOrders}}
<ul>
{{#each orders}}
<li>Order {{this.id}}: ${{this.total}}</li>
{{/each}}
</ul>
{{/if}}
`;
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);Custom Variable Patterns
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); // 0Syntax Validation Only
import { validateTemplateSyntax, TemplateEngine } from '@bernierllc/template-validator';
const template = `
{% if user %}
{{ user.name }}
{% endif %}
{% for item in items %}
{{ item }}
{% endfor %}
`;
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
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 definitions
Development
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build
npm run build
# Lint
npm run lintTesting
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
See Also
- @bernierllc/template-engine - Template rendering engine
- @bernierllc/email-validator - Email content validation
- @bernierllc/csv-validator - CSV data validation
License
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.
