From a7307fe72c82b18882b8c0a7a14d8a6714c5b6bd Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Fri, 28 May 2021 14:42:36 +0200 Subject: [PATCH] Refacto update formatters (#335) --- source/app/metrics/index.mjs | 1 + source/app/metrics/utils.mjs | 83 ++++++++++++++------------ source/plugins/achievements/index.mjs | 2 +- source/plugins/core/index.mjs | 2 +- source/plugins/music/index.mjs | 2 +- source/plugins/stackoverflow/index.mjs | 16 ++--- source/plugins/tweets/index.mjs | 2 +- 7 files changed, 59 insertions(+), 49 deletions(-) diff --git a/source/app/metrics/index.mjs b/source/app/metrics/index.mjs index 9c8a265f..92aff4b4 100644 --- a/source/app/metrics/index.mjs +++ b/source/app/metrics/index.mjs @@ -32,6 +32,7 @@ export default async function metrics({login, q}, {graphql, rest, plugins, conf, templates:Templates, metadata:conf.metadata, ...utils, + ...utils.formatters({timeZone:q["config.timezone"]}), ...(/markdown/.test(convert) ? { imgb64(url, options) { diff --git a/source/app/metrics/utils.mjs b/source/app/metrics/utils.mjs index 76c0dd9d..6fddb230 100644 --- a/source/app/metrics/utils.mjs +++ b/source/app/metrics/utils.mjs @@ -48,51 +48,60 @@ export function s(value, end = "") { return value !== 1 ? {y:"ies", "":"s"}[end] : end } -/**Formatter */ -export function format(n, {sign = false, unit = true, fixed} = {}) { - if (unit) { - for (const {u, v} of [{u:"b", v:10 ** 9}, {u:"m", v:10 ** 6}, {u:"k", v:10 ** 3}]) { - if (n / v >= 1) - return `${(sign) && (n > 0) ? "+" : ""}${(n / v).toFixed(fixed ?? 2).substr(0, 4).replace(/[.]0*$/, "")}${u}` +/**Formatters */ +export function formatters({timeZone} = {}) { + //Check options + try { + new Date().toLocaleString("fr", {timeZoneName:"short", timeZone}) + } + catch { + timeZone = undefined + } + + /**Formatter */ + const format = function(n, {sign = false, unit = true, fixed} = {}) { + if (unit) { + for (const {u, v} of [{u:"b", v:10 ** 9}, {u:"m", v:10 ** 6}, {u:"k", v:10 ** 3}]) { + if (n / v >= 1) + return `${(sign) && (n > 0) ? "+" : ""}${(n / v).toFixed(fixed ?? 2).substr(0, 4).replace(/[.]0*$/, "")}${u}` + } } + return `${(sign) && (n > 0) ? "+" : ""}${fixed ? n.toFixed(fixed) : n}` } - return `${(sign) && (n > 0) ? "+" : ""}${fixed ? n.toFixed(fixed) : n}` -} -/**Bytes formatter */ -export function bytes(n) { - for (const {u, v} of [{u:"E", v:10 ** 18}, {u:"P", v:10 ** 15}, {u:"T", v:10 ** 12}, {u:"G", v:10 ** 9}, {u:"M", v:10 ** 6}, {u:"k", v:10 ** 3}]) { - if (n / v >= 1) - return `${(n / v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")} ${u}B` + /**Bytes formatter */ + format.bytes = function (n) { + for (const {u, v} of [{u:"E", v:10 ** 18}, {u:"P", v:10 ** 15}, {u:"T", v:10 ** 12}, {u:"G", v:10 ** 9}, {u:"M", v:10 ** 6}, {u:"k", v:10 ** 3}]) { + if (n / v >= 1) + return `${(n / v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")} ${u}B` + } + return `${n} byte${n > 1 ? "s" : ""}` } - return `${n} byte${n > 1 ? "s" : ""}` -} -format.bytes = bytes -/**Percentage formatter */ -export function percentage(n, {rescale = true} = {}) { - return `${ - (n * (rescale ? 100 : 1)).toFixed(2) - .replace(/(?<=[.])(?[1-9]*)0+$/, "$") - .replace(/[.]$/, "") - }%` -} -format.percentage = percentage + /**Percentage formatter */ + format.percentage = function (n, {rescale = true} = {}) { + return `${ + (n * (rescale ? 100 : 1)).toFixed(2) + .replace(/(?<=[.])(?[1-9]*)0+$/, "$") + .replace(/[.]$/, "") + }%` + } -/**Text ellipsis formatter */ -export function ellipsis(text, {length = 20} = {}) { - text = `${text}` - if (text.length < length) - return text - return `${text.substring(0, length)}…` -} -format.ellipsis = ellipsis + /**Text ellipsis formatter */ + format.ellipsis = function(text, {length = 20} = {}) { + text = `${text}` + if (text.length < length) + return text + return `${text.substring(0, length)}…` + } -/**Date formatter */ -export function date(string, options) { - return new Intl.DateTimeFormat("en-GB", options).format(new Date(string)) + /**Date formatter */ + format.date = function(string, options) { + return new Intl.DateTimeFormat("en-GB", {timeZone, ...options}).format(new Date(string)) + } + + return {format} } -format.date = date /**Array shuffler */ export function shuffle(array) { diff --git a/source/plugins/achievements/index.mjs b/source/plugins/achievements/index.mjs index ff844072..75506425 100644 --- a/source/plugins/achievements/index.mjs +++ b/source/plugins/achievements/index.mjs @@ -27,7 +27,7 @@ export default async function({login, q, imports, data, computed, graphql, queri .sort((a, b) => (order[b.rank] + b.progress * 0.99) - (order[a.rank] + a.progress * 0.99)) .map(({title, unlock, ...achievement}) => ({ title:({S:`Master ${title.toLocaleLowerCase()}`, A:`Super ${title.toLocaleLowerCase()}`, B:`Great ${title.toLocaleLowerCase()}`}[achievement.rank] ?? title), - unlock:!/invalid date/i.test(unlock) ? `${imports.date(unlock, {timeStyle:"short", timeZone:data.config.timezone?.name})} on ${imports.date(unlock, {dateStyle:"short", timeZone:data.config.timezone?.name})}` : null, + unlock:!/invalid date/i.test(unlock) ? `${imports.format.date(unlock, {timeStyle:"short"})} on ${imports.format.date(unlock, {dateStyle:"short"})}` : null, ...achievement, })) .map(({icon, ...achievement}) => ({icon:icon.replace(/#primary/g, colors[achievement.rank][0]).replace(/#secondary/g, colors[achievement.rank][1]), ...achievement})) diff --git a/source/plugins/core/index.mjs b/source/plugins/core/index.mjs index 05db6c27..796862cc 100644 --- a/source/plugins/core/index.mjs +++ b/source/plugins/core/index.mjs @@ -73,7 +73,7 @@ export default async function({login, q}, {conf, data, rest, graphql, plugins, q } //Total disk usage - computed.diskUsage = `${imports.bytes(data.user.repositories.totalDiskUsage * 1000)}` + computed.diskUsage = `${imports.format.bytes(data.user.repositories.totalDiskUsage * 1000)}` //Compute licenses stats computed.licenses.favorite = Object.entries(computed.licenses.used).sort(([_an, a], [_bn, b]) => b - a).slice(0, 1).map(([name, _value]) => name) ?? "" diff --git a/source/plugins/music/index.mjs b/source/plugins/music/index.mjs index 0d39a20a..a8521e34 100644 --- a/source/plugins/music/index.mjs +++ b/source/plugins/music/index.mjs @@ -164,7 +164,7 @@ export default async function({login, imports, data, q, account}, {enabled = fal name:track.name, artist:track.artists[0].name, artwork:track.album.images[0].url, - played_at:played_at ? `${imports.date(played_at, {timeStyle:"short", timeZone:data.config.timezone?.name})} on ${imports.date(played_at, {dateStyle:"short", timeZone:data.config.timezone?.name})}` : null, + played_at:played_at ? `${imports.format.date(played_at, {timeStyle:"short"})} on ${imports.format.date(played_at, {dateStyle:"short"})}` : null, })) //Ensure no duplicate are added for (const track of loaded) { diff --git a/source/plugins/stackoverflow/index.mjs b/source/plugins/stackoverflow/index.mjs index 186dcec9..34637d8a 100644 --- a/source/plugins/stackoverflow/index.mjs +++ b/source/plugins/stackoverflow/index.mjs @@ -32,14 +32,14 @@ export default async function({login, q, imports, data, account}, {enabled = fal //Load and format answers console.debug(`metrics/compute/${login}/plugins > stackoverflow > querying api for ${key}`) const {data:{items}} = await imports.axios.get(`${api.user}/answers?site=stackoverflow&pagesize=${limit}&filter=${filters.answer}&${sort}`) - result[key] = await Promise.all(items.map(item => format.answer(item, {imports, data, codelines}))) + result[key] = await Promise.all(items.map(item => format.answer(item, {imports, codelines}))) console.debug(`metrics/compute/${login}/plugins > stackoverflow > loaded ${result[key].length} items`) //Load related questions const ids = result[key].map(({question_id}) => question_id).filter(id => id) if (ids) { console.debug(`metrics/compute/${login}/plugins > stackoverflow > loading ${ids.length} related items`) const {data:{items}} = await imports.axios.get(`${api.base}/questions/${ids.join(";")}?site=stackoverflow&filter=${filters.question}`) - await Promise.all(items.map(item => format.question(item, {imports, data, codelines}))) + await Promise.all(items.map(item => format.question(item, {imports, codelines}))) } } @@ -48,14 +48,14 @@ export default async function({login, q, imports, data, account}, {enabled = fal //Load and format questions console.debug(`metrics/compute/${login}/plugins > stackoverflow > querying api for ${key}`) const {data:{items}} = await imports.axios.get(`${api.user}/questions?site=stackoverflow&pagesize=${limit}&filter=${filters.question}&${sort}`) - result[key] = await Promise.all(items.map(item => format.question(item, {imports, data, codelines}))) + result[key] = await Promise.all(items.map(item => format.question(item, {imports, codelines}))) console.debug(`metrics/compute/${login}/plugins > stackoverflow > loaded ${result[key].length} items`) //Load related answers const ids = result[key].map(({accepted_answer_id}) => accepted_answer_id).filter(id => id) if (ids) { console.debug(`metrics/compute/${login}/plugins > stackoverflow > loading ${ids.length} related items`) const {data:{items}} = await imports.axios.get(`${api.base}/answers/${ids.join(";")}?site=stackoverflow&filter=${filters.answer}`) - await Promise.all(items.map(item => format.answer(item, {imports, data, codelines}))) + await Promise.all(items.map(item => format.answer(item, {imports, codelines}))) } } @@ -79,7 +79,7 @@ const format = { return text.replace(/\s*(? {4}[\s\S]+?)(?=(?:)|(?: