jsonblade
Version:
A powerful and modular JSON template engine with extensible filters
134 lines • 6.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.initializeFilters = initializeFilters;
exports.compileJSONTemplateAsync = compileJSONTemplateAsync;
exports.evaluateExpressionAsync = evaluateExpressionAsync;
const filter_registry_1 = require("./filter-registry");
const async_filter_registry_1 = require("./async-filter-registry");
const string_filters_1 = require("./filters/string-filters");
const array_filters_1 = require("./filters/array-filters");
const object_filters_1 = require("./filters/object-filters");
const logic_filters_1 = require("./filters/logic-filters");
const date_filters_1 = require("./filters/date-filters");
const number_filters_1 = require("./filters/number-filters");
const validation_filters_1 = require("./filters/validation-filters");
const template_config_1 = require("./template-config");
const json_template_utils_1 = require("./json-template.utils");
let filtersInitialized = false;
function initializeFilters() {
if (filtersInitialized)
return;
(0, string_filters_1.registerStringFilters)();
(0, array_filters_1.registerArrayFilters)();
(0, object_filters_1.registerObjectFilters)();
(0, logic_filters_1.registerLogicFilters)();
(0, date_filters_1.registerDateFilters)();
(0, number_filters_1.registerNumberFilters)();
(0, validation_filters_1.registerValidationFilters)();
// Initialize async filters
const { registerAsyncFilters } = require("./filters/async-filters");
registerAsyncFilters();
filtersInitialized = true;
}
async function compileJSONTemplateAsync(template, data) {
initializeFilters();
const stringInterpolated = await processStringInterpolations(template, data);
const fullyInterpolated = await processDirectInterpolations(stringInterpolated, data);
return fullyInterpolated;
}
async function processStringInterpolations(template, data) {
const stringMatches = Array.from(template.matchAll(/"([^"]*)"/g));
let result = template;
for (const match of stringMatches) {
const [fullMatch, content] = match;
if (!content.includes("{{")) {
continue;
}
const interpolated = await processInterpolationsInString(content, data);
result = result.replace(fullMatch, `"${interpolated}"`);
}
return result;
}
async function processInterpolationsInString(content, data) {
const expressionMatches = Array.from(content.matchAll(/{{\s*([^}]+)\s*}}/g));
let result = content;
for (const match of expressionMatches) {
const [fullMatch, expr] = match;
const value = await evaluateExpressionAsync(expr.trim(), data);
const stringValue = value == null ? "" : String(value);
result = result.replace(fullMatch, stringValue);
}
return result;
}
async function processDirectInterpolations(template, data) {
const expressionMatches = Array.from(template.matchAll(/{{\s*([^}]+)\s*}}/g));
let result = template;
for (const match of expressionMatches) {
const [fullMatch, expr] = match;
const value = await evaluateExpressionAsync(expr.trim(), data);
const jsonValue = JSON.stringify(value ?? null);
result = result.replace(fullMatch, jsonValue);
}
return result;
}
async function evaluateExpressionAsync(expr, data) {
// Make sure filters are initialized
initializeFilters();
const parts = expr.split("|").map((p) => p.trim());
const [rawPath, ...filterParts] = parts;
let value = (0, json_template_utils_1.getObjectPath)(rawPath, data);
for (const part of filterParts) {
const match = part.match(/^(\w+)(?:\((.*?)\))?$/);
if (!match)
continue;
const [, name, argsString] = match;
// Check if it's an async filter first
if ((0, async_filter_registry_1.hasAsyncFilter)(name)) {
const asyncFn = (0, async_filter_registry_1.getAsyncFilter)(name);
if (asyncFn) {
try {
let args = [];
if (argsString) {
args = parseFilterArguments(argsString, data);
}
value = await asyncFn(value, ...args);
continue;
}
catch (error) {
const config = (0, template_config_1.getTemplateConfig)();
const templateError = (0, template_config_1.createTemplateError)("FILTER_ERROR", `Async filter '${name}' failed: ${error instanceof Error ? error.message : "Unknown error"}`, { filter: name, expression: expr });
(0, template_config_1.handleTemplateError)(templateError, config);
continue;
}
}
}
// Otherwise, use regular filter
const fn = (0, filter_registry_1.getFilter)(name);
if (!fn) {
const config = (0, template_config_1.getTemplateConfig)();
const error = (0, template_config_1.createTemplateError)("UNKNOWN_FILTER", `Unknown filter: ${name}`, { filter: name, expression: expr });
(0, template_config_1.handleTemplateError)(error, config);
continue;
}
let args = [];
if (argsString) {
args = parseFilterArguments(argsString, data);
}
value = fn(value, ...args);
}
return value;
}
function parseFilterArguments(argsString, data) {
const { getObjectPath } = require("./json-template.utils");
return argsString.split(",").map((arg) => {
const trimmed = arg.trim();
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
(trimmed.startsWith("'") && trimmed.endsWith("'"))) {
return trimmed.slice(1, -1);
}
// Try to resolve as data path first, fallback to literal string
const pathValue = getObjectPath(trimmed, data);
return pathValue !== null && pathValue !== undefined ? pathValue : trimmed;
});
}
//# sourceMappingURL=async-json-template.utils.js.map