refactor: move errors related code into separate file (#4554)

* refactor: move errors related code into separate file

* jsdoc

---------

Co-authored-by: Alexandr <qwerty541zxc@gmail.com>
This commit is contained in:
Ophelia Goldstein
2025-10-09 22:31:46 +03:00
committed by GitHub
co-authored by Alexandr
parent f6e5d507ad
commit b164ecebda
11 changed files with 95 additions and 83 deletions
+2 -1
View File
@@ -1,9 +1,10 @@
// @ts-check
import { Card } from "../common/Card.js";
import { CustomError } from "../common/error.js";
import { I18n } from "../common/I18n.js";
import { icons, rankIcon } from "../common/icons.js";
import {
CustomError,
clampValue,
flexLayout,
getCardColors,
+69
View File
@@ -0,0 +1,69 @@
/**
* @type {string} A general message to ask user to try again later.
*/
const TRY_AGAIN_LATER = "Please try again later";
/**
* @type {Object<string, string>} A map of error types to secondary error messages.
*/
const SECONDARY_ERROR_MESSAGES = {
MAX_RETRY:
"You can deploy own instance or wait until public will be no longer limited",
NO_TOKENS:
"Please add an env variable called PAT_1 with your GitHub API token in vercel",
USER_NOT_FOUND: "Make sure the provided username is not an organization",
GRAPHQL_ERROR: TRY_AGAIN_LATER,
GITHUB_REST_API_ERROR: TRY_AGAIN_LATER,
WAKATIME_USER_NOT_FOUND: "Make sure you have a public WakaTime profile",
};
/**
* Custom error class to handle custom GRS errors.
*/
class CustomError extends Error {
/**
* Custom error constructor.
*
* @param {string} message Error message.
* @param {string} type Error type.
*/
constructor(message, type) {
super(message);
this.type = type;
this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || type;
}
static MAX_RETRY = "MAX_RETRY";
static NO_TOKENS = "NO_TOKENS";
static USER_NOT_FOUND = "USER_NOT_FOUND";
static GRAPHQL_ERROR = "GRAPHQL_ERROR";
static GITHUB_REST_API_ERROR = "GITHUB_REST_API_ERROR";
static WAKATIME_ERROR = "WAKATIME_ERROR";
}
/**
* Missing query parameter class.
*/
class MissingParamError extends Error {
/**
* Missing query parameter error constructor.
*
* @param {string[]} missedParams An array of missing parameters names.
* @param {string=} secondaryMessage Optional secondary message to display.
*/
constructor(missedParams, secondaryMessage) {
const msg = `Missing params ${missedParams
.map((p) => `"${p}"`)
.join(", ")} make sure you pass the parameters in URL`;
super(msg);
this.missedParams = missedParams;
this.secondaryMessage = secondaryMessage;
}
}
export {
CustomError,
MissingParamError,
SECONDARY_ERROR_MESSAGES,
TRY_AGAIN_LATER,
};
-2
View File
@@ -22,8 +22,6 @@ export {
getCardColors,
wrapTextMultiline,
logger,
CustomError,
MissingParamError,
measureText,
lowercaseTrim,
chunkArray,
+8 -3
View File
@@ -1,4 +1,7 @@
import { CustomError, logger } from "./utils.js";
// @ts-check
import { CustomError } from "./error.js";
import { logger } from "./utils.js";
// Script variables.
@@ -10,7 +13,7 @@ const RETRIES = process.env.NODE_ENV === "test" ? 7 : PATs;
/**
* @typedef {import("axios").AxiosResponse} AxiosResponse Axios response.
* @typedef {(variables: object, token: string) => Promise<AxiosResponse>} FetcherFunction Fetcher function.
* @typedef {(variables: object, token: string, retriesForTests?: number) => Promise<AxiosResponse>} FetcherFunction Fetcher function.
*/
/**
@@ -19,7 +22,7 @@ const RETRIES = process.env.NODE_ENV === "test" ? 7 : PATs;
* @param {FetcherFunction} fetcher The fetcher function.
* @param {object} variables Object with arguments to pass to the fetcher function.
* @param {number} retries How many times to retry.
* @returns {Promise<T>} The response from the fetcher function.
* @returns {Promise<any>} The response from the fetcher function.
*/
const retryer = async (fetcher, variables, retries = 0) => {
if (!RETRIES) {
@@ -37,7 +40,9 @@ const retryer = async (fetcher, variables, retries = 0) => {
// try to fetch with the first token since RETRIES is 0 index i'm adding +1
let response = await fetcher(
variables,
// @ts-ignore
process.env[`PAT_${retries + 1}`],
// used in tests for faking rate limit
retries,
);
+2 -57
View File
@@ -1,43 +1,10 @@
// @ts-check
import axios from "axios";
import toEmoji from "emoji-name-map";
import wrap from "word-wrap";
import { themes } from "../../themes/index.js";
const TRY_AGAIN_LATER = "Please try again later";
const SECONDARY_ERROR_MESSAGES = {
MAX_RETRY:
"You can deploy own instance or wait until public will be no longer limited",
NO_TOKENS:
"Please add an env variable called PAT_1 with your GitHub API token in vercel",
USER_NOT_FOUND: "Make sure the provided username is not an organization",
GRAPHQL_ERROR: TRY_AGAIN_LATER,
GITHUB_REST_API_ERROR: TRY_AGAIN_LATER,
WAKATIME_USER_NOT_FOUND: "Make sure you have a public WakaTime profile",
};
/**
* Custom error class to handle custom GRS errors.
*/
class CustomError extends Error {
/**
* @param {string} message Error message.
* @param {string} type Error type.
*/
constructor(message, type) {
super(message);
this.type = type;
this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || type;
}
static MAX_RETRY = "MAX_RETRY";
static NO_TOKENS = "NO_TOKENS";
static USER_NOT_FOUND = "USER_NOT_FOUND";
static GRAPHQL_ERROR = "GRAPHQL_ERROR";
static GITHUB_REST_API_ERROR = "GITHUB_REST_API_ERROR";
static WAKATIME_ERROR = "WAKATIME_ERROR";
}
import { SECONDARY_ERROR_MESSAGES, TRY_AGAIN_LATER } from "./error.js";
/**
* Auto layout utility, allows us to layout things vertically or horizontally with
@@ -452,26 +419,6 @@ const noop = () => {};
const logger =
process.env.NODE_ENV === "test" ? { log: noop, error: noop } : console;
/**
* Missing query parameter class.
*/
class MissingParamError extends Error {
/**
* Missing query parameter error constructor.
*
* @param {string[]} missedParams An array of missing parameters names.
* @param {string=} secondaryMessage Optional secondary message to display.
*/
constructor(missedParams, secondaryMessage) {
const msg = `Missing params ${missedParams
.map((p) => `"${p}"`)
.join(", ")} make sure you pass the parameters in URL`;
super(msg);
this.missedParams = missedParams;
this.secondaryMessage = secondaryMessage;
}
}
/**
* Retrieve text length.
*
@@ -620,8 +567,6 @@ export {
getCardColors,
wrapTextMultiline,
logger,
CustomError,
MissingParamError,
measureText,
lowercaseTrim,
chunkArray,
+2 -1
View File
@@ -1,7 +1,8 @@
// @ts-check
import { request, MissingParamError } from "../common/utils.js";
import { request } from "../common/utils.js";
import { retryer } from "../common/retryer.js";
import { MissingParamError } from "../common/error.js";
/**
* @typedef {import('axios').AxiosRequestHeaders} AxiosRequestHeaders Axios request headers.
+3 -1
View File
@@ -1,6 +1,8 @@
// @ts-check
import { MissingParamError } from "../common/error.js";
import { retryer } from "../common/retryer.js";
import { MissingParamError, request } from "../common/utils.js";
import { request } from "../common/utils.js";
/**
* @typedef {import('axios').AxiosRequestHeaders} AxiosRequestHeaders Axios request headers.
+2 -7
View File
@@ -5,14 +5,9 @@ import * as dotenv from "dotenv";
import githubUsernameRegex from "github-username-regex";
import { calculateRank } from "../calculateRank.js";
import { retryer } from "../common/retryer.js";
import {
CustomError,
logger,
MissingParamError,
request,
wrapTextMultiline,
} from "../common/utils.js";
import { logger, request, wrapTextMultiline } from "../common/utils.js";
import { excludeRepositories } from "../common/envs.js";
import { CustomError, MissingParamError } from "../common/error.js";
dotenv.config();
+2 -7
View File
@@ -1,14 +1,9 @@
// @ts-check
import { retryer } from "../common/retryer.js";
import {
CustomError,
logger,
MissingParamError,
request,
wrapTextMultiline,
} from "../common/utils.js";
import { logger, request, wrapTextMultiline } from "../common/utils.js";
import { excludeRepositories } from "../common/envs.js";
import { CustomError, MissingParamError } from "../common/error.js";
/**
* @typedef {import("axios").AxiosRequestHeaders} AxiosRequestHeaders Axios request headers.
+4 -2
View File
@@ -1,11 +1,13 @@
// @ts-check
import axios from "axios";
import { CustomError, MissingParamError } from "../common/utils.js";
import { CustomError, MissingParamError } from "../common/error.js";
/**
* WakaTime data fetcher.
*
* @param {{username: string, api_domain: string }} props Fetcher props.
* @returns {Promise<WakaTimeData>} WakaTime data response.
* @returns {Promise<import("./types").WakaTimeData>} WakaTime data response.
*/
const fetchWakatimeStats = async ({ username, api_domain }) => {
if (!username) {
+1 -2
View File
@@ -7,8 +7,7 @@ import {
import "@testing-library/jest-dom";
import { cssToObject } from "@uppercod/css-to-object";
import { renderStatsCard } from "../src/cards/stats.js";
import { CustomError } from "../src/common/utils.js";
import { CustomError } from "../src/common/error.js";
import { themes } from "../themes/index.js";
const stats = {