diff --git a/backend/api-renamed/gist.js b/backend/api-renamed/gist.js index ad9bf15d..da469701 100644 --- a/backend/api-renamed/gist.js +++ b/backend/api-renamed/gist.js @@ -1,6 +1,6 @@ // @ts-check -import { renderError, parseBoolean } from "../src/common/utils.js"; +import { renderError } from "../src/common/utils.js"; import { isLocaleAvailable } from "../src/translations.js"; import { renderGistCard } from "../src/cards/gist.js"; import { fetchGist } from "../src/fetchers/gist.js"; @@ -16,6 +16,7 @@ import { MissingParamError, retrieveSecondaryMessage, } from "../src/common/error.js"; +import { parseBoolean } from "../src/common/ops.js"; // @ts-ignore export default async (req, res) => { diff --git a/backend/api-renamed/index.js b/backend/api-renamed/index.js index 9a5cad9d..7bcdc8eb 100644 --- a/backend/api-renamed/index.js +++ b/backend/api-renamed/index.js @@ -8,10 +8,9 @@ import { setErrorCacheHeaders, } from "../src/common/cache.js"; import { whitelist } from "../src/common/envs.js"; +import { parseArray, parseBoolean } from "../src/common/ops.js"; import { CONSTANTS, - parseArray, - parseBoolean, renderError, } from "../src/common/utils.js"; import { fetchStats } from "../src/fetchers/stats.js"; diff --git a/backend/api-renamed/pin.js b/backend/api-renamed/pin.js index 7c0b3d9e..df2140e2 100644 --- a/backend/api-renamed/pin.js +++ b/backend/api-renamed/pin.js @@ -12,7 +12,8 @@ import { MissingParamError, retrieveSecondaryMessage, } from "../src/common/error.js"; -import { parseArray, parseBoolean, renderError } from "../src/common/utils.js"; +import { parseBoolean } from "../src/common/ops.js"; +import { parseArray, renderError } from "../src/common/utils.js"; import { fetchRepo } from "../src/fetchers/repo.js"; import { isLocaleAvailable } from "../src/translations.js"; import { storeRequest } from "../src/common/database.js"; diff --git a/backend/api-renamed/status/pat-info.js b/backend/api-renamed/status/pat-info.js index 9d2a3b7f..998d7cbc 100644 --- a/backend/api-renamed/status/pat-info.js +++ b/backend/api-renamed/status/pat-info.js @@ -9,7 +9,7 @@ import { request } from "../../src/common/http.js"; import { logger } from "../../src/common/log.js"; -import { dateDiff } from "../../src/common/utils.js"; +import { dateDiff } from "../../src/common/ops.js"; export const RATE_LIMIT_SECONDS = 60 * 3; // 1 request per 3 minutes diff --git a/backend/api-renamed/top-langs.js b/backend/api-renamed/top-langs.js index 19ac3cc3..0ddd177b 100644 --- a/backend/api-renamed/top-langs.js +++ b/backend/api-renamed/top-langs.js @@ -12,7 +12,8 @@ import { MissingParamError, retrieveSecondaryMessage, } from "../src/common/error.js"; -import { parseArray, parseBoolean, renderError } from "../src/common/utils.js"; +import { parseArray, parseBoolean } from "../src/common/ops.js"; +import { renderError } from "../src/common/utils.js"; import { fetchTopLanguages } from "../src/fetchers/top-languages.js"; import { isLocaleAvailable } from "../src/translations.js"; import { storeRequest } from "../src/common/database.js"; diff --git a/backend/api-renamed/wakatime.js b/backend/api-renamed/wakatime.js index 909a605d..d9495b07 100644 --- a/backend/api-renamed/wakatime.js +++ b/backend/api-renamed/wakatime.js @@ -1,7 +1,7 @@ // @ts-check import { renderWakatimeCard } from "../src/cards/wakatime.js"; -import { parseArray, parseBoolean, renderError } from "../src/common/utils.js"; +import { renderError } from "../src/common/utils.js"; import { fetchWakatimeStats } from "../src/fetchers/wakatime.js"; import { isLocaleAvailable } from "../src/translations.js"; import { storeRequest } from "../src/common/database.js"; @@ -16,6 +16,7 @@ import { MissingParamError, retrieveSecondaryMessage, } from "../src/common/error.js"; +import { parseArray, parseBoolean } from "../src/common/ops.js"; // @ts-ignore export default async (req, res) => { diff --git a/backend/src/cards/gist.js b/backend/src/cards/gist.js index f8e7ab72..ff072bc8 100644 --- a/backend/src/cards/gist.js +++ b/backend/src/cards/gist.js @@ -1,7 +1,6 @@ // @ts-check import { - parseEmojis, encodeHTML, measureText, flexLayout, @@ -13,6 +12,7 @@ import { getCardColors } from "../common/color.js"; import { kFormatter, wrapTextMultiline } from "../common/fmt.js"; import { icons } from "../common/icons.js"; import languageColors from "../common/languageColors.json" with { type: "json" }; +import { parseEmojis } from "../common/ops.js"; const ICON_SIZE = 16; diff --git a/backend/src/cards/repo.js b/backend/src/cards/repo.js index fe58926b..995a0c98 100644 --- a/backend/src/cards/repo.js +++ b/backend/src/cards/repo.js @@ -5,14 +5,13 @@ import { getCardColors } from "../common/color.js"; import { kFormatter, wrapTextMultiline } from "../common/fmt.js"; import { I18n } from "../common/I18n.js"; import { icons } from "../common/icons.js"; +import { clampValue, parseEmojis } from "../common/ops.js"; import { encodeHTML, flexLayout, measureText, - parseEmojis, iconWithLabel, createLanguageNode, - clampValue, buildSearchFilter, } from "../common/utils.js"; import { repoCardLocales } from "../translations.js"; diff --git a/backend/src/cards/stats.js b/backend/src/cards/stats.js index 5b13ff9c..3d9e4382 100644 --- a/backend/src/cards/stats.js +++ b/backend/src/cards/stats.js @@ -6,12 +6,8 @@ import { CustomError } from "../common/error.js"; import { kFormatter } from "../common/fmt.js"; import { I18n } from "../common/I18n.js"; import { icons, rankIcon } from "../common/icons.js"; -import { - clampValue, - flexLayout, - measureText, - buildSearchFilter, -} from "../common/utils.js"; +import { clampValue } from "../common/ops.js"; +import { flexLayout, measureText, buildSearchFilter } from "../common/utils.js"; import { statCardLocales, wakatimeCardLocales } from "../translations.js"; const CARD_MIN_WIDTH = 287; diff --git a/backend/src/cards/top-languages.js b/backend/src/cards/top-languages.js index ec91fcc9..7d4ac977 100644 --- a/backend/src/cards/top-languages.js +++ b/backend/src/cards/top-languages.js @@ -5,13 +5,8 @@ import { getCardColors } from "../common/color.js"; import { createProgressNode } from "../common/createProgressNode.js"; import { formatBytes } from "../common/fmt.js"; import { I18n } from "../common/I18n.js"; -import { - chunkArray, - clampValue, - flexLayout, - lowercaseTrim, - measureText, -} from "../common/utils.js"; +import { chunkArray, clampValue, lowercaseTrim } from "../common/ops.js"; +import { flexLayout, measureText } from "../common/utils.js"; import { langCardLocales } from "../translations.js"; const DEFAULT_CARD_WIDTH = 300; diff --git a/backend/src/cards/wakatime.js b/backend/src/cards/wakatime.js index ec3bda1c..7b95e349 100644 --- a/backend/src/cards/wakatime.js +++ b/backend/src/cards/wakatime.js @@ -4,7 +4,8 @@ import { Card } from "../common/Card.js"; import { getCardColors } from "../common/color.js"; import { createProgressNode } from "../common/createProgressNode.js"; import { I18n } from "../common/I18n.js"; -import { clampValue, flexLayout, lowercaseTrim } from "../common/utils.js"; +import { clampValue, lowercaseTrim } from "../common/ops.js"; +import { flexLayout } from "../common/utils.js"; import { wakatimeCardLocales } from "../translations.js"; import languageColors from "../common/languageColors.json" with { type: "json" }; diff --git a/backend/src/common/cache.js b/backend/src/common/cache.js index b5e8e432..6fe2ea59 100644 --- a/backend/src/common/cache.js +++ b/backend/src/common/cache.js @@ -1,6 +1,6 @@ // @ts-check -import { clampValue } from "./utils.js"; +import { clampValue } from "./ops.js"; const MIN = 60; const HOUR = 60 * MIN; diff --git a/backend/src/common/createProgressNode.js b/backend/src/common/createProgressNode.js index 22a7ad65..e63944e7 100644 --- a/backend/src/common/createProgressNode.js +++ b/backend/src/common/createProgressNode.js @@ -1,6 +1,6 @@ // @ts-check -import { clampValue } from "./utils.js"; +import { clampValue } from "./ops.js"; /** * Create a node to indicate progress in percentage along a horizontal line. diff --git a/backend/src/common/index.js b/backend/src/common/index.js index 84638a6f..12fe563b 100644 --- a/backend/src/common/index.js +++ b/backend/src/common/index.js @@ -10,12 +10,6 @@ export { ERROR_CARD_LENGTH, renderError, encodeHTML, - parseBoolean, - parseArray, - clampValue, flexLayout, measureText, - lowercaseTrim, - chunkArray, - parseEmojis, } from "./utils.js"; diff --git a/backend/src/common/ops.js b/backend/src/common/ops.js new file mode 100644 index 00000000..b4db6e60 --- /dev/null +++ b/backend/src/common/ops.js @@ -0,0 +1,124 @@ +// @ts-check + +import toEmoji from "emoji-name-map"; + +/** + * Returns boolean if value is either "true" or "false" else the value as it is. + * + * @param {string | boolean} value The value to parse. + * @returns {boolean | undefined } The parsed value. + */ +const parseBoolean = (value) => { + if (typeof value === "boolean") { + return value; + } + + if (typeof value === "string") { + if (value.toLowerCase() === "true") { + return true; + } else if (value.toLowerCase() === "false") { + return false; + } + } + return undefined; +}; + +/** + * Parse string to array of strings. + * + * @param {string} str The string to parse. + * @returns {string[]} The array of strings. + */ +const parseArray = (str) => { + if (!str) { + return []; + } + return str.split(","); +}; + +/** + * Clamp the given number between the given range. + * + * @param {number} number The number to clamp. + * @param {number} min The minimum value. + * @param {number} max The maximum value. + * @returns {number} The clamped number. + */ +const clampValue = (number, min, max) => { + // @ts-ignore + if (Number.isNaN(parseInt(number, 10))) { + return min; + } + return Math.max(min, Math.min(number, max)); +}; + +/** + * Lowercase and trim string. + * + * @param {string} name String to lowercase and trim. + * @returns {string} Lowercased and trimmed string. + */ +const lowercaseTrim = (name) => name.toLowerCase().trim(); + +/** + * Split array of languages in two columns. + * + * @template T Language object. + * @param {Array} arr Array of languages. + * @param {number} perChunk Number of languages per column. + * @returns {Array} Array of languages split in two columns. + */ +const chunkArray = (arr, perChunk) => { + return arr.reduce((resultArray, item, index) => { + const chunkIndex = Math.floor(index / perChunk); + + if (!resultArray[chunkIndex]) { + // @ts-ignore + resultArray[chunkIndex] = []; // start a new chunk + } + + // @ts-ignore + resultArray[chunkIndex].push(item); + + return resultArray; + }, []); +}; + +/** + * Parse emoji from string. + * + * @param {string} str String to parse emoji from. + * @returns {string} String with emoji parsed. + */ +const parseEmojis = (str) => { + if (!str) { + throw new Error("[parseEmoji]: str argument not provided"); + } + return str.replace(/:\w+:/gm, (emoji) => { + return toEmoji.get(emoji) || ""; + }); +}; + +/** + * Get diff in minutes between two dates. + * + * @param {Date} d1 First date. + * @param {Date} d2 Second date. + * @returns {number} Number of minutes between the two dates. + */ +const dateDiff = (d1, d2) => { + const date1 = new Date(d1); + const date2 = new Date(d2); + const diff = date1.getTime() - date2.getTime(); + return Math.round(diff / (1000 * 60)); +}; + +export { + parseBoolean, + parseArray, + clampValue, + lowercaseTrim, + chunkArray, + parseEmojis, + dateDiff, +}; diff --git a/backend/src/common/utils.js b/backend/src/common/utils.js index f567ff5c..a4b5573c 100644 --- a/backend/src/common/utils.js +++ b/backend/src/common/utils.js @@ -1,6 +1,5 @@ // @ts-check -import toEmoji from "emoji-name-map"; import { SECONDARY_ERROR_MESSAGES, TRY_AGAIN_LATER } from "./error.js"; import { getCardColors } from "./color.js"; @@ -76,56 +75,6 @@ const iconWithLabel = (icon, label, testid, iconSize) => { return flexLayout({ items: [iconSvg, text], gap: 20 }).join(""); }; -/** - * Returns boolean if value is either "true" or "false" else the value as it is. - * - * @param {string | boolean} value The value to parse. - * @returns {boolean | undefined } The parsed value. - */ -const parseBoolean = (value) => { - if (typeof value === "boolean") { - return value; - } - - if (typeof value === "string") { - if (value.toLowerCase() === "true") { - return true; - } else if (value.toLowerCase() === "false") { - return false; - } - } - return undefined; -}; - -/** - * Parse string to array of strings. - * - * @param {string} str The string to parse. - * @returns {string[]} The array of strings. - */ -const parseArray = (str) => { - if (!str) { - return []; - } - return str.split(","); -}; - -/** - * Clamp the given number between the given range. - * - * @param {number} number The number to clamp. - * @param {number} min The minimum value. - * @param {number} max The maximum value. - * @returns {number} The clamped number. - */ -const clampValue = (number, min, max) => { - // @ts-ignore - if (Number.isNaN(parseInt(number, 10))) { - return min; - } - return Math.max(min, Math.min(number, max)); -}; - const buildSearchFilter = (repos = [], owners = []) => { let repoFilter = Array.isArray(repos) && repos.length > 0 @@ -267,52 +216,6 @@ const measureText = (str, fontSize = 10) => { ); }; -/** - * Lowercase and trim string. - * - * @param {string} name String to lowercase and trim. - * @returns {string} Lowercased and trimmed string. - */ -const lowercaseTrim = (name) => name.toLowerCase().trim(); - -/** - * Split array of languages in two columns. - * - * @template T Language object. - * @param {Array} arr Array of languages. - * @param {number} perChunk Number of languages per column. - * @returns {Array} Array of languages split in two columns. - */ -const chunkArray = (arr, perChunk) => { - return arr.reduce((resultArray, item, index) => { - const chunkIndex = Math.floor(index / perChunk); - - if (!resultArray[chunkIndex]) { - // @ts-ignore - resultArray[chunkIndex] = []; // start a new chunk - } - - // @ts-ignore - resultArray[chunkIndex].push(item); - - return resultArray; - }, []); -}; - -/** - * Parse emoji from string. - * - * @param {string} str String to parse emoji from. - * @returns {string} String with emoji parsed. - */ -const parseEmojis = (str) => { - if (!str) { - throw new Error("[parseEmoji]: str argument not provided"); - } - return str.replace(/:\w+:/gm, (emoji) => { - return toEmoji.get(emoji) || ""; - }); -}; /** * Parse owner affiliations. * @@ -344,36 +247,15 @@ const parseOwnerAffiliations = (affiliations) => { return affiliations; }; -/** - * Get diff in minutes between two dates. - * - * @param {Date} d1 First date. - * @param {Date} d2 Second date. - * @returns {number} Number of minutes between the two dates. - */ -const dateDiff = (d1, d2) => { - const date1 = new Date(d1); - const date2 = new Date(d2); - const diff = date1.getTime() - date2.getTime(); - return Math.round(diff / (1000 * 60)); -}; - export { ERROR_CARD_LENGTH, renderError, createLanguageNode, iconWithLabel, encodeHTML, - parseBoolean, - parseArray, - clampValue, buildSearchFilter, flexLayout, OWNER_AFFILIATIONS, measureText, - lowercaseTrim, - chunkArray, - parseEmojis, parseOwnerAffiliations, - dateDiff, }; diff --git a/backend/tests/utils.test.js b/backend/tests/utils.test.js index 0b37e45a..a079841c 100644 --- a/backend/tests/utils.test.js +++ b/backend/tests/utils.test.js @@ -3,7 +3,8 @@ import { describe, expect, it } from "@jest/globals"; import { queryByTestId } from "@testing-library/dom"; import "@testing-library/jest-dom"; -import { encodeHTML, parseBoolean, renderError } from "../src/common/utils.js"; +import { encodeHTML, renderError } from "../src/common/utils.js"; +import { parseBoolean } from "../src/common/ops.js"; describe("Test utils.js", () => { it("should test parseBoolean", () => {