UNPKG

serverless-offline

Version:

Emulate AWS λ and API Gateway locally when developing your Serverless project

99 lines (81 loc) 2.87 kB
import velocityjs from "velocityjs" import { log } from "../../../utils/log.js" import runInPollutedScope from "../javaHelpers.js" import { isPlainObject } from "../../../utils/index.js" const { parse } = JSON const { entries } = Object function tryToParseJSON(string) { let parsed try { parsed = parse(string) } catch { // nothing! Some things are not meant to be parsed. } return parsed || string } function renderVelocityString(velocityString, context) { // runs in a "polluted" (extended) String.prototype replacement scope const renderResult = runInPollutedScope(() => // This line can throw, but this function does not handle errors // Quick args explanation: // { escape: false } --> otherwise would escape &, < and > chars with html (&amp;, &lt; and &gt;) // render(context, null, true) --> null: no custom macros; true: silent mode, just like APIG new velocityjs.Compile(velocityjs.parse(velocityString), { escape: false, }).render(context, null, true), ) log.debug("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. */ export default 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)) { entries(toProcess).forEach(([key, value]) => { log.debug("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 }