@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/iife.mjs ADDED
@@ -0,0 +1 @@
1
+ !function(){const s={};try{if(process)return process.env=Object.assign({},process.env),void Object.assign(process.env,s)}catch(s){}globalThis.process={env:s}}();const s=s=>`(function(){\n${s}\n})();`;export{s as iifeWrapper};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@budibase/string-templates",
3
- "version": "3.2.5",
3
+ "version": "3.2.6",
4
4
  "description": "Handlebars wrapper for Budibase templating.",
5
5
  "main": "dist/bundle.cjs",
6
6
  "module": "dist/bundle.mjs",
7
- "types": "src/index.ts",
7
+ "types": "dist/index.d.ts",
8
8
  "license": "MPL-2.0",
9
9
  "exports": {
10
10
  ".": {
@@ -12,12 +12,8 @@
12
12
  "import": "./dist/bundle.mjs"
13
13
  },
14
14
  "./package.json": "./package.json",
15
- "./iife": "./src/iife.js"
15
+ "./iife": "./dist/iife.mjs"
16
16
  },
17
- "files": [
18
- "dist",
19
- "src"
20
- ],
21
17
  "scripts": {
22
18
  "build": "tsc --emitDeclarationOnly && rollup -c",
23
19
  "dev": "rollup -cw",
@@ -48,5 +44,5 @@
48
44
  "ts-jest": "29.1.1",
49
45
  "typescript": "5.5.2"
50
46
  },
51
- "gitHead": "c1ee7b00e6687d588565b3d74ee24084a8d1ceab"
47
+ "gitHead": "4b9c088e1a3550a500613b3f24a15d046689abe3"
52
48
  }
