diff --git a/packages/string-templates/src/index.js b/packages/string-templates/src/index.js index 9cedcde061..e7d9b9d7e7 100644 --- a/packages/string-templates/src/index.js +++ b/packages/string-templates/src/index.js @@ -2,7 +2,7 @@ const handlebars = require("handlebars") const { registerAll } = require("./helpers/index") const processors = require("./processors") const { cloneDeep } = require("lodash/fp") -const { removeNull, addConstants } = require("./utilities") +const { removeNull, addConstants, removeHandlebarsStatements } = require("./utilities") const manifest = require("../manifest.json") const hbsInstance = handlebars.create() @@ -83,16 +83,27 @@ module.exports.processObjectSync = (object, context) => { * @returns {string} The enriched string, all templates should have been replaced if they can be. */ module.exports.processStringSync = (string, context) => { + if (!exports.isValid(string)) { + return string + } + // take a copy of input incase error + const input = string let clonedContext = removeNull(cloneDeep(context)) clonedContext = addConstants(clonedContext) // remove any null/undefined properties if (typeof string !== "string") { throw "Cannot process non-string types." } - string = processors.preprocess(string) - // this does not throw an error when template can't be fulfilled, have to try correct beforehand - const template = hbsInstance.compile(string) - return processors.postprocess(template(clonedContext)) + try { + string = processors.preprocess(string) + // this does not throw an error when template can't be fulfilled, have to try correct beforehand + const template = hbsInstance.compile(string, { + strict: false, + }) + return processors.postprocess(template(clonedContext)) + } catch (err) { + return removeHandlebarsStatements(input) + } } /** @@ -110,19 +121,27 @@ module.exports.makePropSafe = property => { * @returns {boolean} Whether or not the input string is valid. */ module.exports.isValid = string => { - const specialCases = ["string", "number", "object", "array"] + const validCases = ["string", "number", "object", "array", "cannot read property"] + // this is a portion of a specific string always output by handlebars in the case of a syntax error + const invalidCases = [`expecting '`] // don't really need a real context to check if its valid const context = {} try { hbsInstance.compile(processors.preprocess(string, false))(context) return true } catch (err) { - const msg = err ? err.message : "" - const foundCase = specialCases.find(spCase => - msg.toLowerCase().includes(spCase) + const msg = err && err.message ? err.message : err + if (!msg) { + return false + } + const invalidCase = invalidCases.some(invalidCase => + msg.toLowerCase().includes(invalidCase) + ) + const validCase = validCases.some(validCase => + msg.toLowerCase().includes(validCase) ) // special case for maths functions - don't have inputs yet - return !!foundCase + return validCase && !invalidCase } } diff --git a/packages/string-templates/src/processors/preprocessor.js b/packages/string-templates/src/processors/preprocessor.js index af6d656eaa..ee3a3a9730 100644 --- a/packages/string-templates/src/processors/preprocessor.js +++ b/packages/string-templates/src/processors/preprocessor.js @@ -63,7 +63,7 @@ module.exports.processors = [ return statement } } - if (HelperNames().some(option => possibleHelper.includes(option))) { + if (HelperNames().some(option => option.includes(possibleHelper))) { insideStatement = `(${insideStatement})` } return `{{ all ${insideStatement} }}` diff --git a/packages/string-templates/src/utilities.js b/packages/string-templates/src/utilities.js index da3aa6ee94..b33e8bfe1d 100644 --- a/packages/string-templates/src/utilities.js +++ b/packages/string-templates/src/utilities.js @@ -32,3 +32,16 @@ module.exports.addConstants = obj => { } return obj } + +module.exports.removeHandlebarsStatements = string => { + let regexp = new RegExp(exports.FIND_HBS_REGEX) + let matches = string.match(regexp) + if (matches == null) { + return string + } + for (let match of matches) { + const idx = string.indexOf(match) + string = exports.swapStrings(string, idx, match.length, "Invalid Binding") + } + return string +} diff --git a/packages/string-templates/test/helpers.spec.js b/packages/string-templates/test/helpers.spec.js index 4a4ed6592a..cd659fcc78 100644 --- a/packages/string-templates/test/helpers.spec.js +++ b/packages/string-templates/test/helpers.spec.js @@ -316,4 +316,18 @@ describe("Cover a few complex use cases", () => { const validity = isValid("{{ subtract [c390c23a7f1b6441c98d2fe2a51248ef3].[total profit] [c390c23a7f1b6441c98d2fe2a51248ef3].[total revenue] }}") expect(validity).toBe(true) }) + + it("should confirm a bunch of invalid strings", () => { + const invalids = ["{{ awd )", "{{ awdd () ", "{{ awdwad ", "{{ awddawd }"] + for (let invalid of invalids) { + const validity = isValid(invalid) + expect(validity).toBe(false) + } + }) + + it("input a garbage string, expect it to be returned", async () => { + const input = `{{{{{{ } {{ ]] ] ] }}} {{ ] {{ { } { dsa { dddddd }}}}}}} }DDD` + const output = await processString(input, {}) + expect(output).toBe(input) + }) }) \ No newline at end of file