From 8ecabc91cc4b9367bdaf9571235ed230cb7bef1f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 21 Jan 2021 11:32:26 +0000 Subject: [PATCH 1/3] Linting. --- .../common/Dropdowns/DropdownItem.svelte | 4 +- .../userInterface/BindingPanel.svelte | 16 ++--- .../IconSelect/IconSelect.svelte | 10 +-- .../userInterface/PropertyControl.svelte | 18 +++-- .../userInterface/TableViewSelect.svelte | 65 ++++++++++--------- packages/client/src/utils/buttonActions.js | 4 +- .../static/templates/BudibaseApp.svelte | 4 +- packages/standard-components/src/Icon.svelte | 4 +- packages/string-templates/jest.config.js | 2 +- packages/string-templates/rollup.config.js | 2 +- .../src/custom/preprocessor.js | 22 +++++-- .../string-templates/src/helpers/index.js | 10 +-- packages/string-templates/src/index.js | 6 +- packages/string-templates/src/utilities.js | 2 +- 14 files changed, 95 insertions(+), 74 deletions(-) diff --git a/packages/builder/src/components/common/Dropdowns/DropdownItem.svelte b/packages/builder/src/components/common/Dropdowns/DropdownItem.svelte index f6f1ec2d12..98fda9efb1 100644 --- a/packages/builder/src/components/common/Dropdowns/DropdownItem.svelte +++ b/packages/builder/src/components/common/Dropdowns/DropdownItem.svelte @@ -11,9 +11,7 @@ on:click class:big={subtitle != null} {...$$restProps}> - {#if icon} - - {/if} + {#if icon}{/if}
{title}
{#if subtitle != null} diff --git a/packages/builder/src/components/userInterface/BindingPanel.svelte b/packages/builder/src/components/userInterface/BindingPanel.svelte index 1e40e8e001..6ab2504077 100644 --- a/packages/builder/src/components/userInterface/BindingPanel.svelte +++ b/packages/builder/src/components/userInterface/BindingPanel.svelte @@ -1,12 +1,6 @@ - + diff --git a/packages/string-templates/jest.config.js b/packages/string-templates/jest.config.js index 3c3d264fa5..c6391cdb92 100644 --- a/packages/string-templates/jest.config.js +++ b/packages/string-templates/jest.config.js @@ -191,4 +191,4 @@ module.exports = { // Whether to use watchman for file crawling // watchman: true, -}; +} diff --git a/packages/string-templates/rollup.config.js b/packages/string-templates/rollup.config.js index fa215261dc..f4cf851f92 100644 --- a/packages/string-templates/rollup.config.js +++ b/packages/string-templates/rollup.config.js @@ -11,7 +11,7 @@ export default { name: "string-templates", exports: "named", globals: { - "fs": "fs", + fs: "fs", }, }, external: ["fs"], diff --git a/packages/string-templates/src/custom/preprocessor.js b/packages/string-templates/src/custom/preprocessor.js index f562c67c6a..6c851432f3 100644 --- a/packages/string-templates/src/custom/preprocessor.js +++ b/packages/string-templates/src/custom/preprocessor.js @@ -1,5 +1,10 @@ const { HelperFunctions } = require("../helpers") -const { swapStrings, isAlphaNumeric, FIND_HBS_REGEX, includesAny } = require("../utilities") +const { + swapStrings, + isAlphaNumeric, + FIND_HBS_REGEX, + includesAny, +} = require("../utilities") function handleProcessor(string, match, fn) { const output = fn(match) @@ -27,7 +32,9 @@ function handleSpacesInProperties(statement) { // find all the parts split by spaces const splitBySpaces = statement.split(" ") // remove the excluded elements - const propertyParts = splitBySpaces.filter(part => exclusions.indexOf(part) === -1) + const propertyParts = splitBySpaces.filter( + part => exclusions.indexOf(part) === -1 + ) // rebuild to get the full property const fullProperty = propertyParts.join(" ") // now work out the dot notation layers and split them up @@ -35,7 +42,12 @@ function handleSpacesInProperties(statement) { // find the layers which need to be wrapped and wrap them for (let layer of propertyLayers) { if (layer.indexOf(" ") !== -1) { - statement = swapStrings(statement, statement.indexOf(layer), layer.length, `[${layer}]`) + statement = swapStrings( + statement, + statement.indexOf(layer), + layer.length, + `[${layer}]` + ) } } // remove the edge case of double brackets being entered (in-case user already has specified) @@ -67,7 +79,7 @@ function finalise(statement) { * @param {string} string The string which *may* contain handlebars statements, it is OK if it does not contain any. * @returns {string} The string that was input with processed up handlebars statements as required. */ -module.exports.preprocess = (string) => { +module.exports.preprocess = string => { let preprocessors = [swapToDotNotation, handleSpacesInProperties, finalise] for (let processor of preprocessors) { // re-run search each time incase previous cleaner update/removed a match @@ -81,4 +93,4 @@ module.exports.preprocess = (string) => { } } return string -} \ No newline at end of file +} diff --git a/packages/string-templates/src/helpers/index.js b/packages/string-templates/src/helpers/index.js index 498ac40dce..768fe297af 100644 --- a/packages/string-templates/src/helpers/index.js +++ b/packages/string-templates/src/helpers/index.js @@ -12,7 +12,7 @@ const HelperFunctionBuiltin = [ "#each", "#with", "lookup", - "log" + "log", ] const HelperFunctionNames = { @@ -27,17 +27,19 @@ const HELPERS = [ }), // this help is applied to all statements new Helper(HelperFunctionNames.ALL, value => { - let text = new SafeString(unescape(value).replace(/&/g, '&')) + let text = new SafeString(unescape(value).replace(/&/g, "&")) if (text == null || typeof text !== "string") { return text } return text.replace(/[<>]/g, tag => { return HTML_SWAPS[tag] || tag }) - }) + }), ] -module.exports.HelperFunctions = Object.values(HelperFunctionNames).concat(HelperFunctionBuiltin) +module.exports.HelperFunctions = Object.values(HelperFunctionNames).concat( + HelperFunctionBuiltin +) module.exports.registerAll = handlebars => { for (let helper of HELPERS) { diff --git a/packages/string-templates/src/index.js b/packages/string-templates/src/index.js index 5f34259260..58ae887e20 100644 --- a/packages/string-templates/src/index.js +++ b/packages/string-templates/src/index.js @@ -30,8 +30,7 @@ module.exports.processObject = async (object, context) => { let val = object[key] if (typeof val === "string") { object[key] = await module.exports.processString(object[key], context) - } - else if (typeof val === "object") { + } else if (typeof val === "object") { object[key] = await module.exports.processObject(object[key], context) } } @@ -64,8 +63,7 @@ module.exports.processObjectSync = (object, context) => { let val = object[key] if (typeof val === "string") { object[key] = module.exports.processStringSync(object[key], context) - } - else if (typeof val === "object") { + } else if (typeof val === "object") { object[key] = module.exports.processObjectSync(object[key], context) } } diff --git a/packages/string-templates/src/utilities.js b/packages/string-templates/src/utilities.js index c7179aac75..76edaef923 100644 --- a/packages/string-templates/src/utilities.js +++ b/packages/string-templates/src/utilities.js @@ -2,7 +2,7 @@ const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g module.exports.FIND_HBS_REGEX = /{{[^}}]*}}/g -module.exports.isAlphaNumeric = (char) => { +module.exports.isAlphaNumeric = char => { return char.match(ALPHA_NUMERIC_REGEX) } From eb627c52d8f3427bb036db868e19061e03b484d4 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 21 Jan 2021 11:37:16 +0000 Subject: [PATCH 2/3] Re-writing pre-processor to be a bit clearer. --- .../src/custom/preprocessor.js | 126 ++++++++++-------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/packages/string-templates/src/custom/preprocessor.js b/packages/string-templates/src/custom/preprocessor.js index 6c851432f3..ffd81f1693 100644 --- a/packages/string-templates/src/custom/preprocessor.js +++ b/packages/string-templates/src/custom/preprocessor.js @@ -6,67 +6,76 @@ const { includesAny, } = require("../utilities") -function handleProcessor(string, match, fn) { - const output = fn(match) - const idx = string.indexOf(match) - return swapStrings(string, idx, match.length, output) +class Preprocessor { + constructor(name, fn) { + this.name = name + this.fn = fn + } + + process(fullString, statement) { + const output = this.fn(statement) + const idx = fullString.indexOf(statement) + return swapStrings(fullString, idx, statement.length, output) + } } -function swapToDotNotation(statement) { - let startBraceIdx = statement.indexOf("[") - let lastIdx = 0 - while (startBraceIdx !== -1) { - // if the character previous to the literal specifier is alpha-numeric this should happen - if (isAlphaNumeric(statement.charAt(startBraceIdx - 1))) { - statement = swapStrings(statement, startBraceIdx + lastIdx, 1, ".[") +const PROCESSORS = [ + new Preprocessor("swap-to-dot-notation", statement => { + let startBraceIdx = statement.indexOf("[") + let lastIdx = 0 + while (startBraceIdx !== -1) { + // if the character previous to the literal specifier is alpha-numeric this should happen + if (isAlphaNumeric(statement.charAt(startBraceIdx - 1))) { + statement = swapStrings(statement, startBraceIdx + lastIdx, 1, ".[") + } + lastIdx = startBraceIdx + 1 + startBraceIdx = statement.substring(lastIdx + 1).indexOf("[") } - lastIdx = startBraceIdx + 1 - startBraceIdx = statement.substring(lastIdx + 1).indexOf("[") - } - return statement -} + return statement + }), -function handleSpacesInProperties(statement) { - // exclude helpers and brackets, regex will only find double brackets - const exclusions = HelperFunctions.concat(["{{", "}}"]) - // find all the parts split by spaces - const splitBySpaces = statement.split(" ") - // remove the excluded elements - const propertyParts = splitBySpaces.filter( - part => exclusions.indexOf(part) === -1 - ) - // rebuild to get the full property - const fullProperty = propertyParts.join(" ") - // now work out the dot notation layers and split them up - const propertyLayers = fullProperty.split(".") - // find the layers which need to be wrapped and wrap them - for (let layer of propertyLayers) { - if (layer.indexOf(" ") !== -1) { - statement = swapStrings( - statement, - statement.indexOf(layer), - layer.length, - `[${layer}]` - ) + new Preprocessor("handle-spaces-in-properties", statement => { + // exclude helpers and brackets, regex will only find double brackets + const exclusions = HelperFunctions.concat(["{{", "}}"]) + // find all the parts split by spaces + const splitBySpaces = statement.split(" ") + // remove the excluded elements + const propertyParts = splitBySpaces.filter( + part => exclusions.indexOf(part) === -1 + ) + // rebuild to get the full property + const fullProperty = propertyParts.join(" ") + // now work out the dot notation layers and split them up + const propertyLayers = fullProperty.split(".") + // find the layers which need to be wrapped and wrap them + for (let layer of propertyLayers) { + if (layer.indexOf(" ") !== -1) { + statement = swapStrings( + statement, + statement.indexOf(layer), + layer.length, + `[${layer}]` + ) + } } - } - // remove the edge case of double brackets being entered (in-case user already has specified) - return statement.replace(/\[\[/g, "[").replace(/]]/g, "]") -} + // remove the edge case of double brackets being entered (in-case user already has specified) + return statement.replace(/\[\[/g, "[").replace(/]]/g, "]") + }), -function finalise(statement) { - let insideStatement = statement.slice(2, statement.length - 2) - if (insideStatement.charAt(0) === " ") { - insideStatement = insideStatement.slice(1) - } - if (insideStatement.charAt(insideStatement.length - 1) === " ") { - insideStatement = insideStatement.slice(0, insideStatement.length - 1) - } - if (includesAny(insideStatement, HelperFunctions)) { - insideStatement = `(${insideStatement})` - } - return `{{ all ${insideStatement} }}` -} + new Preprocessor("finalise", statement => { + let insideStatement = statement.slice(2, statement.length - 2) + if (insideStatement.charAt(0) === " ") { + insideStatement = insideStatement.slice(1) + } + if (insideStatement.charAt(insideStatement.length - 1) === " ") { + insideStatement = insideStatement.slice(0, insideStatement.length - 1) + } + if (includesAny(insideStatement, HelperFunctions)) { + insideStatement = `(${insideStatement})` + } + return `{{ all ${insideStatement} }}` + }) +] /** * When running handlebars statements to execute on the context of the automation it possible user's may input handlebars @@ -80,16 +89,15 @@ function finalise(statement) { * @returns {string} The string that was input with processed up handlebars statements as required. */ module.exports.preprocess = string => { - let preprocessors = [swapToDotNotation, handleSpacesInProperties, finalise] - for (let processor of preprocessors) { - // re-run search each time incase previous cleaner update/removed a match + for (let processor of PROCESSORS) { + // re-run search each time incase previous processor updated/removed a match let regex = new RegExp(FIND_HBS_REGEX) let matches = string.match(regex) if (matches == null) { continue } for (let match of matches) { - string = handleProcessor(string, match, processor) + string = processor.process(string, match) } } return string From d3789c90691446bc4d34e9f48dc1cd2b7ff4d088 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 21 Jan 2021 12:08:57 +0000 Subject: [PATCH 3/3] More fixes for issues found by cheeks, as well as adding a test case for rendering app. --- packages/string-templates/src/utilities.js | 2 +- packages/string-templates/test/basic.spec.js | 7 ++++ .../string-templates/test/escapes.spec.js | 16 +++++++++ .../string-templates/test/renderApp.spec.js | 33 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 packages/string-templates/test/renderApp.spec.js diff --git a/packages/string-templates/src/utilities.js b/packages/string-templates/src/utilities.js index 76edaef923..bb35e94567 100644 --- a/packages/string-templates/src/utilities.js +++ b/packages/string-templates/src/utilities.js @@ -1,6 +1,6 @@ const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g -module.exports.FIND_HBS_REGEX = /{{[^}}]*}}/g +module.exports.FIND_HBS_REGEX = /{{([^{}])+}}/g module.exports.isAlphaNumeric = char => { return char.match(ALPHA_NUMERIC_REGEX) diff --git a/packages/string-templates/test/basic.spec.js b/packages/string-templates/test/basic.spec.js index 172c94ca21..6babce8f8c 100644 --- a/packages/string-templates/test/basic.spec.js +++ b/packages/string-templates/test/basic.spec.js @@ -11,6 +11,13 @@ describe("Test that the string processing works correctly", () => { expect(output).toBe("templating is easy") }) + it("should process a literal template", async () => { + const output = await processString("derp is {{{ adjective }}}", { + adjective: "derp" + }) + expect(output).toBe("derp is derp") + }) + it("should fail gracefully when wrong type passed in", async () => { let error = null try { diff --git a/packages/string-templates/test/escapes.spec.js b/packages/string-templates/test/escapes.spec.js index eb94b1ce2e..39df8719d6 100644 --- a/packages/string-templates/test/escapes.spec.js +++ b/packages/string-templates/test/escapes.spec.js @@ -32,4 +32,20 @@ describe("Handling context properties with spaces in their name", () => { }) expect(output).toBe("testcase 1") }) +}) + +describe("attempt some complex problems", () => { + it("should be able to handle a very complex handlebars statement", async () => { + const context = { + "New Repeater": { + "Get Actors": { + "first_name": "Bob", + "last_name": "Bobert" + }, + }, + } + const hbs = "{{ New Repeater.Get Actors.first_name }} {{ New Repeater.Get Actors.last_name }}" + const output = await processString(hbs, context) + expect(output).toBe("Bob Bobert") + }) }) \ No newline at end of file diff --git a/packages/string-templates/test/renderApp.spec.js b/packages/string-templates/test/renderApp.spec.js new file mode 100644 index 0000000000..1ae08ee113 --- /dev/null +++ b/packages/string-templates/test/renderApp.spec.js @@ -0,0 +1,33 @@ +const { processString } = require("../src/index") + +describe("specific test case for whether or not full app template can still be rendered", () => { + it("should be able to render the app template", async () => { + const template = + ` + + + {{{head}}} + + + {{{body}}} + ` + const context = { + appId: "App1", + head: "App", + body: "

App things

" + } + const output = await processString(template, context) + expect(output).toBe(` + + + App + + +

App things

+ `) + }) +}) \ No newline at end of file