From ed7b89f2f9dfddccfd7c6c2524e95b72f5cf7998 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jan 2024 13:53:20 +0100 Subject: [PATCH 01/15] Move jsRunner to folder --- packages/server/src/{jsRunner.ts => jsRunner/index.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename packages/server/src/{jsRunner.ts => jsRunner/index.ts} (99%) diff --git a/packages/server/src/jsRunner.ts b/packages/server/src/jsRunner/index.ts similarity index 99% rename from packages/server/src/jsRunner.ts rename to packages/server/src/jsRunner/index.ts index 5e8aa2d1e1..477a8c14da 100644 --- a/packages/server/src/jsRunner.ts +++ b/packages/server/src/jsRunner/index.ts @@ -1,5 +1,5 @@ import ivm from "isolated-vm" -import env from "./environment" +import env from "../environment" import { setJSRunner, JsErrorTimeout } from "@budibase/string-templates" import { context } from "@budibase/backend-core" import tracer from "dd-trace" From 786acaa12127dcf21c312dab2d80848dde06e0b8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jan 2024 13:59:16 +0100 Subject: [PATCH 02/15] Add basic test --- .../src/jsRunner/tests/jsRunner.spec.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 packages/server/src/jsRunner/tests/jsRunner.spec.ts diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts new file mode 100644 index 0000000000..730a92e99b --- /dev/null +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -0,0 +1,21 @@ +import { processStringSync, encodeJSBinding } from "@budibase/string-templates" +import TestConfiguration from "../../tests/utilities/TestConfiguration" + +describe("jsRunner", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.init() + }) + + const processJS = (js: string, context?: object) => { + return config.doInContext(config.getAppId(), async () => + processStringSync(encodeJSBinding(js), context || {}) + ) + } + + it("it can run a basic javascript", async () => { + const output = await processJS(`return 1 + 2`) + expect(output).toBe(3) + }) +}) From de4d7d95c39ddc62c5864e7b58585434cf3c8299 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jan 2024 14:20:49 +0100 Subject: [PATCH 03/15] Move code to test helpers --- .../string-templates/test/manifest.spec.js | 62 +++---------------- packages/string-templates/test/utils.js | 53 ++++++++++++++++ 2 files changed, 60 insertions(+), 55 deletions(-) create mode 100644 packages/string-templates/test/utils.js diff --git a/packages/string-templates/test/manifest.spec.js b/packages/string-templates/test/manifest.spec.js index 3e39d775f5..6dd5e8933d 100644 --- a/packages/string-templates/test/manifest.spec.js +++ b/packages/string-templates/test/manifest.spec.js @@ -15,7 +15,6 @@ jest.mock("@budibase/handlebars-helpers/lib/uuid", () => { } }) -const fs = require("fs") const { processString, convertToJS, @@ -25,6 +24,7 @@ const { const tk = require("timekeeper") const { getJsHelperList } = require("../src/helpers") +const { getParsedManifest } = require("./utils") tk.freeze("2021-01-21T12:00:00") @@ -32,64 +32,16 @@ const processJS = (js, context) => { return processStringSync(encodeJSBinding(js), context) } -const manifest = JSON.parse( - fs.readFileSync(require.resolve("../manifest.json"), "utf8") -) - -const collections = Object.keys(manifest) -const examples = collections.reduce((acc, collection) => { - const functions = Object.entries(manifest[collection]) - .filter(([_, details]) => details.example) - .map(([name, details]) => { - const example = details.example - let [hbs, js] = example.split("->").map(x => x.trim()) - if (!js) { - // The function has no return value - return - } - - // Trim 's - js = js.replace(/^\'|\'$/g, "") - if ((parsedExpected = tryParseJson(js))) { - if (Array.isArray(parsedExpected)) { - if (typeof parsedExpected[0] === "object") { - js = JSON.stringify(parsedExpected) - } else { - js = parsedExpected.join(",") - } - } - } - const requiresHbsBody = details.requiresBlock - return [name, { hbs, js, requiresHbsBody }] - }) - .filter(x => !!x) - - if (Object.keys(functions).length) { - acc[collection] = functions - } - return acc -}, {}) - function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string } -function tryParseJson(str) { - if (typeof str !== "string") { - return - } - - try { - return JSON.parse(str.replace(/\'/g, '"')) - } catch (e) { - return - } -} - describe("manifest", () => { + const manifest = getParsedManifest() + describe("examples are valid", () => { - describe.each(Object.keys(examples))("%s", collection => { - it.each(examples[collection])("%s", async (_, { hbs, js }) => { + describe.each(Object.keys(manifest))("%s", collection => { + it.each(manifest[collection])("%s", async (_, { hbs, js }) => { const context = { double: i => i * 2, isString: x => typeof x === "string", @@ -110,8 +62,8 @@ describe("manifest", () => { describe("can be parsed and run as js", () => { const jsHelpers = getJsHelperList() - const jsExamples = Object.keys(examples).reduce((acc, v) => { - acc[v] = examples[v].filter(([key]) => jsHelpers[key]) + const jsExamples = Object.keys(manifest).reduce((acc, v) => { + acc[v] = manifest[v].filter(([key]) => jsHelpers[key]) return acc }, {}) diff --git a/packages/string-templates/test/utils.js b/packages/string-templates/test/utils.js new file mode 100644 index 0000000000..1b9d030cc5 --- /dev/null +++ b/packages/string-templates/test/utils.js @@ -0,0 +1,53 @@ +const { getManifest } = require("../src") + +function tryParseJson(str) { + if (typeof str !== "string") { + return + } + + try { + return JSON.parse(str.replace(/\'/g, '"')) + } catch (e) { + return + } +} + +module.exports.getParsedManifest = () => { + const manifest = getManifest() + const collections = Object.keys(manifest) + const examples = collections.reduce((acc, collection) => { + const functions = Object.entries(manifest[collection]) + .filter(([_, details]) => details.example) + .map(([name, details]) => { + const example = details.example + let [hbs, js] = example.split("->").map(x => x.trim()) + if (!js) { + // The function has no return value + return + } + + // Trim 's + js = js.replace(/^\'|\'$/g, "") + let parsedExpected + if ((parsedExpected = tryParseJson(js))) { + if (Array.isArray(parsedExpected)) { + if (typeof parsedExpected[0] === "object") { + js = JSON.stringify(parsedExpected) + } else { + js = parsedExpected.join(",") + } + } + } + const requiresHbsBody = details.requiresBlock + return [name, { hbs, js, requiresHbsBody }] + }) + .filter(x => !!x) + + if (Object.keys(functions).length) { + acc[collection] = functions + } + return acc + }, {}) + + return examples +} From b96ca1cf54dc31899bd2d8260f19635049f4ad66 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jan 2024 16:15:53 +0100 Subject: [PATCH 04/15] Run hbs on server tests --- .../src/jsRunner/tests/jsRunner.spec.ts | 38 +++++++++---- packages/string-templates/package.json | 3 +- .../string-templates/test/manifest.spec.js | 47 +--------------- packages/string-templates/test/utils.js | 55 ++++++++++++++++++- 4 files changed, 85 insertions(+), 58 deletions(-) diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index 730a92e99b..35c01a5a8a 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -1,21 +1,35 @@ +jest.mock("@budibase/handlebars-helpers/lib/math", () => { + const actual = jest.requireActual("@budibase/handlebars-helpers/lib/math") + + return { + ...actual, + random: () => 10, + } +}) +jest.mock("@budibase/handlebars-helpers/lib/uuid", () => { + const actual = jest.requireActual("@budibase/handlebars-helpers/lib/uuid") + + return { + ...actual, + uuid: () => "f34ebc66-93bd-4f7c-b79b-92b5569138bc", + } +}) + import { processStringSync, encodeJSBinding } from "@budibase/string-templates" -import TestConfiguration from "../../tests/utilities/TestConfiguration" +const { runJsHelpersTests } = require("@budibase/string-templates/test/utils") + +import tk from "timekeeper" +tk.freeze("2021-01-21T12:00:00") describe("jsRunner", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.init() - }) - const processJS = (js: string, context?: object) => { - return config.doInContext(config.getAppId(), async () => - processStringSync(encodeJSBinding(js), context || {}) - ) + return processStringSync(encodeJSBinding(js), context || {}) } - it("it can run a basic javascript", async () => { - const output = await processJS(`return 1 + 2`) + it("it can run a basic javascript", () => { + const output = processJS(`return 1 + 2`) expect(output).toBe(3) }) + + runJsHelpersTests() }) diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 6d0e9298e5..c7a4e79c86 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -12,7 +12,8 @@ "import": "./dist/bundle.mjs" }, "./package.json": "./package.json", - "./index-helpers": "./dist/index-helpers.bundled.js" + "./index-helpers": "./dist/index-helpers.bundled.js", + "./test/utils": "./test/utils.js" }, "files": [ "dist", diff --git a/packages/string-templates/test/manifest.spec.js b/packages/string-templates/test/manifest.spec.js index 6dd5e8933d..fa8683960a 100644 --- a/packages/string-templates/test/manifest.spec.js +++ b/packages/string-templates/test/manifest.spec.js @@ -15,23 +15,13 @@ jest.mock("@budibase/handlebars-helpers/lib/uuid", () => { } }) -const { - processString, - convertToJS, - processStringSync, - encodeJSBinding, -} = require("../src/index.cjs") +const { processString } = require("../src/index.cjs") const tk = require("timekeeper") -const { getJsHelperList } = require("../src/helpers") -const { getParsedManifest } = require("./utils") +const { getParsedManifest, runJsHelpersTests } = require("./utils") tk.freeze("2021-01-21T12:00:00") -const processJS = (js, context) => { - return processStringSync(encodeJSBinding(js), context) -} - function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string } @@ -60,36 +50,5 @@ describe("manifest", () => { }) }) - describe("can be parsed and run as js", () => { - const jsHelpers = getJsHelperList() - const jsExamples = Object.keys(manifest).reduce((acc, v) => { - acc[v] = manifest[v].filter(([key]) => jsHelpers[key]) - return acc - }, {}) - - describe.each(Object.keys(jsExamples))("%s", collection => { - it.each( - jsExamples[collection].filter( - ([_, { requiresHbsBody }]) => !requiresHbsBody - ) - )("%s", async (_, { hbs, js }) => { - const context = { - double: i => i * 2, - isString: x => typeof x === "string", - } - - const arrays = hbs.match(/\[[^/\]]+\]/) - arrays?.forEach((arrayString, i) => { - hbs = hbs.replace(new RegExp(escapeRegExp(arrayString)), `array${i}`) - context[`array${i}`] = JSON.parse(arrayString.replace(/\'/g, '"')) - }) - - let convertedJs = convertToJS(hbs) - - let result = processJS(convertedJs, context) - result = result.replace(/ /g, " ") - expect(result).toEqual(js) - }) - }) - }) + runJsHelpersTests() }) diff --git a/packages/string-templates/test/utils.js b/packages/string-templates/test/utils.js index 1b9d030cc5..8b8943c776 100644 --- a/packages/string-templates/test/utils.js +++ b/packages/string-templates/test/utils.js @@ -1,4 +1,11 @@ const { getManifest } = require("../src") +const { getJsHelperList } = require("../src/helpers") + +const { + convertToJS, + processStringSync, + encodeJSBinding, +} = require("../src/index.cjs") function tryParseJson(str) { if (typeof str !== "string") { @@ -12,7 +19,7 @@ function tryParseJson(str) { } } -module.exports.getParsedManifest = () => { +const getParsedManifest = () => { const manifest = getManifest() const collections = Object.keys(manifest) const examples = collections.reduce((acc, collection) => { @@ -51,3 +58,49 @@ module.exports.getParsedManifest = () => { return examples } +module.exports.getParsedManifest = getParsedManifest + +module.exports.runJsHelpersTests = () => { + const manifest = getParsedManifest() + + const processJS = (js, context) => { + return processStringSync(encodeJSBinding(js), context) + } + + function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string + } + + describe("can be parsed and run as js", () => { + const jsHelpers = getJsHelperList() + const jsExamples = Object.keys(manifest).reduce((acc, v) => { + acc[v] = manifest[v].filter(([key]) => jsHelpers[key]) + return acc + }, {}) + + describe.each(Object.keys(jsExamples))("%s", collection => { + it.each( + jsExamples[collection].filter( + ([_, { requiresHbsBody }]) => !requiresHbsBody + ) + )("%s", async (_, { hbs, js }) => { + const context = { + double: i => i * 2, + isString: x => typeof x === "string", + } + + const arrays = hbs.match(/\[[^/\]]+\]/) + arrays?.forEach((arrayString, i) => { + hbs = hbs.replace(new RegExp(escapeRegExp(arrayString)), `array${i}`) + context[`array${i}`] = JSON.parse(arrayString.replace(/\'/g, '"')) + }) + + let convertedJs = convertToJS(hbs) + + let result = await processJS(convertedJs, context) + result = result.replace(/ /g, " ") + expect(result).toEqual(js) + }) + }) + }) +} From e6ae3649184a7f74bfdd1f1d88ebe2040dec3424 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 31 Jan 2024 16:51:34 +0100 Subject: [PATCH 05/15] Register server helpers --- .../src/jsRunner/tests/jsRunner.spec.ts | 19 +++++++++++++++---- packages/string-templates/test/utils.js | 4 ++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index 35c01a5a8a..ddef60a80e 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -19,17 +19,28 @@ import { processStringSync, encodeJSBinding } from "@budibase/string-templates" const { runJsHelpersTests } = require("@budibase/string-templates/test/utils") import tk from "timekeeper" +import { init } from ".." +import TestConfiguration from "../../tests/utilities/TestConfiguration" tk.freeze("2021-01-21T12:00:00") describe("jsRunner", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + init() + await config.init() + }) + const processJS = (js: string, context?: object) => { - return processStringSync(encodeJSBinding(js), context || {}) + return config.doInContext(config.getAppId(), async () => + processStringSync(encodeJSBinding(js), context || {}) + ) } - it("it can run a basic javascript", () => { - const output = processJS(`return 1 + 2`) + it("it can run a basic javascript", async () => { + const output = await processJS(`return 1 + 2`) expect(output).toBe(3) }) - runJsHelpersTests() + runJsHelpersTests((func: any) => config.doInContext(config.getAppId(), func)) }) diff --git a/packages/string-templates/test/utils.js b/packages/string-templates/test/utils.js index 8b8943c776..33f6c6d6b6 100644 --- a/packages/string-templates/test/utils.js +++ b/packages/string-templates/test/utils.js @@ -60,11 +60,11 @@ const getParsedManifest = () => { } module.exports.getParsedManifest = getParsedManifest -module.exports.runJsHelpersTests = () => { +module.exports.runJsHelpersTests = (funcWrap = delegate => delegate()) => { const manifest = getParsedManifest() const processJS = (js, context) => { - return processStringSync(encodeJSBinding(js), context) + return funcWrap(() => processStringSync(encodeJSBinding(js), context)) } function escapeRegExp(string) { From 82db76627fbbd60322cc85009ff06b5f1df1e0f0 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 10:56:59 +0100 Subject: [PATCH 06/15] Better typing --- packages/server/src/jsRunner/tests/jsRunner.spec.ts | 5 ++++- packages/string-templates/test/utils.js | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index ddef60a80e..56314c9565 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -27,6 +27,7 @@ describe("jsRunner", () => { const config = new TestConfiguration() beforeAll(async () => { + // Register js runner init() await config.init() }) @@ -42,5 +43,7 @@ describe("jsRunner", () => { expect(output).toBe(3) }) - runJsHelpersTests((func: any) => config.doInContext(config.getAppId(), func)) + runJsHelpersTests({ + funcWrap: (func: any) => config.doInContext(config.getAppId(), func), + }) }) diff --git a/packages/string-templates/test/utils.js b/packages/string-templates/test/utils.js index 33f6c6d6b6..04faffb27d 100644 --- a/packages/string-templates/test/utils.js +++ b/packages/string-templates/test/utils.js @@ -60,7 +60,9 @@ const getParsedManifest = () => { } module.exports.getParsedManifest = getParsedManifest -module.exports.runJsHelpersTests = (funcWrap = delegate => delegate()) => { +module.exports.runJsHelpersTests = ( + { funcWrap } = { funcWrap: delegate => delegate() } +) => { const manifest = getParsedManifest() const processJS = (js, context) => { From 4461c49f48e3efb13fef5c4c0f839b2b0275ed1f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 10:58:20 +0100 Subject: [PATCH 07/15] Allow skipping tests --- .../src/jsRunner/tests/jsRunner.spec.ts | 1 + packages/string-templates/test/utils.js | 49 ++++++++++--------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index 56314c9565..876ada5ee0 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -45,5 +45,6 @@ describe("jsRunner", () => { runJsHelpersTests({ funcWrap: (func: any) => config.doInContext(config.getAppId(), func), + testsToSkip: ["random", "uuid"], }) }) diff --git a/packages/string-templates/test/utils.js b/packages/string-templates/test/utils.js index 04faffb27d..2375c5868f 100644 --- a/packages/string-templates/test/utils.js +++ b/packages/string-templates/test/utils.js @@ -60,9 +60,8 @@ const getParsedManifest = () => { } module.exports.getParsedManifest = getParsedManifest -module.exports.runJsHelpersTests = ( - { funcWrap } = { funcWrap: delegate => delegate() } -) => { +module.exports.runJsHelpersTests = ({ funcWrap, testsToSkip } = {}) => { + funcWrap = funcWrap || (delegate => delegate()) const manifest = getParsedManifest() const processJS = (js, context) => { @@ -81,28 +80,32 @@ module.exports.runJsHelpersTests = ( }, {}) describe.each(Object.keys(jsExamples))("%s", collection => { - it.each( - jsExamples[collection].filter( - ([_, { requiresHbsBody }]) => !requiresHbsBody - ) - )("%s", async (_, { hbs, js }) => { - const context = { - double: i => i * 2, - isString: x => typeof x === "string", - } + const examplesToRun = jsExamples[collection] + .filter(([_, { requiresHbsBody }]) => !requiresHbsBody) + .filter(([key]) => !testsToSkip?.includes(key)) - const arrays = hbs.match(/\[[^/\]]+\]/) - arrays?.forEach((arrayString, i) => { - hbs = hbs.replace(new RegExp(escapeRegExp(arrayString)), `array${i}`) - context[`array${i}`] = JSON.parse(arrayString.replace(/\'/g, '"')) + examplesToRun.length && + it.each(examplesToRun)("%s", async (_, { hbs, js }) => { + const context = { + double: i => i * 2, + isString: x => typeof x === "string", + } + + const arrays = hbs.match(/\[[^/\]]+\]/) + arrays?.forEach((arrayString, i) => { + hbs = hbs.replace( + new RegExp(escapeRegExp(arrayString)), + `array${i}` + ) + context[`array${i}`] = JSON.parse(arrayString.replace(/\'/g, '"')) + }) + + let convertedJs = convertToJS(hbs) + + let result = await processJS(convertedJs, context) + result = result.replace(/ /g, " ") + expect(result).toEqual(js) }) - - let convertedJs = convertToJS(hbs) - - let result = await processJS(convertedJs, context) - result = result.replace(/ /g, " ") - expect(result).toEqual(js) - }) }) }) } From 181d462cdf711ff89d31ca45de1a76b1264d716c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 11:15:21 +0100 Subject: [PATCH 08/15] Update uuid --- packages/backend-core/package.json | 2 +- packages/server/package.json | 3 ++- packages/server/src/api/controllers/static/index.ts | 2 +- packages/server/src/utilities/fileSystem/filesystem.ts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index d6325e1de9..93dc911f4e 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -54,7 +54,7 @@ "sanitize-s3-objectkey": "0.0.1", "semver": "7.3.7", "tar-fs": "2.1.1", - "uuid": "8.3.2" + "uuid": "^8.3.2" }, "devDependencies": { "@shopify/jest-koa-mocks": "5.1.1", diff --git a/packages/server/package.json b/packages/server/package.json index 2f5c3db6e9..a52623802a 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -106,7 +106,7 @@ "svelte": "^3.49.0", "tar": "6.1.15", "to-json-schema": "0.2.5", - "uuid": "3.3.2", + "uuid": "^8.3.2", "validate.js": "0.13.1", "worker-farm": "1.7.0", "xml2js": "0.5.0" @@ -130,6 +130,7 @@ "@types/server-destroy": "1.0.1", "@types/supertest": "2.0.14", "@types/tar": "6.1.5", + "@types/uuid": "8.3.4", "apidoc": "0.50.4", "copyfiles": "2.4.1", "docker-compose": "0.23.17", diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 5f383e837d..ec45361604 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -3,7 +3,7 @@ import { InvalidFileExtensions } from "@budibase/shared-core" require("svelte/register") import { join } from "../../../utilities/centralPath" -import uuid from "uuid" +import * as uuid from "uuid" import { ObjectStoreBuckets } from "../../../constants" import { processString } from "@budibase/string-templates" import { diff --git a/packages/server/src/utilities/fileSystem/filesystem.ts b/packages/server/src/utilities/fileSystem/filesystem.ts index be656f54d1..add587cdea 100644 --- a/packages/server/src/utilities/fileSystem/filesystem.ts +++ b/packages/server/src/utilities/fileSystem/filesystem.ts @@ -4,7 +4,7 @@ import { resolve, join } from "path" import env from "../../environment" import tar from "tar" -const uuid = require("uuid/v4") +import { v4 as uuid } from "uuid" export const TOP_LEVEL_PATH = env.TOP_LEVEL_PATH || resolve(join(__dirname, "..", "..", "..")) From 2899c4f7f8b94a302bdbd2f646b3f70029cdfa31 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 11:15:36 +0100 Subject: [PATCH 09/15] Test uuid helper --- .../server/src/jsRunner/tests/jsRunner.spec.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index 876ada5ee0..e16734db93 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -1,3 +1,5 @@ +import { validate as isValidUUID } from "uuid" + jest.mock("@budibase/handlebars-helpers/lib/math", () => { const actual = jest.requireActual("@budibase/handlebars-helpers/lib/math") @@ -43,8 +45,18 @@ describe("jsRunner", () => { expect(output).toBe(3) }) - runJsHelpersTests({ - funcWrap: (func: any) => config.doInContext(config.getAppId(), func), - testsToSkip: ["random", "uuid"], + describe("helpers", () => { + runJsHelpersTests({ + funcWrap: (func: any) => config.doInContext(config.getAppId(), func), + testsToSkip: ["random", "uuid"], + }) + + describe("uuid", () => { + it("uuid helper returns a valid uuid", async () => { + const result = await processJS("return helpers.uuid()") + expect(result).toBeDefined() + expect(isValidUUID(result)).toBe(true) + }) + }) }) }) From 1b88700d0267e32ebee0848c9eb89176404568f0 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 11:17:55 +0100 Subject: [PATCH 10/15] Test random helper --- packages/server/src/jsRunner/tests/jsRunner.spec.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index e16734db93..3545abfe4e 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -58,5 +58,16 @@ describe("jsRunner", () => { expect(isValidUUID(result)).toBe(true) }) }) + + describe("random", () => { + it("random helper returns a valid number", async () => { + const min = 1 + const max = 8 + const result = await processJS(`return helpers.random(${min}, ${max})`) + expect(result).toBeDefined() + expect(result).toBeGreaterThanOrEqual(min) + expect(result).toBeLessThanOrEqual(max) + }) + }) }) }) From d1cf13707d814ba9afca664a0403b8b990ba8f0d Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 11:57:22 +0100 Subject: [PATCH 11/15] Fix url.escape --- packages/server/src/jsRunner/index.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/server/src/jsRunner/index.ts b/packages/server/src/jsRunner/index.ts index 477a8c14da..b7e63ce63c 100644 --- a/packages/server/src/jsRunner/index.ts +++ b/packages/server/src/jsRunner/index.ts @@ -6,6 +6,7 @@ import tracer from "dd-trace" import fs from "fs" import url from "url" import crypto from "crypto" +import querystring from "querystring" const helpersSource = fs.readFileSync( `${require.resolve("@budibase/string-templates/index-helpers")}`, @@ -39,6 +40,10 @@ export function init() { resolve: (...params) => urlResolveCb(...params), parse: (...params) => urlParseCb(...params), } + case "querystring": + return { + escape: (...params) => querystringEscapeCb(...params), + } } };` @@ -57,6 +62,14 @@ export function init() { ) ) + global.setSync( + "querystringEscapeCb", + new ivm.Callback( + (...params: Parameters) => + querystring.escape(...params) + ) + ) + const helpersModule = jsIsolate.compileModuleSync( `${injectedRequire};${helpersSource}` ) From 1439eb9b271c84949c50dfc82b128e9f601452fd Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 12:20:31 +0100 Subject: [PATCH 12/15] Fix stripProtocol --- packages/server/src/jsRunner/index.ts | 9 +++++++++ packages/string-templates/src/index-helpers.js | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/server/src/jsRunner/index.ts b/packages/server/src/jsRunner/index.ts index b7e63ce63c..8e529d533d 100644 --- a/packages/server/src/jsRunner/index.ts +++ b/packages/server/src/jsRunner/index.ts @@ -70,6 +70,15 @@ export function init() { ) ) + global.setSync( + "helpersStripProtocol", + new ivm.Callback((str: string) => { + var parsed = url.parse(str) as any + parsed.protocol = "" + return parsed.format() + }) + ) + const helpersModule = jsIsolate.compileModuleSync( `${injectedRequire};${helpersSource}` ) diff --git a/packages/string-templates/src/index-helpers.js b/packages/string-templates/src/index-helpers.js index 3c16a352fc..b0d9ac5c68 100644 --- a/packages/string-templates/src/index-helpers.js +++ b/packages/string-templates/src/index-helpers.js @@ -1,3 +1,8 @@ const { getJsHelperList } = require("./helpers/list") -module.exports = getJsHelperList() +const helpers = getJsHelperList() +module.exports = { + ...helpers, + // point stripProtocol to a unexisting function to be able to declare it on isolated-vm + stripProtocol: helpersStripProtocol, +} From 843d95c3bbb074144d1f5baba7f3adb98d1567cc Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 12:30:59 +0100 Subject: [PATCH 13/15] Lint --- packages/server/src/jsRunner/tests/jsRunner.spec.ts | 2 ++ packages/string-templates/test/utils.js | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts index 3545abfe4e..cddab3c9b4 100644 --- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts +++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts @@ -18,11 +18,13 @@ jest.mock("@budibase/handlebars-helpers/lib/uuid", () => { }) import { processStringSync, encodeJSBinding } from "@budibase/string-templates" + const { runJsHelpersTests } = require("@budibase/string-templates/test/utils") import tk from "timekeeper" import { init } from ".." import TestConfiguration from "../../tests/utilities/TestConfiguration" + tk.freeze("2021-01-21T12:00:00") describe("jsRunner", () => { diff --git a/packages/string-templates/test/utils.js b/packages/string-templates/test/utils.js index 2375c5868f..3a54502a3d 100644 --- a/packages/string-templates/test/utils.js +++ b/packages/string-templates/test/utils.js @@ -13,7 +13,7 @@ function tryParseJson(str) { } try { - return JSON.parse(str.replace(/\'/g, '"')) + return JSON.parse(str.replace(/'/g, '"')) } catch (e) { return } @@ -34,7 +34,7 @@ const getParsedManifest = () => { } // Trim 's - js = js.replace(/^\'|\'$/g, "") + js = js.replace(/^'|'$/g, "") let parsedExpected if ((parsedExpected = tryParseJson(js))) { if (Array.isArray(parsedExpected)) { @@ -97,7 +97,7 @@ module.exports.runJsHelpersTests = ({ funcWrap, testsToSkip } = {}) => { new RegExp(escapeRegExp(arrayString)), `array${i}` ) - context[`array${i}`] = JSON.parse(arrayString.replace(/\'/g, '"')) + context[`array${i}`] = JSON.parse(arrayString.replace(/'/g, '"')) }) let convertedJs = convertToJS(hbs) From 480476bcfe1143adaa6cf7d03adb779d84ced128 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 12:32:39 +0100 Subject: [PATCH 14/15] Lint --- packages/string-templates/src/index-helpers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/string-templates/src/index-helpers.js b/packages/string-templates/src/index-helpers.js index b0d9ac5c68..c71f8a9853 100644 --- a/packages/string-templates/src/index-helpers.js +++ b/packages/string-templates/src/index-helpers.js @@ -3,6 +3,7 @@ const { getJsHelperList } = require("./helpers/list") const helpers = getJsHelperList() module.exports = { ...helpers, - // point stripProtocol to a unexisting function to be able to declare it on isolated-vm + // pointing stripProtocol to a unexisting function to be able to declare it on isolated-vm + // eslint-disable-next-line no-undef stripProtocol: helpersStripProtocol, } From 380871800444b4509ce78a3388ef5db5e7acb219 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 1 Feb 2024 12:42:23 +0100 Subject: [PATCH 15/15] Fix tests --- packages/server/src/api/routes/tests/table.spec.ts | 2 +- packages/server/src/db/newid.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/routes/tests/table.spec.ts b/packages/server/src/api/routes/tests/table.spec.ts index 9129fd14c3..62efdda448 100644 --- a/packages/server/src/api/routes/tests/table.spec.ts +++ b/packages/server/src/api/routes/tests/table.spec.ts @@ -16,7 +16,7 @@ import { import { checkBuilderEndpoint } from "./utilities/TestFunctions" import * as setup from "./utilities" import sdk from "../../../sdk" -import uuid from "uuid" +import * as uuid from "uuid" const { basicTable } = setup.structures diff --git a/packages/server/src/db/newid.ts b/packages/server/src/db/newid.ts index 0037bc0353..bc8f3bb04b 100644 --- a/packages/server/src/db/newid.ts +++ b/packages/server/src/db/newid.ts @@ -1,4 +1,4 @@ -const { v4 } = require("uuid") +import { v4 } from "uuid" export default function (): string { return v4().replace(/-/g, "")