Merge pull request #13255 from Budibase/chore/stringtemplates-to-esm
String-templates to typescript
This commit is contained in:
commit
9ebec131b9
|
@ -7,11 +7,12 @@ module.exports = {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
/^@budibase\/[^/]+\/.*$/.test(importPath) &&
|
/^@budibase\/[^/]+\/.*$/.test(importPath) &&
|
||||||
importPath !== "@budibase/backend-core/tests"
|
importPath !== "@budibase/backend-core/tests" &&
|
||||||
|
importPath !== "@budibase/string-templates/test/utils"
|
||||||
) {
|
) {
|
||||||
context.report({
|
context.report({
|
||||||
node,
|
node,
|
||||||
message: `Importing from @budibase is not allowed, except for @budibase/backend-core/tests.`,
|
message: `Importing from @budibase is not allowed, except for @budibase/backend-core/tests and @budibase/string-templates/test/utils.`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,8 +12,6 @@ COPY .yarnrc .
|
||||||
|
|
||||||
COPY packages/server/package.json packages/server/package.json
|
COPY packages/server/package.json packages/server/package.json
|
||||||
COPY packages/worker/package.json packages/worker/package.json
|
COPY packages/worker/package.json packages/worker/package.json
|
||||||
# string-templates does not get bundled during the esbuild process, so we want to use the local version
|
|
||||||
COPY packages/string-templates/package.json packages/string-templates/package.json
|
|
||||||
|
|
||||||
|
|
||||||
COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh
|
COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh
|
||||||
|
@ -26,7 +24,7 @@ RUN ./scripts/removeWorkspaceDependencies.sh packages/worker/package.json
|
||||||
RUN echo '' > scripts/syncProPackage.js
|
RUN echo '' > scripts/syncProPackage.js
|
||||||
RUN jq 'del(.scripts.postinstall)' package.json > temp.json && mv temp.json package.json
|
RUN jq 'del(.scripts.postinstall)' package.json > temp.json && mv temp.json package.json
|
||||||
RUN ./scripts/removeWorkspaceDependencies.sh package.json
|
RUN ./scripts/removeWorkspaceDependencies.sh package.json
|
||||||
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production
|
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production --frozen-lockfile
|
||||||
|
|
||||||
# copy the actual code
|
# copy the actual code
|
||||||
COPY packages/server/dist packages/server/dist
|
COPY packages/server/dist packages/server/dist
|
||||||
|
@ -35,7 +33,6 @@ COPY packages/server/client packages/server/client
|
||||||
COPY packages/server/builder packages/server/builder
|
COPY packages/server/builder packages/server/builder
|
||||||
COPY packages/worker/dist packages/worker/dist
|
COPY packages/worker/dist packages/worker/dist
|
||||||
COPY packages/worker/pm2.config.js packages/worker/pm2.config.js
|
COPY packages/worker/pm2.config.js packages/worker/pm2.config.js
|
||||||
COPY packages/string-templates packages/string-templates
|
|
||||||
|
|
||||||
|
|
||||||
FROM budibase/couchdb:v3.3.3 as runner
|
FROM budibase/couchdb:v3.3.3 as runner
|
||||||
|
@ -52,11 +49,11 @@ RUN apt-get update && \
|
||||||
|
|
||||||
# Install postgres client for pg_dump utils
|
# Install postgres client for pg_dump utils
|
||||||
RUN apt install -y software-properties-common apt-transport-https ca-certificates gnupg \
|
RUN apt install -y software-properties-common apt-transport-https ca-certificates gnupg \
|
||||||
&& curl -fsSl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/postgresql.gpg > /dev/null \
|
&& curl -fsSl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/postgresql.gpg > /dev/null \
|
||||||
&& echo deb [arch=amd64,arm64,ppc64el signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main | tee /etc/apt/sources.list.d/postgresql.list \
|
&& echo deb [arch=amd64,arm64,ppc64el signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main | tee /etc/apt/sources.list.d/postgresql.list \
|
||||||
&& apt update -y \
|
&& apt update -y \
|
||||||
&& apt install postgresql-client-15 -y \
|
&& apt install postgresql-client-15 -y \
|
||||||
&& apt remove software-properties-common apt-transport-https gpg -y
|
&& apt remove software-properties-common apt-transport-https gpg -y
|
||||||
|
|
||||||
# We use pm2 in order to run multiple node processes in a single container
|
# We use pm2 in order to run multiple node processes in a single container
|
||||||
RUN npm install --global pm2
|
RUN npm install --global pm2
|
||||||
|
@ -100,9 +97,6 @@ COPY --from=build /app/node_modules /node_modules
|
||||||
COPY --from=build /app/package.json /package.json
|
COPY --from=build /app/package.json /package.json
|
||||||
COPY --from=build /app/packages/server /app
|
COPY --from=build /app/packages/server /app
|
||||||
COPY --from=build /app/packages/worker /worker
|
COPY --from=build /app/packages/worker /worker
|
||||||
COPY --from=build /app/packages/string-templates /string-templates
|
|
||||||
|
|
||||||
RUN cd /string-templates && yarn link && cd ../app && yarn link @budibase/string-templates && cd ../worker && yarn link @budibase/string-templates
|
|
||||||
|
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0c050591c21d3b67dc0c9225d60cc9e2324c8dac
|
Subproject commit 23a1219732bd778654c0bcc4f49910c511e2d51f
|
|
@ -15,7 +15,8 @@
|
||||||
"@budibase/types": ["../types/src"],
|
"@budibase/types": ["../types/src"],
|
||||||
"@budibase/backend-core": ["../backend-core/src"],
|
"@budibase/backend-core": ["../backend-core/src"],
|
||||||
"@budibase/backend-core/*": ["../backend-core/*"],
|
"@budibase/backend-core/*": ["../backend-core/*"],
|
||||||
"@budibase/shared-core": ["../shared-core/src"]
|
"@budibase/shared-core": ["../shared-core/src"],
|
||||||
|
"@budibase/string-templates": ["../string-templates/src"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"],
|
"include": ["src/**/*"],
|
||||||
|
|
|
@ -1,16 +1,8 @@
|
||||||
{
|
{
|
||||||
"extends": "./tsconfig.build.json",
|
"extends": "./tsconfig.build.json",
|
||||||
"compilerOptions": {
|
|
||||||
"composite": true,
|
|
||||||
"declaration": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"resolveJsonModule": true
|
|
||||||
},
|
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
"require": ["tsconfig-paths/register"],
|
"require": ["tsconfig-paths/register"],
|
||||||
"swc": true
|
"swc": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "package.json"],
|
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c4c98ae70f2e936009250893898ecf11f4ddf2c3
|
Subproject commit 65ac3fc8a20a5244fbe47629cf79678db2d9ae8a
|
|
@ -41,17 +41,9 @@ COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.
|
||||||
RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /string-templates
|
|
||||||
COPY packages/string-templates/package.json package.json
|
|
||||||
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
|
||||||
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000
|
|
||||||
COPY packages/string-templates .
|
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY packages/server/package.json .
|
COPY packages/server/package.json .
|
||||||
COPY packages/server/dist/yarn.lock .
|
COPY packages/server/dist/yarn.lock .
|
||||||
RUN cd ../string-templates && yarn link && cd - && yarn link @budibase/string-templates
|
|
||||||
|
|
||||||
COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh
|
COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh
|
||||||
RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
||||||
|
|
|
@ -30,6 +30,8 @@ const baseConfig: Config.InitialProjectOptions = {
|
||||||
"@budibase/backend-core": "<rootDir>/../backend-core/src",
|
"@budibase/backend-core": "<rootDir>/../backend-core/src",
|
||||||
"@budibase/shared-core": "<rootDir>/../shared-core/src",
|
"@budibase/shared-core": "<rootDir>/../shared-core/src",
|
||||||
"@budibase/types": "<rootDir>/../types/src",
|
"@budibase/types": "<rootDir>/../types/src",
|
||||||
|
"@budibase/string-templates/(.*)": ["<rootDir>/../string-templates/$1"],
|
||||||
|
"@budibase/string-templates": ["<rootDir>/../string-templates/src"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { validate as isValidUUID } from "uuid"
|
import { validate as isValidUUID } from "uuid"
|
||||||
import { processStringSync, encodeJSBinding } from "@budibase/string-templates"
|
import { processStringSync, encodeJSBinding } from "@budibase/string-templates"
|
||||||
|
|
||||||
const { runJsHelpersTests } = require("@budibase/string-templates/test/utils")
|
import { runJsHelpersTests } from "@budibase/string-templates/test/utils"
|
||||||
|
|
||||||
import tk from "timekeeper"
|
import tk from "timekeeper"
|
||||||
import { init } from ".."
|
import { init } from ".."
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
preset: "ts-jest",
|
||||||
// All imported modules in your tests should be mocked automatically
|
// All imported modules in your tests should be mocked automatically
|
||||||
// automock: false,
|
// automock: false,
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,28 @@
|
||||||
"name": "@budibase/string-templates",
|
"name": "@budibase/string-templates",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"description": "Handlebars wrapper for Budibase templating.",
|
"description": "Handlebars wrapper for Budibase templating.",
|
||||||
"main": "src/index.js",
|
"main": "dist/bundle.cjs",
|
||||||
"module": "dist/bundle.mjs",
|
"module": "dist/bundle.mjs",
|
||||||
|
"types": "src/index.ts",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"types": "dist/index.d.ts",
|
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"require": "./src/index.js",
|
"require": "./dist/bundle.cjs",
|
||||||
"import": "./dist/bundle.mjs"
|
"import": "./dist/bundle.mjs"
|
||||||
},
|
},
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
"./test/utils": "./test/utils.js",
|
|
||||||
"./iife": "./src/iife.js"
|
"./iife": "./src/iife.js"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
"src",
|
"src"
|
||||||
"manifest.json"
|
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && rollup -c",
|
"build": "tsc --emitDeclarationOnly && rollup -c",
|
||||||
"dev": "concurrently \"tsc --watch\" \"rollup -cw\"",
|
"dev": "rollup -cw",
|
||||||
|
"check:types": "tsc -p tsconfig.json --noEmit --paths null",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"manifest": "node ./scripts/gen-collection-info.js"
|
"manifest": "ts-node ./scripts/gen-collection-info.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/handlebars-helpers": "^0.13.1",
|
"@budibase/handlebars-helpers": "^0.13.1",
|
||||||
|
@ -34,8 +33,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^17.1.0",
|
"@rollup/plugin-commonjs": "^17.1.0",
|
||||||
"@rollup/plugin-json": "^4.1.0",
|
"@rollup/plugin-typescript": "8.3.0",
|
||||||
"concurrently": "^8.2.2",
|
|
||||||
"doctrine": "^3.0.0",
|
"doctrine": "^3.0.0",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"marked": "^4.0.10",
|
"marked": "^4.0.10",
|
||||||
|
|
|
@ -4,31 +4,36 @@ import json from "@rollup/plugin-json"
|
||||||
import { terser } from "rollup-plugin-terser"
|
import { terser } from "rollup-plugin-terser"
|
||||||
import builtins from "rollup-plugin-node-builtins"
|
import builtins from "rollup-plugin-node-builtins"
|
||||||
import globals from "rollup-plugin-node-globals"
|
import globals from "rollup-plugin-node-globals"
|
||||||
|
import typescript from "@rollup/plugin-typescript"
|
||||||
import injectProcessEnv from "rollup-plugin-inject-process-env"
|
import injectProcessEnv from "rollup-plugin-inject-process-env"
|
||||||
|
|
||||||
const production = !process.env.ROLLUP_WATCH
|
const production = !process.env.ROLLUP_WATCH
|
||||||
|
|
||||||
export default [
|
const config = (format, outputFile) => ({
|
||||||
{
|
input: "src/index.ts",
|
||||||
input: "src/index.mjs",
|
output: {
|
||||||
output: {
|
sourcemap: !production,
|
||||||
sourcemap: !production,
|
format,
|
||||||
format: "esm",
|
file: outputFile,
|
||||||
file: "./dist/bundle.mjs",
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
resolve({
|
|
||||||
preferBuiltins: true,
|
|
||||||
browser: true,
|
|
||||||
}),
|
|
||||||
commonjs(),
|
|
||||||
globals(),
|
|
||||||
builtins(),
|
|
||||||
json(),
|
|
||||||
injectProcessEnv({
|
|
||||||
NO_JS: process.env.NO_JS,
|
|
||||||
}),
|
|
||||||
production && terser(),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
plugins: [
|
||||||
|
typescript(),
|
||||||
|
resolve({
|
||||||
|
preferBuiltins: true,
|
||||||
|
browser: true,
|
||||||
|
}),
|
||||||
|
commonjs(),
|
||||||
|
globals(),
|
||||||
|
builtins(),
|
||||||
|
json(),
|
||||||
|
injectProcessEnv({
|
||||||
|
NO_JS: process.env.NO_JS,
|
||||||
|
}),
|
||||||
|
production && terser(),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export default [
|
||||||
|
config("cjs", "./dist/bundle.cjs"),
|
||||||
|
config("esm", "./dist/bundle.mjs"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -22,7 +22,7 @@ const COLLECTIONS = [
|
||||||
"object",
|
"object",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
const FILENAME = join(__dirname, "..", "manifest.json")
|
const FILENAME = join(__dirname, "..", "src", "manifest.json")
|
||||||
const outputJSON = {}
|
const outputJSON = {}
|
||||||
const ADDED_HELPERS = {
|
const ADDED_HELPERS = {
|
||||||
date: {
|
date: {
|
||||||
|
@ -126,7 +126,7 @@ const excludeFunctions = { string: ["raw"] }
|
||||||
* This script is very specific to purpose, parsing the handlebars-helpers files to attempt to get information about them.
|
* This script is very specific to purpose, parsing the handlebars-helpers files to attempt to get information about them.
|
||||||
*/
|
*/
|
||||||
function run() {
|
function run() {
|
||||||
const foundNames = []
|
const foundNames: string[] = []
|
||||||
for (let collection of COLLECTIONS) {
|
for (let collection of COLLECTIONS) {
|
||||||
const collectionFile = fs.readFileSync(
|
const collectionFile = fs.readFileSync(
|
||||||
`${path.dirname(require.resolve(HELPER_LIBRARY))}/lib/${collection}.js`,
|
`${path.dirname(require.resolve(HELPER_LIBRARY))}/lib/${collection}.js`,
|
||||||
|
@ -147,7 +147,7 @@ function run() {
|
||||||
}
|
}
|
||||||
foundNames.push(name)
|
foundNames.push(name)
|
||||||
// this is ridiculous, but it parse the function header
|
// this is ridiculous, but it parse the function header
|
||||||
const fnc = entry[1].toString()
|
const fnc = entry[1]!.toString()
|
||||||
const jsDocInfo = getCommentInfo(collectionFile, fnc)
|
const jsDocInfo = getCommentInfo(collectionFile, fnc)
|
||||||
let args = jsDocInfo.tags
|
let args = jsDocInfo.tags
|
||||||
.filter(tag => tag.title === "param")
|
.filter(tag => tag.title === "param")
|
||||||
|
@ -176,8 +176,8 @@ function run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert all markdown to HTML
|
// convert all markdown to HTML
|
||||||
for (let collection of Object.values(outputJSON)) {
|
for (let collection of Object.values<any>(outputJSON)) {
|
||||||
for (let helper of Object.values(collection)) {
|
for (let helper of Object.values<any>(collection)) {
|
||||||
helper.description = marked.parse(helper.description)
|
helper.description = marked.parse(helper.description)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
const { getJsHelperList } = require("../helpers")
|
import { getJsHelperList } from "../helpers"
|
||||||
|
|
||||||
function getLayers(fullBlock) {
|
function getLayers(fullBlock: string): string[] {
|
||||||
let layers = []
|
let layers = []
|
||||||
while (fullBlock.length) {
|
while (fullBlock.length) {
|
||||||
const start = fullBlock.lastIndexOf("("),
|
const start = fullBlock.lastIndexOf("("),
|
||||||
end = fullBlock.indexOf(")")
|
end = fullBlock.indexOf(")")
|
||||||
let layer
|
let layer: string
|
||||||
if (start === -1 || end === -1) {
|
if (start === -1 || end === -1) {
|
||||||
layer = fullBlock.trim()
|
layer = fullBlock.trim()
|
||||||
fullBlock = ""
|
fullBlock = ""
|
||||||
|
@ -21,7 +21,7 @@ function getLayers(fullBlock) {
|
||||||
return layers
|
return layers
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVariable(variableName) {
|
function getVariable(variableName: string) {
|
||||||
if (!variableName || typeof variableName !== "string") {
|
if (!variableName || typeof variableName !== "string") {
|
||||||
return variableName
|
return variableName
|
||||||
}
|
}
|
||||||
|
@ -47,10 +47,12 @@ function getVariable(variableName) {
|
||||||
return `$("${variableName}")`
|
return `$("${variableName}")`
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildList(parts, value) {
|
function buildList(parts: string[], value: any) {
|
||||||
function build() {
|
function build() {
|
||||||
return parts
|
return parts
|
||||||
.map(part => (part.startsWith("helper") ? part : getVariable(part)))
|
.map((part: string) =>
|
||||||
|
part.startsWith("helper") ? part : getVariable(part)
|
||||||
|
)
|
||||||
.join(", ")
|
.join(", ")
|
||||||
}
|
}
|
||||||
if (!value) {
|
if (!value) {
|
||||||
|
@ -60,12 +62,12 @@ function buildList(parts, value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function splitBySpace(layer) {
|
function splitBySpace(layer: string) {
|
||||||
const parts = []
|
const parts: string[] = []
|
||||||
let started = null,
|
let started = null,
|
||||||
endChar = null,
|
endChar = null,
|
||||||
last = 0
|
last = 0
|
||||||
function add(str) {
|
function add(str: string) {
|
||||||
const startsWith = ["]"]
|
const startsWith = ["]"]
|
||||||
while (startsWith.indexOf(str.substring(0, 1)) !== -1) {
|
while (startsWith.indexOf(str.substring(0, 1)) !== -1) {
|
||||||
str = str.substring(1, str.length)
|
str = str.substring(1, str.length)
|
||||||
|
@ -103,7 +105,7 @@ function splitBySpace(layer) {
|
||||||
return parts
|
return parts
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.convertHBSBlock = (block, blockNumber) => {
|
export function convertHBSBlock(block: string, blockNumber: number) {
|
||||||
const braceLength = block[2] === "{" ? 3 : 2
|
const braceLength = block[2] === "{" ? 3 : 2
|
||||||
block = block.substring(braceLength, block.length - braceLength).trim()
|
block = block.substring(braceLength, block.length - braceLength).trim()
|
||||||
const layers = getLayers(block)
|
const layers = getLayers(block)
|
||||||
|
@ -114,7 +116,7 @@ module.exports.convertHBSBlock = (block, blockNumber) => {
|
||||||
const parts = splitBySpace(layer)
|
const parts = splitBySpace(layer)
|
||||||
if (value || parts.length > 1 || list[parts[0]]) {
|
if (value || parts.length > 1 || list[parts[0]]) {
|
||||||
// first of layer should always be the helper
|
// first of layer should always be the helper
|
||||||
const helper = parts.splice(0, 1)
|
const [helper] = parts.splice(0, 1)
|
||||||
if (list[helper]) {
|
if (list[helper]) {
|
||||||
value = `helpers.${helper}(${buildList(parts, value)})`
|
value = `helpers.${helper}(${buildList(parts, value)})`
|
||||||
}
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
class JsErrorTimeout extends Error {
|
|
||||||
code = "ERR_SCRIPT_EXECUTION_TIMEOUT"
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
JsErrorTimeout,
|
|
||||||
}
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export class JsErrorTimeout extends Error {
|
||||||
|
code = "ERR_SCRIPT_EXECUTION_TIMEOUT"
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
class Helper {
|
|
||||||
constructor(name, fn, useValueFallback = true) {
|
|
||||||
this.name = name
|
|
||||||
this.fn = fn
|
|
||||||
this.useValueFallback = useValueFallback
|
|
||||||
}
|
|
||||||
|
|
||||||
register(handlebars) {
|
|
||||||
// wrap the function so that no helper can cause handlebars to break
|
|
||||||
handlebars.registerHelper(this.name, (value, info) => {
|
|
||||||
let context = {}
|
|
||||||
if (info && info.data && info.data.root) {
|
|
||||||
context = info.data.root
|
|
||||||
}
|
|
||||||
const result = this.fn(value, context)
|
|
||||||
if (result == null) {
|
|
||||||
return this.useValueFallback ? value : null
|
|
||||||
} else {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
unregister(handlebars) {
|
|
||||||
handlebars.unregisterHelper(this.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Helper
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
export default class Helper {
|
||||||
|
private name: any
|
||||||
|
private fn: any
|
||||||
|
private useValueFallback: boolean
|
||||||
|
|
||||||
|
constructor(name: string, fn: any, useValueFallback = true) {
|
||||||
|
this.name = name
|
||||||
|
this.fn = fn
|
||||||
|
this.useValueFallback = useValueFallback
|
||||||
|
}
|
||||||
|
|
||||||
|
register(handlebars: typeof Handlebars) {
|
||||||
|
// wrap the function so that no helper can cause handlebars to break
|
||||||
|
handlebars.registerHelper(
|
||||||
|
this.name,
|
||||||
|
(value: any, info: { data: { root: {} } }) => {
|
||||||
|
let context = {}
|
||||||
|
if (info && info.data && info.data.root) {
|
||||||
|
context = info.data.root
|
||||||
|
}
|
||||||
|
const result = this.fn(value, context)
|
||||||
|
if (result == null) {
|
||||||
|
return this.useValueFallback ? value : null
|
||||||
|
} else {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unregister(handlebars: { unregisterHelper: any }) {
|
||||||
|
handlebars.unregisterHelper(this.name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
module.exports.HelperFunctionBuiltin = [
|
export const HelperFunctionBuiltin = [
|
||||||
"#if",
|
"#if",
|
||||||
"#unless",
|
"#unless",
|
||||||
"#each",
|
"#each",
|
||||||
|
@ -15,11 +15,11 @@ module.exports.HelperFunctionBuiltin = [
|
||||||
"with",
|
"with",
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports.HelperFunctionNames = {
|
export const HelperFunctionNames = {
|
||||||
OBJECT: "object",
|
OBJECT: "object",
|
||||||
ALL: "all",
|
ALL: "all",
|
||||||
LITERAL: "literal",
|
LITERAL: "literal",
|
||||||
JS: "js",
|
JS: "js",
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.LITERAL_MARKER = "%LITERAL%"
|
export const LITERAL_MARKER = "%LITERAL%"
|
|
@ -1,12 +1,22 @@
|
||||||
const dayjs = require("dayjs")
|
import dayjs from "dayjs"
|
||||||
dayjs.extend(require("dayjs/plugin/duration"))
|
|
||||||
dayjs.extend(require("dayjs/plugin/advancedFormat"))
|
import dayjsDurationPlugin from "dayjs/plugin/duration"
|
||||||
dayjs.extend(require("dayjs/plugin/isoWeek"))
|
import dayjsAdvancedFormatPlugin from "dayjs/plugin/advancedFormat"
|
||||||
dayjs.extend(require("dayjs/plugin/weekYear"))
|
import dayjsIsoWeekPlugin from "dayjs/plugin/isoWeek"
|
||||||
dayjs.extend(require("dayjs/plugin/weekOfYear"))
|
import dayjsWeekYearPlugin from "dayjs/plugin/weekYear"
|
||||||
dayjs.extend(require("dayjs/plugin/relativeTime"))
|
import dayjsWeekOfYearPlugin from "dayjs/plugin/weekOfYear"
|
||||||
dayjs.extend(require("dayjs/plugin/utc"))
|
import dayjsRelativeTimePlugin from "dayjs/plugin/relativeTime"
|
||||||
dayjs.extend(require("dayjs/plugin/timezone"))
|
import dayjsUtcPlugin from "dayjs/plugin/utc"
|
||||||
|
import dayjsTimezonePlugin from "dayjs/plugin/timezone"
|
||||||
|
|
||||||
|
dayjs.extend(dayjsDurationPlugin)
|
||||||
|
dayjs.extend(dayjsAdvancedFormatPlugin)
|
||||||
|
dayjs.extend(dayjsIsoWeekPlugin)
|
||||||
|
dayjs.extend(dayjsWeekYearPlugin)
|
||||||
|
dayjs.extend(dayjsWeekOfYearPlugin)
|
||||||
|
dayjs.extend(dayjsRelativeTimePlugin)
|
||||||
|
dayjs.extend(dayjsUtcPlugin)
|
||||||
|
dayjs.extend(dayjsTimezonePlugin)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file was largely taken from the helper-date package - we did this for two reasons:
|
* This file was largely taken from the helper-date package - we did this for two reasons:
|
||||||
|
@ -17,11 +27,11 @@ dayjs.extend(require("dayjs/plugin/timezone"))
|
||||||
* https://github.com/helpers/helper-date
|
* https://github.com/helpers/helper-date
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function isOptions(val) {
|
function isOptions(val: any) {
|
||||||
return typeof val === "object" && typeof val.hash === "object"
|
return typeof val === "object" && typeof val.hash === "object"
|
||||||
}
|
}
|
||||||
|
|
||||||
function isApp(thisArg) {
|
function isApp(thisArg: any) {
|
||||||
return (
|
return (
|
||||||
typeof thisArg === "object" &&
|
typeof thisArg === "object" &&
|
||||||
typeof thisArg.options === "object" &&
|
typeof thisArg.options === "object" &&
|
||||||
|
@ -29,7 +39,7 @@ function isApp(thisArg) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContext(thisArg, locals, options) {
|
function getContext(thisArg: any, locals: any, options: any) {
|
||||||
if (isOptions(thisArg)) {
|
if (isOptions(thisArg)) {
|
||||||
return getContext({}, locals, thisArg)
|
return getContext({}, locals, thisArg)
|
||||||
}
|
}
|
||||||
|
@ -58,7 +68,7 @@ function getContext(thisArg, locals, options) {
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
function initialConfig(str, pattern, options) {
|
function initialConfig(str: any, pattern: any, options?: any) {
|
||||||
if (isOptions(pattern)) {
|
if (isOptions(pattern)) {
|
||||||
options = pattern
|
options = pattern
|
||||||
pattern = null
|
pattern = null
|
||||||
|
@ -72,7 +82,7 @@ function initialConfig(str, pattern, options) {
|
||||||
return { str, pattern, options }
|
return { str, pattern, options }
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLocale(str, pattern, options) {
|
function setLocale(this: any, str: any, pattern: any, options?: any) {
|
||||||
// if options is null then it'll get updated here
|
// if options is null then it'll get updated here
|
||||||
const config = initialConfig(str, pattern, options)
|
const config = initialConfig(str, pattern, options)
|
||||||
const defaults = { lang: "en", date: new Date(config.str) }
|
const defaults = { lang: "en", date: new Date(config.str) }
|
||||||
|
@ -83,7 +93,7 @@ function setLocale(str, pattern, options) {
|
||||||
dayjs.locale(opts.lang || opts.language)
|
dayjs.locale(opts.lang || opts.language)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.date = (str, pattern, options) => {
|
export const date = (str: any, pattern: any, options: any) => {
|
||||||
const config = initialConfig(str, pattern, options)
|
const config = initialConfig(str, pattern, options)
|
||||||
|
|
||||||
// if no args are passed, return a formatted date
|
// if no args are passed, return a formatted date
|
||||||
|
@ -109,7 +119,7 @@ module.exports.date = (str, pattern, options) => {
|
||||||
return date.format(config.pattern)
|
return date.format(config.pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.duration = (str, pattern, format) => {
|
export const duration = (str: any, pattern: any, format: any) => {
|
||||||
const config = initialConfig(str, pattern)
|
const config = initialConfig(str, pattern)
|
||||||
|
|
||||||
setLocale(config.str, config.pattern)
|
setLocale(config.str, config.pattern)
|
|
@ -1,6 +1,8 @@
|
||||||
const helpers = require("@budibase/handlebars-helpers")
|
// @ts-ignore we don't have types for it
|
||||||
const { date, duration } = require("./date")
|
import helpers from "@budibase/handlebars-helpers"
|
||||||
const { HelperFunctionBuiltin } = require("./constants")
|
|
||||||
|
import { date, duration } from "./date"
|
||||||
|
import { HelperFunctionBuiltin } from "./constants"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* full list of supported helpers can be found here:
|
* full list of supported helpers can be found here:
|
||||||
|
@ -24,10 +26,10 @@ const ADDED_HELPERS = {
|
||||||
duration: duration,
|
duration: duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.externalCollections = EXTERNAL_FUNCTION_COLLECTIONS
|
export const externalCollections = EXTERNAL_FUNCTION_COLLECTIONS
|
||||||
exports.addedHelpers = ADDED_HELPERS
|
export const addedHelpers = ADDED_HELPERS
|
||||||
|
|
||||||
exports.registerAll = handlebars => {
|
export function registerAll(handlebars: typeof Handlebars) {
|
||||||
for (let [name, helper] of Object.entries(ADDED_HELPERS)) {
|
for (let [name, helper] of Object.entries(ADDED_HELPERS)) {
|
||||||
handlebars.registerHelper(name, helper)
|
handlebars.registerHelper(name, helper)
|
||||||
}
|
}
|
||||||
|
@ -52,17 +54,17 @@ exports.registerAll = handlebars => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// add date external functionality
|
// add date external functionality
|
||||||
exports.externalHelperNames = externalNames.concat(Object.keys(ADDED_HELPERS))
|
externalHelperNames = externalNames.concat(Object.keys(ADDED_HELPERS))
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.unregisterAll = handlebars => {
|
export function unregisterAll(handlebars: typeof Handlebars) {
|
||||||
for (let name of Object.keys(ADDED_HELPERS)) {
|
for (let name of Object.keys(ADDED_HELPERS)) {
|
||||||
handlebars.unregisterHelper(name)
|
handlebars.unregisterHelper(name)
|
||||||
}
|
}
|
||||||
for (let name of module.exports.externalHelperNames) {
|
for (let name of externalHelperNames) {
|
||||||
handlebars.unregisterHelper(name)
|
handlebars.unregisterHelper(name)
|
||||||
}
|
}
|
||||||
exports.externalHelperNames = []
|
externalHelperNames = []
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.externalHelperNames = []
|
export let externalHelperNames: any[] = []
|
|
@ -1,100 +0,0 @@
|
||||||
const Helper = require("./Helper")
|
|
||||||
const { SafeString } = require("handlebars")
|
|
||||||
const externalHandlebars = require("./external")
|
|
||||||
const { processJS } = require("./javascript")
|
|
||||||
const {
|
|
||||||
HelperFunctionNames,
|
|
||||||
HelperFunctionBuiltin,
|
|
||||||
LITERAL_MARKER,
|
|
||||||
} = require("./constants")
|
|
||||||
const { getJsHelperList } = require("./list")
|
|
||||||
|
|
||||||
const HTML_SWAPS = {
|
|
||||||
"<": "<",
|
|
||||||
">": ">",
|
|
||||||
}
|
|
||||||
|
|
||||||
function isObject(value) {
|
|
||||||
if (value == null || typeof value !== "object") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
value.toString() === "[object Object]" ||
|
|
||||||
(value.length > 0 && typeof value[0] === "object")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const HELPERS = [
|
|
||||||
// external helpers
|
|
||||||
new Helper(HelperFunctionNames.OBJECT, value => {
|
|
||||||
return new SafeString(JSON.stringify(value))
|
|
||||||
}),
|
|
||||||
// javascript helper
|
|
||||||
new Helper(HelperFunctionNames.JS, processJS, false),
|
|
||||||
// this help is applied to all statements
|
|
||||||
new Helper(HelperFunctionNames.ALL, (value, inputs) => {
|
|
||||||
const { __opts } = inputs
|
|
||||||
if (isObject(value)) {
|
|
||||||
return new SafeString(JSON.stringify(value))
|
|
||||||
}
|
|
||||||
// null/undefined values produce bad results
|
|
||||||
if (__opts && __opts.onlyFound && value == null) {
|
|
||||||
return __opts.input
|
|
||||||
}
|
|
||||||
if (value == null || typeof value !== "string") {
|
|
||||||
return value == null ? "" : value
|
|
||||||
}
|
|
||||||
if (value && value.string) {
|
|
||||||
value = value.string
|
|
||||||
}
|
|
||||||
let text = value
|
|
||||||
if (__opts && __opts.escapeNewlines) {
|
|
||||||
text = value.replace(/\n/g, "\\n")
|
|
||||||
}
|
|
||||||
text = new SafeString(text.replace(/&/g, "&"))
|
|
||||||
if (text == null || typeof text !== "string") {
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
return text.replace(/[<>]/g, tag => {
|
|
||||||
return HTML_SWAPS[tag] || tag
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
// adds a note for post-processor
|
|
||||||
new Helper(HelperFunctionNames.LITERAL, value => {
|
|
||||||
if (value === undefined) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
const type = typeof value
|
|
||||||
const outputVal = type === "object" ? JSON.stringify(value) : value
|
|
||||||
return `{{${LITERAL_MARKER} ${type}-${outputVal}}}`
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
|
|
||||||
module.exports.HelperNames = () => {
|
|
||||||
return Object.values(HelperFunctionNames).concat(
|
|
||||||
HelperFunctionBuiltin,
|
|
||||||
externalHandlebars.externalHelperNames
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.registerMinimum = handlebars => {
|
|
||||||
for (let helper of HELPERS) {
|
|
||||||
helper.register(handlebars)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.registerAll = handlebars => {
|
|
||||||
module.exports.registerMinimum(handlebars)
|
|
||||||
// register imported helpers
|
|
||||||
externalHandlebars.registerAll(handlebars)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.unregisterAll = handlebars => {
|
|
||||||
for (let helper of HELPERS) {
|
|
||||||
helper.unregister(handlebars)
|
|
||||||
}
|
|
||||||
// unregister all imported helpers
|
|
||||||
externalHandlebars.unregisterAll(handlebars)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.getJsHelperList = getJsHelperList
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
import Helper from "./Helper"
|
||||||
|
import { SafeString } from "handlebars"
|
||||||
|
import * as externalHandlebars from "./external"
|
||||||
|
import { processJS } from "./javascript"
|
||||||
|
import {
|
||||||
|
HelperFunctionNames,
|
||||||
|
HelperFunctionBuiltin,
|
||||||
|
LITERAL_MARKER,
|
||||||
|
} from "./constants"
|
||||||
|
|
||||||
|
export { getJsHelperList } from "./list"
|
||||||
|
|
||||||
|
const HTML_SWAPS = {
|
||||||
|
"<": "<",
|
||||||
|
">": ">",
|
||||||
|
}
|
||||||
|
|
||||||
|
function isObject(value: string | any[]) {
|
||||||
|
if (value == null || typeof value !== "object") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
value.toString() === "[object Object]" ||
|
||||||
|
(value.length > 0 && typeof value[0] === "object")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const HELPERS = [
|
||||||
|
// external helpers
|
||||||
|
new Helper(HelperFunctionNames.OBJECT, (value: any) => {
|
||||||
|
return new SafeString(JSON.stringify(value))
|
||||||
|
}),
|
||||||
|
// javascript helper
|
||||||
|
new Helper(HelperFunctionNames.JS, processJS, false),
|
||||||
|
// this help is applied to all statements
|
||||||
|
new Helper(
|
||||||
|
HelperFunctionNames.ALL,
|
||||||
|
(value: string, inputs: { __opts: any }) => {
|
||||||
|
const { __opts } = inputs
|
||||||
|
if (isObject(value)) {
|
||||||
|
return new SafeString(JSON.stringify(value))
|
||||||
|
}
|
||||||
|
// null/undefined values produce bad results
|
||||||
|
if (__opts && __opts.onlyFound && value == null) {
|
||||||
|
return __opts.input
|
||||||
|
}
|
||||||
|
if (value == null || typeof value !== "string") {
|
||||||
|
return value == null ? "" : value
|
||||||
|
}
|
||||||
|
// TODO: check, this should always be false
|
||||||
|
if (value && (value as any).string) {
|
||||||
|
value = (value as any).string
|
||||||
|
}
|
||||||
|
let text: any = value
|
||||||
|
if (__opts && __opts.escapeNewlines) {
|
||||||
|
text = value.replace(/\n/g, "\\n")
|
||||||
|
}
|
||||||
|
text = new SafeString(text.replace(/&/g, "&"))
|
||||||
|
if (text == null || typeof text !== "string") {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
return text.replace(/[<>]/g, (tag: string) => {
|
||||||
|
return HTML_SWAPS[tag as keyof typeof HTML_SWAPS] || tag
|
||||||
|
})
|
||||||
|
}
|
||||||
|
),
|
||||||
|
// adds a note for post-processor
|
||||||
|
new Helper(HelperFunctionNames.LITERAL, (value: any) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
const type = typeof value
|
||||||
|
const outputVal = type === "object" ? JSON.stringify(value) : value
|
||||||
|
return `{{${LITERAL_MARKER} ${type}-${outputVal}}}`
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
|
||||||
|
export function HelperNames() {
|
||||||
|
return Object.values(HelperFunctionNames).concat(
|
||||||
|
HelperFunctionBuiltin,
|
||||||
|
externalHandlebars.externalHelperNames
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerMinimum(handlebars: typeof Handlebars) {
|
||||||
|
for (let helper of HELPERS) {
|
||||||
|
helper.register(handlebars)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerAll(handlebars: typeof Handlebars) {
|
||||||
|
registerMinimum(handlebars)
|
||||||
|
// register imported helpers
|
||||||
|
externalHandlebars.registerAll(handlebars)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unregisterAll(handlebars: any) {
|
||||||
|
for (let helper of HELPERS) {
|
||||||
|
helper.unregister(handlebars)
|
||||||
|
}
|
||||||
|
// unregister all imported helpers
|
||||||
|
externalHandlebars.unregisterAll(handlebars)
|
||||||
|
}
|
|
@ -1,22 +1,24 @@
|
||||||
const { atob, isBackendService, isJSAllowed } = require("../utilities")
|
import { atob, isJSAllowed } from "../utilities"
|
||||||
const cloneDeep = require("lodash.clonedeep")
|
import cloneDeep from "lodash/fp/cloneDeep"
|
||||||
const { LITERAL_MARKER } = require("../helpers/constants")
|
import { LITERAL_MARKER } from "../helpers/constants"
|
||||||
const { getJsHelperList } = require("./list")
|
import { getJsHelperList } from "./list"
|
||||||
const { iifeWrapper } = require("../iife")
|
import { iifeWrapper } from "../iife"
|
||||||
|
|
||||||
// The method of executing JS scripts depends on the bundle being built.
|
// The method of executing JS scripts depends on the bundle being built.
|
||||||
// This setter is used in the entrypoint (either index.js or index.mjs).
|
// This setter is used in the entrypoint (either index.js or index.mjs).
|
||||||
let runJS
|
let runJS: ((js: string, context: any) => any) | undefined = undefined
|
||||||
module.exports.setJSRunner = runner => (runJS = runner)
|
export const setJSRunner = (runner: typeof runJS) => (runJS = runner)
|
||||||
module.exports.removeJSRunner = () => {
|
|
||||||
|
export const removeJSRunner = () => {
|
||||||
runJS = undefined
|
runJS = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
let onErrorLog
|
let onErrorLog: (message: Error) => void
|
||||||
module.exports.setOnErrorLog = delegate => (onErrorLog = delegate)
|
export const setOnErrorLog = (delegate: typeof onErrorLog) =>
|
||||||
|
(onErrorLog = delegate)
|
||||||
|
|
||||||
// Helper utility to strip square brackets from a value
|
// Helper utility to strip square brackets from a value
|
||||||
const removeSquareBrackets = value => {
|
const removeSquareBrackets = (value: string) => {
|
||||||
if (!value || typeof value !== "string") {
|
if (!value || typeof value !== "string") {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
@ -30,7 +32,7 @@ const removeSquareBrackets = value => {
|
||||||
|
|
||||||
// Our context getter function provided to JS code as $.
|
// Our context getter function provided to JS code as $.
|
||||||
// Extracts a value from context.
|
// Extracts a value from context.
|
||||||
const getContextValue = (path, context) => {
|
const getContextValue = (path: string, context: any) => {
|
||||||
let data = context
|
let data = context
|
||||||
path.split(".").forEach(key => {
|
path.split(".").forEach(key => {
|
||||||
if (data == null || typeof data !== "object") {
|
if (data == null || typeof data !== "object") {
|
||||||
|
@ -42,8 +44,8 @@ const getContextValue = (path, context) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluates JS code against a certain context
|
// Evaluates JS code against a certain context
|
||||||
module.exports.processJS = (handlebars, context) => {
|
export function processJS(handlebars: string, context: any) {
|
||||||
if (!isJSAllowed() || (isBackendService() && !runJS)) {
|
if (!isJSAllowed() || !runJS) {
|
||||||
throw new Error("JS disabled in environment.")
|
throw new Error("JS disabled in environment.")
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -53,8 +55,8 @@ module.exports.processJS = (handlebars, context) => {
|
||||||
|
|
||||||
// Transform snippets into an object for faster access, and cache previously
|
// Transform snippets into an object for faster access, and cache previously
|
||||||
// evaluated snippets
|
// evaluated snippets
|
||||||
let snippetMap = {}
|
let snippetMap: any = {}
|
||||||
let snippetCache = {}
|
let snippetCache: any = {}
|
||||||
for (let snippet of context.snippets || []) {
|
for (let snippet of context.snippets || []) {
|
||||||
snippetMap[snippet.name] = snippet.code
|
snippetMap[snippet.name] = snippet.code
|
||||||
}
|
}
|
||||||
|
@ -64,7 +66,7 @@ module.exports.processJS = (handlebars, context) => {
|
||||||
// app context.
|
// app context.
|
||||||
const clonedContext = cloneDeep({ ...context, snippets: null })
|
const clonedContext = cloneDeep({ ...context, snippets: null })
|
||||||
const sandboxContext = {
|
const sandboxContext = {
|
||||||
$: path => getContextValue(path, clonedContext),
|
$: (path: string) => getContextValue(path, clonedContext),
|
||||||
helpers: getJsHelperList(),
|
helpers: getJsHelperList(),
|
||||||
|
|
||||||
// Proxy to evaluate snippets when running in the browser
|
// Proxy to evaluate snippets when running in the browser
|
||||||
|
@ -84,7 +86,7 @@ module.exports.processJS = (handlebars, context) => {
|
||||||
// Create a sandbox with our context and run the JS
|
// Create a sandbox with our context and run the JS
|
||||||
const res = { data: runJS(js, sandboxContext) }
|
const res = { data: runJS(js, sandboxContext) }
|
||||||
return `{{${LITERAL_MARKER} js_result-${JSON.stringify(res)}}}`
|
return `{{${LITERAL_MARKER} js_result-${JSON.stringify(res)}}}`
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
onErrorLog && onErrorLog(error)
|
onErrorLog && onErrorLog(error)
|
||||||
|
|
||||||
if (error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
|
if (error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
|
|
@ -1,7 +1,7 @@
|
||||||
const { date, duration } = require("./date")
|
import { date, duration } from "./date"
|
||||||
|
|
||||||
// https://github.com/evanw/esbuild/issues/56
|
// https://github.com/evanw/esbuild/issues/56
|
||||||
const externalCollections = {
|
const getExternalCollections = (): Record<string, () => any> => ({
|
||||||
math: require("@budibase/handlebars-helpers/lib/math"),
|
math: require("@budibase/handlebars-helpers/lib/math"),
|
||||||
array: require("@budibase/handlebars-helpers/lib/array"),
|
array: require("@budibase/handlebars-helpers/lib/array"),
|
||||||
number: require("@budibase/handlebars-helpers/lib/number"),
|
number: require("@budibase/handlebars-helpers/lib/number"),
|
||||||
|
@ -11,32 +11,32 @@ const externalCollections = {
|
||||||
object: require("@budibase/handlebars-helpers/lib/object"),
|
object: require("@budibase/handlebars-helpers/lib/object"),
|
||||||
regex: require("@budibase/handlebars-helpers/lib/regex"),
|
regex: require("@budibase/handlebars-helpers/lib/regex"),
|
||||||
uuid: require("@budibase/handlebars-helpers/lib/uuid"),
|
uuid: require("@budibase/handlebars-helpers/lib/uuid"),
|
||||||
}
|
})
|
||||||
|
|
||||||
const helpersToRemoveForJs = ["sortBy"]
|
export const helpersToRemoveForJs = ["sortBy"]
|
||||||
module.exports.helpersToRemoveForJs = helpersToRemoveForJs
|
|
||||||
|
|
||||||
const addedHelpers = {
|
const addedHelpers = {
|
||||||
date: date,
|
date: date,
|
||||||
duration: duration,
|
duration: duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
let helpers = undefined
|
let helpers: Record<string, any>
|
||||||
|
|
||||||
module.exports.getJsHelperList = () => {
|
export function getJsHelperList() {
|
||||||
if (helpers) {
|
if (helpers) {
|
||||||
return helpers
|
return helpers
|
||||||
}
|
}
|
||||||
|
|
||||||
helpers = {}
|
helpers = {}
|
||||||
for (let collection of Object.values(externalCollections)) {
|
for (let collection of Object.values(getExternalCollections())) {
|
||||||
for (let [key, func] of Object.entries(collection)) {
|
for (let [key, func] of Object.entries(collection)) {
|
||||||
// Handlebars injects the hbs options to the helpers by default. We are adding an empty {} as a last parameter to simulate it
|
// Handlebars injects the hbs options to the helpers by default. We are adding an empty {} as a last parameter to simulate it
|
||||||
helpers[key] = (...props) => func(...props, {})
|
helpers[key] = (...props: any) => func(...props, {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let key of Object.keys(addedHelpers)) {
|
helpers = {
|
||||||
helpers[key] = addedHelpers[key]
|
...helpers,
|
||||||
|
addedHelpers,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const toRemove of helpersToRemoveForJs) {
|
for (const toRemove of helpersToRemoveForJs) {
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports.iifeWrapper = script => {
|
|
||||||
return `(function(){\n${script}\n})();`
|
|
||||||
}
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const iifeWrapper = (script: string) => {
|
||||||
|
return `(function(){\n${script}\n})();`
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
import templates from "./index.js"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ES6 entrypoint for rollup
|
|
||||||
*/
|
|
||||||
export const isValid = templates.isValid
|
|
||||||
export const makePropSafe = templates.makePropSafe
|
|
||||||
export const getManifest = templates.getManifest
|
|
||||||
export const isJSBinding = templates.isJSBinding
|
|
||||||
export const encodeJSBinding = templates.encodeJSBinding
|
|
||||||
export const decodeJSBinding = templates.decodeJSBinding
|
|
||||||
export const processStringSync = templates.processStringSync
|
|
||||||
export const processObjectSync = templates.processObjectSync
|
|
||||||
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
|
|
||||||
export const findHBSBlocks = templates.findHBSBlocks
|
|
||||||
export const convertToJS = templates.convertToJS
|
|
||||||
export const setJSRunner = templates.setJSRunner
|
|
||||||
export const setOnErrorLog = templates.setOnErrorLog
|
|
||||||
export const FIND_ANY_HBS_REGEX = templates.FIND_ANY_HBS_REGEX
|
|
||||||
export const helpersToRemoveForJs = templates.helpersToRemoveForJs
|
|
||||||
|
|
||||||
export * from "./errors.js"
|
|
|
@ -1,24 +1,30 @@
|
||||||
const vm = require("vm")
|
import { Context, createContext, runInNewContext } from "vm"
|
||||||
const handlebars = require("handlebars")
|
import { create } from "handlebars"
|
||||||
const { registerAll, registerMinimum } = require("./helpers/index")
|
import { registerAll, registerMinimum } from "./helpers/index"
|
||||||
const processors = require("./processors")
|
import { preprocess, postprocess } from "./processors"
|
||||||
const { atob, btoa, isBackendService } = require("./utilities")
|
import {
|
||||||
const { iifeWrapper } = require("./iife")
|
atob,
|
||||||
const manifest = require("../manifest.json")
|
btoa,
|
||||||
const {
|
isBackendService,
|
||||||
FIND_HBS_REGEX,
|
FIND_HBS_REGEX,
|
||||||
FIND_ANY_HBS_REGEX,
|
FIND_ANY_HBS_REGEX,
|
||||||
findDoubleHbsInstances,
|
findDoubleHbsInstances,
|
||||||
} = require("./utilities")
|
} from "./utilities"
|
||||||
const { convertHBSBlock } = require("./conversion")
|
import { convertHBSBlock } from "./conversion"
|
||||||
const javascript = require("./helpers/javascript")
|
import { setJSRunner, removeJSRunner } from "./helpers/javascript"
|
||||||
const { helpersToRemoveForJs } = require("./helpers/list")
|
import { helpersToRemoveForJs } from "./helpers/list"
|
||||||
|
|
||||||
const hbsInstance = handlebars.create()
|
import manifest from "./manifest.json"
|
||||||
|
import { ProcessOptions } from "./types"
|
||||||
|
|
||||||
|
export { setJSRunner, setOnErrorLog } from "./helpers/javascript"
|
||||||
|
export { iifeWrapper } from "./iife"
|
||||||
|
|
||||||
|
const hbsInstance = create()
|
||||||
registerAll(hbsInstance)
|
registerAll(hbsInstance)
|
||||||
const hbsInstanceNoHelpers = handlebars.create()
|
const hbsInstanceNoHelpers = create()
|
||||||
registerMinimum(hbsInstanceNoHelpers)
|
registerMinimum(hbsInstanceNoHelpers)
|
||||||
const defaultOpts = {
|
const defaultOpts: ProcessOptions = {
|
||||||
noHelpers: false,
|
noHelpers: false,
|
||||||
cacheTemplates: false,
|
cacheTemplates: false,
|
||||||
noEscaping: false,
|
noEscaping: false,
|
||||||
|
@ -29,7 +35,7 @@ const defaultOpts = {
|
||||||
/**
|
/**
|
||||||
* Utility function to check if the object is valid.
|
* Utility function to check if the object is valid.
|
||||||
*/
|
*/
|
||||||
function testObject(object) {
|
function testObject(object: any) {
|
||||||
// JSON stringify will fail if there are any cycles, stops infinite recursion
|
// JSON stringify will fail if there are any cycles, stops infinite recursion
|
||||||
try {
|
try {
|
||||||
JSON.stringify(object)
|
JSON.stringify(object)
|
||||||
|
@ -41,8 +47,8 @@ function testObject(object) {
|
||||||
/**
|
/**
|
||||||
* Creates a HBS template function for a given string, and optionally caches it.
|
* Creates a HBS template function for a given string, and optionally caches it.
|
||||||
*/
|
*/
|
||||||
let templateCache = {}
|
const templateCache: Record<string, HandlebarsTemplateDelegate<any>> = {}
|
||||||
function createTemplate(string, opts) {
|
function createTemplate(string: string, opts?: ProcessOptions) {
|
||||||
opts = { ...defaultOpts, ...opts }
|
opts = { ...defaultOpts, ...opts }
|
||||||
|
|
||||||
// Finalising adds a helper, can't do this with no helpers
|
// Finalising adds a helper, can't do this with no helpers
|
||||||
|
@ -53,11 +59,11 @@ function createTemplate(string, opts) {
|
||||||
return templateCache[key]
|
return templateCache[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
string = processors.preprocess(string, opts)
|
string = preprocess(string, opts)
|
||||||
|
|
||||||
// Optionally disable built in HBS escaping
|
// Optionally disable built in HBS escaping
|
||||||
if (opts.noEscaping) {
|
if (opts.noEscaping) {
|
||||||
string = exports.disableEscaping(string)
|
string = disableEscaping(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This does not throw an error when template can't be fulfilled,
|
// This does not throw an error when template can't be fulfilled,
|
||||||
|
@ -78,24 +84,25 @@ function createTemplate(string, opts) {
|
||||||
* @param {object|undefined} [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.
|
* @returns {Promise<object|array>} The structure input, as fully updated as possible.
|
||||||
*/
|
*/
|
||||||
module.exports.processObject = async (object, context, opts) => {
|
export async function processObject<T extends Record<string, any>>(
|
||||||
|
object: T,
|
||||||
|
context: object,
|
||||||
|
opts?: { noHelpers?: boolean; escapeNewlines?: boolean; onlyFound?: boolean }
|
||||||
|
): Promise<T> {
|
||||||
testObject(object)
|
testObject(object)
|
||||||
for (let key of Object.keys(object || {})) {
|
|
||||||
|
for (const key of Object.keys(object || {})) {
|
||||||
if (object[key] != null) {
|
if (object[key] != null) {
|
||||||
let val = object[key]
|
const val = object[key]
|
||||||
|
let parsedValue
|
||||||
if (typeof val === "string") {
|
if (typeof val === "string") {
|
||||||
object[key] = await module.exports.processString(
|
parsedValue = await processString(object[key], context, opts)
|
||||||
object[key],
|
|
||||||
context,
|
|
||||||
opts
|
|
||||||
)
|
|
||||||
} else if (typeof val === "object") {
|
} else if (typeof val === "object") {
|
||||||
object[key] = await module.exports.processObject(
|
parsedValue = await processObject(object[key], context, opts)
|
||||||
object[key],
|
|
||||||
context,
|
|
||||||
opts
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
object[key] = parsedValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return object
|
return object
|
||||||
|
@ -109,9 +116,13 @@ module.exports.processObject = async (object, context, opts) => {
|
||||||
* @param {object|undefined} [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.
|
* @returns {Promise<string>} The enriched string, all templates should have been replaced if they can be.
|
||||||
*/
|
*/
|
||||||
module.exports.processString = async (string, context, opts) => {
|
export async function processString(
|
||||||
|
string: string,
|
||||||
|
context: object,
|
||||||
|
opts?: ProcessOptions
|
||||||
|
): Promise<string> {
|
||||||
// TODO: carry out any async calls before carrying out async call
|
// TODO: carry out any async calls before carrying out async call
|
||||||
return module.exports.processStringSync(string, context, opts)
|
return processStringSync(string, context, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,14 +134,18 @@ module.exports.processString = async (string, context, opts) => {
|
||||||
* @param {object|undefined} [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.
|
* @returns {object|array} The structure input, as fully updated as possible.
|
||||||
*/
|
*/
|
||||||
module.exports.processObjectSync = (object, context, opts) => {
|
export function processObjectSync(
|
||||||
|
object: { [x: string]: any },
|
||||||
|
context: any,
|
||||||
|
opts: any
|
||||||
|
): object | Array<any> {
|
||||||
testObject(object)
|
testObject(object)
|
||||||
for (let key of Object.keys(object || {})) {
|
for (let key of Object.keys(object || {})) {
|
||||||
let val = object[key]
|
let val = object[key]
|
||||||
if (typeof val === "string") {
|
if (typeof val === "string") {
|
||||||
object[key] = module.exports.processStringSync(object[key], context, opts)
|
object[key] = processStringSync(object[key], context, opts)
|
||||||
} else if (typeof val === "object") {
|
} else if (typeof val === "object") {
|
||||||
object[key] = module.exports.processObjectSync(object[key], context, opts)
|
object[key] = processObjectSync(object[key], context, opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return object
|
return object
|
||||||
|
@ -144,29 +159,32 @@ module.exports.processObjectSync = (object, context, opts) => {
|
||||||
* @param {object|undefined} [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.
|
* @returns {string} The enriched string, all templates should have been replaced if they can be.
|
||||||
*/
|
*/
|
||||||
module.exports.processStringSync = (string, context, opts) => {
|
export function processStringSync(
|
||||||
|
string: string,
|
||||||
|
context?: object,
|
||||||
|
opts?: ProcessOptions
|
||||||
|
): string {
|
||||||
// Take a copy of input in case of error
|
// Take a copy of input in case of error
|
||||||
const input = string
|
const input = string
|
||||||
if (typeof string !== "string") {
|
if (typeof string !== "string") {
|
||||||
throw "Cannot process non-string types."
|
throw "Cannot process non-string types."
|
||||||
}
|
}
|
||||||
function process(stringPart) {
|
function process(stringPart: string) {
|
||||||
const template = createTemplate(stringPart, opts)
|
const template = createTemplate(stringPart, opts)
|
||||||
const now = Math.floor(Date.now() / 1000) * 1000
|
const now = Math.floor(Date.now() / 1000) * 1000
|
||||||
return processors.postprocess(
|
const processedString = template({
|
||||||
template({
|
now: new Date(now).toISOString(),
|
||||||
now: new Date(now).toISOString(),
|
__opts: {
|
||||||
__opts: {
|
...opts,
|
||||||
...opts,
|
input: stringPart,
|
||||||
input: stringPart,
|
},
|
||||||
},
|
...context,
|
||||||
...context,
|
})
|
||||||
})
|
return postprocess(processedString)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (opts && opts.onlyFound) {
|
if (opts && opts.onlyFound) {
|
||||||
const blocks = exports.findHBSBlocks(string)
|
const blocks = findHBSBlocks(string)
|
||||||
for (let block of blocks) {
|
for (let block of blocks) {
|
||||||
const outcome = process(block)
|
const outcome = process(block)
|
||||||
string = string.replace(block, outcome)
|
string = string.replace(block, outcome)
|
||||||
|
@ -186,7 +204,7 @@ module.exports.processStringSync = (string, context, opts) => {
|
||||||
* this function will find any double braces and switch to triple.
|
* this function will find any double braces and switch to triple.
|
||||||
* @param string the string to have double HBS statements converted to triple.
|
* @param string the string to have double HBS statements converted to triple.
|
||||||
*/
|
*/
|
||||||
module.exports.disableEscaping = string => {
|
export function disableEscaping(string: string) {
|
||||||
const matches = findDoubleHbsInstances(string)
|
const matches = findDoubleHbsInstances(string)
|
||||||
if (matches == null) {
|
if (matches == null) {
|
||||||
return string
|
return string
|
||||||
|
@ -207,7 +225,7 @@ module.exports.disableEscaping = string => {
|
||||||
* @param {string} property The property which is to be wrapped.
|
* @param {string} property The property which is to be wrapped.
|
||||||
* @returns {string} The wrapped property ready to be added to a templating string.
|
* @returns {string} The wrapped property ready to be added to a templating string.
|
||||||
*/
|
*/
|
||||||
module.exports.makePropSafe = property => {
|
export function makePropSafe(property: any): string {
|
||||||
return `[${property}]`.replace("[[", "[").replace("]]", "]")
|
return `[${property}]`.replace("[[", "[").replace("]]", "]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +235,7 @@ module.exports.makePropSafe = property => {
|
||||||
* @param [opts] optional - specify some options for processing.
|
* @param [opts] optional - specify some options for processing.
|
||||||
* @returns {boolean} Whether or not the input string is valid.
|
* @returns {boolean} Whether or not the input string is valid.
|
||||||
*/
|
*/
|
||||||
module.exports.isValid = (string, opts) => {
|
export function isValid(string: any, opts?: any): boolean {
|
||||||
const validCases = [
|
const validCases = [
|
||||||
"string",
|
"string",
|
||||||
"number",
|
"number",
|
||||||
|
@ -238,7 +256,7 @@ module.exports.isValid = (string, opts) => {
|
||||||
})
|
})
|
||||||
template(context)
|
template(context)
|
||||||
return true
|
return true
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
const msg = err && err.message ? err.message : err
|
const msg = err && err.message ? err.message : err
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
return false
|
return false
|
||||||
|
@ -259,7 +277,7 @@ module.exports.isValid = (string, opts) => {
|
||||||
* This manifest provides information about each of the helpers and how it can be used.
|
* This manifest provides information about each of the helpers and how it can be used.
|
||||||
* @returns The manifest JSON which has been generated from the helpers.
|
* @returns The manifest JSON which has been generated from the helpers.
|
||||||
*/
|
*/
|
||||||
module.exports.getManifest = () => {
|
export function getManifest() {
|
||||||
return manifest
|
return manifest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,8 +286,8 @@ module.exports.getManifest = () => {
|
||||||
* @param handlebars the HBS expression to check
|
* @param handlebars the HBS expression to check
|
||||||
* @returns {boolean} whether the expression is JS or not
|
* @returns {boolean} whether the expression is JS or not
|
||||||
*/
|
*/
|
||||||
module.exports.isJSBinding = handlebars => {
|
export function isJSBinding(handlebars: any): boolean {
|
||||||
return module.exports.decodeJSBinding(handlebars) != null
|
return decodeJSBinding(handlebars) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -277,7 +295,7 @@ module.exports.isJSBinding = handlebars => {
|
||||||
* @param javascript the JS code to encode
|
* @param javascript the JS code to encode
|
||||||
* @returns {string} the JS HBS expression
|
* @returns {string} the JS HBS expression
|
||||||
*/
|
*/
|
||||||
module.exports.encodeJSBinding = javascript => {
|
export function encodeJSBinding(javascript: string): string {
|
||||||
return `{{ js "${btoa(javascript)}" }}`
|
return `{{ js "${btoa(javascript)}" }}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +304,7 @@ module.exports.encodeJSBinding = javascript => {
|
||||||
* @param handlebars the JS HBS expression
|
* @param handlebars the JS HBS expression
|
||||||
* @returns {string|null} the raw JS code
|
* @returns {string|null} the raw JS code
|
||||||
*/
|
*/
|
||||||
module.exports.decodeJSBinding = handlebars => {
|
export function decodeJSBinding(handlebars: string): string | null {
|
||||||
if (!handlebars || typeof handlebars !== "string") {
|
if (!handlebars || typeof handlebars !== "string") {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -311,7 +329,7 @@ module.exports.decodeJSBinding = handlebars => {
|
||||||
* @param {string[]} strings The strings to look for.
|
* @param {string[]} strings The strings to look for.
|
||||||
* @returns {boolean} Will return true if all strings found in HBS statement.
|
* @returns {boolean} Will return true if all strings found in HBS statement.
|
||||||
*/
|
*/
|
||||||
module.exports.doesContainStrings = (template, strings) => {
|
export function doesContainStrings(template: string, strings: any[]): boolean {
|
||||||
let regexp = new RegExp(FIND_HBS_REGEX)
|
let regexp = new RegExp(FIND_HBS_REGEX)
|
||||||
let matches = template.match(regexp)
|
let matches = template.match(regexp)
|
||||||
if (matches == null) {
|
if (matches == null) {
|
||||||
|
@ -319,8 +337,8 @@ module.exports.doesContainStrings = (template, strings) => {
|
||||||
}
|
}
|
||||||
for (let match of matches) {
|
for (let match of matches) {
|
||||||
let hbs = match
|
let hbs = match
|
||||||
if (exports.isJSBinding(match)) {
|
if (isJSBinding(match)) {
|
||||||
hbs = exports.decodeJSBinding(match)
|
hbs = decodeJSBinding(match)!
|
||||||
}
|
}
|
||||||
let allFound = true
|
let allFound = true
|
||||||
for (let string of strings) {
|
for (let string of strings) {
|
||||||
|
@ -341,7 +359,7 @@ module.exports.doesContainStrings = (template, strings) => {
|
||||||
* @param {string} string The string to search within.
|
* @param {string} string The string to search within.
|
||||||
* @return {string[]} The found HBS blocks.
|
* @return {string[]} The found HBS blocks.
|
||||||
*/
|
*/
|
||||||
module.exports.findHBSBlocks = string => {
|
export function findHBSBlocks(string: string): string[] {
|
||||||
if (!string || typeof string !== "string") {
|
if (!string || typeof string !== "string") {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
@ -362,18 +380,15 @@ module.exports.findHBSBlocks = string => {
|
||||||
* @param {string} string The word or sentence to search for.
|
* @param {string} string The word or sentence to search for.
|
||||||
* @returns {boolean} The this return true if the string is found, false if not.
|
* @returns {boolean} The this return true if the string is found, false if not.
|
||||||
*/
|
*/
|
||||||
module.exports.doesContainString = (template, string) => {
|
export function doesContainString(template: any, string: any): boolean {
|
||||||
return exports.doesContainStrings(template, [string])
|
return doesContainStrings(template, [string])
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.setJSRunner = javascript.setJSRunner
|
export function convertToJS(hbs: string) {
|
||||||
module.exports.setOnErrorLog = javascript.setOnErrorLog
|
const blocks = findHBSBlocks(hbs)
|
||||||
|
|
||||||
module.exports.convertToJS = hbs => {
|
|
||||||
const blocks = exports.findHBSBlocks(hbs)
|
|
||||||
let js = "return `",
|
let js = "return `",
|
||||||
prevBlock = null
|
prevBlock: string | null = null
|
||||||
const variables = {}
|
const variables: Record<string, any> = {}
|
||||||
if (blocks.length === 0) {
|
if (blocks.length === 0) {
|
||||||
js += hbs
|
js += hbs
|
||||||
}
|
}
|
||||||
|
@ -387,7 +402,7 @@ module.exports.convertToJS = hbs => {
|
||||||
prevBlock = block
|
prevBlock = block
|
||||||
const { variable, value } = convertHBSBlock(block, count++)
|
const { variable, value } = convertHBSBlock(block, count++)
|
||||||
variables[variable] = value
|
variables[variable] = value
|
||||||
js += `${stringPart.split()}\${${variable}}`
|
js += `${[stringPart]}\${${variable}}`
|
||||||
}
|
}
|
||||||
let varBlock = ""
|
let varBlock = ""
|
||||||
for (let [variable, value] of Object.entries(variables)) {
|
for (let [variable, value] of Object.entries(variables)) {
|
||||||
|
@ -397,34 +412,34 @@ module.exports.convertToJS = hbs => {
|
||||||
return `${varBlock}${js}`
|
return `${varBlock}${js}`
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.FIND_ANY_HBS_REGEX = FIND_ANY_HBS_REGEX
|
const _FIND_ANY_HBS_REGEX = FIND_ANY_HBS_REGEX
|
||||||
|
export { _FIND_ANY_HBS_REGEX as FIND_ANY_HBS_REGEX }
|
||||||
|
|
||||||
const errors = require("./errors")
|
export { JsErrorTimeout } from "./errors"
|
||||||
// We cannot use dynamic exports, otherwise the typescript file will not be generating it
|
|
||||||
module.exports.JsErrorTimeout = errors.JsErrorTimeout
|
|
||||||
|
|
||||||
module.exports.helpersToRemoveForJs = helpersToRemoveForJs
|
const _helpersToRemoveForJs = helpersToRemoveForJs
|
||||||
|
export { _helpersToRemoveForJs as helpersToRemoveForJs }
|
||||||
|
|
||||||
function defaultJSSetup() {
|
function defaultJSSetup() {
|
||||||
if (!isBackendService()) {
|
if (!isBackendService()) {
|
||||||
/**
|
/**
|
||||||
* Use polyfilled vm to run JS scripts in a browser Env
|
* Use polyfilled vm to run JS scripts in a browser Env
|
||||||
*/
|
*/
|
||||||
javascript.setJSRunner((js, context) => {
|
setJSRunner((js: string, context: Context) => {
|
||||||
context = {
|
context = {
|
||||||
...context,
|
...context,
|
||||||
alert: undefined,
|
alert: undefined,
|
||||||
setInterval: undefined,
|
setInterval: undefined,
|
||||||
setTimeout: undefined,
|
setTimeout: undefined,
|
||||||
}
|
}
|
||||||
vm.createContext(context)
|
createContext(context)
|
||||||
return vm.runInNewContext(js, context, { timeout: 1000 })
|
return runInNewContext(js, context, { timeout: 1000 })
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
javascript.removeJSRunner()
|
removeJSRunner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defaultJSSetup()
|
defaultJSSetup()
|
||||||
|
|
||||||
module.exports.defaultJSSetup = defaultJSSetup
|
const _defaultJSSetup = defaultJSSetup
|
||||||
module.exports.iifeWrapper = iifeWrapper
|
export { _defaultJSSetup as defaultJSSetup }
|
|
@ -1,8 +1,9 @@
|
||||||
const { FIND_HBS_REGEX } = require("../utilities")
|
import { FIND_HBS_REGEX } from "../utilities"
|
||||||
const preprocessor = require("./preprocessor")
|
import * as preprocessor from "./preprocessor"
|
||||||
const postprocessor = require("./postprocessor")
|
import * as postprocessor from "./postprocessor"
|
||||||
|
import { ProcessOptions } from "../types"
|
||||||
|
|
||||||
function process(output, processors, opts) {
|
function process(output: string, processors: any[], opts?: ProcessOptions) {
|
||||||
for (let processor of processors) {
|
for (let processor of processors) {
|
||||||
// if a literal statement has occurred stop
|
// if a literal statement has occurred stop
|
||||||
if (typeof output !== "string") {
|
if (typeof output !== "string") {
|
||||||
|
@ -21,7 +22,7 @@ function process(output, processors, opts) {
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.preprocess = (string, opts) => {
|
export function preprocess(string: string, opts: ProcessOptions) {
|
||||||
let processors = preprocessor.processors
|
let processors = preprocessor.processors
|
||||||
if (opts.noFinalise) {
|
if (opts.noFinalise) {
|
||||||
processors = processors.filter(
|
processors = processors.filter(
|
||||||
|
@ -30,7 +31,7 @@ module.exports.preprocess = (string, opts) => {
|
||||||
}
|
}
|
||||||
return process(string, processors, opts)
|
return process(string, processors, opts)
|
||||||
}
|
}
|
||||||
module.exports.postprocess = string => {
|
export function postprocess(string: string) {
|
||||||
let processors = postprocessor.processors
|
let processors = postprocessor.processors
|
||||||
return process(string, processors)
|
return process(string, processors)
|
||||||
}
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
const { LITERAL_MARKER } = require("../helpers/constants")
|
|
||||||
|
|
||||||
const PostProcessorNames = {
|
|
||||||
CONVERT_LITERALS: "convert-literals",
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
class Postprocessor {
|
|
||||||
constructor(name, fn) {
|
|
||||||
this.name = name
|
|
||||||
this.fn = fn
|
|
||||||
}
|
|
||||||
|
|
||||||
process(statement) {
|
|
||||||
return this.fn(statement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.PostProcessorNames = PostProcessorNames
|
|
||||||
|
|
||||||
module.exports.processors = [
|
|
||||||
new Postprocessor(PostProcessorNames.CONVERT_LITERALS, statement => {
|
|
||||||
if (typeof statement !== "string" || !statement.includes(LITERAL_MARKER)) {
|
|
||||||
return statement
|
|
||||||
}
|
|
||||||
const splitMarkerIndex = statement.indexOf("-")
|
|
||||||
const type = statement.substring(12, splitMarkerIndex)
|
|
||||||
const value = statement.substring(
|
|
||||||
splitMarkerIndex + 1,
|
|
||||||
statement.length - 2
|
|
||||||
)
|
|
||||||
switch (type) {
|
|
||||||
case "string":
|
|
||||||
return value
|
|
||||||
case "number":
|
|
||||||
return parseFloat(value)
|
|
||||||
case "boolean":
|
|
||||||
return value === "true"
|
|
||||||
case "object":
|
|
||||||
return JSON.parse(value)
|
|
||||||
case "js_result":
|
|
||||||
// We use the literal helper to process the result of JS expressions
|
|
||||||
// as we want to be able to return any types.
|
|
||||||
// We wrap the value in an abject to be able to use undefined properly.
|
|
||||||
return JSON.parse(value).data
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}),
|
|
||||||
]
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { LITERAL_MARKER } from "../helpers/constants"
|
||||||
|
|
||||||
|
export const PostProcessorNames = {
|
||||||
|
CONVERT_LITERALS: "convert-literals",
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
class Postprocessor {
|
||||||
|
name: string
|
||||||
|
private fn: any
|
||||||
|
|
||||||
|
constructor(name: string, fn: any) {
|
||||||
|
this.name = name
|
||||||
|
this.fn = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
process(statement: any) {
|
||||||
|
return this.fn(statement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const processors = [
|
||||||
|
new Postprocessor(
|
||||||
|
PostProcessorNames.CONVERT_LITERALS,
|
||||||
|
(statement: string) => {
|
||||||
|
if (
|
||||||
|
typeof statement !== "string" ||
|
||||||
|
!statement.includes(LITERAL_MARKER)
|
||||||
|
) {
|
||||||
|
return statement
|
||||||
|
}
|
||||||
|
const splitMarkerIndex = statement.indexOf("-")
|
||||||
|
const type = statement.substring(12, splitMarkerIndex)
|
||||||
|
const value = statement.substring(
|
||||||
|
splitMarkerIndex + 1,
|
||||||
|
statement.length - 2
|
||||||
|
)
|
||||||
|
switch (type) {
|
||||||
|
case "string":
|
||||||
|
return value
|
||||||
|
case "number":
|
||||||
|
return parseFloat(value)
|
||||||
|
case "boolean":
|
||||||
|
return value === "true"
|
||||||
|
case "object":
|
||||||
|
return JSON.parse(value)
|
||||||
|
case "js_result":
|
||||||
|
// We use the literal helper to process the result of JS expressions
|
||||||
|
// as we want to be able to return any types.
|
||||||
|
// We wrap the value in an abject to be able to use undefined properly.
|
||||||
|
return JSON.parse(value).data
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,78 +0,0 @@
|
||||||
const { HelperNames } = require("../helpers")
|
|
||||||
const { swapStrings, isAlphaNumeric } = require("../utilities")
|
|
||||||
|
|
||||||
const FUNCTION_CASES = ["#", "else", "/"]
|
|
||||||
|
|
||||||
const PreprocessorNames = {
|
|
||||||
SWAP_TO_DOT: "swap-to-dot-notation",
|
|
||||||
FIX_FUNCTIONS: "fix-functions",
|
|
||||||
FINALISE: "finalise",
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
class Preprocessor {
|
|
||||||
constructor(name, fn) {
|
|
||||||
this.name = name
|
|
||||||
this.fn = fn
|
|
||||||
}
|
|
||||||
|
|
||||||
process(fullString, statement, opts) {
|
|
||||||
const output = this.fn(statement, opts)
|
|
||||||
const idx = fullString.indexOf(statement)
|
|
||||||
return swapStrings(fullString, idx, statement.length, output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.processors = [
|
|
||||||
new Preprocessor(PreprocessorNames.SWAP_TO_DOT, statement => {
|
|
||||||
let startBraceIdx = statement.indexOf("[")
|
|
||||||
let lastIdx = 0
|
|
||||||
while (startBraceIdx !== -1) {
|
|
||||||
// if the character previous to the literal specifier is alphanumeric this should happen
|
|
||||||
if (isAlphaNumeric(statement.charAt(startBraceIdx - 1))) {
|
|
||||||
statement = swapStrings(statement, startBraceIdx + lastIdx, 1, ".[")
|
|
||||||
}
|
|
||||||
lastIdx = startBraceIdx + 1
|
|
||||||
const nextBraceIdx = statement.substring(lastIdx + 1).indexOf("[")
|
|
||||||
startBraceIdx = nextBraceIdx > 0 ? lastIdx + 1 + nextBraceIdx : -1
|
|
||||||
}
|
|
||||||
return statement
|
|
||||||
}),
|
|
||||||
|
|
||||||
new Preprocessor(PreprocessorNames.FIX_FUNCTIONS, statement => {
|
|
||||||
for (let specialCase of FUNCTION_CASES) {
|
|
||||||
const toFind = `{ ${specialCase}`,
|
|
||||||
replacement = `{${specialCase}`
|
|
||||||
statement = statement.replace(new RegExp(toFind, "g"), replacement)
|
|
||||||
}
|
|
||||||
return statement
|
|
||||||
}),
|
|
||||||
|
|
||||||
new Preprocessor(PreprocessorNames.FINALISE, (statement, opts) => {
|
|
||||||
const noHelpers = opts && opts.noHelpers
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
const possibleHelper = insideStatement.split(" ")[0]
|
|
||||||
// function helpers can't be wrapped
|
|
||||||
for (let specialCase of FUNCTION_CASES) {
|
|
||||||
if (possibleHelper.includes(specialCase)) {
|
|
||||||
return statement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const testHelper = possibleHelper.trim().toLowerCase()
|
|
||||||
if (
|
|
||||||
!noHelpers &&
|
|
||||||
HelperNames().some(option => testHelper === option.toLowerCase())
|
|
||||||
) {
|
|
||||||
insideStatement = `(${insideStatement})`
|
|
||||||
}
|
|
||||||
return `{{ all ${insideStatement} }}`
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
|
|
||||||
module.exports.PreprocessorNames = PreprocessorNames
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { HelperNames } from "../helpers"
|
||||||
|
import { swapStrings, isAlphaNumeric } from "../utilities"
|
||||||
|
|
||||||
|
const FUNCTION_CASES = ["#", "else", "/"]
|
||||||
|
|
||||||
|
export const PreprocessorNames = {
|
||||||
|
SWAP_TO_DOT: "swap-to-dot-notation",
|
||||||
|
FIX_FUNCTIONS: "fix-functions",
|
||||||
|
FINALISE: "finalise",
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
class Preprocessor {
|
||||||
|
name: string
|
||||||
|
private fn: any
|
||||||
|
|
||||||
|
constructor(name: string, fn: any) {
|
||||||
|
this.name = name
|
||||||
|
this.fn = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
process(fullString: string, statement: string, opts: Object) {
|
||||||
|
const output = this.fn(statement, opts)
|
||||||
|
const idx = fullString.indexOf(statement)
|
||||||
|
return swapStrings(fullString, idx, statement.length, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const processors = [
|
||||||
|
new Preprocessor(PreprocessorNames.SWAP_TO_DOT, (statement: string) => {
|
||||||
|
let startBraceIdx = statement.indexOf("[")
|
||||||
|
let lastIdx = 0
|
||||||
|
while (startBraceIdx !== -1) {
|
||||||
|
// if the character previous to the literal specifier is alphanumeric this should happen
|
||||||
|
if (isAlphaNumeric(statement.charAt(startBraceIdx - 1))) {
|
||||||
|
statement = swapStrings(statement, startBraceIdx + lastIdx, 1, ".[")
|
||||||
|
}
|
||||||
|
lastIdx = startBraceIdx + 1
|
||||||
|
const nextBraceIdx = statement.substring(lastIdx + 1).indexOf("[")
|
||||||
|
startBraceIdx = nextBraceIdx > 0 ? lastIdx + 1 + nextBraceIdx : -1
|
||||||
|
}
|
||||||
|
return statement
|
||||||
|
}),
|
||||||
|
|
||||||
|
new Preprocessor(PreprocessorNames.FIX_FUNCTIONS, (statement: string) => {
|
||||||
|
for (let specialCase of FUNCTION_CASES) {
|
||||||
|
const toFind = `{ ${specialCase}`,
|
||||||
|
replacement = `{${specialCase}`
|
||||||
|
statement = statement.replace(new RegExp(toFind, "g"), replacement)
|
||||||
|
}
|
||||||
|
return statement
|
||||||
|
}),
|
||||||
|
|
||||||
|
new Preprocessor(
|
||||||
|
PreprocessorNames.FINALISE,
|
||||||
|
(statement: string, opts: { noHelpers: any }) => {
|
||||||
|
const noHelpers = opts && opts.noHelpers
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
const possibleHelper = insideStatement.split(" ")[0]
|
||||||
|
// function helpers can't be wrapped
|
||||||
|
for (let specialCase of FUNCTION_CASES) {
|
||||||
|
if (possibleHelper.includes(specialCase)) {
|
||||||
|
return statement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const testHelper = possibleHelper.trim().toLowerCase()
|
||||||
|
if (
|
||||||
|
!noHelpers &&
|
||||||
|
HelperNames().some(option => testHelper === option.toLowerCase())
|
||||||
|
) {
|
||||||
|
insideStatement = `(${insideStatement})`
|
||||||
|
}
|
||||||
|
return `{{ all ${insideStatement} }}`
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,8 @@
|
||||||
|
export interface ProcessOptions {
|
||||||
|
cacheTemplates?: boolean
|
||||||
|
noEscaping?: boolean
|
||||||
|
noHelpers?: boolean
|
||||||
|
noFinalise?: boolean
|
||||||
|
escapeNewlines?: boolean
|
||||||
|
onlyFound?: boolean
|
||||||
|
}
|
|
@ -1,28 +1,28 @@
|
||||||
const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g
|
const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g
|
||||||
|
|
||||||
module.exports.FIND_HBS_REGEX = /{{([^{].*?)}}/g
|
export const FIND_HBS_REGEX = /{{([^{].*?)}}/g
|
||||||
module.exports.FIND_ANY_HBS_REGEX = /{?{{([^{].*?)}}}?/g
|
export const FIND_ANY_HBS_REGEX = /{?{{([^{].*?)}}}?/g
|
||||||
module.exports.FIND_TRIPLE_HBS_REGEX = /{{{([^{].*?)}}}/g
|
export const FIND_TRIPLE_HBS_REGEX = /{{{([^{].*?)}}}/g
|
||||||
|
|
||||||
module.exports.isBackendService = () => {
|
export const isBackendService = () => {
|
||||||
return typeof window === "undefined"
|
return typeof window === "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.isJSAllowed = () => {
|
export const isJSAllowed = () => {
|
||||||
return process && !process.env.NO_JS
|
return process && !process.env.NO_JS
|
||||||
}
|
}
|
||||||
|
|
||||||
// originally this could be done with a single regex using look behinds
|
// originally this could be done with a single regex using look behinds
|
||||||
// but safari does not support this feature
|
// but safari does not support this feature
|
||||||
// original regex: /(?<!{){{[^{}]+}}(?!})/g
|
// original regex: /(?<!{){{[^{}]+}}(?!})/g
|
||||||
module.exports.findDoubleHbsInstances = string => {
|
export const findDoubleHbsInstances = (string: string): string[] => {
|
||||||
let copied = string
|
let copied = string
|
||||||
const doubleRegex = new RegExp(exports.FIND_HBS_REGEX)
|
const doubleRegex = new RegExp(FIND_HBS_REGEX)
|
||||||
const regex = new RegExp(exports.FIND_TRIPLE_HBS_REGEX)
|
const regex = new RegExp(FIND_TRIPLE_HBS_REGEX)
|
||||||
const tripleMatches = copied.match(regex)
|
const tripleMatches = copied.match(regex)
|
||||||
// remove triple braces
|
// remove triple braces
|
||||||
if (tripleMatches) {
|
if (tripleMatches) {
|
||||||
tripleMatches.forEach(match => {
|
tripleMatches.forEach((match: string) => {
|
||||||
copied = copied.replace(match, "")
|
copied = copied.replace(match, "")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -30,34 +30,39 @@ module.exports.findDoubleHbsInstances = string => {
|
||||||
return doubleMatches ? doubleMatches : []
|
return doubleMatches ? doubleMatches : []
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.isAlphaNumeric = char => {
|
export const isAlphaNumeric = (char: string) => {
|
||||||
return char.match(ALPHA_NUMERIC_REGEX)
|
return char.match(ALPHA_NUMERIC_REGEX)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.swapStrings = (string, start, length, swap) => {
|
export const swapStrings = (
|
||||||
|
string: string,
|
||||||
|
start: number,
|
||||||
|
length: number,
|
||||||
|
swap: string
|
||||||
|
) => {
|
||||||
return string.slice(0, start) + swap + string.slice(start + length)
|
return string.slice(0, start) + swap + string.slice(start + length)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.removeHandlebarsStatements = (
|
export const removeHandlebarsStatements = (
|
||||||
string,
|
string: string,
|
||||||
replacement = "Invalid binding"
|
replacement = "Invalid binding"
|
||||||
) => {
|
) => {
|
||||||
let regexp = new RegExp(exports.FIND_HBS_REGEX)
|
let regexp = new RegExp(FIND_HBS_REGEX)
|
||||||
let matches = string.match(regexp)
|
let matches = string.match(regexp)
|
||||||
if (matches == null) {
|
if (matches == null) {
|
||||||
return string
|
return string
|
||||||
}
|
}
|
||||||
for (let match of matches) {
|
for (let match of matches) {
|
||||||
const idx = string.indexOf(match)
|
const idx = string.indexOf(match)
|
||||||
string = exports.swapStrings(string, idx, match.length, replacement)
|
string = swapStrings(string, idx, match.length, replacement)
|
||||||
}
|
}
|
||||||
return string
|
return string
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.btoa = plainText => {
|
export const btoa = (plainText: string) => {
|
||||||
return Buffer.from(plainText, "utf-8").toString("base64")
|
return Buffer.from(plainText, "utf-8").toString("base64")
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.atob = base64 => {
|
export const atob = (base64: string) => {
|
||||||
return Buffer.from(base64, "base64").toString("utf-8")
|
return Buffer.from(base64, "base64").toString("utf-8")
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
const {
|
import {
|
||||||
processObject,
|
processObject,
|
||||||
processString,
|
processString,
|
||||||
isValid,
|
isValid,
|
||||||
|
@ -8,7 +8,7 @@ const {
|
||||||
doesContainString,
|
doesContainString,
|
||||||
disableEscaping,
|
disableEscaping,
|
||||||
findHBSBlocks,
|
findHBSBlocks,
|
||||||
} = require("../src/index.js")
|
} from "../src/index"
|
||||||
|
|
||||||
describe("Test that the string processing works correctly", () => {
|
describe("Test that the string processing works correctly", () => {
|
||||||
it("should process a basic template string", async () => {
|
it("should process a basic template string", async () => {
|
||||||
|
@ -28,7 +28,7 @@ describe("Test that the string processing works correctly", () => {
|
||||||
it("should fail gracefully when wrong type passed in", async () => {
|
it("should fail gracefully when wrong type passed in", async () => {
|
||||||
let error = null
|
let error = null
|
||||||
try {
|
try {
|
||||||
await processString(null, null)
|
await processString(null as any, null as any)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err
|
error = err
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ describe("Test that the object processing works correctly", () => {
|
||||||
it("should fail gracefully when object passed in has cycles", async () => {
|
it("should fail gracefully when object passed in has cycles", async () => {
|
||||||
let error = null
|
let error = null
|
||||||
try {
|
try {
|
||||||
const innerObj = { a: "thing {{ a }}" }
|
const innerObj: any = { a: "thing {{ a }}" }
|
||||||
innerObj.b = innerObj
|
innerObj.b = innerObj
|
||||||
await processObject(innerObj, { a: 1 })
|
await processObject(innerObj, { a: 1 })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -98,7 +98,7 @@ describe("Test that the object processing works correctly", () => {
|
||||||
it("should be able to handle null objects", async () => {
|
it("should be able to handle null objects", async () => {
|
||||||
let error = null
|
let error = null
|
||||||
try {
|
try {
|
||||||
await processObject(null, null)
|
await processObject(null as any, null as any)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err
|
error = err
|
||||||
}
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
module.exports.UUID_REGEX =
|
export const UUID_REGEX =
|
||||||
/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
|
/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
|
|
@ -1,4 +1,4 @@
|
||||||
const { processString } = require("../src/index.js")
|
import { processString } from "../src/index"
|
||||||
|
|
||||||
describe("Handling context properties with spaces in their name", () => {
|
describe("Handling context properties with spaces in their name", () => {
|
||||||
it("should allow through literal specifiers", async () => {
|
it("should allow through literal specifiers", async () => {
|
|
@ -1,6 +1,6 @@
|
||||||
const { convertToJS } = require("../src/index.js")
|
import { convertToJS } from "../src/index"
|
||||||
|
|
||||||
function checkLines(response, lines) {
|
function checkLines(response: string, lines: string[]) {
|
||||||
const toCheck = response.split("\n")
|
const toCheck = response.split("\n")
|
||||||
let count = 0
|
let count = 0
|
||||||
for (let line of lines) {
|
for (let line of lines) {
|
|
@ -1,7 +1,7 @@
|
||||||
const { processString, processObject, isValid } = require("../src/index.js")
|
import { processString, processObject, isValid } from "../src/index"
|
||||||
const tableJson = require("./examples/table.json")
|
import tableJson from "./examples/table.json"
|
||||||
const dayjs = require("dayjs")
|
import dayjs from "dayjs"
|
||||||
const { UUID_REGEX } = require("./constants")
|
import { UUID_REGEX } from "./constants"
|
||||||
|
|
||||||
describe("test the custom helpers we have applied", () => {
|
describe("test the custom helpers we have applied", () => {
|
||||||
it("should be able to use the object helper", async () => {
|
it("should be able to use the object helper", async () => {
|
||||||
|
@ -188,9 +188,7 @@ describe("test the date helpers", () => {
|
||||||
time: date.toUTCString(),
|
time: date.toUTCString(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const formatted = new dayjs(date)
|
const formatted = dayjs(date).tz("America/New_York").format("HH-mm-ss Z")
|
||||||
.tz("America/New_York")
|
|
||||||
.format("HH-mm-ss Z")
|
|
||||||
expect(output).toBe(formatted)
|
expect(output).toBe(formatted)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -200,7 +198,7 @@ describe("test the date helpers", () => {
|
||||||
time: date.toUTCString(),
|
time: date.toUTCString(),
|
||||||
})
|
})
|
||||||
const timezone = dayjs.tz.guess()
|
const timezone = dayjs.tz.guess()
|
||||||
const offset = new dayjs(date).tz(timezone).format("Z")
|
const offset = dayjs(date).tz(timezone).format("Z")
|
||||||
expect(output).toBe(offset)
|
expect(output).toBe(offset)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -273,7 +271,7 @@ describe("test the string helpers", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("test the comparison helpers", () => {
|
describe("test the comparison helpers", () => {
|
||||||
async function compare(func, a, b) {
|
async function compare(func: string, a: any, b: any) {
|
||||||
const output = await processString(
|
const output = await processString(
|
||||||
`{{ #${func} a b }}Success{{ else }}Fail{{ /${func} }}`,
|
`{{ #${func} a b }}Success{{ else }}Fail{{ /${func} }}`,
|
||||||
{
|
{
|
||||||
|
@ -344,14 +342,14 @@ describe("Test the literal helper", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should allow use of the literal specifier for an object", async () => {
|
it("should allow use of the literal specifier for an object", async () => {
|
||||||
const output = await processString(`{{literal a}}`, {
|
const output: any = await processString(`{{literal a}}`, {
|
||||||
a: { b: 1 },
|
a: { b: 1 },
|
||||||
})
|
})
|
||||||
expect(output.b).toBe(1)
|
expect(output.b).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should allow use of the literal specifier for an object with dashes", async () => {
|
it("should allow use of the literal specifier for an object with dashes", async () => {
|
||||||
const output = await processString(`{{literal a}}`, {
|
const output: any = await processString(`{{literal a}}`, {
|
||||||
a: { b: "i-have-dashes" },
|
a: { b: "i-have-dashes" },
|
||||||
})
|
})
|
||||||
expect(output.b).toBe("i-have-dashes")
|
expect(output.b).toBe("i-have-dashes")
|
|
@ -1,13 +1,9 @@
|
||||||
const vm = require("vm")
|
import vm from "vm"
|
||||||
|
|
||||||
const {
|
import { processStringSync, encodeJSBinding, setJSRunner } from "../src/index"
|
||||||
processStringSync,
|
import { UUID_REGEX } from "./constants"
|
||||||
encodeJSBinding,
|
|
||||||
setJSRunner,
|
|
||||||
} = require("../src/index.js")
|
|
||||||
const { UUID_REGEX } = require("./constants")
|
|
||||||
|
|
||||||
const processJS = (js, context) => {
|
const processJS = (js: string, context?: object): any => {
|
||||||
return processStringSync(encodeJSBinding(js), context)
|
return processStringSync(encodeJSBinding(js), context)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const vm = require("vm")
|
import vm from "vm"
|
||||||
|
|
||||||
jest.mock("@budibase/handlebars-helpers/lib/math", () => {
|
jest.mock("@budibase/handlebars-helpers/lib/math", () => {
|
||||||
const actual = jest.requireActual("@budibase/handlebars-helpers/lib/math")
|
const actual = jest.requireActual("@budibase/handlebars-helpers/lib/math")
|
||||||
|
@ -17,14 +17,14 @@ jest.mock("@budibase/handlebars-helpers/lib/uuid", () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const { processString, setJSRunner } = require("../src/index.js")
|
import { processString, setJSRunner } from "../src/index"
|
||||||
|
|
||||||
const tk = require("timekeeper")
|
import tk from "timekeeper"
|
||||||
const { getParsedManifest, runJsHelpersTests } = require("./utils")
|
import { getParsedManifest, runJsHelpersTests } from "./utils"
|
||||||
|
|
||||||
tk.freeze("2021-01-21T12:00:00")
|
tk.freeze("2021-01-21T12:00:00")
|
||||||
|
|
||||||
function escapeRegExp(string) {
|
function escapeRegExp(string: string) {
|
||||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,9 +40,9 @@ describe("manifest", () => {
|
||||||
describe("examples are valid", () => {
|
describe("examples are valid", () => {
|
||||||
describe.each(Object.keys(manifest))("%s", collection => {
|
describe.each(Object.keys(manifest))("%s", collection => {
|
||||||
it.each(manifest[collection])("%s", async (_, { hbs, js }) => {
|
it.each(manifest[collection])("%s", async (_, { hbs, js }) => {
|
||||||
const context = {
|
const context: any = {
|
||||||
double: i => i * 2,
|
double: (i: number) => i * 2,
|
||||||
isString: x => typeof x === "string",
|
isString: (x: any) => typeof x === "string",
|
||||||
}
|
}
|
||||||
|
|
||||||
const arrays = hbs.match(/\[[^/\]]+\]/)
|
const arrays = hbs.match(/\[[^/\]]+\]/)
|
|
@ -1,4 +1,4 @@
|
||||||
const { processString } = require("../src/index.js")
|
import { processString } from "../src/index"
|
||||||
|
|
||||||
describe("specific test case for whether or not full app template can still be rendered", () => {
|
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 () => {
|
it("should be able to render the app template", async () => {
|
|
@ -1,13 +1,9 @@
|
||||||
const { getManifest } = require("../src")
|
import { getManifest } from "../src"
|
||||||
const { getJsHelperList } = require("../src/helpers")
|
import { getJsHelperList } from "../src/helpers"
|
||||||
|
|
||||||
const {
|
import { convertToJS, processStringSync, encodeJSBinding } from "../src/index"
|
||||||
convertToJS,
|
|
||||||
processStringSync,
|
|
||||||
encodeJSBinding,
|
|
||||||
} = require("../src/index.js")
|
|
||||||
|
|
||||||
function tryParseJson(str) {
|
function tryParseJson(str: string) {
|
||||||
if (typeof str !== "string") {
|
if (typeof str !== "string") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -19,23 +15,35 @@ function tryParseJson(str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getParsedManifest = () => {
|
type ExampleType = [
|
||||||
const manifest = getManifest()
|
string,
|
||||||
|
{
|
||||||
|
hbs: string
|
||||||
|
js: string
|
||||||
|
requiresHbsBody: boolean
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const getParsedManifest = () => {
|
||||||
|
const manifest: any = getManifest()
|
||||||
const collections = Object.keys(manifest)
|
const collections = Object.keys(manifest)
|
||||||
|
|
||||||
const examples = collections.reduce((acc, collection) => {
|
const examples = collections.reduce((acc, collection) => {
|
||||||
const functions = Object.entries(manifest[collection])
|
const functions = Object.entries<{
|
||||||
.filter(([_, details]) => details.example)
|
example: string
|
||||||
.map(([name, details]) => {
|
requiresBlock: boolean
|
||||||
|
}>(manifest[collection])
|
||||||
|
.filter(
|
||||||
|
([_, details]) =>
|
||||||
|
details.example?.split("->").map(x => x.trim()).length > 1
|
||||||
|
)
|
||||||
|
.map(([name, details]): ExampleType => {
|
||||||
const example = details.example
|
const example = details.example
|
||||||
let [hbs, js] = example.split("->").map(x => x.trim())
|
let [hbs, js] = example.split("->").map(x => x.trim())
|
||||||
if (!js) {
|
|
||||||
// The function has no return value
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trim 's
|
// Trim 's
|
||||||
js = js.replace(/^'|'$/g, "")
|
js = js.replace(/^'|'$/g, "")
|
||||||
let parsedExpected
|
let parsedExpected: string
|
||||||
if ((parsedExpected = tryParseJson(js))) {
|
if ((parsedExpected = tryParseJson(js))) {
|
||||||
if (Array.isArray(parsedExpected)) {
|
if (Array.isArray(parsedExpected)) {
|
||||||
if (typeof parsedExpected[0] === "object") {
|
if (typeof parsedExpected[0] === "object") {
|
||||||
|
@ -48,36 +56,40 @@ const getParsedManifest = () => {
|
||||||
const requiresHbsBody = details.requiresBlock
|
const requiresHbsBody = details.requiresBlock
|
||||||
return [name, { hbs, js, requiresHbsBody }]
|
return [name, { hbs, js, requiresHbsBody }]
|
||||||
})
|
})
|
||||||
.filter(x => !!x)
|
|
||||||
|
|
||||||
if (Object.keys(functions).length) {
|
if (functions.length) {
|
||||||
acc[collection] = functions
|
acc[collection] = functions
|
||||||
}
|
}
|
||||||
return acc
|
return acc
|
||||||
}, {})
|
}, {} as Record<string, ExampleType[]>)
|
||||||
|
|
||||||
return examples
|
return examples
|
||||||
}
|
}
|
||||||
module.exports.getParsedManifest = getParsedManifest
|
|
||||||
|
|
||||||
module.exports.runJsHelpersTests = ({ funcWrap, testsToSkip } = {}) => {
|
export const runJsHelpersTests = ({
|
||||||
funcWrap = funcWrap || (delegate => delegate())
|
funcWrap,
|
||||||
|
testsToSkip,
|
||||||
|
}: {
|
||||||
|
funcWrap?: any
|
||||||
|
testsToSkip?: any
|
||||||
|
} = {}) => {
|
||||||
|
funcWrap = funcWrap || ((delegate: () => any) => delegate())
|
||||||
const manifest = getParsedManifest()
|
const manifest = getParsedManifest()
|
||||||
|
|
||||||
const processJS = (js, context) => {
|
const processJS = (js: string, context: object | undefined) => {
|
||||||
return funcWrap(() => processStringSync(encodeJSBinding(js), context))
|
return funcWrap(() => processStringSync(encodeJSBinding(js), context))
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeRegExp(string) {
|
function escapeRegExp(string: string) {
|
||||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("can be parsed and run as js", () => {
|
describe("can be parsed and run as js", () => {
|
||||||
const jsHelpers = getJsHelperList()
|
const jsHelpers = getJsHelperList()!
|
||||||
const jsExamples = Object.keys(manifest).reduce((acc, v) => {
|
const jsExamples = Object.keys(manifest).reduce((acc, v) => {
|
||||||
acc[v] = manifest[v].filter(([key]) => jsHelpers[key])
|
acc[v] = manifest[v].filter(([key]) => jsHelpers[key])
|
||||||
return acc
|
return acc
|
||||||
}, {})
|
}, {} as typeof manifest)
|
||||||
|
|
||||||
describe.each(Object.keys(jsExamples))("%s", collection => {
|
describe.each(Object.keys(jsExamples))("%s", collection => {
|
||||||
const examplesToRun = jsExamples[collection]
|
const examplesToRun = jsExamples[collection]
|
||||||
|
@ -86,9 +98,9 @@ module.exports.runJsHelpersTests = ({ funcWrap, testsToSkip } = {}) => {
|
||||||
|
|
||||||
examplesToRun.length &&
|
examplesToRun.length &&
|
||||||
it.each(examplesToRun)("%s", async (_, { hbs, js }) => {
|
it.each(examplesToRun)("%s", async (_, { hbs, js }) => {
|
||||||
const context = {
|
const context: any = {
|
||||||
double: i => i * 2,
|
double: (i: number) => i * 2,
|
||||||
isString: x => typeof x === "string",
|
isString: (x: any) => typeof x === "string",
|
||||||
}
|
}
|
||||||
|
|
||||||
const arrays = hbs.match(/\[[^/\]]+\]/)
|
const arrays = hbs.match(/\[[^/\]]+\]/)
|
|
@ -5,8 +5,10 @@ jest.mock("../src/utilities", () => {
|
||||||
isBackendService: jest.fn().mockReturnValue(true),
|
isBackendService: jest.fn().mockReturnValue(true),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const { defaultJSSetup, processStringSync, encodeJSBinding } = require("../src")
|
|
||||||
const { isBackendService } = require("../src/utilities")
|
import { defaultJSSetup, processStringSync, encodeJSBinding } from "../src"
|
||||||
|
import { isBackendService } from "../src/utilities"
|
||||||
|
|
||||||
const mockedBackendService = jest.mocked(isBackendService)
|
const mockedBackendService = jest.mocked(isBackendService)
|
||||||
|
|
||||||
const binding = encodeJSBinding("return 1")
|
const binding = encodeJSBinding("return 1")
|
|
@ -1,11 +1,15 @@
|
||||||
{
|
{
|
||||||
"include": ["src/**/*"],
|
"include": ["src/**/*"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowJs": true,
|
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"emitDeclarationOnly": true,
|
"target": "es6",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"incremental": true,
|
||||||
|
"lib": ["dom"],
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"types": ["node", "jest"]
|
"types": ["node", "jest"],
|
||||||
|
"resolveJsonModule": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,17 +16,11 @@ COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.
|
||||||
RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /string-templates
|
|
||||||
COPY packages/string-templates/package.json package.json
|
|
||||||
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
|
||||||
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000
|
|
||||||
COPY packages/string-templates .
|
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY packages/worker/package.json .
|
COPY packages/worker/package.json .
|
||||||
COPY packages/worker/dist/yarn.lock .
|
COPY packages/worker/dist/yarn.lock .
|
||||||
RUN cd ../string-templates && yarn link && cd - && yarn link @budibase/string-templates
|
|
||||||
|
|
||||||
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ const config: Config.InitialOptions = {
|
||||||
"@budibase/backend-core": "<rootDir>/../backend-core/src",
|
"@budibase/backend-core": "<rootDir>/../backend-core/src",
|
||||||
"@budibase/types": "<rootDir>/../types/src",
|
"@budibase/types": "<rootDir>/../types/src",
|
||||||
"@budibase/shared-core": ["<rootDir>/../shared-core/src"],
|
"@budibase/shared-core": ["<rootDir>/../shared-core/src"],
|
||||||
|
"@budibase/string-templates": ["<rootDir>/../string-templates/src"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
"@budibase/backend-core": ["../backend-core/src"],
|
"@budibase/backend-core": ["../backend-core/src"],
|
||||||
"@budibase/backend-core/*": ["../backend-core/*"],
|
"@budibase/backend-core/*": ["../backend-core/*"],
|
||||||
"@budibase/shared-core": ["../shared-core/src"],
|
"@budibase/shared-core": ["../shared-core/src"],
|
||||||
"@budibase/pro": ["../pro/src"]
|
"@budibase/pro": ["../pro/src"],
|
||||||
|
"@budibase/string-templates": ["../string-templates/src"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"],
|
"include": ["src/**/*"],
|
||||||
|
|
48
yarn.lock
48
yarn.lock
|
@ -1988,7 +1988,7 @@
|
||||||
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
|
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
|
||||||
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
||||||
|
|
||||||
"@babel/runtime@^7.10.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.21.0":
|
"@babel/runtime@^7.10.5", "@babel/runtime@^7.13.10":
|
||||||
version "7.23.9"
|
version "7.23.9"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7"
|
||||||
integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==
|
integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==
|
||||||
|
@ -8467,21 +8467,6 @@ concat-with-sourcemaps@^1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
concurrently@^8.2.2:
|
|
||||||
version "8.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.2.tgz#353141985c198cfa5e4a3ef90082c336b5851784"
|
|
||||||
integrity sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==
|
|
||||||
dependencies:
|
|
||||||
chalk "^4.1.2"
|
|
||||||
date-fns "^2.30.0"
|
|
||||||
lodash "^4.17.21"
|
|
||||||
rxjs "^7.8.1"
|
|
||||||
shell-quote "^1.8.1"
|
|
||||||
spawn-command "0.0.2"
|
|
||||||
supports-color "^8.1.1"
|
|
||||||
tree-kill "^1.2.2"
|
|
||||||
yargs "^17.7.2"
|
|
||||||
|
|
||||||
condense-newlines@^0.2.1:
|
condense-newlines@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f"
|
resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f"
|
||||||
|
@ -9049,13 +9034,6 @@ data-urls@^4.0.0:
|
||||||
whatwg-mimetype "^3.0.0"
|
whatwg-mimetype "^3.0.0"
|
||||||
whatwg-url "^12.0.0"
|
whatwg-url "^12.0.0"
|
||||||
|
|
||||||
date-fns@^2.30.0:
|
|
||||||
version "2.30.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
|
|
||||||
integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.21.0"
|
|
||||||
|
|
||||||
dateformat@^3.0.3:
|
dateformat@^3.0.3:
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||||
|
@ -19400,13 +19378,6 @@ rxjs@^7.5.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
rxjs@^7.8.1:
|
|
||||||
version "7.8.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
|
|
||||||
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
|
|
||||||
dependencies:
|
|
||||||
tslib "^2.1.0"
|
|
||||||
|
|
||||||
safe-array-concat@^1.0.1:
|
safe-array-concat@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c"
|
resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c"
|
||||||
|
@ -19682,11 +19653,6 @@ shell-exec@1.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/shell-exec/-/shell-exec-1.0.2.tgz#2e9361b0fde1d73f476c4b6671fa17785f696756"
|
resolved "https://registry.yarnpkg.com/shell-exec/-/shell-exec-1.0.2.tgz#2e9361b0fde1d73f476c4b6671fa17785f696756"
|
||||||
integrity sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==
|
integrity sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==
|
||||||
|
|
||||||
shell-quote@^1.8.1:
|
|
||||||
version "1.8.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
|
|
||||||
integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
|
|
||||||
|
|
||||||
shortid@2.2.15:
|
shortid@2.2.15:
|
||||||
version "2.2.15"
|
version "2.2.15"
|
||||||
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
|
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
|
||||||
|
@ -20005,11 +19971,6 @@ sparse-bitfield@^3.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
memory-pager "^1.0.2"
|
memory-pager "^1.0.2"
|
||||||
|
|
||||||
spawn-command@0.0.2:
|
|
||||||
version "0.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e"
|
|
||||||
integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==
|
|
||||||
|
|
||||||
spdx-correct@^3.0.0:
|
spdx-correct@^3.0.0:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
|
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
|
||||||
|
@ -20582,7 +20543,7 @@ supports-color@^7.0.0, supports-color@^7.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
supports-color@^8.0.0, supports-color@^8.1.1:
|
supports-color@^8.0.0:
|
||||||
version "8.1.1"
|
version "8.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
|
||||||
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
|
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
|
||||||
|
@ -21209,11 +21170,6 @@ tr46@~0.0.3:
|
||||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||||
|
|
||||||
tree-kill@^1.2.2:
|
|
||||||
version "1.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
|
|
||||||
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
|
|
||||||
|
|
||||||
trim-newlines@^3.0.0:
|
trim-newlines@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
|
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
|
||||||
|
|
Loading…
Reference in New Issue