budibase/packages/string-templates/src/helpers/date.js

121 lines
3.5 KiB
JavaScript

const dayjs = require("dayjs")
dayjs.extend(require("dayjs/plugin/duration"))
dayjs.extend(require("dayjs/plugin/advancedFormat"))
dayjs.extend(require("dayjs/plugin/relativeTime"))
dayjs.extend(require("dayjs/plugin/utc"))
dayjs.extend(require("dayjs/plugin/timezone"))
/**
* This file was largely taken from the helper-date package - we did this for two reasons:
* 1. It made use of both moment of date.js - this caused some weird bugs with some relatively simple
* syntax and didn't offer much in return.
* 2. Replacing moment with dayjs helps massively reduce bundle size.
* The original package can be found here:
* https://github.com/helpers/helper-date
*/
function isOptions(val) {
return typeof val === "object" && typeof val.hash === "object"
}
function isApp(thisArg) {
return (
typeof thisArg === "object" &&
typeof thisArg.options === "object" &&
typeof thisArg.app === "object"
)
}
function getContext(thisArg, locals, options) {
if (isOptions(thisArg)) {
return getContext({}, locals, thisArg)
}
// ensure args are in the correct order
if (isOptions(locals)) {
return getContext(thisArg, options, locals)
}
const appContext = isApp(thisArg) ? thisArg.context : {}
options = options || {}
// if "options" is not handlebars options, merge it onto locals
if (!isOptions(options)) {
locals = Object.assign({}, locals, options)
}
// merge handlebars root data onto locals if specified on the hash
if (isOptions(options) && options.hash.root === true) {
locals = Object.assign({}, options.data.root, locals)
}
let context = Object.assign({}, appContext, locals, options.hash)
if (!isApp(thisArg)) {
context = Object.assign({}, thisArg, context)
}
if (isApp(thisArg) && thisArg.view && thisArg.view.data) {
context = Object.assign({}, context, thisArg.view.data)
}
return context
}
function initialConfig(str, pattern, options) {
if (isOptions(pattern)) {
options = pattern
pattern = null
}
if (isOptions(str)) {
options = str
pattern = null
str = null
}
return { str, pattern, options }
}
function setLocale(str, pattern, options) {
// if options is null then it'll get updated here
const config = initialConfig(str, pattern, options)
const defaults = { lang: "en", date: new Date(config.str) }
// for now don't allow this to be configurable, don't pass in options
const opts = getContext(this, defaults, {})
// set the language to use
dayjs.locale(opts.lang || opts.language)
}
module.exports.date = (str, pattern, options) => {
const config = initialConfig(str, pattern, options)
// if no args are passed, return a formatted date
if (config.str == null && config.pattern == null) {
dayjs.locale("en")
return dayjs().format("MMMM DD, YYYY")
}
setLocale(config.str, config.pattern, config.options)
let date = dayjs(new Date(config.str))
if (typeof config.options === "string") {
date =
config.options.toLowerCase() === "utc"
? date.utc()
: date.tz(config.options)
} else {
date = date.tz(dayjs.tz.guess())
}
if (config.pattern === "") {
return date.toISOString()
}
return date.format(config.pattern)
}
module.exports.duration = (str, pattern, format) => {
const config = initialConfig(str, pattern)
setLocale(config.str, config.pattern)
const duration = dayjs.duration(config.str, config.pattern)
if (!isOptions(format)) {
return duration.format(format)
} else {
return duration.humanize()
}
}