@budibase/string-templates 3.2.5 → 3.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.mjs +1 -1
- package/dist/iife.mjs +1 -0
- package/package.json +4 -8
- package/src/conversion/index.ts +0 -131
- package/src/errors.ts +0 -20
- package/src/helpers/Helper.ts +0 -36
- package/src/helpers/constants.ts +0 -41
- package/src/helpers/date.ts +0 -133
- package/src/helpers/external.ts +0 -57
- package/src/helpers/index.ts +0 -103
- package/src/helpers/javascript.ts +0 -168
- package/src/helpers/list.ts +0 -72
- package/src/iife.ts +0 -3
- package/src/index.ts +0 -495
- package/src/manifest.json +0 -1364
- package/src/processors/index.ts +0 -37
- package/src/processors/postprocessor.ts +0 -57
- package/src/processors/preprocessor.ts +0 -90
- package/src/types.ts +0 -10
- package/src/utilities.ts +0 -88
@@ -1,168 +0,0 @@
|
|
1
|
-
import { atob, isBackendService, isJSAllowed } from "../utilities"
|
2
|
-
import { LITERAL_MARKER } from "../helpers/constants"
|
3
|
-
import { getJsHelperList } from "./list"
|
4
|
-
import { iifeWrapper } from "../iife"
|
5
|
-
import { JsTimeoutError, UserScriptError } from "../errors"
|
6
|
-
import { cloneDeep } from "lodash/fp"
|
7
|
-
|
8
|
-
// The method of executing JS scripts depends on the bundle being built.
|
9
|
-
// This setter is used in the entrypoint (either index.js or index.mjs).
|
10
|
-
let runJS: ((js: string, context: Record<string, any>) => any) | undefined =
|
11
|
-
undefined
|
12
|
-
export const setJSRunner = (runner: typeof runJS) => (runJS = runner)
|
13
|
-
|
14
|
-
export const removeJSRunner = () => {
|
15
|
-
runJS = undefined
|
16
|
-
}
|
17
|
-
|
18
|
-
let onErrorLog: (message: Error) => void
|
19
|
-
export const setOnErrorLog = (delegate: typeof onErrorLog) =>
|
20
|
-
(onErrorLog = delegate)
|
21
|
-
|
22
|
-
// Helper utility to strip square brackets from a value
|
23
|
-
const removeSquareBrackets = (value: string) => {
|
24
|
-
if (!value || typeof value !== "string") {
|
25
|
-
return value
|
26
|
-
}
|
27
|
-
const regex = /\[+(.+)]+/
|
28
|
-
const matches = value.match(regex)
|
29
|
-
if (matches && matches[1]) {
|
30
|
-
return matches[1]
|
31
|
-
}
|
32
|
-
return value
|
33
|
-
}
|
34
|
-
|
35
|
-
const isReservedKey = (key: string) =>
|
36
|
-
key === "snippets" ||
|
37
|
-
key === "helpers" ||
|
38
|
-
key.startsWith("snippets.") ||
|
39
|
-
key.startsWith("helpers.")
|
40
|
-
|
41
|
-
// Our context getter function provided to JS code as $.
|
42
|
-
// Extracts a value from context.
|
43
|
-
const getContextValue = (path: string, context: any) => {
|
44
|
-
// We populate `snippets` ourselves, don't allow access to it.
|
45
|
-
if (isReservedKey(path)) {
|
46
|
-
return undefined
|
47
|
-
}
|
48
|
-
const literalStringRegex = /^(["'`]).*\1$/
|
49
|
-
let data = context
|
50
|
-
// check if it's a literal string - just return path if its quoted
|
51
|
-
if (literalStringRegex.test(path)) {
|
52
|
-
return path.substring(1, path.length - 1)
|
53
|
-
}
|
54
|
-
path.split(".").forEach(key => {
|
55
|
-
if (data == null || typeof data !== "object") {
|
56
|
-
return null
|
57
|
-
}
|
58
|
-
data = data[removeSquareBrackets(key)]
|
59
|
-
})
|
60
|
-
|
61
|
-
return data
|
62
|
-
}
|
63
|
-
|
64
|
-
// Evaluates JS code against a certain context
|
65
|
-
export function processJS(handlebars: string, context: any) {
|
66
|
-
if (!isJSAllowed() || !runJS) {
|
67
|
-
throw new Error("JS disabled in environment.")
|
68
|
-
}
|
69
|
-
try {
|
70
|
-
// Wrap JS in a function and immediately invoke it.
|
71
|
-
// This is required to allow the final `return` statement to be valid.
|
72
|
-
const js = iifeWrapper(atob(handlebars))
|
73
|
-
|
74
|
-
// Transform snippets into an object for faster access, and cache previously
|
75
|
-
// evaluated snippets
|
76
|
-
let snippetMap: any = {}
|
77
|
-
let snippetCache: any = {}
|
78
|
-
for (let snippet of context.snippets || []) {
|
79
|
-
snippetMap[snippet.name] = snippet.code
|
80
|
-
}
|
81
|
-
|
82
|
-
let clonedContext: Record<string, any>
|
83
|
-
if (isBackendService()) {
|
84
|
-
// On the backned, values are copied across the isolated-vm boundary and
|
85
|
-
// so we don't need to do any cloning here. This does create a fundamental
|
86
|
-
// difference in how JS executes on the frontend vs the backend, e.g.
|
87
|
-
// consider this snippet:
|
88
|
-
//
|
89
|
-
// $("array").push(2)
|
90
|
-
// return $("array")[1]
|
91
|
-
//
|
92
|
-
// With the context of `{ array: [1] }`, the backend will return
|
93
|
-
// `undefined` whereas the frontend will return `2`. We should fix this.
|
94
|
-
clonedContext = context
|
95
|
-
} else {
|
96
|
-
clonedContext = cloneDeep(context)
|
97
|
-
}
|
98
|
-
|
99
|
-
const sandboxContext = {
|
100
|
-
$: (path: string) => getContextValue(path, clonedContext),
|
101
|
-
helpers: getJsHelperList(),
|
102
|
-
|
103
|
-
// Proxy to evaluate snippets when running in the browser
|
104
|
-
snippets: new Proxy(
|
105
|
-
{},
|
106
|
-
{
|
107
|
-
get: function (_, name) {
|
108
|
-
if (!(name in snippetCache)) {
|
109
|
-
snippetCache[name] = eval(iifeWrapper(snippetMap[name]))
|
110
|
-
}
|
111
|
-
return snippetCache[name]
|
112
|
-
},
|
113
|
-
}
|
114
|
-
),
|
115
|
-
}
|
116
|
-
|
117
|
-
// Create a sandbox with our context and run the JS
|
118
|
-
const res = { data: runJS(js, sandboxContext) }
|
119
|
-
return `{{${LITERAL_MARKER} js_result-${JSON.stringify(res)}}}`
|
120
|
-
} catch (error: any) {
|
121
|
-
onErrorLog && onErrorLog(error)
|
122
|
-
|
123
|
-
const { noThrow = true } = context.__opts || {}
|
124
|
-
|
125
|
-
// The error handling below is quite messy, because it has fallen to
|
126
|
-
// string-templates to handle a variety of types of error specific to usages
|
127
|
-
// above it in the stack. It would be nice some day to refactor this to
|
128
|
-
// allow each user of processStringSync to handle errors in the way they see
|
129
|
-
// fit.
|
130
|
-
|
131
|
-
// This is to catch the error vm.runInNewContext() throws when the timeout
|
132
|
-
// is exceeded.
|
133
|
-
if (error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
|
134
|
-
return "Timed out while executing JS"
|
135
|
-
}
|
136
|
-
|
137
|
-
// This is to catch the JsRequestTimeoutError we throw when we detect a
|
138
|
-
// timeout across an entire request in the backend. We use a magic string
|
139
|
-
// because we can't import from the backend into string-templates.
|
140
|
-
if (error.code === "JS_REQUEST_TIMEOUT_ERROR") {
|
141
|
-
return error.message
|
142
|
-
}
|
143
|
-
|
144
|
-
// This is to catch the JsTimeoutError we throw when we detect a timeout in
|
145
|
-
// a single JS execution.
|
146
|
-
if (error.code === JsTimeoutError.code) {
|
147
|
-
return JsTimeoutError.message
|
148
|
-
}
|
149
|
-
|
150
|
-
// This is to catch the error that happens if a user-supplied JS script
|
151
|
-
// throws for reasons introduced by the user.
|
152
|
-
if (error.code === UserScriptError.code) {
|
153
|
-
if (noThrow) {
|
154
|
-
return error.userScriptError.toString()
|
155
|
-
}
|
156
|
-
throw error
|
157
|
-
}
|
158
|
-
|
159
|
-
if (error.name === "SyntaxError") {
|
160
|
-
if (noThrow) {
|
161
|
-
return error.toString()
|
162
|
-
}
|
163
|
-
throw error
|
164
|
-
}
|
165
|
-
|
166
|
-
return "Error while executing JS"
|
167
|
-
}
|
168
|
-
}
|
package/src/helpers/list.ts
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
import { date, duration } from "./date"
|
2
|
-
|
3
|
-
/*
|
4
|
-
@budibase/handlebars-helpers is not treeshakeable, so we can't use the barrel files.
|
5
|
-
Otherwise, we have issues when generating the isolated-vm bundle because of the treeshaking
|
6
|
-
*/
|
7
|
-
/* eslint-disable local-rules/no-budibase-imports */
|
8
|
-
// @ts-expect-error
|
9
|
-
import math from "@budibase/handlebars-helpers/lib/math"
|
10
|
-
// @ts-expect-error
|
11
|
-
import array from "@budibase/handlebars-helpers/lib/array"
|
12
|
-
// @ts-expect-error
|
13
|
-
import number from "@budibase/handlebars-helpers/lib/number"
|
14
|
-
// @ts-expect-error
|
15
|
-
import url from "@budibase/handlebars-helpers/lib/url"
|
16
|
-
// @ts-expect-error
|
17
|
-
import string from "@budibase/handlebars-helpers/lib/string"
|
18
|
-
// @ts-expect-error
|
19
|
-
import comparison from "@budibase/handlebars-helpers/lib/comparison"
|
20
|
-
// @ts-expect-error
|
21
|
-
import object from "@budibase/handlebars-helpers/lib/object"
|
22
|
-
// @ts-expect-error
|
23
|
-
import regex from "@budibase/handlebars-helpers/lib/regex"
|
24
|
-
// @ts-expect-error
|
25
|
-
import uuid from "@budibase/handlebars-helpers/lib/uuid"
|
26
|
-
/* eslint-enable local-rules/no-budibase-imports */
|
27
|
-
|
28
|
-
// https://github.com/evanw/esbuild/issues/56
|
29
|
-
const externalCollections = {
|
30
|
-
math,
|
31
|
-
array,
|
32
|
-
number,
|
33
|
-
url,
|
34
|
-
string,
|
35
|
-
comparison,
|
36
|
-
object,
|
37
|
-
regex,
|
38
|
-
uuid,
|
39
|
-
}
|
40
|
-
|
41
|
-
export const helpersToRemoveForJs = ["sortBy"]
|
42
|
-
|
43
|
-
const addedHelpers = {
|
44
|
-
date: date,
|
45
|
-
duration: duration,
|
46
|
-
}
|
47
|
-
|
48
|
-
let helpers: Record<string, any>
|
49
|
-
|
50
|
-
export function getJsHelperList() {
|
51
|
-
if (helpers) {
|
52
|
-
return helpers
|
53
|
-
}
|
54
|
-
|
55
|
-
helpers = {}
|
56
|
-
for (let collection of Object.values(externalCollections)) {
|
57
|
-
for (let [key, func] of Object.entries<any>(collection)) {
|
58
|
-
// Handlebars injects the hbs options to the helpers by default. We are adding an empty {} as a last parameter to simulate it
|
59
|
-
helpers[key] = (...props: any) => func(...props, {})
|
60
|
-
}
|
61
|
-
}
|
62
|
-
helpers = {
|
63
|
-
...helpers,
|
64
|
-
...addedHelpers,
|
65
|
-
}
|
66
|
-
|
67
|
-
for (const toRemove of helpersToRemoveForJs) {
|
68
|
-
delete helpers[toRemove]
|
69
|
-
}
|
70
|
-
Object.freeze(helpers)
|
71
|
-
return helpers
|
72
|
-
}
|
package/src/iife.ts
DELETED