//Setup export default async function({login, data, graphql, q, imports, queries, account}, {enabled = false} = {}) { //Plugin execution try { //Check if plugin is enabled and requirements are met if ((!enabled) || (!q.isocalendar)) return null //Load inputs let {duration} = imports.metadata.plugins.isocalendar.inputs({data, account, q}) //Compute start day const now = new Date() const start = new Date(now) if (duration === "full-year") start.setFullYear(now.getFullYear() - 1) else start.setHours(-24 * 180) //Compute padding to ensure last row is complete const padding = new Date(start) padding.setHours(-14 * 24) //Retrieve contribution calendar from graphql api console.debug(`metrics/compute/${login}/plugins > isocalendar > querying api`) const calendar = {} for (const [name, from, to] of [["padding", padding, start], ["weeks", start, now]]) { console.debug(`metrics/compute/${login}/plugins > isocalendar > loading ${name} from "${from.toISOString()}" to "${to.toISOString()}"`) const {user:{calendar:{contributionCalendar:{weeks}}}} = await graphql(queries.isocalendar.calendar({login, from:from.toISOString(), to:to.toISOString()})) calendar[name] = weeks } //Apply padding console.debug(`metrics/compute/${login}/plugins > isocalendar > applying padding`) const firstweek = calendar.weeks[0].contributionDays const padded = calendar.padding.flatMap(({contributionDays}) => contributionDays).filter(({date}) => !firstweek.map(({date}) => date).includes(date)) while (firstweek.length < 7) firstweek.unshift(padded.pop()) //Compute the highest contributions in a day, streaks and average commits per day console.debug(`metrics/compute/${login}/plugins > isocalendar > computing stats`) const {streak, max, average} = await statistics({login, data, graphql, queries}) //Compute SVG console.debug(`metrics/compute/${login}/plugins > isocalendar > computing svg render`) const size = 6 let i = 0, j = 0 let svg = ` ${ [1, 2].map(k => ` ${[..."RGB"].map(channel => ``).join("")} ` ) .join("") } ` //Iterate through weeks for (const week of calendar.weeks) { svg += `` j = 0 //Iterate through days for (const day of week.contributionDays) { const ratio = day.contributionCount / max svg += ` ` j++ } svg += "" i++ } svg += "" //Results return {streak, max, average, svg, duration} } //Handle errors catch (error) { if (error.error?.message) throw error throw {error:{message:"An error occured", instance:error}} } } /**Compute max and current streaks */ async function statistics({login, data, graphql, queries}) { let average = 0, max = 0, streak = {max:0, current:0}, values = [] const now = new Date() for (let from = new Date(data.user.createdAt); from < now;) { //Load contribution calendar let to = new Date(from) to.setFullYear(to.getFullYear() + 1) if (to > now) to = now console.debug(`metrics/compute/${login}/plugins > isocalendar > loading calendar from "${from.toISOString()}" to "${to.toISOString()}"`) const {user:{calendar:{contributionCalendar:{weeks}}}} = await graphql(queries.isocalendar.calendar({login, from:from.toISOString(), to:to.toISOString()})) from = to //Compute streaks for (const week of weeks) { for (const day of week.contributionDays) { values.push(day.contributionCount) max = Math.max(max, day.contributionCount) streak.current = day.contributionCount ? streak.current + 1 : 0 streak.max = Math.max(streak.max, streak.current) } } } average = (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2).replace(/[.]0+$/, "") return {streak, max, average} }