More types
This commit is contained in:
parent
566c4e5c17
commit
c60baaa012
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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[] = []
|
||||||
|
|
|
@ -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(/&/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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue