forked from tsai/budibase
10 changed files with 255 additions and 3 deletions
@ -0,0 +1,87 @@ |
|||||
|
const { getHelperList } = require("../helpers") |
||||
|
|
||||
|
function getLayers(fullBlock) { |
||||
|
let layers = [] |
||||
|
while (fullBlock.length) { |
||||
|
const start = fullBlock.lastIndexOf("("), |
||||
|
end = fullBlock.indexOf(")") |
||||
|
let layer |
||||
|
if (start === -1 || end === -1) { |
||||
|
layer = fullBlock.trim() |
||||
|
fullBlock = "" |
||||
|
} else { |
||||
|
const untrimmed = fullBlock.substring(start, end + 1) |
||||
|
layer = untrimmed.substring(1, untrimmed.length - 1).trim() |
||||
|
fullBlock = |
||||
|
fullBlock.slice(0, start) + |
||||
|
fullBlock.slice(start + untrimmed.length + 1, fullBlock.length) |
||||
|
} |
||||
|
layers.push(layer) |
||||
|
} |
||||
|
return layers |
||||
|
} |
||||
|
|
||||
|
function getVariable(variableName) { |
||||
|
return isNaN(parseFloat(variableName)) ? `$("${variableName}")` : variableName |
||||
|
} |
||||
|
|
||||
|
function buildList(parts, value) { |
||||
|
function build() { |
||||
|
return parts |
||||
|
.map(part => (part.startsWith("helper") ? part : getVariable(part))) |
||||
|
.join(", ") |
||||
|
} |
||||
|
if (!value) { |
||||
|
return parts.length > 1 ? `...[${build()}]` : build() |
||||
|
} else { |
||||
|
return parts.length === 0 ? value : `...[${value}, ${build()}]` |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function splitBySpace(layer) { |
||||
|
const parts = [] |
||||
|
let started = null, |
||||
|
last = 0 |
||||
|
for (let index = 0; index < layer.length; index++) { |
||||
|
const char = layer[index] |
||||
|
if (char === "[" && started == null) { |
||||
|
started = index |
||||
|
} else if (char === "]" && started != null && layer[index + 1] !== ".") { |
||||
|
parts.push(layer.substring(started, index + 1).trim()) |
||||
|
started = null |
||||
|
last = index |
||||
|
} else if (started == null && char === " ") { |
||||
|
parts.push(layer.substring(last, index).trim()) |
||||
|
last = index |
||||
|
} |
||||
|
} |
||||
|
if (!layer.startsWith("[")) { |
||||
|
parts.push(layer.substring(last, layer.length).trim()) |
||||
|
} |
||||
|
return parts |
||||
|
} |
||||
|
|
||||
|
module.exports.convertHBSBlock = (block, blockNumber) => { |
||||
|
const braceLength = block[2] === "{" ? 3 : 2 |
||||
|
block = block.substring(braceLength, block.length - braceLength).trim() |
||||
|
const layers = getLayers(block) |
||||
|
|
||||
|
let value = null |
||||
|
const list = getHelperList() |
||||
|
for (let layer of layers) { |
||||
|
const parts = splitBySpace(layer) |
||||
|
if (value || parts.length > 1) { |
||||
|
// first of layer should always be the helper
|
||||
|
const helper = parts.splice(0, 1) |
||||
|
if (list[helper]) { |
||||
|
value = `helpers.${helper}(${buildList(parts, value)})` |
||||
|
} |
||||
|
} |
||||
|
// no helpers
|
||||
|
else { |
||||
|
value = getVariable(parts[0]) |
||||
|
} |
||||
|
} |
||||
|
// split by space will remove square brackets
|
||||
|
return { variable: `var${blockNumber}`, value } |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
const externalHandlebars = require("./external") |
||||
|
const helperList = require("@budibase/handlebars-helpers") |
||||
|
|
||||
|
module.exports.getHelperList = () => { |
||||
|
let constructed = [] |
||||
|
for (let collection of externalHandlebars.externalCollections) { |
||||
|
constructed.push(helperList[collection]()) |
||||
|
} |
||||
|
const fullMap = {} |
||||
|
for (let collection of constructed) { |
||||
|
for (let [key, func] of Object.entries(collection)) { |
||||
|
fullMap[key] = func |
||||
|
} |
||||
|
} |
||||
|
for (let key of Object.keys(externalHandlebars.addedHelpers)) { |
||||
|
fullMap[key] = externalHandlebars.addedHelpers[key] |
||||
|
} |
||||
|
return fullMap |
||||
|
} |
||||
@ -0,0 +1,84 @@ |
|||||
|
const { |
||||
|
convertToJS |
||||
|
} = require("../src/index.cjs") |
||||
|
|
||||
|
function checkLines(response, lines) { |
||||
|
const toCheck = response.split("\n") |
||||
|
let count = 0 |
||||
|
for (let line of lines) { |
||||
|
expect(toCheck[count++]).toBe(line) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
describe("Test that the string processing works correctly", () => { |
||||
|
it("should convert string without HBS", () => { |
||||
|
const response = convertToJS("Hello my name is Michael") |
||||
|
expect(response).toBe("return `Hello my name is Michael`;") |
||||
|
}) |
||||
|
|
||||
|
it("basic example with square brackets", () => { |
||||
|
const response = convertToJS("{{ [query] }}") |
||||
|
checkLines(response, [ |
||||
|
"const var1 = $(\"[query]\");", |
||||
|
"return `${var1}`;", |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
it("should convert some basic HBS strings", () => { |
||||
|
const response = convertToJS("Hello {{ name }}, welcome to {{ company }}!") |
||||
|
checkLines(response, [ |
||||
|
"const var1 = $(\"name\");", |
||||
|
"const var2 = $(\"company\");", |
||||
|
"return `Hello ${var1}, welcome to ${var2}`;", |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
it("should handle a helper block", () => { |
||||
|
const response = convertToJS("This is the average: {{ avg array }}") |
||||
|
checkLines(response, [ |
||||
|
"const var1 = helpers.avg($(\"array\"));", |
||||
|
"return `This is the average: ${var1}`;", |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
it("should handle multi-variable helper", () => { |
||||
|
const response = convertToJS("This is the average: {{ join ( avg val1 val2 val3 ) }}") |
||||
|
checkLines(response, [ |
||||
|
"const var1 = helpers.join(helpers.avg(...[$(\"val1\"), $(\"val2\"), $(\"val3\")]));", |
||||
|
"return `This is the average: ${var1}`;", |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
it("should handle a complex statement", () => { |
||||
|
const response = convertToJS("This is the average: {{ join ( avg val1 val2 val3 ) val4 }}") |
||||
|
checkLines(response, [ |
||||
|
"const var1 = helpers.join(...[helpers.avg(...[$(\"val1\"), $(\"val2\"), $(\"val3\")]), $(\"val4\")]);", |
||||
|
"return `This is the average: ${var1}`;", |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
it("should handle square brackets", () => { |
||||
|
const response = convertToJS("This is: {{ [val thing] }}") |
||||
|
checkLines(response, [ |
||||
|
"const var1 = $(\"[val thing]\");", |
||||
|
"return `This is: ${var1}`;", |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
it("should handle square brackets with properties", () => { |
||||
|
const response = convertToJS("{{ [user].[_id] }}") |
||||
|
checkLines(response, [ |
||||
|
"const var1 = $(\"[user].[_id]\");", |
||||
|
"return `${var1}`;", |
||||
|
]) |
||||
|
}) |
||||
|
|
||||
|
it("should handle multiple complex statements", () => { |
||||
|
const response = convertToJS("average: {{ avg ( abs val1 ) val2 }} add: {{ add 1 2 }}") |
||||
|
checkLines(response, [ |
||||
|
"const var1 = helpers.avg(...[helpers.abs($(\"val1\")), $(\"val2\")]);", |
||||
|
"const var2 = helpers.add(...[1, 2]);", |
||||
|
"return `average: ${var1} add: ${var2}`;", |
||||
|
]) |
||||
|
}) |
||||
|
}) |
||||
Loading…
Reference in new issue