Skip to content

Instantly share code, notes, and snippets.

@aparajita

aparajita/yarnls.js

Last active Mar 2, 2018
Embed
What would you like to do?
yarnls.js: The missing yarn command. Lists only the top level packages in the current directory.
#!/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