More types

This commit is contained in:
Adria Navarro 2024-02-22 11:52:50 +01:00
parent 566c4e5c17
commit c60baaa012
4 changed files with 77 additions and 71 deletions

View File

@ -1,31 +1,34 @@
export default class Helper { export default class Helper {
private name private name: any
private fn private fn: any
private useValueFallback private useValueFallback: boolean
constructor(name, fn, useValueFallback = true) { constructor(name: string, fn: any, useValueFallback = true) {
this.name = name this.name = name
this.fn = fn this.fn = fn
this.useValueFallback = useValueFallback this.useValueFallback = useValueFallback
} }
register(handlebars) { register(handlebars: typeof Handlebars) {
// wrap the function so that no helper can cause handlebars to break // wrap the function so that no helper can cause handlebars to break
handlebars.registerHelper(this.name, (value, info) => { handlebars.registerHelper(
let context = {} this.name,
if (info && info.data && info.data.root) { (value: any, info: { data: { root: {} } }) => {
context = 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
}
} }
const result = this.fn(value, context) )
if (result == null) {
return this.useValueFallback ? value : null
} else {
return result
}
})
} }
unregister(handlebars) { unregister(handlebars: { unregisterHelper: any }) {
handlebars.unregisterHelper(this.name) handlebars.unregisterHelper(this.name)
} }
} }

View File

@ -1,4 +1,4 @@
import helpers from "@budibase/handlebars-helpers" const helpers = require("@budibase/handlebars-helpers")
import { date, duration } from "./date" import { date, duration } from "./date"
import { HelperFunctionBuiltin } from "./constants" import { HelperFunctionBuiltin } from "./constants"
@ -27,7 +27,7 @@ const ADDED_HELPERS = {
export const externalCollections = EXTERNAL_FUNCTION_COLLECTIONS export const externalCollections = EXTERNAL_FUNCTION_COLLECTIONS
export const addedHelpers = ADDED_HELPERS export const addedHelpers = ADDED_HELPERS
export function 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)
} }
@ -55,7 +55,7 @@ export function registerAll(handlebars) {
externalHelperNames = externalNames.concat(Object.keys(ADDED_HELPERS)) externalHelperNames = externalNames.concat(Object.keys(ADDED_HELPERS))
} }
export function 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)
} }
@ -65,4 +65,4 @@ export function unregisterAll(handlebars) {
externalHelperNames = [] externalHelperNames = []
} }
export let externalHelperNames = [] export let externalHelperNames: any[] = []

View File

