import type { FunctionMap } from "../plug-api/types.ts"; import { niceDate, niceTime, safeTime } from "./dates.ts"; import YAML from "js-yaml"; export const builtinFunctions: FunctionMap = { // String functions contains(str: unknown, substr: unknown) { if (typeof str !== "string") { throw new Error("contains(): str is not a string"); } if (typeof substr !== "string") { throw new Error("contains(): substr is not a string"); } return str.includes(substr); }, replace( str: unknown, ...replacementPairs: unknown[] ) { if (typeof str !== "string") { throw new Error("replace(): str is not a string"); } if (replacementPairs.length % 2 !== 0) { throw new Error( "replace(): requires an even number of replacement arguments", ); } let ret = str; for (let i = 0; i < replacementPairs.length; i += 2) { let match = replacementPairs[i]; const replace = replacementPairs[i + 1]; match = Array.isArray(match) ? new RegExp(match[0], (match[1] ?? "") + "g") : match; if (typeof match !== "string" && (!(match instanceof RegExp))) { throw new Error( `replace(): match is not a string or regexp`, ); } if (typeof replace !== "string") { throw new Error( `replace(): replace is not a string`, ); } ret = ret.replaceAll(match, replace); } return ret; }, json: (v: unknown) => { return JSON.stringify(v); }, yaml: (v: unknown) => { return YAML.dump(v, { quotingType: '"', noCompatMode: true, }); }, niceDate: (ts: unknown) => { if ( typeof ts !== "string" && typeof ts !== "number" && !(ts instanceof Date) ) { throw new Error("niceDate(): ts is not a valid date"); } const date = new Date(ts); if (isNaN(date.getTime())) { throw new Error("niceDate(): ts is not a valid date"); } return niceDate(new Date(ts)); }, escapeRegexp: (ts: unknown) => { if (typeof ts !== "string") { throw new Error("escapeRegexp(): ts is not a string"); } return ts.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); }, // Legacy name: don't use escape: (handlebarsExpr: string) => { return `{{${handlebarsExpr}}}`; }, escapeDirective: (directiveText: unknown) => { return `{{${directiveText}}}`; }, today() { return niceDate(new Date()); }, time: () => niceTime(new Date()), safeTime: () => safeTime(new Date()), tomorrow: () => { const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); return niceDate(tomorrow); }, yesterday: () => { const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); return niceDate(yesterday); }, lastWeek: () => { const lastWeek = new Date(); lastWeek.setDate(lastWeek.getDate() - 7); return niceDate(lastWeek); }, nextWeek: () => { const nextWeek = new Date(); nextWeek.setDate(nextWeek.getDate() + 7); return niceDate(nextWeek); }, weekStart: (startOnMonday = true) => { const d = new Date(); const day = d.getDay(); let diff = d.getDate() - day; if (startOnMonday) { diff += day == 0 ? -6 : 1; } return niceDate(new Date(d.setDate(diff))); }, // List functions count: (list: T[]) => { return list.length; }, at: (list: T[], index: number) => { return list[index]; }, };