@@ -1,131 +0,0 @@
1
- import { getJsHelperList } from "../helpers"
2
-
3
- function getLayers(fullBlock: string): string[] {
4
- let layers = []
5
- while (fullBlock.length) {
6
- const start = fullBlock.lastIndexOf("("),
7
- end = fullBlock.indexOf(")")
8
- let layer: string
9
- if (start === -1 || end === -1) {
10
- layer = fullBlock.trim()
11
- fullBlock = ""
12
- } else {
13
- const untrimmed = fullBlock.substring(start, end + 1)
14
- layer = untrimmed.substring(1, untrimmed.length - 1).trim()
15
- fullBlock =
16
- fullBlock.slice(0, start) +
17
- fullBlock.slice(start + untrimmed.length + 1, fullBlock.length)
18
- }
19
- layers.push(layer)
20
- }
21
- return layers
22
- }
23
-
24
- function getVariable(variableName: string) {
25
- if (!variableName || typeof variableName !== "string") {
26
- return variableName
27
- }
28
- // it is an array
29
- const arrayOrObject = [",", "{", ":"]
30
- let contains = false
31
- arrayOrObject.forEach(char => {
32
- if (variableName.includes(char)) {
33
- contains = true
34
- }
35
- })
36
- if (variableName.startsWith("[") && contains) {
37
- return variableName
38
- }
39
- // it is just a number
40
- if (!isNaN(parseFloat(variableName))) {
41
- return variableName
42
- }
43
- if (variableName.startsWith("'") || variableName.startsWith('"')) {
44
- return variableName
45
- }
46
- // extract variable
47
- return `$("${variableName}")`
48
- }
49
-
50
- function buildList(parts: string[], value: any) {
51
- function build() {
52
- return parts
53
- .map((part: string) =>
54
- part.startsWith("helper") ? part : getVariable(part)
55
- )
56
- .join(", ")
57
- }
58
- if (!value) {
59
- return parts.length > 1 ? `${build()}` : build()
60
- } else {
61
- return parts.length === 0 ? value : `${build()}, ${value}`
62
- }
63
- }
64
-
65
- function splitBySpace(layer: string) {
66
- const parts: string[] = []
67
- let started = null,
68
- endChar = null,
69
- last = 0
70
- function add(str: string) {
71
- const startsWith = ["]"]
72
- while (startsWith.indexOf(str.substring(0, 1)) !== -1) {
73
- str = str.substring(1, str.length)
74
- }
75
- if (str.length > 0) {
76
- parts.push(str.trim())
77
- }
78
- }
79
- const continuationChars = ["[", "'", '"']
80
- for (let index = 0; index < layer.length; index++) {
81
- const char = layer[index]
82
- if (continuationChars.indexOf(char) !== -1 && started == null) {
83
- started = index
84
- endChar = char === "[" ? "]" : char
85
- } else if (
86
- char === endChar &&
87
- started != null &&
88
- layer[index + 1] !== "."
89
- ) {
90
- add(layer.substring(started, index + 1))
91
- started = null
92
- endChar = null
93
- last = index + 1
94
- } else if (started == null && char === " ") {
95
- add(layer.substring(last, index))
96
- last = index
97
- }
98
- }
99
- if (
100
- (!layer.startsWith("[") || parts.length === 0) &&
101
- last !== layer.length - 1
102
- ) {
103
- add(layer.substring(last, layer.length))
104
- }
105
- return parts
106
- }
107
-
108
- export function convertHBSBlock(block: string, blockNumber: number) {
109
- const braceLength = block[2] === "{" ? 3 : 2
110
- block = block.substring(braceLength, block.length - braceLength).trim()
111
- const layers = getLayers(block)
112
-
113
- let value = null
114
- const list = getJsHelperList()
115
- for (let layer of layers) {
116
- const parts = splitBySpace(layer)
117
- if (value || parts.length > 1 || list[parts[0]]) {
118
- // first of layer should always be the helper
119
- const [helper] = parts.splice(0, 1)
120
- if (list[helper]) {
121
- value = `helpers.${helper}(${buildList(parts, value)})`
122
- }
123
- }
124
- // no helpers
125
- else {
126
- value = getVariable(parts[0])
127
- }
128
- }
129
- // split by space will remove square brackets
130
- return { variable: `var${blockNumber}`, value }
131
- }
package/src/errors.ts DELETED
@@ -1,20 +0,0 @@
1
- export class JsTimeoutError extends Error {
2
- static message = "Timed out while executing JS"
3
- static code = "JS_TIMEOUT_ERROR"
4
- code: string = JsTimeoutError.code
5
-
6
- constructor() {
7
- super(JsTimeoutError.message)
8
- }
9
- }
10
-
11
- export class UserScriptError extends Error {
12
- static code = "USER_SCRIPT_ERROR"
13
- code: string = UserScriptError.code
14
-
15
- constructor(readonly userScriptError: Error) {
16
- super(
17
- `error while running user-supplied JavaScript: ${userScriptError.toString()}`
18
- )
19
- }
20
- }
@@ -1,36 +0,0 @@
1
- import Handlebars from "handlebars"
2
-
3
- export default class Helper {
4
- private name: any
5
- private fn: any
6
- private useValueFallback: boolean
7
-
8
- constructor(name: string, fn: any, useValueFallback = true) {
9
- this.name = name
10
- this.fn = fn
11
- this.useValueFallback = useValueFallback
12
- }
13
-
14
- register(handlebars: typeof Handlebars) {
15
- // wrap the function so that no helper can cause handlebars to break
16
- handlebars.registerHelper(
17
- this.name,
18
- (value: any, info: { data: { root: {} } }) => {
19
- let context = {}
20
- if (info && info.data && info.data.root) {
21
- context = info.data.root
22
- }
23
- const result = this.fn(value, context)
24
- if (result == null) {
25
- return this.useValueFallback ? value : null
26
- } else {
27
- return result
28
- }
29
- }
30
- )
31
- }
32
-
33
- unregister(handlebars: { unregisterHelper: any }) {
34
- handlebars.unregisterHelper(this.name)
35
- }
36
- }
@@ -1,41 +0,0 @@
1
- export const HelperFunctionBuiltin = [
2
- "#if",
3
- "#unless",
4
- "#each",
5
- "#with",
6
- "lookup",
7
- "log",
8
- "blockHelperMissing",
9
- "each",
10
- "helperMissing",
11
- "if",
12
- "unless",
13
- "log",
14
- "lookup",
15
- "with",
16
- ]
17
-
18
- /**
19
- * full list of supported helpers can be found here:
20
- * https://github.com/Budibase/handlebars-helpers
21
- */
22
- export const EXTERNAL_FUNCTION_COLLECTIONS = [
23
- "math",
24
- "array",
25
- "number",
26
- "url",
27
- "string",
28
- "comparison",
29
- "object",
30
- "regex",
31
- "uuid",
32
- ]
33
-
34
- export const HelperFunctionNames = {
35
- OBJECT: "object",
36
- ALL: "all",
37
- LITERAL: "literal",
38
- JS: "js",
39
- }
40
-
41
- export const LITERAL_MARKER = "%LITERAL%"
@@ -1,133 +0,0 @@
1
- import dayjs from "dayjs"
2
-
3
- import dayjsDurationPlugin from "dayjs/plugin/duration"
4
- import dayjsAdvancedFormatPlugin from "dayjs/plugin/advancedFormat"
5
- import dayjsIsoWeekPlugin from "dayjs/plugin/isoWeek"
6
- import dayjsWeekYearPlugin from "dayjs/plugin/weekYear"
7
- import dayjsWeekOfYearPlugin from "dayjs/plugin/weekOfYear"
8
- import dayjsRelativeTimePlugin from "dayjs/plugin/relativeTime"
9
- import dayjsUtcPlugin from "dayjs/plugin/utc"
10
- import dayjsTimezonePlugin from "dayjs/plugin/timezone"
11
-
12
- dayjs.extend(dayjsDurationPlugin)
13
- dayjs.extend(dayjsAdvancedFormatPlugin)
14
- dayjs.extend(dayjsIsoWeekPlugin)
15
- dayjs.extend(dayjsWeekYearPlugin)
16
- dayjs.extend(dayjsWeekOfYearPlugin)
17
- dayjs.extend(dayjsRelativeTimePlugin)
18
- dayjs.extend(dayjsUtcPlugin)
19
- dayjs.extend(dayjsTimezonePlugin)
20
-
21
- /**
22
- * This file was largely taken from the helper-date package - we did this for two reasons:
23
- * 1. It made use of both moment of date.js - this caused some weird bugs with some relatively simple
24
- * syntax and didn't offer much in return.
25
- * 2. Replacing moment with dayjs helps massively reduce bundle size.
26
- * The original package can be found here:
27
- * https://github.com/helpers/helper-date
28
- */
29
-
30
- function isOptions(val: any) {
31
- return typeof val === "object" && typeof val.hash === "object"
32
- }
33
-
34
- function isApp(thisArg: any) {
35
- return (
36
- typeof thisArg === "object" &&
37
- typeof thisArg.options === "object" &&
38
- typeof thisArg.app === "object"
39
- )
40
- }
41
-
42
- function getContext(thisArg: any, locals: any, options: any) {
43
- if (isOptions(thisArg)) {
44
- return getContext({}, locals, thisArg)
45
- }
46
- // ensure args are in the correct order
47
- if (isOptions(locals)) {
48
- return getContext(thisArg, options, locals)
49
- }
50
- const appContext = isApp(thisArg) ? thisArg.context : {}
51
- options = options || {}
52
-
53
- // if "options" is not handlebars options, merge it onto locals
54
- if (!isOptions(options)) {
55
- locals = Object.assign({}, locals, options)
56
- }
57
- // merge handlebars root data onto locals if specified on the hash
58
- if (isOptions(options) && options.hash.root === true) {
59
- locals = Object.assign({}, options.data.root, locals)
60
- }
61
- let context = Object.assign({}, appContext, locals, options.hash)
62
- if (!isApp(thisArg)) {
63
- context = Object.assign({}, thisArg, context)
64
- }
65
- if (isApp(thisArg) && thisArg.view && thisArg.view.data) {
66
- context = Object.assign({}, context, thisArg.view.data)
67
- }
68
- return context
69
- }
70
-
71
- function initialConfig(str: any, pattern: any, options?: any) {
72
- if (isOptions(pattern)) {
73
- options = pattern
74
- pattern = null
75
- }
76
-
77
- if (isOptions(str)) {
78
- options = str
79
- pattern = null
80
- str = null
81
- }
82
- return { str, pattern, options }
83
- }
84
-
85
- function setLocale(this: any, str: any, pattern: any, options?: any) {
86
- // if options is null then it'll get updated here
87
- const config = initialConfig(str, pattern, options)
88
- const defaults = { lang: "en", date: new Date(config.str) }
89
- // for now don't allow this to be configurable, don't pass in options
90
- const opts = getContext(this, defaults, {})
91
-
92
- // set the language to use
93
- dayjs.locale(opts.lang || opts.language)
94
- }
95
-
96
- export const date = (str: any, pattern: any, options: any) => {
97
- const config = initialConfig(str, pattern, options)
98
-
99
- // if no args are passed, return a formatted date
100
- if (config.str == null && config.pattern == null) {
101
- dayjs.locale("en")
102
- return dayjs().format("MMMM DD, YYYY")
103
- }
104
-
105
- setLocale(config.str, config.pattern, config.options)
106
-
107
- let date = dayjs(new Date(config.str))
108
- if (typeof config.options === "string") {
109
- date =
110
- config.options.toLowerCase() === "utc"
111
- ? date.utc()
112
- : date.tz(config.options)
113
- } else {
114
- date = date.tz(dayjs.tz.guess())
115
- }
116
- if (config.pattern === "") {
117
- return date.toISOString()
118
- }
119
- return date.format(config.pattern)
120
- }
121
-
122
- export const duration = (str: any, pattern: any, format: any) => {
123
- const config = initialConfig(str, pattern)
124
-
125
- setLocale(config.str, config.pattern)
126
-
127
- const duration = dayjs.duration(config.str, config.pattern)
128
- if (format && !isOptions(format)) {
129
- return duration.format(format)
130
- } else {
131
- return duration.humanize()
132
- }
133
- }
@@ -1,57 +0,0 @@
1
- // @ts-ignore we don't have types for it
2
- import helpers from "@budibase/handlebars-helpers"
3
-
4
- import { date, duration } from "./date"
5
- import {
6
- HelperFunctionBuiltin,
7
- EXTERNAL_FUNCTION_COLLECTIONS,
8
- } from "./constants"
9
- import Handlebars from "handlebars"
10
-
11
- const ADDED_HELPERS = {
12
- date: date,
13
- duration: duration,
14
- }
15
-
16
- export const externalCollections = EXTERNAL_FUNCTION_COLLECTIONS
17
- export const addedHelpers = ADDED_HELPERS
18
-
19
- export function registerAll(handlebars: typeof Handlebars) {
20
- for (let [name, helper] of Object.entries(ADDED_HELPERS)) {
21
- handlebars.registerHelper(name, helper)
22
- }
23
- let externalNames = []
24
- for (let collection of EXTERNAL_FUNCTION_COLLECTIONS) {
25
- // collect information about helper
26
- let hbsHelperInfo = helpers[collection]()
27
- for (let entry of Object.entries(hbsHelperInfo)) {
28
- const name = entry[0]
29
- // skip built-in functions and ones seen already
30
- if (
31
- HelperFunctionBuiltin.indexOf(name) !== -1 ||
32
- externalNames.indexOf(name) !== -1
33
- ) {
34
- continue
35
- }
36
- externalNames.push(name)
37
- }
38
- // attach it to our handlebars instance
39
- helpers[collection]({
40
- handlebars,
41
- })
42
- }
43
- // add date external functionality
44
- externalHelperNames = externalNames.concat(Object.keys(ADDED_HELPERS))
45
- }
46
-
47
- export function unregisterAll(handlebars: typeof Handlebars) {
48
- for (let name of Object.keys(ADDED_HELPERS)) {
49
- handlebars.unregisterHelper(name)
50
- }
51
- for (let name of externalHelperNames) {
52
- handlebars.unregisterHelper(name)
53
- }
54
- externalHelperNames = []
55
- }
56
-
57
- export let externalHelperNames: any[] = []
@@ -1,103 +0,0 @@
1
- import Helper from "./Helper"
2
- import Handlebars from "handlebars"
3
- import * as externalHandlebars from "./external"
4
- import { processJS } from "./javascript"
5
- import {
6
- HelperFunctionNames,
7
- HelperFunctionBuiltin,
8
- LITERAL_MARKER,
9
- } from "./constants"
10
-
11
- export { getJsHelperList } from "./list"
12
-
13
- const HTML_SWAPS = {
14
- "<": "&lt;",
15
- ">": "&gt;",
16
- }
17
-
18
- function isObject(value: string | any[]) {
19
- if (value == null || typeof value !== "object") {
20
- return false
21
- }
22
- return (
23
- value.toString() === "[object Object]" ||
24
- (value.length > 0 && typeof value[0] === "object")
25
- )
26
- }
27
-
28
- const HELPERS = [
29
- // external helpers
30
- new Helper(HelperFunctionNames.OBJECT, (value: any) => {
31
- return new Handlebars.SafeString(JSON.stringify(value))
32
- }),
33
- // javascript helper
34
- new Helper(HelperFunctionNames.JS, processJS, false),
35
- // this help is applied to all statements
36
- new Helper(
37
- HelperFunctionNames.ALL,
38
- (value: string, inputs: { __opts: any }) => {
39
- const { __opts } = inputs
40
- if (isObject(value)) {
41
- return new Handlebars.SafeString(JSON.stringify(value))
42
- }
43
- // null/undefined values produce bad results
44
- if (__opts && __opts.onlyFound && value == null) {
45
- return __opts.input
46
- }
47
- if (value == null || typeof value !== "string") {
48
- return value == null ? "" : value
49
- }
50
- // TODO: check, this should always be false
51
- if (value && (value as any).string) {
52
- value = (value as any).string
53
- }
54
- let text: any = value
55
- if (__opts && __opts.escapeNewlines) {
56
- text = value.replace(/\n/g, "\\n")
57
- }
58
- text = new Handlebars.SafeString(text.replace(/&amp;/g, "&"))
59
- if (text == null || typeof text !== "string") {
60
- return text
61
- }
62
- return text.replace(/[<>]/g, (tag: string) => {
63
- return HTML_SWAPS[tag as keyof typeof HTML_SWAPS] || tag
64
- })
65
- }
66
- ),
67
- // adds a note for post-processor
68
- new Helper(HelperFunctionNames.LITERAL, (value: any) => {
69
- if (value === undefined) {
70
- return ""
71
- }
72
- const type = typeof value
73
- const outputVal = type === "object" ? JSON.stringify(value) : value
74
- return `{{${LITERAL_MARKER} ${type}-${outputVal}}}`
75
- }),
76
- ]
77
-
78
- export function HelperNames() {
79
- return Object.values(HelperFunctionNames).concat(
80
- HelperFunctionBuiltin,
81
- externalHandlebars.externalHelperNames
82
- )
83
- }
84
-
85
- export function registerMinimum(handlebars: typeof Handlebars) {
86
- for (let helper of HELPERS) {
87
- helper.register(handlebars)
88
- }
89
- }
90
-
91
- export function registerAll(handlebars: typeof Handlebars) {
92
- registerMinimum(handlebars)
93
- // register imported helpers
94
- externalHandlebars.registerAll(handlebars)
95
- }
96
-
97
- export function unregisterAll(handlebars: any) {
98
- for (let helper of HELPERS) {
99
- helper.unregister(handlebars)
100
- }
101
- // unregister all imported helpers
102
- externalHandlebars.unregisterAll(handlebars)
103
- }