const axios = require("axios"); const wrap = require("word-wrap"); const themes = require("../themes"); const renderError = (message, secondaryMessage = "") => { return ` Something went wrong! file an issue at https://git.io/JJmN9 ${encodeHTML(message)} ${secondaryMessage} `; }; // https://stackoverflow.com/a/48073476/10629172 function encodeHTML(str) { return str .replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => { return "&#" + i.charCodeAt(0) + ";"; }) .replace(/\u0008/gim, ""); } function kFormatter(num) { return Math.abs(num) > 999 ? Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + "k" : Math.sign(num) * Math.abs(num); } function isValidHexColor(hexColor) { return new RegExp( /^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/ ).test(hexColor); } function parseBoolean(value) { if (value === "true") { return true; } else if (value === "false") { return false; } else { return value; } } function parseArray(str) { if (!str) return []; return str.split(","); } function clampValue(number, min, max) { return Math.max(min, Math.min(number, max)); } function fallbackColor(color, fallbackColor) { return (isValidHexColor(color) && `#${color}`) || fallbackColor; } function request(data, headers) { return axios({ url: "https://api.github.com/graphql", method: "post", headers, data, }); } /** * * @param {String[]} items * @param {Number} gap * @param {string} direction * * @description * Auto layout utility, allows us to layout things * vertically or horizontally with proper gaping */ function FlexLayout({ items, gap, direction }) { // filter() for filtering out empty strings return items.filter(Boolean).map((item, i) => { let transform = `translate(${gap * i}, 0)`; if (direction === "column") { transform = `translate(0, ${gap * i})`; } return `${item}`; }); } // returns theme based colors with proper overrides and defaults function getCardColors({ title_color, text_color, icon_color, bg_color, theme, fallbackTheme = "default", }) { const defaultTheme = themes[fallbackTheme]; const selectedTheme = themes[theme] || defaultTheme; // get the color provided by the user else the theme color // finally if both colors are invalid fallback to default theme const titleColor = fallbackColor( title_color || selectedTheme.title_color, "#" + defaultTheme.title_color ); const iconColor = fallbackColor( icon_color || selectedTheme.icon_color, "#" + defaultTheme.icon_color ); const textColor = fallbackColor( text_color || selectedTheme.text_color, "#" + defaultTheme.text_color ); const bgColor = fallbackColor( bg_color || selectedTheme.bg_color, "#" + defaultTheme.bg_color ); return { titleColor, iconColor, textColor, bgColor }; } function wrapTextMultiline(text, width = 60, maxLines = 3) { const wrapped = wrap(encodeHTML(text), { width }) .split("\n") // Split wrapped lines to get an array of lines .map((line) => line.trim()); // Remove leading and trailing whitespace of each line const lines = wrapped.slice(0, maxLines); // Only consider maxLines lines // Add "..." to the last line if the text exceeds maxLines if (wrapped.length > maxLines) { lines[maxLines - 1] += "..."; } // Remove empty lines if text fits in less than maxLines lines const multiLineText = lines.filter(Boolean); return multiLineText; } const noop = () => {}; // return console instance based on the environment const logger = process.env.NODE_ENV !== "test" ? console : { log: noop, error: noop }; const CONSTANTS = { THIRTY_MINUTES: 1800, TWO_HOURS: 7200, ONE_DAY: 86400, }; module.exports = { renderError, kFormatter, encodeHTML, isValidHexColor, request, parseArray, parseBoolean, fallbackColor, FlexLayout, getCardColors, clampValue, wrapTextMultiline, logger, CONSTANTS, };