@stats-organization/github-readme-stats-core 2.1.3 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/build/api/gist.d.ts.map +1 -1
  2. package/build/api/gist.js +0 -1
  3. package/build/api/index.d.ts.map +1 -1
  4. package/build/api/index.js +0 -1
  5. package/build/api/pin.d.ts.map +1 -1
  6. package/build/api/pin.js +0 -1
  7. package/build/api/top-langs.d.ts.map +1 -1
  8. package/build/api/top-langs.js +0 -1
  9. package/build/api/wakatime.d.ts.map +1 -1
  10. package/build/api/wakatime.js +0 -1
  11. package/build/cards/gist.d.ts.map +1 -1
  12. package/build/cards/gist.js +0 -1
  13. package/build/cards/repo.d.ts.map +1 -1
  14. package/build/cards/repo.js +0 -1
  15. package/build/cards/stats.d.ts.map +1 -1
  16. package/build/cards/stats.js +0 -1
  17. package/build/cards/top-languages.d.ts.map +1 -1
  18. package/build/cards/top-languages.js +0 -1
  19. package/build/cards/wakatime.d.ts.map +1 -1
  20. package/build/cards/wakatime.js +0 -1
  21. package/build/common/Card.d.ts +48 -60
  22. package/build/common/Card.d.ts.map +1 -1
  23. package/build/common/Card.js +49 -50
  24. package/build/common/I18n.d.ts +13 -14
  25. package/build/common/I18n.d.ts.map +1 -1
  26. package/build/common/I18n.js +13 -12
  27. package/build/common/color.d.ts +30 -40
  28. package/build/common/color.d.ts.map +1 -1
  29. package/build/common/color.js +30 -42
  30. package/build/common/config.d.ts +18 -2
  31. package/build/common/config.d.ts.map +1 -1
  32. package/build/common/config.js +17 -26
  33. package/build/common/constants.d.ts +2 -2
  34. package/build/common/constants.d.ts.map +1 -1
  35. package/build/common/constants.js +5 -3
  36. package/build/common/error.d.ts +36 -29
  37. package/build/common/error.d.ts.map +1 -1
  38. package/build/common/error.js +14 -10
  39. package/build/common/fmt.d.ts +14 -13
  40. package/build/common/fmt.d.ts.map +1 -1
  41. package/build/common/fmt.js +19 -15
  42. package/build/common/html.d.ts +2 -4
  43. package/build/common/html.d.ts.map +1 -1
  44. package/build/common/html.js +1 -5
  45. package/build/common/http.d.ts.map +1 -1
  46. package/build/common/http.js +0 -1
  47. package/build/common/icons.d.ts +22 -21
  48. package/build/common/icons.d.ts.map +1 -1
  49. package/build/common/icons.js +4 -5
  50. package/build/common/ops.d.ts.map +1 -1
  51. package/build/common/ops.js +0 -1
  52. package/build/common/render.d.ts.map +1 -1
  53. package/build/common/render.js +0 -1
  54. package/build/common/retryer.d.ts +18 -15
  55. package/build/common/retryer.d.ts.map +1 -1
  56. package/build/common/retryer.js +21 -30
  57. package/build/fetchers/gist.d.ts.map +1 -1
  58. package/build/fetchers/gist.js +0 -1
  59. package/build/fetchers/repo.d.ts.map +1 -1
  60. package/build/fetchers/repo.js +3 -6
  61. package/build/fetchers/stats.d.ts.map +1 -1
  62. package/build/fetchers/stats.js +3 -6
  63. package/build/fetchers/top-languages.d.ts.map +1 -1
  64. package/build/fetchers/top-languages.js +0 -1
  65. package/build/fetchers/wakatime.d.ts.map +1 -1
  66. package/build/fetchers/wakatime.js +0 -1
  67. package/build/translations.d.ts +627 -24
  68. package/build/translations.d.ts.map +1 -1
  69. package/build/translations.js +7 -8
  70. package/package.json +1 -1
  71. package/src/api/gist.js +0 -2
  72. package/src/api/index.js +0 -2
  73. package/src/api/pin.js +0 -2
  74. package/src/api/top-langs.js +0 -2
  75. package/src/api/wakatime.js +0 -2
  76. package/src/cards/gist.js +0 -2
  77. package/src/cards/repo.js +0 -2
  78. package/src/cards/stats.js +0 -2
  79. package/src/cards/top-languages.js +0 -2
  80. package/src/cards/wakatime.js +0 -2
  81. package/src/common/{Card.js → Card.ts} +89 -61
  82. package/src/common/I18n.ts +49 -0
  83. package/src/common/{color.js → color.ts} +55 -51
  84. package/src/common/config.ts +83 -0
  85. package/src/common/constants.ts +10 -0
  86. package/src/common/{error.js → error.ts} +20 -14
  87. package/src/common/{fmt.js → fmt.ts} +27 -19
  88. package/src/common/{html.js → html.ts} +3 -8
  89. package/src/common/http.js +0 -2
  90. package/src/common/{icons.js → icons.ts} +9 -7
  91. package/src/common/ops.js +0 -2
  92. package/src/common/render.js +0 -2
  93. package/src/common/{retryer.js → retryer.ts} +45 -32
  94. package/src/fetchers/gist.js +0 -2
  95. package/src/fetchers/repo.js +3 -7
  96. package/src/fetchers/stats.js +3 -7
  97. package/src/fetchers/top-languages.js +0 -2
  98. package/src/fetchers/types.d.ts +1 -1
  99. package/src/fetchers/wakatime.js +0 -2
  100. package/src/{translations.js → translations.ts} +14 -10
  101. package/src/common/I18n.js +0 -42
  102. package/src/common/config.js +0 -78
  103. package/src/common/constants.js +0 -9
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Valid owner affiliations for GitHub API queries.
3
+ */
4
+ const OWNER_AFFILIATIONS: Array<string> = [
5
+ "OWNER",
6
+ "COLLABORATOR",
7
+ "ORGANIZATION_MEMBER",
8
+ ];
9
+
10
+ export { OWNER_AFFILIATIONS };
@@ -1,14 +1,12 @@
1
- // @ts-check
2
-
3
1
  import { OWNER_AFFILIATIONS } from "./constants.js";
