Quick addition of a duration helper which can be used to create relative humanized date strings.

This commit is contained in:
mike12345567 2021-02-04 10:17:10 +00:00
parent 1e54a3d57c
commit 821fb20e8b
4 changed files with 83 additions and 26 deletions

View File

@ -5,18 +5,31 @@ const fs = require("fs")
const doctrine = require("doctrine") const doctrine = require("doctrine")
const marked = require("marked") const marked = require("marked")
const DIRECTORY = fs.existsSync("node_modules") ? "." : ".."
const FILENAME = `${DIRECTORY}/manifest.json`
/** /**
* full list of supported helpers can be found here: * full list of supported helpers can be found here:
* https://github.com/helpers/handlebars-helpers * https://github.com/budibase/handlebars-helpers
*/ */
const DIRECTORY = fs.existsSync("node_modules") ? "." : ".."
const COLLECTIONS = ["math", "array", "number", "url", "string", "comparison"] const COLLECTIONS = ["math", "array", "number", "url", "string", "comparison"]
const FILENAME = `${DIRECTORY}/manifest.json`
const outputJSON = {} const outputJSON = {}
const ADDED_HELPERS = {
date: {
date: {
args: ["datetime", "format"],
numArgs: 2,
example: '{{date now "DD-MM-YYYY"}} -> 21-01-2021',
description: "Format a date using moment.js date formatting.",
},
duration: {
args: ["time", "durationType"],
numArgs: 2,
example: '{{duration timeLeft "seconds"}} -> a few seconds',
description: "Produce a humanized duration left/until given an amount of time and the type of time measurement."
}
}
}
function fixSpecialCases(name, obj) { function fixSpecialCases(name, obj) {
const args = obj.args const args = obj.args
@ -134,15 +147,15 @@ function run() {
} }
outputJSON[collection] = collectionInfo outputJSON[collection] = collectionInfo
} }
// add the date helper // add extra helpers
outputJSON["date"] = { for (let [collectionName, collection] of Object.entries(ADDED_HELPERS)) {
date: { let input = collection
args: ["datetime", "format"], if (outputJSON[collectionName]) {
numArgs: 2, input = Object.assign(outputJSON[collectionName], collection)
example: '{{date now "DD-MM-YYYY"}}',
description: "Format a date using moment.js date formatting.",
},
} }
outputJSON[collectionName] = input
}
// convert all markdown to HTML // convert all markdown to HTML
for (let collection of Object.values(outputJSON)) { for (let collection of Object.values(outputJSON)) {
for (let helper of Object.values(collection)) { for (let helper of Object.values(collection)) {

View File

@ -1,4 +1,7 @@
const dayjs = require("dayjs") const dayjs = require("dayjs")
dayjs.extend(require("dayjs/plugin/duration"))
dayjs.extend(require("dayjs/plugin/advancedFormat"))
dayjs.extend(require("dayjs/plugin/relativeTime"))
/** /**
* 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:
@ -50,7 +53,7 @@ function getContext(thisArg, locals, options) {
return context return context
} }
module.exports = function dateHelper(str, pattern, options) { function initialSteps(str, pattern, options) {
if (isOptions(pattern)) { if (isOptions(pattern)) {
options = pattern options = pattern
pattern = null pattern = null
@ -61,6 +64,21 @@ module.exports = function dateHelper(str, pattern, options) {
pattern = null pattern = null
str = null str = null
} }
return {str, pattern, options}
}
function setLocale(str, pattern, options) {
// if options is null then it'll get updated here
({str, pattern, options} = initialSteps(str, pattern, options))
const defaults = { lang: "en", date: new Date(str) }
const opts = getContext(this, defaults, options)
// set the language to use
dayjs.locale(opts.lang || opts.language)
}
module.exports.date = (str, pattern, options) => {
({str, pattern, options} = initialSteps(str, pattern, options))
// if no args are passed, return a formatted date // if no args are passed, return a formatted date
if (str == null && pattern == null) { if (str == null && pattern == null) {
@ -68,11 +86,20 @@ module.exports = function dateHelper(str, pattern, options) {
return dayjs().format("MMMM DD, YYYY") return dayjs().format("MMMM DD, YYYY")
} }
const defaults = { lang: "en", date: new Date(str) } setLocale(str, pattern, options)
const opts = getContext(this, defaults, options)
// set the language to use
dayjs.locale(opts.lang || opts.language)
return dayjs(new Date(str)).format(pattern) return dayjs(new Date(str)).format(pattern)
} }
module.exports.duration = (str, pattern, format) => {
({str, pattern} = initialSteps(str, pattern))
setLocale(str, pattern)
const duration = dayjs.duration(str, pattern)
if (!isOptions(format)) {
return duration.format(format)
} else {
return duration.humanize()
}
}

View File

@ -1,5 +1,5 @@
const helpers = require("@budibase/handlebars-helpers") const helpers = require("@budibase/handlebars-helpers")
const dateHelper = require("./date") const { date, duration } = require("./date")
const { HelperFunctionBuiltin } = require("./constants") const { HelperFunctionBuiltin } = require("./constants")
/** /**
@ -18,10 +18,15 @@ const EXTERNAL_FUNCTION_COLLECTIONS = [
"regex", "regex",
] ]
const DATE_NAME = "date" const ADDED_HELPERS = {
"date": date,
"duration": duration,
}
exports.registerAll = handlebars => { exports.registerAll = handlebars => {
handlebars.registerHelper(DATE_NAME, dateHelper) for (let [name, helper] of Object.entries(ADDED_HELPERS)) {
handlebars.registerHelper(name, helper)
}
let externalNames = [] let externalNames = []
for (let collection of EXTERNAL_FUNCTION_COLLECTIONS) { for (let collection of EXTERNAL_FUNCTION_COLLECTIONS) {
// collect information about helper // collect information about helper
@ -43,12 +48,13 @@ exports.registerAll = handlebars => {
}) })
} }
// add date external functionality // add date external functionality
externalNames.push(DATE_NAME) exports.externalHelperNames = externalNames.concat(Object.keys(ADDED_HELPERS))
exports.externalHelperNames = externalNames
} }
exports.unregisterAll = handlebars => { exports.unregisterAll = handlebars => {
handlebars.unregisterHelper(DATE_NAME) for (let name of Object.keys(ADDED_HELPERS)) {
handlebars.unregisterHelper(name)
}
for (let name of module.exports.externalHelperNames) { for (let name of module.exports.externalHelperNames) {
handlebars.unregisterHelper(name) handlebars.unregisterHelper(name)
} }

View File

@ -318,6 +318,17 @@ describe("Cover a few complex use cases", () => {
expect(validity).toBe(true) expect(validity).toBe(true)
}) })
it("test a very complex duration output", async () => {
const currentTime = new Date(1612432082000).toISOString(),
eventTime = new Date(1612432071000).toISOString()
const input = `{{duration ( subtract (date currentTime "X")(date eventTime "X")) "seconds"}}`
const output = await processString(input, {
currentTime,
eventTime,
})
expect(output).toBe("a few seconds")
})
it("should confirm a bunch of invalid strings", () => { it("should confirm a bunch of invalid strings", () => {
const invalids = ["{{ awd )", "{{ awdd () ", "{{ awdwad ", "{{ awddawd }"] const invalids = ["{{ awd )", "{{ awdd () ", "{{ awdwad ", "{{ awddawd }"]
for (let invalid of invalids) { for (let invalid of invalids) {