Stolen from mbostok and improved upon
node cloneAllGists.js username token [outputDir]
#!/usr/bin/env node | |
var fs = require("fs"), | |
https = require("https"), | |
exec = require("child_process").exec; | |
// TODO --pull or --push | |
var user = process.argv[2], | |
token = process.argv[3], | |
outputDir = process.argv[4]; | |
outputDir = outputDir || "gists" | |
var clonedGists = [] | |
exec("mkdir -p "+outputDir, function(err) { | |
clonedGists = fs.readdirSync(outputDir) | |
fetchAndClone(1, function callback(error, nextPage) { | |
if (error) throw error; | |
if (nextPage > 0) fetchAndClone(nextPage, callback); | |
}); | |
}) | |
function fetchAndClone(page, callback) { | |
fetch(page, function(error, gists) { | |
if (error) return callback(error); | |
if (gists.length) ++page; else page = -1; | |
cloneNext(gists.pop()); | |
function cloneNext(gist) { | |
if (!gist) return callback(null, page); | |
repoDst = outputDir + '/' + gistDirName(gist) | |
if (directoryExists(repoDst)) { | |
console.log("Skipping " + gist.id + " - " + repoDst); | |
return cloneNext(gists.pop()) | |
} | |
console.log("cloning " + gist.id + " into " + repoDst); | |
exec("git clone [email protected]:" + gist.id + ".git " + repoDst, function(error, stdout, stderr) { | |
if (error) { | |
console.log("Error cloning " + gist.id + " into " + repoDst); | |
console.log(error); | |
} | |
cloneNext(gists.pop()); | |
}); | |
} | |
}); | |
} | |
function fetch(page, callback) { | |
var request = https.request({ | |
hostname: "api.github.com", | |
port: 443, | |
path: "/users/" + encodeURIComponent(user) + "/gists?page=" + page, | |
method: "GET", | |
headers: { | |
"Accept": "application/vnd.github.v3+json", | |
"Authorization": "token " + token, | |
"User-Agent": "mbostock/gist-clone-all" | |
} | |
}, function(response) { | |
var chunks = []; | |
response.setEncoding("utf8"); | |
response.on("data", function(chunk) { chunks.push(chunk); }); | |
response.on("end", function() { callback(null, JSON.parse(chunks.join(""))); }); | |
}); | |
request.on("error", callback); | |
request.end(); | |
} | |
function directoryExists(path) { | |
try { | |
return fs.lstatSync(path).isDirectory(); | |
} catch (ignored) { | |
return false; | |
} | |
} | |
function gistDirName(gist) { | |
var date = gist.created_at.split('T')[0].replace(/\-/g,'.') | |
var hash = gist.id.substr(0,5) | |
var title = toCamelCase(gist.description) || "unknown" | |
var existing = clonedGists.filter(function(g){ | |
if (g.indexOf(date+"-"+hash) === 0) { | |
return true | |
} | |
return false | |
}) | |
if (existing.length > 0) { | |
return existing[0] | |
} | |
return date + "-" + hash + "-" + title | |
} | |
function preserveCamelCase(str) { | |
let isLastCharLower = false; | |
let isLastCharUpper = false; | |
let isLastLastCharUpper = false; | |
for (let i = 0; i < str.length; i++) { | |
const c = str[i]; | |
if (isLastCharLower && /[a-zA-Z]/.test(c) && c.toUpperCase() === c) { | |
str = str.substr(0, i) + '-' + str.substr(i); | |
isLastCharLower = false; | |
isLastLastCharUpper = isLastCharUpper; | |
isLastCharUpper = true; | |
i++; | |
} else if (isLastCharUpper && isLastLastCharUpper && /[a-zA-Z]/.test(c) && c.toLowerCase() === c) { | |
str = str.substr(0, i - 1) + '-' + str.substr(i - 1); | |
isLastLastCharUpper = isLastCharUpper; | |
isLastCharUpper = false; | |
isLastCharLower = true; | |
} else { | |
isLastCharLower = c.toLowerCase() === c; | |
isLastLastCharUpper = isLastCharUpper; | |
isLastCharUpper = c.toUpperCase() === c; | |
} | |
} | |
return str; | |
} | |
function toCamelCase(str) { | |
if (!str) { | |
return ''; | |
} | |
if (str.length === 0) { | |
return ''; | |
} | |
if (str.length === 1) { | |
return str.toLowerCase(); | |
} | |
if (/^[a-z0-9]+$/.test(str)) { | |
return str; | |
} | |
const hasUpperCase = str !== str.toLowerCase(); | |
if (hasUpperCase) { | |
str = preserveCamelCase(str); | |
} | |
str = str | |
.replace(/^[_.\- ]+/, '') | |
.toLowerCase() | |
.replace(/[_.\- ]+(\w|$)/g, (m, p1) => p1.toUpperCase()); | |
str = str.split(" ")[0] | |
return str.replace(/[^a-zA-Z0-9]/g,'').substr(0,40) | |
}; |
ain't that the legend of d3.js, animations, and charts and dataviz and all? 😁
yeah but it's not stealing its opensourcing. Im grabbing this too.
Cheers 🥂