@combino/plugin-eta
Version:
ETA template engine plugin for Combino
91 lines • 4.08 kB
JavaScript
import { Eta } from 'eta';
import * as path from 'path';
import * as fs from 'fs';
export default function plugin(options = {}) {
const defaultPatterns = ['*'];
const patterns = options.patterns || defaultPatterns;
// Extract Eta options (everything except patterns)
const { patterns: _, ...etaOptions } = options;
// Constants for layout processing
const PATTERNS = {
explicitLayout: /<% layout\(['"]([^'"]+)['"]\) %>/,
};
// Helper function to check if file matches patterns
function matchesPatterns(filePath) {
const fileName = path.basename(filePath);
return patterns.some((pattern) => {
const regex = new RegExp(pattern.replace(/\./g, '\\.').replace(/\*/g, '.*').replace(/\?/g, '.'));
return regex.test(fileName);
});
}
function shouldSkipProcessing(context) {
return (context.sourcePath.includes('/output/') ||
context.sourcePath.includes('\\output\\') ||
context.sourcePath.includes('/layouts/') ||
context.sourcePath.includes('\\layouts\\'));
}
// Find layout content
async function findLayoutContent(context, layoutPath) {
const resolvedLayoutPath = path.resolve(path.dirname(context.sourcePath), layoutPath);
// Try exact path first
if (fs.existsSync(resolvedLayoutPath)) {
return fs.readFileSync(resolvedLayoutPath, 'utf8');
}
// Try with extensions
const extensions = ['.eta', '.ejs', '.md', '.html', '.txt'];
for (const ext of extensions) {
const pathWithExt = resolvedLayoutPath + ext;
if (fs.existsSync(pathWithExt)) {
return fs.readFileSync(pathWithExt, 'utf8');
}
}
throw new Error(`Layout file not found: ${layoutPath}`);
}
// Extract body content (content outside of layout directive)
function extractBodyContent(content) {
return content.replace(PATTERNS.explicitLayout, '').trim();
}
// Render layout
async function renderLayout(layoutContent, data, body, etaOptions = {}) {
const layoutData = { ...data, body };
const eta = new Eta(etaOptions);
const template = eta.compile(layoutContent);
return template.call(eta, layoutData);
}
return {
compile: async (context) => {
// Only compile files that match our patterns
if (!matchesPatterns(context.id)) {
return { content: context.content, id: context.id };
}
try {
if (shouldSkipProcessing(context)) {
return { content: context.content, id: context.id };
}
// Check for explicit layout
const layoutMatch = context.content.match(PATTERNS.explicitLayout);
if (layoutMatch) {
const layoutContent = await findLayoutContent(context, layoutMatch[1]);
// Extract body content
const bodyContent = extractBodyContent(context.content);
// Render body content
const eta = new Eta(etaOptions);
const bodyTemplate = eta.compile(bodyContent);
const body = bodyTemplate.call(eta, { ...context.data, it: context.data });
// Render layout
const renderedContent = await renderLayout(layoutContent, context.data, body, etaOptions);
return { content: renderedContent, id: context.id };
}
// No layout, just render normally
const eta = new Eta(etaOptions);
const template = eta.compile(context.content);
const renderedContent = template.call(eta, context.data);
return { content: renderedContent, id: context.id };
}
catch (error) {
throw new Error(`Error processing Eta template: ${error}`);
}
},
};
}
//# sourceMappingURL=index.js.map