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 🥂