Compare commits
	
		
			No commits in common. "master" and "v1.0.0" have entirely different histories.
		
	
	
		
	
		
| @ -1,8 +0,0 @@ | |||||||
| { |  | ||||||
|   "bracketSpacing": true, |  | ||||||
|   "printWidth": 120, |  | ||||||
|   "singleQuote": true, |  | ||||||
|   "tabWidth": 2, |  | ||||||
|   "trailingComma": "none", |  | ||||||
|   "useTabs": true |  | ||||||
| } |  | ||||||
							
								
								
									
										42
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								README.md
									
									
									
									
									
								
							| @ -1,41 +1,3 @@ | |||||||
| # [how-npm-am-i.js](https://git.coolaj86.com/coolaj86/how-npm-am-i.js) | # how-npm-am-i.js | ||||||
| 
 | 
 | ||||||
| Shows how many downloads you get on npm each month, across all of your packages. | Shows how many downloads you get on npm each month, across all your packages. | ||||||
| 
 |  | ||||||
| > npx how-npm-am-i <username> [--verbose] |  | ||||||
| 
 |  | ||||||
| # Usage |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| how-npm-am-i isaacs --verbose |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ```txt |  | ||||||
| You've published 161 packages to npm and you get... |  | ||||||
| 
 |  | ||||||
| Package Name                             Downloads |  | ||||||
| @isaacs/example-automatic-publishing:            3 |  | ||||||
| cluster-callresp:                               11 |  | ||||||
| voxer-blog-demo:                                12 |  | ||||||
| tako-session-token:                             13 |  | ||||||
| truncating-stream:                              18 |  | ||||||
| ... |  | ||||||
| rimraf:                                 59,309,683 |  | ||||||
| minimatch:                              63,109,081 |  | ||||||
| yallist:                                66,527,785 |  | ||||||
| lru-cache:                              77,627,756 |  | ||||||
| glob:                                  109,654,115 |  | ||||||
| 
 |  | ||||||
| 1,423,623,087 downloads per month. Not bad! |  | ||||||
| You're *very* npm. |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| # Install |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| npm install --global how-npm-am-i |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| # How I built this |  | ||||||
| 
 |  | ||||||
| See <https://coolaj86.com/articles/how-cool-you-are-on-npm/> |  | ||||||
| @ -1,92 +0,0 @@ | |||||||
| #!/usr/bin/env node
 |  | ||||||
| 'use strict'; |  | ||||||
| 
 |  | ||||||
| var pkg = require('../package.json'); |  | ||||||
| 
 |  | ||||||
| var args = process.argv.slice(1).join(','); |  | ||||||
| if (/-V|--version/.test(args)) { |  | ||||||
| 	console.info('v' + pkg.version); |  | ||||||
| 	return; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| var verbose = false; |  | ||||||
| if (/-v|--verbose/.test(args)) { |  | ||||||
| 	verbose = true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| var username = process.argv[2]; |  | ||||||
| if (!username) { |  | ||||||
| 	console.error(); |  | ||||||
| 	console.error('Usage: how-npm-am-i <username>'); |  | ||||||
| 	console.error('   Ex: how-npm-am-i isaacs'); |  | ||||||
| 	console.error(); |  | ||||||
| 	process.exit(1); |  | ||||||
| 	return; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| var hnai = require('../'); |  | ||||||
| hnai |  | ||||||
| 	.packages(username) |  | ||||||
| 	.then(function(pkgnames) { |  | ||||||
| 		console.info(''); |  | ||||||
| 		if (!pkgnames.length) { |  | ||||||
| 			console.info("You've published " + pkgnames.length + ' packages to npm. Hmm.'); |  | ||||||
| 			console.info('Well, we all have to start somewhere.... except maybe you.... you just... keep doing you. 👍'); |  | ||||||
| 			console.info(''); |  | ||||||
| 			process.exit(1337); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		console.info("You've published " + pkgnames.length + ' packages to npm and you get...'); |  | ||||||
| 		hnai.downloads(pkgnames).then(function(downloads) { |  | ||||||
| 			var total = downloads.reduce(function(sum, el) { |  | ||||||
| 				return sum + el.downloads; |  | ||||||
| 			}, 0); |  | ||||||
| 			if (verbose) { |  | ||||||
| 				tabularize(downloads); |  | ||||||
| 			} |  | ||||||
| 			console.info(total.toLocaleString() + ' downloads per month. Not bad!'); |  | ||||||
| 			if (total >= 100000 || pkgnames.length > 100) { |  | ||||||
| 				console.info("You're a little npm. Keep trying."); |  | ||||||
| 			} else { |  | ||||||
| 				console.info("You're *very* npm. Much wow!"); |  | ||||||
| 			} |  | ||||||
| 			console.info(); |  | ||||||
| 		}); |  | ||||||
| 	}) |  | ||||||
| 	.catch(function(e) { |  | ||||||
| 		console.error(); |  | ||||||
| 		console.error(e); |  | ||||||
| 		console.error(); |  | ||||||
| 		process.exit(1); |  | ||||||
| 	}); |  | ||||||
| 
 |  | ||||||
| function tabularize(downloads) { |  | ||||||
| 	console.info(''); |  | ||||||
| 	var maxLen = 0; |  | ||||||
| 	var maxCount = "Downloads".length; |  | ||||||
| 	downloads.sort(function(a, b) { |  | ||||||
| 		maxLen = Math.max(a.package.length, b.package.length, maxLen); |  | ||||||
| 		maxCount = Math.max(a.downloads.toLocaleString().length, b.downloads.toLocaleString().length, maxCount); |  | ||||||
| 		return a.downloads - b.downloads; |  | ||||||
| 	}); |  | ||||||
| 	console.info(leftpad('Package Name', maxLen + 1), rightmad('Downloads', maxCount + 1)); |  | ||||||
| 	downloads.forEach(function(stat) { |  | ||||||
| 		console.info(leftpad(stat.package + ':', maxLen + 1), rightmad(stat.downloads.toLocaleString(), maxCount + 1)); |  | ||||||
| 	}); |  | ||||||
| 	console.info(''); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // no, I was right
 |  | ||||||
| function leftpad(str, n) { |  | ||||||
| 	while (str.length < n) { |  | ||||||
| 		str = str + ' '; |  | ||||||
| 	} |  | ||||||
| 	return str; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function rightmad(str, n) { |  | ||||||
| 	while (str.length < n) { |  | ||||||
| 		str = ' ' + str; |  | ||||||
| 	} |  | ||||||
| 	return str; |  | ||||||
| } |  | ||||||
							
								
								
									
										115
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								index.js
									
									
									
									
									
								
							| @ -1,115 +0,0 @@ | |||||||
| 'use strict'; |  | ||||||
| 
 |  | ||||||
| // Inspired in part by
 |  | ||||||
| // * https://www.npmjs.com/package/npmjs-api
 |  | ||||||
| // * https://github.com/kevva/npm-user-packages/blob/master/index.js
 |  | ||||||
| 
 |  | ||||||
| // Official docs at
 |  | ||||||
| // * https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#meta-endpoints
 |  | ||||||
| // * https://github.com/npm/registry/blob/master/docs/download-counts.md
 |  | ||||||
| 
 |  | ||||||
| var batchAsync = require('batchasync').batchAsync; |  | ||||||
| var request = require('@root/request'); |  | ||||||
| request = require('util').promisify(request); |  | ||||||
| 
 |  | ||||||
| var hnai = exports; |  | ||||||
| hnai.packages = function(username) { |  | ||||||
| 	// I didn't bother to implement paging because... I didn't
 |  | ||||||
| 	return request({ |  | ||||||
| 		url: 'https://api.npms.io/v2/search?q=author:' + username + '&size=250&from=0', |  | ||||||
| 		json: true |  | ||||||
| 	}).then(function(resp) { |  | ||||||
| 		// { total: 214, results: [ { package: { name: 'foobar' } } ] }
 |  | ||||||
| 		if (resp.total > 250) { |  | ||||||
| 			console.warn(); |  | ||||||
| 			console.warn("You have more than 250 published packages, but I haven't implemented paging."); |  | ||||||
| 			console.warn("I'd say please open an issue, but you're ovbiously skilled, so please PR."); |  | ||||||
| 			console.warn(); |  | ||||||
| 		} |  | ||||||
| 		return resp.body.results.map(function(result) { |  | ||||||
| 			return result.package.name; |  | ||||||
| 		}); |  | ||||||
| 	}); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| hnai.downloads = function(pkgnames) { |  | ||||||
| 	// https://github.com/npm/registry/blob/master/docs/download-counts.md#bulk-queries
 |  | ||||||
| 	// FYI: Earliest date is January 10, 2015
 |  | ||||||
| 	// * One-off: https://api.npmjs.org/downloads/range/{period}[/{package}]
 |  | ||||||
| 	// * Bulk: https://api.npmjs.org/downloads/point/last-day/npm,express
 |  | ||||||
| 
 |  | ||||||
| 	// All the batching logic
 |  | ||||||
| 	var batches = []; |  | ||||||
| 	var batch = []; |  | ||||||
| 	pkgnames.forEach(function(pkgname) { |  | ||||||
| 		if ('@' === pkgname[0]) { |  | ||||||
| 			batches.push([pkgname]); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		if (batch.length >= 128) { |  | ||||||
| 			batches.push(batch); |  | ||||||
| 			batch = []; |  | ||||||
| 		} |  | ||||||
| 		batch.push(pkgname); |  | ||||||
| 	}); |  | ||||||
| 	if (batch.length) { |  | ||||||
| 		batches.push(batch); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// do the batching
 |  | ||||||
| 	return batchAsync(4, batches, function(batch) { |  | ||||||
| 		if (1 === batch.length) { |  | ||||||
| 			return one(batch[0]); |  | ||||||
| 		} else { |  | ||||||
| 			return many(batch); |  | ||||||
| 		} |  | ||||||
| 	}).then(function(results) { |  | ||||||
| 		// transform the results
 |  | ||||||
| 		var all = []; |  | ||||||
| 		results.forEach(function(map) { |  | ||||||
| 			//#console.debug('batch size:', Object.keys(map).length);
 |  | ||||||
| 			Object.keys(map).forEach(function(key) { |  | ||||||
| 				if (!map[key]) { |  | ||||||
| 					// can be 'null' for just-published packages
 |  | ||||||
| 					map[key] = { downloads: 0 }; |  | ||||||
| 				} |  | ||||||
| 				all.push({ |  | ||||||
| 					package: key, |  | ||||||
| 					downloads: map[key].downloads |  | ||||||
| 				}); |  | ||||||
| 			}); |  | ||||||
| 		}); |  | ||||||
| 
 |  | ||||||
| 		// get back one big happy list
 |  | ||||||
| 		return all; |  | ||||||
| 	}); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| // these need to be simplified and transformed
 |  | ||||||
| function one(pkgname) { |  | ||||||
| 	return request({ |  | ||||||
| 		url: 'https://api.npmjs.org/downloads/range/last-month/' + pkgname, |  | ||||||
| 		json: true |  | ||||||
| 	}).then(function(resp) { |  | ||||||
| 		// { package: 'foobar', downloads: [{ downloads: 1, day: '2019-06-16' }] }
 |  | ||||||
| 		var result = {}; |  | ||||||
| 		result[resp.body.package] = { |  | ||||||
| 			package: resp.body.package, |  | ||||||
| 			downloads: resp.body.downloads.reduce(function(sum, el) { |  | ||||||
| 				return el.downloads; |  | ||||||
| 			}, 0) |  | ||||||
| 		}; |  | ||||||
| 		return result; |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // these are exactly what we want, pretty much
 |  | ||||||
| function many(pkgnames) { |  | ||||||
| 	return request({ |  | ||||||
| 		url: 'https://api.npmjs.org/downloads/point/last-month/' + pkgnames.join(','), |  | ||||||
| 		json: true |  | ||||||
| 	}).then(function(resp) { |  | ||||||
| 		// { foobar: { downloads: 12 } }
 |  | ||||||
| 		return resp.body; |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
							
								
								
									
										18
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1,18 +0,0 @@ | |||||||
| { |  | ||||||
|   "name": "how-npm-am-i", |  | ||||||
|   "version": "1.0.0", |  | ||||||
|   "lockfileVersion": 1, |  | ||||||
|   "requires": true, |  | ||||||
|   "dependencies": { |  | ||||||
|     "@root/request": { |  | ||||||
|       "version": "1.3.11", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@root/request/-/request-1.3.11.tgz", |  | ||||||
|       "integrity": "sha512-3a4Eeghcjsfe6zh7EJ+ni1l8OK9Fz2wL1OjP4UCa0YdvtH39kdXB9RGWuzyNv7dZi0+Ffkc83KfH0WbPMiuJFw==" |  | ||||||
|     }, |  | ||||||
|     "batchasync": { |  | ||||||
|       "version": "1.0.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/batchasync/-/batchasync-1.0.2.tgz", |  | ||||||
|       "integrity": "sha512-YSKKrMr7BLsQnqHOtGKhuqC83CtHu9pGOhSrmPl8WCz7N3qcFJfEQGbM1I3PEOq11FU2rY+a+IokOODzOyVdXw==" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										41
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								package.json
									
									
									
									
									
								
							| @ -1,41 +0,0 @@ | |||||||
| { |  | ||||||
| 	"name": "how-npm-am-i", |  | ||||||
| 	"version": "1.0.5", |  | ||||||
| 	"description": "See how many downloads you get on npm each month, across all your packages", |  | ||||||
| 	"homepage": "https://git.coolaj86.com/coolaj86/how-npm-am-i.js", |  | ||||||
| 	"main": "index.js", |  | ||||||
| 	"scripts": { |  | ||||||
| 		"test": "node test.js" |  | ||||||
| 	}, |  | ||||||
| 	"repository": { |  | ||||||
| 		"type": "git", |  | ||||||
| 		"url": "https://git.coolaj86.com/coolaj86/how-npm-am-i.js.git" |  | ||||||
| 	}, |  | ||||||
| 	"bin": { |  | ||||||
| 		"how-npm-am-i": "bin/how-npm-am-i.js" |  | ||||||
| 	}, |  | ||||||
| 	"files": [ |  | ||||||
| 		"bin", |  | ||||||
| 		"lib" |  | ||||||
| 	], |  | ||||||
| 	"keywords": [ |  | ||||||
| 		"npm", |  | ||||||
| 		"download", |  | ||||||
| 		"count", |  | ||||||
| 		"monthly", |  | ||||||
| 		"daily", |  | ||||||
| 		"weekly", |  | ||||||
| 		"all", |  | ||||||
| 		"packages" |  | ||||||
| 	], |  | ||||||
| 	"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", |  | ||||||
| 	"license": "MPL-2.0", |  | ||||||
| 	"dependencies": { |  | ||||||
| 		"@root/request": "^1.3.11", |  | ||||||
| 		"batchasync": "^1.0.2" |  | ||||||
| 	}, |  | ||||||
| 	"bundledDependencies": [ |  | ||||||
| 		"@root/request", |  | ||||||
| 		"batchasync" |  | ||||||
| 	] |  | ||||||
| } |  | ||||||
							
								
								
									
										16
									
								
								test.js
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								test.js
									
									
									
									
									
								
							| @ -1,16 +0,0 @@ | |||||||
| 'use strict'; |  | ||||||
| 
 |  | ||||||
| var hnai = require('./'); |  | ||||||
| hnai.packages('coolaj86').then(function(pkgnames) { |  | ||||||
| 	console.info('Total number of pakcages:', pkgnames.length); |  | ||||||
| 	hnai.downloads(pkgnames).then(function(downloads) { |  | ||||||
| 		console.log( |  | ||||||
| 			'Download Counts:', |  | ||||||
| 			downloads |  | ||||||
| 				.map(function(all) { |  | ||||||
| 					return all.package + ' ' + all.downloads; |  | ||||||
| 				}) |  | ||||||
| 				.join('\n') |  | ||||||
| 		); |  | ||||||
| 	}); |  | ||||||
| }); |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user