Repository: anuraghazra/github-readme-stats
Pull request #3435 (2023-10-27 19:01:21)

infra(dependabot): set myself as pull requests reviewer

vercel[bot]: [vc]: #JpqjvddB11IToD2g4cOOx9rto4h9kk2M38WoWgJEME4=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJnaXRodWItcmVhZG1lLXN0YXRzIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2dpdGh1Yi1yZWFkbWUtc3RhdHMtdGVhbS9naXRodWItcmVhZG1lLXN0YXRzL0dyTXAzbzVmYkJoUXhmTW1UVmpzSm92TmhKZ3EiLCJuZXh0Q29tbWl0U3RhdHVzIjoiUEVORElORyJ9XX0=
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Updated (UTC) |
| :--- | :----- | :------ | :------ |
| **github-readme-stats** | 🔄 Building ([Inspect](https://vercel.com/github-readme-stats-team/github-readme-stats/GrMp3o5fbBhQxfMmTVjsJovNhJgq)) |  | Oct 27, 2023 7:01pm |


codecov[bot]: We're currently processing your upload.  This comment will be updated when the results are available.

Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 1691b12..8bf1cdb 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -6,6 +6,8 @@ updates:
     schedule:
       interval: weekly
     open-pull-requests-limit: 10
+    reviewers:
+      - "qwerty541"
 
   # Maintain dependencies for GitHub Actions
   - package-ecosystem: github-actions
@@ -13,3 +15,5 @@ updates:
     schedule:
       interval: weekly
     open-pull-requests-limit: 10
+    reviewers:
+      - "qwerty541"
diff --git a/api/gist.js b/api/gist.js
index 1dbc5ae..8821c7b 100644
--- a/api/gist.js
+++ b/api/gist.js
@@ -27,7 +27,15 @@ export default async (req, res) => {
   res.setHeader("Content-Type", "image/svg+xml");
 
   if (locale && !isLocaleAvailable(locale)) {
-    return res.send(renderError("Something went wrong", "Language not found"));
+    return res.send(
+      renderError("Something went wrong", "Language not found", {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 
   try {
@@ -83,6 +91,14 @@ export default async (req, res) => {
         CONSTANTS.ERROR_CACHE_SECONDS
       }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
     ); // Use lower cache period for errors.
-    return res.send(renderError(err.message, err.secondaryMessage));
+    return res.send(
+      renderError(err.message, err.secondaryMessage, {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 };
diff --git a/api/index.js b/api/index.js
index adfd331..2029367 100644
--- a/api/index.js
+++ b/api/index.js
@@ -42,11 +42,27 @@ export default async (req, res) => {
   res.setHeader("Content-Type", "image/svg+xml");
 
   if (blacklist.includes(username)) {
-    return res.send(renderError("Something went wrong"));
+    return res.send(
+      renderError("Something went wrong", "This username is blacklisted", {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 
   if (locale && !isLocaleAvailable(locale)) {
-    return res.send(renderError("Something went wrong", "Language not found"));
+    return res.send(
+      renderError("Something went wrong", "Language not found", {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 
   try {
@@ -111,6 +127,14 @@ export default async (req, res) => {
         CONSTANTS.ERROR_CACHE_SECONDS
       }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
     ); // Use lower cache period for errors.
-    return res.send(renderError(err.message, err.secondaryMessage));
+    return res.send(
+      renderError(err.message, err.secondaryMessage, {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 };
diff --git a/api/pin.js b/api/pin.js
index 21ecf96..c67df29 100644
--- a/api/pin.js
+++ b/api/pin.js
@@ -29,11 +29,27 @@ export default async (req, res) => {
   res.setHeader("Content-Type", "image/svg+xml");
 
   if (blacklist.includes(username)) {
-    return res.send(renderError("Something went wrong"));
+    return res.send(
+      renderError("Something went wrong", "This username is blacklisted", {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 
   if (locale && !isLocaleAvailable(locale)) {
-    return res.send(renderError("Something went wrong", "Language not found"));
+    return res.send(
+      renderError("Something went wrong", "Language not found", {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 
   try {
@@ -89,6 +105,14 @@ export default async (req, res) => {
         CONSTANTS.ERROR_CACHE_SECONDS
       }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
     ); // Use lower cache period for errors.
-    return res.send(renderError(err.message, err.secondaryMessage));
+    return res.send(
+      renderError(err.message, err.secondaryMessage, {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 };
diff --git a/api/top-langs.js b/api/top-langs.js
index d9bf6b0..382ee42 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -37,7 +37,15 @@ export default async (req, res) => {
   res.setHeader("Content-Type", "image/svg+xml");
 
   if (blacklist.includes(username)) {
-    return res.send(renderError("Something went wrong"));
+    return res.send(
+      renderError("Something went wrong", "This username is blacklisted", {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 
   if (locale && !isLocaleAvailable(locale)) {
@@ -105,6 +113,14 @@ export default async (req, res) => {
         CONSTANTS.ERROR_CACHE_SECONDS
       }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
     ); // Use lower cache period for errors.
-    return res.send(renderError(err.message, err.secondaryMessage));
+    return res.send(
+      renderError(err.message, err.secondaryMessage, {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 };
diff --git a/api/wakatime.js b/api/wakatime.js
index b2582ca..732b05a 100644
--- a/api/wakatime.js
+++ b/api/wakatime.js
@@ -35,7 +35,15 @@ export default async (req, res) => {
   res.setHeader("Content-Type", "image/svg+xml");
 
   if (locale && !isLocaleAvailable(locale)) {
-    return res.send(renderError("Something went wrong", "Language not found"));
+    return res.send(
+      renderError("Something went wrong", "Language not found", {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 
   try {
@@ -84,6 +92,14 @@ export default async (req, res) => {
         CONSTANTS.ERROR_CACHE_SECONDS
       }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
     ); // Use lower cache period for errors.
-    return res.send(renderError(err.message, err.secondaryMessage));
+    return res.send(
+      renderError(err.message, err.secondaryMessage, {
+        title_color,
+        text_color,
+        bg_color,
+        border_color,
+        theme,
+      }),
+    );
   }
 };
diff --git a/src/common/utils.js b/src/common/utils.js
index 6792df8..48ea051 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -39,61 +39,6 @@ class CustomError extends Error {
   static WAKATIME_ERROR = "WAKATIME_ERROR";
 }
 
-// Script parameters.
-const ERROR_CARD_LENGTH = 576.5;
-
-/**
- * Encode string as HTML.
- *
- * @see https://stackoverflow.com/a/48073476/10629172
- *
- * @param {string} str String to encode.
- * @returns {string} Encoded string.
- */
-const encodeHTML = (str) => {
-  return str
-    .replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
-      return "&#" + i.charCodeAt(0) + ";";
-    })
-    .replace(/\u0008/gim, "");
-};
-
-const UPSTREAM_API_ERRORS = [
-  TRY_AGAIN_LATER,
-  SECONDARY_ERROR_MESSAGES.MAX_RETRY,
-];
-
-/**
- * Renders error message on the card.
- *
- * @param {string} message Main error message.
- * @param {string} secondaryMessage The secondary error message.
- * @returns {string} The SVG markup.
- */
-const renderError = (message, secondaryMessage = "") => {
-  return `
-    <svg width="${ERROR_CARD_LENGTH}" height="120" viewBox="0 0 ${ERROR_CARD_LENGTH} 120" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <style>
-    .text { font: 600 16px 'Segoe UI', Ubuntu, Sans-Serif; fill: #2F80ED }
-    .small { font: 600 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: #252525 }
-    .gray { fill: #858585 }
-    </style>
-    <rect x="0.5" y="0.5" width="${
-      ERROR_CARD_LENGTH - 1
-    }" height="99%" rx="4.5" fill="#FFFEFE" stroke="#E4E2E2"/>
-    <text x="25" y="45" class="text">Something went wrong!${
-      UPSTREAM_API_ERRORS.includes(secondaryMessage)
-        ? ""
-        : " file an issue at https://tiny.one/readme-stats"
-    }</text>
-    <text data-testid="message" x="25" y="55" class="text small">
-      <tspan x="25" dy="18">${encodeHTML(message)}</tspan>
-      <tspan x="25" dy="18" class="gray">${secondaryMessage}</tspan>
-    </text>
-    </svg>
-  `;
-};
-
 /**
  * Auto layout utility, allows us to layout things vertically or horizontally with
  * proper gaping.
@@ -380,6 +325,81 @@ const getCardColors = ({
   return { titleColor, iconColor, textColor, bgColor, borderColor, ringColor };
 };
 
+// Script parameters.
+const ERROR_CARD_LENGTH = 576.5;
+
+/**
+ * Encode string as HTML.
+ *
+ * @see https://stackoverflow.com/a/48073476/10629172
+ *
+ * @param {string} str String to encode.
+ * @returns {string} Encoded string.
+ */
+const encodeHTML = (str) => {
+  return str
+    .replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
+      return "&#" + i.charCodeAt(0) + ";";
+    })
+    .replace(/\u0008/gim, "");
+};
+
+const UPSTREAM_API_ERRORS = [
+  TRY_AGAIN_LATER,
+  SECONDARY_ERROR_MESSAGES.MAX_RETRY,
+];
+
+/**
+ * Renders error message on the card.
+ *
+ * @param {string} message Main error message.
+ * @param {string} secondaryMessage The secondary error message.
+ * @param {object} options Function options.
+ * @returns {string} The SVG markup.
+ */
+const renderError = (message, secondaryMessage = "", options = {}) => {
+  const {
+    title_color,
+    text_color,
+    bg_color,
+    border_color,
+    theme = "default",
+  } = options;
+
+  // returns theme based colors with proper overrides and defaults
+  const { titleColor, textColor, bgColor, borderColor } = getCardColors({
+    title_color,
+    text_color,
+    icon_color: "",
+    bg_color,
+    border_color,
+    ring_color: "",
+    theme,
+  });
+
+  return `
+    <svg width="${ERROR_CARD_LENGTH}"  height="120" viewBox="0 0 ${ERROR_CARD_LENGTH} 120" fill="${bgColor}" xmlns="http://www.w3.org/2000/svg">
+    <style>
+    .text { font: 600 16px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${titleColor} }
+    .small { font: 600 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
+    .gray { fill: #858585 }
+    </style>
+    <rect x="0.5" y="0.5" width="${
+      ERROR_CARD_LENGTH - 1
+    }" height="99%" rx="4.5" fill="${bgColor}" stroke="${borderColor}"/>
+    <text x="25" y="45" class="text">Something went wrong!${
+      UPSTREAM_API_ERRORS.includes(secondaryMessage)
+        ? ""
+        : " file an issue at https://tiny.one/readme-stats"
+    }</text>
+    <text data-testid="message" x="25" y="55" class="text small">
+      <tspan x="25" dy="18">${encodeHTML(message)}</tspan>
+      <tspan x="25" dy="18" class="gray">${secondaryMessage}</tspan>
+    </text>
+    </svg>
+  `;
+};
+
 /**
  * Split text over multiple lines based on the card width.
  *
diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js
index faf4bc9..485cc8b 100644
--- a/src/fetchers/top-languages-fetcher.js
+++ b/src/fetchers/top-languages-fetcher.js
@@ -92,7 +92,7 @@ const fetchTopLanguages = async (
       );
     }
     throw new CustomError(
-      "Something went while trying to retrieve the language data using the GraphQL API.",
+      "Something went wrong while trying to retrieve the language data using the GraphQL API.",
       CustomError.GRAPHQL_ERROR,
     );
   }


Test patch:
diff --git a/tests/api.test.js b/tests/api.test.js
index a6ed04b..eee9a1a 100644
--- a/tests/api.test.js
+++ b/tests/api.test.js
@@ -120,6 +120,21 @@ describe("Test /api/", () => {
     );
   });
 
+  it("should render error card in same theme as requested card", async () => {
+    const { req, res } = faker({ theme: "merko" }, error);
+
+    await api(req, res);
+
+    expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
+    expect(res.send).toBeCalledWith(
+      renderError(
+        error.errors[0].message,
+        "Make sure the provided username is not an organization",
+        { theme: "merko" },
+      ),
+    );
+  });
+
   it("should get the query options", async () => {
     const { req, res } = faker(
       {
@@ -291,7 +306,9 @@ describe("Test /api/", () => {
     await api(req, res);
 
     expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
-    expect(res.send).toBeCalledWith(renderError("Something went wrong"));
+    expect(res.send).toBeCalledWith(
+      renderError("Something went wrong", "This username is blacklisted"),
+    );
   });
 
   it("should render error card when wrong locale is provided", async () => {
diff --git a/tests/fetchTopLanguages.test.js b/tests/fetchTopLanguages.test.js
index 90648c3..e7bd54a 100644
--- a/tests/fetchTopLanguages.test.js
+++ b/tests/fetchTopLanguages.test.js
@@ -165,7 +165,7 @@ describe("FetchTopLanguages", () => {
     });
 
     await expect(fetchTopLanguages("anuraghazra")).rejects.toThrow(
-      "Something went while trying to retrieve the language data using the GraphQL API.",
+      "Something went wrong while trying to retrieve the language data using the GraphQL API.",
     );
   });
 });
diff --git a/tests/pin.test.js b/tests/pin.test.js
index 0dcb5aa..105e445 100644
--- a/tests/pin.test.js
+++ b/tests/pin.test.js
@@ -155,7 +155,9 @@ describe("Test /api/pin", () => {
     await pin(req, res);
 
     expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
-    expect(res.send).toBeCalledWith(renderError("Something went wrong"));
+    expect(res.send).toBeCalledWith(
+      renderError("Something went wrong", "This username is blacklisted"),
+    );
   });
 
   it("should render error card if wrong locale provided", async () => {
diff --git a/tests/top-langs.test.js b/tests/top-langs.test.js
index 272ee7e..692681b 100644
--- a/tests/top-langs.test.js
+++ b/tests/top-langs.test.js
@@ -183,7 +183,9 @@ describe("Test /api/top-langs", () => {
     await topLangs(req, res);
 
     expect(res.setHeader).toBeCalledWith("Content-Type", "image/svg+xml");
-    expect(res.send).toBeCalledWith(renderError("Something went wrong"));
+    expect(res.send).toBeCalledWith(
+      renderError("Something went wrong", "This username is blacklisted"),
+    );
   });
 
   it("should render error card if wrong locale provided", async () => {