Last active
March 2, 2018 18:50
-
-
Save aparajita/e646370c181ebf82e673fba11d660ed2 to your computer and use it in GitHub Desktop.
yarnls.js: The missing yarn command. Lists only the top level packages in the current directory.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
'use strict'; | |
const child_process = require('child_process'); | |
const format = require('util').format; | |
const fs = require('fs'); | |
const path = require('path'); | |
function parseOptions() { | |
const options = { | |
devOnly: false, | |
prodOnly: false, | |
pattern: '' | |
}; | |
for (let i = 2; i < process.argv.length; i++) { | |
const arg = process.argv[i]; | |
switch (arg) { | |
case '--help': | |
case '-h': { | |
const help = `usage: yarnls.js [options] [pattern] | |
Displays an alphabetical listing of top level packages | |
(as determined by package.json) and the actual *installed* version. | |
Runtime dependencies are displayed in green. To filter | |
the list, pass a pattern, which uses the same format as | |
\`yarn list\` (which in turn uses micromatch). | |
OPTIONS | |
--dev, -d Show only packages listed in package.json devDependencies | |
--prod, -p Show only packages listed in package.json dependencies`; | |
console.log(help); | |
process.exit(0); | |
break; | |
} | |
case '--dev': | |
case '-d': | |
options.devOnly = true; | |
options.prodOnly = false; | |
break; | |
case '--prod': | |
case '-p': | |
options.devOnly = false; | |
options.prodOnly = true; | |
break; | |
default: | |
if (arg.startsWith('-')) { | |
console.log(`Error: unknown option '${arg}'`); | |
process.exit(1); | |
} | |
options.pattern = arg; | |
} | |
} | |
return options; | |
} | |
function ls() { | |
// Read in package.json | |
let packageJson = {}; | |
try { | |
packageJson = JSON.parse( | |
fs.readFileSync(path.join(process.cwd(), 'package.json')) | |
); | |
} catch (e) { | |
console.log('No packages'); | |
process.exit(0); | |
} | |
packageJson.dependencies = packageJson.dependencies || {}; | |
packageJson.devDependencies = packageJson.devDependencies || {}; | |
const options = parseOptions(); | |
const packages = {}; | |
if (!options.devOnly) { | |
Object.assign(packages, packageJson.dependencies); | |
} | |
if (!options.prodOnly) { | |
Object.assign(packages, packageJson.devDependencies); | |
} | |
const packageNames = [...Object.keys(packages)]; | |
packageNames.sort(); | |
let cmd = `yarn list --depth 0`; | |
if (options.pattern) { | |
cmd += ` --pattern '${options.pattern}'`; | |
} | |
child_process.exec(cmd, (error, stdout) => { | |
if (error && !stdout) { | |
console.error(error.toString()); | |
process.exit(1); | |
} else { | |
let lines = stdout.split('\n'); | |
// First line is 'yarn list <version>' | |
lines.shift(); | |
// Last two lines are 'Done in <time>\n' | |
lines.splice(lines.length - 2, 2); | |
// Trim hierarchy characters, filter down to packages | |
// listed in package.json | |
const pattern = new RegExp(`^(${packageNames.join('|')})@([0-9.]+)$`); | |
lines = lines | |
.map(line => line.substr(3)) | |
.filter(line => pattern.test(line)); | |
const matches = lines.map(line => line.match(pattern)); | |
matches.forEach(match => { | |
const name = match[1]; | |
const version = match[2]; | |
// Color it green if it's a runtime dependency | |
// \x1b[32m\x1b[1m%s\x1b[0m \x1b[90m(%s)\x1b[0m | |
const color = name in packageJson.dependencies ? 32 : 0; | |
console.log( | |
format('\x1b[%im%s\x1b[0m \x1b[90m(%s)\x1b[0m', color, name, version) | |
); | |
}); | |
} | |
}); | |
} | |
ls(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment