diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte
index 2a9a64b455..4dc9d9700e 100644
--- a/packages/builder/src/components/common/bindings/BindingPanel.svelte
+++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte
@@ -24,6 +24,7 @@
import { addHBSBinding, addJSBinding } from "./utils"
import CodeMirrorEditor from "components/common/CodeMirrorEditor.svelte"
import { convertToJS } from "@budibase/string-templates"
+ import { admin } from "stores/portal"
const dispatch = createEventDispatcher()
@@ -62,16 +63,24 @@
const updateValue = val => {
valid = isValid(readableToRuntimeBinding(bindings, val))
- console.log(readableToRuntimeBinding(bindings, val))
if (valid) {
dispatch("change", val)
}
}
- // Adds a HBS helper to the expression
- const addHelper = helper => {
- hbsValue = addHBSBinding(hbsValue, getCaretPosition(), helper.text)
- updateValue(hbsValue)
+ // Adds a JS/HBS helper to the expression
+ const addHelper = (helper, js) => {
+ let value
+ const pos = getCaretPosition()
+ if (js) {
+ const decoded = decodeJSBinding(jsValue)
+ value = jsValue = encodeJSBinding(
+ addJSBinding(decoded, pos, helper.text, { helper: true })
+ )
+ } else {
+ value = hbsValue = addHBSBinding(hbsValue, pos, helper.text)
+ }
+ updateValue(value)
}
// Adds a data binding to the expression
@@ -108,7 +117,6 @@
const convert = () => {
const runtime = readableToRuntimeBinding(bindings, hbsValue)
- console.log(runtime)
const runtimeJs = encodeJSBinding(convertToJS(runtime))
jsValue = runtimeToReadableBinding(bindings, runtimeJs)
hbsValue = null
@@ -116,6 +124,17 @@
addBinding("", { forceJS: true })
}
+ const getHelperExample = (helper, js) => {
+ let example = helper.example || ""
+ if (js) {
+ example = convertToJS(example).split("\n")[0].split("= ")[1]
+ if (example === "null;") {
+ example = ""
+ }
+ }
+ return example || ""
+ }
+
onMount(() => {
valid = isValid(readableToRuntimeBinding(bindings, value))
})
@@ -151,18 +170,21 @@
{/if}
{/each}
- {#if filteredHelpers?.length && !usingJS}
+ {#if filteredHelpers?.length}
Helpers
{#each filteredHelpers as helper}
- - addHelper(helper)}>
+
- addHelper(helper, usingJS)}>
{helper.displayText}
{@html helper.description}
-
{helper.example || ""}
+
{getHelperExample(
+ helper,
+ usingJS
+ )}
{/each}
@@ -188,9 +210,11 @@
for more details.
{/if}
-
-
-
+ {#if $admin.isDev}
+
+
+
+ {/if}
{#if allowJS}
diff --git a/packages/builder/src/components/common/bindings/utils.js b/packages/builder/src/components/common/bindings/utils.js
index 42a3f11677..c7b40604ad 100644
--- a/packages/builder/src/components/common/bindings/utils.js
+++ b/packages/builder/src/components/common/bindings/utils.js
@@ -18,10 +18,14 @@ export function addHBSBinding(value, caretPos, binding) {
return value
}
-export function addJSBinding(value, caretPos, binding) {
+export function addJSBinding(value, caretPos, binding, { helper } = {}) {
binding = typeof binding === "string" ? binding : binding.path
value = value == null ? "" : value
- binding = `$("${binding}")`
+ if (!helper) {
+ binding = `$("${binding}")`
+ } else {
+ binding = `helper.${binding}()`
+ }
if (caretPos.start) {
value =
value.substring(0, caretPos.start) +
diff --git a/packages/string-templates/manifest.json b/packages/string-templates/manifest.json
index 748330add2..f8600121f1 100644
--- a/packages/string-templates/manifest.json
+++ b/packages/string-templates/manifest.json
@@ -74,7 +74,7 @@
"b"
],
"numArgs": 2,
- "example": "{{ product 10 5 }} -> 50",
+ "example": "{{ multiply 10 5 }} -> 50",
"description": "Return the product of a
times b
.
\n"
},
"plus": {
diff --git a/packages/string-templates/scripts/gen-collection-info.js b/packages/string-templates/scripts/gen-collection-info.js
index 29df10423f..bfc0ec79ac 100644
--- a/packages/string-templates/scripts/gen-collection-info.js
+++ b/packages/string-templates/scripts/gen-collection-info.js
@@ -108,6 +108,10 @@ function getCommentInfo(file, func) {
if (examples.length > 0) {
docs.example = examples.join(" ")
}
+ // hacky example fix
+ if (docs.example && docs.example.includes("product")) {
+ docs.example = docs.example.replace("product", "multiply")
+ }
docs.description = blocks[0].trim()
return docs
}
@@ -166,7 +170,7 @@ function run() {
// convert all markdown to HTML
for (let collection of Object.values(outputJSON)) {
for (let helper of Object.values(collection)) {
- helper.description = marked(helper.description)
+ helper.description = marked.parse(helper.description)
}
}
fs.writeFileSync(FILENAME, JSON.stringify(outputJSON, null, 2))
diff --git a/packages/string-templates/src/conversion/index.js b/packages/string-templates/src/conversion/index.js
index 51b760b8c5..bbe0c33942 100644
--- a/packages/string-templates/src/conversion/index.js
+++ b/packages/string-templates/src/conversion/index.js
@@ -22,7 +22,29 @@ function getLayers(fullBlock) {
}
function getVariable(variableName) {
- return isNaN(parseFloat(variableName)) ? `$("${variableName}")` : variableName
+ if (!variableName || typeof variableName !== "string") {
+ return variableName
+ }
+ // it is an array
+ const arrayOrObject = [",", "{", ":"]
+ let contains = false
+ arrayOrObject.forEach(char => {
+ if (variableName.includes(char)) {
+ contains = true
+ }
+ })
+ if (variableName.startsWith("[") && contains) {
+ return variableName
+ }
+ // it is just a number
+ if (!isNaN(parseFloat(variableName))) {
+ return variableName
+ }
+ if (variableName.startsWith("'") || variableName.startsWith('"')) {
+ return variableName
+ }
+ // extract variable
+ return `$("${variableName}")`
}
function buildList(parts, value) {
@@ -41,17 +63,34 @@ function buildList(parts, value) {
function splitBySpace(layer) {
const parts = []
let started = null,
+ endChar = null,
last = 0
+ function add(str) {
+ const startsWith = ["]"]
+ while (startsWith.indexOf(str.substring(0, 1)) !== -1) {
+ str = str.substring(1, str.length)
+ }
+ if (str.length > 0) {
+ parts.push(str.trim())
+ }
+ }
+ const continuationChars = ["[", "'", '"']
for (let index = 0; index < layer.length; index++) {
const char = layer[index]
- if (char === "[" && started == null) {
+ if (continuationChars.indexOf(char) !== -1 && started == null) {
started = index
- } else if (char === "]" && started != null && layer[index + 1] !== ".") {
- parts.push(layer.substring(started, index + 1).trim())
+ endChar = char === "[" ? "]" : char
+ } else if (
+ char === endChar &&
+ started != null &&
+ layer[index + 1] !== "."
+ ) {
+ add(layer.substring(started, index + 1))
started = null
- last = index
- } else if (started == null && char === " " && last !== index - 1) {
- parts.push(layer.substring(last, index).trim())
+ endChar = null
+ last = index + 1
+ } else if (started == null && char === " ") {
+ add(layer.substring(last, index))
last = index
}
}
@@ -59,7 +98,7 @@ function splitBySpace(layer) {
(!layer.startsWith("[") || parts.length === 0) &&
last !== layer.length - 1
) {
- parts.push(layer.substring(last, layer.length).trim())
+ add(layer.substring(last, layer.length))
}
return parts
}
diff --git a/packages/string-templates/test/hbsToJs.spec.js b/packages/string-templates/test/hbsToJs.spec.js
index aca2e931fc..63bd80db81 100644
--- a/packages/string-templates/test/hbsToJs.spec.js
+++ b/packages/string-templates/test/hbsToJs.spec.js
@@ -41,11 +41,43 @@ describe("Test that the string processing works correctly", () => {
])
})
- it("Should handle many square brackets in helpers", () => {
+ it("should handle many square brackets in helpers", () => {
const response = convertToJS("Hello {{ avg [user].[_id] [user].[_rev] }}")
checkLines(response, [
"const var1 = helpers.avg($(\"[user].[_id]\"), $(\"[user].[_rev]\"));",
- "return `Hello ${var1}`;"
+ "return `Hello ${var1}`;",
+ ])
+ })
+
+ it("should handle one of the examples (after)", () => {
+ const response = convertToJS("{{ after [1, 2, 3] 1}}")
+ checkLines(response, [
+ "const var1 = helpers.after([1, 2, 3], 1);",
+ "return `${var1}`;",
+ ])
+ })
+
+ it("should handle one of the examples (equalsLength)", () => {
+ const response = convertToJS("{{equalsLength '[1,2,3]' 3}}")
+ checkLines(response, [
+ "const var1 = helpers.equalsLength('[1,2,3]', 3);",
+ "return `${var1}`;"
+ ])
+ })
+
+ it("should handle one of the examples (pluck)", () => {
+ const response = convertToJS("{{pluck [{ 'name': 'Bob' }] 'name' }}")
+ checkLines(response, [
+ "const var1 = helpers.pluck([{ 'name': 'Bob' }], 'name');",
+ "return `${var1}`;",
+ ])
+ })
+
+ it("should handle sorting an array", () => {
+ const response = convertToJS("{{ sort ['b', 'a', 'c'] }}")
+ checkLines(response, [
+ "const var1 = helpers.sort(['b', 'a', 'c']);",
+ "return `${var1}`;",
])
})