serverless-offline
Version:
Emulate AWS λ and API Gateway locally when developing your Serverless project
93 lines (66 loc) • 2.68 kB
JavaScript
;
const Velocity = require('velocityjs');
const isPlainObject = require('lodash').isPlainObject;
const debugLog = require('./debugLog');
const Compile = Velocity.Compile;
const parse = Velocity.parse;
function tryToParseJSON(string) {
let parsed;
try {
parsed = JSON.parse(string);
}
catch (err) {
// nothing! Some things are not meant to be parsed.
}
return parsed || string;
}
function renderVelocityString(velocityString, context) {
// This line can throw, but this function does not handle errors
// Quick args explanation:
// { escape: false } --> otherwise would escape &, < and > chars with html (&, < and >)
// render(context, null, true) --> null: no custom macros; true: silent mode, just like APIG
const renderResult = (new Compile(parse(velocityString), { escape: false })).render(context, null, true);
debugLog('Velocity rendered:', renderResult || 'undefined');
// Haaaa Velocity... this language sure loves strings a lot
switch (renderResult) {
case 'undefined':
return undefined; // But we don't, we want JavaScript types
case 'null':
return null;
case 'true':
return true;
case 'false':
return false;
default:
return tryToParseJSON(renderResult);
}
}
/*
Deeply traverses a Serverless-style JSON (Velocity) template
When it finds a string, assumes it's Velocity language and renders it.
*/
module.exports = function renderVelocityTemplateObject(templateObject, context) {
const result = {};
let toProcess = templateObject;
// In some projects, the template object is a string, let us see if it's JSON
if (typeof toProcess === 'string') toProcess = tryToParseJSON(toProcess);
// Let's check again
if (isPlainObject(toProcess)) {
for (let key in toProcess) { // eslint-disable-line prefer-const
const value = toProcess[key];
debugLog('Processing key:', key, '- value:', value);
if (typeof value === 'string') result[key] = renderVelocityString(value, context);
// Go deeper
else if (isPlainObject(value)) result[key] = renderVelocityTemplateObject(value, context);
// This should never happen: value should either be a string or a plain object
else result[key] = value;
}
}
// Still a string? Maybe it's some complex Velocity stuff
else if (typeof toProcess === 'string') {
// If the plugin threw here then you should consider reviewing your template or posting an issue.
const alternativeResult = tryToParseJSON(renderVelocityString(toProcess, context));
return isPlainObject(alternativeResult) ? alternativeResult : result;
}
return result;
};