refactor: jsdoc in utils & minor changes (#1377)

* refactor: jsdoc in utils & minor changes

* chore: jsdoc Card class

* chore: jsdoc for getStyles
This commit is contained in:
Anurag Hazra 2021-10-10 20:41:40 +05:30 committed by GitHub
parent d0ab2ff030
commit 02ebd3243b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 41 deletions

View file

@ -34,8 +34,6 @@ module.exports = async (req, res) => {
border_radius, border_radius,
border_color, border_color,
} = req.query; } = req.query;
let stats;
res.setHeader("Content-Type", "image/svg+xml"); res.setHeader("Content-Type", "image/svg+xml");
if (blacklist.includes(username)) { if (blacklist.includes(username)) {
@ -47,7 +45,7 @@ module.exports = async (req, res) => {
} }
try { try {
stats = await fetchStats( const stats = await fetchStats(
username, username,
parseBoolean(count_private), parseBoolean(count_private),
parseBoolean(include_all_commits), parseBoolean(include_all_commits),

View file

@ -27,8 +27,6 @@ module.exports = async (req, res) => {
border_color, border_color,
} = req.query; } = req.query;
let repoData;
res.setHeader("Content-Type", "image/svg+xml"); res.setHeader("Content-Type", "image/svg+xml");
if (blacklist.includes(username)) { if (blacklist.includes(username)) {
@ -40,7 +38,7 @@ module.exports = async (req, res) => {
} }
try { try {
repoData = await fetchRepo(username, repo); const repoData = await fetchRepo(username, repo);
let cacheSeconds = clampValue( let cacheSeconds = clampValue(
parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10), parseInt(cache_seconds || CONSTANTS.TWO_HOURS, 10),

View file

@ -31,8 +31,6 @@ module.exports = async (req, res) => {
border_radius, border_radius,
border_color, border_color,
} = req.query; } = req.query;
let topLangs;
res.setHeader("Content-Type", "image/svg+xml"); res.setHeader("Content-Type", "image/svg+xml");
if (blacklist.includes(username)) { if (blacklist.includes(username)) {
@ -44,7 +42,7 @@ module.exports = async (req, res) => {
} }
try { try {
topLangs = await fetchTopLanguages( const topLangs = await fetchTopLanguages(
username, username,
parseArray(exclude_repo), parseArray(exclude_repo),
parseArray(hide), parseArray(hide),

View file

@ -110,15 +110,14 @@ const renderRepoCard = (repo, options = {}) => {
}); });
// returns theme based colors with proper overrides and defaults // returns theme based colors with proper overrides and defaults
const { titleColor, textColor, iconColor, bgColor, borderColor } = const colors = getCardColors({
getCardColors({ title_color,
title_color, icon_color,
icon_color, text_color,
text_color, bg_color,
bg_color, border_color,
border_color, theme,
theme, });
});
const svgLanguage = primaryLanguage const svgLanguage = primaryLanguage
? createLanguageNode(langName, langColor) ? createLanguageNode(langName, langColor)
@ -145,22 +144,16 @@ const renderRepoCard = (repo, options = {}) => {
width: 400, width: 400,
height, height,
border_radius, border_radius,
colors: { colors,
titleColor,
textColor,
iconColor,
bgColor,
borderColor,
},
}); });
card.disableAnimations(); card.disableAnimations();
card.setHideBorder(hide_border); card.setHideBorder(hide_border);
card.setHideTitle(false); card.setHideTitle(false);
card.setCSS(` card.setCSS(`
.description { font: 400 13px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} } .description { font: 400 13px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }
.gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} } .gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${colors.textColor} }
.icon { fill: ${iconColor} } .icon { fill: ${colors.iconColor} }
.badge { font: 600 11px 'Segoe UI', Ubuntu, Sans-Serif; } .badge { font: 600 11px 'Segoe UI', Ubuntu, Sans-Serif; }
.badge rect { opacity: 0.2 } .badge rect { opacity: 0.2 }
`); `);
@ -168,9 +161,9 @@ const renderRepoCard = (repo, options = {}) => {
return card.render(` return card.render(`
${ ${
isTemplate isTemplate
? getBadgeSVG(i18n.t("repocard.template"), textColor) ? getBadgeSVG(i18n.t("repocard.template"), colors.textColor)
: isArchived : isArchived
? getBadgeSVG(i18n.t("repocard.archived"), textColor) ? getBadgeSVG(i18n.t("repocard.archived"), colors.textColor)
: "" : ""
} }

View file

@ -2,6 +2,16 @@ const { getAnimations } = require("../getStyles");
const { flexLayout, encodeHTML } = require("../common/utils"); const { flexLayout, encodeHTML } = require("../common/utils");
class Card { class Card {
/**
* @param {object} args
* @param {number?=} args.width
* @param {number?=} args.height
* @param {number?=} args.border_radius
* @param {string?=} args.customTitle
* @param {string?=} args.defaultTitle
* @param {string?=} args.titlePrefixIcon
* @param {ReturnType<import('../common/utils').getCardColors>?=} args.colors
*/
constructor({ constructor({
width = 100, width = 100,
height = 100, height = 100,
@ -38,14 +48,23 @@ class Card {
this.animations = false; this.animations = false;
} }
/**
* @param {string} value
*/
setCSS(value) { setCSS(value) {
this.css = value; this.css = value;
} }
/**
* @param {boolean} value
*/
setHideBorder(value) { setHideBorder(value) {
this.hideBorder = value; this.hideBorder = value;
} }
/**
* @param {boolean} value
*/
setHideTitle(value) { setHideTitle(value) {
this.hideTitle = value; this.hideTitle = value;
if (value) { if (value) {
@ -53,6 +72,9 @@ class Card {
} }
} }
/**
* @param {string} text
*/
setTitle(text) { setTitle(text) {
this.title = text; this.title = text;
} }
@ -114,6 +136,9 @@ class Card {
: ""; : "";
} }
/**
* @param {string} body
*/
render(body) { render(body) {
return ` return `
<svg <svg

View file

@ -1,8 +1,14 @@
// @ts-check
const axios = require("axios"); const axios = require("axios");
const wrap = require("word-wrap"); const wrap = require("word-wrap");
const themes = require("../../themes"); const themes = require("../../themes");
const toEmoji = require("emoji-name-map"); const toEmoji = require("emoji-name-map");
/**
* @param {string} message
* @param {string} secondaryMessage
* @returns {string}
*/
const renderError = (message, secondaryMessage = "") => { const renderError = (message, secondaryMessage = "") => {
return ` return `
<svg width="495" height="120" viewBox="0 0 495 120" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="495" height="120" viewBox="0 0 495 120" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -21,7 +27,11 @@ const renderError = (message, secondaryMessage = "") => {
`; `;
}; };
// https://stackoverflow.com/a/48073476/10629172 /**
* @see https://stackoverflow.com/a/48073476/10629172
* @param {string} str
* @returns {string}
*/
function encodeHTML(str) { function encodeHTML(str) {
return str return str
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => { .replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
@ -30,18 +40,29 @@ function encodeHTML(str) {
.replace(/\u0008/gim, ""); .replace(/\u0008/gim, "");
} }
/**
* @param {number} num
*/
function kFormatter(num) { function kFormatter(num) {
return Math.abs(num) > 999 return Math.abs(num) > 999
? Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + "k" ? Math.sign(num) * parseFloat((Math.abs(num) / 1000).toFixed(1)) + "k"
: Math.sign(num) * Math.abs(num); : Math.sign(num) * Math.abs(num);
} }
/**
* @param {string} hexColor
* @returns {boolean}
*/
function isValidHexColor(hexColor) { function isValidHexColor(hexColor) {
return new RegExp( return new RegExp(
/^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/, /^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/,
).test(hexColor); ).test(hexColor);
} }
/**
* @param {string} value
* @returns {boolean | string}
*/
function parseBoolean(value) { function parseBoolean(value) {
if (value === "true") { if (value === "true") {
return true; return true;
@ -52,19 +73,37 @@ function parseBoolean(value) {
} }
} }
/**
* @param {string} str
*/
function parseArray(str) { function parseArray(str) {
if (!str) return []; if (!str) return [];
return str.split(","); return str.split(",");
} }
/**
* @param {number} number
* @param {number} min
* @param {number} max
*/
function clampValue(number, min, max) { function clampValue(number, min, max) {
// @ts-ignore
if (Number.isNaN(parseInt(number))) return min;
return Math.max(min, Math.min(number, max)); return Math.max(min, Math.min(number, max));
} }
/**
* @param {string[]} colors
*/
function isValidGradient(colors) { function isValidGradient(colors) {
return isValidHexColor(colors[1]) && isValidHexColor(colors[2]); return isValidHexColor(colors[1]) && isValidHexColor(colors[2]);
} }
/**
* @param {string} color
* @param {string} fallbackColor
* @returns {string | string[]}
*/
function fallbackColor(color, fallbackColor) { function fallbackColor(color, fallbackColor) {
let colors = color.split(","); let colors = color.split(",");
let gradient = null; let gradient = null;
@ -79,7 +118,12 @@ function fallbackColor(color, fallbackColor) {
); );
} }
/**
* @param {import('axios').AxiosRequestConfig['data']} data
* @param {import('axios').AxiosRequestConfig['headers']} headers
*/
function request(data, headers) { function request(data, headers) {
// @ts-ignore
return axios({ return axios({
url: "https://api.github.com/graphql", url: "https://api.github.com/graphql",
method: "post", method: "post",
@ -92,8 +136,8 @@ function request(data, headers) {
* @param {object} props * @param {object} props
* @param {string[]} props.items * @param {string[]} props.items
* @param {number} props.gap * @param {number} props.gap
* @param {number[]} props.sizes * @param {number[]?=} props.sizes
* @param {"column" | "row"} props.direction * @param {"column" | "row"?=} props.direction
* *
* @returns {string[]} * @returns {string[]}
* *
@ -115,14 +159,27 @@ function flexLayout({ items, gap, direction, sizes = [] }) {
}); });
} }
// returns theme based colors with proper overrides and defaults /**
* @typedef {object} CardColors
* @prop {string} title_color
* @prop {string} text_color
* @prop {string} icon_color
* @prop {string} bg_color
* @prop {string} border_color
* @prop {keyof typeof import('../../themes')?=} fallbackTheme
* @prop {keyof typeof import('../../themes')?=} theme
*/
/**
* returns theme based colors with proper overrides and defaults
* @param {CardColors} options
*/
function getCardColors({ function getCardColors({
title_color, title_color,
text_color, text_color,
icon_color, icon_color,
bg_color, bg_color,
theme,
border_color, border_color,
theme,
fallbackTheme = "default", fallbackTheme = "default",
}) { }) {
const defaultTheme = themes[fallbackTheme]; const defaultTheme = themes[fallbackTheme];
@ -157,6 +214,12 @@ function getCardColors({
return { titleColor, iconColor, textColor, bgColor, borderColor }; return { titleColor, iconColor, textColor, bgColor, borderColor };
} }
/**
* @param {string} text
* @param {number} width
* @param {number} maxLines
* @returns {string[]}
*/
function wrapTextMultiline(text, width = 60, maxLines = 3) { function wrapTextMultiline(text, width = 60, maxLines = 3) {
const wrapped = wrap(encodeHTML(text), { width }) const wrapped = wrap(encodeHTML(text), { width })
.split("\n") // Split wrapped lines to get an array of lines .split("\n") // Split wrapped lines to get an array of lines
@ -193,6 +256,10 @@ const SECONDARY_ERROR_MESSAGES = {
}; };
class CustomError extends Error { class CustomError extends Error {
/**
* @param {string} message
* @param {string} type
*/
constructor(message, type) { constructor(message, type) {
super(message); super(message);
this.type = type; this.type = type;
@ -203,7 +270,12 @@ class CustomError extends Error {
static USER_NOT_FOUND = "USER_NOT_FOUND"; static USER_NOT_FOUND = "USER_NOT_FOUND";
} }
// https://stackoverflow.com/a/48172630/10629172 /**
* @see https://stackoverflow.com/a/48172630/10629172
* @param {string} str
* @param {number} fontSize
* @returns
*/
function measureText(str, fontSize = 10) { function measureText(str, fontSize = 10) {
// prettier-ignore // prettier-ignore
const widths = [ const widths = [
@ -237,6 +309,8 @@ function measureText(str, fontSize = 10) {
.reduce((cur, acc) => acc + cur) * fontSize .reduce((cur, acc) => acc + cur) * fontSize
); );
} }
/** @param {string} name */
const lowercaseTrim = (name) => name.toLowerCase().trim(); const lowercaseTrim = (name) => name.toLowerCase().trim();
/** /**

View file

@ -1,14 +1,21 @@
/**
* @param {number} value
*/
const calculateCircleProgress = (value) => { const calculateCircleProgress = (value) => {
let radius = 40; const radius = 40;
let c = Math.PI * (radius * 2); const c = Math.PI * (radius * 2);
if (value < 0) value = 0; if (value < 0) value = 0;
if (value > 100) value = 100; if (value > 100) value = 100;
let percentage = ((100 - value) / 100) * c; return ((100 - value) / 100) * c;
return percentage;
}; };
/**
*
* @param {{progress: number}} param0
* @returns
*/
const getProgressAnimation = ({ progress }) => { const getProgressAnimation = ({ progress }) => {
return ` return `
@keyframes rankAnimation { @keyframes rankAnimation {
@ -44,6 +51,15 @@ const getAnimations = () => {
`; `;
}; };
/**
* @param {{
* titleColor: string;
* textColor: string;
* iconColor: string;
* show_icons: boolean;
* progress: number;
* }} args
*/
const getStyles = ({ const getStyles = ({
titleColor, titleColor,
textColor, textColor,