Skip to content

Instantly share code, notes, and snippets.

@MaxGraey
Last active March 27, 2021 20:37
Show Gist options
  • Save MaxGraey/e80843bf15e9eacc4f2881126b590648 to your computer and use it in GitHub Desktop.
Save MaxGraey/e80843bf15e9eacc4f2881126b590648 to your computer and use it in GitHub Desktop.
Script which sort programming languages in Github Explore Collection Category
// TODO: next implement HITS ranking algorithm from: https://d-nb.info/1112813659/34
const https = require('https');
const url = require('url');
const fs = require('fs');
const LANGS_URL = 'https://raw.githubusercontent.com/github/explore/main/collections/programming-languages/index.md';
const MD_PROLOGUE = "---\nitems:\n";
const MD_EPILOGUE = (
"\n" +
"display_name: Programming languages\n" +
"created_by: leereilly\n" +
"---\n" +
"A list of programming languages that are actively developed on GitHub\n"
);
function request(urlString, headersOptions = {}) {
return new Promise((ok, fail) => {
const { host, path } = url.parse(urlString);
const options = { host, path, headers: {
'User-Agent': 'NodeJS', ...headersOptions }
};
let content = '';
https.get(options, response => {
response.on('data', data => {
content += data.toString();
}).on('end', () => { ok(content); });
}).on('error', err => {
fail(err.message);
});
});
}
function zip(a, b) {
return a.map((e, i) => [e, b[i]]);
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function getLangCollection(content) {
return content.split('\n')
.filter(l => l.startsWith('- '))
.map(l => l.substring(2));
}
function computeScore({ stargazers_count: stars, forks }) {
// Use simple geometric weighted mean for now
const STARS_WEIGHT = 0.85;
const FORKS_WEIGHT = 0.15;
const n = (
STARS_WEIGHT * Math.log(stars) +
FORKS_WEIGHT * Math.log(forks)
);
const m = STARS_WEIGHT + FORKS_WEIGHT;
const score = Math.exp(n / m);
if (!Number.isFinite(score)) {
throw new Error(`Invalid score for stars=${stars}, watchers=${watchers}, forks=${forks}`);
}
return score;
}
async function regenerateMarkdownPage() {
const collection = getLangCollection(await request(LANGS_URL));
const responces = [];
console.log('please wait...');
for (const repo of collection) {
try {
const responce = await request(`https://api.github.com/repos/${repo}`);
responces.push(responce);
await sleep(40);
} catch (e) {
throw new Error('cannot accees to GitHub API or parse responce', e);
}
}
// calculate scores from "stars", "subscribers" and "repos" in responce data
const scores = responces.map(info => computeScore(JSON.parse(info)));
const entries = zip(collection, scores);
// descending sort by score
entries.sort((a, b) => {
const score1 = a[1];
const score2 = b[1];
return score2 - score1;
});
const updatedContent = (
MD_PROLOGUE +
entries.map((e, i) => '- ' + e[0]).join('\n') +
MD_EPILOGUE
);
console.log(updatedContent);
fs.writeFileSync(__dirname + '/index.md', updatedContent);
}
regenerateMarkdownPage();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment