@stats-organization/github-readme-stats-core 2.1.4 → 2.2.0
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.
- package/build/api/gist.d.ts +2 -7
- package/build/api/gist.d.ts.map +1 -1
- package/build/api/gist.js +28 -26
- package/build/api/index.d.ts +3 -8
- package/build/api/index.d.ts.map +1 -1
- package/build/api/index.js +32 -36
- package/build/api/pin.d.ts +2 -7
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +18 -33
- package/build/api/top-langs.d.ts +2 -7
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +32 -44
- package/build/api/wakatime.d.ts +2 -7
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +28 -26
- package/build/calculateRank.d.ts +12 -11
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +18 -18
- package/build/cards/common-options.d.ts +13 -0
- package/build/cards/common-options.d.ts.map +1 -0
- package/build/cards/common-options.js +1 -0
- package/build/cards/gist.d.ts +11 -16
- package/build/cards/gist.d.ts.map +1 -1
- package/build/cards/gist.js +26 -31
- package/build/cards/repo.d.ts +19 -16
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +79 -72
- package/build/cards/stats.d.ts +29 -44
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +118 -173
- package/build/cards/top-languages.d.ts +81 -77
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +186 -184
- package/build/cards/wakatime.d.ts +21 -11
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +92 -109
- package/build/common/Card.d.ts +41 -14
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +92 -31
- package/build/common/I18n.d.ts +4 -2
- package/build/common/I18n.d.ts.map +1 -1
- package/build/common/color.d.ts +91 -15
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +163 -17
- package/build/common/config.d.ts +2 -1
- package/build/common/config.d.ts.map +1 -1
- package/build/common/config.js +16 -26
- package/build/common/constants.d.ts +2 -1
- package/build/common/constants.d.ts.map +1 -1
- package/build/common/date.d.ts +37 -0
- package/build/common/date.d.ts.map +1 -0
- package/build/common/date.js +31 -0
- package/build/common/html.js +1 -1
- package/build/common/http.d.ts +37 -5
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +29 -6
- package/build/common/icons.d.ts +1 -0
- package/build/common/icons.d.ts.map +1 -1
- package/build/common/icons.js +1 -0
- package/build/common/languageColors.d.ts +11 -0
- package/build/common/languageColors.d.ts.map +1 -0
- package/build/common/languageColors.js +15 -0
- package/build/common/languageColors.json +10 -1
- package/build/common/ops.d.ts +27 -33
- package/build/common/ops.d.ts.map +1 -1
- package/build/common/ops.js +31 -48
- package/build/common/render.d.ts +154 -113
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +209 -92
- package/build/common/retryer.d.ts +15 -6
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +2 -0
- package/build/fetchers/gist.d.ts +6 -21
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +28 -64
- package/build/fetchers/repo.d.ts +12 -11
- package/build/fetchers/repo.d.ts.map +1 -1
- package/build/fetchers/repo.js +27 -68
- package/build/fetchers/stats.d.ts +24 -17
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +302 -184
- package/build/fetchers/top-languages.d.ts +10 -15
- package/build/fetchers/top-languages.d.ts.map +1 -1
- package/build/fetchers/top-languages.js +52 -103
- package/build/fetchers/types.d.ts +130 -0
- package/build/fetchers/types.d.ts.map +1 -0
- package/build/fetchers/types.js +1 -0
- package/build/fetchers/wakatime.d.ts +9 -5
- package/build/fetchers/wakatime.d.ts.map +1 -1
- package/build/fetchers/wakatime.js +8 -4
- package/build/graphql/contributionsDocument.d.ts +18 -0
- package/build/graphql/contributionsDocument.d.ts.map +1 -0
- package/build/graphql/contributionsDocument.js +30 -0
- package/build/graphql/generated/common.d.ts +42 -0
- package/build/graphql/generated/common.d.ts.map +1 -0
- package/build/graphql/generated/common.js +2 -0
- package/build/graphql/generated/gist.d.ts +44 -0
- package/build/graphql/generated/gist.d.ts.map +1 -0
- package/build/graphql/generated/gist.js +27 -0
- package/build/graphql/generated/repo.d.ts +67 -0
- package/build/graphql/generated/repo.d.ts.map +1 -0
- package/build/graphql/generated/repo.js +30 -0
- package/build/graphql/generated/stats.d.ts +150 -0
- package/build/graphql/generated/stats.d.ts.map +1 -0
- package/build/graphql/generated/stats.js +95 -0
- package/build/graphql/generated/top-languages.d.ts +54 -0
- package/build/graphql/generated/top-languages.d.ts.map +1 -0
- package/build/graphql/generated/top-languages.js +27 -0
- package/build/graphql/graphqlDocument.d.ts +22 -0
- package/build/graphql/graphqlDocument.d.ts.map +1 -0
- package/build/graphql/graphqlDocument.js +8 -0
- package/build/graphql/reposContributedToDocument.d.ts +27 -0
- package/build/graphql/reposContributedToDocument.d.ts.map +1 -0
- package/build/graphql/reposContributedToDocument.js +59 -0
- package/build/index.d.ts +3 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -1
- package/build/themes/index.d.ts +32 -0
- package/build/themes/index.d.ts.map +1 -1
- package/build/themes/index.js +28 -0
- package/build/translations.d.ts +17 -0
- package/build/translations.d.ts.map +1 -1
- package/build/translations.js +17 -0
- package/package.json +14 -8
- package/src/_emoji-name-map.d.ts +10 -0
- package/src/_github-username-regex.d.ts +4 -0
- package/src/api/gist.js +31 -31
- package/src/api/index.js +40 -42
- package/src/api/pin.js +20 -38
- package/src/api/top-langs.js +36 -49
- package/src/api/wakatime.js +31 -31
- package/src/{calculateRank.js → calculateRank.ts} +29 -19
- package/src/cards/common-options.ts +13 -0
- package/src/cards/{gist.js → gist.ts} +37 -37
- package/src/cards/{repo.js → repo.ts} +107 -79
- package/src/cards/{stats.js → stats.ts} +173 -210
- package/src/cards/{top-languages.js → top-languages.ts} +325 -243
- package/src/cards/{wakatime.js → wakatime.ts} +158 -127
- package/src/common/Card.ts +123 -43
- package/src/common/I18n.ts +6 -2
- package/src/common/color.ts +240 -28
- package/src/common/config.ts +22 -29
- package/src/common/constants.ts +3 -1
- package/src/common/date.ts +45 -0
- package/src/common/html.ts +1 -1
- package/src/common/http.ts +71 -0
- package/src/common/icons.ts +1 -0
- package/src/common/languageColors.json +10 -1
- package/src/common/languageColors.ts +19 -0
- package/src/common/ops.ts +158 -0
- package/src/common/render.ts +652 -0
- package/src/common/retryer.ts +21 -12
- package/src/fetchers/gist.ts +79 -0
- package/src/fetchers/repo.ts +114 -0
- package/src/fetchers/stats.ts +743 -0
- package/src/fetchers/top-languages.ts +135 -0
- package/src/fetchers/{types.d.ts → types.ts} +28 -20
- package/src/fetchers/{wakatime.js → wakatime.ts} +19 -5
- package/src/graphql/contributionsDocument.ts +44 -0
- package/src/graphql/generated/common.ts +26 -0
- package/src/graphql/generated/gist.ts +59 -0
- package/src/graphql/generated/repo.ts +90 -0
- package/src/graphql/generated/stats.ts +194 -0
- package/src/graphql/generated/top-languages.ts +75 -0
- package/src/graphql/graphqlDocument.ts +25 -0
- package/src/graphql/queries/gist.graphql +25 -0
- package/src/graphql/queries/repo.graphql +28 -0
- package/src/graphql/queries/stats.graphql +120 -0
- package/src/graphql/queries/top-languages.graphql +34 -0
- package/src/graphql/reposContributedToDocument.ts +86 -0
- package/src/index.ts +3 -1
- package/src/themes/index.ts +33 -0
- package/src/translations.ts +17 -0
- package/src/cards/types.d.ts +0 -78
- package/src/common/http.js +0 -19
- package/src/common/ops.js +0 -170
- package/src/common/render.js +0 -440
- package/src/fetchers/gist.js +0 -112
- package/src/fetchers/repo.js +0 -161
- package/src/fetchers/stats.js +0 -474
- package/src/fetchers/top-languages.js +0 -175
- package/src/themes/README.md +0 -229
package/src/common/config.ts
CHANGED
|
@@ -9,7 +9,8 @@ interface Config {
|
|
|
9
9
|
whitelist: Array<string> | undefined;
|
|
10
10
|
gistWhitelist: Array<string> | undefined;
|
|
11
11
|
excludeRepositories: Array<string>;
|
|
12
|
-
|
|
12
|
+
/** Max pages of starred repos to fetch; `Infinity` means every page, `1` only the first. */
|
|
13
|
+
fetchMultiPageStars: number;
|
|
13
14
|
pats: Array<PersonalAccessToken>;
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -17,11 +18,19 @@ interface Config {
|
|
|
17
18
|
* @param value Comma-separated string.
|
|
18
19
|
* @returns Parsed string values.
|
|
19
20
|
*/
|
|
20
|
-
const parseCsv = (value: string | undefined): Array<string> | undefined =>
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const parseCsv = (value: string | undefined): Array<string> | undefined =>
|
|
22
|
+
value ? value.split(",") : undefined;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param value Raw `FETCH_MULTI_PAGE_STARS` value.
|
|
26
|
+
* @returns Page limit: `"true"` means every page, a positive number caps the pages, anything else means one.
|
|
27
|
+
*/
|
|
28
|
+
const parseFetchMultiPageStars = (value: string | undefined): number => {
|
|
29
|
+
if (value === "true") {
|
|
30
|
+
return Infinity;
|
|
23
31
|
}
|
|
24
|
-
|
|
32
|
+
const limit = Number(value);
|
|
33
|
+
return limit > 0 ? limit : 1;
|
|
25
34
|
};
|
|
26
35
|
|
|
27
36
|
/**
|
|
@@ -45,37 +54,21 @@ const getDefaultEnv = (): Env => {
|
|
|
45
54
|
return processEnv ?? {};
|
|
46
55
|
};
|
|
47
56
|
|
|
48
|
-
/**
|
|
49
|
-
* @param config (Partial) config values to normalize.
|
|
50
|
-
* @returns Normalized config object with defaults applied.
|
|
51
|
-
*/
|
|
52
|
-
const normalizeConfig = (config: Partial<Config> = {}): Config => {
|
|
53
|
-
return {
|
|
54
|
-
whitelist: config.whitelist,
|
|
55
|
-
gistWhitelist: config.gistWhitelist,
|
|
56
|
-
excludeRepositories: config.excludeRepositories ?? [],
|
|
57
|
-
fetchMultiPageStars: config.fetchMultiPageStars,
|
|
58
|
-
pats: config.pats ?? [],
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
|
|
62
57
|
let currentConfig: Config;
|
|
63
58
|
|
|
64
59
|
/**
|
|
65
60
|
* @param env Environment variables used to build the runtime config.
|
|
66
61
|
*/
|
|
67
62
|
export const loadConfigFromEnv = (env: Env = getDefaultEnv()): void => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
excludeRepositories,
|
|
76
|
-
fetchMultiPageStars: env["FETCH_MULTI_PAGE_STARS"],
|
|
63
|
+
currentConfig = {
|
|
64
|
+
whitelist: parseCsv(env["WHITELIST"]),
|
|
65
|
+
gistWhitelist: parseCsv(env["GIST_WHITELIST"]),
|
|
66
|
+
excludeRepositories: parseCsv(env["EXCLUDE_REPO"]) ?? [],
|
|
67
|
+
fetchMultiPageStars: parseFetchMultiPageStars(
|
|
68
|
+
env["FETCH_MULTI_PAGE_STARS"],
|
|
69
|
+
),
|
|
77
70
|
pats: parsePATsFromEnv(env),
|
|
78
|
-
}
|
|
71
|
+
};
|
|
79
72
|
};
|
|
80
73
|
|
|
81
74
|
loadConfigFromEnv();
|
package/src/common/constants.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { RepositoryAffiliation } from "../graphql/generated/common.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Valid owner affiliations for GitHub API queries.
|
|
3
5
|
*/
|
|
4
|
-
const OWNER_AFFILIATIONS: Array<
|
|
6
|
+
const OWNER_AFFILIATIONS: Array<RepositoryAffiliation> = [
|
|
5
7
|
"OWNER",
|
|
6
8
|
"COLLABORATOR",
|
|
7
9
|
"ORGANIZATION_MEMBER",
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** A span between two dates, as GitHub's range arguments take it. */
|
|
2
|
+
interface GitHubDateRange {
|
|
3
|
+
/** Start of the range, inclusive. */
|
|
4
|
+
from: Date;
|
|
5
|
+
/** End of the range, inclusive. */
|
|
6
|
+
to: Date;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Format a date as a GitHub `DateTime` scalar.
|
|
11
|
+
* Seconds precision, no milliseconds.
|
|
12
|
+
*
|
|
13
|
+
* @param date Date to format.
|
|
14
|
+
* @returns e.g. `2024-01-01T00:00:00Z`.
|
|
15
|
+
*/
|
|
16
|
+
const toGitHubDateTime = (date: Date): string =>
|
|
17
|
+
`${date.toISOString().slice(0, 19)}Z`;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The full UTC span of a calendar year, both ends inclusive.
|
|
21
|
+
*
|
|
22
|
+
* The end matters to callers that would otherwise leave a range open:
|
|
23
|
+
* GitHub's `contributionsCollection` defaults `to` to one year after `from`,
|
|
24
|
+
* which pulls the next 1st of January into the year.
|
|
25
|
+
*
|
|
26
|
+
* @param year Four-digit year.
|
|
27
|
+
* @returns The range covering it.
|
|
28
|
+
*/
|
|
29
|
+
const getGitHubYearRange = (year: number): GitHubDateRange => ({
|
|
30
|
+
from: new Date(Date.UTC(year, 0, 1)),
|
|
31
|
+
to: new Date(Date.UTC(year, 11, 31, 23, 59, 59)),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get diff in minutes between two dates.
|
|
36
|
+
*
|
|
37
|
+
* @param d1 First date.
|
|
38
|
+
* @param d2 Second date.
|
|
39
|
+
* @returns Number of minutes between the two dates.
|
|
40
|
+
*/
|
|
41
|
+
const dateDiff = (d1: Date, d2: Date): number =>
|
|
42
|
+
Math.round((d1.getTime() - d2.getTime()) / (1000 * 60));
|
|
43
|
+
|
|
44
|
+
export { dateDiff, getGitHubYearRange, toGitHubDateTime };
|
|
45
|
+
export type { GitHubDateRange };
|
package/src/common/html.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const encodeHTML = (str: string): string => {
|
|
7
7
|
return (
|
|
8
8
|
str
|
|
9
|
-
.replace(/[\u00A0-\u9999<>&](?!#)/gim, (i: string) => {
|
|
9
|
+
.replace(/[\u00A0-\u9999<>&"'](?!#)/gim, (i: string) => {
|
|
10
10
|
return `&#${i.charCodeAt(0)};`;
|
|
11
11
|
})
|
|
12
12
|
// eslint-disable-next-line no-control-regex
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import type { AxiosRequestConfig, AxiosResponse } from "axios";
|
|
3
|
+
|
|
4
|
+
import type { GraphQLDocument } from "../graphql/graphqlDocument.js";
|
|
5
|
+
|
|
6
|
+
const GITHUB_GRAPHQL_API = "https://api.github.com/graphql";
|
|
7
|
+
|
|
8
|
+
/** Response of a GraphQL call: the envelope the GitHub API wraps results in. */
|
|
9
|
+
type GraphQLResponse<TResult> = AxiosResponse<{
|
|
10
|
+
data: TResult;
|
|
11
|
+
errors?: Array<{ type?: string; message?: string }>;
|
|
12
|
+
}>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param document Generated query document.
|
|
16
|
+
* @param scheme `Authorization` scheme for the token.
|
|
17
|
+
* @returns A fetcher `retryer` can drive.
|
|
18
|
+
*/
|
|
19
|
+
const createGraphQLFetcher = <TResult, TVariables>(
|
|
20
|
+
document: GraphQLDocument<TResult, TVariables>,
|
|
21
|
+
scheme: "bearer" | "token",
|
|
22
|
+
) => {
|
|
23
|
+
return (
|
|
24
|
+
variables: TVariables,
|
|
25
|
+
token: string,
|
|
26
|
+
): Promise<GraphQLResponse<TResult>> => {
|
|
27
|
+
return axios({
|
|
28
|
+
url: GITHUB_GRAPHQL_API,
|
|
29
|
+
method: "post",
|
|
30
|
+
headers: { Authorization: `${scheme} ${token}` },
|
|
31
|
+
data: { query: document.text, variables },
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** Body of a GraphQL request sent to the GitHub API. */
|
|
37
|
+
interface GraphQLRequest {
|
|
38
|
+
/** The GraphQL query. */
|
|
39
|
+
query: string;
|
|
40
|
+
/** Variables referenced by the query. */
|
|
41
|
+
variables: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Send an untyped GraphQL request to the GitHub API.
|
|
46
|
+
*
|
|
47
|
+
* @param data Request data.
|
|
48
|
+
* @param headers Request headers.
|
|
49
|
+
* @returns Request response.
|
|
50
|
+
*
|
|
51
|
+
* @description Superseded by {@link createGraphQLFetcher}.
|
|
52
|
+
* Still used by the backend status endpoints for their own `rateLimit` query,
|
|
53
|
+
* and part of this package's published API.
|
|
54
|
+
*
|
|
55
|
+
* @todo consider dropping this once those endpoints post through axios directly,
|
|
56
|
+
* which they already depend on.
|
|
57
|
+
*/
|
|
58
|
+
const request = (
|
|
59
|
+
data: GraphQLRequest,
|
|
60
|
+
headers: NonNullable<AxiosRequestConfig["headers"]>,
|
|
61
|
+
): Promise<AxiosResponse> => {
|
|
62
|
+
return axios({
|
|
63
|
+
url: GITHUB_GRAPHQL_API,
|
|
64
|
+
method: "post",
|
|
65
|
+
headers,
|
|
66
|
+
data,
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export { createGraphQLFetcher, request };
|
|
71
|
+
export type { GraphQLResponse };
|
package/src/common/icons.ts
CHANGED
|
@@ -38,6 +38,7 @@ const icons = {
|
|
|
38
38
|
discussions_started: `<path fill-rule="evenodd" d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z" />`,
|
|
39
39
|
discussions_answered: `<path fill-rule="evenodd" d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z" />`,
|
|
40
40
|
comments: `<path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z" />`,
|
|
41
|
+
contributions: `<path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm7.25-3.25v2.5h2.5a.75.75 0 0 1 0 1.5h-2.5v2.5a.75.75 0 0 1-1.5 0v-2.5h-2.5a.75.75 0 0 1 0-1.5h2.5v-2.5a.75.75 0 0 1 1.5 0Z"/>`,
|
|
41
42
|
gist: `<path fill-rule="evenodd" d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z" />`,
|
|
42
43
|
};
|
|
43
44
|
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"Awk": "#c30e9b",
|
|
45
45
|
"B (Formal Method)": "#8aa8c5",
|
|
46
46
|
"B4X": "#00e4ff",
|
|
47
|
+
"BAML": "#a855f7",
|
|
47
48
|
"BASIC": "#ff0000",
|
|
48
49
|
"BQN": "#2b7067",
|
|
49
50
|
"Ballerina": "#FF5000",
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
"Blade": "#f7523f",
|
|
59
60
|
"BlitzBasic": "#00FFAE",
|
|
60
61
|
"BlitzMax": "#cd6400",
|
|
62
|
+
"Blueprint": "#3584E4",
|
|
61
63
|
"Bluespec": "#12223c",
|
|
62
64
|
"Bluespec BH": "#12223c",
|
|
63
65
|
"Boo": "#d4bec1",
|
|
@@ -69,7 +71,7 @@
|
|
|
69
71
|
"Bru": "#F4AA41",
|
|
70
72
|
"BuildStream": "#006bff",
|
|
71
73
|
"C": "#555555",
|
|
72
|
-
"C#": "#
|
|
74
|
+
"C#": "#7355dd",
|
|
73
75
|
"C++": "#f34b7d",
|
|
74
76
|
"C3": "#2563eb",
|
|
75
77
|
"CAP CDS": "#0092d1",
|
|
@@ -210,6 +212,7 @@
|
|
|
210
212
|
"Glimmer JS": "#F5835F",
|
|
211
213
|
"Glimmer TS": "#3178c6",
|
|
212
214
|
"Glyph": "#c1ac7f",
|
|
215
|
+
"Gno": "#226c57",
|
|
213
216
|
"Gnuplot": "#f0a9f0",
|
|
214
217
|
"Go": "#00ADD8",
|
|
215
218
|
"Go Checksums": "#00ADD8",
|
|
@@ -227,6 +230,7 @@
|
|
|
227
230
|
"Graphviz (DOT)": "#2596be",
|
|
228
231
|
"Groovy": "#4298b8",
|
|
229
232
|
"Groovy Server Pages": "#4298b8",
|
|
233
|
+
"GtkRC": "#7fe719",
|
|
230
234
|
"HAProxy": "#106da9",
|
|
231
235
|
"HCL": "#844FBA",
|
|
232
236
|
"HIP": "#4F3A4F",
|
|
@@ -416,6 +420,7 @@
|
|
|
416
420
|
"OpenSCAD": "#e5cd45",
|
|
417
421
|
"Option List": "#476732",
|
|
418
422
|
"Org": "#77aa99",
|
|
423
|
+
"OverPy": "#78b355",
|
|
419
424
|
"OverpassQL": "#cce2aa",
|
|
420
425
|
"Oxygene": "#cdd0e3",
|
|
421
426
|
"Oz": "#fab738",
|
|
@@ -445,10 +450,12 @@
|
|
|
445
450
|
"Portugol": "#f8bd00",
|
|
446
451
|
"PostCSS": "#dc3a0c",
|
|
447
452
|
"PostScript": "#da291c",
|
|
453
|
+
"Power Query": "#d38e0d",
|
|
448
454
|
"PowerBuilder": "#8f0f8d",
|
|
449
455
|
"PowerShell": "#012456",
|
|
450
456
|
"Praat": "#c8506d",
|
|
451
457
|
"Prisma": "#0c344b",
|
|
458
|
+
"Pro*C": "#bb8368",
|
|
452
459
|
"Processing": "#0096D8",
|
|
453
460
|
"Procfile": "#3B2F63",
|
|
454
461
|
"Prolog": "#74283c",
|
|
@@ -490,6 +497,7 @@
|
|
|
490
497
|
"Rebol": "#358a5b",
|
|
491
498
|
"Record Jar": "#0673ba",
|
|
492
499
|
"Red": "#f50000",
|
|
500
|
+
"Redscript": "#f44336",
|
|
493
501
|
"Regular Expression": "#009a00",
|
|
494
502
|
"Ren'Py": "#ff7f7f",
|
|
495
503
|
"Rez": "#FFDAB3",
|
|
@@ -659,6 +667,7 @@
|
|
|
659
667
|
"nanorc": "#2d004d",
|
|
660
668
|
"nesC": "#94B0C7",
|
|
661
669
|
"ooc": "#b0b77e",
|
|
670
|
+
"pkg-config": "#2b5e82",
|
|
662
671
|
"q": "#0040cd",
|
|
663
672
|
"reStructuredText": "#141414",
|
|
664
673
|
"sed": "#64b970",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import languageColorsJson from "./languageColors.json" with { type: "json" };
|
|
2
|
+
|
|
3
|
+
/** Shown for languages missing from the generated table, and for a null API color. */
|
|
4
|
+
const DEFAULT_LANG_COLOR = "#858585";
|
|
5
|
+
|
|
6
|
+
// The generated JSON types has literal keys; index it as a plain lookup table.
|
|
7
|
+
const languageColors: Record<string, string> = languageColorsJson;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Resolves a language's brand color from the generated table.
|
|
11
|
+
*
|
|
12
|
+
* @param name Language name as GitHub spells it.
|
|
13
|
+
* @returns The language's hex color, or the default gray when it is unknown.
|
|
14
|
+
*/
|
|
15
|
+
const getLanguageColor = (name: string): string => {
|
|
16
|
+
return languageColors[name] ?? DEFAULT_LANG_COLOR;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { DEFAULT_LANG_COLOR, getLanguageColor };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import toEmoji from "emoji-name-map";
|
|
2
|
+
|
|
3
|
+
import type { RepositoryAffiliation } from "../graphql/generated/common.js";
|
|
4
|
+
|
|
5
|
+
import { OWNER_AFFILIATIONS } from "./constants.js";
|
|
6
|
+
import { CustomError } from "./error.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns boolean if value is either "true" or "false" else the value as it is.
|
|
10
|
+
*
|
|
11
|
+
* @param value The value to parse.
|
|
12
|
+
* @returns The parsed value.
|
|
13
|
+
*/
|
|
14
|
+
const parseBoolean = (value: string | boolean): boolean | undefined => {
|
|
15
|
+
if (typeof value === "boolean") {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (typeof value === "string") {
|
|
20
|
+
if (value.toLowerCase() === "true") {
|
|
21
|
+
return true;
|
|
22
|
+
} else if (value.toLowerCase() === "false") {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parse string to array of strings.
|
|
31
|
+
*
|
|
32
|
+
* @param str The string to parse.
|
|
33
|
+
* @returns The array of strings.
|
|
34
|
+
*/
|
|
35
|
+
const parseArray = (str: string): Array<string> => {
|
|
36
|
+
if (!str) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
return str.split(",");
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Clamp the given number between the given range.
|
|
44
|
+
*
|
|
45
|
+
* @param number The number to clamp.
|
|
46
|
+
* @param min The minimum value.
|
|
47
|
+
* @param max The maximum value.
|
|
48
|
+
* @returns The clamped number.
|
|
49
|
+
*/
|
|
50
|
+
const clampValue = (
|
|
51
|
+
number: string | number,
|
|
52
|
+
min: number,
|
|
53
|
+
max: number,
|
|
54
|
+
): number => {
|
|
55
|
+
if (Number.isNaN(parseInt(String(number), 10))) {
|
|
56
|
+
return min;
|
|
57
|
+
}
|
|
58
|
+
return Math.max(min, Math.min(Number(number), max));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Lowercase and trim string.
|
|
63
|
+
*
|
|
64
|
+
* @param name String to lowercase and trim.
|
|
65
|
+
* @returns Lowercased and trimmed string.
|
|
66
|
+
*/
|
|
67
|
+
const lowercaseTrim = (name: string): string => name.toLowerCase().trim();
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Split array of languages in two columns.
|
|
71
|
+
*
|
|
72
|
+
* @template T Language object.
|
|
73
|
+
* @param arr Array of languages.
|
|
74
|
+
* @param perChunk Number of languages per column.
|
|
75
|
+
* @returns Array of languages split in two columns.
|
|
76
|
+
*/
|
|
77
|
+
const chunkArray = <T>(arr: Array<T>, perChunk: number): Array<Array<T>> => {
|
|
78
|
+
return arr.reduce<Array<Array<T>>>((resultArray, item, index) => {
|
|
79
|
+
const chunkIndex = Math.floor(index / perChunk);
|
|
80
|
+
const chunk = resultArray[chunkIndex] ?? [];
|
|
81
|
+
chunk.push(item);
|
|
82
|
+
resultArray[chunkIndex] = chunk;
|
|
83
|
+
return resultArray;
|
|
84
|
+
}, []);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Parse emoji from string.
|
|
89
|
+
*
|
|
90
|
+
* @param str String to parse emoji from.
|
|
91
|
+
* @returns String with emoji parsed.
|
|
92
|
+
*/
|
|
93
|
+
const parseEmojis = (str: string): string => {
|
|
94
|
+
if (!str) {
|
|
95
|
+
throw new Error("[parseEmoji]: str argument not provided");
|
|
96
|
+
}
|
|
97
|
+
return str.replace(/:\w+:/gm, (emoji) => {
|
|
98
|
+
return toEmoji.get(emoji) || "";
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const isOwnerAffiliation = (value: string): value is RepositoryAffiliation =>
|
|
103
|
+
OWNER_AFFILIATIONS.some((affiliation) => affiliation === value);
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Parse owner affiliations.
|
|
107
|
+
*
|
|
108
|
+
* @param affiliations input affiliations to be parsed.
|
|
109
|
+
* @returns Parsed affiliations.
|
|
110
|
+
*
|
|
111
|
+
* @throws {CustomError} If affiliations contains invalid values.
|
|
112
|
+
*/
|
|
113
|
+
const parseOwnerAffiliations = (
|
|
114
|
+
affiliations: Array<string>,
|
|
115
|
+
): Array<RepositoryAffiliation> => {
|
|
116
|
+
// Set default value for ownerAffiliations.
|
|
117
|
+
// NOTE: Done here since parseArray() will always return an empty array even nothing
|
|
118
|
+
//was specified.
|
|
119
|
+
const normalized =
|
|
120
|
+
affiliations.length > 0
|
|
121
|
+
? affiliations.map((affiliation) => affiliation.toUpperCase())
|
|
122
|
+
: ["OWNER"];
|
|
123
|
+
|
|
124
|
+
// Check if ownerAffiliations contains valid values.
|
|
125
|
+
if (!normalized.every(isOwnerAffiliation)) {
|
|
126
|
+
throw new CustomError(
|
|
127
|
+
"Invalid query parameter",
|
|
128
|
+
CustomError.INVALID_AFFILIATION,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
return normalized;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const buildSearchFilter = (
|
|
135
|
+
repos: Array<string> | string = [],
|
|
136
|
+
owners: Array<string> | string = [],
|
|
137
|
+
): string => {
|
|
138
|
+
const repoFilter =
|
|
139
|
+
Array.isArray(repos) && repos.length > 0
|
|
140
|
+
? repos.map((r) => `repo:${r} `).join("")
|
|
141
|
+
: "";
|
|
142
|
+
const orgFilter =
|
|
143
|
+
Array.isArray(owners) && owners.length > 0
|
|
144
|
+
? owners.map((o) => `owner:${o} `).join("")
|
|
145
|
+
: "";
|
|
146
|
+
return repoFilter + orgFilter;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
parseBoolean,
|
|
151
|
+
parseArray,
|
|
152
|
+
clampValue,
|
|
153
|
+
lowercaseTrim,
|
|
154
|
+
chunkArray,
|
|
155
|
+
parseEmojis,
|
|
156
|
+
parseOwnerAffiliations,
|
|
157
|
+
buildSearchFilter,
|
|
158
|
+
};
|