gh-star-fetch
Version:
Fetch all the starred repositories for a GitHub user
150 lines (149 loc) • 4.88 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.setHttpClient = exports.compactByTopic = exports.compactByLanguage = exports.getNextPage = void 0;
const parse_link_header_1 = __importDefault(require("parse-link-header"));
const client_1 = require("./client");
function getNextPage({ next, last }) {
if (!next?.page || !last?.page)
return null;
if (next.page === last.page)
return null;
return next.page;
}
exports.getNextPage = getNextPage;
async function* paginateStars(url, opts) {
let nextPage = '1';
while (nextPage) {
try {
const { headers, body } = await opts.http.get(url, {
searchParams: {
per_page: 100,
page: nextPage,
},
});
for (const record of body) {
yield record;
}
const links = (0, parse_link_header_1.default)(headers.link);
if (!links)
return; // exit if no page
nextPage = getNextPage(links);
if (!opts.accessToken) {
console.warn('No github access token provided, limiting call to first page to avoid rate limit ban');
break;
}
}
catch (e) {
console.error('[http-error]:', e?.response?.body || e);
break;
}
}
}
function compactByLanguage(data, _transform = transform) {
return data.reduce((acc, val) => {
const language = val.language || 'miscellaneous';
acc[language] ||= [];
const parsed = typeof _transform !== 'function' ? val : _transform(val);
acc[language].push(parsed);
return acc;
}, {});
}
exports.compactByLanguage = compactByLanguage;
function compactByTopic(data, _transform = transform) {
return data.reduce((acc, val) => {
if (!Array.isArray(val.topics))
return acc;
const topics = val.topics.length === 0 ? ['miscellaneous'] : val.topics;
for (const topic of topics) {
if (!Array.isArray(acc[topic]))
acc[topic] = [];
const parsed = typeof _transform !== 'function' ? val : _transform(val);
acc[topic].push(parsed);
}
return acc;
}, {});
}
exports.compactByTopic = compactByTopic;
async function apiGetStar(opts) {
const data = [];
const API_STARRED_URL = `users/${opts.username}/starred`;
for await (const star of paginateStars(API_STARRED_URL, opts)) {
data.push(star);
}
if (opts.compactByLanguage) {
return compactByLanguage(data, opts.transform);
}
if (opts.compactByTopic) {
return compactByTopic(data, opts.transform);
}
if (typeof opts.transform !== 'function')
return data;
return data.map((star) => opts.transform(star));
}
function transform(star) {
return {
id: star.id,
node_id: star.node_id,
name: star.name,
full_name: star.full_name,
owner: {
login: star?.owner?.login,
id: star?.owner?.id,
avatar_url: star?.owner?.avatar_url,
url: star?.owner?.url,
html_url: star?.owner?.html_url,
},
html_url: star.html_url,
description: star.description,
url: star.url,
languages_url: star.languages_url,
created_at: star.created_at,
updated_at: star.updated_at,
git_url: star.git_url,
ssh_url: star.ssh_url,
clone_url: star.clone_url,
homepage: star.homepage,
stargazers_count: star.stargazers_count,
watchers_count: star.watchers_count,
language: star.language,
topics: star.topics,
};
}
const DEFAULT_OPTIONS = {
accessToken: process.env.GITHUB_TOKEN,
username: process.env.GITHUB_USERNAME,
compactByLanguage: false,
compactByTopic: false,
transform,
};
function setHttpClient(opts) {
// http is provided in opts in test cases env
if (opts.http)
return opts.http;
const headers = {};
if (opts.accessToken) {
headers.Authorization = `token ${opts.accessToken}`;
}
return (0, client_1.createClient)({ headers });
}
exports.setHttpClient = setHttpClient;
async function main(options) {
const http = setHttpClient(options);
const opts = Object.assign({}, DEFAULT_OPTIONS, options, {
http,
});
if (!opts.username) {
try {
const { login } = await http.get('user').json();
opts.username = login;
}
catch {
throw new Error('[options.username] is not set');
}
}
return apiGetStar(opts);
}
exports.default = main;