Skip to content

Instantly share code, notes, and snippets.

@haze
Created November 29, 2019 04:40
Show Gist options
  • Save haze/6d8bfea2609e23fedd7806db06f85450 to your computer and use it in GitHub Desktop.
Save haze/6d8bfea2609e23fedd7806db06f85450 to your computer and use it in GitHub Desktop.
import {walk, ensureDir} from "https://deno.land/std/fs/mod.ts";
import {readFileStr} from 'https://deno.land/std/fs/read_file_str.ts';
const inspect = false;
interface CloneResult {sshURL: string, exitCode: number};
const repositories = async (name: string): Promise<any[]> => {
return await (await fetch(`https://api.github.com/users/${name}/repos`)).json();
};
// clone will clone the given git repo from `sshURL` and return the exit code
const clone = async (sshURL: string, into?: string): Promise<CloneResult> => {
const exitCode = (await Deno.run({args: ['git', 'clone', sshURL, into || '.'], stdout: 'null', stdin: 'null', stderr: 'null'}).status()).code;
return new Promise<CloneResult>(resolve => {
resolve({sshURL, exitCode});
});
};
const cloneReposForUser = async (name: string): Promise<CloneResult[]> => {
const repos = await repositories(name);
await ensureDir(name);
console.log(`Cloning repositories for user ${name}…`);
return Promise.all(repos.map(repo => clone(repo.git_url, `${name}/${repo.name}`)));
};
const extension = (filename: string): string => {
const ext = /(?:\.([^.]+))?$/.exec(filename)[1];
if (ext && ext.includes('/')) return undefined;
return ext;
};
const username: string = 'haze';
const now = window.performance.now();
await cloneReposForUser(username);
const after = window.performance.now() - now;
console.log(`Mass clone took ${after}ms`);
const extensionMap = new Map<string, string[]>();
const knownExtensionMapping = new Map<string, string>();
knownExtensionMapping.set("python", "py");
knownExtensionMapping.set("py3", "py");
knownExtensionMapping.set("py2", "py");
knownExtensionMapping.set("jsx", "js");
knownExtensionMapping.set("tsx", "ts");
knownExtensionMapping.set("cc", "c");
knownExtensionMapping.set("cc", "c");
knownExtensionMapping.set("hh", "c");
for await (const fileInfo of walk(username)) {
let ext = extension(fileInfo.filename);
if (ext) {
const mapping = knownExtensionMapping.get(ext);
if (mapping) {
ext = mapping;
}
const arr = extensionMap.get(ext);
if (arr) {
arr.push(fileInfo.filename);
} else {
extensionMap.set(ext, [fileInfo.filename]);
}
}
}
interface CountResult {comments: number, code: number}
interface CountLocFunc {
(source: string): CountResult;
}
const robustCommentsFn = (opts: {line: string, multiline?: {start: string, end: string}}, source: string): CountResult => {
let readingMultiline = false;
let code = 0;
let comments = 0;
for (let line of source.split('\n')) {
let whitespaceStripped = line.trim();
const hasStartMultiline = opts.multiline ? line.includes(opts.multiline.start) : false;
const hasEndMultiline = opts.multiline ? line.includes(opts.multiline.end) : false;
const isComment = whitespaceStripped.startsWith(opts.line);
if (readingMultiline && hasEndMultiline) {
readingMultiline = false;
comments += 1;
continue;
}
if (hasStartMultiline && !hasEndMultiline) { // we start reading a multiline comment
readingMultiline = true;
comments += 1;
continue;
} else if (hasStartMultiline && hasEndMultiline) { // code with /* */, count as comment (pass)
comments += 1;
continue
} else if (isComment) { // line entirely is comment
comments += 1
continue;
}
code += 1;
}
return {code, comments};
};
const countJS = robustCommentsFn.bind(null, {line: '//', multiline: {start: '/*', end: '*/'}});
const countZig = robustCommentsFn.bind(null, {line: '//'}); // zig has no multiline strings
const countPython = robustCommentsFn.bind(null, {line: '#'}); // python has no multiline strings
const knowledgeBase = new Map<string, CountLocFunc>();
knowledgeBase.set('js', countJS);
knowledgeBase.set('d', countJS);
knowledgeBase.set('c', countJS);
knowledgeBase.set('zig', countZig);
knowledgeBase.set('py', countPython);
knowledgeBase.set('cpp', countJS);
knowledgeBase.set('nim', countPython);
knowledgeBase.set('java', countJS);
knowledgeBase.set('go', countJS);
knowledgeBase.set('ts', countJS);
const countTable = {};
for (let [ext, files] of extensionMap) {
const fn = knowledgeBase.get(ext);
if (fn) {
let comments = 0;
let count = 0;
for (let file of files) {
const res = fn(await readFileStr(file));
count += res.code;
comments += res.comments;
}
countTable[ext] = {codeLines: count, commentLines: comments};
} else if (inspect) {
console.log(`${ext} has no count function.`);
}
}
console.table(countTable);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment