UNPKG

@fajarkim/github-readme-profile

Version:

🙀 Generate your Stats GitHub Profile in SVG

369 lines (339 loc) • 11 kB
import axios from "axios"; import { getToken, getToken2, getToken3 } from "../getToken"; /** * Represents a user's information and statistics. * * @interface User * @property {string} name - The name of the user. * @property {string} login - The login username of the user. * @property {string} avatarUrl - The URL of the user's avatar. * @property {Repositories} repositories - Information about user repositories. * @property {Followers} followers - Information about user followers. * @property {Following} following - Information about users being followed by the user. * @property {OpenedIssues} openedIssues - Information about opened issues by the user. * @property {ClosedIssues} closedIssues - Information about closed issues by the user. * @property {PullRequests} pullRequests - Information about user pull requests. * @property {MergedPullRequests} mergedPullRequests - Information about merged pull requests by the user. * @property {DiscussionStarted} discussionStarted - Information about discussions started by the user. * @property {DiscussionAnswered} discussionAnswered - Information about discussions answered by the user. * @property {RepositoriesContributedTo} repositoriesContributedTo - Information about repositories contributed to by the user. * @property {number} totalCommitContributions - The total count of commit contributions by the user. * @property {number} restrictedContributionsCount - The count of restricted contributions by the user. * @property {number} totalPullRequestReviewContributions - The total count of pull request review contributions by the user. */ interface User { name: string; login: string; avatarUrl: string; repositories: Repositories; followers: Followers; following: Following; openedIssues: OpenedIssues; closedIssues: ClosedIssues; pullRequests: PullRequests; mergedPullRequests: MergedPullRequests; discussionStarted: DiscussionStarted; discussionAnswered: DiscussionAnswered; repositoriesContributedTo: RepositoriesContributedTo; totalCommitContributions: number; restrictedContributionsCount: number; totalPullRequestReviewContributions: number; } /** * Represents information about user repositories. * * @interface Repositories * @property {number} totalCount - The total count of repositories. */ interface Repositories { totalCount: number; } /** * Represents information about user followers. * * @interface Followers * @property {number} totalCount - The total count of followers. */ interface Followers { totalCount: number; } /** * Represents information about user following. * * @interface Following * @property {number} totalCount - The total count of following. */ interface Following { totalCount: number; } /** * Represents contributions data collected over a specific time period. * * @interface ContributionsCollection * @property {number} totalCommitContributions - The total count of commit contributions. * @property {number} restrictedContributionsCount - The count of restricted contributions. * @property {number} totalPullRequestReviewContributions - The total count of pull request review contributions. */ interface ContributionsCollection { totalCommitContributions: number; restrictedContributionsCount: number; totalPullRequestReviewContributions: number; } /** * Represents information about user opened issues. * * @interface OpenedIssues * @property {number} totalCount - The total count of opened issues. */ interface OpenedIssues { totalCount: number; } /** * Represents information about user closed issues. * * @interface ClosedIssues * @property {number} totalCount - The total count of closed issues. */ interface ClosedIssues { totalCount: number; } /** * Represents information about user pull requests. * * @interface PullRequests * @property {number} totalCount - The total count of pull requests. */ interface PullRequests { totalCount: number; } /** * Represents information about user merged pull requests. * * @interface MergedPullRequests * @property {number} totalCount - The total count of merged pull requests. */ interface MergedPullRequests { totalCount: number; } /** * Represents information about user discussion started. * * @interface DiscussionStarted * @property {number} totalCount - The total count of discussion started. */ interface DiscussionStarted { totalCount: number; } /** * Represents information about user discussion answered. * * @interface DiscussionAnswered * @property {number} totalCount - The total count of discussion answered. */ interface DiscussionAnswered { totalCount: number; } /** * Represents information about user repositories contributed to. * * @interface RepositoriesContributedTo * @property {number} totalCount - The total count of repositories contributed to. */ interface RepositoriesContributedTo { totalCount: number; } /** * Fetches the user's join year based on the provided username. * * @param {string} username - The GitHub username of the user. * @returns {Promise<number>} - A promise that resolves with the user's join year. */ async function getUserJoinYear(username: string): Promise<number> { const data = await axios({ method: "post", url: "https://api.github.com/graphql", headers: { "User-Agent": "FajarKim/github-readme-profile", Authorization: getToken3(true), }, data: { query: `query userInfo($username: String!) { user(login: $username) { createdAt } }`, variables: { username, }, }, }); if (data.data.errors?.length > 0) { throw new Error(data.data.errors[0].message); } const user = data.data.data.user; if (!user || !user.createdAt) { throw new Error("User data is missing."); } const joinDate = new Date(user.createdAt); return joinDate.getFullYear(); } /** * Fetches the contributions data for the specified year. * * @param {string} username - The GitHub username of the user. * @param {number} year - The year for which contributions data is fetched. * @returns {Promise<ContributionsCollection>} - A promise that resolves with contributions data. */ async function fetchContributions(username: string, year: number): Promise<ContributionsCollection> { const from = `${year}-01-01T00:00:00Z`; const to = `${year}-12-31T23:59:59Z`; const data = await axios({ method: "post", url: "https://api.github.com/graphql", headers: { "User-Agent": "FajarKim/github-readme-profile", Authorization: getToken2(true), }, data: { query: `query userInfo($username: String!, $from: DateTime!, $to: DateTime!) { user(login: $username) { contributionsCollection(from: $from, to: $to) { totalCommitContributions restrictedContributionsCount totalPullRequestReviewContributions } } }`, variables: { username, from, to, }, }, }); if (data.data.errors?.length > 0) { throw new Error(data.data.errors[0].message); } const contributions = data.data.data.user.contributionsCollection; return { totalCommitContributions: contributions.totalCommitContributions, restrictedContributionsCount: contributions.restrictedContributionsCount, totalPullRequestReviewContributions: contributions.totalPullRequestReviewContributions, }; } /** * Fetches various statistics and information about the user. * * @param {string} username - The GitHub username of the user. * @returns {Promise<User>} - A promise that resolves with the user's information and statistics. */ async function stats(username: string): Promise<User> { const startYear = await getUserJoinYear(username); const endYear = new Date().getFullYear(); const contributionPromises = []; for (let year = startYear; year <= endYear; year++) { contributionPromises.push(fetchContributions(username, year)); } const contributions = await Promise.all(contributionPromises); const TotalCommitContributions = contributions.reduce( (total, contribution) => total + contribution.totalCommitContributions, 0 ); const RestrictedContributionsCount = contributions.reduce( (total, contribution) => total + contribution.restrictedContributionsCount, 0 ); const TotalPullRequestReviewContributions = contributions.reduce( (total, contribution) => total + contribution.totalPullRequestReviewContributions, 0 ); const data = await axios({ method: "post", url: "https://api.github.com/graphql", headers: { "User-Agent": "FajarKim/github-readme-profile", Authorization: getToken(true), }, data: { query: `query userInfo($username: String!) { user(login: $username) { name login avatarUrl repositories(ownerAffiliations: OWNER, privacy: PUBLIC) { totalCount } followers { totalCount } following { totalCount } openedIssues: issues(states: OPEN) { totalCount } closedIssues: issues(states: CLOSED) { totalCount } pullRequests(first: 1) { totalCount } mergedPullRequests: pullRequests(states: MERGED) { totalCount } discussionStarted: repositoryDiscussions { totalCount } discussionAnswered: repositoryDiscussionComments(onlyAnswers: true) { totalCount } repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) { totalCount } } }`, variables: { username, }, }, }); if (data.data.errors?.length > 0) throw new Error(data.data.errors[0].message); const user = data.data.data.user; return { name: user.name, login: user.login, avatarUrl: user.avatarUrl, repositories: user.repositories, followers: user.followers, following: user.following, openedIssues: user.openedIssues, closedIssues: user.closedIssues, pullRequests: user.pullRequests, mergedPullRequests: user.mergedPullRequests, discussionStarted: user.discussionStarted, discussionAnswered: user.discussionAnswered, repositoriesContributedTo: user.repositoriesContributedTo, totalCommitContributions: TotalCommitContributions, restrictedContributionsCount: RestrictedContributionsCount, totalPullRequestReviewContributions: TotalPullRequestReviewContributions, }; } export { User, Repositories, Followers, Following, ContributionsCollection, OpenedIssues, ClosedIssues, PullRequests, MergedPullRequests, DiscussionStarted, DiscussionAnswered, RepositoriesContributedTo, getUserJoinYear, fetchContributions, stats }; export default stats;