@rudderstack/json-template-engine
Version:
A library for evaluating JSON template expressions.
152 lines (151 loc) • 6.18 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsonTemplateEngine = void 0;
/* eslint-disable import/no-cycle */
const constants_1 = require("./constants");
const mapping_1 = require("./errors/mapping");
const lexer_1 = require("./lexer");
const parser_1 = require("./parser");
const reverse_translator_1 = require("./reverse_translator");
const translator_1 = require("./translator");
const types_1 = require("./types");
const utils_1 = require("./utils");
class JsonTemplateEngine {
constructor(fn) {
this.fn = fn;
}
static compileAsSync(template, options) {
// eslint-disable-next-line @typescript-eslint/no-implied-eval
return Function(constants_1.DATA_PARAM_KEY, constants_1.BINDINGS_PARAM_KEY, JsonTemplateEngine.translate(template, options));
}
static compileAsAsync(templateOrExpr, options) {
return (0, utils_1.CreateAsyncFunction)(constants_1.DATA_PARAM_KEY, constants_1.BINDINGS_PARAM_KEY, JsonTemplateEngine.translate(templateOrExpr, options));
}
static translateExpression(expr) {
const translator = new translator_1.JsonTemplateTranslator(expr);
return translator.translate();
}
static isValidJSONPath(path = '') {
try {
const expression = JsonTemplateEngine.parse(path, { defaultPathType: types_1.PathType.JSON });
const statement = expression.statements?.[0];
return (statement &&
statement.type === types_1.SyntaxType.PATH &&
(!statement.root || statement.root === constants_1.DATA_PARAM_KEY));
}
catch (e) {
return false;
}
}
static toJsonPath(input) {
if (input.startsWith('$')) {
return input;
}
// Check if it's wrapped in quotes
// or is a simple identifier
// or contains dots
if (/^'.*'$/.test(input) ||
/^".*"$/.test(input) ||
/^\w+$/.test(input) ||
input.includes('.')) {
return `$.${input}`;
}
// If input contains special characters
return `$.'${input}'`;
}
static convertToJSONPath(path, options) {
if (!path) {
return path;
}
if (options?.defaultPathType === types_1.PathType.JSON) {
return JsonTemplateEngine.toJsonPath(path);
}
return path;
}
static prepareMapping(mapping, options) {
return {
...mapping,
input: mapping.input ?? mapping.from,
output: JsonTemplateEngine.convertToJSONPath(mapping.output ?? mapping.to, options),
};
}
static prepareMappings(mappings, options) {
return mappings
.map((mapping) => JsonTemplateEngine.prepareMapping(mapping, options))
.filter((mapping) => mapping.input && mapping.output);
}
static validateMappings(mappings, options) {
JsonTemplateEngine.prepareMappings(mappings, options).forEach((mapping) => {
if (!JsonTemplateEngine.isValidJSONPath(mapping.output)) {
throw new mapping_1.JsonTemplateMappingError('Invalid mapping: invalid JSON path', mapping.input, mapping.output);
}
});
JsonTemplateEngine.parseMappingPaths(mappings, options);
}
static isValidMapping(mapping, options) {
try {
JsonTemplateEngine.validateMappings([mapping], options);
return true;
}
catch (e) {
return false;
}
}
static createFlatMappingsAST(mappings, options) {
const newOptions = { ...options, mappings: true };
return JsonTemplateEngine.prepareMappings(mappings, options)
.filter((mapping) => mapping.input && mapping.output)
.map((mapping) => ({
...mapping,
inputExpr: JsonTemplateEngine.parse(mapping.input, newOptions).statements[0],
outputExpr: JsonTemplateEngine.parse(mapping.output, newOptions).statements[0],
}));
}
static parseMappingPaths(mappings, options) {
return (0, utils_1.convertToObjectMapping)(JsonTemplateEngine.createFlatMappingsAST(mappings, options));
}
static create(templateOrExpr, options) {
return new JsonTemplateEngine(JsonTemplateEngine.compileAsAsync(templateOrExpr, options));
}
static createAsSync(template, options) {
return new JsonTemplateEngine(JsonTemplateEngine.compileAsSync(template, options));
}
static parse(template, options) {
if (!template) {
return constants_1.EMPTY_EXPR;
}
if ((0, utils_1.isExpression)(template)) {
return template;
}
if (typeof template === 'string') {
const lexer = new lexer_1.JsonTemplateLexer(template);
const parser = new parser_1.JsonTemplateParser(lexer, options);
return parser.parse();
}
return JsonTemplateEngine.parseMappingPaths(template, options);
}
static translate(template, options) {
return JsonTemplateEngine.translateExpression(JsonTemplateEngine.parse(template, options));
}
static reverseTranslate(expr, options) {
const translator = new reverse_translator_1.JsonTemplateReverseTranslator(options);
let newExpr = expr;
if (Array.isArray(expr)) {
newExpr = JsonTemplateEngine.parseMappingPaths(expr, options);
}
return translator.translate(newExpr);
}
static convertMappingsToTemplate(mappings, options) {
return JsonTemplateEngine.reverseTranslate(JsonTemplateEngine.parse(mappings, options), options);
}
static evaluateAsSync(template, options = {}, data = {}, bindings = {}) {
return JsonTemplateEngine.createAsSync(template, options).evaluate(data, bindings);
}
static evaluate(template, options = {}, data = {}, bindings = {}) {
return JsonTemplateEngine.create(template, options).evaluate(data, bindings);
}
evaluate(data = {}, bindings = {}) {
return this.fn(data, bindings);
}
}
exports.JsonTemplateEngine = JsonTemplateEngine;