Moving everything over to use the string template library, now just need to escape spaces properly and handle HTML escaping.
This commit is contained in:
parent
e8ef03bb1c
commit
4c597ed91a
|
@ -76,7 +76,6 @@
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"fast-sort": "^2.2.0",
|
"fast-sort": "^2.2.0",
|
||||||
"lodash": "^4.17.13",
|
"lodash": "^4.17.13",
|
||||||
"mustache": "^4.0.1",
|
|
||||||
"posthog-js": "1.4.5",
|
"posthog-js": "1.4.5",
|
||||||
"remixicon": "^2.5.0",
|
"remixicon": "^2.5.0",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
export const CAPTURE_VAR_INSIDE_MUSTACHE = /{{([^}]+)}}/g
|
export const CAPTURE_VAR_INSIDE_TEMPLATE = /{{([^}]+)}}/g
|
||||||
|
|
||||||
export function readableToRuntimeBinding(bindableProperties, textWithBindings) {
|
export function readableToRuntimeBinding(bindableProperties, textWithBindings) {
|
||||||
// Find all instances of mustasche
|
// Find all instances of template strings
|
||||||
const boundValues = textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE)
|
const boundValues = textWithBindings.match(CAPTURE_VAR_INSIDE_TEMPLATE)
|
||||||
|
|
||||||
let result = textWithBindings
|
let result = textWithBindings
|
||||||
// Replace readableBindings with runtimeBindings
|
// Replace readableBindings with runtimeBindings
|
||||||
|
@ -22,7 +22,7 @@ export function runtimeToReadableBinding(bindableProperties, textWithBindings) {
|
||||||
let temp = textWithBindings
|
let temp = textWithBindings
|
||||||
const boundValues =
|
const boundValues =
|
||||||
(typeof textWithBindings === "string" &&
|
(typeof textWithBindings === "string" &&
|
||||||
textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE)) ||
|
textWithBindings.match(CAPTURE_VAR_INSIDE_TEMPLATE)) ||
|
||||||
[]
|
[]
|
||||||
|
|
||||||
// Replace runtimeBindings with readableBindings:
|
// Replace runtimeBindings with readableBindings:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export function uuid() {
|
export function uuid() {
|
||||||
// always want to make this start with a letter, as this makes it
|
// always want to make this start with a letter, as this makes it
|
||||||
// easier to use with mustache bindings in the client
|
// easier to use with template string bindings in the client
|
||||||
return "cxxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, c => {
|
return "cxxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, c => {
|
||||||
const r = (Math.random() * 16) | 0,
|
const r = (Math.random() * 16) | 0,
|
||||||
v = c == "x" ? r : (r & 0x3) | 0x8
|
v = c == "x" ? r : (r & 0x3) | 0x8
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import mustache from "mustache"
|
import { processString } from "@budibase/string-templates"
|
||||||
import { get } from "lodash/fp"
|
import { get } from "lodash/fp"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Fill in bindings with handlebars
|
// Fill in bindings with templating library
|
||||||
return mustache.render(formattedTagline, { inputs })
|
return processString(formattedTagline, { inputs })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -5324,11 +5324,6 @@ ms@2.1.2, ms@^2.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||||
|
|
||||||
mustache@^4.0.1:
|
|
||||||
version "4.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.0.1.tgz#d99beb031701ad433338e7ea65e0489416c854a2"
|
|
||||||
integrity sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA==
|
|
||||||
|
|
||||||
nan@^2.12.1:
|
nan@^2.12.1:
|
||||||
version "2.14.2"
|
version "2.14.2"
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/string-templates": "^0.5.3",
|
"@budibase/string-templates": "^0.5.3",
|
||||||
"deep-equal": "^2.0.1",
|
"deep-equal": "^2.0.1",
|
||||||
"mustache": "^4.0.1",
|
|
||||||
"regexparam": "^1.3.0",
|
"regexparam": "^1.3.0",
|
||||||
"svelte-spa-router": "^3.0.5"
|
"svelte-spa-router": "^3.0.5"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,23 +1,7 @@
|
||||||
import mustache from "mustache"
|
import { processString } from "@budibase/string-templates"
|
||||||
|
|
||||||
// this is a much more liberal version of mustache's escape function
|
// Regex to test inputs with to see if they are likely candidates for template strings
|
||||||
// ...just ignoring < and > to prevent tags from user input
|
const looksLikeTemplate = /{{.*}}/
|
||||||
// original version here https://github.com/janl/mustache.js/blob/4b7908f5c9fec469a11cfaed2f2bed23c84e1c5c/mustache.js#L78
|
|
||||||
const entityMap = {
|
|
||||||
"<": "<",
|
|
||||||
">": ">",
|
|
||||||
}
|
|
||||||
mustache.escape = text => {
|
|
||||||
if (text == null || typeof text !== "string") {
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
return text.replace(/[<>]/g, function fromEntityMap(s) {
|
|
||||||
return entityMap[s] || s
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regex to test inputs with to see if they are likely candidates for mustache
|
|
||||||
const looksLikeMustache = /{{.*}}/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enriches a given input with a row from the database.
|
* Enriches a given input with a row from the database.
|
||||||
|
@ -27,11 +11,11 @@ export const enrichDataBinding = (input, context) => {
|
||||||
if (!input || typeof input !== "string") {
|
if (!input || typeof input !== "string") {
|
||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
// Do a fast regex check if this looks like a mustache string
|
// Do a fast regex check if this looks like a template string
|
||||||
if (!looksLikeMustache.test(input)) {
|
if (!looksLikeTemplate.test(input)) {
|
||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
return mustache.render(input, context)
|
return processString(input, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1362,11 +1362,6 @@ minimatch@^3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^1.1.7"
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
mustache@^4.0.1:
|
|
||||||
version "4.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.0.1.tgz#d99beb031701ad433338e7ea65e0489416c854a2"
|
|
||||||
integrity sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA==
|
|
||||||
|
|
||||||
nwsapi@^2.2.0:
|
nwsapi@^2.2.0:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
|
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
"main": "dist/bundle.js",
|
"main": "dist/bundle.js",
|
||||||
"module": "dist/bundle.js",
|
"module": "dist/bundle.js",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rollup -c",
|
"build": "rollup -c",
|
||||||
|
|
|
@ -1,10 +1,26 @@
|
||||||
const Helper = require("./Helper")
|
const Helper = require("./Helper")
|
||||||
const { SafeString } = require("handlebars")
|
const { SafeString } = require("handlebars")
|
||||||
|
|
||||||
|
const HTML_SWAPS = {
|
||||||
|
"<": "<",
|
||||||
|
">": ">",
|
||||||
|
}
|
||||||
|
|
||||||
const HELPERS = [
|
const HELPERS = [
|
||||||
|
// external helpers
|
||||||
new Helper("object", value => {
|
new Helper("object", value => {
|
||||||
return new SafeString(JSON.stringify(value))
|
return new SafeString(JSON.stringify(value))
|
||||||
}),
|
}),
|
||||||
|
// this help is applied to all statements
|
||||||
|
new Helper("all", value => {
|
||||||
|
let text = unescape(value).replace(/&/g, '&');
|
||||||
|
if (text == null || typeof text !== "string") {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
return text.replace(/[<>]/g, tag => {
|
||||||
|
return HTML_SWAPS[tag] || tag
|
||||||
|
})
|
||||||
|
})
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports.registerAll = handlebars => {
|
module.exports.registerAll = handlebars => {
|
||||||
|
|
|
@ -2,6 +2,7 @@ const handlebars = require("handlebars")
|
||||||
const { registerAll } = require("./helpers/index")
|
const { registerAll } = require("./helpers/index")
|
||||||
|
|
||||||
const HBS_CLEANING_REGEX = /{{[^}}]*}}/g
|
const HBS_CLEANING_REGEX = /{{[^}}]*}}/g
|
||||||
|
const FIND_HBS_REGEX = /{{.*}}/
|
||||||
|
|
||||||
const hbsInstance = handlebars.create()
|
const hbsInstance = handlebars.create()
|
||||||
registerAll(hbsInstance)
|
registerAll(hbsInstance)
|
||||||
|
@ -22,6 +23,12 @@ function attemptToCorrectError(string) {
|
||||||
* @returns {string} The string that was input with cleaned up handlebars statements as required.
|
* @returns {string} The string that was input with cleaned up handlebars statements as required.
|
||||||
*/
|
*/
|
||||||
function cleanHandlebars(string) {
|
function cleanHandlebars(string) {
|
||||||
|
// TODO: handle these types of statement
|
||||||
|
// every statement must have the "all" helper added e.g.
|
||||||
|
// {{ person }} => {{ html person }}
|
||||||
|
// escaping strings must be handled as such:
|
||||||
|
// {{ person name }} => {{ [person name] }}
|
||||||
|
// {{ obj.person name }} => {{ obj.[person name] }}
|
||||||
let charToReplace = {
|
let charToReplace = {
|
||||||
"[": ".",
|
"[": ".",
|
||||||
"]": "",
|
"]": "",
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
const {
|
||||||
|
processString,
|
||||||
|
} = require("../src/index")
|
||||||
|
|
||||||
|
describe("Handling context properties with spaces in their name", () => {
|
||||||
|
it("should be able to handle a property with a space in its name", () => {
|
||||||
|
const output = processString("hello my name is {{ person name }}", {
|
||||||
|
"person name": "Mike",
|
||||||
|
})
|
||||||
|
expect(output).toBe("hello my name is Mike")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to handle an object with layers that requires escaping", () => {
|
||||||
|
const output = processString("testcase {{ testing.test case }}", {
|
||||||
|
testing: {
|
||||||
|
"test case": 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(output).toBe("testcase 1")
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,12 @@
|
||||||
|
const {
|
||||||
|
processString,
|
||||||
|
} = require("../src/index")
|
||||||
|
|
||||||
|
describe("test the custom helpers we have applied", () => {
|
||||||
|
it("should be able to use the object helper", () => {
|
||||||
|
const output = processString("object is {{ object obj }}", {
|
||||||
|
obj: { a: 1 },
|
||||||
|
})
|
||||||
|
expect(output).toBe("object is {\"a\":1}")
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue