@stats-forge/github-stats-forge-core 0.0.2 → 0.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/README.md +0 -10
- package/build/api/api-result.d.ts +6 -7
- package/build/api/api-result.d.ts.map +1 -1
- package/build/api/api-result.js +4 -5
- package/build/api/contributed-to.d.ts +23 -0
- package/build/api/contributed-to.d.ts.map +1 -0
- package/build/api/contributed-to.js +43 -0
- package/build/api/gist.d.ts +8 -22
- package/build/api/gist.d.ts.map +1 -1
- package/build/api/gist.js +14 -36
- package/build/api/handler.d.ts +16 -0
- package/build/api/handler.d.ts.map +1 -0
- package/build/api/handler.js +29 -0
- package/build/api/index.d.ts +13 -12
- package/build/api/index.d.ts.map +1 -1
- package/build/api/index.js +1 -0
- package/build/api/params.d.ts +21 -12
- package/build/api/params.d.ts.map +1 -1
- package/build/api/params.js +41 -19
- package/build/api/pin.d.ts +11 -31
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +35 -63
- package/build/api/stats.d.ts +15 -16
- package/build/api/stats.d.ts.map +1 -1
- package/build/api/stats.js +60 -99
- package/build/api/top-langs.d.ts +13 -18
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +35 -72
- package/build/api/wakatime.d.ts +11 -17
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +27 -64
- package/build/calculateRank.d.ts +0 -9
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +12 -17
- package/build/cards/contributed-to.d.ts +19 -0
- package/build/cards/contributed-to.d.ts.map +1 -0
- package/build/cards/contributed-to.js +242 -0
- package/build/cards/gist.d.ts +3 -4
- package/build/cards/gist.d.ts.map +1 -1
- package/build/cards/gist.js +38 -43
- package/build/cards/options.d.ts +1 -1
- package/build/cards/repo.d.ts +14 -5
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +93 -103
- package/build/cards/stats.d.ts +18 -11
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +191 -222
- package/build/cards/top-languages.d.ts +18 -33
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +196 -387
- package/build/cards/wakatime.d.ts +17 -8
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +133 -187
- package/build/common/Card.d.ts +20 -59
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +131 -198
- package/build/common/I18n.d.ts +1 -7
- package/build/common/I18n.d.ts.map +1 -1
- package/build/common/I18n.js +7 -8
- package/build/common/brand.d.ts +76 -0
- package/build/common/brand.d.ts.map +1 -0
- package/build/common/brand.js +73 -0
- package/build/common/color.d.ts +4 -17
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +67 -49
- package/build/common/config.d.ts +4 -14
- package/build/common/config.d.ts.map +1 -1
- package/build/common/config.js +3 -16
- package/build/common/constants.d.ts +6 -2
- package/build/common/constants.d.ts.map +1 -1
- package/build/common/constants.js +5 -1
- package/build/common/date.d.ts +50 -5
- package/build/common/date.d.ts.map +1 -1
- package/build/common/date.js +104 -4
- package/build/common/emojiMap.d.ts +8 -0
- package/build/common/emojiMap.d.ts.map +1 -0
- package/build/common/emojiMap.js +10 -0
- package/build/common/emojiMap.json +1915 -0
- package/build/common/error.d.ts +1 -10
- package/build/common/error.d.ts.map +1 -1
- package/build/common/error.js +1 -10
- package/build/common/fmt.d.ts +3 -15
- package/build/common/fmt.d.ts.map +1 -1
- package/build/common/fmt.js +7 -35
- package/build/common/http.d.ts +2 -7
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +8 -17
- package/build/common/icons.d.ts +20 -20
- package/build/common/icons.d.ts.map +1 -1
- package/build/common/icons.js +108 -67
- package/build/common/languageColors.d.ts +0 -1
- package/build/common/languageColors.d.ts.map +1 -1
- package/build/common/languageColors.js +1 -4
- package/build/common/languageColors.json +18 -2
- package/build/common/ops.d.ts +11 -17
- package/build/common/ops.d.ts.map +1 -1
- package/build/common/ops.js +22 -39
- package/build/common/render.d.ts +34 -82
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +225 -259
- package/build/common/retryer.d.ts +2 -7
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +4 -11
- package/build/fetchers/contributed-to.d.ts +62 -0
- package/build/fetchers/contributed-to.d.ts.map +1 -0
- package/build/fetchers/contributed-to.js +184 -0
- package/build/fetchers/gist.d.ts +2 -5
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +1 -5
- package/build/fetchers/graphql-error.d.ts +13 -0
- package/build/fetchers/graphql-error.d.ts.map +1 -0
- package/build/fetchers/graphql-error.js +29 -0
- package/build/fetchers/index.d.ts +13 -12
- package/build/fetchers/index.d.ts.map +1 -1
- package/build/fetchers/index.js +1 -0
- package/build/fetchers/repo.d.ts +2 -11
- package/build/fetchers/repo.d.ts.map +1 -1
- package/build/fetchers/repo.js +20 -33
- package/build/fetchers/stats.d.ts +16 -40
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +89 -271
- package/build/fetchers/top-languages.d.ts +2 -9
- package/build/fetchers/top-languages.d.ts.map +1 -1
- package/build/fetchers/top-languages.js +16 -47
- package/build/fetchers/types.d.ts +25 -1
- package/build/fetchers/types.d.ts.map +1 -1
- package/build/fetchers/wakatime.d.ts +2 -6
- package/build/fetchers/wakatime.d.ts.map +1 -1
- package/build/fetchers/wakatime.js +1 -5
- package/build/graphql/contributionsCollection.d.ts +9 -0
- package/build/graphql/contributionsCollection.d.ts.map +1 -0
- package/build/graphql/contributionsCollection.js +12 -0
- package/build/graphql/contributionsDocument.d.ts +6 -6
- package/build/graphql/contributionsDocument.d.ts.map +1 -1
- package/build/graphql/contributionsDocument.js +8 -16
- package/build/graphql/generated/contributed-to.d.ts +22 -0
- package/build/graphql/generated/contributed-to.d.ts.map +1 -0
- package/build/graphql/generated/contributed-to.js +11 -0
- package/build/graphql/generated/gist.d.ts +1 -1
- package/build/graphql/generated/repo.d.ts +1 -1
- package/build/graphql/generated/stats.d.ts +16 -4
- package/build/graphql/generated/stats.d.ts.map +1 -1
- package/build/graphql/generated/stats.js +2 -2
- package/build/graphql/generated/top-languages.d.ts +2 -2
- package/build/graphql/graphqlDocument.d.ts +1 -2
- package/build/graphql/graphqlDocument.d.ts.map +1 -1
- package/build/graphql/graphqlDocument.js +0 -1
- package/build/graphql/reposContributedToDocument.d.ts +4 -5
- package/build/graphql/reposContributedToDocument.d.ts.map +1 -1
- package/build/graphql/reposContributedToDocument.js +11 -7
- package/build/markup/css.d.ts +35 -0
- package/build/markup/css.d.ts.map +1 -0
- package/build/markup/css.js +64 -0
- package/build/markup/element.d.ts +41 -0
- package/build/markup/element.d.ts.map +1 -0
- package/build/markup/element.js +127 -0
- package/build/markup/html.d.ts +13 -0
- package/build/markup/html.d.ts.map +1 -0
- package/build/markup/html.js +27 -0
- package/build/markup/index.d.ts +9 -0
- package/build/markup/index.d.ts.map +1 -0
- package/build/markup/index.js +6 -0
- package/build/markup/serialize.d.ts +16 -0
- package/build/markup/serialize.d.ts.map +1 -0
- package/build/markup/serialize.js +17 -0
- package/build/themes/index.d.ts +332 -333
- package/build/themes/index.d.ts.map +1 -1
- package/build/themes/index.js +1 -1
- package/build/translations.d.ts +66 -7
- package/build/translations.d.ts.map +1 -1
- package/build/translations.js +686 -629
- package/package.json +17 -26
- package/src/api/api-result.ts +10 -9
- package/src/api/contributed-to.ts +84 -0
- package/src/api/gist.ts +22 -46
- package/src/api/handler.ts +42 -0
- package/src/api/index.ts +13 -12
- package/src/api/params.ts +74 -29
- package/src/api/pin.ts +38 -65
- package/src/api/stats.ts +81 -118
- package/src/api/top-langs.ts +38 -80
- package/src/api/wakatime.ts +35 -73
- package/src/calculateRank.ts +12 -23
- package/src/cards/contributed-to.ts +373 -0
- package/src/cards/gist.ts +55 -49
- package/src/cards/options.ts +1 -1
- package/src/cards/repo.ts +134 -120
- package/src/cards/stats.ts +262 -252
- package/src/cards/top-languages.ts +315 -422
- package/src/cards/wakatime.ts +207 -225
- package/src/common/Card.ts +207 -214
- package/src/common/I18n.ts +7 -8
- package/src/common/brand.ts +109 -0
- package/src/common/color.ts +80 -57
- package/src/common/config.ts +5 -18
- package/src/common/constants.ts +8 -2
- package/src/common/date.ts +135 -5
- package/src/common/emojiMap.json +1915 -0
- package/src/common/emojiMap.ts +13 -0
- package/src/common/error.ts +2 -11
- package/src/common/fmt.ts +7 -44
- package/src/common/http.ts +9 -15
- package/src/common/icons.ts +122 -42
- package/src/common/languageColors.json +18 -2
- package/src/common/languageColors.ts +1 -4
- package/src/common/ops.ts +31 -48
- package/src/common/render.ts +334 -284
- package/src/common/retryer.ts +8 -15
- package/src/fetchers/contributed-to.ts +271 -0
- package/src/fetchers/gist.ts +8 -12
- package/src/fetchers/graphql-error.ts +36 -0
- package/src/fetchers/index.ts +15 -12
- package/src/fetchers/repo.ts +27 -40
- package/src/fetchers/stats.ts +157 -366
- package/src/fetchers/top-languages.ts +27 -55
- package/src/fetchers/types.ts +27 -1
- package/src/fetchers/wakatime.ts +5 -9
- package/src/graphql/contributionsCollection.ts +18 -0
- package/src/graphql/contributionsDocument.ts +14 -19
- package/src/graphql/generated/contributed-to.ts +25 -0
- package/src/graphql/generated/gist.ts +1 -1
- package/src/graphql/generated/repo.ts +1 -1
- package/src/graphql/generated/stats.ts +21 -8
- package/src/graphql/generated/top-languages.ts +2 -2
- package/src/graphql/graphqlDocument.ts +1 -2
- package/src/graphql/queries/contributed-to.graphql +8 -0
- package/src/graphql/queries/stats.graphql +14 -2
- package/src/graphql/reposContributedToDocument.ts +16 -15
- package/src/markup/css.ts +118 -0
- package/src/markup/element.ts +246 -0
- package/src/markup/html.ts +34 -0
- package/src/markup/index.ts +9 -0
- package/src/markup/serialize.ts +27 -0
- package/src/themes/index.ts +1 -1
- package/src/translations.ts +699 -629
- package/build/cards/index.d.ts +0 -11
- package/build/cards/index.d.ts.map +0 -1
- package/build/cards/index.js +0 -7
- package/build/common/html.d.ts +0 -8
- package/build/common/html.d.ts.map +0 -1
- package/build/common/html.js +0 -14
- package/build/index.d.ts +0 -15
- package/build/index.d.ts.map +0 -1
- package/build/index.js +0 -10
- package/src/_emoji-name-map.d.ts +0 -10
- package/src/_github-username-regex.d.ts +0 -4
- package/src/cards/index.ts +0 -21
- package/src/common/html.ts +0 -17
- package/src/index.ts +0 -18
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
import type { CardConfig } from '../common/config.
|
|
2
|
-
import { CardError
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { retryer } from '../common/retryer.js';
|
|
8
|
-
import { TopLanguagesDocument } from '../graphql/generated/top-languages.js';
|
|
1
|
+
import type { CardConfig } from '../common/config.ts';
|
|
2
|
+
import { CardError } from '../common/error.ts';
|
|
3
|
+
import { createGraphQLFetcher } from '../common/http.ts';
|
|
4
|
+
import { parseOwnerAffiliations } from '../common/ops.ts';
|
|
5
|
+
import { retryer } from '../common/retryer.ts';
|
|
6
|
+
import { TopLanguagesDocument } from '../graphql/generated/top-languages.ts';
|
|
9
7
|
import type {
|
|
10
8
|
TopLanguageFragment,
|
|
11
9
|
TopLanguagesRepositoryFragment,
|
|
12
|
-
} from '../graphql/generated/top-languages.
|
|
10
|
+
} from '../graphql/generated/top-languages.ts';
|
|
13
11
|
|
|
14
|
-
import
|
|
12
|
+
import { graphqlError } from './graphql-error.ts';
|
|
13
|
+
import type { Lang, TopLangData } from './types.ts';
|
|
15
14
|
|
|
16
15
|
const fetcher = createGraphQLFetcher(TopLanguagesDocument, 'token');
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* Fetch top languages for a given username.
|
|
20
19
|
*
|
|
21
|
-
* @param props Fetcher props.
|
|
22
|
-
* @param props.username GitHub username.
|
|
23
|
-
* @param props.exclude_repo List of repositories to exclude. Default: [].
|
|
24
|
-
* @param props.size_weight Weightage to be given to size.
|
|
25
|
-
* @param props.count_weight Weightage to be given to count.
|
|
26
|
-
* @param props.ownerAffiliations The owner affiliations to filter by. Default: OWNER.
|
|
27
|
-
* @param config Deployment config supplying the PAT pool.
|
|
28
20
|
* @returns Top languages data.
|
|
29
21
|
*/
|
|
30
22
|
const fetchTopLanguages = async (
|
|
@@ -58,23 +50,10 @@ const fetchTopLanguages = async (
|
|
|
58
50
|
);
|
|
59
51
|
|
|
60
52
|
if (res.data.errors) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
throw new CardError(firstError.message || 'Could not fetch user.', {
|
|
65
|
-
code: 'not_found',
|
|
66
|
-
secondaryMessage: USER_NOT_FOUND,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
if (firstError?.message) {
|
|
70
|
-
throw new CardError(wrapTextMultiline(firstError.message, 525, 12)[0] ?? '', {
|
|
71
|
-
code: 'upstream',
|
|
72
|
-
secondaryMessage: res.statusText,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
throw new CardError(
|
|
53
|
+
throw graphqlError(
|
|
54
|
+
res.data.errors,
|
|
55
|
+
res.statusText,
|
|
76
56
|
'Something went wrong while trying to retrieve the language data using the GraphQL API.',
|
|
77
|
-
{ code: 'upstream' },
|
|
78
57
|
);
|
|
79
58
|
}
|
|
80
59
|
|
|
@@ -82,53 +61,46 @@ const fetchTopLanguages = async (
|
|
|
82
61
|
const allExcludedRepos = [...exclude_repo, ...config.excludeRepositories];
|
|
83
62
|
|
|
84
63
|
// populate repoToHide map for quick lookup while filtering out
|
|
85
|
-
|
|
64
|
+
for (const repoName of allExcludedRepos) {
|
|
86
65
|
repoToHide[repoName] = true;
|
|
87
|
-
}
|
|
66
|
+
}
|
|
88
67
|
|
|
89
68
|
// filter out repositories to be hidden
|
|
90
69
|
const repoNodes = (res.data.data.user?.repositories.nodes ?? []).filter(
|
|
91
70
|
(node): node is TopLanguagesRepositoryFragment => !!node && !repoToHide[node.name],
|
|
92
71
|
);
|
|
93
72
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const languageEdges = repoNodes.reduce<Array<TopLanguageFragment>>((acc, repo) => {
|
|
73
|
+
let languageEdges: Array<TopLanguageFragment> = [];
|
|
74
|
+
for (const repo of repoNodes) {
|
|
97
75
|
const edges = (repo.languages?.edges ?? []).filter(
|
|
98
76
|
(edge): edge is TopLanguageFragment => !!edge,
|
|
99
77
|
);
|
|
100
|
-
|
|
101
|
-
|
|
78
|
+
if (edges.length > 0) {
|
|
79
|
+
languageEdges = [...edges, ...languageEdges];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
102
82
|
|
|
103
|
-
// accumulate size and repo count per language
|
|
83
|
+
// accumulate size and repo count per language, each read back off the language's own entry
|
|
104
84
|
const languageMap: Record<string, Lang> = {};
|
|
105
|
-
let repoCount = 0;
|
|
106
85
|
for (const edge of languageEdges) {
|
|
107
86
|
const existing = languageMap[edge.node.name];
|
|
108
|
-
|
|
109
|
-
// same language seen again: add to its size and bump count; else reset to 1
|
|
110
|
-
let langSize = edge.size;
|
|
111
|
-
if (existing && edge.node.name === existing.name) {
|
|
112
|
-
langSize = edge.size + existing.size;
|
|
113
|
-
repoCount += 1;
|
|
114
|
-
} else {
|
|
115
|
-
repoCount = 1;
|
|
116
|
-
}
|
|
117
87
|
languageMap[edge.node.name] = {
|
|
118
88
|
name: edge.node.name,
|
|
119
89
|
color: edge.node.color,
|
|
120
|
-
size:
|
|
121
|
-
count:
|
|
90
|
+
size: edge.size + (existing?.size ?? 0),
|
|
91
|
+
count: (existing?.count ?? 0) + 1,
|
|
122
92
|
};
|
|
123
93
|
}
|
|
124
94
|
|
|
125
95
|
// comparison index calculation
|
|
126
96
|
for (const lang of Object.values(languageMap)) {
|
|
127
|
-
lang.size =
|
|
97
|
+
lang.size = lang.size ** size_weight * lang.count ** count_weight;
|
|
128
98
|
}
|
|
129
99
|
|
|
130
100
|
// return languages sorted by (weighted) size, descending
|
|
131
|
-
return Object.fromEntries(
|
|
101
|
+
return Object.fromEntries(
|
|
102
|
+
Object.entries(languageMap).toSorted(([, a], [, b]) => b.size - a.size),
|
|
103
|
+
);
|
|
132
104
|
};
|
|
133
105
|
|
|
134
106
|
export { fetchTopLanguages };
|
package/src/fetchers/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { GitHubDateRange } from '../common/date.ts';
|
|
2
|
+
import type { RepoInfoFragment } from '../graphql/generated/repo.ts';
|
|
2
3
|
|
|
3
4
|
export interface GistData {
|
|
4
5
|
name: string;
|
|
@@ -39,6 +40,8 @@ export interface StatsData {
|
|
|
39
40
|
mergedPRsPercentage: number;
|
|
40
41
|
totalReviews: number;
|
|
41
42
|
totalCommits: number;
|
|
43
|
+
/** The range `totalCommits` covers; `undefined` when it is GitHub's own last year, or all time. */
|
|
44
|
+
commitsRange: GitHubDateRange | undefined;
|
|
42
45
|
totalIssues: number;
|
|
43
46
|
totalStars: number;
|
|
44
47
|
totalDiscussionsStarted: number;
|
|
@@ -54,6 +57,29 @@ export interface StatsData {
|
|
|
54
57
|
rank: { level: string; percentile: number };
|
|
55
58
|
}
|
|
56
59
|
|
|
60
|
+
/** One repository a user contributed to, as the card ranks it. */
|
|
61
|
+
export interface ContributedRepo {
|
|
62
|
+
nameWithOwner: string;
|
|
63
|
+
/**
|
|
64
|
+
* Commit-days plus issues and pull requests opened, summed over every year.
|
|
65
|
+
* Not a commit count: GitHub groups commit contributions by day, not by commit.
|
|
66
|
+
*/
|
|
67
|
+
contributions: number;
|
|
68
|
+
/** Every year the user contributed to it, ascending. */
|
|
69
|
+
years: Array<number>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ContributedToData {
|
|
73
|
+
/** GitHub's own casing of the login, which the query param need not match. */
|
|
74
|
+
login: string;
|
|
75
|
+
/** The ranked slice, most contributions first. */
|
|
76
|
+
repos: Array<ContributedRepo>;
|
|
77
|
+
/** Every repository the walk found, which `repos` is a slice of. */
|
|
78
|
+
totalRepos: number;
|
|
79
|
+
/** The account's contribution years, ascending — the range the year marks cover. */
|
|
80
|
+
years: Array<number>;
|
|
81
|
+
}
|
|
82
|
+
|
|
57
83
|
export interface Lang {
|
|
58
84
|
name: string;
|
|
59
85
|
// GitHub's GraphQL `Language.color` is nullable — the card falls back to a default.
|
package/src/fetchers/wakatime.ts
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import type { CardConfig } from '../common/config.
|
|
2
|
-
import { CardError, WAKATIME_USER_NOT_FOUND } from '../common/error.
|
|
3
|
-
import { httpRequest } from '../common/http.
|
|
1
|
+
import type { CardConfig } from '../common/config.ts';
|
|
2
|
+
import { CardError, WAKATIME_USER_NOT_FOUND } from '../common/error.ts';
|
|
3
|
+
import { httpRequest } from '../common/http.ts';
|
|
4
4
|
|
|
5
|
-
import type { WakaTimeData } from './types.
|
|
5
|
+
import type { WakaTimeData } from './types.ts';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* WakaTime data fetcher.
|
|
9
9
|
*
|
|
10
10
|
* WakaTime needs no GitHub token; the config is here for the transport it carries.
|
|
11
11
|
*
|
|
12
|
-
* @param props Fetcher props.
|
|
13
|
-
* @param props.username WakaTime username.
|
|
14
|
-
* @param props.api_domain Optional WakaTime API domain (defaults to `wakatime.com`).
|
|
15
|
-
* @param config Deployment config supplying the transport.
|
|
16
12
|
* @returns WakaTime data response.
|
|
17
13
|
*/
|
|
18
14
|
const fetchWakatimeStats = async (
|
|
@@ -29,7 +25,7 @@ const fetchWakatimeStats = async (
|
|
|
29
25
|
throw CardError.missingParam(['username']);
|
|
30
26
|
}
|
|
31
27
|
|
|
32
|
-
const domain = api_domain ? api_domain.
|
|
28
|
+
const domain = api_domain ? api_domain.replaceAll(/\/$/gi, '') : 'wakatime.com';
|
|
33
29
|
const res = await httpRequest<{ data: WakaTimeData }>(
|
|
34
30
|
config.fetch,
|
|
35
31
|
`https://${domain}/api/v1/users/${username}/stats?is_including_today=true`,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { GitHubDateRange } from '../common/date.ts';
|
|
2
|
+
import { toGitHubDateTime } from '../common/date.ts';
|
|
3
|
+
|
|
4
|
+
/** Naming `to` is not optional: GitHub defaults an omitted one to a year after `from`. */
|
|
5
|
+
const contributionsCollectionOf = ({ from, to }: GitHubDateRange): string =>
|
|
6
|
+
`contributionsCollection(from: "${toGitHubDateTime(from)}", to: "${toGitHubDateTime(to)}")`;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* One `contributionsCollection` field per range, aliased by position.
|
|
10
|
+
*
|
|
11
|
+
* @returns The fields, for a query that selects `fragment`.
|
|
12
|
+
*/
|
|
13
|
+
const aliasedRanges = (ranges: Array<GitHubDateRange>, fragment: string): string =>
|
|
14
|
+
ranges
|
|
15
|
+
.map((range, index) => `range_${index}: ${contributionsCollectionOf(range)} { ...${fragment} }`)
|
|
16
|
+
.join('\n');
|
|
17
|
+
|
|
18
|
+
export { aliasedRanges };
|
|
@@ -1,44 +1,39 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { GitHubDateRange } from '../common/date.ts';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import { aliasedRanges } from './contributionsCollection.ts';
|
|
4
|
+
import type { RangeContributionsFragment } from './generated/stats.ts';
|
|
5
|
+
import type { GraphQLDocument } from './graphqlDocument.ts';
|
|
6
|
+
import { graphqlDocument } from './graphqlDocument.ts';
|
|
5
7
|
|
|
6
8
|
interface ContributionsQueryVariables {
|
|
7
9
|
login: string;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
interface ContributionsQuery {
|
|
11
|
-
user: Record<`
|
|
13
|
+
user: Record<`range_${number}`, RangeContributionsFragment> | null;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
|
-
* Build the
|
|
16
|
-
* The shape is only known at runtime.
|
|
17
|
+
* Build the contributions query for a set of ranges. The shape is only known at runtime.
|
|
17
18
|
*
|
|
18
|
-
* @param years Contribution years, one `year_<year>` alias each.
|
|
19
19
|
* @returns Document for `createGraphQLFetcher`.
|
|
20
20
|
*/
|
|
21
|
-
const buildContributionsDocument = (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const { from, to } = getGitHubYearRange(year);
|
|
25
|
-
return `year_${year}: contributionsCollection(from: "${toGitHubDateTime(from)}", to: "${toGitHubDateTime(to)}") { ...YearContributions }`;
|
|
26
|
-
})
|
|
27
|
-
.join('\n');
|
|
28
|
-
|
|
21
|
+
const buildContributionsDocument = (
|
|
22
|
+
ranges: Array<GitHubDateRange>,
|
|
23
|
+
): GraphQLDocument<ContributionsQuery, ContributionsQueryVariables> =>
|
|
29
24
|
// fragment must match queries/stats.graphql, which generates its type
|
|
30
|
-
|
|
25
|
+
graphqlDocument<ContributionsQuery, ContributionsQueryVariables>(`
|
|
31
26
|
query userContributions($login: String!) {
|
|
32
27
|
user(login: $login) {
|
|
33
|
-
${
|
|
28
|
+
${aliasedRanges(ranges, 'RangeContributions')}
|
|
34
29
|
}
|
|
35
30
|
}
|
|
36
|
-
fragment
|
|
31
|
+
fragment RangeContributions on ContributionsCollection {
|
|
32
|
+
totalCommitContributions
|
|
37
33
|
contributionCalendar {
|
|
38
34
|
totalContributions
|
|
39
35
|
}
|
|
40
36
|
}`);
|
|
41
|
-
};
|
|
42
37
|
|
|
43
38
|
export { buildContributionsDocument };
|
|
44
39
|
export type { ContributionsQuery };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Generated file — see .github/CONTRIBUTING.md
|
|
2
|
+
|
|
3
|
+
/** Internal type. DO NOT USE DIRECTLY. */
|
|
4
|
+
type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
|
5
|
+
import { graphqlDocument } from '../graphqlDocument.ts';
|
|
6
|
+
export type UserContributionYearsQueryVariables = Exact<{
|
|
7
|
+
login: string;
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
export type UserContributionYearsQuery = {
|
|
11
|
+
user: { login: string; contributionsCollection: { contributionYears: Array<number> } } | null;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const UserContributionYearsDocument = graphqlDocument<
|
|
15
|
+
UserContributionYearsQuery,
|
|
16
|
+
UserContributionYearsQueryVariables
|
|
17
|
+
>(`
|
|
18
|
+
query userContributionYears($login: String!) {
|
|
19
|
+
user(login: $login) {
|
|
20
|
+
login
|
|
21
|
+
contributionsCollection {
|
|
22
|
+
contributionYears
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}`);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/** Internal type. DO NOT USE DIRECTLY. */
|
|
4
4
|
type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
|
5
|
-
import { graphqlDocument } from '../graphqlDocument.
|
|
5
|
+
import { graphqlDocument } from '../graphqlDocument.ts';
|
|
6
6
|
export type GistFileInfoFragment = {
|
|
7
7
|
name: string | null;
|
|
8
8
|
size: number | null;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/** Internal type. DO NOT USE DIRECTLY. */
|
|
4
4
|
type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
|
5
|
-
import { graphqlDocument } from '../graphqlDocument.
|
|
5
|
+
import { graphqlDocument } from '../graphqlDocument.ts';
|
|
6
6
|
export type RepoInfoFragment = {
|
|
7
7
|
name: string;
|
|
8
8
|
nameWithOwner: string;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
/** Internal type. DO NOT USE DIRECTLY. */
|
|
4
4
|
type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
|
5
|
-
import { graphqlDocument } from '../graphqlDocument.
|
|
5
|
+
import { graphqlDocument } from '../graphqlDocument.ts';
|
|
6
6
|
|
|
7
|
-
import type * as Types from './common.
|
|
7
|
+
import type * as Types from './common.ts';
|
|
8
8
|
export type RepoNodeFragment = { name: string; stargazerCount: number };
|
|
9
9
|
|
|
10
10
|
export type RepoStarsFragment = {
|
|
@@ -42,6 +42,7 @@ export type UserInfoQueryVariables = Exact<{
|
|
|
42
42
|
includeDiscussions: boolean;
|
|
43
43
|
includeDiscussionsAnswers: boolean;
|
|
44
44
|
startTime?: string | null | undefined;
|
|
45
|
+
endTime?: string | null | undefined;
|
|
45
46
|
ownerAffiliations?:
|
|
46
47
|
| Array<Types.RepositoryAffiliation | null | undefined>
|
|
47
48
|
| Types.RepositoryAffiliation
|
|
@@ -73,12 +74,24 @@ export type UserInfoQuery = {
|
|
|
73
74
|
} | null;
|
|
74
75
|
};
|
|
75
76
|
|
|
76
|
-
export type
|
|
77
|
+
export type RangeContributionsFragment = {
|
|
78
|
+
totalCommitContributions: number;
|
|
79
|
+
contributionCalendar: { totalContributions: number };
|
|
80
|
+
};
|
|
77
81
|
|
|
78
82
|
export type RangeContributionsByRepoFragment = {
|
|
79
|
-
commitContributionsByRepository: Array<{
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
commitContributionsByRepository: Array<{
|
|
84
|
+
repository: { nameWithOwner: string };
|
|
85
|
+
contributions: { totalCount: number };
|
|
86
|
+
}>;
|
|
87
|
+
issueContributionsByRepository: Array<{
|
|
88
|
+
repository: { nameWithOwner: string };
|
|
89
|
+
contributions: { totalCount: number };
|
|
90
|
+
}>;
|
|
91
|
+
pullRequestContributionsByRepository: Array<{
|
|
92
|
+
repository: { nameWithOwner: string };
|
|
93
|
+
contributions: { totalCount: number };
|
|
94
|
+
}>;
|
|
82
95
|
repositoryContributions?: {
|
|
83
96
|
nodes: Array<{ repository: { nameWithOwner: string } } | null> | null;
|
|
84
97
|
};
|
|
@@ -113,11 +126,11 @@ fragment RepoNode on Repository {
|
|
|
113
126
|
}`);
|
|
114
127
|
|
|
115
128
|
export const UserInfoDocument = graphqlDocument<UserInfoQuery, UserInfoQueryVariables>(`
|
|
116
|
-
query userInfo($login: String!, $after: String, $includeMergedPullRequests: Boolean!, $includeDiscussions: Boolean!, $includeDiscussionsAnswers: Boolean!, $startTime: DateTime = null, $ownerAffiliations: [RepositoryAffiliation], $includeUserRepositories: Boolean!) {
|
|
129
|
+
query userInfo($login: String!, $after: String, $includeMergedPullRequests: Boolean!, $includeDiscussions: Boolean!, $includeDiscussionsAnswers: Boolean!, $startTime: DateTime = null, $endTime: DateTime = null, $ownerAffiliations: [RepositoryAffiliation], $includeUserRepositories: Boolean!) {
|
|
117
130
|
user(login: $login) {
|
|
118
131
|
name
|
|
119
132
|
login
|
|
120
|
-
commits: contributionsCollection(from: $startTime) {
|
|
133
|
+
commits: contributionsCollection(from: $startTime, to: $endTime) {
|
|
121
134
|
totalCommitContributions
|
|
122
135
|
}
|
|
123
136
|
reviews: contributionsCollection {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
/** Internal type. DO NOT USE DIRECTLY. */
|
|
4
4
|
type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
|
5
|
-
import { graphqlDocument } from '../graphqlDocument.
|
|
5
|
+
import { graphqlDocument } from '../graphqlDocument.ts';
|
|
6
6
|
|
|
7
|
-
import type * as Types from './common.
|
|
7
|
+
import type * as Types from './common.ts';
|
|
8
8
|
export type TopLanguageFragment = { size: number; node: { color: string | null; name: string } };
|
|
9
9
|
|
|
10
10
|
export type TopLanguagesRepositoryFragment = {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `text` is what goes over the wire; the other two members only carry types and are never assigned.
|
|
5
5
|
* Documents are generated from `queries/*.graphql`
|
|
6
|
-
* See `scripts/generate-graphql-types.
|
|
6
|
+
* See `scripts/generate-graphql-types.ts`.
|
|
7
7
|
*/
|
|
8
8
|
interface GraphQLDocument<TResult, TVariables> {
|
|
9
9
|
readonly text: string;
|
|
@@ -14,7 +14,6 @@ interface GraphQLDocument<TResult, TVariables> {
|
|
|
14
14
|
/**
|
|
15
15
|
* Build a typed document.
|
|
16
16
|
*
|
|
17
|
-
* @param text The query text, including every fragment it spreads.
|
|
18
17
|
* @returns The document to pass to the function created by `createGraphQLFetcher`.
|
|
19
18
|
*/
|
|
20
19
|
const graphqlDocument = <TResult, TVariables>(
|
|
@@ -34,13 +34,14 @@ query userInfo(
|
|
|
34
34
|
$includeDiscussions: Boolean!
|
|
35
35
|
$includeDiscussionsAnswers: Boolean!
|
|
36
36
|
$startTime: DateTime = null
|
|
37
|
+
$endTime: DateTime = null
|
|
37
38
|
$ownerAffiliations: [RepositoryAffiliation]
|
|
38
39
|
$includeUserRepositories: Boolean!
|
|
39
40
|
) {
|
|
40
41
|
user(login: $login) {
|
|
41
42
|
name
|
|
42
43
|
login
|
|
43
|
-
commits: contributionsCollection(from: $startTime) {
|
|
44
|
+
commits: contributionsCollection(from: $startTime, to: $endTime) {
|
|
44
45
|
totalCommitContributions
|
|
45
46
|
}
|
|
46
47
|
reviews: contributionsCollection {
|
|
@@ -81,27 +82,38 @@ query userInfo(
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
fragment
|
|
85
|
+
fragment RangeContributions on ContributionsCollection {
|
|
86
|
+
totalCommitContributions
|
|
85
87
|
contributionCalendar {
|
|
86
88
|
totalContributions
|
|
87
89
|
}
|
|
88
90
|
}
|
|
89
91
|
|
|
92
|
+
# `contributions` takes no slicing argument on purpose: `totalCount` alone costs no nodes.
|
|
90
93
|
fragment RangeContributionsByRepo on ContributionsCollection {
|
|
91
94
|
commitContributionsByRepository(maxRepositories: $maxRepositories) {
|
|
92
95
|
repository {
|
|
93
96
|
nameWithOwner
|
|
94
97
|
}
|
|
98
|
+
contributions {
|
|
99
|
+
totalCount
|
|
100
|
+
}
|
|
95
101
|
}
|
|
96
102
|
issueContributionsByRepository(maxRepositories: $maxRepositories) {
|
|
97
103
|
repository {
|
|
98
104
|
nameWithOwner
|
|
99
105
|
}
|
|
106
|
+
contributions {
|
|
107
|
+
totalCount
|
|
108
|
+
}
|
|
100
109
|
}
|
|
101
110
|
pullRequestContributionsByRepository(maxRepositories: $maxRepositories) {
|
|
102
111
|
repository {
|
|
103
112
|
nameWithOwner
|
|
104
113
|
}
|
|
114
|
+
contributions {
|
|
115
|
+
totalCount
|
|
116
|
+
}
|
|
105
117
|
}
|
|
106
118
|
repositoryContributions(first: $maxRepositories) @include(if: $includeOwnRepos) {
|
|
107
119
|
nodes {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { GitHubDateRange } from '../common/date.
|
|
2
|
-
import { toGitHubDateTime } from '../common/date.js';
|
|
1
|
+
import type { GitHubDateRange } from '../common/date.ts';
|
|
3
2
|
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import { aliasedRanges } from './contributionsCollection.ts';
|
|
4
|
+
import type { RangeContributionsByRepoFragment } from './generated/stats.ts';
|
|
5
|
+
import type { GraphQLDocument } from './graphqlDocument.ts';
|
|
6
|
+
import { graphqlDocument } from './graphqlDocument.ts';
|
|
6
7
|
|
|
7
8
|
/** max value GitHub allows for `first/maxRepositories` */
|
|
8
9
|
const MAX_REPOSITORIES_LIMIT = 100;
|
|
@@ -24,21 +25,12 @@ interface ReposContributedToQuery {
|
|
|
24
25
|
* Mirrors the `contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]`
|
|
25
26
|
* filter used by `repositoriesContributedTo` in `stats.graphql`.
|
|
26
27
|
*
|
|
27
|
-
* @param ranges Ranges to fetch, one `range_<index>` alias each.
|
|
28
|
-
* @param includeOwnRepos Whether to select `repositoryContributions`.
|
|
29
28
|
* @returns Document for `createGraphQLFetcher`.
|
|
30
29
|
*/
|
|
31
30
|
const buildReposContributedToDocument = (
|
|
32
31
|
ranges: Array<GitHubDateRange>,
|
|
33
32
|
includeOwnRepos: boolean,
|
|
34
|
-
) => {
|
|
35
|
-
const rangeFields = ranges
|
|
36
|
-
.map(
|
|
37
|
-
({ from, to }, index) =>
|
|
38
|
-
`range_${index}: contributionsCollection(from: "${toGitHubDateTime(from)}", to: "${toGitHubDateTime(to)}") { ...RangeContributionsByRepo }`,
|
|
39
|
-
)
|
|
40
|
-
.join('\n');
|
|
41
|
-
|
|
33
|
+
): GraphQLDocument<ReposContributedToQuery, ReposContributedToQueryVariables> => {
|
|
42
34
|
// `repositoryContributions` only ever returns repos the user owns,
|
|
43
35
|
// so it is left out rather than gated with @include: an excluded field still counts toward the query's node cost.
|
|
44
36
|
// stats.graphql carries the directive so the generated type marks the field optional.
|
|
@@ -56,7 +48,7 @@ const buildReposContributedToDocument = (
|
|
|
56
48
|
return graphqlDocument<ReposContributedToQuery, ReposContributedToQueryVariables>(`
|
|
57
49
|
query userReposContributedTo($login: String!, $maxRepositories: Int!) {
|
|
58
50
|
user(login: $login) {
|
|
59
|
-
${
|
|
51
|
+
${aliasedRanges(ranges, 'RangeContributionsByRepo')}
|
|
60
52
|
}
|
|
61
53
|
}
|
|
62
54
|
fragment RangeContributionsByRepo on ContributionsCollection {
|
|
@@ -64,16 +56,25 @@ fragment RangeContributionsByRepo on ContributionsCollection {
|
|
|
64
56
|
repository {
|
|
65
57
|
nameWithOwner
|
|
66
58
|
}
|
|
59
|
+
contributions {
|
|
60
|
+
totalCount
|
|
61
|
+
}
|
|
67
62
|
}
|
|
68
63
|
issueContributionsByRepository(maxRepositories: $maxRepositories) {
|
|
69
64
|
repository {
|
|
70
65
|
nameWithOwner
|
|
71
66
|
}
|
|
67
|
+
contributions {
|
|
68
|
+
totalCount
|
|
69
|
+
}
|
|
72
70
|
}
|
|
73
71
|
pullRequestContributionsByRepository(maxRepositories: $maxRepositories) {
|
|
74
72
|
repository {
|
|
75
73
|
nameWithOwner
|
|
76
74
|
}
|
|
75
|
+
contributions {
|
|
76
|
+
totalCount
|
|
77
|
+
}
|
|
77
78
|
}
|
|
78
79
|
${ownRepoField}
|
|
79
80
|
}`);
|