@ -15,7 +15,7 @@ const HTML_SWAPS = {
">": ">", ">": ">",
} }
function isObject(value) { function isObject(value: string | any[]) {
if (value == null || typeof value !== "object") { if (value == null || typeof value !== "object") {
return false return false
} }
@ -27,42 +27,45 @@ function isObject(value) {
const HELPERS = [ const HELPERS = [
// external helpers // external helpers
new Helper(HelperFunctionNames.OBJECT, value => { new Helper(HelperFunctionNames.OBJECT, (value: any) => {
return new SafeString(JSON.stringify(value)) return new SafeString(JSON.stringify(value))
}), }),
// javascript helper // javascript helper
new Helper(HelperFunctionNames.JS, processJS, false), new Helper(HelperFunctionNames.JS, processJS, false),
// this help is applied to all statements // this help is applied to all statements
new Helper(HelperFunctionNames.ALL, (value, inputs) => { new Helper(
const { __opts } = inputs HelperFunctionNames.ALL,
if (isObject(value)) { (value: string, inputs: { __opts: any }) => {
return new SafeString(JSON.stringify(value)) 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 = value
if (__opts && __opts.escapeNewlines) {
text = value.replace(/\n/g, "\\n")
}
text = new SafeString(text.replace(/&/g, "&")).toString()
if (text == null || typeof text !== "string") {
return text
}
return text.replace(/[<>]/g, (tag: string) => {
return HTML_SWAPS[tag as keyof typeof HTML_SWAPS] || tag
})
} }
// 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 = value
if (__opts && __opts.escapeNewlines) {
text = value.replace(/\n/g, "\\n")
}
text = new SafeString(text.replace(/&amp;/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 // adds a note for post-processor
new Helper(HelperFunctionNames.LITERAL, value => { new Helper(HelperFunctionNames.LITERAL, (value: any) => {
if (value === undefined) { if (value === undefined) {
return "" return ""
} }
@ -79,19 +82,19 @@ export function HelperNames() {
) )
} }
export function registerMinimum(handlebars) { export function registerMinimum(handlebars: typeof Handlebars) {
for (let helper of HELPERS) { for (let helper of HELPERS) {
helper.register(handlebars) helper.register(handlebars)
} }
} }
export function registerAll(handlebars) { export function registerAll(handlebars: typeof Handlebars) {
registerMinimum(handlebars) registerMinimum(handlebars)
// register imported helpers // register imported helpers
externalHandlebars.registerAll(handlebars) externalHandlebars.registerAll(handlebars)
} }
export function unregisterAll(handlebars) { export function unregisterAll(handlebars: any) {
for (let helper of HELPERS) { for (let helper of HELPERS) {
helper.unregister(handlebars) helper.unregister(handlebars)
} }

View File

@ -46,8 +46,8 @@ function testObject(object: any) {
/** /**
* 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: string, opts: ProcessOptions) { 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
@ -87,7 +87,7 @@ export async function processObject(
object: { [x: string]: any }, object: { [x: string]: any },
context: object, context: object,
opts?: { noHelpers?: boolean; escapeNewlines?: boolean; onlyFound?: boolean } opts?: { noHelpers?: boolean; escapeNewlines?: boolean; onlyFound?: boolean }
) { ): Promise<object | Array<any>> {
testObject(object) testObject(object)
for (let key of Object.keys(object || {})) { for (let key of Object.keys(object || {})) {
if (object[key] != null) { if (object[key] != null) {
@ -114,7 +114,7 @@ export async function processString(
string: string, string: string,
context: object, context: object,
opts?: ProcessOptions 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 processStringSync(string, context, opts) return processStringSync(string, context, opts)
} }
@ -132,7 +132,7 @@ export function processObjectSync(
object: { [x: string]: any }, object: { [x: string]: any },
context: any, context: any,
opts: 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]
@ -157,7 +157,7 @@ export function processStringSync(
string: string, string: string,
context: object, context: object,
opts?: ProcessOptions 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") {
@ -220,7 +220,7 @@ export function disableEscaping(string: 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.
*/ */
export function makePropSafe(property: any) { export function makePropSafe(property: any): string {
return `[${property}]`.replace("[[", "[").replace("]]", "]") return `[${property}]`.replace("[[", "[").replace("]]", "]")
} }
@ -230,7 +230,7 @@ export function makePropSafe(property: any) {
* @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.
*/ */
export function isValid(string: any, opts?: any) { export function isValid(string: any, opts?: any): boolean {
const validCases = [ const validCases = [
"string", "string",
"number", "number",
@ -251,7 +251,7 @@ export function isValid(string: any, opts?: any) {
}) })
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
@ -281,7 +281,7 @@ export function 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
*/ */
export function isJSBinding(handlebars: any) { export function isJSBinding(handlebars: any): boolean {
return decodeJSBinding(handlebars) != null return decodeJSBinding(handlebars) != null
} }
@ -290,7 +290,7 @@ export function isJSBinding(handlebars: any) {
* @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
*/ */
export function encodeJSBinding(javascript: string) { export function encodeJSBinding(javascript: string): string {
return `{{ js "${btoa(javascript)}" }}` return `{{ js "${btoa(javascript)}" }}`
} }
@ -299,7 +299,7 @@ export function encodeJSBinding(javascript: string) {
* @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
*/ */
export function decodeJSBinding(handlebars: string) { export function decodeJSBinding(handlebars: string): string | null {
if (!handlebars || typeof handlebars !== "string") { if (!handlebars || typeof handlebars !== "string") {
return null return null
} }
@ -324,7 +324,7 @@ export function decodeJSBinding(handlebars: string) {
* @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.
*/ */
export function doesContainStrings(template: string, strings: any[]) { 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) {
@ -333,7 +333,7 @@ export function doesContainStrings(template: string, strings: any[]) {
for (let match of matches) { for (let match of matches) {
let hbs = match let hbs = match
if (isJSBinding(match)) { if (isJSBinding(match)) {
hbs = decodeJSBinding(match) hbs = decodeJSBinding(match)!
} }
let allFound = true let allFound = true
for (let string of strings) { for (let string of strings) {
@ -354,7 +354,7 @@ export function doesContainStrings(template: string, strings: any[]) {
* @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.
*/ */
export function findHBSBlocks(string: string) { export function findHBSBlocks(string: string): string[] {
if (!string || typeof string !== "string") { if (!string || typeof string !== "string") {
return [] return []
} }
@ -375,7 +375,7 @@ export function findHBSBlocks(string: 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.
*/ */
export function doesContainString(template: any, string: any) { export function doesContainString(template: any, string: any): boolean {
return doesContainStrings(template, [string]) return doesContainStrings(template, [string])
} }
@ -383,7 +383,7 @@ export function convertToJS(hbs: string) {
const blocks = findHBSBlocks(hbs) const blocks = findHBSBlocks(hbs)
let js = "return `", let js = "return `",
prevBlock: string | null = null prevBlock: string | null = null
const variables = {} const variables: Record<string, any> = {}
if (blocks.length === 0) { if (blocks.length === 0) {
js += hbs js += hbs
} }