4
2
 
5
3
  /**
6
- * @type {string} A general message to ask user to try again later.
4
+ * A general message to ask user to try again later.
7
5
  */
8
6
  const TRY_AGAIN_LATER = "Please try again later";
9
7
 
10
8
  /**
11
- * @type {Object<string, string>} A map of error types to secondary error messages.
9
+ * A map of error types to secondary error messages.
12
10
  */
13
11
  const SECONDARY_ERROR_MESSAGES = {
14
12
  MAX_RETRY:
@@ -28,16 +26,21 @@ const SECONDARY_ERROR_MESSAGES = {
28
26
  * Custom error class to handle custom GRS errors.
29
27
  */
30
28
  class CustomError extends Error {
29
+ type: string;
30
+ secondaryMessage: string;
31
+
31
32
  /**
32
33
  * Custom error constructor.
33
34
  *
34
- * @param {string} message Error message.
35
- * @param {string} type Error type.
35
+ * @param message Error message.
36
+ * @param type Error type.
36
37
  */
37
- constructor(message, type) {
38
+ constructor(message: string, type: string) {
38
39
  super(message);
39
40
  this.type = type;
40
- this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || type;
41
+ type PartialRecord = Partial<Record<string, string>>;
42
+ this.secondaryMessage =
43
+ (SECONDARY_ERROR_MESSAGES as PartialRecord)[type] ?? type;
41
44
  }
42
45
 
43
46
  static MAX_RETRY = "MAX_RETRY";
@@ -53,13 +56,16 @@ class CustomError extends Error {
53
56
  * Missing query parameter class.
54
57
  */
55
58
  class MissingParamError extends Error {
59
+ missedParams: Array<string>;
60
+ secondaryMessage: string | undefined;
61
+
56
62
  /**
57
63
  * Missing query parameter error constructor.
58
64
  *
59
- * @param {string[]} missedParams An array of missing parameters names.
60
- * @param {string=} secondaryMessage Optional secondary message to display.
65
+ * @param missedParams An array of missing parameters names.
66
+ * @param secondaryMessage Optional secondary message to display.
61
67
  */
62
- constructor(missedParams, secondaryMessage) {
68
+ constructor(missedParams: Array<string>, secondaryMessage?: string) {
63
69
  const msg = `Missing params ${missedParams
64
70
  .map((p) => `"${p}"`)
65
71
  .join(", ")} make sure you pass the parameters in URL`;
@@ -72,10 +78,10 @@ class MissingParamError extends Error {
72
78
  /**
73
79
  * Retrieve secondary message from an error object.
74
80
  *
75
- * @param {Error} err The error object.
76
- * @returns {string|undefined} The secondary message if available, otherwise undefined.
81
+ * @param err The error object.
82
+ * @returns The secondary message if available, otherwise undefined.
77
83
  */
78
- const retrieveSecondaryMessage = (err) => {
84
+ const retrieveSecondaryMessage = (err: Error): string | undefined => {
79
85
  return "secondaryMessage" in err && typeof err.secondaryMessage === "string"
80
86
  ? err.secondaryMessage
81
87
  : undefined;
@@ -1,16 +1,14 @@
1
- // @ts-check
2
-
3
1
  import { encodeHTML } from "./html.js";
4
2
  import { splitWrappedText } from "./render.js";
5
3
 
6
4
  /**
7
5
  * Retrieves num with suffix k(thousands) precise to given decimal places.
8
6
  *
9
- * @param {number} num The number to format.
10
- * @param {number=} precision The number of decimal places to include.
11
- * @returns {string|number} The formatted number.
7
+ * @param num The number to format.
8
+ * @param precision The number of decimal places to include.
9
+ * @returns The formatted number.
12
10
  */
13
- const kFormatter = (num, precision) => {
11
+ const kFormatter = (num: number, precision?: number): string | number => {
14
12
  const abs = Math.abs(num);
15
13
  const sign = Math.sign(num);
16
14
 
@@ -22,17 +20,17 @@ const kFormatter = (num, precision) => {
22
20
  return sign * abs;
23
21
  }
24
22
 
25
- return sign * parseFloat((abs / 1000).toFixed(1)) + "k";
23
+ return `${sign * parseFloat((abs / 1000).toFixed(1))}k`;
26
24
  };
27
25
 
28
26
  /**
29
27
  * Convert bytes to a human-readable string representation.
30
28
  *
31
- * @param {number} bytes The number of bytes to convert.
32
- * @returns {string} The human-readable representation of bytes.
29
+ * @param bytes The number of bytes to convert.
30
+ * @returns The human-readable representation of bytes.
33
31
  * @throws {Error} If bytes is negative or too large.
34
32
  */
35
- const formatBytes = (bytes) => {
33
+ const formatBytes = (bytes: number): string => {
36
34
  if (bytes < 0) {
37
35
  throw new Error("Bytes must be a non-negative number");
38
36
  }
@@ -45,23 +43,29 @@ const formatBytes = (bytes) => {
45
43
  const base = 1024;
46
44
  const i = Math.floor(Math.log(bytes) / Math.log(base));
47
45
 
48
- if (i >= sizes.length) {
46
+ const unit = sizes[i];
47
+ if (unit === undefined) {
49
48
  throw new Error("Bytes is too large to convert to a human-readable string");
50
49
  }
51
50
 
52
- return `${(bytes / Math.pow(base, i)).toFixed(1)} ${sizes[i]}`;
51
+ return `${(bytes / Math.pow(base, i)).toFixed(1)} ${unit}`;
53
52
  };
54
53
 
55
54
  /**
56
55
  * Split text over multiple lines based on the card width.
57
56
  *
58
- * @param {string} text Text to split.
59
- * @param {number} width Available wrap width in px.
60
- * @param {number} fontSize Font size in px.
61
- * @param {number} maxLines Maximum number of lines.
62
- * @returns {string[]} Array of lines.
57
+ * @param text Text to split.
58
+ * @param width Available wrap width in px.
59
+ * @param fontSize Font size in px.
60
+ * @param maxLines Maximum number of lines.
61
+ * @returns Array of lines.
63
62
  */
64
- const wrapTextMultiline = (text, width, fontSize, maxLines = 3) => {
63
+ const wrapTextMultiline = (
64
+ text: string,
65
+ width: number,
66
+ fontSize: number,
67
+ maxLines = 3,
68
+ ): Array<string> => {
65
69
  const wrapped = splitWrappedText(text, fontSize, width);
66
70
  const lines = wrapped
67
71
  .map((line) => encodeHTML(line.trim()))
@@ -69,7 +73,11 @@ const wrapTextMultiline = (text, width, fontSize, maxLines = 3) => {
69
73
 
70
74
  // Add "..." to the last line if the text exceeds maxLines
71
75
  if (wrapped.length > maxLines) {
72
- lines[maxLines - 1] += "...";
76
+ const lastIndex = maxLines - 1;
77
+ const lastLine = lines[lastIndex];
78
+ if (lastLine !== undefined) {
79
+ lines[lastIndex] = `${lastLine}...`;
80
+ }
73
81
  }
74
82
 
75
83
  // Remove empty lines if text fits in less than maxLines lines
@@ -1,18 +1,13 @@
1
- // @ts-check
2
-
3
1
  /**
4
2
  * Encode string as HTML.
5
3
  *
6
4
  * @see https://stackoverflow.com/a/48073476/10629172
7
- *
8
- * @param {string} str String to encode.
9
- * @returns {string} Encoded string.
10
5
  */
11
- const encodeHTML = (str) => {
6
+ const encodeHTML = (str: string): string => {
12
7
  return (
13
8
  str
14
- .replace(/[\u00A0-\u9999<>&](?!#)/gim, (i) => {
15
- return "&#" + i.charCodeAt(0) + ";";
9
+ .replace(/[\u00A0-\u9999<>&](?!#)/gim, (i: string) => {
10
+ return `&#${i.charCodeAt(0)};`;
16
11
  })
17
12
  // eslint-disable-next-line no-control-regex
18
13
  .replace(/\u0008/gim, "")
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  import axios from "axios";
4
2
 
5
3
  /**
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  /*
4
2
  The icons in this file are based on https://github.com/primer/octicons which is released under the MIT license:
5
3
 
@@ -46,12 +44,16 @@ const icons = {
46
44
  /**
47
45
  * Get rank icon
48
46
  *
49
- * @param {string} rankIcon - The rank icon type.
50
- * @param {string} rankLevel - The rank level.
51
- * @param {number} percentile - The rank percentile.
52
- * @returns {string} - The SVG code of the rank icon
47
+ * @param rankIcon - The rank icon type.
48
+ * @param rankLevel - The rank level.
49
+ * @param percentile - The rank percentile.
50
+ * @returns The SVG code of the rank icon
53
51
  */
54
- const rankIcon = (rankIcon, rankLevel, percentile) => {
52
+ const rankIcon = (
53
+ rankIcon: string,
54
+ rankLevel: string,
55
+ percentile: number,
56
+ ): string => {
55
57
  switch (rankIcon) {
56
58
  case "github":
57
59
  return `
package/src/common/ops.js CHANGED
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  import toEmoji from "emoji-name-map";
4
2
 
5
3
  import { OWNER_AFFILIATIONS } from "./constants.js";
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  import { getCardColors } from "./color.js";
4
2
  import { SECONDARY_ERROR_MESSAGES, TRY_AGAIN_LATER } from "./error.js";
5
3
  import { encodeHTML } from "./html.js";
@@ -1,43 +1,56 @@
1
- // @ts-check
1
+ import type { AxiosResponse } from "axios";
2
2
 
3
3
  import { getConfig } from "./config.js";
4
4
  import { CustomError } from "./error.js";
5
5
  import { logger } from "./log.js";
6
6
 
7
+ /**
8
+ * Subset of the response payload the retryer inspects to detect
9
+ * rate-limiting and credential failures.
10
+ */
11
+ interface ResponseData {
12
+ errors?: Array<{ type?: string; message?: string }>;
13
+ message?: string;
14
+ }
15
+
7
16
  /**
8
17
  * Returns a random integer from 0 (inclusive) to `max` (exclusive).
9
18
  *
10
19
  * The value is generated using `Math.random()` and uniformly distributed
11
20
  * across the range.
12
21
  *
13
- * @param {number} max The upper bound (exclusive). Must be a positive number.
22
+ * @param max The upper bound (exclusive). Must be a positive number.
14
23
  *
15
- * @returns {number} A random integer `n` such that `0 <= n < max`.
24
+ * @returns A random integer `n` such that `0 <= n < max`.
16
25
  */
17
- function getRandomInt(max) {
26
+ function getRandomInt(max: number): number {
18
27
  return Math.floor(Math.random() * max);
19
28
  }
20
29
 
21
- /**
22
- * @typedef {import("axios").AxiosResponse} AxiosResponse Axios response.
23
- * @typedef {(variables: any, token: string, retriesForTests?: number) => Promise<AxiosResponse>} FetcherFunction Fetcher function.
24
- */
30
+ type FetcherResponse = AxiosResponse<ResponseData>;
31
+
32
+ type FetcherFunction = (
33
+ variables: Record<string, unknown>,
34
+ token: string,
35
+ retriesForTests?: number,
36
+ ) => Promise<FetcherResponse>;
25
37
 
26
38
  /**
27
39
  * Try to execute the fetcher function until it succeeds or the max number of retries is reached.
28
40
  *
29
- * @param {FetcherFunction} fetcher The fetcher function.
30
- * @param {any} variables Object with arguments to pass to the fetcher function.
31
- * @param {string | null} pat Optional PAT override.
32
- * @returns {Promise<any>} The response from the fetcher function.
41
+ * @param fetcher The fetcher function.
42
+ * @param variables Object with arguments to pass to the fetcher function.
43
+ * @param pat Optional PAT override.
44
+ * @returns The response from the fetcher function.
33
45
  */
34
- const retryer = async (fetcher, variables, pat = null) => {
35
- let PATs;
36
- if (pat) {
37
- PATs = [{ name: "user PAT from database", value: pat }];
38
- } else {
39
- PATs = getConfig().pats;
40
- }
46
+ const retryer = async (
47
+ fetcher: FetcherFunction,
48
+ variables: Record<string, unknown>,
49
+ pat: string | null = null,
50
+ ): Promise<FetcherResponse> => {
51
+ const PATs = pat
52
+ ? [{ name: "user PAT from database", value: pat }]
53
+ : getConfig().pats;
41
54
 
42
55
  if (!PATs.length) {
43
56
  throw new CustomError("No GitHub API tokens found", CustomError.NO_TOKENS);
@@ -46,11 +59,13 @@ const retryer = async (fetcher, variables, pat = null) => {
46
59
 
47
60
  for (let retries = 0; retries < PATs.length; retries++) {
48
61
  const currentPAT = PATs[(startPAT + retries) % PATs.length];
62
+ if (!currentPAT) {
63
+ continue;
64
+ }
49
65
 
50
66
  try {
51
- let response = await fetcher(
67
+ const response = await fetcher(
52
68
  variables,
53
- // @ts-ignore
54
69
  currentPAT.value,
55
70
  // used in tests for faking rate limit
56
71
  retries,
@@ -58,11 +73,11 @@ const retryer = async (fetcher, variables, pat = null) => {
58
73
 
59
74
  // react on both type and message-based rate-limit signals.
60
75
  // https://github.com/anuraghazra/github-readme-stats/issues/4425
61
- const errors = response?.data?.errors;
76
+ const errors = response.data.errors;
62
77
  const errorType = errors?.[0]?.type;
63
- const errorMsg = errors?.[0]?.message || "";
78
+ const errorMsg = errors?.[0]?.message ?? "";
64
79
  const isRateLimited =
65
- (errors && errorType === "RATE_LIMITED") ||
80
+ (!!errors && errorType === "RATE_LIMITED") ||
66
81
  /rate limit/i.test(errorMsg);
67
82
 
68
83
  if (isRateLimited) {
@@ -71,20 +86,18 @@ const retryer = async (fetcher, variables, pat = null) => {
71
86
  return response;
72
87
  }
73
88
  } catch (err) {
74
- /** @type {any} */
75
- const e = err;
89
+ const e = err as { response?: FetcherResponse };
76
90
 
77
91
  // network/unexpected error → let caller treat as failure
78
- if (!e?.response) {
79
- throw e;
92
+ if (!e.response) {
93
+ throw err;
80
94
  }
81
95
 
82
- // prettier-ignore
83
96
  // also checking for bad credentials if any tokens gets invalidated
84
- const isBadCredential =
85
- e?.response?.data?.message === "Bad credentials";
97
+ const message = e.response.data.message;
98
+ const isBadCredential = message === "Bad credentials";
86
99
  const isAccountSuspended =
87
- e?.response?.data?.message === "Sorry. Your account was suspended.";
100
+ message === "Sorry. Your account was suspended.";
88
101
 
89
102
  if (isBadCredential || isAccountSuspended) {
90
103
  logger.log(`${currentPAT.name} Failed due to bad credentials`);
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  import { MissingParamError } from "../common/error.js";
4
2
  import { request } from "../common/http.js";
5
3
  import { retryer } from "../common/retryer.js";
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  import { MissingParamError } from "../common/error.js";
4
2
  import { request } from "../common/http.js";
5
3
  import { retryer } from "../common/retryer.js";
@@ -23,9 +21,7 @@ const fetcher = (variables, token) => {
23
21
  isPrivate
24
22
  isArchived
25
23
  isTemplate
26
- stargazers {
27
- totalCount
28
- }
24
+ stargazerCount
29
25
  description
30
26
  primaryLanguage {
31
27
  color
@@ -130,7 +126,7 @@ const fetchRepo = async (
130
126
  return {
131
127
  ...repoUserStats,
132
128
  ...data.user.repository,
133
- starCount: data.user.repository.stargazers.totalCount,
129
+ starCount: data.user.repository.stargazerCount,
134
130
  };
135
131
  }
136
132
 
@@ -155,7 +151,7 @@ const fetchRepo = async (
155
151
  return {
156
152
  ...repoUserStats,
157
153
  ...data.organization.repository,
158
- starCount: data.organization.repository.stargazers.totalCount,
154
+ starCount: data.organization.repository.stargazerCount,
159
155
  };
160
156
  }
161
157
 
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  import axios from "axios";
4
2
  import githubUsernameRegex from "github-username-regex";
5
3
 
@@ -18,9 +16,7 @@ const GRAPHQL_REPOS_FIELD = `
18
16
  totalCount
19
17
  nodes {
20
18
  name
21
- stargazers {
22
- totalCount
23
- }
19
+ stargazerCount
24
20
  }
25
21
  pageInfo {
26
22
  hasNextPage
@@ -159,7 +155,7 @@ const statsFetcher = async ({
159
155
  // Disable multi page fetching on public Vercel instance due to rate limits.
160
156
  fetchedPages++;
161
157
  const repoNodesWithStars = repoNodes.filter(
162
- (node) => node.stargazers.totalCount !== 0,
158
+ (node) => node.stargazerCount !== 0,
163
159
  );
164
160
 
165
161
  hasNextPage =
@@ -458,7 +454,7 @@ const fetchStats = async (
458
454
  return !repoToHide.has(data.name);
459
455
  })
460
456
  .reduce((prev, curr) => {
461
- return prev + curr.stargazers.totalCount;
457
+ return prev + curr.stargazerCount;
462
458
  }, 0);
463
459
 
464
460
  stats.rank = calculateRank({
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  import { getConfig } from "../common/config.js";
4
2
  import { CustomError, MissingParamError } from "../common/error.js";
5
3
  import { wrapTextMultiline } from "../common/fmt.js";
@@ -13,7 +13,7 @@ export interface RepositoryData {
13
13
  isPrivate: boolean;
14
14
  isArchived: boolean;
15
15
  isTemplate: boolean;
16
- stargazers: { totalCount: number };
16
+ stargazerCount: number;
17
17
  description: string;
18
18
  primaryLanguage: {
19
19
  color: string;
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  import axios from "axios";
4
2
 
5
3
  import { CustomError, MissingParamError } from "../common/error.js";
@@ -1,18 +1,22 @@
1
- // @ts-check
2
-
3
1
  import { encodeHTML } from "./common/html.js";
4
2
 
5
3
  /**
6
4
  * Retrieves stat card labels in the available locales.
7
5
  *
8
- * @param {object} props Function arguments.
9
- * @param {string} props.name The name of the locale.
10
- * @param {string} props.apostrophe Whether to use apostrophe or not.
11
- * @returns {object} The locales object.
6
+ * @param props Function arguments.
7
+ * @param props.name The name of the locale.
8
+ * @param props.apostrophe Whether to use apostrophe or not.
9
+ * @returns The locales object.
12
10
  *
13
11
  * @see https://www.andiamo.co.uk/resources/iso-language-codes/ for language codes.
14
12
  */
15
- const statCardLocales = ({ name, apostrophe }) => {
13
+ const statCardLocales = ({
14
+ name,
15
+ apostrophe,
16
+ }: {
17
+ name: string;
18
+ apostrophe: string;
19
+ }) => {
16
20
  const encodedName = encodeHTML(name);
17
21
  return {
18
22
  "statcard.title": {
@@ -1140,10 +1144,10 @@ const availableLocales = Object.keys(repoCardLocales["repocard.archived"]);
1140
1144
  /**
1141
1145
  * Checks whether the locale is available or not.
1142
1146
  *
1143
- * @param {string} locale The locale to check.
1144
- * @returns {boolean} Boolean specifying whether the locale is available or not.
1147
+ * @param locale The locale to check.
1148
+ * @returns Boolean specifying whether the locale is available or not.
1145
1149
  */
1146
- const isLocaleAvailable = (locale) => {
1150
+ const isLocaleAvailable = (locale: string): boolean => {
1147
1151
  return availableLocales.includes(locale.toLowerCase());
1148
1152
  };
1149
1153
 
@@ -1,42 +0,0 @@
1
- // @ts-check
2
-
3
- const FALLBACK_LOCALE = "en";
4
-
5
- /**
6
- * I18n translation class.
7
- */
8
- class I18n {
9
- /**
10
- * Constructor.
11
- *
12
- * @param {Object} options Options.
13
- * @param {string=} options.locale Locale.
14
- * @param {any} options.translations Translations.
15
- */
16
- constructor({ locale, translations }) {
17
- this.locale = locale || FALLBACK_LOCALE;
18
- this.translations = translations;
19
- }
20
-
21
- /**
22
- * Get translation.
23
- *
24
- * @param {string} str String to translate.
25
- * @returns {string} Translated string.
26
- */
27
- t(str) {
28
- if (!this.translations[str]) {
29
- throw new Error(`${str} Translation string not found`);
30
- }
31
-
32
- if (!this.translations[str][this.locale]) {
33
- throw new Error(
34
- `'${str}' translation not found for locale '${this.locale}'`,
35
- );
36
- }
37
-
38
- return this.translations[str][this.locale];
39
- }
40
- }
41
-
42
- export { I18n };
@@ -1,78 +0,0 @@
1
- // @ts-check
2
-
3
- /**
4
- * @param {string | undefined} value Comma-separated string.
5
- * @returns {string[] | undefined} Parsed string values.
6
- */
7
- const parseCsv = (value) => {
8
- if (!value) {
9
- return undefined;
10
- }
11
- return value.split(",");
12
- };
13
-
14
- /**
15
- * @param {Record<string, string | undefined>} env Environment variables to inspect.
16
- * @returns {{name: string, value: string}[]} Personal access tokens found in the environment.
17
- */
18
- const parsePATsFromEnv = (env) => {
19
- return Object.keys(env)
20
- .filter((key) => /PAT_\d*$/.exec(key))
21
- .map((name) => ({
22
- name,
23
- value: env[name],
24
- }));
25
- };
26
-
27
- /**
28
- * @returns {Record<string, string | undefined>} `process.env` if available, otherwise `{}`.
29
- */
30
- const getDefaultEnv = () => {
31
- if (typeof process !== "undefined" && process?.env) {
32
- return process.env;
33
- }
34
- return {};
35
- };
36
-
37
- /**
38
- * @param {Partial<ReturnType<typeof loadConfigFromEnv>>} config (Partial) config values to normalize.
39
- * @returns {{
40
- * whitelist: string[] | undefined,
41
- * gistWhitelist: string[] | undefined,
42
- * excludeRepositories: string[],
43
- * fetchMultiPageStars: string | undefined,
44
- * pats: {name: string, value: string}[],
45
- * }} Normalized config object with defaults applied.
46
- */
47
- const normalizeConfig = (config = {}) => {
48
- return {
49
- whitelist: config.whitelist,
50
- gistWhitelist: config.gistWhitelist,
51
- excludeRepositories: config.excludeRepositories || [],
52
- fetchMultiPageStars: config.fetchMultiPageStars,
53
- pats: config.pats || [],
54
- };
55
- };
56
-
57
- let currentConfig;
58
-
59
- /**
60
- * @param {Record<string, string | undefined>} env Environment variables used to build the runtime config.
61
- */
62
- export const loadConfigFromEnv = (env = getDefaultEnv()) => {
63
- const whitelist = parseCsv(env.WHITELIST);
64
- const gistWhitelist = parseCsv(env.GIST_WHITELIST);
65
- const excludeRepositories = parseCsv(env.EXCLUDE_REPO) || [];
66
-
67
- currentConfig = normalizeConfig({
68
- whitelist,
69
- gistWhitelist,
70
- excludeRepositories,
71
- fetchMultiPageStars: env.FETCH_MULTI_PAGE_STARS,
72
- pats: parsePATsFromEnv(env),
73
- });
74
- };
75
-
76
- loadConfigFromEnv();
77
-
78
- export const getConfig = () => currentConfig;
@@ -1,9 +0,0 @@
1
- // @ts-check
2
-
3
- /**
4
- * Valid owner affiliations for GitHub API queries.
5
- * @type {Array<string>}
6
- */
7
- const OWNER_AFFILIATIONS = ["OWNER", "COLLABORATOR", "ORGANIZATION_MEMBER"];
8
-
9
- export { OWNER_AFFILIATIONS };