Refacto update formatters (#335)
This commit is contained in:
@@ -32,6 +32,7 @@ export default async function metrics({login, q}, {graphql, rest, plugins, conf,
|
|||||||
templates:Templates,
|
templates:Templates,
|
||||||
metadata:conf.metadata,
|
metadata:conf.metadata,
|
||||||
...utils,
|
...utils,
|
||||||
|
...utils.formatters({timeZone:q["config.timezone"]}),
|
||||||
...(/markdown/.test(convert)
|
...(/markdown/.test(convert)
|
||||||
? {
|
? {
|
||||||
imgb64(url, options) {
|
imgb64(url, options) {
|
||||||
|
|||||||
@@ -48,51 +48,60 @@ export function s(value, end = "") {
|
|||||||
return value !== 1 ? {y:"ies", "":"s"}[end] : end
|
return value !== 1 ? {y:"ies", "":"s"}[end] : end
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Formatter */
|
/**Formatters */
|
||||||
export function format(n, {sign = false, unit = true, fixed} = {}) {
|
export function formatters({timeZone} = {}) {
|
||||||
if (unit) {
|
//Check options
|
||||||
for (const {u, v} of [{u:"b", v:10 ** 9}, {u:"m", v:10 ** 6}, {u:"k", v:10 ** 3}]) {
|
try {
|
||||||
if (n / v >= 1)
|
new Date().toLocaleString("fr", {timeZoneName:"short", timeZone})
|
||||||
return `${(sign) && (n > 0) ? "+" : ""}${(n / v).toFixed(fixed ?? 2).substr(0, 4).replace(/[.]0*$/, "")}${u}`
|
}
|
||||||
|
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 */
|
/**Bytes formatter */
|
||||||
export function bytes(n) {
|
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}]) {
|
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)
|
if (n / v >= 1)
|
||||||
return `${(n / v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")} ${u}B`
|
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 */
|
/**Percentage formatter */
|
||||||
export function percentage(n, {rescale = true} = {}) {
|
format.percentage = function (n, {rescale = true} = {}) {
|
||||||
return `${
|
return `${
|
||||||
(n * (rescale ? 100 : 1)).toFixed(2)
|
(n * (rescale ? 100 : 1)).toFixed(2)
|
||||||
.replace(/(?<=[.])(?<decimal>[1-9]*)0+$/, "$<decimal>")
|
.replace(/(?<=[.])(?<decimal>[1-9]*)0+$/, "$<decimal>")
|
||||||
.replace(/[.]$/, "")
|
.replace(/[.]$/, "")
|
||||||
}%`
|
}%`
|
||||||
}
|
}
|
||||||
format.percentage = percentage
|
|
||||||
|
|
||||||
/**Text ellipsis formatter */
|
/**Text ellipsis formatter */
|
||||||
export function ellipsis(text, {length = 20} = {}) {
|
format.ellipsis = function(text, {length = 20} = {}) {
|
||||||
text = `${text}`
|
text = `${text}`
|
||||||
if (text.length < length)
|
if (text.length < length)
|
||||||
return text
|
return text
|
||||||
return `${text.substring(0, length)}…`
|
return `${text.substring(0, length)}…`
|
||||||
}
|
}
|
||||||
format.ellipsis = ellipsis
|
|
||||||
|
|
||||||
/**Date formatter */
|
/**Date formatter */
|
||||||
export function date(string, options) {
|
format.date = function(string, options) {
|
||||||
return new Intl.DateTimeFormat("en-GB", options).format(new Date(string))
|
return new Intl.DateTimeFormat("en-GB", {timeZone, ...options}).format(new Date(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
return {format}
|
||||||
}
|
}
|
||||||
format.date = date
|
|
||||||
|
|
||||||
/**Array shuffler */
|
/**Array shuffler */
|
||||||
export function shuffle(array) {
|
export function shuffle(array) {
|
||||||
|
|||||||
@@ -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))
|
.sort((a, b) => (order[b.rank] + b.progress * 0.99) - (order[a.rank] + a.progress * 0.99))
|
||||||
.map(({title, unlock, ...achievement}) => ({
|
.map(({title, unlock, ...achievement}) => ({
|
||||||
title:({S:`Master ${title.toLocaleLowerCase()}`, A:`Super ${title.toLocaleLowerCase()}`, B:`Great ${title.toLocaleLowerCase()}`}[achievement.rank] ?? title),
|
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,
|
...achievement,
|
||||||
}))
|
}))
|
||||||
.map(({icon, ...achievement}) => ({icon:icon.replace(/#primary/g, colors[achievement.rank][0]).replace(/#secondary/g, colors[achievement.rank][1]), ...achievement}))
|
.map(({icon, ...achievement}) => ({icon:icon.replace(/#primary/g, colors[achievement.rank][0]).replace(/#secondary/g, colors[achievement.rank][1]), ...achievement}))
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export default async function({login, q}, {conf, data, rest, graphql, plugins, q
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Total disk usage
|
//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
|
//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) ?? ""
|
computed.licenses.favorite = Object.entries(computed.licenses.used).sort(([_an, a], [_bn, b]) => b - a).slice(0, 1).map(([name, _value]) => name) ?? ""
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ export default async function({login, imports, data, q, account}, {enabled = fal
|
|||||||
name:track.name,
|
name:track.name,
|
||||||
artist:track.artists[0].name,
|
artist:track.artists[0].name,
|
||||||
artwork:track.album.images[0].url,
|
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
|
//Ensure no duplicate are added
|
||||||
for (const track of loaded) {
|
for (const track of loaded) {
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ export default async function({login, q, imports, data, account}, {enabled = fal
|
|||||||
//Load and format answers
|
//Load and format answers
|
||||||
console.debug(`metrics/compute/${login}/plugins > stackoverflow > querying api for ${key}`)
|
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}`)
|
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`)
|
console.debug(`metrics/compute/${login}/plugins > stackoverflow > loaded ${result[key].length} items`)
|
||||||
//Load related questions
|
//Load related questions
|
||||||
const ids = result[key].map(({question_id}) => question_id).filter(id => id)
|
const ids = result[key].map(({question_id}) => question_id).filter(id => id)
|
||||||
if (ids) {
|
if (ids) {
|
||||||
console.debug(`metrics/compute/${login}/plugins > stackoverflow > loading ${ids.length} related items`)
|
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}`)
|
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
|
//Load and format questions
|
||||||
console.debug(`metrics/compute/${login}/plugins > stackoverflow > querying api for ${key}`)
|
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}`)
|
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`)
|
console.debug(`metrics/compute/${login}/plugins > stackoverflow > loaded ${result[key].length} items`)
|
||||||
//Load related answers
|
//Load related answers
|
||||||
const ids = result[key].map(({accepted_answer_id}) => accepted_answer_id).filter(id => id)
|
const ids = result[key].map(({accepted_answer_id}) => accepted_answer_id).filter(id => id)
|
||||||
if (ids) {
|
if (ids) {
|
||||||
console.debug(`metrics/compute/${login}/plugins > stackoverflow > loading ${ids.length} related items`)
|
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}`)
|
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(/<!-- language: lang-(?<lang>\w+) -->\s*(?<snippet> {4}[\s\S]+?)(?=(?:<!-- end snippet -->)|(?:<!-- language: lang-))/g, "```$<lang>\n$<snippet>```")
|
return text.replace(/<!-- language: lang-(?<lang>\w+) -->\s*(?<snippet> {4}[\s\S]+?)(?=(?:<!-- end snippet -->)|(?:<!-- language: lang-))/g, "```$<lang>\n$<snippet>```")
|
||||||
},
|
},
|
||||||
/**Format answers */
|
/**Format answers */
|
||||||
async answer({body_markdown:body, score, up_vote_count:upvotes, down_vote_count:downvotes, is_accepted:accepted, comment_count:comments = 0, creation_date, owner:{display_name:author}, link, answer_id:id, question_id}, {imports, data, codelines}) {
|
async answer({body_markdown:body, score, up_vote_count:upvotes, down_vote_count:downvotes, is_accepted:accepted, comment_count:comments = 0, creation_date, owner:{display_name:author}, link, answer_id:id, question_id}, {imports, codelines}) {
|
||||||
const formatted = {
|
const formatted = {
|
||||||
type:"answer",
|
type:"answer",
|
||||||
body:await imports.markdown(format.code(imports.htmlunescape(body)), {codelines}),
|
body:await imports.markdown(format.code(imports.htmlunescape(body)), {codelines}),
|
||||||
@@ -89,7 +89,7 @@ const format = {
|
|||||||
accepted,
|
accepted,
|
||||||
comments,
|
comments,
|
||||||
author,
|
author,
|
||||||
created:imports.date(creation_date * 1000, {dateStyle:"short", timeZone:data.config.timezone?.name}),
|
created:imports.format.date(creation_date * 1000, {dateStyle:"short"}),
|
||||||
link,
|
link,
|
||||||
id,
|
id,
|
||||||
question_id,
|
question_id,
|
||||||
@@ -120,7 +120,7 @@ const format = {
|
|||||||
question_id:id,
|
question_id:id,
|
||||||
accepted_answer_id = null,
|
accepted_answer_id = null,
|
||||||
},
|
},
|
||||||
{imports, data, codelines},
|
{imports, codelines},
|
||||||
) {
|
) {
|
||||||
const formatted = {
|
const formatted = {
|
||||||
type:"question",
|
type:"question",
|
||||||
@@ -136,7 +136,7 @@ const format = {
|
|||||||
comments,
|
comments,
|
||||||
views,
|
views,
|
||||||
author,
|
author,
|
||||||
created:imports.date(creation_date * 1000, {dateStyle:"short", timeZone:data.config.timezone?.name}),
|
created:imports.format.date(creation_date * 1000, {dateStyle:"short"}),
|
||||||
link,
|
link,
|
||||||
id,
|
id,
|
||||||
accepted_answer_id,
|
accepted_answer_id,
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default async function({login, imports, data, q, account}, {enabled = fal
|
|||||||
|
|
||||||
//Format text
|
//Format text
|
||||||
console.debug(`metrics/compute/${login}/plugins > tweets > formatting tweet ${tweet.id}`)
|
console.debug(`metrics/compute/${login}/plugins > tweets > formatting tweet ${tweet.id}`)
|
||||||
tweet.createdAt = `${imports.date(tweet.created_at, {timeStyle:"short", timeZone:data.config.timezone?.name})} on ${imports.date(tweet.created_at, {dateStyle:"short", timeZone:data.config.timezone?.name})}`
|
tweet.createdAt = `${imports.format.date(tweet.created_at, {timeStyle:"short"})} on ${imports.format.date(tweet.created_at, {dateStyle:"short"})}`
|
||||||
tweet.text = imports.htmlescape(
|
tweet.text = imports.htmlescape(
|
||||||
//Escape tags
|
//Escape tags
|
||||||
imports.htmlescape(tweet.text, {"<":true, ">":true})
|
imports.htmlescape(tweet.text, {"<":true, ">":true})
|
||||||
|
|||||||
Reference in New Issue
Block a user