Merge branch 'frontend-core' of github.com:Budibase/budibase into experimental-hbs-caching

This commit is contained in:
Andrew Kingston 2022-02-07 09:50:17 +00:00
commit a76508c76e
27 changed files with 294 additions and 139 deletions

View File

@ -1,5 +1,5 @@
{
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"npmClient": "yarn",
"packages": [
"packages/*"

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/backend-core",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"description": "Budibase backend core libraries used in server and worker",
"main": "src/index.js",
"author": "Budibase",

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"license": "MPL-2.0",
"svelte": "src/index.js",
"module": "dist/bbui.es.js",

View File

@ -13,6 +13,7 @@
start: textarea.selectionStart,
end: textarea.selectionEnd,
})
export let align = null
let focus = false
let textarea
@ -46,6 +47,7 @@
bind:this={textarea}
placeholder={placeholder || ""}
class="spectrum-Textfield-input"
style={align ? `text-align: ${align}` : ""}
{disabled}
{id}
on:focus={() => (focus = true)}

View File

@ -12,6 +12,7 @@
export let updateOnChange = true
export let quiet = false
export let dataCy
export let align
const dispatch = createEventDispatcher()
let focus = false
@ -92,8 +93,9 @@
on:input={onInput}
on:keyup={updateValueOnEnter}
{type}
inputmode={type === "number" ? "decimal" : "text"}
class="spectrum-Textfield-input"
style={align ? `text-align: ${align};` : ""}
inputmode={type === "number" ? "decimal" : "text"}
/>
</div>

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"license": "GPL-3.0",
"private": true,
"scripts": {
@ -64,10 +64,10 @@
}
},
"dependencies": {
"@budibase/bbui": "^1.0.49-alpha.8",
"@budibase/client": "^1.0.49-alpha.8",
"@budibase/frontend-core": "^1.0.49-alpha.8",
"@budibase/string-templates": "^1.0.49-alpha.8",
"@budibase/bbui": "^1.0.49-alpha.9",
"@budibase/client": "^1.0.49-alpha.9",
"@budibase/frontend-core": "^1.0.49-alpha.9",
"@budibase/string-templates": "^1.0.49-alpha.9",
"@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1",

View File

@ -188,18 +188,17 @@
{:else}
<Body size="S"><i>No tables found.</i></Body>
{/if}
{#if plusTables?.length !== 0 && integration.relationships}
<Divider size="S" />
<div class="query-header">
<Divider size="S" />
<div class="query-header">
<Heading size="S">Relationships</Heading>
<Button primary on:click={openRelationshipModal}>
<Button primary on:click={() => openRelationshipModal()}>
Define relationship
</Button>
</div>
<Body>
</div>
<Body>
Tell budibase how your tables are related to get even more smart features.
</Body>
{#if relationshipInfo && relationshipInfo.length > 0}
</Body>
{#if relationshipInfo && relationshipInfo.length > 0}
<Table
on:click={({ detail }) => openRelationshipModal(detail.from, detail.to)}
schema={relationshipSchema}
@ -208,9 +207,8 @@
allowEditRows={false}
allowSelectRows={false}
/>
{:else}
{:else}
<Body size="S"><i>No relationships configured.</i></Body>
{/if}
{/if}
<style>

View File

@ -22,6 +22,10 @@
let originalFromName = fromRelationship.name,
originalToName = toRelationship.name
let fromTable, toTable, through, linkTable, tableOptions
let isManyToMany, isManyToOne, relationshipTypes
let errors, valid
let currentTables = {}
if (fromRelationship && !fromRelationship.relationshipType) {
fromRelationship.relationshipType = RelationshipTypes.MANY_TO_ONE
@ -41,61 +45,52 @@
const touched = writable({})
function checkForErrors(
fromTable,
toTable,
throughTable,
fromRelate,
toRelate
) {
function checkForErrors(fromRelate, toRelate) {
const isMany =
fromRelate.relationshipType === RelationshipTypes.MANY_TO_MANY
const tableNotSet = "Please specify a table"
const errors = {}
const errObj = {}
if ($touched.from && !fromTable) {
errors.from = tableNotSet
errObj.from = tableNotSet
}
if ($touched.to && !toTable) {
errors.to = tableNotSet
errObj.to = tableNotSet
}
if ($touched.through && isMany && !fromRelate.through) {
errors.through = tableNotSet
errObj.through = tableNotSet
}
if ($touched.foreign && !isMany && !fromRelate.fieldName) {
errors.foreign = "Please pick the foreign key"
errObj.foreign = "Please pick the foreign key"
}
const colNotSet = "Please specify a column name"
if ($touched.fromCol && !fromRelate.name) {
errors.fromCol = colNotSet
errObj.fromCol = colNotSet
}
if ($touched.toCol && !toRelate.name) {
errors.toCol = colNotSet
errObj.toCol = colNotSet
}
if ($touched.primary && !fromPrimary) {
errors.primary = "Please pick the primary key"
errObj.primary = "Please pick the primary key"
}
// currently don't support relationships back onto the table itself, needs to relate out
const tableError = "From/to/through tables must be different"
if (fromTable && (fromTable === toTable || fromTable === throughTable)) {
errors.from = tableError
if (fromTable && (fromTable === toTable || fromTable === through)) {
errObj.from = tableError
}
if (toTable && (toTable === fromTable || toTable === throughTable)) {
errors.to = tableError
if (toTable && (toTable === fromTable || toTable === through)) {
errObj.to = tableError
}
if (
throughTable &&
(throughTable === fromTable || throughTable === toTable)
) {
errors.through = tableError
if (through && (through === fromTable || through === toTable)) {
errObj.through = tableError
}
const colError = "Column name cannot be an existing column"
if (inSchema(fromTable, fromRelate.name, originalFromName)) {
errors.fromCol = colError
errObj.fromCol = colError
}
if (inSchema(toTable, toRelate.name, originalToName)) {
errors.toCol = colError
errObj.toCol = colError
}
return errors
errors = errObj
}
let fromPrimary
@ -115,13 +110,7 @@
$: fromTable = plusTables.find(table => table._id === toRelationship?.tableId)
$: toTable = plusTables.find(table => table._id === fromRelationship?.tableId)
$: through = plusTables.find(table => table._id === fromRelationship?.through)
$: errors = checkForErrors(
fromTable,
toTable,
through,
fromRelationship,
toRelationship
)
$: checkForErrors(fromRelationship, toRelationship)
$: valid =
Object.keys(errors).length === 0 && Object.keys($touched).length !== 0
$: linkTable = through || toTable
@ -239,19 +228,19 @@
}
function tableChanged(fromTbl, toTbl) {
if (
(currentTables?.from?._id === fromTbl?._id &&
currentTables?.to?._id === toTbl?._id) ||
originalFromName ||
originalToName
) {
return
}
fromRelationship.name = toTbl?.name || ""
errors.fromCol = ""
toRelationship.name = fromTbl?.name || ""
errors.toCol = ""
if (toTbl || fromTbl) {
checkForErrors(
fromTable,
toTable,
through,
fromRelationship,
toRelationship
)
}
currentTables = { from: fromTbl, to: toTbl }
}
</script>

View File

@ -30,6 +30,7 @@
async function getPermissions(queryToFetch) {
if (fetched?._id === queryToFetch?._id) {
loaded = true
return
}
fetched = queryToFetch

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js",
"bin": {

View File

@ -1942,6 +1942,35 @@
"type": "validation/string",
"label": "Validation",
"key": "validation"
},
{
"type": "select",
"label": "Alignment",
"key": "align",
"defaultValue": "left",
"showInBar": true,
"barStyle": "buttons",
"options": [{
"label": "Left",
"value": "left",
"barIcon": "TextAlignLeft",
"barTitle": "Align left"
}, {
"label": "Center",
"value": "center",
"barIcon": "TextAlignCenter",
"barTitle": "Align center"
}, {
"label": "Right",
"value": "right",
"barIcon": "TextAlignRight",
"barTitle": "Align right"
}, {
"label": "Justify",
"value": "justify",
"barIcon": "TextAlignJustify",
"barTitle": "Justify text"
}]
}
]
},
@ -2373,6 +2402,35 @@
"type": "validation/string",
"label": "Validation",
"key": "validation"
},
{
"type": "select",
"label": "Alignment",
"key": "align",
"defaultValue": "left",
"showInBar": true,
"barStyle": "buttons",
"options": [{
"label": "Left",
"value": "left",
"barIcon": "TextAlignLeft",
"barTitle": "Align left"
}, {
"label": "Center",
"value": "center",
"barIcon": "TextAlignCenter",
"barTitle": "Align center"
}, {
"label": "Right",
"value": "right",
"barIcon": "TextAlignRight",
"barTitle": "Align right"
}, {
"label": "Justify",
"value": "justify",
"barIcon": "TextAlignJustify",
"barTitle": "Justify text"
}]
}
]
},

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/client",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"license": "MPL-2.0",
"module": "dist/budibase-client.js",
"main": "dist/budibase-client.js",
@ -19,9 +19,9 @@
"dev:builder": "rollup -cw"
},
"dependencies": {
"@budibase/bbui": "^1.0.49-alpha.8",
"@budibase/frontend-core": "^1.0.49-alpha.8",
"@budibase/string-templates": "^1.0.49-alpha.8",
"@budibase/bbui": "^1.0.49-alpha.9",
"@budibase/frontend-core": "^1.0.49-alpha.9",
"@budibase/string-templates": "^1.0.49-alpha.9",
"@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3",

View File

@ -9,6 +9,7 @@
export let disabled = false
export let validation
export let defaultValue = ""
export let align
let fieldState
let fieldApi
@ -35,6 +36,7 @@
disabled={fieldState.disabled}
error={fieldState.error}
id={fieldState.fieldId}
{align}
{placeholder}
/>
</div>

View File

@ -9,6 +9,7 @@
export let disabled = false
export let validation
export let defaultValue = ""
export let align
let fieldState
let fieldApi
@ -34,6 +35,7 @@
id={fieldState.fieldId}
{placeholder}
{type}
{align}
/>
{/if}
</Field>

View File

@ -1,12 +1,12 @@
{
"name": "@budibase/frontend-core",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"description": "Budibase frontend core libraries used in builder and client",
"author": "Budibase",
"license": "MPL-2.0",
"svelte": "src/index.js",
"dependencies": {
"@budibase/bbui": "^1.0.49-alpha.8",
"@budibase/bbui": "^1.0.49-alpha.9",
"lodash": "^4.17.21",
"svelte": "^3.46.2"
}

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"description": "Budibase Web Server",
"main": "src/index.ts",
"repository": {
@ -70,9 +70,9 @@
"license": "GPL-3.0",
"dependencies": {
"@apidevtools/swagger-parser": "^10.0.3",
"@budibase/backend-core": "^1.0.49-alpha.8",
"@budibase/client": "^1.0.49-alpha.8",
"@budibase/string-templates": "^1.0.49-alpha.8",
"@budibase/backend-core": "^1.0.49-alpha.9",
"@budibase/client": "^1.0.49-alpha.9",
"@budibase/string-templates": "^1.0.49-alpha.9",
"@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0",

View File

@ -9,11 +9,15 @@ CREATE TABLE Persons (
);
CREATE TABLE Tasks (
TaskID SERIAL PRIMARY KEY,
PersonID INT,
ExecutorID INT,
QaID INT,
Completed BOOLEAN,
TaskName varchar(255),
CONSTRAINT fkPersons
FOREIGN KEY(PersonID)
CONSTRAINT fkexecutor
FOREIGN KEY(ExecutorID)
REFERENCES Persons(PersonID),
CONSTRAINT fkqa
FOREIGN KEY(QaID)
REFERENCES Persons(PersonID)
);
CREATE TABLE Products (
@ -32,8 +36,9 @@ CREATE TABLE Products_Tasks (
PRIMARY KEY (ProductID, TaskID)
);
INSERT INTO Persons (FirstName, LastName, Address, City) VALUES ('Mike', 'Hughes', '123 Fake Street', 'Belfast');
INSERT INTO Tasks (PersonID, TaskName, Completed) VALUES (1, 'assembling', TRUE);
INSERT INTO Tasks (PersonID, TaskName, Completed) VALUES (1, 'processing', FALSE);
INSERT INTO Persons (FirstName, LastName, Address, City) Values ('John', 'Smith', '64 Updown Road', 'Dublin');
INSERT INTO Tasks (ExecutorID, QaID, TaskName, Completed) VALUES (1, 2, 'assembling', TRUE);
INSERT INTO Tasks (ExecutorID, QaID, TaskName, Completed) VALUES (2, 1, 'processing', FALSE);
INSERT INTO Products (ProductName) VALUES ('Computers');
INSERT INTO Products (ProductName) VALUES ('Laptops');
INSERT INTO Products (ProductName) VALUES ('Chairs');

View File

@ -184,7 +184,7 @@ module External {
thisRow._id = generateIdForRow(row, table)
thisRow.tableId = table._id
thisRow._rev = "rev"
return thisRow
return processFormulas(table, thisRow)
}
function fixArrayTypes(row: Row, table: Table) {
@ -327,8 +327,12 @@ module External {
* This iterates through the returned rows and works out what elements of the rows
* actually match up to another row (based on primary keys) - this is pretty specific
* to SQL and the way that SQL relationships are returned based on joins.
* This is complicated, but the idea is that when a SQL query returns all the relations
* will be separate rows, with all of the data in each row. We have to decipher what comes
* from where (which tables) and how to convert that into budibase columns.
*/
updateRelationshipColumns(
table: Table,
row: Row,
rows: { [key: string]: Row },
relationships: RelationshipsJson[]
@ -339,6 +343,13 @@ module External {
if (!linkedTable) {
continue
}
const fromColumn = `${table.name}.${relationship.from}`
const toColumn = `${linkedTable.name}.${relationship.to}`
// this is important when working with multiple relationships
// between the same tables, don't want to overlap/multiply the relations
if (!relationship.through && row[fromColumn] !== row[toColumn]) {
continue
}
let linked = basicProcessing(row, linkedTable)
if (!linked._id) {
continue
@ -386,6 +397,7 @@ module External {
// this is a relationship of some sort
if (finalRows[rowId]) {
finalRows = this.updateRelationshipColumns(
table,
row,
finalRows,
relationships
@ -399,6 +411,7 @@ module External {
finalRows[thisRow._id] = thisRow
// do this at end once its been added to the final rows
finalRows = this.updateRelationshipColumns(
table,
row,
finalRows,
relationships

View File

@ -191,29 +191,70 @@ class InternalBuilder {
if (!relationships) {
return query
}
const tableSets: Record<string, [any]> = {}
// aggregate into table sets (all the same to tables)
for (let relationship of relationships) {
const keyObj: { toTable: string; throughTable: string | undefined } = {
toTable: relationship.tableName,
throughTable: undefined,
}
if (relationship.through) {
keyObj.throughTable = relationship.through
}
const key = JSON.stringify(keyObj)
if (tableSets[key]) {
tableSets[key].push(relationship)
} else {
tableSets[key] = [relationship]
}
}
for (let [key, relationships] of Object.entries(tableSets)) {
const { toTable, throughTable } = JSON.parse(key)
if (!throughTable) {
// @ts-ignore
query = query.join(
toTable,
function () {
for (let relationship of relationships) {
const from = relationship.from,
to = relationship.to,
toTable = relationship.tableName
if (!relationship.through) {
to = relationship.to
// @ts-ignore
query = query.leftJoin(
toTable,
`${fromTable}.${from}`,
`${toTable}.${to}`
this.orOn(`${fromTable}.${from}`, "=", `${toTable}.${to}`)
}
},
"left"
)
} else {
const throughTable = relationship.through
const fromPrimary = relationship.fromPrimary
const toPrimary = relationship.toPrimary
query = query
// @ts-ignore
.leftJoin(
.join(
throughTable,
function () {
for (let relationship of relationships) {
const fromPrimary = relationship.fromPrimary
const from = relationship.from
// @ts-ignore
this.orOn(
`${fromTable}.${fromPrimary}`,
"=",
`${throughTable}.${from}`
)
.leftJoin(toTable, `${toTable}.${toPrimary}`, `${throughTable}.${to}`)
}
},
"left"
)
.join(
toTable,
function () {
for (let relationship of relationships) {
const toPrimary = relationship.toPrimary
const to = relationship.to
// @ts-ignore
this.orOn(`${toTable}.${toPrimary}`, `${throughTable}.${to}`)
}
},
"left"
)
}
}
return query.limit(BASE_LIMIT)

View File

@ -5,9 +5,6 @@ const { integrations } = require("../integrations")
const { processStringSync } = require("@budibase/string-templates")
const { doInAppContext, getAppDB } = require("@budibase/backend-core/context")
const IS_TRIPLE_BRACE = new RegExp(/^{{3}.*}{3}$/)
const IS_HANDLEBARS = new RegExp(/^{{2}.*}{2}$/)
class QueryRunner {
constructor(input, flags = { noRecursiveQuery: false }) {
this.datasource = input.datasource
@ -188,12 +185,8 @@ class QueryRunner {
enrichedQuery[key] = this.enrichQueryFields(fields[key], parameters)
} else if (typeof fields[key] === "string") {
// enrich string value as normal
let value = fields[key]
// add triple brace to avoid escaping e.g. '=' in cookie header
if (IS_HANDLEBARS.test(value) && !IS_TRIPLE_BRACE.test(value)) {
value = `{${value}}`
}
enrichedQuery[key] = processStringSync(value, parameters, {
enrichedQuery[key] = processStringSync(fields[key], parameters, {
noEscaping: true,
noHelpers: true,
})
} else {

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/string-templates",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs",
"module": "dist/bundle.mjs",

View File

@ -17,6 +17,7 @@ module.exports.processString = templates.processString
module.exports.processObject = templates.processObject
module.exports.doesContainStrings = templates.doesContainStrings
module.exports.doesContainString = templates.doesContainString
module.exports.disableEscaping = templates.disableEscaping
/**
* Use vm2 to run JS scripts in a node env

View File

@ -3,12 +3,16 @@ const { registerAll } = require("./helpers/index")
const processors = require("./processors")
const { atob, btoa } = require("./utilities")
const manifest = require("../manifest.json")
const { FIND_HBS_REGEX } = require("./utilities")
const { FIND_HBS_REGEX, FIND_DOUBLE_HBS_REGEX } = require("./utilities")
const hbsInstance = handlebars.create()
registerAll(hbsInstance)
const hbsInstanceNoHelpers = handlebars.create()
const defaultOpts = { noHelpers: false, cacheTemplates: false }
const defaultOpts = {
noHelpers: false,
cacheTemplates: false,
noEscaping: false,
}
/**
* Utility function to check if the object is valid.
@ -26,21 +30,28 @@ function testObject(object) {
* Creates a HBS template function for a given string, and optionally caches it.
*/
let templateCache = {}
function createTemplate(string, noHelpers, cache) {
function createTemplate(string, opts) {
opts = { ...defaultOpts, ...opts }
// Finalising adds a helper, can't do this with no helpers
const shouldFinalise = !noHelpers
const key = `${string}${shouldFinalise}`
const shouldFinalise = !opts.noHelpers
const key = `${string}${shouldFinalise}${opts.noEscaping}`
// Reuse the cached template is possible
if (cache && templateCache[key]) {
if (opts.cacheTemplates && templateCache[key]) {
return templateCache[key]
}
string = processors.preprocess(string, shouldFinalise)
// Optionally disable built in HBS escaping
if (opts.noEscaping) {
string = exports.disableEscaping(string)
}
// This does not throw an error when template can't be fulfilled,
// have to try correct beforehand
const instance = noHelpers ? hbsInstanceNoHelpers : hbsInstance
const instance = opts.noHelpers ? hbsInstanceNoHelpers : hbsInstance
const template = instance.compile(string, {
strict: false,
})
@ -53,7 +64,7 @@ function createTemplate(string, noHelpers, cache) {
* @param {object|array} object The input structure which is to be recursed, it is important to note that
* if the structure contains any cycles then this will fail.
* @param {object} context The context that handlebars should fill data from.
* @param {object|null} opts optional - specify some options for processing.
* @param {object|undefined} opts optional - specify some options for processing.
* @returns {Promise<object|array>} The structure input, as fully updated as possible.
*/
module.exports.processObject = async (object, context, opts) => {
@ -84,7 +95,7 @@ module.exports.processObject = async (object, context, opts) => {
* then nothing will occur.
* @param {string} string The template string which is the filled from the context object.
* @param {object} context An object of information which will be used to enrich the string.
* @param {object|null} opts optional - specify some options for processing.
* @param {object|undefined} opts optional - specify some options for processing.
* @returns {Promise<string>} The enriched string, all templates should have been replaced if they can be.
*/
module.exports.processString = async (string, context, opts) => {
@ -98,7 +109,7 @@ module.exports.processString = async (string, context, opts) => {
* @param {object|array} object The input structure which is to be recursed, it is important to note that
* if the structure contains any cycles then this will fail.
* @param {object} context The context that handlebars should fill data from.
* @param {object|null} opts optional - specify some options for processing.
* @param {object|undefined} opts optional - specify some options for processing.
* @returns {object|array} The structure input, as fully updated as possible.
*/
module.exports.processObjectSync = (object, context, opts) => {
@ -119,19 +130,17 @@ module.exports.processObjectSync = (object, context, opts) => {
* then nothing will occur. This is a pure sync call and therefore does not have the full functionality of the async call.
* @param {string} string The template string which is the filled from the context object.
* @param {object} context An object of information which will be used to enrich the string.
* @param {object|null} opts optional - specify some options for processing.
* @param {object|undefined} opts optional - specify some options for processing.
* @returns {string} The enriched string, all templates should have been replaced if they can be.
*/
module.exports.processStringSync = (string, context, opts) => {
opts = { ...defaultOpts, ...opts }
// take a copy of input in case of error
// Take a copy of input in case of error
const input = string
if (typeof string !== "string") {
throw "Cannot process non-string types."
}
try {
const template = createTemplate(string, opts.noHelpers, opts.cacheTemplates)
const template = createTemplate(string, opts)
const now = Math.floor(Date.now() / 1000) * 1000
return processors.postprocess(
template({
@ -144,6 +153,24 @@ module.exports.processStringSync = (string, context, opts) => {
}
}
/**
* By default with expressions like {{ name }} handlebars will escape various
* characters, which can be problematic. To fix this we use the syntax {{{ name }}},
* this function will find any double braces and switch to triple.
* @param string the string to have double HBS statements converted to triple.
*/
module.exports.disableEscaping = string => {
let regexp = new RegExp(FIND_DOUBLE_HBS_REGEX)
const matches = string.match(regexp)
if (matches == null) {
return string
}
for (let match of matches) {
string = string.replace(match, `{${match}}`)
}
return string
}
/**
* Simple utility function which makes sure that a templating property has been wrapped in literal specifiers correctly.
* @param {string} property The property which is to be wrapped.
@ -160,7 +187,6 @@ module.exports.makePropSafe = property => {
* @returns {boolean} Whether or not the input string is valid.
*/
module.exports.isValid = (string, opts) => {
opts = { ...defaultOpts, ...opts }
const validCases = [
"string",
"number",
@ -174,7 +200,7 @@ module.exports.isValid = (string, opts) => {
// don't really need a real context to check if its valid
const context = {}
try {
const template = createTemplate(string, opts.noHelpers, opts.cache)
const template = createTemplate(string, opts)
template(context)
return true
} catch (err) {

View File

@ -17,6 +17,7 @@ export const processString = templates.processString
export const processObject = templates.processObject
export const doesContainStrings = templates.doesContainStrings
export const doesContainString = templates.doesContainString
export const disableEscaping = templates.disableEscaping
/**
* Use polyfilled vm to run JS scripts in a browser Env

View File

@ -1,6 +1,7 @@
const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g
module.exports.FIND_HBS_REGEX = /{{([^{].*?)}}/g
module.exports.FIND_DOUBLE_HBS_REGEX = /(?<!{){{[^{}]+}}(?!})/g
module.exports.isAlphaNumeric = char => {
return char.match(ALPHA_NUMERIC_REGEX)

View File

@ -6,6 +6,7 @@ const {
getManifest,
encodeJSBinding,
doesContainString,
disableEscaping,
} = require("../src/index.cjs")
describe("Test that the string processing works correctly", () => {
@ -176,3 +177,22 @@ describe("check does contain string function", () => {
expect(doesContainString(js, "foo")).toEqual(true)
})
})
describe("check that disabling escaping function works", () => {
it("should work for a single statement", () => {
expect(disableEscaping("{{ name }}")).toEqual("{{{ name }}}")
})
it("should work for two statements", () => {
expect(disableEscaping("{{ name }} welcome to {{ platform }}")).toEqual("{{{ name }}} welcome to {{{ platform }}}")
})
it("shouldn't convert triple braces", () => {
expect(disableEscaping("{{{ name }}}")).toEqual("{{{ name }}}")
})
it("should work with a combination", () => {
expect(disableEscaping("{{ name }} welcome to {{{ platform }}}")).toEqual("{{{ name }}} welcome to {{{ platform }}}")
})
})

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/worker",
"email": "hi@budibase.com",
"version": "1.0.49-alpha.8",
"version": "1.0.49-alpha.9",
"description": "Budibase background service",
"main": "src/index.ts",
"repository": {
@ -34,8 +34,8 @@
"author": "Budibase",
"license": "GPL-3.0",
"dependencies": {
"@budibase/backend-core": "^1.0.49-alpha.8",
"@budibase/string-templates": "^1.0.49-alpha.8",
"@budibase/backend-core": "^1.0.49-alpha.9",
"@budibase/string-templates": "^1.0.49-alpha.9",
"@koa/router": "^8.0.0",
"@sentry/node": "^6.0.0",
"@techpass/passport-openidconnect": "^0.3.0",